From 7d51de1d3c8117e734db512c2bb3030062af1006 Mon Sep 17 00:00:00 2001 From: Brian Faherty Date: Wed, 8 Aug 2018 09:46:58 -0400 Subject: [PATCH 001/179] Fix http redirect Pdbadger was sending a 301 so that it would not regenerate the documentation when hit again in a browser. Instead the browser would use their cache and just bring users to static. Switching from 301 to 302 fixes this issue. --- badger/badgerserver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/badger/badgerserver.go b/badger/badgerserver.go index ab1629252..f256a974d 100644 --- a/badger/badgerserver.go +++ b/badger/badgerserver.go @@ -53,5 +53,5 @@ func BadgerGenerate(w http.ResponseWriter, r *http.Request) { } log.Println("Report generated. Redirecting..") - http.Redirect(w, r, "/static", 301) + http.Redirect(w, r, "/static", 302) } From 50e56339a8489496aa65e1bac8f67573cc3a6b5e Mon Sep 17 00:00:00 2001 From: Brian Faherty Date: Wed, 8 Aug 2018 12:27:58 -0400 Subject: [PATCH 002/179] Add handler for / in pgbadger http server Currently you have to remember /api/badgergenerate which is a longer url than I would like to keep in my head. I added a root handler with two code paths. If /report/index.html does not exist you get a redirect to /api/badgergenerate. If it does exist you get a redirect to /static. I don't believe this change will break anything because there is nothing listening there currently on this http server. --- badger/badgerserver.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/badger/badgerserver.go b/badger/badgerserver.go index ab1629252..cd57dac93 100644 --- a/badger/badgerserver.go +++ b/badger/badgerserver.go @@ -33,6 +33,7 @@ func init() { func main() { http.HandleFunc("/api/badgergenerate", BadgerGenerate) http.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir("/report")))) + http.HandleFunc("/", RootPathRedirect) log.Fatal(http.ListenAndServe(":10000", nil)) } @@ -55,3 +56,11 @@ func BadgerGenerate(w http.ResponseWriter, r *http.Request) { log.Println("Report generated. Redirecting..") http.Redirect(w, r, "/static", 301) } + +func RootPathRedirect(w http.ResponseWriter, r *http.Request) { + redirect_url := "/static/" + if _, err := os.Stat(REPORT); os.IsNotExist(err) { + redirect_url = "/api/badgergenerate" + } + http.Redirect(w, r, redirect_url, 302) +} From e4c7f4430c799810f7eb436903a94de4bae43ea9 Mon Sep 17 00:00:00 2001 From: Jason O'Donnell <2160810+jasonodonnell@users.noreply.github.com> Date: Tue, 14 Aug 2018 17:51:00 -0400 Subject: [PATCH 003/179] Change default timezone to UTC --- conf/postgres/postgresql.conf.template | 4 ++-- conf/postgres/postgresql.conf.template.nopgaudit | 4 ++-- examples/docker/custom-config/configs/postgresql.conf | 4 ++-- examples/docker/postgres-sshd/config/postgresql.conf | 4 ++-- examples/helm/custom-config/configs/postgresql.conf | 4 ++-- examples/kube/custom-config/configs/postgresql.conf | 4 ++-- examples/kube/postgres-sshd/configs/postgresql.conf | 4 ++-- .../kube/primary-deployment/configs/postgresql.conf | 4 ++-- pgconf/postgresql.conf | 4 ++-- tools/test-harness/custom_config_ssl_test.go | 11 +++++++++++ tools/test-harness/custom_config_test.go | 11 +++++++++++ tools/test-harness/primary_test.go | 11 +++++++++++ 12 files changed, 51 insertions(+), 18 deletions(-) diff --git a/conf/postgres/postgresql.conf.template b/conf/postgres/postgresql.conf.template index 2ba610020..ef727a5d3 100644 --- a/conf/postgres/postgresql.conf.template +++ b/conf/postgres/postgresql.conf.template @@ -455,7 +455,7 @@ log_lock_waits = on # log lock waits >= deadlock_timeout #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'US/Eastern' +log_timezone = 'UTC' # - Process Title - @@ -551,7 +551,7 @@ log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and datestyle = 'iso, mdy' #intervalstyle = 'postgres' -timezone = 'US/Eastern' +timezone = 'UTC' #timezone_abbreviations = 'Default' # Select the set of available time zone # abbreviations. Currently, there are # Default diff --git a/conf/postgres/postgresql.conf.template.nopgaudit b/conf/postgres/postgresql.conf.template.nopgaudit index feb9b44e9..6c222646f 100644 --- a/conf/postgres/postgresql.conf.template.nopgaudit +++ b/conf/postgres/postgresql.conf.template.nopgaudit @@ -455,7 +455,7 @@ log_lock_waits = on # log lock waits >= deadlock_timeout #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'US/Eastern' +log_timezone = 'UTC' # - Process Title - @@ -551,7 +551,7 @@ log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and datestyle = 'iso, mdy' #intervalstyle = 'postgres' -timezone = 'US/Eastern' +timezone = 'UTC' #timezone_abbreviations = 'Default' # Select the set of available time zone # abbreviations. Currently, there are # Default diff --git a/examples/docker/custom-config/configs/postgresql.conf b/examples/docker/custom-config/configs/postgresql.conf index b7b641405..a3fb4f880 100644 --- a/examples/docker/custom-config/configs/postgresql.conf +++ b/examples/docker/custom-config/configs/postgresql.conf @@ -418,7 +418,7 @@ log_lock_waits = on # log lock waits >= deadlock_timeout #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'US/Eastern' +log_timezone = 'UTC' #------------------------------------------------------------------------------ @@ -505,7 +505,7 @@ log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and datestyle = 'iso, mdy' #intervalstyle = 'postgres' -timezone = 'US/Eastern' +timezone = 'UTC' #timezone_abbreviations = 'Default' # Select the set of available time zone # abbreviations. Currently, there are # Default diff --git a/examples/docker/postgres-sshd/config/postgresql.conf b/examples/docker/postgres-sshd/config/postgresql.conf index 15439b3ef..257592d94 100644 --- a/examples/docker/postgres-sshd/config/postgresql.conf +++ b/examples/docker/postgres-sshd/config/postgresql.conf @@ -455,7 +455,7 @@ log_lock_waits = on # log lock waits >= deadlock_timeout #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'US/Eastern' +log_timezone = 'UTC' # - Process Title - @@ -551,7 +551,7 @@ log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and datestyle = 'iso, mdy' #intervalstyle = 'postgres' -timezone = 'US/Eastern' +timezone = 'UTC' #timezone_abbreviations = 'Default' # Select the set of available time zone # abbreviations. Currently, there are # Default diff --git a/examples/helm/custom-config/configs/postgresql.conf b/examples/helm/custom-config/configs/postgresql.conf index 289cd16ad..c2f85ea80 100644 --- a/examples/helm/custom-config/configs/postgresql.conf +++ b/examples/helm/custom-config/configs/postgresql.conf @@ -418,7 +418,7 @@ log_lock_waits = on # log lock waits >= deadlock_timeout #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'US/Eastern' +log_timezone = 'UTC' #------------------------------------------------------------------------------ @@ -505,7 +505,7 @@ log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and datestyle = 'iso, mdy' #intervalstyle = 'postgres' -timezone = 'US/Eastern' +timezone = 'UTC' #timezone_abbreviations = 'Default' # Select the set of available time zone # abbreviations. Currently, there are # Default diff --git a/examples/kube/custom-config/configs/postgresql.conf b/examples/kube/custom-config/configs/postgresql.conf index d11ea5e27..0a37a2ffa 100644 --- a/examples/kube/custom-config/configs/postgresql.conf +++ b/examples/kube/custom-config/configs/postgresql.conf @@ -418,7 +418,7 @@ log_lock_waits = on # log lock waits >= deadlock_timeout #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'US/Eastern' +log_timezone = 'UTC' #------------------------------------------------------------------------------ @@ -505,7 +505,7 @@ log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and datestyle = 'iso, mdy' #intervalstyle = 'postgres' -timezone = 'US/Eastern' +timezone = 'UTC' #timezone_abbreviations = 'Default' # Select the set of available time zone # abbreviations. Currently, there are # Default diff --git a/examples/kube/postgres-sshd/configs/postgresql.conf b/examples/kube/postgres-sshd/configs/postgresql.conf index a0f057a5f..876599d1a 100644 --- a/examples/kube/postgres-sshd/configs/postgresql.conf +++ b/examples/kube/postgres-sshd/configs/postgresql.conf @@ -455,7 +455,7 @@ log_lock_waits = on # log lock waits >= deadlock_timeout #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'US/Eastern' +log_timezone = 'UTC' # - Process Title - @@ -551,7 +551,7 @@ log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and datestyle = 'iso, mdy' #intervalstyle = 'postgres' -timezone = 'US/Eastern' +timezone = 'UTC' #timezone_abbreviations = 'Default' # Select the set of available time zone # abbreviations. Currently, there are # Default diff --git a/examples/kube/primary-deployment/configs/postgresql.conf b/examples/kube/primary-deployment/configs/postgresql.conf index fafb02e68..52c06227a 100644 --- a/examples/kube/primary-deployment/configs/postgresql.conf +++ b/examples/kube/primary-deployment/configs/postgresql.conf @@ -418,7 +418,7 @@ log_lock_waits = on # log lock waits >= deadlock_timeout #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'US/Eastern' +log_timezone = 'UTC' #------------------------------------------------------------------------------ @@ -505,7 +505,7 @@ log_autovacuum_min_duration = 0 # -1 disables, 0 logs all actions and datestyle = 'iso, mdy' #intervalstyle = 'postgres' -timezone = 'US/Eastern' +timezone = 'UTC' #timezone_abbreviations = 'Default' # Select the set of available time zone # abbreviations. Currently, there are # Default diff --git a/pgconf/postgresql.conf b/pgconf/postgresql.conf index 30b3237a8..bfa51be86 100644 --- a/pgconf/postgresql.conf +++ b/pgconf/postgresql.conf @@ -419,7 +419,7 @@ log_line_prefix = '< %m >' # special values: #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'US/Eastern' +log_timezone = 'UTC' #------------------------------------------------------------------------------ @@ -506,7 +506,7 @@ log_timezone = 'US/Eastern' datestyle = 'iso, mdy' #intervalstyle = 'postgres' -timezone = 'US/Eastern' +timezone = 'UTC' #timezone_abbreviations = 'Default' # Select the set of available time zone # abbreviations. Currently, there are # Default diff --git a/tools/test-harness/custom_config_ssl_test.go b/tools/test-harness/custom_config_ssl_test.go index f7ca18e2c..e37a612f5 100644 --- a/tools/test-harness/custom_config_ssl_test.go +++ b/tools/test-harness/custom_config_ssl_test.go @@ -55,6 +55,17 @@ func TestCustomConfigSSL(t *testing.T) { t.Fatalf("extensions less then 1, it shouldn't be: %d", len(extensions)) } + settings, err := db.Settings() + if err != nil { + t.Fatal(err) + } + + for _, setting := range settings { + if setting.Name == "log_timezone" && setting.Value != "UTC" { + t.Fatalf("log_timezone isn't UTC, it should be: %s = %s", setting.Name, setting.Value) + } + } + report, err := harness.createReport() if err != nil { t.Fatal(err) diff --git a/tools/test-harness/custom_config_test.go b/tools/test-harness/custom_config_test.go index 757d813a1..acb682a46 100644 --- a/tools/test-harness/custom_config_test.go +++ b/tools/test-harness/custom_config_test.go @@ -68,6 +68,17 @@ func TestCustomConfig(t *testing.T) { t.Fatalf("extensions less then 1, it shouldn't be: %d", len(extensions)) } + settings, err := db.Settings() + if err != nil { + t.Fatal(err) + } + + for _, setting := range settings { + if setting.Name == "log_timezone" && setting.Value != "UTC" { + t.Fatalf("log_timezone isn't UTC, it should be: %s = %s", setting.Name, setting.Value) + } + } + report, err := harness.createReport() if err != nil { t.Fatal(err) diff --git a/tools/test-harness/primary_test.go b/tools/test-harness/primary_test.go index 4ed01b353..0c2d7acba 100644 --- a/tools/test-harness/primary_test.go +++ b/tools/test-harness/primary_test.go @@ -47,6 +47,17 @@ func TestPrimary(t *testing.T) { t.Fatalf("extensions less then 1, it shouldn't be: %d", len(extensions)) } + settings, err := db.Settings() + if err != nil { + t.Fatal(err) + } + + for _, setting := range settings { + if setting.Name == "log_timezone" && setting.Value != "UTC" { + t.Fatalf("log_timezone isn't UTC, it should be: %s = %s", setting.Name, setting.Value) + } + } + report, err := harness.createReport() if err != nil { t.Fatal(err) From f0a5d725d134afa78e5442fab0db8d2dc771eace Mon Sep 17 00:00:00 2001 From: Jason O'Donnell <2160810+jasonodonnell@users.noreply.github.com> Date: Thu, 16 Aug 2018 15:20:19 -0400 Subject: [PATCH 004/179] Update RPM variables to be consistent --- centos7/10/Dockerfile.backrest-restore.centos7 | 3 +-- centos7/10/Dockerfile.backup.centos7 | 2 +- centos7/10/Dockerfile.collect.centos7 | 2 +- centos7/10/Dockerfile.pgadmin4.centos7 | 2 +- centos7/10/Dockerfile.postgres-gis.centos7 | 2 +- centos7/10/Dockerfile.postgres.centos7 | 2 +- centos7/10/Dockerfile.upgrade.centos7 | 10 +++++++--- centos7/9.6/Dockerfile.collect.centos7 | 2 +- centos7/9.6/Dockerfile.upgrade.centos7 | 7 +++++-- 9 files changed, 19 insertions(+), 13 deletions(-) diff --git a/centos7/10/Dockerfile.backrest-restore.centos7 b/centos7/10/Dockerfile.backrest-restore.centos7 index 6e50876e6..22646c813 100644 --- a/centos7/10/Dockerfile.backrest-restore.centos7 +++ b/centos7/10/Dockerfile.backrest-restore.centos7 @@ -16,8 +16,7 @@ LABEL name="crunchydata/postgres" \ ENV PGVERSION="10" PGDG_REPO="pgdg-centos10-10-2.noarch.rpm" -#RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/${PGDG_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} RUN yum -y update && yum -y install epel-release \ && yum -y install \ diff --git a/centos7/10/Dockerfile.backup.centos7 b/centos7/10/Dockerfile.backup.centos7 index 46a9759dc..704ec698b 100644 --- a/centos7/10/Dockerfile.backup.centos7 +++ b/centos7/10/Dockerfile.backup.centos7 @@ -16,7 +16,7 @@ LABEL name="crunchydata/backup" \ ENV PGVERSION="10" PGDG_REPO="pgdg-centos10-10-2.noarch.rpm" -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/${PGDG_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} RUN yum -y update && yum install -y epel-release \ && yum -y update glibc-common \ diff --git a/centos7/10/Dockerfile.collect.centos7 b/centos7/10/Dockerfile.collect.centos7 index 6a6f37898..ca9bd9a44 100644 --- a/centos7/10/Dockerfile.collect.centos7 +++ b/centos7/10/Dockerfile.collect.centos7 @@ -17,7 +17,7 @@ LABEL name="crunchydata/collect" \ ENV PGVERSION="10" PGDG_REPO="pgdg-centos10-10-2.noarch.rpm" # Install the PGDG yum repo -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/${PGDG_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} # Install postgres client tools and libraries RUN yum install -y epel-release \ diff --git a/centos7/10/Dockerfile.pgadmin4.centos7 b/centos7/10/Dockerfile.pgadmin4.centos7 index 68130448a..45f3f2616 100644 --- a/centos7/10/Dockerfile.pgadmin4.centos7 +++ b/centos7/10/Dockerfile.pgadmin4.centos7 @@ -16,7 +16,7 @@ LABEL name="crunchydata/pgadmin4" \ ENV PGVERSION="10" PGDG_REPO="pgdg-centos10-10-2.noarch.rpm" -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/${PGDG_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} RUN yum -y update && yum -y install epel-release \ && yum -y install glibc-common-*2.17* \ diff --git a/centos7/10/Dockerfile.postgres-gis.centos7 b/centos7/10/Dockerfile.postgres-gis.centos7 index 3482cb4cc..d04886473 100644 --- a/centos7/10/Dockerfile.postgres-gis.centos7 +++ b/centos7/10/Dockerfile.postgres-gis.centos7 @@ -16,7 +16,7 @@ LABEL name="crunchydata/postgres-gis" \ ENV PGVERSION="10" PGDG_REPO="pgdg-centos10-10-2.noarch.rpm" -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/${PGDG_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} RUN yum -y update && yum -y install epel-release \ && yum -y update glibc-common \ diff --git a/centos7/10/Dockerfile.postgres.centos7 b/centos7/10/Dockerfile.postgres.centos7 index b72a34fe7..240de4290 100644 --- a/centos7/10/Dockerfile.postgres.centos7 +++ b/centos7/10/Dockerfile.postgres.centos7 @@ -16,7 +16,7 @@ LABEL name="crunchydata/postgres" \ ENV PGVERSION="10" PGDG_REPO="pgdg-centos10-10-2.noarch.rpm" -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/${PGDG_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} RUN yum -y update \ && yum -y install epel-release \ diff --git a/centos7/10/Dockerfile.upgrade.centos7 b/centos7/10/Dockerfile.upgrade.centos7 index c28f76914..9180357f1 100644 --- a/centos7/10/Dockerfile.upgrade.centos7 +++ b/centos7/10/Dockerfile.upgrade.centos7 @@ -14,9 +14,13 @@ LABEL name="crunchydata/upgrade" \ io.openshift.expose-services="" \ io.openshift.tags="crunchy,database" -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.5/redhat/rhel-7-x86_64/pgdg-centos95-9.5-3.noarch.rpm -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-centos96-9.6-3.noarch.rpm -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm +ENV PGDG_95_REPO="pgdg-centos95-9.5-3.noarch.rpm" \ + PGDG_96_REPO="pgdg-centos96-9.6-3.noarch.rpm" \ + PGDG_10_REPO="pgdg-centos10-10-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.5/redhat/rhel-7-x86_64/${PGDG_95_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/${PGDG_96_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/${PGDG_10_REPO} RUN yum -y update && yum install -y epel-release \ && yum -y update glibc-common \ diff --git a/centos7/9.6/Dockerfile.collect.centos7 b/centos7/9.6/Dockerfile.collect.centos7 index 5c84c9086..ae5288ab7 100644 --- a/centos7/9.6/Dockerfile.collect.centos7 +++ b/centos7/9.6/Dockerfile.collect.centos7 @@ -17,7 +17,7 @@ LABEL name="crunchydata/collect" \ ENV PGVERSION="9.6" PGDG_REPO="pgdg-centos96-9.6-3.noarch.rpm" # Install the PGDG yum repo -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/${PGDG_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} # Install postgres client tools and libraries RUN yum install -y epel-release \ diff --git a/centos7/9.6/Dockerfile.upgrade.centos7 b/centos7/9.6/Dockerfile.upgrade.centos7 index ce66b4e98..ef0ef1938 100644 --- a/centos7/9.6/Dockerfile.upgrade.centos7 +++ b/centos7/9.6/Dockerfile.upgrade.centos7 @@ -14,8 +14,11 @@ LABEL name="crunchydata/upgrade" \ io.openshift.expose-services="" \ io.openshift.tags="crunchy,database" -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.5/redhat/rhel-7-x86_64/pgdg-centos95-9.5-3.noarch.rpm -RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-centos96-9.6-3.noarch.rpm +ENV PGDG_95_REPO="pgdg-centos95-9.5-3.noarch.rpm" \ + PGDG_96_REPO="pgdg-centos96-9.6-3.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.5/redhat/rhel-7-x86_64/${PGDG_95_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/${PGDG_96_REPO} RUN yum -y update && yum install -y epel-release \ && yum -y update glibc-common \ From a5987dd0b59b28b8bd5ddd4a5d2f8abf7403c55a Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Thu, 16 Aug 2018 16:29:05 -0400 Subject: [PATCH 005/179] Initial pgc, label command structure. --- Godeps/Godeps.json | 8 ++++ Makefile | 14 +++++- commands/pgc/cmd/label.go | 94 +++++++++++++++++++++++++++++++++++++ commands/pgc/cmd/root.go | 98 +++++++++++++++++++++++++++++++++++++++ commands/pgc/pgc.go | 29 ++++++++++++ 5 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 commands/pgc/cmd/label.go create mode 100644 commands/pgc/cmd/root.go create mode 100644 commands/pgc/pgc.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 2f5bb29de..3d0896048 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1078,6 +1078,14 @@ { "ImportPath": "k8s.io/kube-openapi/pkg/common", "Rev": "39a7bf85c140f972372c2a0d1ee40adbf0c8bfe1" + }, + { + "ImportPath": "github.com/fatih/color", + "Rev": "507f6050b8568533fb3f5504de8e5205fa62a114" + }, + { + "ImportPath": "github.com/spf13/cobra", + "Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57" } ] } diff --git a/Makefile b/Makefile index c4bd7ce60..23e957bf4 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,10 @@ ifndef CCPROOT export CCPROOT=$(GOPATH)/src/github.com/crunchydata/crunchy-containers endif -.PHONY: all versiontest +.PHONY: all versiontest # Default target -all: backup backrestrestore collect dbaserver grafana pgadmin4 pgbadger pgbouncer pgdump pgpool pgrestore postgres postgres-gis prometheus upgrade vac +all: commands backup backrestrestore collect dbaserver grafana pgadmin4 pgbadger pgbouncer pgdump pgpool pgrestore postgres postgres-gis prometheus upgrade vac versiontest: ifndef CCP_BASEOS @@ -32,6 +32,16 @@ gendeps: docbuild: cd $CCPROOT && ./generate-docs.sh +#============================================= +# Targets that generate commands (alphabetized) +#============================================= + +commands: pgc + +pgc: + cd $(CCPROOT)/commands/pgc && go build pgc.go && mv pgc $(GOBIN)/pgc + + #============================================= # Targets that generate images (alphabetized) #============================================= diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go new file mode 100644 index 000000000..5a784ca16 --- /dev/null +++ b/commands/pgc/cmd/label.go @@ -0,0 +1,94 @@ +package cmd + +/* + Copyright 2017-2018 Crunchy Data Solutions, Inc. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import ( + // "bytes" + // "encoding/json" + "fmt" + log "github.com/Sirupsen/logrus" + // msgs "github.com/crunchydata/postgres-operator/apiservermsgs" + "github.com/spf13/cobra" + // "net/http" + // "os" +) + +var LabelCmdLabel string +var LabelMap map[string]string +var DeleteLabel bool + +var labelCmd = &cobra.Command{ + Use: "label", + Short: "Label a set of clusters", + Long: `Update label on one or more resources + +A valid label value consists of letters and/or numbers with a max length of 63 characters. If --overwrite is specified, +existing labels can be overwritten, otherwise attempting to overwrite an existing label will result in an error. + +Usage: + pgc label [--overwrite] TYPE NAME KEY_1=VAL_1 ... KEY_N=VAL_N + +Example: + + pgc label --overwrite pod postres-primary environment=prod + +.`, + Run: func(cmd *cobra.Command, args []string) { + log.Debug("label called") + var inValid bool = false + + if len(args) == 0 { + log.Error("A resource type and name must be specified.") + inValid = true + } + + // if Pod == "" { + // fmt.Println("No pod specified") + // inValid = true + // } + + if LabelCmdLabel == "" { + log.Error(`You must specify the label to apply.`) + inValid = true + } + + if (inValid) { + return + } + labelResource(args) + }, +} + +func init() { + + labelCmd.Flags().BoolVarP(&Overwrite, "overwrite", "o", false, "--overwrite forces an existing label to be overwritten") + labelCmd.Flags().StringVarP(&Pod, "pods", "", "", "Specify the name of the pod to apply label to") + labelCmd.MarkFlagRequired("pods") + labelCmd.Flags().StringVarP(&LabelCmdLabel, "label", "l", "", "The new label to apply for specified resource") + labelCmd.MarkFlagRequired("label") + + RootCmd.AddCommand(labelCmd) + +} + +func labelResource(args []string) { + // var err error + + + +fmt.Println("Args: ", args) +fmt.Println("Pod: ", Pod) +fmt.Println("Label: ", LabelCmdLabel) + +} \ No newline at end of file diff --git a/commands/pgc/cmd/root.go b/commands/pgc/cmd/root.go new file mode 100644 index 000000000..12bda2fd8 --- /dev/null +++ b/commands/pgc/cmd/root.go @@ -0,0 +1,98 @@ +package cmd + +/* + Copyright 2017-2018 Crunchy Data Solutions, Inc. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import ( + "fmt" + log "github.com/Sirupsen/logrus" + "github.com/fatih/color" + "github.com/spf13/cobra" + "os" +) + +// RED ... +var RED func(a ...interface{}) string + +// GREEN ... +var GREEN func(a ...interface{}) string + +var OutputFormat string +var APIServerURL string +var Labelselector string +var DebugFlag bool +var Pod string +var Overwrite bool + +// RootCmd represents the base command when called without any subcommands +var RootCmd = &cobra.Command{ + Use: "pgc", + Short: "The Crunchy Postgres Container Client", + Long: "The pgc command allows you to modify resources in an Kubenetes Cluster, including Openshift", + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + fmt.Println("Execute called") + + if err := RootCmd.Execute(); err != nil { + log.Debug(err.Error()) + os.Exit(-1) + } + +} + +func init() { + + cobra.OnInitialize(initConfig) + log.Debug("init called") + GREEN = color.New(color.FgGreen).SprintFunc() + RED = color.New(color.FgRed).SprintFunc() + +// RootCmd.PersistentFlags().StringVar(&APIServerURL, "apiserver-url", "", "postgres operator apiserver URL") + RootCmd.PersistentFlags().BoolVar(&DebugFlag, "debug", false, "enable debug with true") + +} + +func initConfig() { + if DebugFlag { + log.SetLevel(log.DebugLevel) + log.Debug("debug flag is set to true") + } + + // if APIServerURL == "" { + // APIServerURL = os.Getenv("CO_APISERVER_URL") + // if APIServerURL == "" { + // log.Error("CO_APISERVER_URL env var or --apiserver-url flag needs to be supplied") + // os.Exit(-1) + // } + // } + // log.Debug("in initConfig with url=" + APIServerURL) + // GetCredentials() + + //generateBashCompletion() + log.Debug("initConfig() called.") +} + +func generateBashCompletion() { + file, err2 := os.Create("/tmp/pgc-bash-completion.out") + if err2 != nil { + log.Error(err2.Error()) + } + defer file.Close() + RootCmd.GenBashCompletion(file) +} \ No newline at end of file diff --git a/commands/pgc/pgc.go b/commands/pgc/pgc.go new file mode 100644 index 000000000..60c571acb --- /dev/null +++ b/commands/pgc/pgc.go @@ -0,0 +1,29 @@ +package main + +/* + Copyright 2017-2018 Crunchy Data Solutions, Inc. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import ( + "fmt" + "github.com/crunchydata/crunchy-containers/commands/pgc/cmd" + "os" +) + +func main() { + err := cmd.RootCmd.Execute() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + +} \ No newline at end of file From a56a74da1288f0c69f9d196e69610499aaf6ce4f Mon Sep 17 00:00:00 2001 From: Jason O'Donnell <2160810+jasonodonnell@users.noreply.github.com> Date: Fri, 17 Aug 2018 12:20:24 -0400 Subject: [PATCH 006/179] Remove nodeport doc from pgAdmin4 examples --- .../kubernetes-and-openshift/_index.adoc | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc b/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc index 4e0d79181..787c6d47e 100644 --- a/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc +++ b/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc @@ -116,17 +116,23 @@ This example deploys the pgadmin4 v2 web user interface for PostgreSQL without TLS. After running the example, you should be able to browse to http://127.0.0.1:5050 -and log into the web application using a user ID of *admin@admin.com* -and password of *password*. +and log into the web application with the following configured credentials: + + * Username : *admin@admin.com* + * Password: *password* If you are running this example using Kubernetes or -OpenShift, replace *127.0.0.1:5050* with the :30000. +OpenShift, it is required to use a port-forward proxy to access the dashboard. + +To start the port-forward proxy run the following: -To get the node IP, run the following: .... -${CCP_CLI} describe pod pgadmin4-http | grep Node: +${CCP_CLI} port-forward pgadmin4-http 5050:5050 .... +To access the pgAdmin4 dashboard through the proxy, navigate to *http://127.0.0.1:5050* +in a browser. + See the link:http://pgadmin.org[pgAdmin4 documentation] for more details. To shutdown the instance and remove the container for each example, run the following: @@ -160,18 +166,23 @@ This example deploys the pgadmin4 v2 web user interface for PostgreSQL with TLS. After running the example, you should be able to browse to https://127.0.0.1:5050 -and log into the web application using a user ID of *admin@admin.com* -and password of *password*. +and log into the web application with the following configured credentials: + + * Username : *admin@admin.com* + * Password: *password* If you are running this example using Kubernetes or -OpenShift, replace *127.0.0.1:5050* with the :30000. +OpenShift, it is required to use a port-forward proxy to access the dashboard. -To get the node IP, run the following: +To start the port-forward proxy run the following: .... -${CCP_CLI} describe pod pgadmin4-https | grep Node: +${CCP_CLI} port-forward pgadmin4-https 5050:5050 .... +To access the pgAdmin4 dashboard through the proxy, navigate to *https://127.0.0.1:5050* +in a browser. + See the link:http://pgadmin.org[pgadmin4 documentation] for more details. To shutdown the instance and remove the container for each example, run the following: From da310abdb40e3b74d2ee73b40d10b2dfd9c099d1 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Fri, 17 Aug 2018 12:41:06 -0400 Subject: [PATCH 007/179] Updates to label command, wip --- commands/pgc/cmd/label.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index 5a784ca16..7d0002a8c 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -18,7 +18,6 @@ import ( // "encoding/json" "fmt" log "github.com/Sirupsen/logrus" - // msgs "github.com/crunchydata/postgres-operator/apiservermsgs" "github.com/spf13/cobra" // "net/http" // "os" @@ -74,9 +73,7 @@ func init() { labelCmd.Flags().BoolVarP(&Overwrite, "overwrite", "o", false, "--overwrite forces an existing label to be overwritten") labelCmd.Flags().StringVarP(&Pod, "pods", "", "", "Specify the name of the pod to apply label to") - labelCmd.MarkFlagRequired("pods") labelCmd.Flags().StringVarP(&LabelCmdLabel, "label", "l", "", "The new label to apply for specified resource") - labelCmd.MarkFlagRequired("label") RootCmd.AddCommand(labelCmd) @@ -88,7 +85,7 @@ func labelResource(args []string) { fmt.Println("Args: ", args) -fmt.Println("Pod: ", Pod) +fmt.Println("Pod : ", Pod) fmt.Println("Label: ", LabelCmdLabel) } \ No newline at end of file From df01f090c2e2967ca7f52437dbda118bbb57658d Mon Sep 17 00:00:00 2001 From: Sarah Conway Date: Sat, 18 Aug 2018 17:28:11 -0700 Subject: [PATCH 008/179] Optimize website theme for Firefox & Chrome --- docs/js/docdock.js | 1 - hugo/themes/docdock/static/images/clippy.svg | 4 ---- hugo/themes/docdock/static/images/home_bg.jpg | Bin 204942 -> 20037 bytes hugo/themes/docdock/static/js/docdock.js | 1 - hugo/themes/static/js/docdock.js | 1 - 5 files changed, 7 deletions(-) delete mode 100644 hugo/themes/docdock/static/images/clippy.svg diff --git a/docs/js/docdock.js b/docs/js/docdock.js index d68069cd1..d5c0824c1 100644 --- a/docs/js/docdock.js +++ b/docs/js/docdock.js @@ -185,7 +185,6 @@ jQuery(document).ready(function() { clipInit = true; } - code.after(''); code.next('.copy-to-clipboard').on('mouseleave', function() { $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w'); }); diff --git a/hugo/themes/docdock/static/images/clippy.svg b/hugo/themes/docdock/static/images/clippy.svg deleted file mode 100644 index 8a77a3303..000000000 --- a/hugo/themes/docdock/static/images/clippy.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/hugo/themes/docdock/static/images/home_bg.jpg b/hugo/themes/docdock/static/images/home_bg.jpg index 1b7086eacb61afe9215eefe16240ceeaadca0676..11d07801c4bfce5755150611695f5b823c5dfbc7 100644 GIT binary patch literal 20037 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 Xa)&|8O<)HU1@ijETgLzKqu2j01n=Q7 literal 204942 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%0AkScjZVo85&S&&fLn>7?y zF~&n=B71%SdsBNf7jxE2R@4VzE*wCkZ5sic0qlo}G8(gclQ@WJ#Vc0d+idWX55%y2 zSX+*4RbHtqa=*nj40|~eD*F6ZtLu&B%hb5!*uH?kpv-s zBAlk>H;t+K)%)GRr_$xC=Gj}g68nqa`{Z71B5F&0*!~AaA1aqBdKIHSr}$ZCi}Y6;^u;AsEaYE)p7R7V6QHj zXn@hHTwFa(Ks7hgsV%(^WqRSgp;2Y~zeLdC zTYv?W@4FQ&yENFuFS%bQ*Cj6$M;9&ZSJg?GPeNB+P~@pKvXR)&fK>uZX}~` zIE15_<9miJxYE)BRx}r5pdQwW_X_TO0HLNMSmZkPky4r9bZ`MlZBrz=!DgY&wP)|n z)@IPIgNTLJOLQM~dNrh<8r0%xIFo5bj>oIUuSEfiD_^b$CA^pQ<;Yn*PqPQI%GP~K zYdNDPARgF%CPW2t$Cp|Wed?GKkgVAA;nCNd@)b0HwMO>69>sLu+@hhmN@Q@cc%Ui}o4agp$GIUp1@saB!E*`%>6dS%uon#aWD$Vk|q2}=6L=ECOis``RQE=Gs> zWtEIN0CG3Tut`GcR64$kH{RfTeBtHZyf7LTBK?DY9*S45l$0KSmhsd+DEVDr=;-jx zZ|p}or6mh!^g}$W0-A?93O17oGx^EuXvf*ZuH-s%zF74ad;Cl)ou|J;zKZCkTj3XP zyhjdnvMXJE%D!2+XQ2ZxFK{HR-UF;JIOu^LEUPae(aweQ<|3=?04O5d#r%+DcF%e1 zPem7Gvkxt~IyxN2df#8-rqhqHRY~AhY3naU_GfO&m5LFE4j>i=GdFOzIZHm~xEL0I z<~G<{bZfQnwn5Qd-cw}~rJGhwB)4G{n5(6!?%+l7w_mH|$-9o=eN0sJW-eKuEKawO zy1jR}OO3{%2iWVfO1zVi!Hql%FYN1H^)A$_MFP-d4t_*W1!qkmNt(3;<@&yJZ%Lb> z7jpB%XtK586F`DeqD0vns2>^oJk;_6M0A7MJ6RzpLi=H+FfF*khGKsn+18@{kQ!)_ zLrZrC-1A+ws2hbV_tq-yp+&*)uyF(PgA{i@E9R7Yc#3;XeL9uNIMen@p|xwHPYgP- zqWdTEQ>be>+(|o07MtRd4va=of#?@bsoqc3SsI|W5%3_59B5@wOkX&k>J?^T3JeTQi~Yg^|*cMw0KwDWz)Ds5dy-eK3O!1FkV{H|tkDmx7I=YxcTmqtza1t*RBDg#)d zE#o6p<7vMrO@DU*Cx2P-(wczOApj}+6zc@;wXERHk%vH3aHx^LKL4oD3OSp_{lTN> z?0j60U0-4~5YwXlNBrL>p*OWV-x)?VumUZt$lUHZ6Ql$~T1aDbGe?@Ty`8*0L~9MaFMMbp@&q8!wg z3~*UHOWAwJDv(~b&B`5%@8Z|%l*PG>GDGou9v?WWo_1YK)6DTY@+cU3nWN<{b(<)5 z4tY(~Fu=S6tizMR6t@P|tLVDGZvooD^bR-~7ztfTlvXt9p%E?Q5WD-cO^W{Q>POgK zbHcW|$Xxp5b^aOZ$OGpKw^zj2Szbh+mX;~7uu=O&|JO@V%}CTG9&0y%;Pd?p^~9o zMmSYR2{m7`^?$;```PFBZ;Kh%`n?IUh5uG|>%p)14BRg-EfdO>$_(?t_IS^?sDJ7l z0kJy~dqR;g|6;(a3o=tWcdjyt5TQ|rM}1PZ5((!#?*F!F%6q0K%AIYduV`JCX2hiu zYb^KW`4I>PT;`PI7+E5w_eR8qFeTj1>Au*wS0YeOCP%2etFmkywAq6+ zAc#B9)sjTC7fq>ba$l%l_ZKtndcapaK0l|B6*|`AaI%^O=^yK!=mcq(Uu#VFw-W`= zfm@CYM>%+Hb8Cqr6&}0r__^`GbMLR5dsiWdsTOFbLDNZ=vay3Q5%;{;sPJy*o`*GefNBQ{&dRF zTR@^pc>>t+QwRXSxs0|w**<6XHE~s6-sVGE?V=4_XeAXdK5_Y>nh}8IR~L#JRttYH z=rw|vg!&YEl11Px>U{>8*ENb4+S~I`XGe1QJ7W@h zv)>Z_FnUrkX3-4y&(0b$+i+k-cg&5huAW{KCom2%K}8_Q%klsVF*T|4a-WkE&xEos zkjHRUEzbtUUraD4`?GN93-YqfIxGD41WZGu9UE|u$*h41IWDyi&E1ivTQk5}OCyHB&(p&bR(qZ92hn01m#$L74m zG63C-%uZ0r(Gh zm!5u4HykZ0>u1-VGBJbDThX-hCMRR*#A1!T)`385!;adoZK5h!`)PbOFGp$7vwh7< z`O0x|t-Es=%So5fmQu)~WBKOVf<%oYuVk|rvgWJj%i2FR`0NN&g{?W#HBB$8# zU_YB*s7?stf5aQG`ch}rKsb!#ntZM!U+xz|+XBvf#nV{dUF^N8S)2^%r)A!_XD4Wk znq}{*k#;=+phx=>I#wa~J-x>C;ne;x$*QSNI6J@;eh!IbmXvGjb2jf16qbvsz~aoY zl^UC^L8VS^;>np}vya9gH8=UA(Ss^7#x5*&-nSp>yCVTfrAge3gMw8w{_Ro)LyUZ6-RmpEE);Z6fP%3n*YBW z#6*+1522R?f?Y8_Y3k%bW_A@QuhJ)BFTdN=lP~x&G(LARYF;{{K!J@D;MkO780s`K zfqiYt0OZXYAL^@|4g(QMByScH_5CJIA>75#_P}|?^GY36@^UTe8i(z2bjt!2y#|e~ zRGPf37%j6g03r#dOUH<#eQ2tiI3W>X#(!GjZZWRQy@lFhXKlEl^SM4MlbZx`7&~(s zxZ;gNTaFa!7e?e?Zj9s8CubV4lowJ}fbnqFrS3+mxc8zM{SPGZLTK`3*M?G}@kFUl ze@C_Q?RcHtWL#TvS{KK^5nox$+F*2ZNqS?igM<#Yy-a=(6eM@>K}#5~8C6 z&g#Di9<5j>JtLy-ev_yHVm~4^z8iR8(~V3EI=QZ6GB~BQms=`u)>=7H>PnHuG5&g@Xv*tMOjymqWXa@ce(*^vokLyMB6n$WV>tzYMZLuBu1x+N!l z$cle?W_w*{@pFC8u=3!`IZe;`A_O)P)3Hs)$N2ox6lOawC{d(5D_yhUEjH^)DQ<|Iyz%|uCay@%mMC`_ zjOo{dGB#lqN+-EEq9nMY<8S2|4y?KLV#eVPJ+n`cTk%=K+-;w0qVqHX@d$&oMw^!1 zbeRk(oUD06kW8uuD!Q$cChGAP^YXGLYHDg&(M4s;6h*l(vqj%*acxNm9_%UrSXjl5 z>r!?XaH&O0yxazI`t_xO;fESmta9P{Mi+V|fewT_3G2j)8zcSZe0pH>PF~;>B&U$O(i+pk2n%$ZTg<%r#*$BG{WD~jV(-)OM3Cn zGZsf*@kn^vk8|tDai^G9`#Ws?@Jh#RO*k%Byalua zotq)yoC+qLJkahrKk}YJfODVr@6&C+%?3;UY4YTsYHC-MA`V1HZuUffoiq^?EvAYb z0!G-Kw)LLrT)_=wT#K5kbr?qYLk-dhKdFP!@4Upzd%1ry0Bm$ zDQ3LSi!NX^om$I3DG5D{7SU@0T8vfyM7&5f-bJcrLOC$q{1A6G#dY3dWn5(LIi;LS zxGKVlxm&c3jt~8~fn*bE-1*XCS?*rI5$aROi38sxR;=Qj5Uvp1OZ<1u2`$D=PA4tS zj7h5rpu345nk?SOFTWSmx^L&`(vGhql5(kUlWwlO zALOw8@k{#z9S;Nnsk!qtaBm5EEyhVz6+rb!m!wiQa@@KqCf1h{`?JD2{hRPWDf7}q zFn%osZ1(-sYJkPp^)}hK+D$e`%Bg!X<7^N=m2C=SdF?ulO34>i@ z9gwr+65YCZA?NC=iszdQg$o9foaY=OxHtX*z0ajMyH>Z$ZCRH(zB`v@IKI8DTYpJ# za)K9Soi!k3jJmTPKfM_9q%^bR`<_v87jpm&dQSXe!vU8-oT_d4Qu!@Spr-chCWG0j!5s}z^ zuH{5A%H#fbXK+Ft^=R1UO(zYEbcI}Pj3p2`y8TvDI%2x?FwDZXQ|p6eDm?TcwmNQ| zOXE75#V({c{dhtjkz)%>wFgD&3MYFkmm&)$D+X^*}elp&(5 z>q{<8oC*??q|ZQ0gxCV~+GswFXPXS{Lkwq`{N<2u>vVJbtJ?=_R{bOJ$0(}c^Xa@0 z*}}%N*R(KY6oq_hJN@HT`#ZA4LgKi_mk;L)L*$2sc4Wzoj*UtDu6S5!W{hKV2JU z%jj38FH+qH(J}TY

Vo(E@aBQ_HY2A7umd`KEGuHcvUJPO&Wr$Bk*iI=U{#;h)m+ z#^5WZQfee#*TeLIfx!_<`Rhuc6Pkt_8socBFmPu5`E#2zPKLtel+fGOK72=nAbhk- zwu_~5G%{*5g@s@8{U>;9M>6&dcdYO8XB~R3KE?K+ba3P$+@Xk(3@Qi-l8LbN^APn} z)(+>q&;}Ag@Q9CWOJ&C5fIL}TlCW}Yf0t;AIs$9u^)OZN7~RYfSdJpj^MBdfp~H>~ z5fmW=GN@7}yjPs$T*l3_<{PUh>=1b(=7&CN-L|V3iNc|OyE8vh7mG^j)tT-i9j)27cFX9CwL%3_bkd7sw)+ z)_*A$PJ%nw&4h^+qC3SKWfE;7gVQOx-NI}gU1%Cz_!)oc;r;57Gp;`^@3aLdbRtU zwj{Qoo$zlGKql*e%RX&!Iv^2l(sI93@xY;9N+!;X9Kll7hPWZ;uCS^y@NLTyPGUQ!$_(>h!;Db(8qi+5*LLZ=_tIw7exjpc}x#R2Wfk zMO#Nu;OvjwvH4R@^EQL4HmX-Dyp!}-tjjqiOC+l_lGzdWHv@6i+4q4Usn>xRcB(lz z#$~n#esTHx8aTp@$--I$q^jM+PhD!+37Q24oAVwont$wi_HktuYaI_`CoiaCOl~@9 zN8PxbeNeh}ktQsa;v9rpFhxtYH=0yVM}_SckepFHY3@L#>={=00G-v|oY9YHKB>PF zX5ApI0DNxvKN-Z%9GV#!=21h#h4Ga4G$9haKoXFj=}zr25lifo*-UWgA{%v3f~1uYq6| zIRFqSi&I0}lfXc49``}37CQTcV*Cdf z;s|njOKw9!Ia*WoD!>@ztEJpq7J}Td`P}>LK7?yPp|51mI zF35l#613G98Y7RS#p7|{VZ$r@g%B*FBZ*@yjXn=d8@;v2KT8#fIM9**d))KAG5bJg zxt5*JeS4p)rC{8CL?#s`GByrv}9A_T4}fcoyp;~SQRBk0%4uVim>dZ5V;VmR|R z5<&o=<$R}<3E8_RN5dNGRKBJru`MrshM)eeXg<(xtXwpGhO}L2DI&g?o6A-DBdthl zA#?h&7APT=y7Pk(6pbkGU0cI9eM+vb1hDGeLq5amPJ+e z2L-V00Cni0wJIy7D{kQkH6qm2Y&BRQbdj$r9m^PJazQ|sB_E!HC{%bi%dnEzAsUeg z<`&GlC81g(25sy0ekO7-h9jai298ka_NROG(Wu)QKn1Iu*V#Micbd#WH<}vBD$M+( zshKFctDm!r=53AY)keSCJP_B7^ZW(l=PNZ~TT0`5nWPyew6Vz^4+Xnk9~f5lRwXGk zX)TSUMcLNx1&2mD3pi)v`#@0Ck=(kMJ-iNelR$EV%Ony-^a+nXbw5&5fM0G&eamtH zr3o;2E3icwB(GA5TMB5g5W-Se9(bR+zD>H!DWTsoF6c%k$1_0Cj()qT z!p!|TOSQ{yxvO1SHdfEot}_{Rj(zMskrA4a!;P|#*FZNIJ~?jF@L#^%{wx&)ifnMD zQw1%n;yO?hjHHCHVpVgC%XnY_D0^>D!x@ZfSxffrR8Zo)F}5plyMf3Y$}>1KFD07bIlmYhev<_6`zRdOLh42GH9 z&!2Yi#n}U>sF)&ozpE|A ziE>yz0gK|V8n&3}Coud{Dbz=g-X_DtC^I*$d4_d5r36lmwnd$t#3OwfmE&a>b++^9$28-S>CH@+ zGK77DKi(3NQCP$BdR<}{31s_FewVOPolyT69472O{9%z}^S=!*7W!UmIB#6b zv0c1%L98NttQe6O9(s*~4jNuw9UsW9O{E&%_Ml`^Vv3zbzp7kClrtK5X-$`+9H;(uF%Bo2CDX zI6PeK7xlVi=ZB?1DXdVCwhJ3n=xvB1Bh~WKXN_6%-~*sQ&?Z8neT~??fu^1C7=D-o zpyes|hqdnYJI?DIpn<~6rxbu`e#>2FVZ%fjg-E(%9n}_pd+D)FPdojc-F=H-UNDgh z4iEKYwGb2+dw?VN?1~i`;ND2>mFBK3SbHu6T>xf}jz62Zt1Z}^*U=@Hg&J_jS`_Nd zUPy7mshJ}aZ84u^J>%@06~(^X53QWS{WDPu`yufOT}K^TPLfBf-2bXP4@Q>SfZW@A zj%;RzGRNLbfuj0#^c!^%r5K82Fdj<;4oFB3qzWFjc@q}Qf`}luLa)c^cPb5*i@X?4 zJKRpIgNte^{PP<>@mIhu-H{4DvRh8cEi}TU`=!r-W)Z9w{0LrK^pHMx*YYX-kG4Zc zZcq)JosO1+Vak3+e~)1WA0*&=^|LE%!)tnXxuAy6384H14coh0bxtrWyP8;*2(Mr} zksSd5h&FOp0O*wlFa`2p1$@X)7HRCfrGIEnMF#@O*JzTMZEI4A^af~9(!rJuG*I0H zK6tni?CiVYmdZN+Q2WY*4RJ%mO}!_#Q0Hd4xf;YTW_&gHY(>)Y`2mYZ=hWJiCaYG! z=fKkkyAlqnW^MSb%&ojSh@}&~)?6=eaJlUSz5l^D+9jCQA0sx&U?}S`>D&FOlhcbC z=aFT;b}<-;s2xVh}#Q3VAmobJ#k?+24WO2~Lur zLfuhQv*xnO0qkurIWX0Do+V~J-=NQ1&96i_9I-cZh3U)lbe}jtE9Qm`FJ@2|o&l!^ z~7T1-5q8^@Gz{-`|8{a4@ys6NsQdW03=N#c@fV%s)u{~d8#!3=KCQhyLmim9} zc&UFl{Ll&rjjUaLY0=M77MaqkB~Mu65#LFC_tVSS)4Et6`(nn;8j-in<1MnAOYe4% zBg{Z_^Xg>oEVqoD0?i1*GhYUQOU53_S*HiJ2u{?3KMjsuoE**tsHYD z;IW123!!8~3wk@}wte~l=NB%;HD-=XZy1t<6HfqasA&!-r;<)yR(z&+s0E1_9j@?% z1RXfBT-3?(V$>4qGhQn3kV|;}Kt=ernrjb?5Pyw)6<1v6*w6-O&})*nXW1!&K62hI zzy7cq=+&)x|5#L8ovLI-vMZ{Cf<#$x>)7SYMc#CTI^u+eL>758!-_Kg;!3q^X7N=v zdpG=3+}ux`FW7T7k8?=m-&8;)p$*`dR`1#Mu? z?o)(}fw!WNblGNOGt0Dx6XA^c{Ygi5*Z<;weW|&s2!vg)R;4CIGCatmQoabj;rOpA zDve)+QpG8e$W@hAGAqVWQ4>0x0YK}L&$`F6A$?{0nFs99Uo(_+bBHEvEgsS53o8qC zOyJ*_T^W?gr*1J7-!ca@d$x|(4hi-oSnqItD~+MHp3E0XkH3Syr(q50B&P7@8em?z z=-$|3^cPK+IXd*M^7CWVjs9ne&WNL$5RxqL*qGse4isB+R6lkU7x#w;GH&-Neozd} zvxe?`eAOnw&^@;DDWYEf{A({}e4Jt^SE4egy=c6DlVPNEMD~p1@UuF&%?MU9%E@+B zq`fkD^X{%5viBwVb^kc;IuLuT>om)HJr$jGqa*(p$%R~RtU1W0p#+Mu6W0VNQ>Wv5 z&{0GJ^SJNtYaLLatZ?2!=blVE5OmPC3S6(TmXRhk*x^1K-R z0zbW=<-^gQUZFhh%9R~J=MZ~;B(%WKW(?IG*Jh!m?M+0!^3t<^7j7(H#wN{OT)cER zt|NvVt^eg!=0Dockq!i2C^x~r};X|7HG7O&)-Xm7W@dt{@r1b>Nq2ZplMs1 zE-5=(hYV8hRCc6sq_T)a!?Ca`w%2mLWLDcA#5I6mc^mhtnXMU$NAoi^cv>Rx^RMeD z<)My(qRtO9RexNLhKXudBSh?_E`-KFo!s}XSU=uUzuq>ZS#P-qAj?JY&P`)YTNyC{ za?=pfiE~ogPTmz83K@)kMnWeRK8iR0HUd_r5m!KapJSkBozY}<<>@bhxb(DF6hC*3 zEb8Nr59j?kGhAgnaD&b+@>wuZ*CMr{c$$EVG|(b6(8&zLV`^vEW1x(eP#; z5uZeAbWiYsbVsdVD9u11UaG$ucC}Xc7pUGyyk2Ef8h?Aq(M72KcZpRV?K)ina;kTc zAIkiLY8GR%>Qq#AVEFO@Jr1*1hmEnh%dr=TADm!9GO#$ zZdb84@hmx>nGXgEN!gI!0h3Am_;8qVvuaWFB=drqQL7#YClHs~Q1)VmVB8nJ6$a2H z+7qTm)#r5+cBnWSd|zNQEpZqF;rVpTn@q-&$Zk<);|inG9Dkrq=X#~o-#PxXtymKFL2laq1szw(mM%BZU_E@(#TAXp0iJlIAnHwVzUE@o6|3Etd?M^>rW2}+& zP!cSW5?VLLxb?TBt+690M}E#Qf_@zV*&x99EfZl(I$imO*bw3ArIEWT`&^&RyUzdq z#S8>Ur}&dhZ)m!FLo6Pd#$Hb0<9frJ2_lbSf2sXcl)xlHgg0aGR{ig|Cz_cvvAacC-T>}K zb+O2SwQZt!0R}#MC?f!u6;rN)*I#LryD8ylgzp0lC-*%$Y={_L&qK*I7Zx98g*^JtlRC%br3gnX6j`A^K6f6)E*#{J5fk z^TV5ZKKc419c*A&eKkT@DrB^7FF1%s9fkevJyud6A{hrgSq z40A^I(TB|~k-EBBwl&v4wMv;EtA8CI>u2{{XwIW`FF@fV@j9XUR}vNEmVznmRRjeu zmJDZ%BVwqH>DoDNU$B8URycyS?w;v;$Iz{bm7;44I6u!bZ&vqFI<^|DE~2raChDr+ zSWhj=!y~)F_AIxkt#O(#c!Sm(?t92i0mHlA7j@I0BNXv!(3;HpoS>^TBN9ha0H@nS z8q$Yuy70yAoCB`dM^VZc(ir_@A2m@HHMdR)=(U|0mWI<5 z=SQ=ztgY({Y@Ee#{msZt;8`LG&^6=|`~cc&IZM#9=5Lzy`cy?E2{14`E5k-6x;y6P zzJ^d%gxsigt|-gy_)G*xrf2b2LO72YEuc+aDqPw4>MC~MxtD?kriTn88aRf$7||P0 z$Rs{+)9N@Byl-xFDJZ3v(?hA9J3?0ziN6m&mriyrt+~y{iLcSnOo^#MFHeFUMs)ez z^!Cu?PO>bfMe@&_xNs$_FUB2$P_u2l#~D4@`AOM<`8d7dXX-R~bCf#mt#&N<(6{T!ByU)>up_t`X`vAFVF zasSCeztYzLRF9s+_eUX|Z95jqGw+htBZd95Gz^pxb5>AzdR^fWHk_Zc8J;gGYNGT{&`&x4S(*sq2K9YZ#frS{3$QX~u%o>v93W#lc1vhDWgwmS+KYl@@HHiDL} zv;K{+0`6{1lEI^<2$vfGu7Ir1CGi8%R~hO3bn4kO@Z#XTf5$#mHwAC&{|td|1RZ(! zf(7-X9BynZ6iYdu-=?$ufjocf`&YtHwpFiHFWx3?pU@2ZY@en`a`5<#c#!%;lEfbY zruR_Mc$s=JfYeNi2c}HtrMAk(;kF6abilwzidIy>`HD}ZFD*{UIehRSVuiUTDM)nr z{ZRNm9|7-xI$w-p<8$Kb$I}O?;Catjm1>NB*gcAWT~Pmy4%_mD^^y+-9>()r$J2 z2NbMsV|7c@ISY$@U9Y1mNhl7YY;Y0@IW<&PY`qDm7I$RY5~#X$$p*L0^2EQP=ttr@ z@NC+7$PLC-fAYT#BXz*St2bliaf5!P?o0PeNfOGA^iw$xl&Mft!Hb~kNu7O zrbh*?heTx^z2kCE-{D`MP*vO)-KtaOR<8c`^WFO!b-+CE$m@9J4g#nQstn)ZDe<6% z1gDoncqb6n33ivn4JJL2=`yr{$Ll^9^w&&LYskd(e{Ac1-9EX|_Mu*$pSN07^#L#| z1d>o$$RB5pqeu)rtWM8FLP&U4QG|C}I5aa-SFvdG-0>5C>H87H{l2GpH|U}_edN&M zPu=1>NmqHb>rIc?V7}ntI>D;OAq|?nr3EHDo2C`HQqK?QyGs2;evxPN$jeg;!o%R1 zSm*s@3P3H0cg~~$S@L&O?iMENh!%>sfY3C6&-AX6SxUYyp`BoOlw?JuiBuIq9hs=t&= z^4Cc`oAh~uy2I+lmO;wye4QSR<=DI3cnWcw!YL94$v*LKh%IQdnG3p z@p|oQ1f2Pj^^OQ4gpA2|-#Zo?p*ShIxAjbyuVz+mWgdj;1W|LL-`x4~-A&6NE4+UAf{Dy0Xd@{!7=EL zSe^E;;rL!|%^e>Z(;1cl3uIt?H`Z3KvrjvXO#viTOi*d68 zJc1f2fz#q}#@=^hRip=RY)n>Tt~ej-(+ZRe@AkJ5%!H4!Y0L&R04RG}&LyXcqVUxc zUs&f`$A?XKv&9+UL&b`Sx3itLtb^b*7aErcuTRE#!p&X*crBlNL78vW&HM4Cc77Kt z+WGP*1U=#-%UhOu-&nU&X09zRABIPyBoK49J}L80{3VHZ_o3EcX{h}mU!eV15S{5W zs2GPLe5rh$YmF`;-1PMXwoWDEE7b6y7g6vC;Bjni#O<*oE9*3cp)&o`DcgFn7}=qX z-iWyX0I+e<+gX&{@%6|oq!N#hG*KpYgJN){y`;1)w`^hni5=-m{$0B&3{8dp$10Ml zf>zfbDLA-f$bc+HYbP4Zox!r@Q=Ta11Gq&L(<+JBz`P(<$O%KPR0Frgrrjy1bqMMS zDZWhmrGD_j$ok_ExX>Q{`Y%a1`~pWwOd0H8zVws&OYxNx^4whXlhq6_fk?~Jg7kAs zxz>XS!VB4>VgTn)ZCX6OW@=c6?wjJ<(u-=%mF>$ZJ(CfKOrFn}i^*=nur;XA3Ixf$ zs>WE~4kn*mpL_MZrl3`SbL_Bs$+knP6)Xf@<98e2Pzmc0pf+Es@JY z+ZvQ+fgG7tV2&so=d$Wh?N|;}`4bHm`{~NYueh~zRZDsG^)%oZuq)rHs)3DU!7rOg zHuSiAA4Gn*pUQt=0M4;`G^d%1h-S|M7w0NL$@brD7=Y9L>ezjrf3f%){qK?h>`IV@9MBpkI#0C?vS3#mz^G%@>VS0lK)() zDhWd{ZBXgN3PG0VPBU;YZAR#%%M5gPm7G^ec8z=hc(9wQ%+)OkbEY5LCgwJQdwl!1 zJRsL@pZy-Dd=UyeD@DPBcLxCpyXNpn-& zQia|*>eNLW7Q^{GTWL##y-Ak%#Sey2~@%&=5hD3f!|V$UnhqQ^?~eRg52>Nc{< zz$8Sl<{dKncJUkful#G<6gxkUu#E5k$yIn6m|G8oFLN4=AA*2$qaYF^5Cb21W*7rM zR{TcU&4F>k5~TGt-|a6dep2efSNU@YrZ1gjTyQX*d+zv;COw-rkHM_vj?3clWWf@Y z0!ePcbmlhqp*-dOm|W8#?oR&K!RASdUXwdhvU;e;O)sv1y9}gutRfES!kspfZ5f}P z_>7i{-KR$iQWBBt$Z$pStCj&yS`QX*AXR^L90-O%KZpOOVJSD20D`}ONst`X`fog%u1f`u;TGpB=4lj@K z9m_$+(g$&;4UKK12vBo7*mD#bNgr9eE*94lDTZ*D(7W-5EAPA3UK1T{?@bL}t!64Z zIqWjyVvOJXubWTn5FnjRt*dr;RMyHwXk<+KayQUKba2Ks`W>5dqF zJz@cM@&lieKuute2miG=e9X5Xl`%|>P_>{g%4<3Qq? z2coO{Btt0n!b-RW(c|iqNx3Fm9@)|!)x~2F+ge?1GeFfG9%bFiVu*iIh`BSZYE*>d zYR?K6Q4*%z3~cgiL)hX)kw4ht2+6fTq~t?gfKf@6rPrdj;cZoCFVdrSG_}^liYN-J zNA6;v)jTk(=Pch8bWG;9z&zzEh}aD*cs4CU;jp?cEoiv8J&J7<#%+hH+r z4!!M#ig#4YvjcqMuj_d>ZEIqOSpY2xQ`gireGb4k%X7l?S+sf>z2$olnE5-25M*i_ z7yd`u_rZ{1#A2dv5DqX7X@ac-yt{a$k$-3VghwSY^a_Ncv9Ijg=D#=9iyrKL(wU&E zi(-p7vYAJTtcepAu&QD&nUstRQ4@M?$)x^nI)A-Af59pbB3f%o<$fxNc;p=2^?B}Z zCEpKSLE!86nR*+f9qPJqbOYO3vK{<9cVj_`32c4Xfm5ToQ<(i5Pcbk@c?Y^q+*(>z z^#xI(MXxPxk~j9;7zXunyv#jr4plyz*4(x1!rqNX;D5K68Hb~|VDC%uPmrgSQU)O|wx=bFW4CqfUy!T4l*c1sHuA8V?`0YfJ$!mnEv$4xp zOM8zh8E6gQN;~DB^k zz`SOqi{8}96)(YIM=BPGfKl4G&X|A3cUZx#jhWt#A@f^9R^C7(_itqcCfcP2mL;~Z z{z^UU5>~V^g)?jgKg0H@jv_+a{plKD$+DX&Md6ERL41&3dC@-C4vNMU!QmRu6WHY} zH_{eV2tEZxX;00)_`tc9m<4GH2u&b6<$TUA;L+yWXPh+odMH$g&0-sj91vZ0JQwVK zz)G-jM<&z!+jGW`y0FG&nckoBW*%b_Y-sgFUFeBLBVj$1VBxtte`dzJK^+ z4!xj1)?QMSTdo$Ebs?;mpr!J{@y-YhQ(*qg31&dPzt31o`+s(f(IhDU`_vQlvXYO_M%;}{sN5QT)GV0Z-O!pp1Ucuq zD@UKV+&2hDrST-O7XG_UJBP163d^uJiIhzM#*c2Tx=G$S2R&)!oe>Yi;TWWQc4-}L zI+kdDkj_>%Y)V1LA7nEJ(SS<4ewhTywukl9 zjE6a{6maw+`;BWeoF3@`efQF!V_70laqq*!e^1`>p}f}Kt4b|@`j~5HE1>tu4=M{U z3L4>gn1`_tR|WgxDT9$0jogFInP1uij&NCGkw1h*qJ^8KZt6jK^*QlVVA%gxYAcmx9~2 z6G_gX66Vmj9tlir)aMWRr8nWUO6~|5Pnqv7$OU4(d2PnM`)WcsiXLFwq{%C{s5W;s z@KVS4J0i=I$`%fd9UcfcKYaDpt{fPP=#LGb>ROP~iAQ1CcTcbwYLzE3`<*!rx`76^e6WB?{J8 zpx5d{Fdud-Fs>ZEg?-frG6zO*Up++a5OftzP{;)u2=KDjtn6N%Yp;c7)-MyhG zF(GGsF%lwD{SPw+56z__lYDM(Wamj%yuReY-$geeuLxW2QO^0HBJ8j4aVx9}>x~$x zx=G-V2&p1@vkQQe0tRrhVOw>t0;r37kWl!UXgCX!45`2)u?o=t=2#1D>sm0dUEIFD9E#Ljdk!2QQZs-`F=~TzcWLc?xt&-_b zKp-3c<)F)(cVVx4ly%`c`%&&41raZy3vDNP*UmY=v)*M2=?4%O<^k!ji=UE?z+8F7 zW0PwK5N?xM!IXaHTON+()<@Xc$DyuNX*Y*aea_~H)~i@c=pn)x=+0Q=7rXI zhRb(kh?O`~AgIy9s6@xHcuQq$JUcS>-895}Uv}C|9haC-vyXk*Fo#?EWhnkjMqBZV zvIG-oFI`5QGQ+NKi^>$53Vhr%Ea5$y7Fl@@?L(u{EZ2NGbV%Pjd)pK)<)vii+F{AG z+}C^ZJ;JhnQS30KL$VZ*x1|0b;_40vihU{RsZQ>3*9Wy4B{Z{n3mkVeA!==8c;a;K zCER0SZq*)OwWUG`#>k=42*nl!ab>lWt}XG0)xN6VlAWl0*NSu?{IE-wRon#HKIXzu zj;T8x8lcdXL*g;U5u!Dz6Uyw4kkW8LNih5-(!Vv(%}HKGA7$$7J=Q)ljF-xEVlzeF zo0T7V-x+Iy>Q-W5mEz^x7~EqQ^1~Ox2PS>V36&MRlMWlr-8E?wGFkJLTy}YUC23MuSSP6v z-ykm$yM??T5#90RRnEE9(K16{85&&!NIehiPr<>_2inLBO@(|)lR0{WQe;x9vf!sd z`mgZ%QNoNOz%+&q@>}}4?`MKM4y#waAM~Iz-f-=az$eI>S-#NK7Eys+@~VluSMVe* zbDjma`Jr5STrrZ1D2iCqBib=?ho=m5o^TZ0E3ZTU_@!J#g*hHmNzZCBpMf`yLo<@}&$k*bTP{uV5+-WZWupT(>yYcX7X)^K6rI<~pDT)OqMhQea6~ z(4i(5nG@w*uG1h9JwrE9etAmMPz_z2ng|$G0ETKfPqL8C1%I)4*nEkGO&9o%Y2Vp3 zER!5j+g_(m(TC3C7H05Rt2b>x0>fTl)?Je*o&?6gzjBl~R8nXiU#C}I+}1Ka65XA9 zK2nmz4N<&hEU^M)Xtk}xs_!4Dd%k1HyGn9bufmQg8*PA{?J3)FioU#Yp-N@HWm#EVDs%zlrL@O?m!cPu zJ-HlpC$Q~y{^{AYr$1@%seO`rWrPLHo)aQ(I3kgXi!#g#2pL$;QKf+is0;S=J7?iM z;6y^43%m-X(=j@f=W|zK3ft}I@_H0S>&Xx`*3v)kRhEP-B9# z50P*m&7T5_)}I`cYjVZkPIvK@t%%9P1Z~xBk5H(zeb$f~!PPDr} ziCT4XbN!;K(~j?Xz^bhrNxatbBwRO|u8~=y6l6pdM7*D~E22dm?I(ppF8NiZ$63@) zkocFmb!*olDR+5v&GDu=9Ql715;y)${*MF+$=&cWr`e)Y;KmFWP(F)qjO~klCr(qV z(+_KEFWNqJ8_p7(c#O{v%<1R|13+&)pmUIwHFU6vcPBXR+WO9}@bJ>JXBfp*z@R3f zVjNOd)6d@C!Jj(E0RhNisnJHKv2Xe67Cz7oG^hw$KAhWAHeXKWp>wT)fG)1>Npvn; zo9_3EXVdDUlCBquWyfFQj z7iHFzRo>okE8MPC{unJf@G6b~^IaQVcFg%d+{X^yM{3P&&aFqc{^?_X2i+4x(UakF z!KB2^)Bvks+p}pW!ZAMtd()vv@8rh6{?jg?`UoLml>-&cs@&_PfR{M9G06Gr(F~Ag zpb5Cbe+hEa$A*srHXj*l9EWoc3pZE_HtnUnh*djLKv04pJ|vLEU%R~+*O9QeVag{v zHyt}kS8fnYY^kyl=BkB(%5Byb7FGWs6t(_iOf%`cruARkD6VRaZveDu?Bv|&_>fg&oeoYCW;}3`uCoqi-FA_QA0P&hp4Ri`j zC9{F6^yb$1A0Idj_X&+eB| zrke9OYhRb|Fr21L-CXr#XFnKJh5XQT98BQu#G{JrqJ@_t?Tt|}PPUmIRA@sQvXj5v z>*xsMeP+BRZAWPIJTV9P3fqLt++~!&%Kydp4<`MmY8+s5Q*5_{QBT2q@_i%rqm&Nx z#phNj6hURfgv0RuY4j+E!Kx+{LGuDw#;q731E{7U3DZTsZOelnxuEgJ~tK*V+30Xhn`#!W;CNA4ZhB6P1I&)o^a?*(`d3Y@qZx$U90@ zW^h>6W9Fa1v+KUUp0SzrA;s0A_83*r*L^zZp}F<6AqhVmp%HH(6~o|Y>kiy;q=Wpt`} zUZ424i=qq@-A&=kDob1Id5bGxKx&1Evk*%XIt<}Z5F7<$Y(;#CInDBCd+vvfr*?%& zA*Y(v@z`*DAzp|LGrB&^J4!5{ymjdIy{=_>X``y^QOzxB(DRLIU-#!%vZZI?FB58l zQ32!PxdPfM{ZS?mw~alol9BpCane<+mBuvf+rIbANbZ%yPsh*`G0TyaCG#`k-VK(m z+^CQbjzkC9AN$^JbX@IV?CBS@aN;O>;cN>%12Dvi>FJ)1+Z@Z8JCpP+D%N3egRlrL zJQc-g;|y~=>6J)}-q0l>Vt@#zmKMLrTLd~sE<+Im*vBIZWdFo>TP62$o(6-vaJ22>s4UR1n#b$++QzQQPBwS5a(I;@^!8DlrF6o>NE}vP>3LvE)^U!RA!xpHRU~;Y!~49E@05Qmi(_e&9gANCc~5!Wz+kotk6UK zyrW=qF22E1BVq=OJI*4=5+s5ftQNkNGw;p)Qs>rfJD&2&YRy~;K-$#t-;GD52QcZk ztf={~ypwu3#5i8qljq$zIpM?iJcy!cZr!vJN$2I1@fE0*f^JjDu>mn)6FuB?Rg{sB%?+<2&~g>VdM~#gdqft${J7` zB69HtJ(uWLvg0uTUw!PMZiQidR)}P<%NS#8N)RpOag?-9ymImUoT`oy49ckz6`$jU zkVSN3eAE1R(l&a0fVWvT^W{9?G`{u0$P8qS>jZoB`K$w*i4^K==V1?jB(^WZf5;z{ zf*$M;Gx4ClQpEE?u_z*>xn`Uq{G?j9&4fqzk?t3)-w8x1rV$x1WUB_aoQJJg!E`{V z9dx4`%?;W*5WYAe0inr*Z^?MOljQ0@&M1==jO|#O3`lh8D-R;`ZXDw`ZJ$nso6XwD zSaNWz^4E8_qe?43{cNQo_P$#4|Mh|~d~?Qo748hqqt9Kc1>uj$#*r-@iq|8n1*3Ch z!#!#oCgwtNU(_3We{r(aOSLFXFWQxzi&}F>U)=i)?X1LY?HT7vcL=wC=EnhXrl=3i z@Y`*&y2SBkr@A1-<7tc zwn~TK4I{SZ3R2_eoZ`Zu+W7)_y(kKAhj)e^SS8ZRF_{&7OJ?u(3NU5HcD{9i3X}%n z*#kkFT?EAn)VX4|#_zotb)rQAif~ymm9K+p@bxn1Gj8{igr&KczSVWckMM;3tUwH! z;o$w!SU6?gB}8Q!=e!TGQE66ab>Bn0+$gkmo%&|wNmSLF+?D1jFyczDU30;m1XKzB z5a{T!HK_Ht&sJ&(c7$*|2y2OLMEKeQ%>5G9@aR{Rw7&5*+dMRJ`1jU^2I1wW;u5H4 z(S5QBi55*Akqg0NsS3ggFNr1|>W_~@GWF3+Z2f3w1d<#_JA`2e{X5=GBY@nCy#M)K znEPN30GIP-KPrfyekEJEW3a!Kp27d&Y5Netl30Q4S^}acgMGY?nsI3LL3gFeCp&JV zkDrIM!zZb_6xfnvv#)n1AR;%R9ui2OCjNS*B(<6*7isp0UfO6fmVEw&3c|`#dRe039|9 zBFCS$2(BzN=Oae16rngQBhV2>r&auu6IUeP*eF1!jWO+x@3A(a7I`ZniP*Na99@&H zWD;_q!J-*XJl@7QG$-llb2)hK)c=MHvONTwvU3#h0SnNeFq%s{g-|>Hq$^rN*EI$u z{}^{gQOk>b=Jz;XBDRI48Tj{|b#6qZ^^nFC^-PE=vAC~^hP+Jl8yGWWuyZy!F@@knumGFF1w%O|p@+-L`*6z?RG31b zmnu4(!9RK9Kf!BHxozt7-h&MYw9*8y^yjQiquOcA;txz6B|KKaWhUt(>^dcXAn0~o z764)s+O^={7Q2!(%6AVa35+wTHr%pziRX6=8>(=dtZfhGX3Ji2O|Cb?kTCfHCU<)g zRO=#0`XI&q$%);{prWWBjm#UF)(+q6k*{wym$P4o>?0w01ADA=0C$6eB9B}t3m5p?=wa9v#i*)1d=@qxP8Hs^J(XLYtd6N{Rs9t@) zqHw=`y_h+;=!T~BPJ7Sh(9VP$%}NJfXibdYpJsFQ&p@OwB*{XAJdVAxO$j`z!I-T70lgw$5eAa8Kel8_-Hup=rL z%e#TN%lOp`bANaDCHz8`;sVsG;S=gua8{=ccN4MOgUR4{w=%6BQ8Z3+u90;NS+B$5 zrIoJI#OVdb2!C2fXJ0i}Sl_?U=mEhv+GG@zDEfm~)^QqS>nfNA_3QjE2N=`Rr^ z1<&uS>fAH+W+N}Z@O&)r^HKhEY()V)xpY+;bJcNUGCQ5!^+Rt-Q$Se8S1FCW)v7YK z`JmiT#}{c2xAfOuB>ftPM)aFLS~QuZ+=>oOjBY|J;1svvT(q~+4BJ()L3~nq5GNuV ziglVpY*Ie^)T;NYXg3<*9p=J}$K9Z2{#5zZ1@=#)A+y!igh3l?%_Dy{C zQ6H-E7-irsog=EmY`Y-!mKdV~v{5;T1r$C}VHaamVn();r95a)Y=6x&qR}snSep)$J5%=YoNa3UOibBC&J1X_OIm{w zDv_J=$zbDpVixC~O{)O}hYzoIS*~|Sd%d8LzoF2(a|{^`8tQnBd`L`+<1g7ex6nNR z=@;6+Lf;0U59%ox6L?*Q&JJ4iu{W-F)*R!1aU>Nb{Q$c!loda1@#N^nzjyyjPuT#e z7v>JDfs2MR!p~@`-sxNJcMrp+eaMPBI`{*pN8PU&?jX%eI(@mP3TA1{?3*d|*-|v| z)N9>x%jCn_fx5*P(G)nCEst9c{jh{ld2m_7vLafV0jwokRvWA_csIiEem;pu$elB1 z*&E%P+{tr~qh+(&3~l7}pRLQ*K|9$gO!*nLe+l9x5+a!erN*0YXcf#ydI92K9-c85 zFGsfQ@%->;%`u;E;6WX+~GM3#_opa1r1gn$pe(UPTG}~O@ z6LYD~%8t$^m(avDd0D&tXW3NE;3BpBOf3|m#iz6YbgGfFYc|-#c4W@Xv6aA0mQAo zmwN5oQxgEHe`d{bACH1B6oZ?QKn{Rhwl%%>(9}dQDvx79+ITn7G5kGdzWa#g2^Ti) zQtjp$6Qv3?gsJqhfsTUI2ctKG1mic#&AM#tU%|>%raH2s zu{wkjdpSny{gvYTwd!{$!JRQndVgPO$WjU__aEv~3ea%e4_KIm)#!zecD^vPi=Yvh zQpk#d!VrvR%Uuo1wBQu9I+fPR5@IZ`5>j*i=^g83A3%Ko>u4EKE%{ZN@;?_VYwk0> zVfmSQ=gJ7AlQQn7z*OfNoJ6MONoeCuKUoSwh;}$p8P&IS$}I=l?_AMOI`L5u-}cv$ za_g6BOb7&voNHDLqUKB@1M7Nl+lfcP=RAAGt;R4o`cAuv+JUEUmjjILZo^;zLlV_{ zw*jwwuoRzkUn9CX-X1gu%G|{fSJ-k0t+;g9do2VFNa$76CFpW!x}RKFh#8{|`*%ry zkbvXa9@+5j;(muZnBOu4*TON)&gARiq9;Z3RDSF2eyL4!yFccGZkS&v|JswU>C+wO zisC_&l(ypkA$$qKN?V*-{?D^6IGW?mT$VqPaN3O%5+f_lY5i`$9<>!?la89j8gthZUB8IQ-9?9UV&(Ng!f84}>$>qm41nxM~HZr>iuiHHR~P>VYmQ>dcWW%t77 zABk%P-)3OoaVPDKdl(*_O>x?6F@Vy{WrT%x$rF$qdB?kkg|NfZnI z#Urpww@WO^y*zTrK%cr(B~X z^b$iL8y)zTNv4q9YrAw_BMU$)I=(z5Ioyev)#Hhr!ZKyh9BT}I8WugUX<90P^>c;P z=oieL1NV5xkaF-C`n#c~uxu(ttH35<$g=mQya6Zz`N#{3Z271H`A%(EN|a$qe>h~t zKif;ahZD5xfQV#L70s_jKOE(eh)bP*4xX}ekWlm?HWavt z*X9^RP!$@|@bc%?YJ@~^VeS>22C^bio$|vQ_3C$|_nAP$vo4mt=; zg|bVa^z#yb-N3bSL$hThUYb{VNzsa}2<#h;$|W3bo^&A-5}>tNgDa~6xBM$VUE^S4 zN=HwB9bB6ZfeN*k@T8wB(sZ!2YD0>uX7&~*fI_e=EYQZMv!rvfi0=dK^eoz*$fv40 zP&U9UhuxJIJTrJ#%^=wrR+m3RfH*w&{E?zb?_ynMQlkq{Ghc`-Sdgo!>YhYRbhoOE zjW&E;aag@tGMIC_eGn-P'); code.next('.copy-to-clipboard').on('mouseleave', function() { $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w'); }); diff --git a/hugo/themes/static/js/docdock.js b/hugo/themes/static/js/docdock.js index d68069cd1..d5c0824c1 100644 --- a/hugo/themes/static/js/docdock.js +++ b/hugo/themes/static/js/docdock.js @@ -185,7 +185,6 @@ jQuery(document).ready(function() { clipInit = true; } - code.after(''); code.next('.copy-to-clipboard').on('mouseleave', function() { $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w'); }); From 8d53e42ed0011773d2547ea04f4a3eaa40ed6130 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Thu, 23 Aug 2018 14:10:45 -0400 Subject: [PATCH 009/179] Parsing improvements of command line --- commands/pgc/cmd/label.go | 76 +++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index 7d0002a8c..4788df4a3 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -14,13 +14,11 @@ package cmd */ import ( - // "bytes" - // "encoding/json" "fmt" log "github.com/Sirupsen/logrus" "github.com/spf13/cobra" - // "net/http" - // "os" + "strings" + ) var LabelCmdLabel string @@ -36,7 +34,12 @@ A valid label value consists of letters and/or numbers with a max length of 63 existing labels can be overwritten, otherwise attempting to overwrite an existing label will result in an error. Usage: - pgc label [--overwrite] TYPE NAME KEY_1=VAL_1 ... KEY_N=VAL_N + pgc label [--overwrite] TYPE NAME KEY=VALUE + + TYPE - resource type, currently only 'pod' is supported + NAME - the name of the resource to apply the label against + KEY - the name of the label to be applied + VALUE- the value to be associated with the label KEY Example: @@ -52,40 +55,69 @@ Example: inValid = true } - // if Pod == "" { - // fmt.Println("No pod specified") - // inValid = true - // } - - if LabelCmdLabel == "" { - log.Error(`You must specify the label to apply.`) - inValid = true - } if (inValid) { return } - labelResource(args) + + resources, labels := parseAndClassifyArgs(args) + + labelResource(resources, labels) }, } func init() { labelCmd.Flags().BoolVarP(&Overwrite, "overwrite", "o", false, "--overwrite forces an existing label to be overwritten") - labelCmd.Flags().StringVarP(&Pod, "pods", "", "", "Specify the name of the pod to apply label to") - labelCmd.Flags().StringVarP(&LabelCmdLabel, "label", "l", "", "The new label to apply for specified resource") RootCmd.AddCommand(labelCmd) } -func labelResource(args []string) { - // var err error +func labelResource(resources map[string]string, labels map[string]string) { + + fmt.Printf("Resources: \n") + for k, v := range resources { + fmt.Printf(" %s:%s\n", k, v) + } + fmt.Printf("Labels: \n") + for k, v := range labels { + fmt.Printf(" %s:%s\n", k, v) + } + +fmt.Println("Overwrite: ", Overwrite) + +} + +func parseAndClassifyArgs(args []string)(map[string]string, map[string]string ) { + + + labels := map[string]string{} + resources := map[string]string{} + resType := "" // placeholder for resource type + + for _, item := range args { + + if strings.Contains(item, "=") { + // processing a label + splitLabel := strings.Split(item, "=") + labels[splitLabel[0]] = splitLabel[1] + + } else { + // processing part of a resource pair + if len(resType) > 0 { + resources[resType] = item + resType = "" + + } else { + resType = item + } + + } + } -fmt.Println("Args: ", args) -fmt.Println("Pod : ", Pod) -fmt.Println("Label: ", LabelCmdLabel) + return resources, labels } \ No newline at end of file From 30cf6f786073db69767fa0f46a15949e91eb0add Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Sun, 26 Aug 2018 19:33:44 -0400 Subject: [PATCH 010/179] Can retrieve and printout labels of pods --- Makefile | 3 +- commands/kubeapi/auth.go | 48 +++++++++++++++++++++++++++++ commands/pgc/cmd/label.go | 63 +++++++++++++++++++++++++++++++-------- 3 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 commands/kubeapi/auth.go diff --git a/Makefile b/Makefile index 23e957bf4..afeb9e93c 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,8 @@ setup: gendeps: godep save \ github.com/crunchydata/crunchy-containers/dba \ - github.com/crunchydata/crunchy-containers/badger + github.com/crunchydata/crunchy-containers/badger \ + github.com/crunchydata/crunchy-containers/commands/kubeapi/auth docbuild: cd $CCPROOT && ./generate-docs.sh diff --git a/commands/kubeapi/auth.go b/commands/kubeapi/auth.go new file mode 100644 index 000000000..cd90e8ebc --- /dev/null +++ b/commands/kubeapi/auth.go @@ -0,0 +1,48 @@ +package kubeapi + +import ( +"flag" +"path/filepath" +"os" + +// "k8s.io/apimachinery/pkg/api/errors" +// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +"k8s.io/client-go/kubernetes" +"k8s.io/client-go/tools/clientcmd" +// "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/clientset" +) + +func GetClientConfigOOC ()(* kubernetes.Clientset, error) { + + var kubeconfig *string + + if home := homeDir(); home != "" { + kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "") + } else { + kubeconfig = flag.String("kubeconfig", "", "/etc/origin/master/admin.kubeconfig") + } + flag.Parse() + + // use the current context in kubeconfig + config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) + + if err != nil { + panic(err.Error()) + } + + // create the clientset + clientset, err := kubernetes.NewForConfig(config) + + if err != nil { + panic(err.Error()) + } + + return clientset, err +} + +func homeDir() string { + if h := os.Getenv("HOME"); h != "" { + return h + } + return os.Getenv("USERPROFILE") // windows +} \ No newline at end of file diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index 4788df4a3..a9f884f10 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -18,6 +18,9 @@ import ( log "github.com/Sirupsen/logrus" "github.com/spf13/cobra" "strings" + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/crunchydata/crunchy-containers/commands/kubeapi" ) @@ -75,30 +78,34 @@ func init() { } func labelResource(resources map[string]string, labels map[string]string) { - - fmt.Printf("Resources: \n") - for k, v := range resources { - fmt.Printf(" %s:%s\n", k, v) - } - fmt.Printf("Labels: \n") - for k, v := range labels { - fmt.Printf(" %s:%s\n", k, v) + dumpParsedArgs(resources, labels) + + // change this line to GetClientConfigWC for within cluster operation. - not written yet + clientset, err := kubeapi.GetClientConfigOOC() + + pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{}) + if err != nil { + panic(err.Error()) } + fmt.Printf("There are %d pods in the cluster\n", len(pods.Items)) + + dumpPodInfo(pods.Items) -fmt.Println("Overwrite: ", Overwrite) } -func parseAndClassifyArgs(args []string)(map[string]string, map[string]string ) { +func parseAndClassifyArgs(args []string)(resources map[string]string, labels map[string]string ) { - labels := map[string]string{} - resources := map[string]string{} + labels = map[string]string{} + resources = map[string]string{} resType := "" // placeholder for resource type for _, item := range args { + // there is an assumption here that labels appear with = and resources + // separated by a space in pairs. Minimal works for now. if strings.Contains(item, "=") { // processing a label splitLabel := strings.Split(item, "=") @@ -120,4 +127,36 @@ func parseAndClassifyArgs(args []string)(map[string]string, map[string]string ) return resources, labels +} + +func dumpParsedArgs(resources map[string]string, labels map[string]string) { + + + fmt.Printf("Resources: \n") + for k, v := range resources { + fmt.Printf(" %s:%s\n", k, v) + } + + fmt.Printf("Labels: \n") + for k, v := range labels { + fmt.Printf(" %s:%s\n", k, v) + } + +fmt.Println("Overwrite: ", Overwrite) + +} + +func dumpPodInfo(pods []v1.Pod ) { + + for _, pod := range pods { + + podLabels := pod.ObjectMeta.Labels + fmt.Printf("Pod: %s\n", pod.ObjectMeta.Name) + fmt.Printf("Labels: \n") + for k,v := range podLabels { + fmt.Printf(" %s:%s\n", k, v) + } + + } + } \ No newline at end of file From e9b941891f6d1d42c954e40b5378b46fdb68c769 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Mon, 27 Aug 2018 09:48:40 -0400 Subject: [PATCH 011/179] Addition of updateLabels function --- commands/pgc/cmd/label.go | 18 +++++++++++++++++- commands/pgc/cmd/root.go | 12 ------------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index a9f884f10..367ee1abd 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -129,6 +129,21 @@ func parseAndClassifyArgs(args []string)(resources map[string]string, labels map return resources, labels } + +func updateLabels(pod v1.Pod, newLabels map[string]string ) { + + podLabels := pod.GetLabels() + + // add current labels to new labels - TODO: check for overwrite + for k,v := range podLabels { + newLabels[k] = v + } + + pod.SetLabels(newLabels) +} + + + func dumpParsedArgs(resources map[string]string, labels map[string]string) { @@ -150,12 +165,13 @@ func dumpPodInfo(pods []v1.Pod ) { for _, pod := range pods { - podLabels := pod.ObjectMeta.Labels + podLabels := pod.GetLabels() fmt.Printf("Pod: %s\n", pod.ObjectMeta.Name) fmt.Printf("Labels: \n") for k,v := range podLabels { fmt.Printf(" %s:%s\n", k, v) } + fmt.Printf("\n") } diff --git a/commands/pgc/cmd/root.go b/commands/pgc/cmd/root.go index 12bda2fd8..10e84e316 100644 --- a/commands/pgc/cmd/root.go +++ b/commands/pgc/cmd/root.go @@ -63,7 +63,6 @@ func init() { GREEN = color.New(color.FgGreen).SprintFunc() RED = color.New(color.FgRed).SprintFunc() -// RootCmd.PersistentFlags().StringVar(&APIServerURL, "apiserver-url", "", "postgres operator apiserver URL") RootCmd.PersistentFlags().BoolVar(&DebugFlag, "debug", false, "enable debug with true") } @@ -74,17 +73,6 @@ func initConfig() { log.Debug("debug flag is set to true") } - // if APIServerURL == "" { - // APIServerURL = os.Getenv("CO_APISERVER_URL") - // if APIServerURL == "" { - // log.Error("CO_APISERVER_URL env var or --apiserver-url flag needs to be supplied") - // os.Exit(-1) - // } - // } - // log.Debug("in initConfig with url=" + APIServerURL) - // GetCredentials() - - //generateBashCompletion() log.Debug("initConfig() called.") } From 444711b5112700f63797130bb271d1d965e05183 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Mon, 27 Aug 2018 18:32:49 -0400 Subject: [PATCH 012/179] Label command is working. --- commands/pgc/cmd/label.go | 64 +++++++++++++++++++++++++-------------- commands/pgc/cmd/root.go | 1 + 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index 367ee1abd..e4a8893eb 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -65,33 +65,65 @@ Example: resources, labels := parseAndClassifyArgs(args) - labelResource(resources, labels) + namespace := "demo" // replace with getActiveNamespace or something like that. + + labelResource(namespace, resources, labels) }, } func init() { labelCmd.Flags().BoolVarP(&Overwrite, "overwrite", "o", false, "--overwrite forces an existing label to be overwritten") + labelCmd.Flags().BoolVarP(&Debug, "debug", "d", false, "--debug turns on useful debug information to be output while command executes") RootCmd.AddCommand(labelCmd) } -func labelResource(resources map[string]string, labels map[string]string) { +func labelResource(namespace string, resources map[string]string, labels map[string]string) { dumpParsedArgs(resources, labels) // change this line to GetClientConfigWC for within cluster operation. - not written yet - clientset, err := kubeapi.GetClientConfigOOC() + clientset, _ := kubeapi.GetClientConfigOOC() - pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{}) - if err != nil { - panic(err.Error()) - } - fmt.Printf("There are %d pods in the cluster\n", len(pods.Items)) + for _, podName := range resources { + + fmt.Printf("Pod: %s\n", podName) + + podClient := clientset.CoreV1().Pods(namespace) + + thePod, podErr := podClient.Get(podName, metav1.GetOptions{}) + + // pods, err := clientset.CoreV1().Pods(podName).List(metav1.ListOptions{}) + if podErr != nil { + panic(podErr.Error()) + } - dumpPodInfo(pods.Items) + podLabels := thePod.GetLabels() + + newLabels := map[string]string{} + + // add current labels to new labels - TODO: check for overwrite + for k,v := range podLabels { + newLabels[k] = v + } + + for k,v := range labels { + newLabels[k] = v + } + + fmt.Println("New Labels: ") + for k,v := range newLabels { + fmt.Printf(" %s:%s\n", k, v) + } + + thePod.SetLabels(newLabels) + + podClient.Update(thePod) + + } } @@ -130,19 +162,6 @@ func parseAndClassifyArgs(args []string)(resources map[string]string, labels map } -func updateLabels(pod v1.Pod, newLabels map[string]string ) { - - podLabels := pod.GetLabels() - - // add current labels to new labels - TODO: check for overwrite - for k,v := range podLabels { - newLabels[k] = v - } - - pod.SetLabels(newLabels) -} - - func dumpParsedArgs(resources map[string]string, labels map[string]string) { @@ -158,6 +177,7 @@ func dumpParsedArgs(resources map[string]string, labels map[string]string) { } fmt.Println("Overwrite: ", Overwrite) +fmt.Println("") } diff --git a/commands/pgc/cmd/root.go b/commands/pgc/cmd/root.go index 10e84e316..60ff616c7 100644 --- a/commands/pgc/cmd/root.go +++ b/commands/pgc/cmd/root.go @@ -33,6 +33,7 @@ var Labelselector string var DebugFlag bool var Pod string var Overwrite bool +var Debug bool // RootCmd represents the base command when called without any subcommands var RootCmd = &cobra.Command{ From 263f6b3676998543539a4a3ebcf66e94f6d164be Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Tue, 28 Aug 2018 12:23:53 -0400 Subject: [PATCH 013/179] Added in-cluster auth, some cleanup --- commands/kubeapi/auth.go | 32 ++++++++++++++++++-------------- commands/pgc/cmd/label.go | 21 +++++++++++++-------- commands/pgc/cmd/root.go | 2 -- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/commands/kubeapi/auth.go b/commands/kubeapi/auth.go index cd90e8ebc..ebbe4e02e 100644 --- a/commands/kubeapi/auth.go +++ b/commands/kubeapi/auth.go @@ -9,35 +9,39 @@ import ( // metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" +"k8s.io/client-go/rest" // "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/clientset" ) func GetClientConfigOOC ()(* kubernetes.Clientset, error) { var kubeconfig *string - + var config *rest.Config + var err error if home := homeDir(); home != "" { kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "") - } else { - kubeconfig = flag.String("kubeconfig", "", "/etc/origin/master/admin.kubeconfig") - } - flag.Parse() - // use the current context in kubeconfig - config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) + config, err = clientcmd.BuildConfigFromFlags("", *kubeconfig) if err != nil { - panic(err.Error()) + panic(err.Error()) } - // create the clientset - clientset, err := kubernetes.NewForConfig(config) + } else { + // kubeconfig = flag.String("kubeconfig", "", "/etc/origin/master/admin.kubeconfig") + config, err = rest.InClusterConfig() + } + flag.Parse() - if err != nil { - panic(err.Error()) - } - return clientset, err + // create the clientset + clientset, err := kubernetes.NewForConfig(config) + + if err != nil { + panic(err.Error()) + } + + return clientset, err } func homeDir() string { diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index e4a8893eb..fe9eb7bd5 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -82,22 +82,25 @@ func init() { func labelResource(namespace string, resources map[string]string, labels map[string]string) { - dumpParsedArgs(resources, labels) + if DebugFlag { + dumpParsedArgs(resources, labels) + } // change this line to GetClientConfigWC for within cluster operation. - not written yet clientset, _ := kubeapi.GetClientConfigOOC() for _, podName := range resources { - fmt.Printf("Pod: %s\n", podName) - podClient := clientset.CoreV1().Pods(namespace) thePod, podErr := podClient.Get(podName, metav1.GetOptions{}) - // pods, err := clientset.CoreV1().Pods(podName).List(metav1.ListOptions{}) if podErr != nil { - panic(podErr.Error()) + log.WithFields(log.Fields { + "pod": podName, + }).Error("Pod not found.") + continue + // panic(podErr.Error()) } @@ -114,9 +117,11 @@ func labelResource(namespace string, resources map[string]string, labels map[str newLabels[k] = v } - fmt.Println("New Labels: ") - for k,v := range newLabels { - fmt.Printf(" %s:%s\n", k, v) + if DebugFlag { + fmt.Println("New Labels: ") + for k,v := range newLabels { + fmt.Printf(" %s:%s\n", k, v) + } } thePod.SetLabels(newLabels) diff --git a/commands/pgc/cmd/root.go b/commands/pgc/cmd/root.go index 60ff616c7..1f44164b6 100644 --- a/commands/pgc/cmd/root.go +++ b/commands/pgc/cmd/root.go @@ -14,7 +14,6 @@ package cmd */ import ( - "fmt" log "github.com/Sirupsen/logrus" "github.com/fatih/color" "github.com/spf13/cobra" @@ -48,7 +47,6 @@ var RootCmd = &cobra.Command{ // Execute adds all child commands to the root command sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { - fmt.Println("Execute called") if err := RootCmd.Execute(); err != nil { log.Debug(err.Error()) From fe2266c8e40c0aece2768e7038a77e4febd719a1 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Tue, 28 Aug 2018 13:05:20 -0400 Subject: [PATCH 014/179] Fix (??) debug flag; add logic for overwrite flag --- commands/pgc/cmd/label.go | 25 +++++++++++++++++-------- commands/pgc/cmd/root.go | 2 +- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index fe9eb7bd5..45c395ab0 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -74,7 +74,7 @@ Example: func init() { labelCmd.Flags().BoolVarP(&Overwrite, "overwrite", "o", false, "--overwrite forces an existing label to be overwritten") - labelCmd.Flags().BoolVarP(&Debug, "debug", "d", false, "--debug turns on useful debug information to be output while command executes") + // labelCmd.Flags().BoolVarP(&DebugFlag, "debug", "d", false, "--debug turns on useful debug information to be output while command executes") RootCmd.AddCommand(labelCmd) @@ -104,18 +104,19 @@ func labelResource(namespace string, resources map[string]string, labels map[str } - podLabels := thePod.GetLabels() + podLabels := thePod.GetLabels() // get current labels assigned to pod newLabels := map[string]string{} - // add current labels to new labels - TODO: check for overwrite - for k,v := range podLabels { - newLabels[k] = v + // Leverage last in wins, for overwrite during merge. + if Overwrite { + mergeLabels(podLabels, newLabels) + mergeLabels(labels, newLabels) + } else { + mergeLabels(labels, newLabels) + mergeLabels(podLabels, newLabels) } - for k,v := range labels { - newLabels[k] = v - } if DebugFlag { fmt.Println("New Labels: ") @@ -132,6 +133,14 @@ func labelResource(namespace string, resources map[string]string, labels map[str } +// given two maps, assign all key value pairs found in source to dest +func mergeLabels(source map[string]string, dest map[string]string) { + + for k,v := range source { + dest[k] = v + } +} + func parseAndClassifyArgs(args []string)(resources map[string]string, labels map[string]string ) { diff --git a/commands/pgc/cmd/root.go b/commands/pgc/cmd/root.go index 1f44164b6..4d5606909 100644 --- a/commands/pgc/cmd/root.go +++ b/commands/pgc/cmd/root.go @@ -62,7 +62,7 @@ func init() { GREEN = color.New(color.FgGreen).SprintFunc() RED = color.New(color.FgRed).SprintFunc() - RootCmd.PersistentFlags().BoolVar(&DebugFlag, "debug", false, "enable debug with true") + RootCmd.PersistentFlags().BoolVarP(&DebugFlag, "debug", "d", false, "enable debug with true") } From 813100e37b05fa9a38b2cadfdb630ac155d755d9 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Tue, 28 Aug 2018 18:57:55 -0400 Subject: [PATCH 015/179] Adding new command to start.sh, minor fixes --- Makefile | 9 +++------ bin/postgres/start.sh | 6 ++---- commands/kubeapi/auth.go | 19 ++++++++++++++++--- commands/pgc/cmd/label.go | 2 +- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index afeb9e93c..4d4901d70 100644 --- a/Makefile +++ b/Makefile @@ -60,8 +60,7 @@ collect: versiontest docker tag crunchy-collect $(CCP_IMAGE_PREFIX)/crunchy-collect:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) dbaserver: - cp `which oc` bin/dba - cp `which kubectl` bin/dba + cp $(GOBIN)/pgc bin/postgres cd dba && godep go install dbaserver.go cp $(GOBIN)/dbaserver bin/dba docker build -t crunchy-dba -f $(CCP_BASEOS)/Dockerfile.dba.$(CCP_BASEOS) . @@ -106,14 +105,12 @@ pgsim: docker tag crunchy-sim $(CCP_IMAGE_PREFIX)/crunchy-sim:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) postgres: versiontest - cp `which kubectl` bin/postgres - cp `which oc` bin/postgres + cp $(GOBIN)/pgc bin/postgres docker build -t crunchy-postgres -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.postgres.$(CCP_BASEOS) . docker tag crunchy-postgres $(CCP_IMAGE_PREFIX)/crunchy-postgres:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) postgres-gis: versiontest - cp `which kubectl` bin/postgres - cp `which oc` bin/postgres + cp $(GOBIN)/pgc bin/postgres docker build -t crunchy-postgres-gis -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.postgres-gis.$(CCP_BASEOS) . docker tag crunchy-postgres-gis $(CCP_IMAGE_PREFIX)/crunchy-postgres-gis:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) diff --git a/bin/postgres/start.sh b/bin/postgres/start.sh index c1db92b43..c8cfb3bef 100755 --- a/bin/postgres/start.sh +++ b/bin/postgres/start.sh @@ -80,14 +80,12 @@ function role_discovery() { ordinal=${HOSTNAME##*-} echo_info "Ordinal is set to ${ordinal?}." if [ $ordinal -eq 0 ]; then - kubectl label --overwrite=true pod $HOSTNAME name=$PG_PRIMARY_HOST - oc label --overwrite=true pod $HOSTNAME name=$PG_PRIMARY_HOST + pgc label --overwrite=true pod $HOSTNAME name=$PG_PRIMARY_HOST echo_info "Setting PG_MODE to primary." export PG_MODE=primary else echo_info "Setting PG_MODE to replica." - kubectl label --overwrite=true pod $HOSTNAME name=$PG_REPLICA_HOST - oc label --overwrite=true pod $HOSTNAME name=$PG_REPLICA_HOST + pgc label --overwrite=true pod $HOSTNAME name=$PG_REPLICA_HOST export PG_MODE=replica fi } diff --git a/commands/kubeapi/auth.go b/commands/kubeapi/auth.go index ebbe4e02e..3ab4de159 100644 --- a/commands/kubeapi/auth.go +++ b/commands/kubeapi/auth.go @@ -13,12 +13,17 @@ import ( // "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/clientset" ) -func GetClientConfigOOC ()(* kubernetes.Clientset, error) { +func GetClientConfig ()(* kubernetes.Clientset, error) { var kubeconfig *string var config *rest.Config var err error - if home := homeDir(); home != "" { + + + + if inAContainer() { + config, err = rest.InClusterConfig() + } else if home := homeDir(); home != "" { kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "") // use the current context in kubeconfig config, err = clientcmd.BuildConfigFromFlags("", *kubeconfig) @@ -29,7 +34,8 @@ func GetClientConfigOOC ()(* kubernetes.Clientset, error) { } else { // kubeconfig = flag.String("kubeconfig", "", "/etc/origin/master/admin.kubeconfig") - config, err = rest.InClusterConfig() + // config, err = rest.InClusterConfig() + panic("Unable to obtain a cluster configuration. Exiting.") } flag.Parse() @@ -49,4 +55,11 @@ func homeDir() string { return h } return os.Getenv("USERPROFILE") // windows +} + +func inAContainer() bool { + if e := os.Getenv("container"); e != "" { + return true + } + return false } \ No newline at end of file diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index 45c395ab0..d93ce0abd 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -87,7 +87,7 @@ func labelResource(namespace string, resources map[string]string, labels map[str } // change this line to GetClientConfigWC for within cluster operation. - not written yet - clientset, _ := kubeapi.GetClientConfigOOC() + clientset, _ := kubeapi.GetClientConfig() for _, podName := range resources { From 1f5762da0ea06965ae6363d5b33a67c0293191c5 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Wed, 29 Aug 2018 14:06:46 -0400 Subject: [PATCH 016/179] Fix hardcoded namespace, update examples to include CCP_NAMESPACE in env --- commands/kubeapi/auth.go | 18 ++++++++++++++++-- commands/pgc/cmd/label.go | 13 ++++++------- examples/kube/dba/dba-backup.json | 16 +++++++++++++++- examples/kube/dba/dba-vac.json | 14 ++++++++++++++ examples/kube/postgres-gis/postgres-gis.json | 9 ++++++++- examples/kube/primary/primary.json | 7 +++++++ examples/kube/statefulset/statefulset.json | 8 ++++++++ 7 files changed, 74 insertions(+), 11 deletions(-) diff --git a/commands/kubeapi/auth.go b/commands/kubeapi/auth.go index 3ab4de159..c43d946fc 100644 --- a/commands/kubeapi/auth.go +++ b/commands/kubeapi/auth.go @@ -13,7 +13,7 @@ import ( // "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/clientset" ) -func GetClientConfig ()(* kubernetes.Clientset, error) { +func GetClientConfig ()(* kubernetes.Clientset, string, error) { var kubeconfig *string var config *rest.Config @@ -47,7 +47,10 @@ func GetClientConfig ()(* kubernetes.Clientset, error) { panic(err.Error()) } - return clientset, err + namespace := getNamespace() + + + return clientset, namespace, err } func homeDir() string { @@ -62,4 +65,15 @@ func inAContainer() bool { return true } return false +} + + +func getNamespace() string { + + if ns := os.Getenv("CCP_NAMESPACE"); ns != "" { + return ns + } + return "default" + + } \ No newline at end of file diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index d93ce0abd..54b5dc85d 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -65,9 +65,7 @@ Example: resources, labels := parseAndClassifyArgs(args) - namespace := "demo" // replace with getActiveNamespace or something like that. - - labelResource(namespace, resources, labels) + labelResource(resources, labels) }, } @@ -80,14 +78,14 @@ func init() { } -func labelResource(namespace string, resources map[string]string, labels map[string]string) { +func labelResource(resources map[string]string, labels map[string]string) { if DebugFlag { dumpParsedArgs(resources, labels) } // change this line to GetClientConfigWC for within cluster operation. - not written yet - clientset, _ := kubeapi.GetClientConfig() + clientset, namespace, _ := kubeapi.GetClientConfig() for _, podName := range resources { @@ -98,7 +96,8 @@ func labelResource(namespace string, resources map[string]string, labels map[str if podErr != nil { log.WithFields(log.Fields { "pod": podName, - }).Error("Pod not found.") + "namespace" : namespace, + }).Error("Pod not found in namespace.") continue // panic(podErr.Error()) } @@ -209,4 +208,4 @@ func dumpPodInfo(pods []v1.Pod ) { } -} \ No newline at end of file +} diff --git a/examples/kube/dba/dba-backup.json b/examples/kube/dba/dba-backup.json index 5ffc58e7d..c2a00ff91 100644 --- a/examples/kube/dba/dba-backup.json +++ b/examples/kube/dba/dba-backup.json @@ -84,7 +84,7 @@ "name": "CCP_IMAGE_TAG", "value": "$CCP_IMAGE_TAG" }, - { + { "name": "CCP_IMAGE_PREFIX", "value": "$CCP_IMAGE_PREFIX" }, @@ -111,6 +111,13 @@ { "name": "BACKUP_PVC_STORAGE", "value": "75M" + },{ + "name": "CCP_NAMESPACE", + "valueFrom": { + "fieldRef": { + "fieldPath": "metadata.namespace" + } + } } ] }, @@ -155,6 +162,13 @@ { "name": "PG_ROOT_PASSWORD", "value": "password" + },{ + "name": "CCP_NAMESPACE", + "valueFrom": { + "fieldRef": { + "fieldPath": "metadata.namespace" + } + } } ], "volumeMounts": [ diff --git a/examples/kube/dba/dba-vac.json b/examples/kube/dba/dba-vac.json index be278464d..67c6275db 100644 --- a/examples/kube/dba/dba-vac.json +++ b/examples/kube/dba/dba-vac.json @@ -115,6 +115,13 @@ { "name": "VAC_TABLE", "value": "testtable" + },{ + "name": "CCP_NAMESPACE", + "valueFrom": { + "fieldRef": { + "fieldPath": "metadata.namespace" + } + } } ] }, @@ -159,6 +166,13 @@ { "name": "PG_ROOT_PASSWORD", "value": "password" + },{ + "name": "CCP_NAMESPACE", + "valueFrom": { + "fieldRef": { + "fieldPath": "metadata.namespace" + } + } } ], "volumeMounts": [ diff --git a/examples/kube/postgres-gis/postgres-gis.json b/examples/kube/postgres-gis/postgres-gis.json index 0b33582df..5415687e9 100644 --- a/examples/kube/postgres-gis/postgres-gis.json +++ b/examples/kube/postgres-gis/postgres-gis.json @@ -132,7 +132,14 @@ { "name":"CONTAINER_NAME", "value":"postgres-gis" - } + },{ + "name": "CCP_NAMESPACE", + "valueFrom": { + "fieldRef": { + "fieldPath": "metadata.namespace" + } + } + } ], "volumeMounts":[ { diff --git a/examples/kube/primary/primary.json b/examples/kube/primary/primary.json index 33792976c..e10dad071 100644 --- a/examples/kube/primary/primary.json +++ b/examples/kube/primary/primary.json @@ -100,6 +100,13 @@ { "name": "PG_ROOT_PASSWORD", "value": "password" + },{ + "name": "CCP_NAMESPACE", + "valueFrom": { + "fieldRef": { + "fieldPath": "metadata.namespace" + } + } } ], "volumeMounts": [ diff --git a/examples/kube/statefulset/statefulset.json b/examples/kube/statefulset/statefulset.json index 2a31e60e1..2c261d5e2 100644 --- a/examples/kube/statefulset/statefulset.json +++ b/examples/kube/statefulset/statefulset.json @@ -90,6 +90,14 @@ { "name": "PG_ROOT_PASSWORD", "value": "password" + }, + { + "name": "CCP_NAMESPACE", + "valueFrom": { + "fieldRef": { + "fieldPath": "metadata.namespace" + } + } } ], "volumeMounts": [ From fa434df291d19135243fa549c057389ce31b7051 Mon Sep 17 00:00:00 2001 From: Carvel Baus Date: Thu, 30 Aug 2018 12:43:17 -0400 Subject: [PATCH 017/179] Rework in-container, out of container detection --- commands/kubeapi/auth.go | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/commands/kubeapi/auth.go b/commands/kubeapi/auth.go index c43d946fc..3477f75d5 100644 --- a/commands/kubeapi/auth.go +++ b/commands/kubeapi/auth.go @@ -4,13 +4,13 @@ import ( "flag" "path/filepath" "os" +"strings" +"bufio" +"fmt" -// "k8s.io/apimachinery/pkg/api/errors" -// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/rest" -// "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/clientset" ) func GetClientConfig ()(* kubernetes.Clientset, string, error) { @@ -61,13 +61,40 @@ func homeDir() string { } func inAContainer() bool { - if e := os.Getenv("container"); e != "" { + + // based on this post + // https://stackoverflow.com/questions/20010199/how-to-determine-if-a-process-runs-inside-lxc-docker + + + var cgroupFile = "/proc/1/cgroup" + // if e := os.Getenv("container"); e != "" { + // return true + // } + // return false + + inFile, _ := os.Open(cgroupFile) + + defer inFile.Close() + scanner := bufio.NewScanner(inFile) + scanner.Split(bufio.ScanLines) + + scanner.Scan() // read one line. + pieces := strings.Split(scanner.Text(), ":") + + fmt.Printf("Cgroup root: %s \n", pieces[2]) + fmt.Printf("Length of cgroup root: %d\n", len(pieces[2] ) ) + + if len(pieces[2]) > 1 { + fmt.Println("Running inside of container.") return true } + fmt.Println("Running outside of container") return false } + + func getNamespace() string { if ns := os.Getenv("CCP_NAMESPACE"); ns != "" { @@ -76,4 +103,5 @@ func getNamespace() string { return "default" -} \ No newline at end of file +} + From 4619c6624c6980e98abc6a8e0f94576427f001bd Mon Sep 17 00:00:00 2001 From: Carvel Baus Date: Thu, 30 Aug 2018 13:11:47 -0400 Subject: [PATCH 018/179] Add commands target where needed in Makefile, remove printfs from pgc --- Makefile | 6 +++--- commands/kubeapi/auth.go | 21 ++++++--------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 4d4901d70..41311c63a 100644 --- a/Makefile +++ b/Makefile @@ -59,7 +59,7 @@ collect: versiontest docker build -t crunchy-collect -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.collect.$(CCP_BASEOS) . docker tag crunchy-collect $(CCP_IMAGE_PREFIX)/crunchy-collect:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) -dbaserver: +dbaserver: commands cp $(GOBIN)/pgc bin/postgres cd dba && godep go install dbaserver.go cp $(GOBIN)/dbaserver bin/dba @@ -104,12 +104,12 @@ pgsim: docker build -t crunchy-sim -f $(CCP_BASEOS)/Dockerfile.sim.$(CCP_BASEOS) . docker tag crunchy-sim $(CCP_IMAGE_PREFIX)/crunchy-sim:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) -postgres: versiontest +postgres: versiontest commands cp $(GOBIN)/pgc bin/postgres docker build -t crunchy-postgres -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.postgres.$(CCP_BASEOS) . docker tag crunchy-postgres $(CCP_IMAGE_PREFIX)/crunchy-postgres:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) -postgres-gis: versiontest +postgres-gis: versiontest commands cp $(GOBIN)/pgc bin/postgres docker build -t crunchy-postgres-gis -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.postgres-gis.$(CCP_BASEOS) . docker tag crunchy-postgres-gis $(CCP_IMAGE_PREFIX)/crunchy-postgres-gis:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) diff --git a/commands/kubeapi/auth.go b/commands/kubeapi/auth.go index 3477f75d5..2c5e60ef0 100644 --- a/commands/kubeapi/auth.go +++ b/commands/kubeapi/auth.go @@ -6,7 +6,6 @@ import ( "os" "strings" "bufio" -"fmt" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" @@ -62,33 +61,25 @@ func homeDir() string { func inAContainer() bool { - // based on this post + // based on this post for how to determine if running inside a container. // https://stackoverflow.com/questions/20010199/how-to-determine-if-a-process-runs-inside-lxc-docker - var cgroupFile = "/proc/1/cgroup" - // if e := os.Getenv("container"); e != "" { - // return true - // } - // return false inFile, _ := os.Open(cgroupFile) - defer inFile.Close() + + // read first line, determine cgroup structure scanner := bufio.NewScanner(inFile) scanner.Split(bufio.ScanLines) - - scanner.Scan() // read one line. + scanner.Scan() pieces := strings.Split(scanner.Text(), ":") - fmt.Printf("Cgroup root: %s \n", pieces[2]) - fmt.Printf("Length of cgroup root: %d\n", len(pieces[2] ) ) - + // if the 3rd piece is more than a single "/", we are in a container if len(pieces[2]) > 1 { - fmt.Println("Running inside of container.") return true } - fmt.Println("Running outside of container") + return false } From 3530ebbc67d4adff90de5a0f2464cf2b5a2ae62f Mon Sep 17 00:00:00 2001 From: Carvel Baus Date: Thu, 30 Aug 2018 14:16:15 -0400 Subject: [PATCH 019/179] Remove unnecessary godep dependency --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 41311c63a..ef3e3c8f4 100644 --- a/Makefile +++ b/Makefile @@ -27,8 +27,7 @@ setup: gendeps: godep save \ github.com/crunchydata/crunchy-containers/dba \ - github.com/crunchydata/crunchy-containers/badger \ - github.com/crunchydata/crunchy-containers/commands/kubeapi/auth + github.com/crunchydata/crunchy-containers/badger docbuild: cd $CCPROOT && ./generate-docs.sh From 419eef9528f68af3c5915ca4ab308a03b58d773e Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Thu, 30 Aug 2018 18:10:03 -0400 Subject: [PATCH 020/179] Add missing copyright notice --- commands/kubeapi/auth.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/commands/kubeapi/auth.go b/commands/kubeapi/auth.go index 2c5e60ef0..7f4677dac 100644 --- a/commands/kubeapi/auth.go +++ b/commands/kubeapi/auth.go @@ -1,5 +1,19 @@ package kubeapi +/* + Copyright 2017-2018 Crunchy Data Solutions, Inc. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + + import ( "flag" "path/filepath" From 1837084bbcdca6d70cfbf614e856d0685ad0ee33 Mon Sep 17 00:00:00 2001 From: Sarah Conway Date: Fri, 31 Aug 2018 12:35:16 -0700 Subject: [PATCH 021/179] update .expand CSS styles to be more noticeable --- hugo/themes/docdock/static/theme-original/style.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hugo/themes/docdock/static/theme-original/style.css b/hugo/themes/docdock/static/theme-original/style.css index ed9380cec..06e1c4335 100644 --- a/hugo/themes/docdock/static/theme-original/style.css +++ b/hugo/themes/docdock/static/theme-original/style.css @@ -24,6 +24,18 @@ @import url('https://fonts.googleapis.com/css?family=Roboto:200,400,700'); +.expand { + background-color: #f1f1f1; + color: #444; + cursor: pointer; + padding: 18px; + width: 100%; + border: none; + text-align: left; + outline: none; + font-size: 15px; +} + /* Table of contents */ .progress ul { list-style: none; From 47de7411fc966d2b176104c435245f3cd6fe1a98 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Tue, 4 Sep 2018 10:30:18 -0400 Subject: [PATCH 022/179] Add namespace flag, check for PG_MODE, remote flag, remove automatic namespace determination. --- commands/kubeapi/auth.go | 56 +++++++++++++-------------------------- commands/pgc/cmd/label.go | 26 +++++++----------- commands/pgc/cmd/root.go | 14 ++++++++-- 3 files changed, 40 insertions(+), 56 deletions(-) diff --git a/commands/kubeapi/auth.go b/commands/kubeapi/auth.go index 7f4677dac..2ae0b9af0 100644 --- a/commands/kubeapi/auth.go +++ b/commands/kubeapi/auth.go @@ -18,24 +18,30 @@ import ( "flag" "path/filepath" "os" -"strings" -"bufio" - +log "github.com/Sirupsen/logrus" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/rest" ) -func GetClientConfig ()(* kubernetes.Clientset, string, error) { +func GetClientConfig (oocFlag bool, namespaceFlag string)(* kubernetes.Clientset, string, error) { var kubeconfig *string var config *rest.Config var err error + namespace := getNamespace(oocFlag, namespaceFlag) // this may call os.Exit(non-zero) - if inAContainer() { + if !oocFlag { config, err = rest.InClusterConfig() + + if err != nil { + log.Error(err.Error()) + log.Info("If running outside of container, use [ -r | --remote ] flag") + os.Exit(-1) + } + } else if home := homeDir(); home != "" { kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "") // use the current context in kubeconfig @@ -46,8 +52,6 @@ func GetClientConfig ()(* kubernetes.Clientset, string, error) { } } else { - // kubeconfig = flag.String("kubeconfig", "", "/etc/origin/master/admin.kubeconfig") - // config, err = rest.InClusterConfig() panic("Unable to obtain a cluster configuration. Exiting.") } flag.Parse() @@ -60,9 +64,6 @@ func GetClientConfig ()(* kubernetes.Clientset, string, error) { panic(err.Error()) } - namespace := getNamespace() - - return clientset, namespace, err } @@ -73,40 +74,21 @@ func homeDir() string { return os.Getenv("USERPROFILE") // windows } -func inAContainer() bool { - - // based on this post for how to determine if running inside a container. - // https://stackoverflow.com/questions/20010199/how-to-determine-if-a-process-runs-inside-lxc-docker - var cgroupFile = "/proc/1/cgroup" +func getNamespace(outOfContainer bool, namespaceFlag string) string { - inFile, _ := os.Open(cgroupFile) - defer inFile.Close() - - // read first line, determine cgroup structure - scanner := bufio.NewScanner(inFile) - scanner.Split(bufio.ScanLines) - scanner.Scan() - pieces := strings.Split(scanner.Text(), ":") - - // if the 3rd piece is more than a single "/", we are in a container - if len(pieces[2]) > 1 { - return true + if namespaceFlag != "" { + return namespaceFlag } - return false -} - - - - -func getNamespace() string { - - if ns := os.Getenv("CCP_NAMESPACE"); ns != "" { + if ns := os.Getenv("CCP_NAMESPACE"); ns != "" || outOfContainer { return ns } - return "default" + log.Error("CCP_NAMESPACE must be set.") + // if namespace not set, exit + os.Exit(-1) + return "" // make compiler happy - never executed } diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index 54b5dc85d..fa9191a6b 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -51,20 +51,13 @@ Example: .`, Run: func(cmd *cobra.Command, args []string) { log.Debug("label called") - var inValid bool = false if len(args) == 0 { log.Error("A resource type and name must be specified.") - inValid = true - } - - - if (inValid) { return } resources, labels := parseAndClassifyArgs(args) - labelResource(resources, labels) }, } @@ -72,8 +65,6 @@ Example: func init() { labelCmd.Flags().BoolVarP(&Overwrite, "overwrite", "o", false, "--overwrite forces an existing label to be overwritten") - // labelCmd.Flags().BoolVarP(&DebugFlag, "debug", "d", false, "--debug turns on useful debug information to be output while command executes") - RootCmd.AddCommand(labelCmd) } @@ -84,8 +75,9 @@ func labelResource(resources map[string]string, labels map[string]string) { dumpParsedArgs(resources, labels) } - // change this line to GetClientConfigWC for within cluster operation. - not written yet - clientset, namespace, _ := kubeapi.GetClientConfig() + // oocFlag := RootCmd.PersistentFlags().Lookup("remote").Value + + clientset, namespace, _ := kubeapi.GetClientConfig(OOCFlag, Namespace) for _, podName := range resources { @@ -99,7 +91,6 @@ func labelResource(resources map[string]string, labels map[string]string) { "namespace" : namespace, }).Error("Pod not found in namespace.") continue - // panic(podErr.Error()) } @@ -109,11 +100,11 @@ func labelResource(resources map[string]string, labels map[string]string) { // Leverage last in wins, for overwrite during merge. if Overwrite { - mergeLabels(podLabels, newLabels) - mergeLabels(labels, newLabels) + mergeMaps(podLabels, newLabels) + mergeMaps(labels, newLabels) } else { - mergeLabels(labels, newLabels) - mergeLabels(podLabels, newLabels) + mergeMaps(labels, newLabels) + mergeMaps(podLabels, newLabels) } @@ -133,7 +124,8 @@ func labelResource(resources map[string]string, labels map[string]string) { } // given two maps, assign all key value pairs found in source to dest -func mergeLabels(source map[string]string, dest map[string]string) { +// identical keys will get overwritten +func mergeMaps(source map[string]string, dest map[string]string) { for k,v := range source { dest[k] = v diff --git a/commands/pgc/cmd/root.go b/commands/pgc/cmd/root.go index 4d5606909..27ec442ec 100644 --- a/commands/pgc/cmd/root.go +++ b/commands/pgc/cmd/root.go @@ -32,13 +32,14 @@ var Labelselector string var DebugFlag bool var Pod string var Overwrite bool -var Debug bool +var OOCFlag bool +var Namespace string // RootCmd represents the base command when called without any subcommands var RootCmd = &cobra.Command{ Use: "pgc", Short: "The Crunchy Postgres Container Client", - Long: "The pgc command allows you to modify resources in an Kubenetes Cluster, including Openshift", + Long: "Allows you to modify stateful set resources in a postgres cluster.", // Uncomment the following line if your bare application // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { }, @@ -63,6 +64,8 @@ func init() { RED = color.New(color.FgRed).SprintFunc() RootCmd.PersistentFlags().BoolVarP(&DebugFlag, "debug", "d", false, "enable debug with true") + RootCmd.PersistentFlags().BoolVarP(&OOCFlag, "remote", "r", false, "execute remotely, from outside of cluster") + RootCmd.PersistentFlags().StringVarP(&Namespace, "namespace", "n", "", "specify namespace pod is in") } @@ -73,6 +76,13 @@ func initConfig() { } log.Debug("initConfig() called.") + + // if not operating in a "set" cluster, bail immediately + if pgm := os.Getenv("PG_MODE"); pgm != "set" && !OOCFlag { + log.Error("PG_MODE must be specified as 'set'.") + os.Exit(-1) + } + } func generateBashCompletion() { From 3eb0a609087d7dd133e61f2f97384c3be0591674 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Tue, 4 Sep 2018 12:54:15 -0400 Subject: [PATCH 023/179] remove CCP_NAMESPACE from examples, not needed --- examples/kube/postgres-gis/postgres-gis.json | 9 +-------- examples/kube/primary/primary.json | 7 ------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/examples/kube/postgres-gis/postgres-gis.json b/examples/kube/postgres-gis/postgres-gis.json index 5415687e9..0b33582df 100644 --- a/examples/kube/postgres-gis/postgres-gis.json +++ b/examples/kube/postgres-gis/postgres-gis.json @@ -132,14 +132,7 @@ { "name":"CONTAINER_NAME", "value":"postgres-gis" - },{ - "name": "CCP_NAMESPACE", - "valueFrom": { - "fieldRef": { - "fieldPath": "metadata.namespace" - } - } - } + } ], "volumeMounts":[ { diff --git a/examples/kube/primary/primary.json b/examples/kube/primary/primary.json index e10dad071..33792976c 100644 --- a/examples/kube/primary/primary.json +++ b/examples/kube/primary/primary.json @@ -100,13 +100,6 @@ { "name": "PG_ROOT_PASSWORD", "value": "password" - },{ - "name": "CCP_NAMESPACE", - "valueFrom": { - "fieldRef": { - "fieldPath": "metadata.namespace" - } - } } ], "volumeMounts": [ From 4c4416d4cd38bd83e22527e62bb528856c6e435b Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Tue, 4 Sep 2018 16:04:56 -0400 Subject: [PATCH 024/179] Force container failure if stateful set cannot be properly labled. --- bin/postgres/start.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bin/postgres/start.sh b/bin/postgres/start.sh index c8cfb3bef..c48d15d7a 100755 --- a/bin/postgres/start.sh +++ b/bin/postgres/start.sh @@ -81,11 +81,21 @@ function role_discovery() { echo_info "Ordinal is set to ${ordinal?}." if [ $ordinal -eq 0 ]; then pgc label --overwrite=true pod $HOSTNAME name=$PG_PRIMARY_HOST + rc=$?; + if [[ $rc != 0 ]]; then + echo_err "Unable to set mode on pod, label command failed." + exit $rc; + fi echo_info "Setting PG_MODE to primary." export PG_MODE=primary else echo_info "Setting PG_MODE to replica." pgc label --overwrite=true pod $HOSTNAME name=$PG_REPLICA_HOST + rc=$?; + if [[ $rc != 0 ]]; then + echo_err "Unable to set mode on pod, label command failed." + exit $rc; + fi export PG_MODE=replica fi } From 70fa8670ee680d2f3b908357b1d0a053512b8cc8 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Wed, 5 Sep 2018 10:08:24 -0400 Subject: [PATCH 025/179] Fix case issue with logrus import --- commands/kubeapi/auth.go | 2 +- commands/pgc/cmd/label.go | 2 +- commands/pgc/cmd/root.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/kubeapi/auth.go b/commands/kubeapi/auth.go index 2ae0b9af0..707976556 100644 --- a/commands/kubeapi/auth.go +++ b/commands/kubeapi/auth.go @@ -18,7 +18,7 @@ import ( "flag" "path/filepath" "os" -log "github.com/Sirupsen/logrus" +log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/rest" diff --git a/commands/pgc/cmd/label.go b/commands/pgc/cmd/label.go index fa9191a6b..05e26f8da 100644 --- a/commands/pgc/cmd/label.go +++ b/commands/pgc/cmd/label.go @@ -15,7 +15,7 @@ package cmd import ( "fmt" - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "strings" "k8s.io/api/core/v1" diff --git a/commands/pgc/cmd/root.go b/commands/pgc/cmd/root.go index 27ec442ec..5f1ff9bde 100644 --- a/commands/pgc/cmd/root.go +++ b/commands/pgc/cmd/root.go @@ -14,7 +14,7 @@ package cmd */ import ( - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" "github.com/fatih/color" "github.com/spf13/cobra" "os" From f9bcf798fecda359b792e2de006ac80d74e0528c Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Wed, 5 Sep 2018 11:03:04 -0400 Subject: [PATCH 026/179] Fix cleanup of stateful set example --- examples/kube/statefulset/cleanup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/kube/statefulset/cleanup.sh b/examples/kube/statefulset/cleanup.sh index ed40af755..4143dba5e 100755 --- a/examples/kube/statefulset/cleanup.sh +++ b/examples/kube/statefulset/cleanup.sh @@ -19,6 +19,7 @@ ${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} statefulset statefulset ${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} sa statefulset-sa ${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} clusterrolebinding statefulset-sa ${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} pvc -l 'name=statefulset-pgdata' +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} pvc -l 'app=statefulset' if [ -z "$CCP_STORAGE_CLASS" ]; then ${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} pv -l 'name=statefulset-pgdata' fi From c4a8c2455ccb68c064136dc65c0257d3e8e187aa Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Wed, 5 Sep 2018 13:05:13 -0400 Subject: [PATCH 027/179] Update gitignore, remove oc / kubectl, add pgc --- bin/postgres/.gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/postgres/.gitignore b/bin/postgres/.gitignore index 614a65e85..600d22307 100644 --- a/bin/postgres/.gitignore +++ b/bin/postgres/.gitignore @@ -1,2 +1 @@ -kubectl -oc +pgc From c00c00edbd41fcc1eae365ba32da21eb0b3d3837 Mon Sep 17 00:00:00 2001 From: Carvel Baus Date: Wed, 5 Sep 2018 15:20:18 -0400 Subject: [PATCH 028/179] Remove kubectl package from containers - not needed --- centos7/10/Dockerfile.postgres.centos7 | 1 - centos7/9.5/Dockerfile.postgres.centos7 | 1 - centos7/9.6/Dockerfile.postgres.centos7 | 1 - 3 files changed, 3 deletions(-) diff --git a/centos7/10/Dockerfile.postgres.centos7 b/centos7/10/Dockerfile.postgres.centos7 index 240de4290..ae304bd5e 100644 --- a/centos7/10/Dockerfile.postgres.centos7 +++ b/centos7/10/Dockerfile.postgres.centos7 @@ -26,7 +26,6 @@ RUN yum -y update \ hostname \ nss_wrapper \ openssh-server \ - kubernetes-client \ procps-ng \ rsync \ && yum -y install postgresql10-server postgresql10-contrib postgresql10 \ diff --git a/centos7/9.5/Dockerfile.postgres.centos7 b/centos7/9.5/Dockerfile.postgres.centos7 index 6c8cf7735..8d65c9441 100644 --- a/centos7/9.5/Dockerfile.postgres.centos7 +++ b/centos7/9.5/Dockerfile.postgres.centos7 @@ -25,7 +25,6 @@ RUN yum -y update && yum -y install epel-release \ hostname \ nss_wrapper \ openssh-server \ - kubernetes-client \ procps-ng \ rsync \ && yum -y install postgresql95-server postgresql95-contrib postgresql95 \ diff --git a/centos7/9.6/Dockerfile.postgres.centos7 b/centos7/9.6/Dockerfile.postgres.centos7 index abf366cf7..20d430eeb 100644 --- a/centos7/9.6/Dockerfile.postgres.centos7 +++ b/centos7/9.6/Dockerfile.postgres.centos7 @@ -25,7 +25,6 @@ RUN yum -y update && yum -y install epel-release \ hostname \ nss_wrapper \ openssh-server \ - kubernetes-client \ procps-ng \ rsync \ && yum -y install postgresql96-server postgresql96-contrib postgresql96 \ From 108e928d9934c63adc54d0e1e5303c23075a311f Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Wed, 5 Sep 2018 17:01:42 -0400 Subject: [PATCH 029/179] Fix issue with dbaserver --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ef3e3c8f4..799381330 100644 --- a/Makefile +++ b/Makefile @@ -58,8 +58,9 @@ collect: versiontest docker build -t crunchy-collect -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.collect.$(CCP_BASEOS) . docker tag crunchy-collect $(CCP_IMAGE_PREFIX)/crunchy-collect:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) -dbaserver: commands - cp $(GOBIN)/pgc bin/postgres +dbaserver: + cp `which oc` bin/dba + cp `which kubectl` bin/dba cd dba && godep go install dbaserver.go cp $(GOBIN)/dbaserver bin/dba docker build -t crunchy-dba -f $(CCP_BASEOS)/Dockerfile.dba.$(CCP_BASEOS) . From 63e63399ac289abe8f855036d2775b96ba4c599b Mon Sep 17 00:00:00 2001 From: Sarah Conway Date: Fri, 7 Sep 2018 13:06:57 -0700 Subject: [PATCH 030/179] deprecate crunchy-watch crunchy-containers-test issue 63 --- bin/pull-from-crunchy.sh | 2 +- bin/pull-from-dockerhub.sh | 1 - bin/pull-from-gcr.sh | 1 - bin/push-to-dockerhub.sh | 1 - bin/tag.sh | 2 +- examples/docker/watch/cleanup.sh | 21 ---- examples/docker/watch/hooks/watch-post-hook | 3 - examples/docker/watch/hooks/watch-pre-hook | 3 - examples/docker/watch/run.sh | 45 ------- examples/kube/watch/cleanup.sh | 25 ---- examples/kube/watch/hooks/watch-post-hook | 3 - examples/kube/watch/hooks/watch-pre-hook | 3 - examples/kube/watch/run.sh | 40 ------- examples/kube/watch/watch-ocp.yaml | 49 -------- examples/kube/watch/watch-sa.json | 7 -- examples/kube/watch/watch.yaml | 43 ------- examples/ocp-templates/watch/cleanup.sh | 15 --- examples/ocp-templates/watch/run.sh | 22 ---- examples/ocp-templates/watch/watch-sa.json | 7 -- examples/ocp-templates/watch/watch.json | 99 ---------------- hugo/content/_index.adoc | 1 - .../container-specifications/_index.adoc | 112 +++--------------- .../container-specifications/crunchy-watch.md | 91 ++------------ .../kubernetes-and-openshift/_index.adoc | 79 ++---------- 24 files changed, 35 insertions(+), 640 deletions(-) delete mode 100755 examples/docker/watch/cleanup.sh delete mode 100755 examples/docker/watch/hooks/watch-post-hook delete mode 100755 examples/docker/watch/hooks/watch-pre-hook delete mode 100755 examples/docker/watch/run.sh delete mode 100755 examples/kube/watch/cleanup.sh delete mode 100755 examples/kube/watch/hooks/watch-post-hook delete mode 100755 examples/kube/watch/hooks/watch-pre-hook delete mode 100755 examples/kube/watch/run.sh delete mode 100755 examples/kube/watch/watch-ocp.yaml delete mode 100644 examples/kube/watch/watch-sa.json delete mode 100755 examples/kube/watch/watch.yaml delete mode 100755 examples/ocp-templates/watch/cleanup.sh delete mode 100755 examples/ocp-templates/watch/run.sh delete mode 100644 examples/ocp-templates/watch/watch-sa.json delete mode 100644 examples/ocp-templates/watch/watch.json diff --git a/bin/pull-from-crunchy.sh b/bin/pull-from-crunchy.sh index 2eecbe55e..5fe8e5be5 100755 --- a/bin/pull-from-crunchy.sh +++ b/bin/pull-from-crunchy.sh @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. REG_CCP_IMAGE_PREFIX=registry.crunchydata.com/crunchydata -for CONTAINER in crunchy-prometheus crunchy-dba crunchy-vacuum crunchy-upgrade crunchy-grafana crunchy-collect crunchy-pgbadger crunchy-pgpool crunchy-watch crunchy-backup crunchy-postgres crunchy-postgres-gis crunchy-pgbouncer crunchy-pgadmin4 crunchy-pgdump crunchy-pgrestore crunchy-backrest-restore +for CONTAINER in crunchy-prometheus crunchy-dba crunchy-vacuum crunchy-upgrade crunchy-grafana crunchy-collect crunchy-pgbadger crunchy-pgpool crunchy-backup crunchy-postgres crunchy-postgres-gis crunchy-pgbouncer crunchy-pgadmin4 crunchy-pgdump crunchy-pgrestore crunchy-backrest-restore do echo $CONTAINER is the container docker pull $REG_CCP_IMAGE_PREFIX/$CONTAINER:$CCP_IMAGE_TAG diff --git a/bin/pull-from-dockerhub.sh b/bin/pull-from-dockerhub.sh index 35e6cd5cf..94ac1e19a 100755 --- a/bin/pull-from-dockerhub.sh +++ b/bin/pull-from-dockerhub.sh @@ -30,7 +30,6 @@ docker pull $CCP_IMAGE_PREFIX/crunchy-grafana:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-collect:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-pgbadger:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-pgpool:$CCP_IMAGE_TAG -docker pull $CCP_IMAGE_PREFIX/crunchy-watch:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-backup:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-postgres:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-postgres-gis:$CCP_IMAGE_TAG diff --git a/bin/pull-from-gcr.sh b/bin/pull-from-gcr.sh index bf84e094f..33c901cdf 100644 --- a/bin/pull-from-gcr.sh +++ b/bin/pull-from-gcr.sh @@ -21,7 +21,6 @@ IMAGES=( crunchy-pgrestore crunchy-upgrade crunchy-vacuum - crunchy-watch ) function echo_green() { diff --git a/bin/push-to-dockerhub.sh b/bin/push-to-dockerhub.sh index 634137aa5..fbc76079d 100755 --- a/bin/push-to-dockerhub.sh +++ b/bin/push-to-dockerhub.sh @@ -19,7 +19,6 @@ docker push $CCP_IMAGE_PREFIX/crunchy-grafana:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-collect:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-pgbadger:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-pgpool:$CCP_IMAGE_TAG -docker push $CCP_IMAGE_PREFIX/crunchy-watch:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-backup:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-postgres:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-postgres-gis:$CCP_IMAGE_TAG diff --git a/bin/tag.sh b/bin/tag.sh index d0c82eab2..25b5f5413 100755 --- a/bin/tag.sh +++ b/bin/tag.sh @@ -15,7 +15,7 @@ CCP_VERSION=2.1.0 REGISTRY=52.2.93.43:5000 -containers="$CCP_IMAGE_PREFIX/crunchy-vacuum $CCP_IMAGE_PREFIX/crunchy-prometheus $CCP_IMAGE_PREFIX/crunchy-grafana $CCP_IMAGE_PREFIX/crunchy-collect $CCP_IMAGE_PREFIX/crunchy-pgbadger $CCP_IMAGE_PREFIX/crunchy-pgpool $CCP_IMAGE_PREFIX/crunchy-watch $CCP_IMAGE_PREFIX/crunchy-backup $CCP_IMAGE_PREFIX/crunchy-postgres" +containers="$CCP_IMAGE_PREFIX/crunchy-vacuum $CCP_IMAGE_PREFIX/crunchy-prometheus $CCP_IMAGE_PREFIX/crunchy-grafana $CCP_IMAGE_PREFIX/crunchy-collect $CCP_IMAGE_PREFIX/crunchy-pgbadger $CCP_IMAGE_PREFIX/crunchy-pgpool $CCP_IMAGE_PREFIX/crunchy-backup $CCP_IMAGE_PREFIX/crunchy-postgres" for i in $containers; do echo $i is the container diff --git a/examples/docker/watch/cleanup.sh b/examples/docker/watch/cleanup.sh deleted file mode 100755 index aba7d8a62..000000000 --- a/examples/docker/watch/cleanup.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -echo "Cleaning up..." - -CONTAINER_NAME=watch - -docker stop $CONTAINER_NAME -docker rm $CONTAINER_NAME diff --git a/examples/docker/watch/hooks/watch-post-hook b/examples/docker/watch/hooks/watch-post-hook deleted file mode 100755 index 3b8bd021a..000000000 --- a/examples/docker/watch/hooks/watch-post-hook +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -echo "Hello from crunchy-watch post-hook!" diff --git a/examples/docker/watch/hooks/watch-pre-hook b/examples/docker/watch/hooks/watch-pre-hook deleted file mode 100755 index 6c97dc686..000000000 --- a/examples/docker/watch/hooks/watch-pre-hook +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -echo "Hello from crunchy-watch pre-hook!" diff --git a/examples/docker/watch/run.sh b/examples/docker/watch/run.sh deleted file mode 100755 index 6fe0e5bd0..000000000 --- a/examples/docker/watch/run.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -$DIR/cleanup.sh - -export CONTAINER_NAME=watch - -echo "Starting the ${CONTAINER_NAME} example..." -# -# Make sure the Docker socket has permissions that allow -# the postgres user to read it, or else this example will not -# be able to read and write to the mounted Docker socket. -# -sudo docker run \ - --privileged \ - -v /run/docker.sock:/run/docker.sock \ - --link primary:primary \ - --link replica:replica \ - -e CRUNCHY_WATCH_PRIMARY=primary \ - -e CRUNCHY_WATCH_REPLICA=replica \ - -e CRUNCHY_WATCH_PRIMARY_PORT=5432 \ - -e CRUNCHY_WATCH_USERNAME=primaryuser \ - -e CRUNCHY_WATCH_DATABASE=postgres \ - -e CRUNCHY_WATCH_HEALTHCHECK_INTERVAL=20 \ - -e CRUNCHY_WATCH_FAILOVER_WAIT=10s \ - -e CRUNCHY_WATCH_PRE_HOOK="/hooks/watch-pre-hook" \ - -e CRUNCHY_WATCH_POST_HOOK="/hooks/watch-post-hook" \ - --name=$CONTAINER_NAME \ - --hostname=$CONTAINER_NAME \ - -v $PWD/hooks:/hooks \ - -d $CCP_IMAGE_PREFIX/crunchy-watch:$CCP_IMAGE_TAG diff --git a/examples/kube/watch/cleanup.sh b/examples/kube/watch/cleanup.sh deleted file mode 100755 index ff613f0fe..000000000 --- a/examples/kube/watch/cleanup.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source ${CCPROOT}/examples/common.sh -echo_info "Cleaning up.." - -${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} pod watch -../../waitforterm.sh watch ${CCP_CLI?} - -${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} sa pg-watcher - -${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} rolebinding pg-watcher-sa-edit - -${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} configmap watch-hooks-configmap diff --git a/examples/kube/watch/hooks/watch-post-hook b/examples/kube/watch/hooks/watch-post-hook deleted file mode 100755 index 3b8bd021a..000000000 --- a/examples/kube/watch/hooks/watch-post-hook +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -echo "Hello from crunchy-watch post-hook!" diff --git a/examples/kube/watch/hooks/watch-pre-hook b/examples/kube/watch/hooks/watch-pre-hook deleted file mode 100755 index 6c97dc686..000000000 --- a/examples/kube/watch/hooks/watch-pre-hook +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -echo "Hello from crunchy-watch pre-hook!" diff --git a/examples/kube/watch/run.sh b/examples/kube/watch/run.sh deleted file mode 100755 index 44d3432a4..000000000 --- a/examples/kube/watch/run.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source ${CCPROOT}/examples/common.sh - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -$DIR/cleanup.sh - -echo_info "Creating the example components.." - -${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} configmap watch-hooks-configmap \ - --from-file=./hooks/watch-pre-hook \ - --from-file=./hooks/watch-post-hook - -${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f $DIR/watch-sa.json - -${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} rolebinding pg-watcher-sa-edit \ - --clusterrole=edit \ - --serviceaccount=$CCP_NAMESPACE:pg-watcher - -if [ "$CCP_CLI" = "oc" ]; then - echo "an openshift example..." - expenv -f $DIR/watch-ocp.yaml | ${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f - -else - echo "a kube example..." - expenv -f $DIR/watch.yaml | ${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f - -fi - diff --git a/examples/kube/watch/watch-ocp.yaml b/examples/kube/watch/watch-ocp.yaml deleted file mode 100755 index 2eb219362..000000000 --- a/examples/kube/watch/watch-ocp.yaml +++ /dev/null @@ -1,49 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: watch - labels: - name: crunchy-watch -spec: - serviceAccount: pg-watcher - containers: - - name: watch - image: $CCP_IMAGE_PREFIX/crunchy-watch:$CCP_IMAGE_TAG - env: - - name: CRUNCHY_DEBUG - value: "true" - - name: CRUNCHY_WATCH_PLATFORM - value: openshift - - name: CRUNCHY_WATCH_OPENSHIFT_PROJECT - value: $CCP_NAMESPACE - - name: CRUNCHY_WATCH_OPENSHIFT_FAILOVER_STRATEGY - value: latest - - name: CRUNCHY_WATCH_PRIMARY - value: pr-primary - - name: CRUNCHY_WATCH_PRIMARY_PORT - value: "5432" - - name: CRUNCHY_WATCH_REPLICA - value: pr-replica - - name: CRUNCHY_WATCH_REPLICA_PORT - value: "5432" - - name: CRUNCHY_WATCH_USERNAME - value: primaryuser - - name: CRUNCHY_WATCH_PASSWORD - value: password - - name: CRUNCHY_WATCH_DATABASE - value: postgres - - name: CRUNCHY_WATCH_PRE_HOOK - value: /hooks/watch-pre-hook - - name: CRUNCHY_WATCH_POST_HOOK - value: /hooks/watch-post-hook - - name: CRUNCHY_WATCH_HEALTHCHECK_INTERVAL - value: 30s - - name: CRUNCHY_WATCH_FAILOVER_WAIT - value: 10s - volumeMounts: - - name: watch-hooks-volume - mountPath: /hooks - volumes: - - name: watch-hooks-volume - configMap: - name: watch-hooks-configmap diff --git a/examples/kube/watch/watch-sa.json b/examples/kube/watch/watch-sa.json deleted file mode 100644 index 8379d0a35..000000000 --- a/examples/kube/watch/watch-sa.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "apiVersion": "v1", - "kind": "ServiceAccount", - "metadata": { - "name": "pg-watcher" - } -} diff --git a/examples/kube/watch/watch.yaml b/examples/kube/watch/watch.yaml deleted file mode 100755 index 58b476c9c..000000000 --- a/examples/kube/watch/watch.yaml +++ /dev/null @@ -1,43 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: watch - labels: - name: crunchy-watch -spec: - serviceAccount: pg-watcher - containers: - - name: watch - image: $CCP_IMAGE_PREFIX/crunchy-watch:$CCP_IMAGE_TAG - env: - - name: CRUNCHY_WATCH_PLATFORM - value: kube - - name: CRUNCHY_WATCH_PRIMARY - value: pr-primary - - name: CRUNCHY_WATCH_REPLICA - value: pr-replica - - name: CRUNCHY_WATCH_USERNAME - value: primaryuser - - name: CRUNCHY_WATCH_PASSWORD - value: password - - name: CRUNCHY_WATCH_DATABASE - value: postgres - - name: CRUNCHY_WATCH_HEALTHCHECK_INTERVAL - value: 30s - - name: CRUNCHY_WATCH_FAILOVER_WAIT - value: 10s - - name: CRUNCHY_WATCH_KUBE_NAMESPACE - value: $CCP_NAMESPACE - - name: CRUNCHY_WATCH_KUBE_FAILOVER_STRATEGY - value: latest - - name: CRUNCHY_WATCH_PRE_HOOK - value: /hooks/watch-pre-hook - - name: CRUNCHY_WATCH_POST_HOOK - value: /hooks/watch-post-hook - volumeMounts: - - name: watch-hooks-volume - mountPath: /hooks - volumes: - - name: watch-hooks-volume - configMap: - name: watch-hooks-configmap diff --git a/examples/ocp-templates/watch/cleanup.sh b/examples/ocp-templates/watch/cleanup.sh deleted file mode 100755 index 4f1f3f671..000000000 --- a/examples/ocp-templates/watch/cleanup.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -# Copyright 2017 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -oc delete template crunchy-cluster-watch-template diff --git a/examples/ocp-templates/watch/run.sh b/examples/ocp-templates/watch/run.sh deleted file mode 100755 index 5888367c0..000000000 --- a/examples/ocp-templates/watch/run.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# Copyright 2017 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -$DIR/cleanup.sh - -oc create -f $DIR/watch.json - -oc create -f $DIR/watch-sa.json diff --git a/examples/ocp-templates/watch/watch-sa.json b/examples/ocp-templates/watch/watch-sa.json deleted file mode 100644 index 14f498c05..000000000 --- a/examples/ocp-templates/watch/watch-sa.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "apiVersion": "v1", - "kind": "ServiceAccount", - "metadata": { - "name": "pg-watcher" - } -} diff --git a/examples/ocp-templates/watch/watch.json b/examples/ocp-templates/watch/watch.json deleted file mode 100644 index f03924f68..000000000 --- a/examples/ocp-templates/watch/watch.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "kind": "Template", - "apiVersion": "v1", - "metadata": { - "name": "crunchy-cluster-watch-template", - "creationTimestamp": null, - "annotations": { - "description": "Crunchy PostgreSQL cluster watch template ", - "iconClass": "icon-database", - "tags": "database,postgresql,crunchy" - } - }, - "parameters": [{ - "name": "CCP_IMAGE_TAG", - "value": "centos7-10.5-2.1.0", - "description": "The image tag to use" - }, { - "name": "CCP_IMAGE_PREFIX", - "value": "crunchydata", - "description": "The image prefix to use" - }, { - "name": "SERVICE_NAME", - "description": "The name to use for the watch service", - "value": "pgwatch" - }, { - "name": "SERVICE_ACCOUNT_NAME", - "description": "The name of the service account to use", - "value": "pg-watcher" - }, { - "name": "OSE_PROJECT", - "description": "The name of the OSE project to use", - "value": "jeff-project" - }, { - "name": "SLEEP_TIME", - "description": "The time to sleep for polling the primary", - "value": "20" - }, { - "name": "REPLICA_TO_TRIGGER", - "description": "The name of a replica to trigger a failover upon", - "value": "thisone" - }, { - "name": "PRIMARY_TO_WATCH", - "description": "The name of a primary service to watch", - "value": "pgprimary" - }, { - "name": "REPLICA_TO_WATCH", - "description": "The name of a replica service to watch", - "value": "pgreplica" - }, { - "name": "PRIMARY_USER", - "description": "The primary user to watch with", - "value": "primaryuser" - }], - "objects": [{ - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "${SERVICE_NAME}", - "labels": { - "name": "${SERVICE_NAME}" - } - }, - "spec": { - "serviceAccount": "${SERVICE_ACCOUNT_NAME}", - "containers": [{ - "name": "watch", - "image": "${CCP_IMAGE_PREFIX}/crunchy-watch:${CCP_IMAGE_TAG}", - "env": [{ - "name": "OSE_PROJECT", - "value": "${OSE_PROJECT}" - }, { - "name": "SLEEP_TIME", - "value": "${SLEEP_TIME}" - }, { - "name": "REPLICA_TO_TRIGGER_LABEL", - "value": "${REPLICA_TO_TRIGGER}" - }, { - "name": "PG_PRIMARY_SERVICE", - "value": "${PRIMARY_TO_WATCH}" - }, { - "name": "PG_REPLICA_SERVICE", - "value": "${REPLICA_TO_WATCH}" - }, { - "name": "PG_PRIMARY_PORT", - "value": "5432" - }, { - "name": "PG_PRIMARY_USER", - "value": "${PRIMARY_USER}" - }, { - "name": "HOME", - "value": "/tmp" - }, { - "name": "PG_DATABASE", - "value": "postgres" - }] - }] - } - }] -} diff --git a/hugo/content/_index.adoc b/hugo/content/_index.adoc index b16037a3e..79051946c 100644 --- a/hugo/content/_index.adoc +++ b/hugo/content/_index.adoc @@ -40,7 +40,6 @@ The project includes the following containers: * link:https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backup[crunchy-backup] - performs a full database backup * link:https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgpool[crunchy-pgpool] - executes pgpool * link:https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbadger[crunchy-pgbadger] - executes pgbadger - * link:https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-watch[crunchy-watch] - performs a form of automated failover * link:https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-collect[crunchy-collect] - collects Postgres metrics * link:https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-prometheus[crunchy-prometheus] -stores Postgres metrics * link:https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-grafana[crunchy-grafana] - graphs Postgres metrics diff --git a/hugo/content/container-specifications/_index.adoc b/hugo/content/container-specifications/_index.adoc index 34412d983..60cca8915 100644 --- a/hugo/content/container-specifications/_index.adoc +++ b/hugo/content/container-specifications/_index.adoc @@ -29,7 +29,6 @@ The following container images are provided with further information: * link:/container-specifications/crunchy-grafana[crunchy-grafana] * link:/container-specifications/crunchy-pgbadger[crunchy-pgbadger] * link:/container-specifications/crunchy-pgpool[crunchy-pgpool] - * link:/container-specifications/crunchy-watch[crunchy-watch] * link:/container-specifications/crunchy-vacuum[crunchy-vacuum] * link:/container-specifications/crunchy-dba[crunchy-dba] * link:/container-specifications/crunchy-pgbouncer[crunchy-pgbouncer] @@ -376,7 +375,7 @@ http://<>:10000/api/badgergenerate === Environment Variables -*Optional:* +*Optional:* * BADGER_TARGET - only used in standalone mode to specify the name of the container, also used to find the location of the @@ -430,91 +429,14 @@ The following features are supported by the crunchy-pgpool container: == crunchy-watch -crunchy-watch runs as a pod unto itself -typically. The watch container essentially does a health check -on a primary database container and performs a failover sequence -if the primary is not reached. - -The watch container has access to a service account that is used -inside the container to issue commands to OpenShift. - -In Kube 1.5, if a policy file is being used for securing down the -Kube cluster, you could possibly need to add a policy to allow -the pg-watcher service account access to the Kube API as mentioned -here: https://kubernetes.io/docs/admin/authorization/abac/#a-quick-note-on-service-accounts - -In Kube 1.6, an equivalent RBAC policy is also possibly required depending -on your authorization/authentication configuration. See this -link for details on the new RBAC policy mechanism: -https://kubernetes.io/docs/admin/authorization/rbac/ - -For example, you can grant cluster-admin permissions on the pg-watcher service -account, in the my-namespace namespace as follows: -.... -kubectl create clusterrolebinding pgwatcher-view-binding --clusterrole=cluster-admin --serviceaccount=my-namespace:pg-watcher -.... - -A less wide open policy would be applied like this on Kube 1.6 rbac: -.... -kubectl create rolebinding my-sa-binding --clusterrole=admin --serviceaccount=demo:pg-watcher --namespace=demo -.... - -NOTE: this kubectl command is only available in Kube 1.6, for prior -Kube release such as 1.5 and the alpha RBAC, you will need to -specify the role binding in a JSON/YAML file instead of using -this command syntax above. - -You then reference the SA within the POD spec. +Crunchy Watch is an application wrapped in a container that watches a PostgreSQL +primary database and waits for a failure to occur, at which point a failover is +performed to promote a replica. -The oc/docker/kubectl commands are included into the container from the -host when the container image is built. These commands are used by -the watch logic to interact with the replica containers. - -Starting with release 1.7.1 crunchy-watch source code is relocated -to https://github.com/crunchydata/crunchy-watch - -=== Environment Variables - - * CRUNCHY_WATCH_HEALTHCHECK_INTERVAL - the time to sleep in seconds between checking on the primary - * CRUNCHY_WATCH_FAILOVER_WAIT - the time to sleep in seconds between triggering the failover and updating its label (default is 40 secs) - * PG_CONTAINER_NAME - if set, the name of the container to refer to when doing an *exec*, this is required if you have more than 1 container in your database pod - * CRUNCHY_WATCH_PRIMARY - the primary service name - * CRUNCHY_WATCH_REPLICA - the replica service name - * PG_PRIMARY_PORT - database port to use when checking the database - * CRUNCHY_WATCH_USERNAME - database user account to use when checking the database - using pg_isready utility - * CRUNCHY_WATCH_DATABASE - database to use when checking the database using pg_isready - * REPLICA_TO_TRIGGER_LABEL - the pod name of a replica that you - want to choose as the new primary in a failover; this will override - the normal replica selection - * CRUNCHY_WATCH_PRE_HOOK - path to an executable file to run before failover is processed. - * CRUNCHY_WATCH_POST_HOOK - path to an executable file to run after failover is processed. - * CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. - Note: this mode can reveal secrets in logs. - -=== Logic - -The watch container will watch the primary, if the primary dies, then -the watcher will: - - * create the trigger file on the replica that will become the new primary - * change the labels on the replica to be those of the primary - * start watching the new primary in case that falls over next - * look for replicas that have the metadata label value of *replicatype=trigger* to prefer - the failover to. If found, it will use the first replica with that label; if - not found, it will use the first replica it finds. - -Example of looking for the failover replica: -.... -oc get pod -l name=pg-replica-rc-dc -NAME READY STATUS RESTARTS AGE -pg-replica-rc-dc 1/1 Running 2 16m -pg-replica-rc-dc-1-96qs8 1/1 Running 1 16m - -oc get pod -l replicatype=trigger -NAME READY STATUS RESTARTS AGE -pg-replica-rc-dc 1/1 Running 2 16m -.... +The crunchy-watch container, while originally part of the Container Suite, has been +split out into its own project. More information on the Watch container and it's +capabilities can be found in the new project repository located at +https://github.com/CrunchyData/crunchy-watch. == crunchy-vacuum @@ -741,20 +663,20 @@ Crunchy pgBouncer is a lightweight connection pooler for PostgreSQL databases. ==== REQUIRED ARGS - * PGBOUNCER_PASSWORD - the password of the pgbouncer role in PostgreSQL. Must be also + * PGBOUNCER_PASSWORD - the password of the pgbouncer role in PostgreSQL. Must be also set on the primary database. * PG_SERVICE - the hostname of the database service ==== OPTIONAL/EXTENDED ARGS - * DEFAULT_POOL_SIZE - default 20, how many server connections to allow per user/database pair. + * DEFAULT_POOL_SIZE - default 20, how many server connections to allow per user/database pair. * MAX_CLIENT_CONN - default 100, maximum number of client connections allowed. * MAX_DB_CONNECTIONS - default unlimited, do not allow more than this many connections per-database. * MIN_POOL_SIZE - default 0 (disabled), adds more server connections to pool if below this number. - * POOL_MODE - default `session`, specifies when a server connection can be reused by other clients. + * POOL_MODE - default `session`, specifies when a server connection can be reused by other clients. Possible values: `session`, `transaction` and `statement`. * RESERVE_POOL_SIZE - default 0 (disabled), how many additional connections to allow to a pool. - * RESERVE_POOL_TIMEOUT - default 5, if a client has not been serviced in this many seconds, + * RESERVE_POOL_TIMEOUT - default 5, if a client has not been serviced in this many seconds, pgbouncer enables use of additional connections from reserve pool. 0 disables. * CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs. @@ -763,7 +685,7 @@ Crunchy pgBouncer is a lightweight connection pooler for PostgreSQL databases. The following features are supported by the crunchy-pgbouncer container: - * Crunchy pgBouncer uses `auth_query` to authenticate users. This requires only the `pgbouncer` + * Crunchy pgBouncer uses `auth_query` to authenticate users. This requires only the `pgbouncer` username and password in `users.txt`. Automatically generated from environment variables. * Mount a custom `users.txt` and `pgbouncer.ini` configurations for advanced usage. * Tune pooling parameters via environment variables. @@ -785,11 +707,11 @@ The crunchy-backrest-restore container executes the pgbackrest utility, allowing * STANZA - desired stanza to restore from. For most cases this should be set to `db`. *Optional:* - * DELTA - when set to true, this will configure pgBackRest to do a delta restore. Delta - restores do not require `pgdata` directoy to be empty. This will only pull in differences + * DELTA - when set to true, this will configure pgBackRest to do a delta restore. Delta + restores do not require `pgdata` directoy to be empty. This will only pull in differences between pgdata and the backup. - * BACKREST_CUSTOM_OPTS - pass in custom parameters to pgBackRest for advanced use cases (such as - point in time recovery). + * BACKREST_CUSTOM_OPTS - pass in custom parameters to pgBackRest for advanced use cases (such as + point in time recovery). * CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs. diff --git a/hugo/content/container-specifications/crunchy-watch.md b/hugo/content/container-specifications/crunchy-watch.md index a8c80ad41..f288bde8c 100644 --- a/hugo/content/container-specifications/crunchy-watch.md +++ b/hugo/content/container-specifications/crunchy-watch.md @@ -4,86 +4,11 @@ date: 2018-05-24T12:06:15-07:00 draft: false --- -The crunchy-watch container essentially does a health check -on a primary database container and performs a failover sequence -if the primary is not reached. The watch container has access to a service -account that is used inside the container to issue commands to OpenShift. - -In Kubrnetese 1.5, if a policy file is being used for securing down the -Kubernetes cluster, you could possibly need to add a policy to allow -the pg-watcher service account access to the Kubernetes API as mentioned -[here](https://kubernetes.io/docs/admin/authorization/abac/#a-quick-note-on-service-accounts). - -In Kubernetes 1.6, an equivalent RBAC policy is also possibly required depending -on your authorization/authentication configuration. See [this link](https://kubernetes.io/docs/admin/authorization/rbac/) for details on the new RBAC policy mechanism. - -For example, you can grant cluster-admin permissions on the pg-watcher service -account in the my-namespace namespace as follows: -```bash -kubectl create clusterrolebinding pgwatcher-view-binding --clusterrole=cluster-admin --serviceaccount=my-namespace:pg-watcher -``` - -A less wide open policy would be applied like this on Kube 1.6 rbac: -```bash -kubectl create rolebinding my-sa-binding --clusterrole=admin --serviceaccount=demo:pg-watcher --namespace=demo -``` - -{{% notice tip %}} -The above kubectl command is only available in Kubernetes 1.6. For prior -Kubernetes releases such as 1.5 and the alpha RBAC, you will need to -specify the role binding in a JSON/YAML file instead of using -the previous command syntax. -{{% /notice %}} - -The oc/docker/kubectl commands are included into the container from the -host when the container image is built. These commands are used by -the watch logic to interact with the replica containers. - -Starting with release 1.7.1, crunchy-watch source code is relocated -to a separate GitHub repository located [here](https://github.com/crunchydata/crunchy-watch). - -## Environment Variables - -### Required -**Name**|**Default**|**Description** -:-----|:-----|:----- -**CRUNCHY_WATCH_HEALTHCHECK_INTERVAL**|None|The time to sleep in seconds between checking on the primary. -**CRUNCHY_WATCH_FAILOVER_WAIT**|40s|The time to sleep in seconds between triggering the failover and updating its label. -**PG_CONTAINER_NAME**|None|If set, the name of the container to refer to when doing an *exec*. This is required if you have more than 1 container in your database pod. -**CRUNCHY_WATCH_PRIMARY**|None|The primary service name. -**CRUNCHY_WATCH_REPLICA**|None|The replica service name. -**PG_PRIMARY_PORT**|None|Database port to use when checking the database. -**CRUNCHY_WATCH_USERNAME**|None|Database user account to use when checking the database using pg_isready utility. -**CRUNCHY_WATCH_DATABASE**|None|Database to use when checking the database using pg_isready. -**REPLICA_TO_TRIGGER_LABEL**|None|The pod name of a replica that you want to choose as the new primary in a failover; this will override the normal replica selection. -**CRUNCHY_WATCH_PRE_HOOK**|None|Path to an executable file to run before failover is processed. -**CRUNCHY_WATCH_POST_HOOK**|None|Path to an executable file to run after failover is processed. - -### Optional -**Name**|**Default**|**Description** -:-----|:-----|:----- -**CRUNCHY_DEBUG**|FALSE|Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. - -## Logic - -The watch container will watch the primary. If the primary dies, then -the watcher will: - - * create the trigger file on the replica that will become the new primary - * change the labels on the replica to be those of the primary - * start watching the new primary in case that falls over next - * look for replicas that have the metadata label value of *replicatype=trigger* to prefer - the failover to. If found, it will use the first replica with that label; if - not found, it will use the first replica it finds. - -Example of looking for the failover replica: -```bash -oc get pod -l name=pg-replica-rc-dc -NAME READY STATUS RESTARTS AGE -pg-replica-rc-dc 1/1 Running 2 16m -pg-replica-rc-dc-1-96qs8 1/1 Running 1 16m - -oc get pod -l replicatype=trigger -NAME READY STATUS RESTARTS AGE -pg-replica-rc-dc 1/1 Running 2 16m -``` +Crunchy Watch is an application wrapped in a container that watches a PostgreSQL +primary database and waits for a failure to occur, at which point a failover is +performed to promote a replica. + +The crunchy-watch container, while originally part of the Container Suite, has been +split out into its own project. More information on the Watch container and it's +capabilities can be found in the new project repository located at +https://github.com/CrunchyData/crunchy-watch. diff --git a/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc b/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc index 787c6d47e..d4f0b9b74 100644 --- a/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc +++ b/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc @@ -2115,77 +2115,14 @@ You should see a row for each replica along with its replication status. === Watch -This example shows how to run the crunchy-watch container -to perform an automated failover. For the example to -work, the host on which you are running needs to allow -read-write access to `/run/docker.sock`. The crunchy-watch -container runs as the *postgres* user, so adjust the -file permissions of `/run/docker.sock` accordingly. - -The *primary-replica* example is required to be run before this example. - -To shutdown the instance and remove the container for each example, run the following: -.... -./cleanup.sh -.... - -==== Docker - -Run the example as follows: -.... -cd $CCPROOT/examples/docker/watch -./run.sh -.... - -This will start the watch container which tests every few seconds -whether the primary database is running, if not, it will -trigger a failover using `docker exec` on the replica host. - -Test it out by stopping the primary: -.... -docker stop primary -docker logs watch -.... - -Look at the watch container logs to see it perform the failover. - -==== Kubernetes and OpenShift - -Running the example: -.... -cd $CCPROOT/examples/kube/watch -./run.sh -.... - -Check out the log of the watch container as follows: -.... -${CCP_CLI} log watch -.... - -Then trigger a failover using this command: -.... -${CCP_CLI} delete pod pr-primary -.... - -Resume watching the watch container's log and verify that it -detects the primary is not reachable and performs a failover -on the replica. - -A final test is to see if the old replica is now a fully functioning -primary by inserting some test data into it as follows: -.... -psql -h pr-primary -U postgres postgres -c 'create table failtest (id int)' -.... - -The above command still works because the watch container has -changed the labels of the replica to make it a primary, so the primary -service will still work and route now to the new primary even though -the pod is named replica. - -You can view the labels on a pod with this command: -.... -${CCP_CLI} describe pod pr-replica | grep Label -.... +Crunchy Watch is an application wrapped in a container that watches a PostgreSQL +primary database and waits for a failure to occur, at which point a failover is +performed to promote a replica. + +The crunchy-watch container, while originally part of the Container Suite, has been +split out into its own project. More information on the Watch container and it's +capabilities can be found in the new project repository located at +https://github.com/CrunchyData/crunchy-watch. == Metrics and Performance From 7063122ea50bdd6a741931e7f9d522bd3900378f Mon Sep 17 00:00:00 2001 From: Paul Cahoon Date: Fri, 14 Sep 2018 20:23:13 -0400 Subject: [PATCH 031/179] adding pg11 images and update for pgbadger --- bin/pgbadger/badger-generate.sh | 2 +- .../11/Dockerfile.backrest-restore.centos7 | 57 +++++++++++ centos7/11/Dockerfile.backup.centos7 | 42 ++++++++ centos7/11/Dockerfile.collect.centos7 | 52 ++++++++++ centos7/11/Dockerfile.pgadmin4.centos7 | 56 +++++++++++ centos7/11/Dockerfile.pgbadger.centos7 | 47 +++++++++ centos7/11/Dockerfile.pgbouncer.centos7 | 46 +++++++++ centos7/11/Dockerfile.pgdump.centos7 | 42 ++++++++ centos7/11/Dockerfile.pgpool.centos7 | 53 +++++++++++ centos7/11/Dockerfile.pgrestore.centos7 | 43 +++++++++ centos7/11/Dockerfile.postgres-gis.centos7 | 76 +++++++++++++++ centos7/11/Dockerfile.postgres.centos7 | 74 +++++++++++++++ centos7/11/Dockerfile.upgrade.centos7 | 52 ++++++++++ rhel7/11/Dockerfile.backrest-restore.rhel7 | 69 ++++++++++++++ rhel7/11/Dockerfile.backup.rhel7 | 53 +++++++++++ rhel7/11/Dockerfile.collect.rhel7 | 66 +++++++++++++ rhel7/11/Dockerfile.pgadmin4.rhel7 | 73 ++++++++++++++ rhel7/11/Dockerfile.pgbadger.rhel7 | 61 ++++++++++++ rhel7/11/Dockerfile.pgbouncer.rhel7 | 60 ++++++++++++ rhel7/11/Dockerfile.pgdump.rhel7 | 53 +++++++++++ rhel7/11/Dockerfile.pgpool.rhel7 | 67 +++++++++++++ rhel7/11/Dockerfile.pgrestore.rhel7 | 54 +++++++++++ rhel7/11/Dockerfile.postgres-gis.rhel7 | 95 +++++++++++++++++++ rhel7/11/Dockerfile.postgres.rhel7 | 92 ++++++++++++++++++ rhel7/11/Dockerfile.upgrade.rhel7 | 61 ++++++++++++ 25 files changed, 1445 insertions(+), 1 deletion(-) create mode 100644 centos7/11/Dockerfile.backrest-restore.centos7 create mode 100644 centos7/11/Dockerfile.backup.centos7 create mode 100644 centos7/11/Dockerfile.collect.centos7 create mode 100644 centos7/11/Dockerfile.pgadmin4.centos7 create mode 100644 centos7/11/Dockerfile.pgbadger.centos7 create mode 100644 centos7/11/Dockerfile.pgbouncer.centos7 create mode 100644 centos7/11/Dockerfile.pgdump.centos7 create mode 100644 centos7/11/Dockerfile.pgpool.centos7 create mode 100644 centos7/11/Dockerfile.pgrestore.centos7 create mode 100644 centos7/11/Dockerfile.postgres-gis.centos7 create mode 100644 centos7/11/Dockerfile.postgres.centos7 create mode 100644 centos7/11/Dockerfile.upgrade.centos7 create mode 100644 rhel7/11/Dockerfile.backrest-restore.rhel7 create mode 100644 rhel7/11/Dockerfile.backup.rhel7 create mode 100644 rhel7/11/Dockerfile.collect.rhel7 create mode 100644 rhel7/11/Dockerfile.pgadmin4.rhel7 create mode 100644 rhel7/11/Dockerfile.pgbadger.rhel7 create mode 100644 rhel7/11/Dockerfile.pgbouncer.rhel7 create mode 100644 rhel7/11/Dockerfile.pgdump.rhel7 create mode 100644 rhel7/11/Dockerfile.pgpool.rhel7 create mode 100644 rhel7/11/Dockerfile.pgrestore.rhel7 create mode 100644 rhel7/11/Dockerfile.postgres-gis.rhel7 create mode 100644 rhel7/11/Dockerfile.postgres.rhel7 create mode 100644 rhel7/11/Dockerfile.upgrade.rhel7 diff --git a/bin/pgbadger/badger-generate.sh b/bin/pgbadger/badger-generate.sh index 8a69b60b5..02b51c195 100755 --- a/bin/pgbadger/badger-generate.sh +++ b/bin/pgbadger/badger-generate.sh @@ -26,4 +26,4 @@ then fi echo_info "Creating pgBadger output.." -/bin/pgbadger ${BADGER_CUSTOM_OPTS} -o /report/index.html /pgdata/${TARGET?}/pg_log/*.log +/bin/pgbadger -f stderr ${BADGER_CUSTOM_OPTS} -o /report/index.html /pgdata/${TARGET?}/pg_log/*.log diff --git a/centos7/11/Dockerfile.backrest-restore.centos7 b/centos7/11/Dockerfile.backrest-restore.centos7 new file mode 100644 index 000000000..d6aa77c2e --- /dev/null +++ b/centos7/11/Dockerfile.backrest-restore.centos7 @@ -0,0 +1,57 @@ +FROM centos:7 + +LABEL name="crunchydata/postgres" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Executes the pgbackrest utility, allowing FULL & DELTA restore capability." \ + description="Executes pgbackrest utility, allowing FULL & DELTA restore capability. Capable of mounting the pgbackrest.conf config file via /pgconf volume in addition to mounting the /backrestrepo for access to pgbackrest archives." \ + io.k8s.description="backrest restore container" \ + io.k8s.display-name="Crunchy backrest restore container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update && yum -y install epel-release \ + && yum -y install \ + hostname \ + gettext \ + nss_wrapper \ + procps-ng \ + && yum -y clean all + +RUN yum -y install postgresql11-server \ + pgbackrest \ + && yum -y clean all + +ENV PGROOT="/usr/pgsql-${PGVERSION}" + +# add path settings for postgres user +ADD conf/.bash_profile /var/lib/pgsql/ + +# set up cpm directory +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgconf /backrestrepo \ + /var/lib/pgsql /var/log/pgbackrest + +RUN chown -R postgres:postgres /opt/cpm \ + /pgdata /pgconf /backrestrepo \ + /var/lib/pgsql /var/log/pgbackrest + +# volume pgconf to store pgbackrest.conf +# volume backrestrepo for pgbackrest to restore from and log + +VOLUME /pgconf /pgdata /backrestrepo + +ADD bin/backrest_restore /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/backrest_restore /opt/cpm/conf + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/centos7/11/Dockerfile.backup.centos7 b/centos7/11/Dockerfile.backup.centos7 new file mode 100644 index 000000000..d6d786208 --- /dev/null +++ b/centos7/11/Dockerfile.backup.centos7 @@ -0,0 +1,42 @@ +FROM centos:7 + +LABEL name="crunchydata/backup" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Performs a pg_basebackup full database backup on a database container" \ + description="Meant to be executed upon demand, this container will run pg_basebackup against a running database container and write the backup files to a mounted directory." \ + io.k8s.description="backup container" \ + io.k8s.display-name="Crunchy backup container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update && yum install -y epel-release \ + && yum -y update glibc-common \ + && yum install -y bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + unzip \ + && yum -y install postgresql11 postgresql11-server \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /pgdata /opt/cpm/conf +ADD bin/backup/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/backup/ /opt/cpm/conf +RUN chown -R postgres:postgres /opt/cpm /pgdata + +VOLUME ["/pgdata"] + +USER 26 + +CMD ["/opt/cpm/bin/start-backupjob.sh"] diff --git a/centos7/11/Dockerfile.collect.centos7 b/centos7/11/Dockerfile.collect.centos7 new file mode 100644 index 000000000..7d6e36c94 --- /dev/null +++ b/centos7/11/Dockerfile.collect.centos7 @@ -0,0 +1,52 @@ +FROM centos:7 + +LABEL name="crunchydata/collect" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Provides metrics for crunchy-postgres" \ + description="Run with crunchy-postgres, crunchy-collect reads the Postgres data directory and has a SQL interface to a database to allow for metrics collection. Used in conjunction with crunchy-prometheus and crunchy-grafana." \ + io.k8s.description="collect container" \ + io.k8s.display-name="Crunchy collect container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +# Install the PGDG yum repo +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +# Install postgres client tools and libraries +RUN yum install -y epel-release \ + && yum -y update \ + && yum -y install \ + gettext \ + postgresql11 \ + postgresql11-libs \ + nss_wrapper \ + && yum -y clean all + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf + +ADD postgres_exporter.tar.gz /opt/cpm/bin +ADD node_exporter.tar.gz /opt/cpm/bin +ADD tools/pgmonitor/exporter/postgres /opt/cpm/conf +ADD bin/collect /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/collect /opt/cpm/conf + +RUN chown -R 2:2 /opt/cpm/bin /opt/cpm/conf + +VOLUME ["/conf"] + +# postgres_exporter +EXPOSE 9187 +# node exporter +EXPOSE 9100 + +USER 2 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/centos7/11/Dockerfile.pgadmin4.centos7 b/centos7/11/Dockerfile.pgadmin4.centos7 new file mode 100644 index 000000000..9b10cf4d3 --- /dev/null +++ b/centos7/11/Dockerfile.pgadmin4.centos7 @@ -0,0 +1,56 @@ +FROM centos:7 + +LABEL name="crunchydata/pgadmin4" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Crunchy Data pgAdmin4 GUI utility" \ + description="Provides GUI for the pgAdmin utility." \ + io.k8s.description="pgadmin4 container" \ + io.k8s.display-name="Crunchy pgadmin4 container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update && yum -y install epel-release \ + && yum -y install glibc-common-*2.17* \ + && yum -y install gcc \ + gettext \ + hostname \ + nss_wrapper \ + openssl \ + procps-ng \ + mod_wsgi mod_ssl \ + && yum -y install postgresql11-devel postgresql11-server pgadmin4-web \ + && yum -y clean all + +ENV PGROOT="/usr/pgsql-${PGVERSION}" + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /var/lib/pgadmin /certs /run/httpd + +ADD bin/pgadmin4/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgadmin4/ /opt/cpm/conf + +RUN cp /opt/cpm/conf/httpd.conf /etc/httpd/conf/httpd.conf \ + && rm /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/ssl.conf + +RUN chown -R 2:0 /usr/lib/python2.7/site-packages/pgadmin4-web \ + && chown -R 2:0 /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd + +RUN ln -sf /var/lib/pgadmin/config_local.py /usr/lib/python2.7/site-packages/pgadmin4-web/config_local.py \ + && ln -sf /var/lib/pgadmin/pgadmin.conf /etc/httpd/conf.d/pgadmin.conf + +EXPOSE 5050 + +VOLUME ["/var/lib/pgadmin", "/certs", "/run/httpd"] + +USER 2 + +CMD ["/opt/cpm/bin/start-pgadmin4.sh"] diff --git a/centos7/11/Dockerfile.pgbadger.centos7 b/centos7/11/Dockerfile.pgbadger.centos7 new file mode 100644 index 000000000..e1fc4e88f --- /dev/null +++ b/centos7/11/Dockerfile.pgbadger.centos7 @@ -0,0 +1,47 @@ +FROM centos:7 + +LABEL name="crunchydata/pgbadger" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="HTTP wrapper around the PGBadger PostgreSQL utility" \ + description="Has an HTTP REST interface. You GET http://host:10000/api/badgergenerate, and it will generate a pgbadger report on a database container's log files." \ + io.k8s.description="pgbadger container" \ + io.k8s.display-name="Crunchy pgbadger container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update \ + && yum -y install epel-release \ + && yum -y install \ + gettext \ + hostname \ + nss_wrapper \ + pgbadger \ + && yum clean all -y + +RUN groupadd -g 26 postgres && useradd -g 26 -u 26 postgres + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /report + +ADD conf/pgbadger /opt/cpm/conf +ADD bin/common /opt/cpm/bin +ADD bin/pgbadger /opt/cpm/bin + +RUN chown -R 26:26 /opt/cpm /report + +# pgbadger port +EXPOSE 10000 + +VOLUME ["/pgdata", "/report"] + +USER 26 + +CMD ["/opt/cpm/bin/start-pgbadger.sh"] diff --git a/centos7/11/Dockerfile.pgbouncer.centos7 b/centos7/11/Dockerfile.pgbouncer.centos7 new file mode 100644 index 000000000..54f502d65 --- /dev/null +++ b/centos7/11/Dockerfile.pgbouncer.centos7 @@ -0,0 +1,46 @@ +FROM centos:7 + +LABEL name="crunchydata/pgbouncer" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Lightweight connection pooler for crunchy-postgres" \ + description="The aim of crunchy-pgbouncer is to lower the performance impact of opening new connections to PostgreSQL; clients connect through this service. It offers session, transaction and statement pooling." \ + io.k8s.description="pgbouncer container" \ + io.k8s.display-name="Crunchy pgbouncer container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update \ + && yum -y install epel-release \ + && yum -y install \ + gettext \ + hostname \ + nss_wrapper \ + pgbouncer \ + postgresql11 \ + procps-ng \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgconf + +ADD bin/pgbouncer /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgbouncer /opt/cpm/conf + +RUN chown -R 2:2 /opt/cpm /pgconf + +EXPOSE 6432 + +VOLUME ["/pgconf"] + +USER 2 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/centos7/11/Dockerfile.pgdump.centos7 b/centos7/11/Dockerfile.pgdump.centos7 new file mode 100644 index 000000000..fe6acb1e7 --- /dev/null +++ b/centos7/11/Dockerfile.pgdump.centos7 @@ -0,0 +1,42 @@ +FROM centos:7 + +LABEL name="crunchydata/pgdump" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Performs a pg_dump on a database container" \ + description="Meant to be executed upon demand, this container will run pg_dump against a running database container and write the backup files to a mounted directory." \ + io.k8s.description="pgdump container" \ + io.k8s.display-name="Crunchy pgdump container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update && yum install -y epel-release \ + && yum -y update glibc-common \ + && yum install -y bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + unzip \ + && yum -y install postgresql11 postgresql11-server \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /pgdata /opt/cpm/conf +ADD bin/pgdump/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgdump/ /opt/cpm/conf +RUN chown -R 26:26 /opt/cpm /pgdata + +VOLUME ["/pgdata"] + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/centos7/11/Dockerfile.pgpool.centos7 b/centos7/11/Dockerfile.pgpool.centos7 new file mode 100644 index 000000000..6597d5658 --- /dev/null +++ b/centos7/11/Dockerfile.pgpool.centos7 @@ -0,0 +1,53 @@ +FROM centos:7 + +LABEL name="crunchydata/pgpool" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Contains the pgpool utility as a PostgreSQL-aware load balancer" \ + description="Offers a smart load balancer in front of a Postgres cluster, sending writes only to the primary and reads to the replica(s). This allows an application to only have a single connection point when interacting with a Postgres cluster." \ + io.k8s.description="pgpool container" \ + io.k8s.display-name="Crunchy pgpool container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update \ + && yum -y install epel-release \ + && yum -y install \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + && yum -y install \ + postgresql11 \ + pgpool-II-11 \ + pgpool-II-11-extensions \ + && yum -y clean all + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf + +ADD bin/pgpool /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgpool /opt/cpm/conf + +RUN ln -sf /opt/cpm/conf/pool_hba.conf /etc/pgpool-II-11/pool_hba.conf \ + && ln -sf /opt/cpm/conf/pgpool/pool_passwd /etc/pgpool-II-11/pool_passwd + +RUN chown -R 2:2 /opt/cpm + +# open up the postgres port +EXPOSE 5432 + +# add volumes to allow override of pgpool config files +VOLUME ["/pgconf"] + +USER 2 + +CMD ["/opt/cpm/bin/startpgpool.sh"] diff --git a/centos7/11/Dockerfile.pgrestore.centos7 b/centos7/11/Dockerfile.pgrestore.centos7 new file mode 100644 index 000000000..690448be8 --- /dev/null +++ b/centos7/11/Dockerfile.pgrestore.centos7 @@ -0,0 +1,43 @@ +FROM centos:7 + +LABEL name="crunchydata/restore" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Performs a pg_restore on a database container" \ + description="Meant to be executed upon demand, this container will run pg_restore against a running database container and write the backup files to a mounted directory." \ + io.k8s.description="pgrestore container" \ + io.k8s.display-name="Crunchy pgrestore` container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update && yum install -y epel-release \ + && yum -y update glibc-common \ + && yum install -y bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + unzip \ + file \ + && yum -y install postgresql11 postgresql11-server \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /pgdata /opt/cpm/conf +ADD bin/pgrestore/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgrestore/ /opt/cpm/conf +RUN chown -R 26:26 /opt/cpm /pgdata + +VOLUME ["/pgdata"] + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/centos7/11/Dockerfile.postgres-gis.centos7 b/centos7/11/Dockerfile.postgres-gis.centos7 new file mode 100644 index 000000000..6932c1137 --- /dev/null +++ b/centos7/11/Dockerfile.postgres-gis.centos7 @@ -0,0 +1,76 @@ +FROM centos:7 + +LABEL name="crunchydata/postgres-gis" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Includes PostGIS extensions on top of crunchy-postgres" \ + description="An identical image of crunchy-postgres with the extra PostGIS packages added for users that require PostGIS." \ + io.k8s.description="postgres-gis container" \ + io.k8s.display-name="Crunchy postgres-gis container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update && yum -y install epel-release \ + && yum -y update glibc-common \ + && yum -y install bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + openssh-server \ + procps-ng \ + rsync \ + && yum -y install postgresql11-server postgresql11-contrib postgresql11 \ + R-core libRmath plr11 \ + pgaudit12_11 \ + pgbackrest \ + postgis24_11 postgis24_11-client \ + && yum -y clean all + +ENV PGROOT="/usr/pgsql-${PGVERSION}" + +# add path settings for postgres user +# bash_profile is loaded in login, but not with exec +# bashrc to set permissions in OCP when using exec +# HOME is / in OCP +ADD conf/.bash_profile /var/lib/pgsql/ +ADD conf/.bash_profile / +ADD conf/.bashrc / + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgwal /pgconf /backup /recover /backrestrepo /sshd + +RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ + /pgdata /pgwal /pgconf /backup /recover /backrestrepo + +# Link pgbackrest.conf to default location for convenience +RUN ln -sf /tmp/pgbackrest.conf /etc/pgbackrest.conf + +# add volumes to allow override of pg_hba.conf and postgresql.conf +# add volumes to allow backup of postgres files +# add volumes to offer a restore feature +# add volumes to allow storage of postgres WAL segment files +# add volumes to locate WAL files to recover with +# add volumes for pgbackrest to write to +# add volumes for sshd host keys + +VOLUME ["/pgconf", "/pgdata", "/pgwal", "/backup", "/recover", "/backrestrepo", "/sshd"] + +# open up the postgres port +EXPOSE 5432 + +ADD bin/postgres /opt/cpm/bin +ADD bin/postgres-gis /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/postgres /opt/cpm/conf +ADD tools/pgmonitor/exporter/postgres /opt/cpm/bin/pgmonitor + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/centos7/11/Dockerfile.postgres.centos7 b/centos7/11/Dockerfile.postgres.centos7 new file mode 100644 index 000000000..c219ed318 --- /dev/null +++ b/centos7/11/Dockerfile.postgres.centos7 @@ -0,0 +1,74 @@ +FROM centos:7 + +LABEL name="crunchydata/postgres" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="PostgreSQL 10.5 (PGDG) on a Centos7 base image" \ + description="Allows multiple deployment methods for PostgreSQL, including basic single primary, streaming replication with synchronous and asynchronous replicas, and stateful sets. Includes utilities for Auditing (pgaudit), statement tracking, and Backup / Restore (pgbackrest, pg_basebackup)." \ + io.k8s.description="postgres container" \ + io.k8s.display-name="Crunchy postgres container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGVERSION="11" PGDG_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/${PGVERSION}/redhat/rhel-7-x86_64/${PGDG_REPO} + +RUN yum -y update \ + && yum -y install epel-release \ + && yum -y update glibc-common \ + && yum -y install bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + openssh-server \ + procps-ng \ + rsync \ + && yum -y install postgresql11-server postgresql11-contrib postgresql11 \ + pgaudit12_11 \ + pgbackrest \ + && yum -y clean all + +ENV PGROOT="/usr/pgsql-${PGVERSION}" + +# add path settings for postgres user +# bash_profile is loaded in login, but not with exec +# bashrc to set permissions in OCP when using exec +# HOME is / in OCP +ADD conf/.bash_profile /var/lib/pgsql/ +ADD conf/.bash_profile / +ADD conf/.bashrc / + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgwal /pgconf /backup /recover /backrestrepo /sshd + +RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ + /pgdata /pgwal /pgconf /backup /recover /backrestrepo + +# Link pgbackrest.conf to default location for convenience +RUN ln -sf /tmp/pgbackrest.conf /etc/pgbackrest.conf + +# add volumes to allow override of pg_hba.conf and postgresql.conf +# add volumes to allow backup of postgres files +# add volumes to offer a restore feature +# add volumes to allow storage of postgres WAL segment files +# add volumes to locate WAL files to recover with +# add volumes for pgbackrest to write to +# add volumes for sshd host keys + +VOLUME ["/pgconf", "/pgdata", "/pgwal", "/backup", "/recover", "/backrestrepo", "/sshd"] + +# open up the postgres port +EXPOSE 5432 + +ADD bin/postgres /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/postgres /opt/cpm/conf +ADD tools/pgmonitor/exporter/postgres /opt/cpm/bin/pgmonitor + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/centos7/11/Dockerfile.upgrade.centos7 b/centos7/11/Dockerfile.upgrade.centos7 new file mode 100644 index 000000000..499707f0e --- /dev/null +++ b/centos7/11/Dockerfile.upgrade.centos7 @@ -0,0 +1,52 @@ +FROM centos:7 + +LABEL name="crunchydata/upgrade" \ + vendor="crunchy data" \ + PostgresVersion="11.0" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Provides a pg_upgrade capability that performs a major PostgreSQL upgrade." \ + description="Provides a means to perform a major PostgreSQL upgrade from 9.5 to 9.6, 9.6 to 10 or 10 to 11. Old data files are left intact." \ + io.k8s.description="postgres upgrade container" \ + io.k8s.display-name="Crunchy postgres upgrade container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +ENV PGDG_95_REPO="pgdg-centos95-9.5-3.noarch.rpm" \ + PGDG_96_REPO="pgdg-centos96-9.6-3.noarch.rpm" \ + PGDG_10_REPO="pgdg-centos10-10-2.noarch.rpm" \ + PGDG_11_REPO="pgdg-centos11-11-2.noarch.rpm" + +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.5/redhat/rhel-7-x86_64/${PGDG_95_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/${PGDG_96_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/${PGDG_10_REPO} +RUN rpm -Uvh https://download.postgresql.org/pub/repos/yum/11/redhat/rhel-7-x86_64/${PGDG_11_REPO} + +RUN yum -y update && yum install -y epel-release \ + && yum -y update glibc-common \ + && yum install -y bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + unzip \ + && yum -y install \ + postgresql95 postgresql95-server postgresql95-contrib pgaudit_95 \ + postgresql96 postgresql96-server postgresql96-contrib pgaudit_96 \ + postgresql10 postgresql11-server postgresql10-contrib pgaudit12_10 \ + postgresql11 postgresql11-server postgresql11-contrib pgaudit12_11 \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /pgolddata /pgnewdata /opt/cpm/conf +ADD bin/upgrade/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/upgrade/ /opt/cpm/conf +RUN chown -R postgres:postgres /opt/cpm /pgolddata /pgnewdata + +VOLUME /pgolddata /pgnewdata + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.backrest-restore.rhel7 b/rhel7/11/Dockerfile.backrest-restore.rhel7 new file mode 100644 index 000000000..8a945874e --- /dev/null +++ b/rhel7/11/Dockerfile.backrest-restore.rhel7 @@ -0,0 +1,69 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/postgres" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Executes the pgbackrest utility, allowing FULL & DELTA restore capability." \ + description="Executes pgbackrest utility, allowing FULL & DELTA restore capability. Capable of mounting the pgbackrest.conf config file via /pgconf volume in addition to mounting the /backrestrepo for access to pgbackrest archives." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="backrest restore container" \ + io.k8s.display-name="Crunchy backrest restore container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/backrestrestore/help.1 /help.1 +COPY conf/atomic/backrestrestore/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y update && yum -y install \ + hostname \ + gettext \ + nss_wrapper \ + procps-ng \ + && yum -y clean all + +RUN yum -y install postgresql11-server \ + crunchy-backrest \ + && yum -y clean all + +ENV PGROOT="/usr/pgsql-${PGVERSION}" + +# add path settings for postgres user +ADD conf/.bash_profile /var/lib/pgsql/ + +# set up cpm directory +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgconf /backrestrepo \ + /var/lib/pgsql /var/log/pgbackrest + +RUN chown -R postgres:postgres /opt/cpm \ + /pgdata /pgconf /backrestrepo \ + /var/lib/pgsql /var/log/pgbackrest + +# volume pgconf to store pgbackrest.conf +# volume backrestrepo for pgbackrest to restore from and log + +VOLUME /pgconf /pgdata /backrestrepo + +ADD bin/backrest_restore /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/backrest_restore /opt/cpm/conf + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.backup.rhel7 b/rhel7/11/Dockerfile.backup.rhel7 new file mode 100644 index 000000000..063b6487b --- /dev/null +++ b/rhel7/11/Dockerfile.backup.rhel7 @@ -0,0 +1,53 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/backup" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Performs a pg_basebackup full database backup on a database container" \ + description="Meant to be executed upon demand, this container will run pg_basebackup against a running database container and write the backup files to a mounted directory." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="backup container" \ + io.k8s.display-name="Crunchy backup container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/backup/help.1 /help.1 +COPY conf/atomic/backup/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y update && yum install -y bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + unzip \ + && yum -y install postgresql11 postgresql11-server \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata +ADD bin/backup/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/backup/ /opt/cpm/conf +RUN chown -R postgres:postgres /opt/cpm /pgdata + +VOLUME ["/pgdata"] + +USER 26 + +CMD ["/opt/cpm/bin/start-backupjob.sh"] diff --git a/rhel7/11/Dockerfile.collect.rhel7 b/rhel7/11/Dockerfile.collect.rhel7 new file mode 100644 index 000000000..1aed9d60e --- /dev/null +++ b/rhel7/11/Dockerfile.collect.rhel7 @@ -0,0 +1,66 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/collect" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Provides metrics for crunchy-postgres" \ + description="Run with crunchy-postgres, crunchy-collect reads the Postgres data directory and has a SQL interface to a database to allow for metrics collection. Used in conjunction with crunchy-prometheus and crunchy-grafana." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="collect container" \ + io.k8s.display-name="Crunchy collect container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/collect/help.1 /help.1 +COPY conf/atomic/collect/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + +# Install postgres client tools and libraries +RUN yum install -y epel-release \ + && yum -y update \ + && yum -y install \ + gettext \ + postgresql11 \ + postgresql11-libs \ + nss_wrapper \ + hostname \ + && yum -y clean all + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf + +ADD postgres_exporter.tar.gz /opt/cpm/bin +ADD node_exporter.tar.gz /opt/cpm/bin +ADD tools/pgmonitor/exporter/postgres /opt/cpm/conf +ADD bin/collect /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/collect /opt/cpm/conf + +RUN chown -R 2:2 /opt/cpm/bin /opt/cpm/conf + +VOLUME ["/conf"] + +# postgres_exporter +EXPOSE 9187 +# node exporter +EXPOSE 9100 + +USER 2 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.pgadmin4.rhel7 b/rhel7/11/Dockerfile.pgadmin4.rhel7 new file mode 100644 index 000000000..ab9894366 --- /dev/null +++ b/rhel7/11/Dockerfile.pgadmin4.rhel7 @@ -0,0 +1,73 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/pgadmin4" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Crunchy Data pgAdmin4 GUI utility" \ + description="Provides GUI for the pgAdmin utility." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="pgadmin4 container" \ + io.k8s.display-name="Crunchy pgadmin4 container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/pgadmin4/help.1 /help.1 +COPY conf/atomic/pgadmin4/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + +RUN yum -y update \ + && yum -y install epel-release \ + && yum -y install \ + glibc-common \ + gcc \ + gettext \ + hostname \ + nss_wrapper \ + openssl \ + procps-ng \ + mod_wsgi mod_ssl \ + && yum --enablerepo rhel-7-server-extras-rpms -y install pgadmin4-web \ + && yum -y install postgresql11-devel postgresql11-server \ + && yum -y clean all + +ENV PGROOT="/usr/pgsql-${PGVERSION}" + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /var/lib/pgadmin /certs /run/httpd + +ADD bin/pgadmin4/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgadmin4/ /opt/cpm/conf + +RUN cp /opt/cpm/conf/httpd.conf /etc/httpd/conf/httpd.conf \ + && rm /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/ssl.conf + +RUN chown -R 2:0 /usr/lib/python2.7/site-packages/pgadmin4-web \ + && chown -R 2:0 /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd + +RUN ln -sf /var/lib/pgadmin/config_local.py /usr/lib/python2.7/site-packages/pgadmin4-web/config_local.py \ + && ln -sf /var/lib/pgadmin/pgadmin.conf /etc/httpd/conf.d/pgadmin.conf + +EXPOSE 5050 + +VOLUME ["/var/lib/pgadmin", "/certs", "/run/httpd"] + +USER 2 + +CMD ["/opt/cpm/bin/start-pgadmin4.sh"] diff --git a/rhel7/11/Dockerfile.pgbadger.rhel7 b/rhel7/11/Dockerfile.pgbadger.rhel7 new file mode 100644 index 000000000..5ebbc0a95 --- /dev/null +++ b/rhel7/11/Dockerfile.pgbadger.rhel7 @@ -0,0 +1,61 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/pgbadger" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="HTTP wrapper around the PGBadger PostgreSQL utility" \ + description="Has an HTTP REST interface. You GET http://host:10000/api/badgergenerate, and it will generate a pgbadger report on a database container's log files." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="pgbadger container" \ + io.k8s.display-name="Crunchy pgbadger container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/pgbadger/help.1 /help.1 +COPY conf/atomic/pgbadger/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + +RUN yum -y update \ + && yum -y install epel-release \ + && yum -y install \ + gettext \ + hostname \ + nss_wrapper \ + pgbadger \ + && yum clean all -y + +RUN groupadd -g 26 postgres && useradd -g 26 -u 26 postgres + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /report + +ADD conf/pgbadger /opt/cpm/conf +ADD bin/common /opt/cpm/bin +ADD bin/pgbadger /opt/cpm/bin + +RUN chown -R 26:26 /opt/cpm /report + +# pgbadger port +EXPOSE 10000 + +VOLUME ["/pgdata", "/report"] + +USER 26 + +CMD ["/opt/cpm/bin/start-pgbadger.sh"] diff --git a/rhel7/11/Dockerfile.pgbouncer.rhel7 b/rhel7/11/Dockerfile.pgbouncer.rhel7 new file mode 100644 index 000000000..616a95b2b --- /dev/null +++ b/rhel7/11/Dockerfile.pgbouncer.rhel7 @@ -0,0 +1,60 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/pgbouncer" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Lightweight connection pooler for crunchy-postgres" \ + description="The aim of crunchy-pgbouncer is to lower the performance impact of opening new connections to PostgreSQL; clients connect through this service. It offers session, transaction and statement pooling." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="pgbouncer container" \ + io.k8s.display-name="Crunchy pgbouncer container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/pgbouncer/help.1 /help.1 +COPY conf/atomic/pgbouncer/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + +RUN yum -y update \ + && yum -y install epel-release \ + && yum -y install \ + gettext \ + hostname \ + nss_wrapper \ + pgbouncer \ + postgresql11 \ + procps-ng \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgconf + +ADD bin/pgbouncer /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgbouncer /opt/cpm/conf + +RUN chown -R 2:2 /opt/cpm /pgconf + +EXPOSE 6432 + +VOLUME ["/pgconf"] + +USER 2 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.pgdump.rhel7 b/rhel7/11/Dockerfile.pgdump.rhel7 new file mode 100644 index 000000000..878a3b3e7 --- /dev/null +++ b/rhel7/11/Dockerfile.pgdump.rhel7 @@ -0,0 +1,53 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/pgdump" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Performs a pg_dump on a database container" \ + description="Meant to be executed upon demand, this container will run pg_dump against a running database container and write the backup files to a mounted directory." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="pgdump container" \ + io.k8s.display-name="Crunchy pgdump container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/pgdump/help.1 /help.1 +COPY conf/atomic/pgdump/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y update && yum install -y bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + unzip \ + && yum -y install postgresql11 postgresql11-server \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata +ADD bin/pgdump/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgdump/ /opt/cpm/conf +RUN chown -R 26:26 /opt/cpm /pgdata + +VOLUME ["/pgdata"] + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.pgpool.rhel7 b/rhel7/11/Dockerfile.pgpool.rhel7 new file mode 100644 index 000000000..5ec98656e --- /dev/null +++ b/rhel7/11/Dockerfile.pgpool.rhel7 @@ -0,0 +1,67 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/pgpool" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Contains the pgpool utility as a PostgreSQL-aware load balancer" \ + description="Offers a smart load balancer in front of a Postgres cluster, sending writes only to the primary and reads to the replica(s). This allows an application to only have a single connection point when interacting with a Postgres cluster." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="pgpool container" \ + io.k8s.display-name="Crunchy pgpool container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/pgpool/help.1 /help.1 +COPY conf/atomic/pgpool/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + +RUN yum -y update \ + && yum -y install epel-release \ + && yum -y install \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + && yum -y install \ + postgresql11 \ + pgpool-II-11 \ + pgpool-II-11-extensions \ + && yum -y clean all + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf + +ADD bin/pgpool /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgpool /opt/cpm/conf + +RUN ln -sf /opt/cpm/conf/pool_hba.conf /etc/pgpool-II-11/pool_hba.conf \ + && ln -sf /opt/cpm/conf/pgpool/pool_passwd /etc/pgpool-II-11/pool_passwd + +RUN chown -R 2:2 /opt/cpm + +# open up the postgres port +EXPOSE 5432 + +# add volumes to allow override of pgpool config files +VOLUME ["/pgconf"] + +USER 2 + +CMD ["/opt/cpm/bin/startpgpool.sh"] diff --git a/rhel7/11/Dockerfile.pgrestore.rhel7 b/rhel7/11/Dockerfile.pgrestore.rhel7 new file mode 100644 index 000000000..688de714f --- /dev/null +++ b/rhel7/11/Dockerfile.pgrestore.rhel7 @@ -0,0 +1,54 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/restore" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Performs a pg_restore on a database container" \ + description="Meant to be executed upon demand, this container will run pg_restore against a running database container and write the backup files to a mounted directory." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="pgrestore container" \ + io.k8s.display-name="Crunchy pgrestore container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/pgrestore/help.1 /help.1 +COPY conf/atomic/pgrestore/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y update && yum install -y bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + unzip \ + file \ + && yum -y install postgresql11 postgresql11-server \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata +ADD bin/pgrestore/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/pgrestore/ /opt/cpm/conf +RUN chown -R 26:26 /opt/cpm /pgdata + +VOLUME ["/pgdata"] + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.postgres-gis.rhel7 b/rhel7/11/Dockerfile.postgres-gis.rhel7 new file mode 100644 index 000000000..6e0432b30 --- /dev/null +++ b/rhel7/11/Dockerfile.postgres-gis.rhel7 @@ -0,0 +1,95 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/postgres-gis" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Includes PostGIS extensions on top of crunchy-postgres" \ + description="An identical image of crunchy-postgres with the extra PostGIS and pgrouting packages added for users that require PostGIS." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="postgres-gis container" \ + io.k8s.display-name="Crunchy postgres-gis container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/postgres-gis/help.1 /help.1 +COPY conf/atomic/postgres-gis/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# if you ever need to install package docs inside the container, uncomment +#RUN sed -i '/nodocs/d' /etc/yum.conf + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y update && yum --enablerepo=epel --enablerepo="rhel-7-server-optional-rpms" -y install bind-utils \ + gettext \ + hostname \ + R-core libRmath texinfo-tex texlive-epsf \ + nss_wrapper \ + openssh-server \ + procps-ng \ + rsync \ + && yum -y reinstall glibc-common \ + && yum -y install postgresql11 postgresql11-contrib postgresql11-server \ + pgaudit11 pgaudit11_set_user \ + crunchy-backrest plr11 \ + postgis24_11 postgis24_11-client pgrouting_11 \ + && yum -y --setopt=tsflags='' install pgaudit_analyze \ + && yum -y clean all + +ENV PGROOT="/usr/pgsql-${PGVERSION}" + +# add path settings for postgres user +# bash_profile is loaded in login, but not with exec +# bashrc to set permissions in OCP when using exec +# HOME is / in OCP +ADD conf/.bash_profile /var/lib/pgsql/ +ADD conf/.bash_profile / +ADD conf/.bashrc / + +# set up cpm directory +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgwal /pgconf /backup /recover /backrestrepo /sshd + +RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ + /pgdata /pgwal /pgconf /backup /recover /backrestrepo + +# Link pgbackrest.conf to default location for convenience +# Remove nologin file to prevent sshd from being blocked +RUN ln -sf /tmp/pgbackrest.conf /etc/pgbackrest.conf \ + && rm -f /run/nologin + +# add volumes to allow override of pg_hba.conf and postgresql.conf +# add volumes to allow backup of postgres files +# add volumes to offer a restore feature +# add volumes to allow storage of postgres WAL segment files +# add volumes to locate WAL files to recover with +# add volumes for pgbackrest to write to +# add volumes for sshd host keys + +VOLUME ["/pgconf", "/pgdata", "/pgwal", "/backup", "/recover", "/backrestrepo", "/sshd"] + +# open up the postgres port +EXPOSE 5432 + +ADD bin/postgres /opt/cpm/bin +ADD bin/postgres-gis /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/postgres /opt/cpm/conf +ADD tools/pgmonitor/exporter/postgres /opt/cpm/bin/pgmonitor + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.postgres.rhel7 b/rhel7/11/Dockerfile.postgres.rhel7 new file mode 100644 index 000000000..ca8c243da --- /dev/null +++ b/rhel7/11/Dockerfile.postgres.rhel7 @@ -0,0 +1,92 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/postgres" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="PostgreSQL 11.0 (PGDG) on a RHEL7 base image" \ + description="Allows multiple deployment methods for PostgreSQL, including basic single primary, streaming replication with synchronous and asynchronous replicas, and stateful sets. Includes utilities for Auditing (pgaudit), statement tracking, and Backup / Restore (pgbackrest, pg_basebackup)." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="postgres container" \ + io.k8s.display-name="Crunchy postgres container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/postgres/help.1 /help.1 +COPY conf/atomic/postgres/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# if you ever need to install package docs inside the container, uncomment +#RUN sed -i '/nodocs/d' /etc/yum.conf + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y update && yum -y install bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + openssh-server \ + procps-ng \ + rsync \ + && yum -y reinstall glibc-common \ + && yum -y install postgresql11 postgresql11-contrib postgresql11-server \ + pgaudit11 pgaudit11_set_user \ + crunchy-backrest \ + && yum -y --setopt=tsflags='' install pgaudit_analyze \ + && yum -y clean all + +ENV PGROOT="/usr/pgsql-${PGVERSION}" + +# add path settings for postgres user +# bash_profile is loaded in login, but not with exec +# bashrc to set permissions in OCP when using exec +# HOME is / in OCP +ADD conf/.bash_profile /var/lib/pgsql/ +ADD conf/.bash_profile / +ADD conf/.bashrc / + +# set up cpm directory +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgwal /pgconf /backup /recover /backrestrepo /sshd + +RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ + /pgdata /pgwal /pgconf /backup /recover /backrestrepo + +# Link pgbackrest.conf to default location for convenience +# Remove nologin file to prevent sshd from being blocked +RUN ln -sf /tmp/pgbackrest.conf /etc/pgbackrest.conf \ + && rm -f /run/nologin + +# add volumes to allow override of pg_hba.conf and postgresql.conf +# add volumes to allow backup of postgres files +# add volumes to offer a restore feature +# add volumes to allow storage of postgres WAL segment files +# add volumes to locate WAL files to recover with +# add volumes for pgbackrest to write to +# add volumes for sshd host keys + +VOLUME ["/pgconf", "/pgdata", "/pgwal", "/backup", "/recover", "/backrestrepo", "/sshd"] + +# open up the postgres port +EXPOSE 5432 + +ADD bin/postgres /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/postgres /opt/cpm/conf +ADD tools/pgmonitor/exporter/postgres /opt/cpm/bin/pgmonitor + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.upgrade.rhel7 b/rhel7/11/Dockerfile.upgrade.rhel7 new file mode 100644 index 000000000..7c016d231 --- /dev/null +++ b/rhel7/11/Dockerfile.upgrade.rhel7 @@ -0,0 +1,61 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/upgrade" \ + vendor="crunchy data" \ + PostgresVersion="11" \ + PostgresFullVersion="11.0" \ + Version="7.5" \ + Release="2.2.0" \ + url="https://crunchydata.com" \ + summary="Provides a pg_upgrade capability that performs a major PostgreSQL upgrade." \ + description="Provides a means to perform a major PostgreSQL upgrade from 9.5 to 9.6 and 9.6 to 10 and 10 to 11. Old data files are left intact." \ + run="" \ + start="" \ + stop="" \ + io.k8s.description="postgres upgrade container" \ + io.k8s.display-name="Crunchy postgres upgrade container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database" + +COPY conf/atomic/upgrade/help.1 /help.1 +COPY conf/atomic/upgrade/help.md /help.md +COPY conf/licenses /licenses + +ENV PGVERSION="11" + +# Crunchy Postgres repo +ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/crunchypg11.repo /etc/yum.repos.d/ +ADD conf/crunchypg10.repo /etc/yum.repos.d/ +ADD conf/crunchypg96.repo /etc/yum.repos.d/ +ADD conf/crunchypg95.repo /etc/yum.repos.d/ +RUN rpm --import CRUNCHY-GPG-KEY.public + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y update && yum -y update glibc-common \ + && yum install -y bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + unzip \ + && yum -y install \ + postgresql95 postgresql95-server postgresql95-contrib pgaudit95 \ + postgresql96 postgresql96-server postgresql96-contrib pgaudit96 \ + postgresql10 postgresql11-server postgresql10-contrib pgaudit10 \ + postgresql11 postgresql11-server postgresql11-contrib pgaudit11 \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /pgolddata /pgnewdata /opt/cpm/conf +ADD bin/upgrade/ /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/upgrade/ /opt/cpm/conf +RUN chown -R postgres:postgres /opt/cpm /pgolddata /pgnewdata + +VOLUME /pgolddata /pgnewdata + +USER 26 + +CMD ["/opt/cpm/bin/start.sh"] From ff9398ef9981f8d50f9909efbbc84d523caffe28 Mon Sep 17 00:00:00 2001 From: Paul Cahoon Date: Fri, 14 Sep 2018 23:22:49 -0400 Subject: [PATCH 032/179] removed unused version target --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index 799381330..81831ead7 100644 --- a/Makefile +++ b/Makefile @@ -138,10 +138,6 @@ vac: versiontest docker build -t crunchy-vacuum -f $(CCP_BASEOS)/Dockerfile.vacuum.$(CCP_BASEOS) . docker tag crunchy-vacuum $(CCP_IMAGE_PREFIX)/crunchy-vacuum:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) -version: - docker build -t crunchy-version -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.version.$(CCP_BASEOS) . - docker tag crunchy-version $(CCP_IMAGE_PREFIX)/crunchy-version:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) - #================= # Utility targets #================= From 4c4d5526dd562d84f6a58c8bfc872473b1735e48 Mon Sep 17 00:00:00 2001 From: Sarah Conway Date: Sat, 15 Sep 2018 09:24:08 -0700 Subject: [PATCH 033/179] issue #688 separate subdirectories between examples --- examples/common.sh | 11 ++++------- .../backrest/async-archiving/backrest-pv-nfs.json | 4 ++-- .../kube/backrest/async-archiving/backrest-pv.json | 4 ++-- examples/kube/backrest/async-archiving/cleanup.sh | 2 -- examples/kube/backrest/backup/backrest-pv-nfs.json | 4 ++-- examples/kube/backrest/backup/backrest-pv.json | 4 ++-- examples/kube/backrest/backup/cleanup.sh | 2 -- examples/kube/backrest/full/backrest-pv-nfs.json | 2 +- examples/kube/backrest/full/backrest-pv.json | 2 +- examples/kube/backrest/full/cleanup.sh | 2 -- examples/kube/backup/backup-pv-nfs.json | 2 +- examples/kube/backup/backup-pv.json | 2 +- examples/kube/custom-config-ssl/cleanup.sh | 3 --- .../custom-config-ssl/custom-config-ssl-pv-nfs.json | 4 ++-- .../kube/custom-config-ssl/custom-config-ssl-pv.json | 4 ++-- examples/kube/custom-config/cleanup.sh | 4 ---- examples/kube/custom-config/custom-config-pv-nfs.json | 6 +++--- examples/kube/custom-config/custom-config-pv.json | 6 +++--- examples/kube/metrics/cleanup.sh | 6 +----- examples/kube/metrics/metrics-pv-nfs.json | 4 ++-- examples/kube/metrics/metrics-pv.json | 4 ++-- examples/kube/pgadmin4-http/cleanup.sh | 9 +-------- examples/kube/pgadmin4-http/pgadmin4-http-pv-nfs.json | 2 +- examples/kube/pgadmin4-http/pgadmin4-http-pv.json | 2 +- examples/kube/pgadmin4-https/cleanup.sh | 9 +-------- .../kube/pgadmin4-https/pgadmin4-https-pv-nfs.json | 2 +- examples/kube/pgadmin4-https/pgadmin4-https-pv.json | 2 +- examples/kube/pgdump/pgdump-pv-nfs.json | 2 +- examples/kube/pgdump/pgdump-pv.json | 2 +- examples/kube/pitr/backup-pitr-pv-nfs.json | 2 +- examples/kube/pitr/backup-pitr-pv.json | 2 +- examples/kube/pitr/cleanup.sh | 3 --- examples/kube/pitr/pitr-pv-nfs.json | 4 ++-- examples/kube/pitr/pitr-pv.json | 4 ++-- examples/kube/pitr/restore-pitr-pv-nfs.json | 4 ++-- examples/kube/pitr/restore-pitr-pv.json | 4 ++-- examples/kube/postgres-sshd/cleanup.sh | 3 --- examples/kube/postgres-sshd/postgres-sshd-pv-nfs.json | 4 ++-- examples/kube/postgres-sshd/postgres-sshd-pv.json | 4 ++-- examples/kube/primary-deployment/cleanup.sh | 1 - .../primary-deployment/primary-deployment-pv-nfs.json | 6 +++--- .../primary-deployment/primary-deployment-pv.json | 6 +++--- examples/kube/primary/primary-pv-nfs.json | 2 +- examples/kube/primary/primary-pv.json | 2 +- examples/kube/restore/restore-pv-nfs.json | 2 +- examples/kube/restore/restore-pv.json | 2 +- examples/kube/statefulset/cleanup.sh | 4 +--- examples/kube/statefulset/statefulset-pv-nfs.json | 6 +++--- examples/kube/statefulset/statefulset-pv.json | 6 +++--- examples/kube/upgrade/upgrade-pv-nfs.json | 2 +- examples/kube/upgrade/upgrade-pv.json | 2 +- 51 files changed, 72 insertions(+), 115 deletions(-) diff --git a/examples/common.sh b/examples/common.sh index e5c70127c..e4625f657 100755 --- a/examples/common.sh +++ b/examples/common.sh @@ -44,13 +44,6 @@ function dir_check_rm() { fi } -function file_check_rm() { - if [[ -f ${CCP_STORAGE_PATH}/${1?} ]] - then - sudo rm -f ${CCP_STORAGE_PATH?}/${1?} && echo_info "Deleted ${1?} from the data directory." || echo_err "${1?} was not successfully deleted from the data directory." - fi -} - function create_storage { env_check_err "CCP_STORAGE_CAPACITY" env_check_err "CCP_STORAGE_MODE" @@ -63,9 +56,13 @@ function create_storage { elif [[ ! -z ${CCP_NFS_IP} ]] then echo_info "CCP_NFS_IP is set. Creating NFS based storage volumes." + sudo mkdir -p ${CCP_STORAGE_PATH?}/${1?} + sudo chmod -R 777 ${CCP_STORAGE_PATH?}/${1?} PV="${1?}-pv-nfs.json" else echo_info "CCP_NFS_IP and CCP_STORAGE_CLASS not set. Creating HostPath based storage volumes." + sudo mkdir -p ${CCP_STORAGE_PATH?}/${1?} + sudo chmod -R 777 ${CCP_STORAGE_PATH?}/${1?} PV="${1?}-pv.json" fi diff --git a/examples/kube/backrest/async-archiving/backrest-pv-nfs.json b/examples/kube/backrest/async-archiving/backrest-pv-nfs.json index dfc23ef07..2a614dca6 100644 --- a/examples/kube/backrest/async-archiving/backrest-pv-nfs.json +++ b/examples/kube/backrest/async-archiving/backrest-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/backrest-async-archive", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/backrest-async-archive", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/backrest/async-archiving/backrest-pv.json b/examples/kube/backrest/async-archiving/backrest-pv.json index c52be40e0..656eab8f0 100644 --- a/examples/kube/backrest/async-archiving/backrest-pv.json +++ b/examples/kube/backrest/async-archiving/backrest-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/backrest" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/backrest" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/backrest/async-archiving/cleanup.sh b/examples/kube/backrest/async-archiving/cleanup.sh index 442b6a17a..4617efdbf 100755 --- a/examples/kube/backrest/async-archiving/cleanup.sh +++ b/examples/kube/backrest/async-archiving/cleanup.sh @@ -26,5 +26,3 @@ fi $CCPROOT/examples/waitforterm.sh backrest-async-archive ${CCP_CLI?} dir_check_rm "backrest-async-archive" -dir_check_rm "backrest-async-archive-spool" -dir_check_rm "backrest-async-archive-backups" diff --git a/examples/kube/backrest/backup/backrest-pv-nfs.json b/examples/kube/backrest/backup/backrest-pv-nfs.json index 09c212abf..18afc8581 100644 --- a/examples/kube/backrest/backup/backrest-pv-nfs.json +++ b/examples/kube/backrest/backup/backrest-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/backrest", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/backrest", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/backrest/backup/backrest-pv.json b/examples/kube/backrest/backup/backrest-pv.json index 3b0535602..c52b41479 100644 --- a/examples/kube/backrest/backup/backrest-pv.json +++ b/examples/kube/backrest/backup/backrest-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/backrest" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/backrest" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/backrest/backup/cleanup.sh b/examples/kube/backrest/backup/cleanup.sh index 1a6a4f714..027d2cfe1 100755 --- a/examples/kube/backrest/backup/cleanup.sh +++ b/examples/kube/backrest/backup/cleanup.sh @@ -26,5 +26,3 @@ fi $CCPROOT/examples/waitforterm.sh backrest ${CCP_CLI?} dir_check_rm "backrest" -dir_check_rm "backrest-backups" -dir_check_rm "backrest-spool" diff --git a/examples/kube/backrest/full/backrest-pv-nfs.json b/examples/kube/backrest/full/backrest-pv-nfs.json index bdaa98f4b..2b1cbc6dd 100644 --- a/examples/kube/backrest/full/backrest-pv-nfs.json +++ b/examples/kube/backrest/full/backrest-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/backrest-full-restored", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/backrest/full/backrest-pv.json b/examples/kube/backrest/full/backrest-pv.json index a8504268f..d92b65693 100644 --- a/examples/kube/backrest/full/backrest-pv.json +++ b/examples/kube/backrest/full/backrest-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/backrest-full-restored" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/backrest/full/cleanup.sh b/examples/kube/backrest/full/cleanup.sh index 3e9cb8e5a..41031811f 100755 --- a/examples/kube/backrest/full/cleanup.sh +++ b/examples/kube/backrest/full/cleanup.sh @@ -25,5 +25,3 @@ ${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} configmap br-full-restore-pgcon $CCPROOT/examples/waitforterm.sh backrest ${CCP_CLI?} dir_check_rm "backrest-full-restored" -dir_check_rm "backrest-full-restored-backups" -dir_check_rm "backrest-full-restored-spool" diff --git a/examples/kube/backup/backup-pv-nfs.json b/examples/kube/backup/backup-pv-nfs.json index e862f59d8..141c67402 100644 --- a/examples/kube/backup/backup-pv-nfs.json +++ b/examples/kube/backup/backup-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/backup", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/backup/backup-pv.json b/examples/kube/backup/backup-pv.json index 187028173..aff106dc8 100644 --- a/examples/kube/backup/backup-pv.json +++ b/examples/kube/backup/backup-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/backup" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/custom-config-ssl/cleanup.sh b/examples/kube/custom-config-ssl/cleanup.sh index b9f08f1ad..805c8032a 100755 --- a/examples/kube/custom-config-ssl/cleanup.sh +++ b/examples/kube/custom-config-ssl/cleanup.sh @@ -31,10 +31,7 @@ fi $CCPROOT/examples/waitforterm.sh custom-config-ssl ${CCP_CLI?} -dir_check_rm "archive" -dir_check_rm "backup" dir_check_rm "custom-config-ssl" -file_check_rm "db-stanza-create.log" rm -rf ${DIR?}/certs rm -rf ${DIR?}/out diff --git a/examples/kube/custom-config-ssl/custom-config-ssl-pv-nfs.json b/examples/kube/custom-config-ssl/custom-config-ssl-pv-nfs.json index d01a2cf2c..0a3e78d48 100644 --- a/examples/kube/custom-config-ssl/custom-config-ssl-pv-nfs.json +++ b/examples/kube/custom-config-ssl/custom-config-ssl-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/custom-config-ssl", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/custom-config-ssl", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/custom-config-ssl/custom-config-ssl-pv.json b/examples/kube/custom-config-ssl/custom-config-ssl-pv.json index 5d758e1a1..06a5ff06e 100644 --- a/examples/kube/custom-config-ssl/custom-config-ssl-pv.json +++ b/examples/kube/custom-config-ssl/custom-config-ssl-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/custom-config-ssl" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/custom-config-ssl" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/custom-config/cleanup.sh b/examples/kube/custom-config/cleanup.sh index 6ebbdd8bf..fb8cde0f4 100755 --- a/examples/kube/custom-config/cleanup.sh +++ b/examples/kube/custom-config/cleanup.sh @@ -28,8 +28,4 @@ fi $CCPROOT/examples/waitforterm.sh custom-config ${CCP_CLI?} -dir_check_rm "archive" -dir_check_rm "backup" dir_check_rm "custom-config" -dir_check_rm "custom-config-wal" -file_check_rm "db-stanza-create.log" diff --git a/examples/kube/custom-config/custom-config-pv-nfs.json b/examples/kube/custom-config/custom-config-pv-nfs.json index ae2778f37..a161e73f5 100644 --- a/examples/kube/custom-config/custom-config-pv-nfs.json +++ b/examples/kube/custom-config/custom-config-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/custom-config", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/custom-config", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -57,7 +57,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/custom-config", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/custom-config/custom-config-pv.json b/examples/kube/custom-config/custom-config-pv.json index 5c08cd33b..1aa1764bf 100644 --- a/examples/kube/custom-config/custom-config-pv.json +++ b/examples/kube/custom-config/custom-config-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/custom-config" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/custom-config" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -55,7 +55,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/custom-config" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/metrics/cleanup.sh b/examples/kube/metrics/cleanup.sh index 317417801..b5fbd2cfd 100755 --- a/examples/kube/metrics/cleanup.sh +++ b/examples/kube/metrics/cleanup.sh @@ -33,8 +33,4 @@ $CCPROOT/examples/waitforterm.sh metrics ${CCP_CLI?} $CCPROOT/examples/waitforterm.sh primary ${CCP_CLI?} $CCPROOT/examples/waitforterm.sh replica ${CCP_CLI?} -dir_check_rm "grafana" -dir_check_rm "wal" -file_check_rm "defaults.ini" -file_check_rm "lock" -file_check_rm "prometheus.yml" +dir_check_rm "metrics" diff --git a/examples/kube/metrics/metrics-pv-nfs.json b/examples/kube/metrics/metrics-pv-nfs.json index 842190d8d..eb4dec713 100644 --- a/examples/kube/metrics/metrics-pv-nfs.json +++ b/examples/kube/metrics/metrics-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/metrics", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/metrics", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/metrics/metrics-pv.json b/examples/kube/metrics/metrics-pv.json index 4a871b701..71c78efc7 100644 --- a/examples/kube/metrics/metrics-pv.json +++ b/examples/kube/metrics/metrics-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/metrics" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/metrics" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/pgadmin4-http/cleanup.sh b/examples/kube/pgadmin4-http/cleanup.sh index 9439852a8..655a41ffa 100755 --- a/examples/kube/pgadmin4-http/cleanup.sh +++ b/examples/kube/pgadmin4-http/cleanup.sh @@ -26,11 +26,4 @@ fi $CCPROOT/examples/waitforterm.sh pgadmin4-http ${CCP_CLI?} -dir_check_rm "sessions" -dir_check_rm "storage" -file_check_rm "access_log" -file_check_rm "config_local.py" -file_check_rm "error_log" -file_check_rm "pgadmin4.db" -file_check_rm "pgadmin4.conf" -file_check_rm "pgadmin.log" +dir_check_rm "pgadmin4-http" diff --git a/examples/kube/pgadmin4-http/pgadmin4-http-pv-nfs.json b/examples/kube/pgadmin4-http/pgadmin4-http-pv-nfs.json index d1a50499f..1310b0b5d 100644 --- a/examples/kube/pgadmin4-http/pgadmin4-http-pv-nfs.json +++ b/examples/kube/pgadmin4-http/pgadmin4-http-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/pgadmin4-http", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/pgadmin4-http/pgadmin4-http-pv.json b/examples/kube/pgadmin4-http/pgadmin4-http-pv.json index 1331a760a..4e913ea3d 100644 --- a/examples/kube/pgadmin4-http/pgadmin4-http-pv.json +++ b/examples/kube/pgadmin4-http/pgadmin4-http-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/pgadmin4-http" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/pgadmin4-https/cleanup.sh b/examples/kube/pgadmin4-https/cleanup.sh index f9dd54b1b..2b31478a8 100755 --- a/examples/kube/pgadmin4-https/cleanup.sh +++ b/examples/kube/pgadmin4-https/cleanup.sh @@ -32,11 +32,4 @@ rm -f ${DIR?}/server.crt ${DIR?}/server.key ${DIR?}/privkey.pem $CCPROOT/examples/waitforterm.sh pgadmin4-https ${CCP_CLI?} -file_check_rm "access_log" -file_check_rm "config_local.py" -file_check_rm "error_log" -file_check_rm "pgadmin4.db" -file_check_rm "pgadmin4.conf" -file_check_rm "pgadmin.log" -file_check_rm "sessions" -file_check_rm "storage" +dir_check_rm "pgadmin4-https" diff --git a/examples/kube/pgadmin4-https/pgadmin4-https-pv-nfs.json b/examples/kube/pgadmin4-https/pgadmin4-https-pv-nfs.json index 3a2216e1c..e83f0de7d 100644 --- a/examples/kube/pgadmin4-https/pgadmin4-https-pv-nfs.json +++ b/examples/kube/pgadmin4-https/pgadmin4-https-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/pgadmin4-https", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/pgadmin4-https/pgadmin4-https-pv.json b/examples/kube/pgadmin4-https/pgadmin4-https-pv.json index f749e4381..362d8e4f6 100644 --- a/examples/kube/pgadmin4-https/pgadmin4-https-pv.json +++ b/examples/kube/pgadmin4-https/pgadmin4-https-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/pgadmin4-https" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/pgdump/pgdump-pv-nfs.json b/examples/kube/pgdump/pgdump-pv-nfs.json index 411020ff5..10d6320b9 100644 --- a/examples/kube/pgdump/pgdump-pv-nfs.json +++ b/examples/kube/pgdump/pgdump-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/pgdump", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/pgdump/pgdump-pv.json b/examples/kube/pgdump/pgdump-pv.json index dc3c42f58..372bedb06 100644 --- a/examples/kube/pgdump/pgdump-pv.json +++ b/examples/kube/pgdump/pgdump-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/pgdump" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/pitr/backup-pitr-pv-nfs.json b/examples/kube/pitr/backup-pitr-pv-nfs.json index 4e3618034..d2095100c 100644 --- a/examples/kube/pitr/backup-pitr-pv-nfs.json +++ b/examples/kube/pitr/backup-pitr-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/pitr", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/pitr/backup-pitr-pv.json b/examples/kube/pitr/backup-pitr-pv.json index 93e5e0236..de613fa5a 100644 --- a/examples/kube/pitr/backup-pitr-pv.json +++ b/examples/kube/pitr/backup-pitr-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/pitr" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/pitr/cleanup.sh b/examples/kube/pitr/cleanup.sh index 2870bf724..a77f15009 100755 --- a/examples/kube/pitr/cleanup.sh +++ b/examples/kube/pitr/cleanup.sh @@ -30,6 +30,3 @@ if [ -z "$CCP_STORAGE_CLASS" ]; then fi dir_check_rm "pitr" -dir_check_rm "pitr-wal" -dir_check_rm "pitr-backups" -dir_check_rm "restore-pitr" diff --git a/examples/kube/pitr/pitr-pv-nfs.json b/examples/kube/pitr/pitr-pv-nfs.json index 2e6360f3d..45c37d944 100644 --- a/examples/kube/pitr/pitr-pv-nfs.json +++ b/examples/kube/pitr/pitr-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/pitr", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/pitr", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/pitr/pitr-pv.json b/examples/kube/pitr/pitr-pv.json index 9495591c9..4d37f0f0b 100644 --- a/examples/kube/pitr/pitr-pv.json +++ b/examples/kube/pitr/pitr-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/pitr" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/pitr" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/pitr/restore-pitr-pv-nfs.json b/examples/kube/pitr/restore-pitr-pv-nfs.json index 2cd97378c..370534d6d 100644 --- a/examples/kube/pitr/restore-pitr-pv-nfs.json +++ b/examples/kube/pitr/restore-pitr-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/pitr", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/pitr", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/pitr/restore-pitr-pv.json b/examples/kube/pitr/restore-pitr-pv.json index 3d321626b..18500f9d6 100644 --- a/examples/kube/pitr/restore-pitr-pv.json +++ b/examples/kube/pitr/restore-pitr-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/pitr" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/pitr" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/postgres-sshd/cleanup.sh b/examples/kube/postgres-sshd/cleanup.sh index e0d9c84b1..fa1e6a97b 100755 --- a/examples/kube/postgres-sshd/cleanup.sh +++ b/examples/kube/postgres-sshd/cleanup.sh @@ -31,7 +31,4 @@ fi $CCPROOT/examples/waitforterm.sh postgres-sshd ${CCP_CLI?} rm -rf ${DIR?}/keys -dir_check_rm "archive" -dir_check_rm "backup" dir_check_rm "postgres-sshd" -file_check_rm "db-stanza-create.log" diff --git a/examples/kube/postgres-sshd/postgres-sshd-pv-nfs.json b/examples/kube/postgres-sshd/postgres-sshd-pv-nfs.json index 02af7f1ea..8b327087d 100644 --- a/examples/kube/postgres-sshd/postgres-sshd-pv-nfs.json +++ b/examples/kube/postgres-sshd/postgres-sshd-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/postgres-sshd", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/postgres-sshd", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/postgres-sshd/postgres-sshd-pv.json b/examples/kube/postgres-sshd/postgres-sshd-pv.json index 0f8fb3d54..25625b616 100644 --- a/examples/kube/postgres-sshd/postgres-sshd-pv.json +++ b/examples/kube/postgres-sshd/postgres-sshd-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/postgres-sshd" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/postgres-sshd" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/primary-deployment/cleanup.sh b/examples/kube/primary-deployment/cleanup.sh index 049b1e45a..2ea7cacdf 100755 --- a/examples/kube/primary-deployment/cleanup.sh +++ b/examples/kube/primary-deployment/cleanup.sh @@ -29,4 +29,3 @@ then fi dir_check_rm "primary-deployment" -dir_check_rm "replica-deployment" diff --git a/examples/kube/primary-deployment/primary-deployment-pv-nfs.json b/examples/kube/primary-deployment/primary-deployment-pv-nfs.json index 4abcfb0a8..c216d9c92 100644 --- a/examples/kube/primary-deployment/primary-deployment-pv-nfs.json +++ b/examples/kube/primary-deployment/primary-deployment-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/primary-deployment", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/primary-deployment", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -57,7 +57,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/primary-deployment", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/primary-deployment/primary-deployment-pv.json b/examples/kube/primary-deployment/primary-deployment-pv.json index f8d2b0a9c..c1a155cc0 100644 --- a/examples/kube/primary-deployment/primary-deployment-pv.json +++ b/examples/kube/primary-deployment/primary-deployment-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/primary-deployment" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/primary-deployment" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -55,7 +55,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/primary-deployment" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/primary/primary-pv-nfs.json b/examples/kube/primary/primary-pv-nfs.json index fd4cd7724..d6dc91bec 100644 --- a/examples/kube/primary/primary-pv-nfs.json +++ b/examples/kube/primary/primary-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/primary", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/primary/primary-pv.json b/examples/kube/primary/primary-pv.json index baf1a46a6..b1da93501 100644 --- a/examples/kube/primary/primary-pv.json +++ b/examples/kube/primary/primary-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/primary" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/restore/restore-pv-nfs.json b/examples/kube/restore/restore-pv-nfs.json index c72a76519..1304b0fcf 100644 --- a/examples/kube/restore/restore-pv-nfs.json +++ b/examples/kube/restore/restore-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/restore", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/restore/restore-pv.json b/examples/kube/restore/restore-pv.json index b08e379e7..f85defb9d 100644 --- a/examples/kube/restore/restore-pv.json +++ b/examples/kube/restore/restore-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/restore" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/statefulset/cleanup.sh b/examples/kube/statefulset/cleanup.sh index 4143dba5e..5e8e4921a 100755 --- a/examples/kube/statefulset/cleanup.sh +++ b/examples/kube/statefulset/cleanup.sh @@ -27,6 +27,4 @@ fi ${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} service statefulset statefulset-primary statefulset-replica ${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} pod statefulset-0 statefulset-1 -dir_check_rm "statefulset-0" -dir_check_rm "statefulset-1" -dir_check_rm "statefulset-2" +dir_check_rm "statefulset" diff --git a/examples/kube/statefulset/statefulset-pv-nfs.json b/examples/kube/statefulset/statefulset-pv-nfs.json index 308619363..e4714dce7 100644 --- a/examples/kube/statefulset/statefulset-pv-nfs.json +++ b/examples/kube/statefulset/statefulset-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/statefulset", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -35,7 +35,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/statefulset", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" @@ -57,7 +57,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/statefulset", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/statefulset/statefulset-pv.json b/examples/kube/statefulset/statefulset-pv.json index ea3505587..cad391162 100644 --- a/examples/kube/statefulset/statefulset-pv.json +++ b/examples/kube/statefulset/statefulset-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/statefulset" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -34,7 +34,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/statefulset" }, "persistentVolumeReclaimPolicy": "Retain" } @@ -55,7 +55,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/statefulset" }, "persistentVolumeReclaimPolicy": "Retain" } diff --git a/examples/kube/upgrade/upgrade-pv-nfs.json b/examples/kube/upgrade/upgrade-pv-nfs.json index 2021a1b9e..59d2be248 100644 --- a/examples/kube/upgrade/upgrade-pv-nfs.json +++ b/examples/kube/upgrade/upgrade-pv-nfs.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "nfs": { - "path": "$CCP_STORAGE_PATH", + "path": "$CCP_STORAGE_PATH/upgrade", "server": "$CCP_NFS_IP" }, "persistentVolumeReclaimPolicy": "Retain" diff --git a/examples/kube/upgrade/upgrade-pv.json b/examples/kube/upgrade/upgrade-pv.json index 3a66868d0..cc9e92bc8 100644 --- a/examples/kube/upgrade/upgrade-pv.json +++ b/examples/kube/upgrade/upgrade-pv.json @@ -13,7 +13,7 @@ }, "accessModes": ["$CCP_STORAGE_MODE"], "hostPath": { - "path": "$CCP_STORAGE_PATH" + "path": "$CCP_STORAGE_PATH/upgrade" }, "persistentVolumeReclaimPolicy": "Retain" } From 36aa7f562935d2069ffa8de086163313c17bdb16 Mon Sep 17 00:00:00 2001 From: Jason O'Donnell <2160810+jasonodonnell@users.noreply.github.com> Date: Thu, 20 Sep 2018 13:33:59 -0400 Subject: [PATCH 034/179] Add scheduler image, remove DBA --- Makefile | 39 ++-- bin/dba/.gitignore | 3 - bin/dba/create-backup-job.sh | 36 ---- bin/dba/start-dba.sh | 69 ------- bin/pull-from-crunchy.sh | 2 +- bin/pull-from-dockerhub.sh | 2 +- bin/pull-from-gcr.sh | 2 +- bin/push-to-dockerhub.sh | 2 +- bin/remove-all-images.sh | 2 +- bin/scheduler/.gitignore | 1 + .../create-vac-job.sh => scheduler/start.sh} | 19 +- centos7/Dockerfile.dba.centos7 | 37 ---- centos7/Dockerfile.scheduler-build.centos7 | 7 + centos7/Dockerfile.scheduler.centos7 | 33 +++ conf/atomic/scheduler/help.1 | 39 ++++ conf/atomic/scheduler/help.md | 22 ++ conf/atomic/scheduler/scheduler.1 | 58 ++++++ conf/dba/backup-job-pv-template.json | 18 -- conf/dba/backup-job-pvc-template.json | 17 -- conf/dba/backup-job-template.json | 51 ----- conf/dba/vacuum-job-template.json | 57 ----- conf/scheduler/backup-template.json | 66 ++++++ conf/{dba => scheduler}/group.template | 0 conf/{dba => scheduler}/passwd.template | 0 dba/dbaserver.go | 82 -------- dba/test.go | 98 --------- dbaapi/backupjob.go | 186 ----------------- dbaapi/cron.go | 29 --- dbaapi/vacjob.go | 103 ---------- examples/kube/dba/dba-backup.json | 190 ----------------- examples/kube/dba/dba-vac.json | 194 ------------------ examples/kube/dba/run-kube-backup.sh | 23 --- examples/kube/dba/run-kube-vac.sh | 23 --- examples/kube/scheduler/add-schedules.sh | 16 ++ examples/kube/{dba => scheduler}/cleanup.sh | 15 +- .../configs/schedule-backrest-diff.json | 13 ++ .../configs/schedule-backrest-full.json | 13 ++ .../configs/schedule-pgbasebackup.json | 16 ++ examples/kube/scheduler/primary/cleanup.sh | 31 +++ .../scheduler/primary/configs/pgbackrest.conf | 8 + .../primary/primary-deployment-pv-nfs.json | 65 ++++++ .../primary/primary-deployment-pv.json | 62 ++++++ .../primary/primary-deployment-pvc-sc.json | 56 +++++ .../primary/primary-deployment-pvc.json | 68 ++++++ .../scheduler/primary/primary-deployment.json | 181 ++++++++++++++++ .../primary/run.sh} | 20 +- .../run-ocp-backup.sh => scheduler/run.sh} | 9 +- examples/kube/scheduler/scheduler-sa.json | 108 ++++++++++ examples/kube/scheduler/scheduler.json | 35 ++++ .../container-specifications/crunchy-dba.md | 159 -------------- .../crunchy-scheduler.md | 32 +++ .../kubernetes-and-openshift/_index.adoc | 105 +++++++--- rhel7/Dockerfile.scheduler-build.rhel7 | 7 + rhel7/Dockerfile.scheduler.rhel7 | 40 ++++ tools/kubeapi/configmap.go | 47 +++++ .../{test-harness => }/kubeapi/deployment.go | 7 + tools/{test-harness => }/kubeapi/exec.go | 0 tools/kubeapi/job.go | 67 ++++++ tools/{test-harness => }/kubeapi/kubeapi.go | 0 tools/{test-harness => }/kubeapi/namespace.go | 0 tools/{test-harness => }/kubeapi/pod.go | 0 tools/{test-harness => }/kubeapi/proxy.go | 0 tools/kubeapi/secret.go | 10 + tools/{test-harness => }/kubeapi/service.go | 0 .../{test-harness => }/kubeapi/statefulset.go | 0 tools/scheduler/cron/cron.go | 157 ++++++++++++++ tools/scheduler/cron/pgbackrest.go | 88 ++++++++ tools/scheduler/cron/pgbasebackup.go | 150 ++++++++++++++ tools/scheduler/cron/types.go | 64 ++++++ tools/scheduler/main.go | 92 +++++++++ tools/test-harness/kubeapi/job.go | 39 ---- tools/test-harness/setup_test.go | 2 +- tools/test-harness/utils_test.go | 2 +- 73 files changed, 1796 insertions(+), 1498 deletions(-) delete mode 100644 bin/dba/.gitignore delete mode 100755 bin/dba/create-backup-job.sh delete mode 100755 bin/dba/start-dba.sh create mode 100644 bin/scheduler/.gitignore rename bin/{dba/create-vac-job.sh => scheduler/start.sh} (72%) delete mode 100644 centos7/Dockerfile.dba.centos7 create mode 100644 centos7/Dockerfile.scheduler-build.centos7 create mode 100644 centos7/Dockerfile.scheduler.centos7 create mode 100644 conf/atomic/scheduler/help.1 create mode 100644 conf/atomic/scheduler/help.md create mode 100644 conf/atomic/scheduler/scheduler.1 delete mode 100644 conf/dba/backup-job-pv-template.json delete mode 100644 conf/dba/backup-job-pvc-template.json delete mode 100644 conf/dba/backup-job-template.json delete mode 100644 conf/dba/vacuum-job-template.json create mode 100644 conf/scheduler/backup-template.json rename conf/{dba => scheduler}/group.template (100%) rename conf/{dba => scheduler}/passwd.template (100%) delete mode 100644 dba/dbaserver.go delete mode 100644 dba/test.go delete mode 100644 dbaapi/backupjob.go delete mode 100644 dbaapi/cron.go delete mode 100644 dbaapi/vacjob.go delete mode 100644 examples/kube/dba/dba-backup.json delete mode 100644 examples/kube/dba/dba-vac.json delete mode 100755 examples/kube/dba/run-kube-backup.sh delete mode 100755 examples/kube/dba/run-kube-vac.sh create mode 100755 examples/kube/scheduler/add-schedules.sh rename examples/kube/{dba => scheduler}/cleanup.sh (61%) create mode 100644 examples/kube/scheduler/configs/schedule-backrest-diff.json create mode 100644 examples/kube/scheduler/configs/schedule-backrest-full.json create mode 100644 examples/kube/scheduler/configs/schedule-pgbasebackup.json create mode 100755 examples/kube/scheduler/primary/cleanup.sh create mode 100644 examples/kube/scheduler/primary/configs/pgbackrest.conf create mode 100644 examples/kube/scheduler/primary/primary-deployment-pv-nfs.json create mode 100644 examples/kube/scheduler/primary/primary-deployment-pv.json create mode 100644 examples/kube/scheduler/primary/primary-deployment-pvc-sc.json create mode 100644 examples/kube/scheduler/primary/primary-deployment-pvc.json create mode 100644 examples/kube/scheduler/primary/primary-deployment.json rename examples/kube/{dba/run-ocp-vac.sh => scheduler/primary/run.sh} (52%) rename examples/kube/{dba/run-ocp-backup.sh => scheduler/run.sh} (72%) create mode 100644 examples/kube/scheduler/scheduler-sa.json create mode 100644 examples/kube/scheduler/scheduler.json delete mode 100644 hugo/content/container-specifications/crunchy-dba.md create mode 100644 hugo/content/container-specifications/crunchy-scheduler.md create mode 100644 rhel7/Dockerfile.scheduler-build.rhel7 create mode 100644 rhel7/Dockerfile.scheduler.rhel7 create mode 100644 tools/kubeapi/configmap.go rename tools/{test-harness => }/kubeapi/deployment.go (90%) rename tools/{test-harness => }/kubeapi/exec.go (100%) create mode 100644 tools/kubeapi/job.go rename tools/{test-harness => }/kubeapi/kubeapi.go (100%) rename tools/{test-harness => }/kubeapi/namespace.go (100%) rename tools/{test-harness => }/kubeapi/pod.go (100%) rename tools/{test-harness => }/kubeapi/proxy.go (100%) create mode 100644 tools/kubeapi/secret.go rename tools/{test-harness => }/kubeapi/service.go (100%) rename tools/{test-harness => }/kubeapi/statefulset.go (100%) create mode 100644 tools/scheduler/cron/cron.go create mode 100644 tools/scheduler/cron/pgbackrest.go create mode 100644 tools/scheduler/cron/pgbasebackup.go create mode 100644 tools/scheduler/cron/types.go create mode 100644 tools/scheduler/main.go delete mode 100644 tools/test-harness/kubeapi/job.go diff --git a/Makefile b/Makefile index 799381330..3b00a76dd 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,10 @@ ifndef CCPROOT export CCPROOT=$(GOPATH)/src/github.com/crunchydata/crunchy-containers endif -.PHONY: all versiontest +.PHONY: all versiontest # Default target -all: commands backup backrestrestore collect dbaserver grafana pgadmin4 pgbadger pgbouncer pgdump pgpool pgrestore postgres postgres-gis prometheus upgrade vac +all: commands backup backrestrestore collect grafana pgadmin4 pgbadger pgbouncer pgdump pgpool pgrestore postgres postgres-gis prometheus scheduler upgrade vac versiontest: ifndef CCP_BASEOS @@ -26,8 +26,7 @@ setup: gendeps: godep save \ - github.com/crunchydata/crunchy-containers/dba \ - github.com/crunchydata/crunchy-containers/badger + github.com/crunchydata/crunchy-containers/badger docbuild: cd $CCPROOT && ./generate-docs.sh @@ -38,7 +37,7 @@ docbuild: commands: pgc -pgc: +pgc: cd $(CCPROOT)/commands/pgc && go build pgc.go && mv pgc $(GOBIN)/pgc @@ -58,14 +57,6 @@ collect: versiontest docker build -t crunchy-collect -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.collect.$(CCP_BASEOS) . docker tag crunchy-collect $(CCP_IMAGE_PREFIX)/crunchy-collect:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) -dbaserver: - cp `which oc` bin/dba - cp `which kubectl` bin/dba - cd dba && godep go install dbaserver.go - cp $(GOBIN)/dbaserver bin/dba - docker build -t crunchy-dba -f $(CCP_BASEOS)/Dockerfile.dba.$(CCP_BASEOS) . - docker tag crunchy-dba $(CCP_IMAGE_PREFIX)/crunchy-dba:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) - grafana: versiontest docker build -t crunchy-grafana -f $(CCP_BASEOS)/Dockerfile.grafana.$(CCP_BASEOS) . docker tag crunchy-grafana $(CCP_IMAGE_PREFIX)/crunchy-grafana:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) @@ -109,7 +100,7 @@ postgres: versiontest commands docker build -t crunchy-postgres -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.postgres.$(CCP_BASEOS) . docker tag crunchy-postgres $(CCP_IMAGE_PREFIX)/crunchy-postgres:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) -postgres-gis: versiontest commands +postgres-gis: versiontest commands cp $(GOBIN)/pgc bin/postgres docker build -t crunchy-postgres-gis -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.postgres-gis.$(CCP_BASEOS) . docker tag crunchy-postgres-gis $(CCP_IMAGE_PREFIX)/crunchy-postgres-gis:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) @@ -118,12 +109,6 @@ prometheus: versiontest docker build -t crunchy-prometheus -f $(CCP_BASEOS)/Dockerfile.prometheus.$(CCP_BASEOS) . docker tag crunchy-prometheus $(CCP_IMAGE_PREFIX)/crunchy-prometheus:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) -upgrade: versiontest - if [[ '$(CCP_PGVERSION)' != '9.5' ]]; then \ - docker build -t crunchy-upgrade -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.upgrade.$(CCP_BASEOS) . ;\ - docker tag crunchy-upgrade $(CCP_IMAGE_PREFIX)/crunchy-upgrade:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) ;\ - fi - sample-app: versiontest docker build -t $(CCP_IMAGE_PREFIX)/sample-app-build:build -f $(CCP_BASEOS)/Dockerfile.sample-app-build.$(CCP_BASEOS) . docker create --name extract $(CCP_IMAGE_PREFIX)/sample-app-build:build @@ -132,6 +117,20 @@ sample-app: versiontest docker build -t crunchy-sample-app -f $(CCP_BASEOS)/Dockerfile.sample-app.$(CCP_BASEOS) . docker tag crunchy-sample-app $(CCP_IMAGE_PREFIX)/crunchy-sample-app:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) +scheduler: versiontest + docker build -t $(CCP_IMAGE_PREFIX)/scheduler-build:build -f $(CCP_BASEOS)/Dockerfile.scheduler-build.$(CCP_BASEOS) . + docker create --name extract $(CCP_IMAGE_PREFIX)/scheduler-build:build + docker cp extract:/go/src/github.com/crunchydata/crunchy-containers/scheduler ./bin/scheduler + docker rm -f extract + docker build -t crunchy-scheduler -f $(CCP_BASEOS)/Dockerfile.scheduler.$(CCP_BASEOS) . + docker tag crunchy-scheduler $(CCP_IMAGE_PREFIX)/crunchy-scheduler:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) + +upgrade: versiontest + if [[ '$(CCP_PGVERSION)' != '9.5' ]]; then \ + docker build -t crunchy-upgrade -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.upgrade.$(CCP_BASEOS) . ;\ + docker tag crunchy-upgrade $(CCP_IMAGE_PREFIX)/crunchy-upgrade:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) ;\ + fi + vac: versiontest cd vacuum && godep go install vacuum.go cp $(GOBIN)/vacuum bin/vacuum diff --git a/bin/dba/.gitignore b/bin/dba/.gitignore deleted file mode 100644 index 04a8f1829..000000000 --- a/bin/dba/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -dbaserver -kubectl -oc diff --git a/bin/dba/create-backup-job.sh b/bin/dba/create-backup-job.sh deleted file mode 100755 index 6609e0c69..000000000 --- a/bin/dba/create-backup-job.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source /opt/cpm/bin/common_lib.sh -enable_debugging -ose_hack - -BACKUP_TEMPLATE=${1?} -BACKUP_PVC_TEMPLATE=${2?} -JOB_HOST=${3?} -CMD=${4?} - -echo_info "Deleting backup job ${JOB_HOST?}.." -/opt/cpm/bin/${CMD?} delete job ${JOB_HOST?}-backup -sleep 15 - -echo_info "Creating Backup PVC ${BACKUP_PVC_TEMPLATE?}.." -/opt/cpm/bin/${CMD?} create -f ${BACKUP_PVC_TEMPLATE?} -sleep 4 - -echo_info "Creating backup job ${BACKUP_TEMPLATE?}.." -/opt/cpm/bin/$4 create -f $1 - -exit 0 diff --git a/bin/dba/start-dba.sh b/bin/dba/start-dba.sh deleted file mode 100755 index f324d0d20..000000000 --- a/bin/dba/start-dba.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source /opt/cpm/bin/common_lib.sh -enable_debugging -ose_hack - -export PATH=$PATH:/opt/cpm/bin -export TOKEN="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" - -function trap_sigterm() { - echo_info "Doing trap logic.." - echo_warn "Clean shutdown of dbaserver.." - killall dbaserver -} - -trap 'trap_sigterm' SIGINT SIGTERM - -if [[ -v OSE_PROJECT ]] -then - echo_info "OpenShift deployment detected.." - export CMD=oc - - env_check_err "KUBERNETES_SERVICE_HOST" - env_check_err "KUBERNETES_SERVICE_PORT" - env_check_err "OSE_PROJECT" - - echo_info "Current OpenShift Project is ${OSE_PROJECT?}.." - - url="https://${KUBERNETES_SERVICE_HOST?}:${KUBERNETES_SERVICE_PORT?}" - - echo_info "Logging into OpenShift.." - oc login ${url?} --insecure-skip-tls-verify=true --token="$TOKEN" - - echo_info "Setting OpenShift Project to ${OSE_PROJECT?}.." - oc project ${OSE_PROJECT?} - - echo_info "Adding role to group system:serviceaccounts in ${OSE_PROJECT?}.." - oc policy add-role-to-group edit system:serviceaccounts -n ${OSE_PROJECT?} -elif [[ -v KUBE_PROJECT ]] -then - echo_info "Kubernetes deployment detected.." - export CMD=kubectl -else - echo_err "OSE_PROJECT or KUBE_PROJECT need to be set" - exit 2 -fi - -echo_info "Vacuum Schedule is ${VAC_SCHEDULE}.." - -env_check_err "JOB_HOST" -echo_info "Job Host is ${JOB_HOST?}.." - -echo_info "Starting dbaserver.." -dbaserver & - -wait diff --git a/bin/pull-from-crunchy.sh b/bin/pull-from-crunchy.sh index 5fe8e5be5..b5f8ece76 100755 --- a/bin/pull-from-crunchy.sh +++ b/bin/pull-from-crunchy.sh @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. REG_CCP_IMAGE_PREFIX=registry.crunchydata.com/crunchydata -for CONTAINER in crunchy-prometheus crunchy-dba crunchy-vacuum crunchy-upgrade crunchy-grafana crunchy-collect crunchy-pgbadger crunchy-pgpool crunchy-backup crunchy-postgres crunchy-postgres-gis crunchy-pgbouncer crunchy-pgadmin4 crunchy-pgdump crunchy-pgrestore crunchy-backrest-restore +for CONTAINER in crunchy-prometheus crunchy-vacuum crunchy-upgrade crunchy-grafana crunchy-collect crunchy-pgbadger crunchy-pgpool crunchy-backup crunchy-postgres crunchy-postgres-gis crunchy-pgbouncer crunchy-pgadmin4 crunchy-pgdump crunchy-pgrestore crunchy-backrest-restore crunchy-scheduler do echo $CONTAINER is the container docker pull $REG_CCP_IMAGE_PREFIX/$CONTAINER:$CCP_IMAGE_TAG diff --git a/bin/pull-from-dockerhub.sh b/bin/pull-from-dockerhub.sh index 94ac1e19a..df551f934 100755 --- a/bin/pull-from-dockerhub.sh +++ b/bin/pull-from-dockerhub.sh @@ -38,5 +38,5 @@ docker pull $CCP_IMAGE_PREFIX/crunchy-pgadmin4:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-pgdump:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-pgrestore:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-upgrade:$CCP_IMAGE_TAG -docker pull $CCP_IMAGE_PREFIX/crunchy-dba:$CCP_IMAGE_TAG +docker pull $CCP_IMAGE_PREFIX/crunchy-scheduler:$CCP_IMAGE_TAG docker pull $CCP_IMAGE_PREFIX/crunchy-vacuum:$CCP_IMAGE_TAG diff --git a/bin/pull-from-gcr.sh b/bin/pull-from-gcr.sh index 33c901cdf..6a8be1c30 100644 --- a/bin/pull-from-gcr.sh +++ b/bin/pull-from-gcr.sh @@ -8,7 +8,7 @@ IMAGES=( crunchy-backrest-restore crunchy-backup crunchy-collect - crunchy-dba + crunchy-scheduler crunchy-pgdump crunchy-grafana crunchy-pgadmin4 diff --git a/bin/push-to-dockerhub.sh b/bin/push-to-dockerhub.sh index fbc76079d..7d826c2b7 100755 --- a/bin/push-to-dockerhub.sh +++ b/bin/push-to-dockerhub.sh @@ -25,5 +25,5 @@ docker push $CCP_IMAGE_PREFIX/crunchy-postgres-gis:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-pgbouncer:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-pgadmin4:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-vacuum:$CCP_IMAGE_TAG -docker push $CCP_IMAGE_PREFIX/crunchy-dba:$CCP_IMAGE_TAG +docker push $CCP_IMAGE_PREFIX/crunchy-scheduler:$CCP_IMAGE_TAG docker push $CCP_IMAGE_PREFIX/crunchy-upgrade:$CCP_IMAGE_TAG diff --git a/bin/remove-all-images.sh b/bin/remove-all-images.sh index 815faae14..b6109369f 100755 --- a/bin/remove-all-images.sh +++ b/bin/remove-all-images.sh @@ -15,7 +15,7 @@ for i in \ restore pgdump postgres-gis prometheus grafana collect pgbadger pgpool \ -watch backup postgres pgbouncer pgadmin4 vacuum dba upgrade backrest-restore +watch backup postgres pgbouncer pgadmin4 vacuum scheduler upgrade backrest-restore do docker rmi -f $CCP_IMAGE_PREFIX/crunchy-$i:$CCP_IMAGE_TAG docker rmi -f crunchy-$i diff --git a/bin/scheduler/.gitignore b/bin/scheduler/.gitignore new file mode 100644 index 000000000..17e0b594c --- /dev/null +++ b/bin/scheduler/.gitignore @@ -0,0 +1 @@ +scheduler diff --git a/bin/dba/create-vac-job.sh b/bin/scheduler/start.sh similarity index 72% rename from bin/dba/create-vac-job.sh rename to bin/scheduler/start.sh index 47af13b48..edf475077 100755 --- a/bin/dba/create-vac-job.sh +++ b/bin/scheduler/start.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash # Copyright 2016 - 2018 Crunchy Data Solutions, Inc. # Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,15 +17,10 @@ source /opt/cpm/bin/common_lib.sh enable_debugging ose_hack -TEMP_FILE=${1?} -JOB_HOST=${2?} -CMD=${3?} +export TEMPLATE_DIR='/opt/cpm/conf/backup-template.json' +if [[ -f '/configs/backup-template.json' ]] +then + export TEMPLATE_DIR='/configs/backup-template.json' +fi -echo_info "Deleting vacuum job ${JOB_HOST?}.." -/opt/cpm/bin/${CMD?} delete job ${JOB_HOST?}-vac -sleep 15 - -echo_info "Creating vacuum job.." -/opt/cpm/bin/${CMD?} create -f ${TEMP_FILE?} - -exit 0 +/opt/cpm/bin/scheduler diff --git a/centos7/Dockerfile.dba.centos7 b/centos7/Dockerfile.dba.centos7 deleted file mode 100644 index 0c648069a..000000000 --- a/centos7/Dockerfile.dba.centos7 +++ /dev/null @@ -1,37 +0,0 @@ -FROM centos:7 - -LABEL name="crunchydata/dba" \ - vendor="crunchy data" \ - Version="7.5" \ - Release="2.1.0" \ - url="https://crunchydata.com" \ - summary="Implements a cron scheduler." \ - description="Offers a way to perform simple DBA tasks that occur on some form of schedule such as backup jobs or running a vacuum on a single Postgres database container. You can either run the crunchy-dba container as a single pod or include the container within a database pod. The crunchy-dba container makes use of a Service Account to perform the startup of scheduled jobs. The Kube Job type is used to execute the scheduled jobs with a Restart policy of Never." \ - io.k8s.description="DBA container" \ - io.k8s.display-name="Crunchy DBA container" \ - io.openshift.expose-services="" \ - io.openshift.tags="crunchy,database" - -RUN yum -y update \ - && yum -y install epel-release \ - && yum -y install \ - bind-utils \ - gettext \ - hostname \ - iproute \ - nss_wrapper \ - procps-ng \ - psmisc \ - && yum clean all -y - -RUN mkdir -p /opt/cpm/bin /opt/cpm/conf - -ADD bin/dba /opt/cpm/bin -ADD bin/common /opt/cpm/bin -ADD conf/dba /opt/cpm/conf - -RUN chown -R 2:2 /opt/cpm - -USER 2 - -CMD ["/opt/cpm/bin/start-dba.sh"] diff --git a/centos7/Dockerfile.scheduler-build.centos7 b/centos7/Dockerfile.scheduler-build.centos7 new file mode 100644 index 000000000..3c7b10763 --- /dev/null +++ b/centos7/Dockerfile.scheduler-build.centos7 @@ -0,0 +1,7 @@ +FROM golang:1.9.1 +WORKDIR /go/src/github.com/crunchydata/crunchy-containers +ADD . . +RUN go get github.com/tools/godep \ + && godep restore \ + && go get gopkg.in/robfig/cron.v2 +RUN CGO_ENABLED=0 GOOS=linux go build -a -o scheduler ./tools/scheduler diff --git a/centos7/Dockerfile.scheduler.centos7 b/centos7/Dockerfile.scheduler.centos7 new file mode 100644 index 000000000..b992a227d --- /dev/null +++ b/centos7/Dockerfile.scheduler.centos7 @@ -0,0 +1,33 @@ +FROM centos:7 + +LABEL name="crunchydata/scheduler" \ + vendor="crunchy data" \ + Version="7.5" \ + Release="2.1.0" \ + url="https://crunchydata.com" \ + summary="Crunchy Scheduler is a cron-like microservice for scheduling automatic backups" \ + description="Crunchy Scheduler parses JSON configMaps with the label 'crunchy-scheduler=true' and transforms them into cron based tasks for automating pgBaseBackup and pgBackRest backups" \ + io.k8s.description="scheduler container" \ + io.k8s.display-name="Crunchy Scheduler container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database,cron" + +RUN yum -y update \ + && yum -y install epel-release \ + && yum -y install \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /configs \ + && chown -R 2:2 /opt/cpm /configs + +ADD bin/scheduler /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/scheduler /opt/cpm/conf + +USER 2 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/conf/atomic/scheduler/help.1 b/conf/atomic/scheduler/help.1 new file mode 100644 index 000000000..29ef6d803 --- /dev/null +++ b/conf/atomic/scheduler/help.1 @@ -0,0 +1,39 @@ +.TH "scheduler" "1" " Container Image Pages" "Crunchy Data" "September 19 2018" +.nh +.ad l + + +.SH NAME +.PP +Crunchy Scheduler\- cron-like microservice image + + +.SH DESCRIPTION +.PP +The Crunchy Scheduler image provides automated backup scheduling for a namespace. + +.PP +The container itself consists of: + \- RHEL7 base image + \- bash script that performs the container startup + \- scheduler binary app + +.PP +Files added to the container during docker build include: /help.1. + + +.SH USAGE +.PP +See the crunchy docs. + +.PP +\fB\fCVersion=\fR + +.PP +The Red Hat Enterprise Linux version from which the container was built. For example, Version="7.5" + +.PP +\fB\fCRelease=\fR + +.PP +The specific release number of the container. For example, Release="2.1.0" diff --git a/conf/atomic/scheduler/help.md b/conf/atomic/scheduler/help.md new file mode 100644 index 000000000..86c77340a --- /dev/null +++ b/conf/atomic/scheduler/help.md @@ -0,0 +1,22 @@ += scheduler(1) +Crunchy Data +September 19, 2018 +== NAME +Crunchy Scheduler - cron-like microservice image + +== DESCRIPTION +The Crunchy Scheduler image provides automated backup scheduling for a namespace. + +The container itself consists of: + - RHEL7 base image + - bash script that performs the container startup + - scheduler binary app + +== USAGE +See the crunchy docs. + +The Red Hat Enterprise Linux version from which the container was built. For example, Version="7.5" + +`Release=` + +The specific release number of the container. For example, Release="2.1.0" diff --git a/conf/atomic/scheduler/scheduler.1 b/conf/atomic/scheduler/scheduler.1 new file mode 100644 index 000000000..5f79c211c --- /dev/null +++ b/conf/atomic/scheduler/scheduler.1 @@ -0,0 +1,58 @@ +'\" t +.\" Title: Crunchy Scheduler +.\" Author: Crunchy Data +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 2018 +.\" Manual: \ \& +.\" Source: \ \& 13 +.\" Language: English +.\" +.TH "SCHEDULER" "1" "2018" "\ \& 13" "\ \&" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +Crunchy Scheduler \- cron-like microservice image +.SH "DESCRIPTION" +.sp +The Crunchy Scheduler image provides automated backup scheduling for a namespace\&. +.sp +The container itself consists of: \- RHEL7 base image \- bash script that performs the container startup \- scheduler binary app +.sp +.sp +Files added to the container during docker build include: /help\&.1\&. +.SH "USAGE" +.sp +See the crunchy docs\&. +.sp +The registry location and name of the image\&. For example, Name="crunchydata/postgres"\&. +.sp +Version= +.sp +The Red Hat Enterprise Linux version from which the container was built\&. For example, Version="7.5" +.sp +Release= +.sp +The specific release number of the container\&. For example, Release="2.1.0" +.SH "AUTHOR" +.PP +\fBCrunchy Data\fR +.RS 4 +Author. +.RE diff --git a/conf/dba/backup-job-pv-template.json b/conf/dba/backup-job-pv-template.json deleted file mode 100644 index bd866bfe2..000000000 --- a/conf/dba/backup-job-pv-template.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "v1", - "kind": "PersistentVolume", - "metadata": { - "name": "{{.JOB_HOST}}-backup-pv" - }, - "spec": { - "capacity": { - "storage": "{{.BACKUP_PV_CAPACITY}}" - }, - "accessModes": [ "ReadWriteMany" ], - "nfs": { - "path": "{{.BACKUP_PV_PATH}}", - "server": "{{.BACKUP_PV_HOST}}" - }, - "persistentVolumeReclaimPolicy": "Retain" - } -} diff --git a/conf/dba/backup-job-pvc-template.json b/conf/dba/backup-job-pvc-template.json deleted file mode 100644 index 844f21dd4..000000000 --- a/conf/dba/backup-job-pvc-template.json +++ /dev/null @@ -1,17 +0,0 @@ - { - "kind": "PersistentVolumeClaim", - "apiVersion": "v1", - "metadata": { - "name": "{{.JOB_HOST}}-backup-pvc" - }, - "spec": { - "accessModes": [ - "ReadWriteMany" - ], - "resources": { - "requests": { - "storage": "{{.BACKUP_PVC_STORAGE}}" - } - } - } - } diff --git a/conf/dba/backup-job-template.json b/conf/dba/backup-job-template.json deleted file mode 100644 index 5545a6aaa..000000000 --- a/conf/dba/backup-job-template.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "apiVersion": "batch/v1", - "kind": "Job", - "metadata": { - "name": "{{.JOB_HOST}}-backup" - }, - "spec": { - "template": { - "metadata": { - "name": "{{.JOB_HOST}}-backup", - "labels": { - "app": "{{.JOB_HOST}}-backup" - } - }, - "spec": { - "securityContext": { - "supplementalGroups": [65534] - }, - "volumes": [{ - "name": "pgdata", - "persistentVolumeClaim": { - "claimName": "{{.JOB_HOST}}-backup-pvc" - } - }], - "containers": [{ - "name": "{{.JOB_HOST}}-backup", - "image": "{{.CCP_IMAGE_PREFIX}}/crunchy-backup:{{.CCP_IMAGE_TAG}}", - "volumeMounts": [{ - "mountPath": "/pgdata", - "name": "pgdata", - "readOnly": false - }], - "env": [{ - "name": "BACKUP_HOST", - "value": "{{.JOB_HOST}}" - }, { - "name": "BACKUP_USER", - "value": "{{.PG_USER}}" - }, { - "name": "BACKUP_PASS", - "value": "{{.PG_PASSWORD}}" - }, { - "name": "BACKUP_PORT", - "value": "{{.PG_PORT}}" - }] - }], - "restartPolicy": "Never" - } - } - } -} diff --git a/conf/dba/vacuum-job-template.json b/conf/dba/vacuum-job-template.json deleted file mode 100644 index 3139fc051..000000000 --- a/conf/dba/vacuum-job-template.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "apiVersion": "batch/v1", - "kind": "Job", - "metadata": { - "name": "{{.JOB_HOST}}-vac" - }, - "spec": { - "template": { - "metadata": { - "name": "{{.JOB_HOST}}-vac", - "labels": { - "app": "{{.JOB_HOST}}-vac" - } - }, - "spec": { - "volumes": [ ], - "containers": [{ - "name": "{{.JOB_HOST}}-vac", - "image": "{{.CCP_IMAGE_PREFIX}}/crunchy-vacuum:{{.CCP_IMAGE_TAG}}", - "volumeMounts": [ ], - "env": [{ - "name": "VAC_FULL", - "value": "{{.VAC_FULL}}" - }, { - "name": "JOB_HOST", - "value": "{{.JOB_HOST}}" - }, { - "name": "VAC_ANALYZE", - "value": "{{.VAC_ANALYZE}}" - }, { - "name": "VAC_VERBOSE", - "value": "{{.VAC_VERBOSE}}" - }, { - "name": "VAC_FREEZE", - "value": "{{.VAC_FREEZE}}" - }, { - "name": "VAC_TABLE", - "value": "{{.VAC_TABLE}}" - }, { - "name": "PG_USER", - "value": "{{.PG_USER}}" - }, { - "name": "PG_PORT", - "value": "{{.PG_PORT}}" - }, { - "name": "PG_DATABASE", - "value": "{{.PG_DATABASE}}" - }, { - "name": "PG_PASSWORD", - "value": "{{.PG_PASSWORD}}" - }] - }], - "restartPolicy": "Never" - } - } - } -} diff --git a/conf/scheduler/backup-template.json b/conf/scheduler/backup-template.json new file mode 100644 index 000000000..37e96ba27 --- /dev/null +++ b/conf/scheduler/backup-template.json @@ -0,0 +1,66 @@ +{ + "apiVersion": "batch/v1", + "kind": "Job", + "metadata": { + "name": "{{.Name}}", + "labels": { + "vendor": "crunchydata", + "pgbackup": "true", + "pg-cluster": "{{.Name}}" + } + }, + "spec": { + "template": { + "metadata": { + "name": "{{.Name}}", + "labels": { + "vendor": "crunchydata", + "pgbackup": "true", + "pg-cluster": "{{.Name}}" + } + }, + "spec": { + "volumes": [ + { + "name": "pgdata", + "persistentVolumeClaim": { + "claimName": "{{.PvcName}}" + } + } + ], + "containers": [ + { + "name": "backup", + "image": "{{.CCPImagePrefix}}/crunchy-backup:{{.CCPImageTag}}", + "volumeMounts": [ + { + "mountPath": "/pgdata", + "name": "pgdata", + "readOnly": false + } + ], + "env": [ + { + "name": "BACKUP_HOST", + "value": "{{.BackupHost}}" + }, + { + "name": "BACKUP_USER", + "value": "{{.BackupUser}}" + }, + { + "name": "BACKUP_PASS", + "value": "{{.BackupPass}}" + }, + { + "name": "BACKUP_PORT", + "value": "{{.BackupPort}}" + } + ] + } + ], + "restartPolicy": "Never" + } + } + } +} diff --git a/conf/dba/group.template b/conf/scheduler/group.template similarity index 100% rename from conf/dba/group.template rename to conf/scheduler/group.template diff --git a/conf/dba/passwd.template b/conf/scheduler/passwd.template similarity index 100% rename from conf/dba/passwd.template rename to conf/scheduler/passwd.template diff --git a/dba/dbaserver.go b/dba/dbaserver.go deleted file mode 100644 index 3d63eb28f..000000000 --- a/dba/dbaserver.go +++ /dev/null @@ -1,82 +0,0 @@ -/* - Copyright 2016 - 2018 Crunchy Data Solutions, Inc. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package main - -import ( - "github.com/crunchydata/crunchy-containers/dbaapi" - "github.com/robfig/cron" - "log" - "os" - "time" -) - -var POLL_INT = int64(3) - -var logger *log.Logger - -func main() { - logger = log.New(os.Stdout, "logger: ", log.Lshortfile|log.Ldate|log.Ltime) - var VERSION = os.Getenv("CCP_VERSION") - - logger.Println("dbaserver " + VERSION + ": starting") - - cron := cron.New() - - LoadSchedules(cron) - - cron.Start() - - for true { - time.Sleep(time.Duration(POLL_INT) * time.Minute) - } - -} - -func LoadSchedules(cron *cron.Cron) { - var BACKUP_SCHEDULE = os.Getenv("BACKUP_SCHEDULE") - var VAC_SCHEDULE = os.Getenv("VAC_SCHEDULE") - var JOB_HOST = os.Getenv("JOB_HOST") - var CCP_IMAGE_TAG = os.Getenv("CCP_IMAGE_TAG") - var CCP_IMAGE_PREFIX = os.Getenv("CCP_IMAGE_PREFIX") - var CMD = os.Getenv("CMD") - logger.Println("BACKUP_SCHEDULE=" + BACKUP_SCHEDULE) - logger.Println("VAC_SCHEDULE=" + VAC_SCHEDULE) - logger.Println("JOB_HOST=" + JOB_HOST) - logger.Println("CCP_IMAGE_TAG=" + CCP_IMAGE_TAG) - logger.Println("CCP_IMAGE_PREFIX=" + CCP_IMAGE_PREFIX) - logger.Println("CMD=" + CMD) - - if VAC_SCHEDULE != "" { - - job := dbaapi.VacJob{} - job.Host = JOB_HOST - job.CCP_IMAGE_TAG = CCP_IMAGE_TAG - job.CCP_IMAGE_PREFIX = CCP_IMAGE_PREFIX - job.Cmd = CMD - job.Logger = logger - cron.AddJob(VAC_SCHEDULE, job) - } - if BACKUP_SCHEDULE != "" { - - job := dbaapi.BackupJob{} - job.Host = JOB_HOST - job.CCP_IMAGE_TAG = CCP_IMAGE_TAG - job.CCP_IMAGE_PREFIX = CCP_IMAGE_PREFIX - job.Cmd = CMD - job.Logger = logger - cron.AddJob(BACKUP_SCHEDULE, job) - } -} diff --git a/dba/test.go b/dba/test.go deleted file mode 100644 index 61b6dec6d..000000000 --- a/dba/test.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - "io/ioutil" - "log" - "os" - "text/template" -) - -type Parms struct { - VAC_HOST string - VAC_FULL bool - VAC_ANALYZE bool - VAC_ALL bool - VAC_VERBOSE bool - VAC_FREEZE bool - VAC_TABLE string - PG_USER string - PG_PORT string - PG_DATABASE string - PG_PASSWORD string -} - -func main() { - var logger *log.Logger - logger = log.New(os.Stdout, "logger: ", log.Lshortfile|log.Ldate|log.Ltime) - - var filename = "/tmp/vacuum-job-template.json" - buff, err := ioutil.ReadFile(filename) - if err != nil { - logger.Println(err.Error()) - logger.Println("error reading template file, can not continue") - os.Exit(2) - } - s := string(buff) - - parms := getParms() - tmpl, err := template.New("test").Parse(s) - if err != nil { - panic(err) - } - err = tmpl.Execute(os.Stdout, parms) -} -func getParms() *Parms { - parms := new(Parms) - var temp = os.Getenv("VAC_HOST") - if temp == "" { - parms.VAC_HOST = temp - } - temp = os.Getenv("VAC_FULL") - if temp == "" { - parms.VAC_FULL = true - } - temp = os.Getenv("VAC_ANALYZE") - if temp == "" { - parms.VAC_ANALYZE = true - } - - temp = os.Getenv("VAC_ALL") - if temp == "" { - parms.VAC_ALL = true - } - - temp = os.Getenv("VAC_VERBOSE") - if temp == "" { - parms.VAC_VERBOSE = true - } - temp = os.Getenv("VAC_FREEZE") - if temp == "" { - parms.VAC_FREEZE = false - } - temp = os.Getenv("VAC_TABLE") - if temp == "" { - parms.VAC_TABLE = temp - } - - temp = os.Getenv("PG_USER") - if temp == "" { - parms.PG_USER = "postgres" - } - - temp = os.Getenv("PG_PORT") - if temp == "" { - parms.PG_PORT = "5432" - } - temp = os.Getenv("PG_DATABASE") - if temp == "" { - parms.PG_DATABASE = "postgres" - } - - temp = os.Getenv("PG_PASSWORD") - if temp == "" { - parms.PG_PASSWORD = "" - } - - return parms - -} diff --git a/dbaapi/backupjob.go b/dbaapi/backupjob.go deleted file mode 100644 index 349b53d22..000000000 --- a/dbaapi/backupjob.go +++ /dev/null @@ -1,186 +0,0 @@ -/* - Copyright 2016 - 2018 Crunchy Data Solutions, Inc. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package dbaapi - -import ( - "bytes" - "errors" - "io/ioutil" - "log" - "os" - "os/exec" - "text/template" -) - -type BackupJobParms struct { - JOB_HOST string - CCP_IMAGE_PREFIX string - CCP_IMAGE_TAG string - CMD string - PG_USER string - PG_PASSWORD string - PG_PORT string - BACKUP_PV_CAPACITY string - BACKUP_PV_PATH string - BACKUP_PV_HOST string - BACKUP_PVC_STORAGE string -} - -type BackupJob struct { - Logger *log.Logger - Host string - CCP_IMAGE_PREFIX string - CCP_IMAGE_TAG string - Cmd string -} - -// Run this is the func that implements the cron Job interface -func (t BackupJob) Run() { - - parms, err := GetBackupJobParms(t.Logger) - if err != nil { - panic(err) - } - parms.CCP_IMAGE_TAG = t.CCP_IMAGE_TAG - parms.CCP_IMAGE_PREFIX = t.CCP_IMAGE_PREFIX - - var s = getBackupJobTemplate(t.Logger) - var pvc = getBackupJobPVCTemplate(t.Logger) - - tmpl, err := template.New("jobtemplate").Parse(s) - if err != nil { - panic(err) - } - tmplpvc, err := template.New("pvctemplate").Parse(pvc) - if err != nil { - panic(err) - } - - var tmpfile, tmpfilePVC *os.File - tmpfile, err = ioutil.TempFile("/tmp", "backupjob") - if err != nil { - t.Logger.Println(err.Error()) - panic(err) - } - tmpfilePVC, err = ioutil.TempFile("/tmp", "backupjobpvc") - if err != nil { - t.Logger.Println(err.Error()) - panic(err) - } - - err = tmpl.Execute(tmpfile, parms) - - if err := tmpfile.Close(); err != nil { - t.Logger.Println(err.Error()) - panic(err) - } - t.Logger.Println("tmpfile is " + tmpfile.Name()) - - err = tmplpvc.Execute(tmpfilePVC, parms) - if err := tmpfilePVC.Close(); err != nil { - t.Logger.Println(err.Error()) - panic(err) - } - t.Logger.Println("tmpfilePVC is " + tmpfilePVC.Name()) - - var stdout, stderr string - stdout, stderr, err = createBackupJob(parms, tmpfile.Name(), tmpfilePVC.Name(), t.Cmd) - if err != nil { - t.Logger.Println(err.Error()) - } - t.Logger.Println(stdout) - t.Logger.Println(stderr) - -} - -func getBackupJobTemplate(logger *log.Logger) string { - var filename = "/opt/cpm/conf/backup-job-template.json" - buff, err := ioutil.ReadFile(filename) - if err != nil { - logger.Println(err.Error()) - logger.Println("error reading template file, can not continue") - os.Exit(2) - } - s := string(buff) - return s -} - -func getBackupJobPVCTemplate(logger *log.Logger) string { - var filename = "/opt/cpm/conf/backup-job-pvc-template.json" - buff, err := ioutil.ReadFile(filename) - if err != nil { - logger.Println(err.Error()) - logger.Println("error reading pvc template file, can't continue") - os.Exit(2) - } - s := string(buff) - return s -} - -func createBackupJob(parms *BackupJobParms, templateFile string, - templatePVCFile string, environ string) (string, string, error) { - - var cmd *exec.Cmd - cmd = exec.Command("create-backup-job.sh", templateFile, - templatePVCFile, parms.JOB_HOST, environ, parms.CCP_IMAGE_TAG, parms.CCP_IMAGE_PREFIX) - - var out bytes.Buffer - var stderr bytes.Buffer - cmd.Stdout = &out - cmd.Stderr = &stderr - err := cmd.Run() - if err != nil { - return out.String(), stderr.String(), err - } - return out.String(), stderr.String(), err - -} - -func GetBackupJobParms(logger *log.Logger) (*BackupJobParms, error) { - var err error - parms := new(BackupJobParms) - - parms.JOB_HOST = os.Getenv("JOB_HOST") - if parms.JOB_HOST == "" { - return parms, errors.New("JOB_HOST env var not found") - } - parms.CCP_IMAGE_TAG = os.Getenv("CCP_IMAGE_TAG") - if parms.CCP_IMAGE_TAG == "" { - return parms, errors.New("CCP_IMAGE_TAG env var not found") - } - parms.CCP_IMAGE_PREFIX = os.Getenv("CCP_IMAGE_PREFIX") - if parms.CCP_IMAGE_PREFIX == "" { - return parms, errors.New("CCP_IMAGE_PREFIX env var not found") - } - parms.PG_USER = os.Getenv("PG_USER") - if parms.PG_USER == "" { - return parms, errors.New("PG_USER env var not found") - } - parms.PG_PASSWORD = os.Getenv("PG_PASSWORD") - if parms.PG_PASSWORD == "" { - return parms, errors.New("PG_PASSWORD env var not found") - } - parms.PG_PORT = os.Getenv("PG_PORT") - if parms.PG_PORT == "" { - return parms, errors.New("PG_PORT env var not found") - } - parms.BACKUP_PVC_STORAGE = os.Getenv("BACKUP_PVC_STORAGE") - if parms.BACKUP_PVC_STORAGE == "" { - return parms, errors.New("BACKUP_PVC_STORAGE env var not found") - } - - return parms, err -} diff --git a/dbaapi/cron.go b/dbaapi/cron.go deleted file mode 100644 index 5728870f2..000000000 --- a/dbaapi/cron.go +++ /dev/null @@ -1,29 +0,0 @@ -/* - Copyright 2016 - 2018 Crunchy Data Solutions, Inc. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package dbaapi - -import ( - "log" -) - -func Something(logger *log.Logger) error { - var err error - logger.Println("Something") - if false { - return err - } - return err -} diff --git a/dbaapi/vacjob.go b/dbaapi/vacjob.go deleted file mode 100644 index f13d57021..000000000 --- a/dbaapi/vacjob.go +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright 2016 - 2018 Crunchy Data Solutions, Inc. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package dbaapi - -import ( - "bytes" - "github.com/crunchydata/crunchy-containers/vacuumapi" - "io/ioutil" - "log" - "os" - "os/exec" - "text/template" -) - -type VacJob struct { - Logger *log.Logger - Host string - CCP_IMAGE_TAG string - CCP_IMAGE_PREFIX string - Cmd string -} - -// Run this is the func that implements the cron Job interface -func (t VacJob) Run() { - - var s = getTemplate(t.Logger) - - parms, err := vacuumapi.GetParms(t.Logger) - if err != nil { - panic(err) - } - parms.CCP_IMAGE_TAG = t.CCP_IMAGE_TAG - parms.CCP_IMAGE_PREFIX = t.CCP_IMAGE_PREFIX - - tmpl, err := template.New("jobtemplate").Parse(s) - if err != nil { - panic(err) - } - - var tmpfile *os.File - tmpfile, err = ioutil.TempFile("/tmp", "vacjob") - if err != nil { - t.Logger.Println(err.Error()) - panic(err) - } - err = tmpl.Execute(tmpfile, parms) - - if err := tmpfile.Close(); err != nil { - t.Logger.Println(err.Error()) - panic(err) - } - t.Logger.Println("tmpfile is " + tmpfile.Name()) - - var stdout, stderr string - stdout, stderr, err = createJob(parms, tmpfile.Name(), t.Cmd) - if err != nil { - t.Logger.Println(err.Error()) - } - t.Logger.Println(stdout) - t.Logger.Println(stderr) -} - -func getTemplate(logger *log.Logger) string { - var filename = "/opt/cpm/conf/vacuum-job-template.json" - buff, err := ioutil.ReadFile(filename) - if err != nil { - logger.Println(err.Error()) - logger.Println("error reading template file, can not continue") - os.Exit(2) - } - s := string(buff) - return s -} - -func createJob(parms *vacuumapi.Parms, templateFile string, environ string) (string, string, error) { - - var cmd *exec.Cmd - cmd = exec.Command("create-vac-job.sh", templateFile, parms.JOB_HOST, environ) - - var out bytes.Buffer - var stderr bytes.Buffer - cmd.Stdout = &out - cmd.Stderr = &stderr - err := cmd.Run() - if err != nil { - return out.String(), stderr.String(), err - } - return out.String(), stderr.String(), err - -} diff --git a/examples/kube/dba/dba-backup.json b/examples/kube/dba/dba-backup.json deleted file mode 100644 index c2a00ff91..000000000 --- a/examples/kube/dba/dba-backup.json +++ /dev/null @@ -1,190 +0,0 @@ -{ - "apiVersion": "v1", - "kind": "ServiceAccount", - "metadata": { - "name": "dba-sa" - } -} - -{ - "apiVersion": "rbac.authorization.k8s.io/v1beta1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "dba-sa" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "cluster-admin" - }, - "subjects": [ - { - "kind": "ServiceAccount", - "name": "dba-sa", - "namespace": "$CCP_NAMESPACE" - } - ] -} - -{ - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "dba", - "labels": { - "name": "dba" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5432, - "targetPort": 5432, - "nodePort": 0 - } - ], - "selector": { - "name": "dba" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } -} - -{ - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "dba", - "labels": { - "name": "dba" - } - }, - "spec": { - "serviceAccount": "dba-sa", - "securityContext": {}, - "containers": [ - { - "name": "dba", - "image": "$CCP_IMAGE_PREFIX/crunchy-dba:$CCP_IMAGE_TAG", - "env": [ - { - "name": "KUBECONFIG", - "value": "/tmp/.kube" - }, - { - "name": "$PLATFORM", - "value": "$CCP_NAMESPACE" - }, - { - "name": "CCP_IMAGE_TAG", - "value": "$CCP_IMAGE_TAG" - }, - { - "name": "CCP_IMAGE_PREFIX", - "value": "$CCP_IMAGE_PREFIX" - }, - { - "name": "JOB_HOST", - "value": "dba" - }, - { - "name": "PG_USER", - "value": "primaryuser" - }, - { - "name": "PG_PASSWORD", - "value": "password" - }, - { - "name": "PG_PORT", - "value": "5432" - }, - { - "name": "BACKUP_SCHEDULE", - "value": "0 5,10,15,20,25,30,35,40,45,50,55 * * * *" - }, - { - "name": "BACKUP_PVC_STORAGE", - "value": "75M" - },{ - "name": "CCP_NAMESPACE", - "valueFrom": { - "fieldRef": { - "fieldPath": "metadata.namespace" - } - } - } - ] - }, - { - "name": "postgres", - "image": "$CCP_IMAGE_PREFIX/crunchy-postgres:$CCP_IMAGE_TAG", - "ports": [ - { - "containerPort": 5432, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "PG_PRIMARY_USER", - "value": "primaryuser" - }, - { - "name": "PG_PRIMARY_PORT", - "value": "5432" - }, - { - "name": "PG_MODE", - "value": "primary" - }, - { - "name": "PG_PRIMARY_PASSWORD", - "value": "password" - }, - { - "name": "PG_USER", - "value": "testuser" - }, - { - "name": "PG_PASSWORD", - "value": "password" - }, - { - "name": "PG_DATABASE", - "value": "userdb" - }, - { - "name": "PG_ROOT_PASSWORD", - "value": "password" - },{ - "name": "CCP_NAMESPACE", - "valueFrom": { - "fieldRef": { - "fieldPath": "metadata.namespace" - } - } - } - ], - "volumeMounts": [ - { - "mountPath": "/pgdata", - "name": "pgdata", - "readOnly": false - } - ] - } - ], - "volumes": [ - { - "name": "pgdata", - "emptyDir": {} - } - ] - } -} diff --git a/examples/kube/dba/dba-vac.json b/examples/kube/dba/dba-vac.json deleted file mode 100644 index 67c6275db..000000000 --- a/examples/kube/dba/dba-vac.json +++ /dev/null @@ -1,194 +0,0 @@ -{ - "apiVersion": "v1", - "kind": "ServiceAccount", - "metadata": { - "name": "dba-sa" - } -} - -{ - "apiVersion": "rbac.authorization.k8s.io/v1beta1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "dba-sa" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "cluster-admin" - }, - "subjects": [ - { - "kind": "ServiceAccount", - "name": "dba-sa", - "namespace": "$CCP_NAMESPACE" - } - ] -} - -{ - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "dba", - "labels": { - "name": "dba" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5432, - "targetPort": 5432, - "nodePort": 0 - } - ], - "selector": { - "name": "dba" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } -} - -{ - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "dba", - "labels": { - "name": "dba" - } - }, - "spec": { - "serviceAccount": "dba-sa", - "securityContext": {}, - "containers": [ - { - "name": "dba", - "image": "$CCP_IMAGE_PREFIX/crunchy-dba:$CCP_IMAGE_TAG", - "env": [ - { - "name": "KUBECONFIG", - "value": "/tmp/.kube" - }, - { - "name": "$PLATFORM", - "value": "$CCP_NAMESPACE" - }, - { - "name": "CCP_IMAGE_TAG", - "value": "$CCP_IMAGE_TAG" - }, - { - "name": "CCP_IMAGE_PREFIX", - "value": "$CCP_IMAGE_PREFIX" - }, - { - "name": "JOB_HOST", - "value": "dba" - }, - { - "name": "PG_USER", - "value": "primaryuser" - }, - { - "name": "PG_PASSWORD", - "value": "password" - }, - { - "name": "PG_PORT", - "value": "5432" - }, - { - "name": "VAC_SCHEDULE", - "value": "0 0,5,10,15,20,25,30,35,40,45,50,55 * * * *" - }, - { - "name": "VAC_ANALYZE", - "value": "true" - }, - { - "name": "VAC_TABLE", - "value": "testtable" - },{ - "name": "CCP_NAMESPACE", - "valueFrom": { - "fieldRef": { - "fieldPath": "metadata.namespace" - } - } - } - ] - }, - { - "name": "postgres", - "image": "$CCP_IMAGE_PREFIX/crunchy-postgres:$CCP_IMAGE_TAG", - "ports": [ - { - "containerPort": 5432, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "PG_PRIMARY_USER", - "value": "primaryuser" - }, - { - "name": "PG_PRIMARY_PORT", - "value": "5432" - }, - { - "name": "PG_MODE", - "value": "primary" - }, - { - "name": "PG_PRIMARY_PASSWORD", - "value": "password" - }, - { - "name": "PG_USER", - "value": "testuser" - }, - { - "name": "PG_PASSWORD", - "value": "password" - }, - { - "name": "PG_DATABASE", - "value": "userdb" - }, - { - "name": "PG_ROOT_PASSWORD", - "value": "password" - },{ - "name": "CCP_NAMESPACE", - "valueFrom": { - "fieldRef": { - "fieldPath": "metadata.namespace" - } - } - } - ], - "volumeMounts": [ - { - "mountPath": "/pgdata", - "name": "pgdata", - "readOnly": false - } - ] - } - ], - "volumes": [ - { - "name": "pgdata", - "emptyDir": {} - } - ] - } -} diff --git a/examples/kube/dba/run-kube-backup.sh b/examples/kube/dba/run-kube-backup.sh deleted file mode 100755 index 126966e7a..000000000 --- a/examples/kube/dba/run-kube-backup.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source ${CCPROOT}/examples/common.sh - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -$DIR/cleanup.sh - -echo_info "Creating the example components.." - -PLATFORM='KUBE_PROJECT' expenv -f $DIR/dba-backup.json | ${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f - diff --git a/examples/kube/dba/run-kube-vac.sh b/examples/kube/dba/run-kube-vac.sh deleted file mode 100755 index 1ea162b5f..000000000 --- a/examples/kube/dba/run-kube-vac.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source ${CCPROOT}/examples/common.sh - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -$DIR/cleanup.sh - -echo_info "Creating the example components.." - -PLATFORM='KUBE_PROJECT' expenv -f $DIR/dba-vac.json | ${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f - diff --git a/examples/kube/scheduler/add-schedules.sh b/examples/kube/scheduler/add-schedules.sh new file mode 100755 index 000000000..3e2371f0a --- /dev/null +++ b/examples/kube/scheduler/add-schedules.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +source ${CCPROOT}/examples/common.sh + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} configmap backrest-schedule-full \ + --from-file=${DIR?}/configs/schedule-backrest-full.json +${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} configmap backrest-schedule-diff \ + --from-file=${DIR?}/configs/schedule-backrest-diff.json +${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} configmap pgbasebackup-backup \ + --from-file=${DIR?}/configs/schedule-pgbasebackup.json + +${CCP_CLI?} label --namespace=${CCP_NAMESPACE?} configmap backrest-schedule-full crunchy-scheduler=true +${CCP_CLI?} label --namespace=${CCP_NAMESPACE?} configmap backrest-schedule-diff crunchy-scheduler=true +${CCP_CLI?} label --namespace=${CCP_NAMESPACE?} configmap pgbasebackup-backup crunchy-scheduler=true diff --git a/examples/kube/dba/cleanup.sh b/examples/kube/scheduler/cleanup.sh similarity index 61% rename from examples/kube/dba/cleanup.sh rename to examples/kube/scheduler/cleanup.sh index 174b64527..2b1a883fe 100755 --- a/examples/kube/dba/cleanup.sh +++ b/examples/kube/scheduler/cleanup.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. +# Copyright 2017 - 2018 Crunchy Data Solutions, Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -15,10 +15,11 @@ source ${CCPROOT}/examples/common.sh echo_info "Cleaning up.." -${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} pod dba -${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} service dba -${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} serviceaccount dba-sa -${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} clusterrolebinding dba-sa -${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} clusterrole dba-sa +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} clusterrolebinding,clusterrole,sa,rolebinding scheduler-sa scheduler-sa-edit +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} pod scheduler +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} configmap -l crunchy-scheduler=true +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} secret primary-primaryuser-secret -$CCPROOT/examples/waitforterm.sh dba ${CCP_CLI?} +$CCPROOT/examples/waitforterm.sh scheduler ${CCP_CLI?} + +dir_check_rm "scheduler" diff --git a/examples/kube/scheduler/configs/schedule-backrest-diff.json b/examples/kube/scheduler/configs/schedule-backrest-diff.json new file mode 100644 index 000000000..28e635cf4 --- /dev/null +++ b/examples/kube/scheduler/configs/schedule-backrest-diff.json @@ -0,0 +1,13 @@ +{ + "version": "v1", + "name": "backrest-diff", + "created": "2018-09-04T18:25:43.511Z", + "schedule": "1-59/2 * * * *", + "namespace": "demo", + "type": "pgbackrest", + "pgbackrest": { + "deployment": "primary-deployment", + "container": "postgres", + "type": "diff" + } +} diff --git a/examples/kube/scheduler/configs/schedule-backrest-full.json b/examples/kube/scheduler/configs/schedule-backrest-full.json new file mode 100644 index 000000000..2d879cb16 --- /dev/null +++ b/examples/kube/scheduler/configs/schedule-backrest-full.json @@ -0,0 +1,13 @@ +{ + "version": "v1", + "name": "backrest-full", + "created": "2018-09-04T18:25:43.511Z", + "schedule": "*/2 * * * *", + "namespace": "demo", + "type": "pgbackrest", + "pgbackrest": { + "deployment": "primary-deployment", + "container": "postgres", + "type": "full" + } +} diff --git a/examples/kube/scheduler/configs/schedule-pgbasebackup.json b/examples/kube/scheduler/configs/schedule-pgbasebackup.json new file mode 100644 index 000000000..56e705624 --- /dev/null +++ b/examples/kube/scheduler/configs/schedule-pgbasebackup.json @@ -0,0 +1,16 @@ +{ + "version": "v1", + "name": "primary-backup-pgbasebackup", + "created": "2018-09-04T18:25:43.511Z", + "schedule": "* * * * *", + "namespace": "demo", + "type": "pgbasebackup", + "pgbasebackup": { + "backupHost": "primary-deployment", + "backupPort": "5432", + "backupVolume": "primary-deployment-backup", + "imagePrefix": "crunchydata", + "imageTag": "centos7-10.5-2.1.0", + "secret": "pgprimary-secret" + } +} diff --git a/examples/kube/scheduler/primary/cleanup.sh b/examples/kube/scheduler/primary/cleanup.sh new file mode 100755 index 000000000..4f7d3824d --- /dev/null +++ b/examples/kube/scheduler/primary/cleanup.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Copyright 2017 - 2018 Crunchy Data Solutions, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source ${CCPROOT}/examples/common.sh +echo_info "Cleaning up.." + +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} deployment primary-deployment +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} configmap primary-deployment-pgconf +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} secret pgprimary-secret +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} service primary-deployment + +# primary-deployment-backup is used for basebackup schedules - don't delete +${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} pvc primary-deployment-pgdata primary-deployment-br primary-deployment-backup + +if [ -z "$CCP_STORAGE_CLASS" ] +then + ${CCP_CLI?} delete --namespace=${CCP_NAMESPACE?} pv primary-deployment-pgdata primary-deployment-br primary-deployment-backup +fi + +dir_check_rm "primary-deployment" diff --git a/examples/kube/scheduler/primary/configs/pgbackrest.conf b/examples/kube/scheduler/primary/configs/pgbackrest.conf new file mode 100644 index 000000000..9e4679563 --- /dev/null +++ b/examples/kube/scheduler/primary/configs/pgbackrest.conf @@ -0,0 +1,8 @@ +[db] +db-path=/pgdata/primary-deployment + +[global] +repo-path=/backrestrepo/primary-deployment-backups +repo1-retention-full=2 +repo1-retention-diff=3 +log-path=/tmp diff --git a/examples/kube/scheduler/primary/primary-deployment-pv-nfs.json b/examples/kube/scheduler/primary/primary-deployment-pv-nfs.json new file mode 100644 index 000000000..adf9beed6 --- /dev/null +++ b/examples/kube/scheduler/primary/primary-deployment-pv-nfs.json @@ -0,0 +1,65 @@ +{ + "apiVersion": "v1", + "kind": "PersistentVolume", + "metadata": { + "name": "primary-deployment-pgdata", + "labels": { + "name": "primary-deployment-pgdata" + } + }, + "spec": { + "capacity": { + "storage": "$CCP_STORAGE_CAPACITY" + }, + "accessModes": ["$CCP_STORAGE_MODE"], + "nfs": { + "path": "$CCP_STORAGE_PATH", + "server": "$CCP_NFS_IP" + }, + "persistentVolumeReclaimPolicy": "Retain" + } +} + +{ + "apiVersion": "v1", + "kind": "PersistentVolume", + "metadata": { + "name": "primary-deployment-br", + "labels": { + "name": "primary-deployment-br" + } + }, + "spec": { + "capacity": { + "storage": "$CCP_STORAGE_CAPACITY" + }, + "accessModes": ["$CCP_STORAGE_MODE"], + "nfs": { + "path": "$CCP_STORAGE_PATH", + "server": "$CCP_NFS_IP" + }, + "persistentVolumeReclaimPolicy": "Retain" + } +} + +{ + "apiVersion": "v1", + "kind": "PersistentVolume", + "metadata": { + "name": "primary-deployment-backup", + "labels": { + "name": "primary-deployment-backup" + } + }, + "spec": { + "capacity": { + "storage": "$CCP_STORAGE_CAPACITY" + }, + "accessModes": ["$CCP_STORAGE_MODE"], + "nfs": { + "path": "$CCP_STORAGE_PATH", + "server": "$CCP_NFS_IP" + }, + "persistentVolumeReclaimPolicy": "Retain" + } +} diff --git a/examples/kube/scheduler/primary/primary-deployment-pv.json b/examples/kube/scheduler/primary/primary-deployment-pv.json new file mode 100644 index 000000000..b89477a41 --- /dev/null +++ b/examples/kube/scheduler/primary/primary-deployment-pv.json @@ -0,0 +1,62 @@ +{ + "apiVersion": "v1", + "kind": "PersistentVolume", + "metadata": { + "name": "primary-deployment-pgdata", + "labels": { + "name": "primary-deployment-pgdata" + } + }, + "spec": { + "capacity": { + "storage": "$CCP_STORAGE_CAPACITY" + }, + "accessModes": ["$CCP_STORAGE_MODE"], + "hostPath": { + "path": "$CCP_STORAGE_PATH" + }, + "persistentVolumeReclaimPolicy": "Retain" + } +} + +{ + "apiVersion": "v1", + "kind": "PersistentVolume", + "metadata": { + "name": "primary-deployment-br", + "labels": { + "name": "primary-deployment-br" + } + }, + "spec": { + "capacity": { + "storage": "$CCP_STORAGE_CAPACITY" + }, + "accessModes": ["$CCP_STORAGE_MODE"], + "hostPath": { + "path": "$CCP_STORAGE_PATH" + }, + "persistentVolumeReclaimPolicy": "Retain" + } +} + +{ + "apiVersion": "v1", + "kind": "PersistentVolume", + "metadata": { + "name": "primary-deployment-backup", + "labels": { + "name": "primary-deployment-backup" + } + }, + "spec": { + "capacity": { + "storage": "$CCP_STORAGE_CAPACITY" + }, + "accessModes": ["$CCP_STORAGE_MODE"], + "hostPath": { + "path": "$CCP_STORAGE_PATH" + }, + "persistentVolumeReclaimPolicy": "Retain" + } +} diff --git a/examples/kube/scheduler/primary/primary-deployment-pvc-sc.json b/examples/kube/scheduler/primary/primary-deployment-pvc-sc.json new file mode 100644 index 000000000..e9d38ce4a --- /dev/null +++ b/examples/kube/scheduler/primary/primary-deployment-pvc-sc.json @@ -0,0 +1,56 @@ +{ + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "primary-deployment-pgdata" + }, + "spec": { + "accessModes": [ + "$CCP_STORAGE_MODE" + ], + "storageClassName": "$CCP_STORAGE_CLASS", + "resources": { + "requests": { + "storage": "$CCP_STORAGE_CAPACITY" + } + } + } +} + +{ + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "primary-deployment-br" + }, + "spec": { + "accessModes": [ + "$CCP_STORAGE_MODE" + ], + "storageClassName": "$CCP_STORAGE_CLASS", + "resources": { + "requests": { + "storage": "$CCP_STORAGE_CAPACITY" + } + } + } +} + +{ + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "primary-deployment-backup" + }, + "spec": { + "accessModes": [ + "$CCP_STORAGE_MODE" + ], + "storageClassName": "$CCP_STORAGE_CLASS", + "resources": { + "requests": { + "storage": "$CCP_STORAGE_CAPACITY" + } + } + } +} diff --git a/examples/kube/scheduler/primary/primary-deployment-pvc.json b/examples/kube/scheduler/primary/primary-deployment-pvc.json new file mode 100644 index 000000000..53315c997 --- /dev/null +++ b/examples/kube/scheduler/primary/primary-deployment-pvc.json @@ -0,0 +1,68 @@ +{ + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "primary-deployment-pgdata" + }, + "spec": { + "selector": { + "matchLabels": { + "name": "primary-deployment-pgdata" + } + }, + "accessModes": [ + "$CCP_STORAGE_MODE" + ], + "resources": { + "requests": { + "storage": "$CCP_STORAGE_CAPACITY" + } + } + } +} + +{ + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "primary-deployment-br" + }, + "spec": { + "selector": { + "matchLabels": { + "name": "primary-deployment-br" + } + }, + "accessModes": [ + "$CCP_STORAGE_MODE" + ], + "resources": { + "requests": { + "storage": "$CCP_STORAGE_CAPACITY" + } + } + } +} + +{ + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "primary-deployment-backup" + }, + "spec": { + "selector": { + "matchLabels": { + "name": "primary-deployment-backup" + } + }, + "accessModes": [ + "$CCP_STORAGE_MODE" + ], + "resources": { + "requests": { + "storage": "$CCP_STORAGE_CAPACITY" + } + } + } +} diff --git a/examples/kube/scheduler/primary/primary-deployment.json b/examples/kube/scheduler/primary/primary-deployment.json new file mode 100644 index 000000000..ae02b7261 --- /dev/null +++ b/examples/kube/scheduler/primary/primary-deployment.json @@ -0,0 +1,181 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "primary-deployment", + "labels": { + "name": "primary-deployment" + } + }, + "spec": { + "ports": [ + { + "protocol": "TCP", + "port": 5432, + "targetPort": 5432, + "nodePort": 0 + } + ], + "selector": { + "name": "primary-deployment" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + } +} + +{ + "kind": "Deployment", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "primary-deployment", + "labels": { + "name": "primary-deployment" + } + }, + "spec": { + "replicas": 1, + "template": { + "metadata": { + "labels": { + "name": "primary-deployment" + } + }, + "spec": { + "containers": [ + { + "name": "postgres", + "image": "$CCP_IMAGE_PREFIX/crunchy-postgres:$CCP_IMAGE_TAG", + "readinessProbe": { + "exec": { + "command": [ + "/opt/cpm/bin/readiness.sh" + ] + }, + "initialDelaySeconds": 40, + "timeoutSeconds": 1 + }, + "livenessProbe": { + "exec": { + "command": [ + "/opt/cpm/bin/liveness.sh" + ] + }, + "initialDelaySeconds": 40, + "timeoutSeconds": 1 + }, + "env": [ + { + "name": "PG_PRIMARY_PORT", + "value": "5432" + }, + { + "name": "PG_MODE", + "value": "primary" + }, + { + "name": "PGDATA_PATH_OVERRIDE", + "value": "primary-deployment" + }, + { + "name": "PGHOST", + "value": "/tmp" + }, + { + "name": "PG_USER", + "value": "testuser" + }, + { + "name": "PG_PASSWORD", + "value": "password" + }, + { + "name": "PG_PRIMARY_USER", + "valueFrom": { + "secretKeyRef": { + "key": "username", + "name": "pgprimary-secret" + } + } + }, + { + "name": "PG_PRIMARY_PASSWORD", + "valueFrom": { + "secretKeyRef": { + "key": "password", + "name": "pgprimary-secret" + } + } + }, + { + "name": "PG_ROOT_PASSWORD", + "value": "password" + }, + { + "name": "PG_DATABASE", + "value": "userdb" + } + ], + "volumeMounts": [ + { + "mountPath": "/pgdata", + "name": "pgdata", + "readOnly": false + }, + { + "mountPath": "/backrestrepo", + "name": "backrestrepo", + "readOnly": false + }, + { + "mountPath": "/pgconf", + "name": "primary-deployment-pgconf" + } + ], + "ports": [ + { + "containerPort": 5432, + "protocol": "TCP" + } + ], + "resources": {}, + "imagePullPolicy": "IfNotPresent" + } + ], + "volumes": [ + { + "name": "pgdata", + "persistentVolumeClaim": { + "claimName": "primary-deployment-pgdata" + } + }, + { + "name": "backrestrepo", + "persistentVolumeClaim": { + "claimName": "primary-deployment-br" + } + }, + { + "name": "primary-deployment-pgconf", + "configMap": { + "name": "primary-deployment-pgconf" + } + } + ], + "restartPolicy": "Always", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "securityContext": { + $CCP_SECURITY_CONTEXT + } + } + }, + "strategy": { + "type": "RollingUpdate", + "rollingUpdate": { + "maxUnavailable": 1, + "maxSurge": 1 + } + } + } +} diff --git a/examples/kube/dba/run-ocp-vac.sh b/examples/kube/scheduler/primary/run.sh similarity index 52% rename from examples/kube/dba/run-ocp-vac.sh rename to examples/kube/scheduler/primary/run.sh index aedfde7d0..e2f735a95 100755 --- a/examples/kube/dba/run-ocp-vac.sh +++ b/examples/kube/scheduler/primary/run.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. +# Copyright 2017 - 2018 Crunchy Data Solutions, Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -16,8 +16,20 @@ source ${CCPROOT}/examples/common.sh DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -$DIR/cleanup.sh +${DIR}/cleanup.sh -echo_info "Creating the example components.." +create_storage "primary-deployment" +if [[ $? -ne 0 ]] +then + echo_err "Failed to create storage, exiting.." + exit 1 +fi -PLATFORM='OSE_PROJECT' expenv -f $DIR/dba-vac.json | ${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f - +${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} configmap primary-deployment-pgconf \ + --from-file ${DIR?}/configs/pgbackrest.conf + +${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} secret generic pgprimary-secret \ + --from-literal=username='primaryuser' \ + --from-literal=password='password' + +expenv -f $DIR/primary-deployment.json | ${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f - diff --git a/examples/kube/dba/run-ocp-backup.sh b/examples/kube/scheduler/run.sh similarity index 72% rename from examples/kube/dba/run-ocp-backup.sh rename to examples/kube/scheduler/run.sh index 8ad646a2d..338d7ceb3 100755 --- a/examples/kube/dba/run-ocp-backup.sh +++ b/examples/kube/scheduler/run.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2016 - 2018 Crunchy Data Solutions, Inc. +# Copyright 2017 - 2018 Crunchy Data Solutions, Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -16,8 +16,7 @@ source ${CCPROOT}/examples/common.sh DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -$DIR/cleanup.sh +${DIR}/cleanup.sh -echo_info "Creating the example components.." - -PLATFORM='OSE_PROJECT' expenv -f $DIR/dba-backup.json | ${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f - +expenv -f $DIR/scheduler-sa.json | ${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f - +expenv -f $DIR/scheduler.json | ${CCP_CLI?} create --namespace=${CCP_NAMESPACE?} -f - diff --git a/examples/kube/scheduler/scheduler-sa.json b/examples/kube/scheduler/scheduler-sa.json new file mode 100644 index 000000000..de65fe9ee --- /dev/null +++ b/examples/kube/scheduler/scheduler-sa.json @@ -0,0 +1,108 @@ +{ + "apiVersion": "rbac.authorization.k8s.io/v1beta1", + "kind": "ClusterRole", + "metadata": { + "name": "scheduler-sa" + }, + "rules": [ + { + "apiGroups": [ + "" + ], + "resources": [ + "namespaces", + "pods", + "configmaps", + "deployments", + "secrets" + ], + "verbs": [ + "get", + "list", + "watch" + ] + }, + { + "apiGroups": [ + "batch", + "extensions" + ], + "resources": [ + "jobs" + ], + "verbs": [ + "get", + "list", + "watch", + "create", + "update", + "patch", + "delete" + ] + }, + { + "apiGroups": [ + "extensions", + "apps" + ], + "resources": [ + "deployments" + ], + "verbs": [ + "get", + "list", + "watch" + ] + }, + { + "nonResourceURLs": [ + "/apis" + ], + "verbs": [ + "get", + "list", + "watch" + ] + }, + { + "apiGroups": [ + "" + ], + "resources": [ + "pods/exec" + ], + "verbs": [ + "create" + ] + } + ] +} + +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "metadata": { + "name": "scheduler-sa", + "namespace": "$CCP_NAMESPACE" + } +} + +{ + "apiVersion": "rbac.authorization.k8s.io/v1beta1", + "kind": "ClusterRoleBinding", + "metadata": { + "name": "scheduler-sa" + }, + "roleRef": { + "apiGroup": "rbac.authorization.k8s.io", + "kind": "ClusterRole", + "name": "scheduler-sa" + }, + "subjects": [ + { + "kind": "ServiceAccount", + "name": "scheduler-sa", + "namespace": "$CCP_NAMESPACE" + } + ] +} diff --git a/examples/kube/scheduler/scheduler.json b/examples/kube/scheduler/scheduler.json new file mode 100644 index 000000000..fdaca585f --- /dev/null +++ b/examples/kube/scheduler/scheduler.json @@ -0,0 +1,35 @@ +{ + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "scheduler", + "namespace": "$CCP_NAMESPACE", + "labels": { + "name": "scheduler" + } + }, + "spec": { + "serviceAccountName": "scheduler-sa", + "securityContext": { + $CCP_SECURITY_CONTEXT + }, + "containers": [ + { + "name": "scheduler", + "image": "$CCP_IMAGE_PREFIX/crunchy-scheduler:$CCP_IMAGE_TAG", + "env": [ + { + "name": "NAMESPACE", + "valueFrom": { + "fieldRef": { + "fieldPath": "metadata.namespace" + } + } + } + ], + "volumeMounts": [] + } + ], + "volumes": [] + } +} diff --git a/hugo/content/container-specifications/crunchy-dba.md b/hugo/content/container-specifications/crunchy-dba.md deleted file mode 100644 index 5ee24b252..000000000 --- a/hugo/content/container-specifications/crunchy-dba.md +++ /dev/null @@ -1,159 +0,0 @@ ---- -title: "crunchy-dba" -date: 2018-05-24T12:05:24-07:00 -draft: false ---- - -The crunchy-dba container implements a cron scheduler. The purpose -of the crunchy-dba container is to offer a way to perform -simple DBA tasks that occur on some form of schedule such as -backup jobs or running a vacuum on a *single* PostgreSQL database container. - -You can either run the crunchy-dba container as a single pod or include -the container within a database pod. - -The crunchy-dba container makes use of a Service Account to perform -the startup of scheduled jobs. The Kubernetes Job type is used to execute -the scheduled jobs with a Restart policy of Never. - -## Packages - -The crunchy-dba Docker image contains the following packages: - -* CentOS7 - publicly available -* RHEL7 - customers only - -## Environment Variables - -### General -**Name**|**Default**|**Description** -:-----|:-----|:----- -**OSE_PROJECT**|None|The OSE project name to log into. -**JOB_HOST**|None|The PostgreSQL container name the action will be taken against. -**VAC_SCHEDULE**|None|If set, this will start a vacuum job container. The setting value must be a valid cron expression as described below. -**BACKUP_SCHEDULE**|None|If set, this will start a backup job container. The setting value must be a valid cron expression as described below. -**CRUNCHY_DEBUG**|FALSE|Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. - -### Vacuum Job - -For a vacuum job, you are required to supply the following environment variables: - -**Name**|**Default**|**Description** -:-----|:-----|:----- -**JOB_HOST**|None|The PostgreSQL container name the action will be taken against. -**PG_USER**|None|Username for the PostgreSQL role being used. -**PG_PASSWORD**|None|Password for the PostgreSQL role being used. -**PG_DATABASE**|postgres|Database host to connect to. -**PG_PORT**|5432|Allows you to override the default value of 5432. -**VAC_ANALYZE**|TRUE|When set to true, adds the ANALYZE parameter to the VACUUM command. -**VAC_FULL**|TRUE|hen set to true, adds the FULL parameter to the VACUUM command. -**VAC_VERBOSE**|TRUE|When set to true, adds the VERBOSE parameter to the VACUUM command. -**VAC_FREEZE**|FALSE|When set to true, adds the FREEZE parameter to the VACUUM command. -**VAC_TABLE**|FALSE|When set to true, allows you to specify a single table to vacuum. When not specified, the entire database tables are vacuumed. - -### Backup Job - -For a backup job, you are required to supply the following environment variables: - -**Name**|**Default**|**Description** -:-----|:-----|:----- -**JOB_HOST**|None|The PostgreSQL container name the action will be taken against. -**PG_USER**|None|Username for the PostgreSQL role being used. -**PG_PASSWORD**|None|Password for the PostgreSQL role being used. -**PG_PORT**|5432|Allows you to override the default value of 5432. -**BACKUP_PV_CAPACITY**|None|A value like 1Gi is used to define the PV storage capacity. -**BACKUP_PV_PATH**|None|The storage path used to build the PV. -**BACKUP_PV_HOST**|None|The storage host used to build the PV. -**BACKUP_PVC_STORAGE**|None|A value like 75M means to allow 75 megabytes for the PVC used in performing the backup. - -## CRON Expression Format - -A cron expression represents a set of times, using 6 space-separated fields. - -**Field Name**|**Mandatory?**|**Allowed Values**|**Allowed Special Characters** -:-----|:-----|:-----|:----- -**Seconds**|Yes|0-59|* / , - -**Minutes**|Yes|0-59|* / , - -**Hours**|Yes|0-23|* / , - -**Day of month**|Yes|1-31|* / , - ? -**Month**|Yes|1-12 or JAN-DEC|* / , - -**Day of week**|Yes|0-6 or SUN-SAT|* / , - ? - -{{% notice tip %}} -Month and Day-of-week field values are case insensitive. "SUN", "Sun", and "sun" are equally accepted. -{{% /notice %}} - -### Special Characters - -#### Asterisk - -The asterisk indicates that the cron expression will match for all values -of the field; e.g., using an asterisk in the 5th field (month) would -indicate every month. - -#### Slash - -Slashes are used to describe increments of ranges. For example 3-59/15 in -the 1st field (minutes) would indicate the 3rd minute of the hour and every -15 minutes thereafter. The form "*\/..." is equivalent to the form -"first-last/...", that is, an increment over the largest possible range of -the field. The form "N/..." is accepted as meaning "N-MAX/...", that is, -starting at N, use the increment until the end of that specific range. -It does not wrap around. - -#### Comma - -Commas are used to separate items of a list. For example, using -"MON,WED,FRI" in the 5th field (day of week) would mean Mondays, -Wednesdays and Fridays. - -#### Hyphen - -Hyphens are used to define ranges. For example, 9-17 would indicate every -hour between 9am and 5pm inclusive. - -#### Question mark - -Question mark may be used instead of "*" for leaving either day-of-month or -day-of-week blank. - -### Predefined schedules - -You may use one of several pre-defined schedules in place of a cron expression. - -**Entry**|**Description**|**Equivalent To** -:-----|:-----|:----- -**@yearly (or @annually)**|Run once a year, midnight, Jan. 1st|0 0 0 1 1 * -**@monthly**|Run once a month, midnight, first of month|0 0 0 1 * * -**@weekly**|Run once a week, midnight on Sunday|0 0 0 * * 0 -**@daily (or @midnight)**|Run once a day, midnight|0 0 0 * * * -**@hourly**|Run once an hour, beginning of hour|0 0 * * * * - -### Intervals - -You may also schedule a job to execute at fixed intervals. This is -supported by formatting the cron spec like this: - -``` -@every -``` - -where "duration" is a string accepted by time.ParseDuration -(http://golang.org/pkg/time/#ParseDuration). - -For example, "@every 1h30m10s" would indicate a schedule that activates every -1 hour, 30 minutes, 10 seconds. - -NOTE: The interval does not take the job runtime into account. For example, -if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes, -it will have only 2 minutes of idle time between each run. - -### Time zones - -All interpretation and scheduling is done in the machines local -time zone (as provided by the Go time package -(http://www.golang.org/pkg/time). - -{{% notice tip %}} -Be aware that jobs scheduled during daylight-savings leap-ahead transitions will not be run. -{{% /notice %}} diff --git a/hugo/content/container-specifications/crunchy-scheduler.md b/hugo/content/container-specifications/crunchy-scheduler.md new file mode 100644 index 000000000..c19112b02 --- /dev/null +++ b/hugo/content/container-specifications/crunchy-scheduler.md @@ -0,0 +1,32 @@ +--- +title: "crunchy-scheduler" +date: 2018-05-24T10:06:13-07:00 +draft: false +weight: 7 +--- + +The Crunchy Scheduler container provides a cronlike microservice for automating +pgBaseBackup and pgBackRest backups within a single namespace. The scheduler +watches Kubernetes for config maps with the label `crunchy-scheduler=true`. +If found the scheduler parses a JSON object contained in the config map and +converts it into an scheduled task. + +## Packages + +The Crunchy Scheduler Docker image contains the following packages: + +* CentOS7 - publicly available +* RHEL7 - customers only +* Scheduler App + +## Environment Variables + +### Required +**Name**|**Default**|**Description** +:-----|:-----|:----- +**NAMESPACE**|None|The namespace the microservice should watch. Crunchy Scheduler only works in a single namespace. + +### Optional +**Name**|**Default**|**Description** +:-----|:-----|:----- +**CRUNCHY_DEBUG**|FALSE|Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. diff --git a/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc b/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc index d4f0b9b74..10afec8c5 100644 --- a/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc +++ b/hugo/content/getting-started/kubernetes-and-openshift/_index.adoc @@ -262,52 +262,99 @@ You can verify the upgraded database by running the `post-upgrade.sh` script in `examples/kube/upgrade` directory. This will create a PostgreSQL pod that mounts the upgraded volume. -=== Cron Scheduler +=== Crunchy Scheduler -The crunchy-dba container implements a cron scheduler. The purpose of the crunchy-dba -container is to offer a way to perform simple DBA tasks that occur on some form of -schedule such as backup jobs or running a vacuum on a single PostgreSQL database container -(such as the *primary* example). +The Crunchy Scheduler container implements a cronlike microservice within a namespace +to automate backups of a PostgreSQL database. -You can either run the crunchy-dba container as a single pod or include the container -within a database pod. +Currently Crunchy Scheduler only supports two types of tasks: +* pgBackRest +* pgBaseBackup -The crunchy-dba container makes use of a Service Account to perform the startup of -scheduled jobs. The Kubernetes Job type is used to execute the scheduled jobs with a Restart -policy of Never. +This service watches Kubernetes for config maps with the label `crunchy-scheduler=true`. +If found the scheduler will parse the data found in the config map (json object) and +convert it to a scheduled task. If the config map is removed, the scheduler will +delete the task. -To shutdown the instance and remove the container for each example, run the following: -.... -./cleanup.sh -.... +See the following examples for creating config maps that Crunchy Scheduler can parse: +* link:https://github.com/CrunchyData/crunchy-containers/blob/scheduler/examples/kube/scheduler/configs/schedule-backrest-diff.json[pgBackRest Diff Backup] +* link:https://github.com/CrunchyData/crunchy-containers/blob/scheduler/examples/kube/scheduler/configs/schedule-backrest-full.json[pgBackRest Full Backup] +* link:https://github.com/CrunchyData/crunchy-containers/blob/scheduler/examples/kube/scheduler/configs/schedule-pgbasebackup.json[pgBaseBackup Backup] + +The Crunchy Scheduler requires a Service Account to create jobs (pgBaseBackup) and to +exec (pgBackRest). See the link:https://github.com/CrunchyData/crunchy-containers/blob/scheduler/examples/kube/scheduler/scheduler-sa.json[scheduler example] +for the required permissions on this account. + +==== pgBackRest Schedules + +To configure Crunchy Scheduler to create pgBackRest backups the following is required: + * pgBackRest schedule definition requires a deployment name. The PostgreSQL pod should be created by a deployment. + +==== pgBaseBackup Schedules + +To configure Crunchy Scheduler to create pgBaseBackup scheduled backups, the following is required: + * The name of the secret that contains the username and password the Scheduler will use to + configure the job template. See link:https://github.com/CrunchyData/crunchy-containers/blob/scheduler/examples/kube/scheduler/primary/secret.json[the primary secret example]. + for the structure required by the Scheduler. + * The name of the PVC created for the backups. This should be created by the user prior to scheduling the task. ==== Kubernetes and OpenShift -The script to schedule vacuum on a regular schedule is executed through the following -commands: +First, start the PostgreSQL example created for the Scheduler by running the following commands: + .... # Kubernetes -cd $CCPROOT/examples/kube/dba -./run-kube-vac.sh +cd $CCPROOT/examples/kube/scheduler/primary +./run.sh +.... -# OpenShift -cd $CCPROOT/examples/kube/dba -./run-ocp-vac.sh +The pod created should show a ready status before proceeding. + +Next, start the scheduler by running the following command: + +.... +# Kubernetes +cd $CCPROOT/examples/kube/scheduler +./run.sh .... -To run the script for scheduled backups, run the following in the same directory: +Once the scheduler is deployed, register the backup tasks by running the following command: + .... # Kubernetes -cd $CCPROOT/examples/kube/dba -./run-kube-backup.sh +cd $CCPROOT/examples/kube/scheduler +./add-tasks.sh +.... + +The scheduled tasks will (these are just for fast results, not recommended for production): + * take a backup every minute using pgBaseBackup + * take a full pgBackRest backup every even minute + * take a diff pgBackRest backup every odd minute + +View the logs for the `scheduler` pod until the tasks run: -# OpenShift -cd $CCPROOT/examples/kube/dba -./run-ocp-backup.sh .... +${CCP_CLI?} logs scheduler -f +.... + +View the `pgBaseBackup` pods results after the backup completes: -Individual parameters for both can be modified within their respective JSON files; -please see the link:/container-specifications/[Container Specifications] document for a full list of what can be modified. +.... +${CCP_CLI?} logs +.... + +View the `pgBackRest` backups via exec after the backup completes: + +.... +${CCP_CLI?} exec -ti -- pgbackrest info +.... + +Clean up the examples by running the following commands: + +.... +$CCPROOT/examples/kube/scheduler/primary/cleanup.sh +$CCPROOT/examples/kube/scheduler/cleanup.sh +.... === Vacuum diff --git a/rhel7/Dockerfile.scheduler-build.rhel7 b/rhel7/Dockerfile.scheduler-build.rhel7 new file mode 100644 index 000000000..3c7b10763 --- /dev/null +++ b/rhel7/Dockerfile.scheduler-build.rhel7 @@ -0,0 +1,7 @@ +FROM golang:1.9.1 +WORKDIR /go/src/github.com/crunchydata/crunchy-containers +ADD . . +RUN go get github.com/tools/godep \ + && godep restore \ + && go get gopkg.in/robfig/cron.v2 +RUN CGO_ENABLED=0 GOOS=linux go build -a -o scheduler ./tools/scheduler diff --git a/rhel7/Dockerfile.scheduler.rhel7 b/rhel7/Dockerfile.scheduler.rhel7 new file mode 100644 index 000000000..fbe682d09 --- /dev/null +++ b/rhel7/Dockerfile.scheduler.rhel7 @@ -0,0 +1,40 @@ +FROM registry.access.redhat.com/rhel7 + +MAINTAINER Crunchy Data + +LABEL name="crunchydata/scheduler" \ + vendor="crunchy data" \ + Version="7.5" \ + Release="2.1.0" \ + url="https://crunchydata.com" \ + summary="Crunchy Scheduler is a cron-like microservice for scheduling automatic backups" \ + description="Crunchy Scheduler parses JSON configMaps with the label 'crunchy-scheduler=true' and transforms them into cron based tasks for automating pgBaseBackup and pgBackRest backups" \ + io.k8s.description="scheduler container" \ + io.k8s.display-name="Crunchy Scheduler container" \ + io.openshift.expose-services="" \ + io.openshift.tags="crunchy,database,cron" + +COPY conf/atomic/scheduler/help.1 /help.1 +COPY conf/atomic/scheduler/help.md /help.md +COPY conf/licenses /licenses + +RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y update \ + && yum -y install \ + bind-utils \ + gettext \ + hostname \ + nss_wrapper \ + procps-ng \ + && yum clean all -y + +RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /configs \ + && chown -R 2:2 /opt/cpm /configs + +ADD bin/scheduler /opt/cpm/bin +ADD bin/common /opt/cpm/bin +ADD conf/scheduler /opt/cpm/conf + +USER 2 + +CMD ["/opt/cpm/bin/start.sh"] diff --git a/tools/kubeapi/configmap.go b/tools/kubeapi/configmap.go new file mode 100644 index 000000000..24d9811a0 --- /dev/null +++ b/tools/kubeapi/configmap.go @@ -0,0 +1,47 @@ +package kubeapi + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ConfigMap struct { + Name, Filename, Data []byte +} + +func (k *KubeAPI) GetConfigMaps(namespace string, label, field string) ([]ConfigMap, error) { + opts := metav1.ListOptions{ + LabelSelector: label, + FieldSelector: field, + } + + mapList, err := k.ListConfigMaps(namespace, opts) + if err != nil { + return nil, err + } + + var configMaps []ConfigMap + for _, v := range mapList.Items { + c, err := k.GetConfigMap(namespace, v.GetName(), metav1.GetOptions{}) + if err != nil { + return nil, err + } + var configMap ConfigMap + for name, data := range c.Data { + configMap.Name = []byte(c.Name) + configMap.Filename = []byte(name) + configMap.Data = []byte(data) + configMaps = append(configMaps, configMap) + } + } + + return configMaps, nil +} + +func (k *KubeAPI) GetConfigMap(namespace, name string, opts metav1.GetOptions) (*v1.ConfigMap, error) { + return k.Client.CoreV1().ConfigMaps(namespace).Get(name, opts) +} + +func (k *KubeAPI) ListConfigMaps(namespace string, opts metav1.ListOptions) (*v1.ConfigMapList, error) { + return k.Client.CoreV1().ConfigMaps(namespace).List(opts) +} diff --git a/tools/test-harness/kubeapi/deployment.go b/tools/kubeapi/deployment.go similarity index 90% rename from tools/test-harness/kubeapi/deployment.go rename to tools/kubeapi/deployment.go index b87285281..6c3d01876 100644 --- a/tools/test-harness/kubeapi/deployment.go +++ b/tools/kubeapi/deployment.go @@ -36,6 +36,13 @@ func (k *KubeAPI) GetDeploymentPods(namespace, deployment string) ([]string, err return podList, nil } +func (k *KubeAPI) ListDeployments(namespace, label string) (*apps.DeploymentList, error) { + return k.Client.AppsV1().Deployments(namespace).List( + metav1.ListOptions{ + LabelSelector: label, + }) +} + // DeleteDeployment method deletes a given deployment in a given // namespace. func (k *KubeAPI) DeleteDeployment(namespace, deployment string) error { diff --git a/tools/test-harness/kubeapi/exec.go b/tools/kubeapi/exec.go similarity index 100% rename from tools/test-harness/kubeapi/exec.go rename to tools/kubeapi/exec.go diff --git a/tools/kubeapi/job.go b/tools/kubeapi/job.go new file mode 100644 index 000000000..908698a17 --- /dev/null +++ b/tools/kubeapi/job.go @@ -0,0 +1,67 @@ +package kubeapi + +import ( + "fmt" + "time" + + v1batch "k8s.io/api/batch/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func (k *KubeAPI) CreateJob(namespace string, job *v1batch.Job) (*v1batch.Job, error) { + return k.Client.BatchV1().Jobs(namespace).Create(job) +} + +func (k *KubeAPI) DeleteJob(namespace string, job *v1batch.Job) error { + cascade := metav1.DeletePropagationForeground + return k.Client.BatchV1().Jobs(namespace).Delete(job.Name, &metav1.DeleteOptions{PropagationPolicy: &cascade}) +} + +// GetJob method returns a job data structure for a +// given job in a given namespace. +func (k *KubeAPI) GetJob(namespace, job string) (*v1batch.Job, error) { + return k.Client.BatchV1().Jobs(namespace).Get(job, metav1.GetOptions{}) +} + +// IsJobComplete method tests if a job has completed +// successfully. +func (k *KubeAPI) IsJobComplete(namespace string, job *v1batch.Job) error { + timeout := time.After(k.Timeout) + tick := time.Tick(500 * time.Millisecond) + for { + select { + case <-timeout: + return fmt.Errorf("timed out waiting for job to complete: %s", job.Name) + case <-tick: + j, err := k.GetJob(namespace, job.Name) + if err != nil { + return err + } + if j.Status.Failed != 0 { + return fmt.Errorf("job failed to run: %s", job) + } + if j.Status.Succeeded != 0 { + return nil + } + } + } +} + +// IsJobDeleted method tests if a job has deleted +// successfully. +func (k *KubeAPI) IsJobDeleted(namespace string, job *v1batch.Job) error { + timeout := time.After(k.Timeout) + tick := time.Tick(500 * time.Millisecond) + for { + select { + case <-timeout: + return fmt.Errorf("timed out waiting for job to delete: %s", job.Name) + case <-tick: + _, err := k.GetJob(namespace, job.Name) + if err != nil && kerrors.IsNotFound(err) { + return nil + } + } + } +} diff --git a/tools/test-harness/kubeapi/kubeapi.go b/tools/kubeapi/kubeapi.go similarity index 100% rename from tools/test-harness/kubeapi/kubeapi.go rename to tools/kubeapi/kubeapi.go diff --git a/tools/test-harness/kubeapi/namespace.go b/tools/kubeapi/namespace.go similarity index 100% rename from tools/test-harness/kubeapi/namespace.go rename to tools/kubeapi/namespace.go diff --git a/tools/test-harness/kubeapi/pod.go b/tools/kubeapi/pod.go similarity index 100% rename from tools/test-harness/kubeapi/pod.go rename to tools/kubeapi/pod.go diff --git a/tools/test-harness/kubeapi/proxy.go b/tools/kubeapi/proxy.go similarity index 100% rename from tools/test-harness/kubeapi/proxy.go rename to tools/kubeapi/proxy.go diff --git a/tools/kubeapi/secret.go b/tools/kubeapi/secret.go new file mode 100644 index 000000000..229cf8122 --- /dev/null +++ b/tools/kubeapi/secret.go @@ -0,0 +1,10 @@ +package kubeapi + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func (k *KubeAPI) GetSecret(namespace, name string) (*v1.Secret, error) { + return k.Client.CoreV1().Secrets(namespace).Get(name, metav1.GetOptions{}) +} diff --git a/tools/test-harness/kubeapi/service.go b/tools/kubeapi/service.go similarity index 100% rename from tools/test-harness/kubeapi/service.go rename to tools/kubeapi/service.go diff --git a/tools/test-harness/kubeapi/statefulset.go b/tools/kubeapi/statefulset.go similarity index 100% rename from tools/test-harness/kubeapi/statefulset.go rename to tools/kubeapi/statefulset.go diff --git a/tools/scheduler/cron/cron.go b/tools/scheduler/cron/cron.go new file mode 100644 index 000000000..0ef91e4aa --- /dev/null +++ b/tools/scheduler/cron/cron.go @@ -0,0 +1,157 @@ +package cron + +import ( + "encoding/json" + "errors" + "fmt" + "time" + + log "github.com/sirupsen/logrus" + + "github.com/crunchydata/crunchy-containers/tools/kubeapi" + cv2 "gopkg.in/robfig/cron.v2" +) + +func New(label, namespace string, client *kubeapi.KubeAPI) *Cron { + cronClient := cv2.New() + var p phony + cronClient.AddJob("* * * * *", p) + return &Cron{ + namespace: namespace, + label: label, + CronClient: cronClient, + kubeClient: client, + entries: make(map[string]cv2.EntryID), + scheduleTypes: []string{ + "pgbackrest", + "pgbasebackup", + }, + } +} + +func (c *Cron) AddJobs() error { + configs, err := c.kubeClient.GetConfigMaps(c.namespace, c.label, "") + if err != nil { + return err + } + + for _, config := range configs { + if _, ok := c.entries[string(config.Name)]; ok { + continue + } + + contextErr := log.WithFields(log.Fields{ + "configMap": config.Name, + "filename": config.Filename, + }) + + var schedule ScheduleTemplate + if err := json.Unmarshal(config.Data, &schedule); err != nil { + contextErr.WithFields(log.Fields{ + "error": err, + }).Error("Failed unmarshaling configMap") + continue + } + + if err := c.validateSchedule(schedule); err != nil { + contextErr.WithFields(log.Fields{ + "error": err, + }).Error("Failed to validate configMap") + continue + } + + id, err := c.schedule(schedule) + if err != nil { + contextErr.WithFields(log.Fields{ + "error": err, + }).Error("Failed to schedule configMap") + continue + } + + log.WithFields(log.Fields{ + "configMap": string(config.Name), + "type": schedule.Type, + "schedule": schedule.Schedule, + "namespace": schedule.Namespace, + "deployment": schedule.Deployment, + "label": schedule.Label, + "container": schedule.Container, + }).Info("Added new schedule") + c.entries[string(config.Name)] = id + } + return nil +} + +func (c *Cron) DeleteJobs() error { + configs, err := c.kubeClient.GetConfigMaps(c.namespace, c.label, "") + if err != nil { + return err + } + + for name := range c.entries { + found := false + for _, config := range configs { + if name == string(config.Name) { + found = true + } + } + if !found { + log.WithFields(log.Fields{ + "scheduleName": name, + }).Info("Removed schedule") + c.CronClient.Remove(c.entries[name]) + delete(c.entries, name) + } + } + return nil +} + +func (c *Cron) validateSchedule(s ScheduleTemplate) error { + _, err := cv2.Parse(s.Schedule) + if err != nil { + return err + } + + validType := false + for _, v := range c.scheduleTypes { + if v == s.Type { + validType = true + } + } + + if !validType { + return fmt.Errorf("%s is not a valid schedulable type", s.Type) + } + + if s.Type == "pgbackrest" { + if s.PGBackRest.Deployment == "" && s.PGBackRest.Label == "" { + return errors.New("Deployment or Label required for pgBackRest schedules") + } + } + return nil +} + +func (c *Cron) schedule(s ScheduleTemplate) (cv2.EntryID, error) { + var job cv2.Job + + switch s.Type { + case "pgbackrest": + job = s.NewBackRestSchedule("db", c.kubeClient) + case "pgbasebackup": + job = s.NewBackBaseBackupSchedule(c.kubeClient) + default: + var id cv2.EntryID + return id, fmt.Errorf("schedule type not implemented yet") + } + + return c.CronClient.AddJob(s.Schedule, job) +} + +type phony string + +func (p phony) Run() { + // This is a phony job that register with the cron service + // that does nothing to prevent a bug that runs newly scheduled + // jobs multiple times. + _ = time.Now() +} diff --git a/tools/scheduler/cron/pgbackrest.go b/tools/scheduler/cron/pgbackrest.go new file mode 100644 index 000000000..374f375a1 --- /dev/null +++ b/tools/scheduler/cron/pgbackrest.go @@ -0,0 +1,88 @@ +package cron + +import ( + "fmt" + + "github.com/crunchydata/crunchy-containers/tools/kubeapi" + log "github.com/sirupsen/logrus" +) + +type BackRestBackupJob struct { + backupType string + stanza string + namespace string + deployment string + label string + container string + client *kubeapi.KubeAPI +} + +func (s *ScheduleTemplate) NewBackRestSchedule(stanza string, client *kubeapi.KubeAPI) BackRestBackupJob { + return BackRestBackupJob{ + backupType: s.PGBackRest.Type, + stanza: stanza, + namespace: s.Namespace, + deployment: s.PGBackRest.Deployment, + label: s.PGBackRest.Label, + container: s.PGBackRest.Container, + client: client, + } +} + +func (b BackRestBackupJob) Run() { + contextLogger := log.WithFields(log.Fields{ + "namespace": b.namespace, + "deployment": b.deployment, + "label": b.label, + "container": b.container, + "backupType": b.backupType}) + + contextLogger.Info("Running pgBackRest backup") + + backup := []string{ + "/usr/bin/pgbackrest", + fmt.Sprintf("--stanza=%s", b.stanza), + "backup", fmt.Sprintf("--type=%s", b.backupType), + } + cmd := append(nsswrapper, backup...) + + if b.label != "" { + deployments, err := b.client.ListDeployments(b.namespace, b.label) + if err != nil { + contextLogger.WithFields(log.Fields{ + "error": err, + }).Error("Failed getting deployments from label") + return + } + if len(deployments.Items) != 1 { + contextLogger.WithFields(log.Fields{ + "error": err, + "label_count": len(deployments.Items), + }).Error("Failed to get one deployment from label") + return + } + b.deployment = deployments.Items[0].Name + } + + pods, err := b.client.GetDeploymentPods(b.namespace, b.deployment) + if err != nil { + contextLogger.WithFields(log.Fields{ + "error": err, + }).Error("Failed getting pods from deployment") + return + } + + if len(pods) == 0 { + contextLogger.WithFields(log.Fields{}).Error("No pods found in deployment") + return + } + + _, stderr, err := b.client.Exec(b.namespace, pods[0], b.container, cmd) + if err != nil { + contextLogger.WithFields(log.Fields{ + "error": err, + "output": stderr, + }).Error("Failed execing into container") + return + } +} diff --git a/tools/scheduler/cron/pgbasebackup.go b/tools/scheduler/cron/pgbasebackup.go new file mode 100644 index 000000000..10ea87e45 --- /dev/null +++ b/tools/scheduler/cron/pgbasebackup.go @@ -0,0 +1,150 @@ +package cron + +import ( + "bytes" + "encoding/json" + "fmt" + "html/template" + "io/ioutil" + "os" + + "github.com/crunchydata/crunchy-containers/tools/kubeapi" + log "github.com/sirupsen/logrus" + v1batch "k8s.io/api/batch/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" +) + +var BackupJobTemplate *template.Template + +const templateDirEnv = "TEMPLATE_DIR" + +func init() { + templateDir := os.Getenv(templateDirEnv) + if templateDir == "" { + log.WithFields(log.Fields{}).Fatalf("Failed to get template directory environment: %s", templateDirEnv) + } + + buf, err := ioutil.ReadFile(templateDir) + if err != nil { + log.WithFields(log.Fields{}).Fatalf("Failed to open template: %s", err) + } + BackupJobTemplate = template.Must(template.New("backup").Parse(string(buf))) +} + +type BackBaseBackupJob struct { + Name string + PvcName string + CCPImagePrefix string + CCPImageTag string + BackupHost string + BackupUser string + BackupPass string + BackupPort string + SecurityContext SecurityContext + Secret string + Namespace string + client *kubeapi.KubeAPI +} + +func (s *ScheduleTemplate) NewBackBaseBackupSchedule(client *kubeapi.KubeAPI) BackBaseBackupJob { + return BackBaseBackupJob{ + Name: s.Name, + CCPImagePrefix: s.PGBaseBackup.ImagePrefix, + CCPImageTag: s.PGBaseBackup.ImageTag, + BackupHost: s.PGBaseBackup.BackupHost, + BackupUser: s.PGBaseBackup.BackupUser, + BackupPass: s.PGBaseBackup.BackupPass, + BackupPort: s.PGBaseBackup.BackupPort, + PvcName: s.PGBaseBackup.BackupVolume, + Secret: s.PGBaseBackup.Secret, + SecurityContext: s.PGBaseBackup.SecurityContext, + Namespace: s.Namespace, + client: client, + } +} + +func (b BackBaseBackupJob) Run() { + contextLogger := log.WithFields(log.Fields{ + "namespace": b.Namespace, + "host": b.BackupHost, + "port": b.BackupPort}) + contextLogger.Info("Running pgBaseBackup Job") + + secret, err := b.client.GetSecret(b.Namespace, b.Secret) + if err != nil { + contextLogger.WithFields(log.Fields{ + "error": err}).Error("Failed to retreive secret for backup credentials") + return + } + + if err := b.setCredentials(secret.Data); err != nil { + contextLogger.WithFields(log.Fields{ + "secret": b.Secret}).Error("Failed to set username and/or password (does not exist in secret)") + } + + var doc2 bytes.Buffer + if err := BackupJobTemplate.Execute(&doc2, b); err != nil { + contextLogger.WithFields(log.Fields{ + "error": err}).Error("Failed to render job template") + return + } + + oldJob, err := b.client.GetJob(b.Namespace, b.Name) + if !(kerrors.IsNotFound(err)) { + if err := b.client.DeleteJob(b.Namespace, oldJob); err != nil { + contextLogger.WithFields(log.Fields{ + "error": err, + }).Error("Failed to delete backup job") + return + } + if err := b.client.IsJobDeleted(b.Namespace, oldJob); err != nil { + contextLogger.WithFields(log.Fields{ + "error": err, + }).Error("Failed waiting for backup job to delete") + return + } + } + + newJob := &v1batch.Job{} + if err := json.Unmarshal(doc2.Bytes(), newJob); err != nil { + contextLogger.WithFields(log.Fields{ + "error": err, + }).Error("Failed unmarshaling job template") + return + } + + job, err := b.client.CreateJob(b.Namespace, newJob) + if err != nil { + contextLogger.WithFields(log.Fields{ + "error": err, + }).Error("Failed creating backup job") + return + } + + if err := b.client.IsJobComplete(b.Namespace, job); err != nil { + contextLogger.WithFields(log.Fields{ + "error": err, + }).Error("Failed to run backup job") + return + } +} + +func (s *ScheduleTemplate) pvcString() string { + return fmt.Sprintf("\"persistentVolumeClaim\": { \"claimName\": \"%s\"}", s.BackupVolume) +} + +func (b *BackBaseBackupJob) setCredentials(data map[string][]byte) error { + if val, ok := data["username"]; ok { + b.BackupUser = string(val) + } else { + return fmt.Errorf("Username does not exist in secret") + } + + if val, ok := data["password"]; ok { + b.BackupPass = string(val) + } else { + return fmt.Errorf("Password does not exist in secret") + } + + return nil +} diff --git a/tools/scheduler/cron/types.go b/tools/scheduler/cron/types.go new file mode 100644 index 000000000..aa56751e7 --- /dev/null +++ b/tools/scheduler/cron/types.go @@ -0,0 +1,64 @@ +package cron + +import ( + "time" + + "github.com/crunchydata/crunchy-containers/tools/kubeapi" + cv2 "gopkg.in/robfig/cron.v2" +) + +var nsswrapper = []string{"env", + "LD_PRELOAD=/usr/lib64/libnss_wrapper.so", + "NSS_WRAPPER_PASSWD=/tmp/passwd", + "NSS_WRAPPER_GROUP=/tmp/group", +} + +type Cron struct { + entries map[string]cv2.EntryID + kubeClient *kubeapi.KubeAPI + CronClient *cv2.Cron + label string + namespace string + scheduleTypes []string +} + +type ScheduleTemplate struct { + Version string `json:"version"` + Name string `json:"name"` + Created time.Time `json:"created"` + Schedule string `json:"schedule"` + Namespace string `json:"namespace"` + Type string `json:"type"` + PGBackRest `json:"pgbackrest,omitempty"` + PGBaseBackup `json:"pgbasebackup,omitempty"` +} + +type PGBackRest struct { + Deployment string `json:"deployment"` + Label string `json:"label"` + Container string `json:"container"` + Type string `json:"type"` + Options []Options `json:"options"` +} + +type PGBaseBackup struct { + BackupHost string `json:"backupHost"` + BackupPass string `json:"backupPass"` + BackupPort string `json:"backupPort"` + BackupUser string `json:"backupUser"` + BackupVolume string `json:"backupVolume"` + ImagePrefix string `json:"imagePrefix"` + ImageTag string `json:"imageTag"` + Secret string `json:"secret"` + SecurityContext `json:"securityContext"` +} + +type Options struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` +} + +type SecurityContext struct { + FSGroup int `json:"fsGroup,omitempty"` + SupplementalGroups []int `json:"supplementalGroups,omitempty"` +} diff --git a/tools/scheduler/main.go b/tools/scheduler/main.go new file mode 100644 index 000000000..237386795 --- /dev/null +++ b/tools/scheduler/main.go @@ -0,0 +1,92 @@ +package main + +import ( + "os" + "os/signal" + "syscall" + "time" + + "github.com/crunchydata/crunchy-containers/tools/kubeapi" + "github.com/crunchydata/crunchy-containers/tools/scheduler/cron" + log "github.com/sirupsen/logrus" +) + +const ( + schedulerLabel = "crunchy-scheduler=true" + namespaceEnv = "NAMESPACE" + timeout = time.Second * 30 + inCluster = true +) + +var namespace string + +func init() { + log.SetLevel(log.InfoLevel) + log.SetFormatter(&log.TextFormatter{ + FullTimestamp: true, + TimestampFormat: "2006-01-02 15:04:05", + }) + + namespace = os.Getenv(namespaceEnv) + if namespace == "" { + log.WithFields(log.Fields{}).Fatalf("Failed to get namespace environment: %s", namespaceEnv) + } +} + +func main() { + log.Info("Starting Crunchy Scheduler") + kubeClient, err := kubeapi.New(timeout, inCluster) + if err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Fatal("Could not create a new instance of kubeclient") + } + + cron := cron.New(schedulerLabel, namespace, kubeClient) + cron.CronClient.Start() + + sigs := make(chan os.Signal, 1) + done := make(chan bool, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + go func() { + sig := <-sigs + log.WithFields(log.Fields{ + "signal": sig, + }).Warning("Received signal") + done <- true + }() + + go func() { + for { + if err := cron.AddJobs(); err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to add cron entries") + } + time.Sleep(time.Second * 10) + } + }() + + go func() { + for { + time.Sleep(time.Second * 10) + if err := cron.DeleteJobs(); err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to delete cron entries") + } + } + }() + + for { + select { + case <-done: + log.Warning("Shutting down scheduler") + cron.CronClient.Stop() + os.Exit(0) + default: + time.Sleep(time.Second * 1) + } + } +} diff --git a/tools/test-harness/kubeapi/job.go b/tools/test-harness/kubeapi/job.go deleted file mode 100644 index 20ec11ab5..000000000 --- a/tools/test-harness/kubeapi/job.go +++ /dev/null @@ -1,39 +0,0 @@ -package kubeapi - -import ( - "fmt" - "time" - - v1batch "k8s.io/api/batch/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// GetJob method returns a job data structure for a -// given job in a given namespace. -func (k *KubeAPI) GetJob(namespace, job string) (*v1batch.Job, error) { - return k.Client.BatchV1().Jobs(namespace).Get(job, metav1.GetOptions{}) -} - -// IsJobComplete method tests if a job has completed -// successfully. -func (k *KubeAPI) IsJobComplete(namespace string, job string) (bool, error) { - timeout := time.After(k.Timeout) - tick := time.Tick(500 * time.Millisecond) - for { - select { - case <-timeout: - return false, fmt.Errorf("timed out waiting for job to complete: %s", job) - case <-tick: - j, err := k.GetJob(namespace, job) - if err != nil { - return false, err - } - if j.Status.Failed != 0 { - return false, fmt.Errorf("job failed to run: %s", job) - } - if j.Status.Succeeded != 0 { - return true, nil - } - } - } -} diff --git a/tools/test-harness/setup_test.go b/tools/test-harness/setup_test.go index 9b8cb1798..ed3a0bcda 100644 --- a/tools/test-harness/setup_test.go +++ b/tools/test-harness/setup_test.go @@ -5,7 +5,7 @@ import ( "time" pg "github.com/crunchydata/crunchy-containers/tools/test-harness/data" - "github.com/crunchydata/crunchy-containers/tools/test-harness/kubeapi" + "github.com/crunchydata/crunchy-containers/tools/kubeapi" "github.com/crunchydata/crunchy-containers/tools/test-harness/runner" ) diff --git a/tools/test-harness/utils_test.go b/tools/test-harness/utils_test.go index b004ee4c1..8a8263ed7 100644 --- a/tools/test-harness/utils_test.go +++ b/tools/test-harness/utils_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/crunchydata/crunchy-containers/tools/test-harness/kubeapi" + "github.com/crunchydata/crunchy-containers/tools/kubeapi" "github.com/crunchydata/crunchy-containers/tools/test-harness/runner" ) From 1c1ea5758d1fc8971c1f70a7ae897ccdfe835e32 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Fri, 21 Sep 2018 13:07:20 -0400 Subject: [PATCH 035/179] Initial round of changes, more to come --- bin/backrest_restore/start.sh | 2 +- bin/backup/start-backupjob.sh | 1 - bin/common/common_lib.sh | 3 --- bin/common/uid_daemon.sh | 7 +++++++ bin/common/uid_postgres.sh | 7 +++++++ bin/grafana/start.sh | 1 - bin/pgadmin4/start-pgadmin4.sh | 1 - bin/postgres/start.sh | 2 +- bin/prometheus/start.sh | 1 - conf/.bash_profile | 6 +++--- conf/.bashrc | 6 +++--- rhel7/10/Dockerfile.backrest-restore.rhel7 | 12 +++++++++--- rhel7/10/Dockerfile.backup.rhel7 | 8 ++++++-- rhel7/10/Dockerfile.collect.rhel7 | 1 - rhel7/10/Dockerfile.pgadmin4.rhel7 | 13 ++++++++++--- rhel7/10/Dockerfile.pgbadger.rhel7 | 9 ++++++--- rhel7/10/Dockerfile.postgres.rhel7 | 12 ++++++++++-- rhel7/Dockerfile.grafana.rhel7 | 7 +++++-- rhel7/Dockerfile.prometheus.rhel7 | 7 +++++-- 19 files changed, 73 insertions(+), 33 deletions(-) create mode 100755 bin/common/uid_daemon.sh create mode 100755 bin/common/uid_postgres.sh diff --git a/bin/backrest_restore/start.sh b/bin/backrest_restore/start.sh index 56714d689..99da24b1c 100755 --- a/bin/backrest_restore/start.sh +++ b/bin/backrest_restore/start.sh @@ -17,7 +17,7 @@ set -e source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack +# ose_hack env_check_err "STANZA" diff --git a/bin/backup/start-backupjob.sh b/bin/backup/start-backupjob.sh index 85c2ac5c7..a49a3e44b 100755 --- a/bin/backup/start-backupjob.sh +++ b/bin/backup/start-backupjob.sh @@ -27,7 +27,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack BACKUPBASE=/pgdata/$BACKUP_HOST-backups if [ ! -d "$BACKUPBASE" ]; then diff --git a/bin/common/common_lib.sh b/bin/common/common_lib.sh index 7f4b6d0f8..5e9117dae 100755 --- a/bin/common/common_lib.sh +++ b/bin/common/common_lib.sh @@ -13,9 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -export LD_PRELOAD=/usr/lib64/libnss_wrapper.so -export NSS_WRAPPER_PASSWD=/tmp/passwd -export NSS_WRAPPER_GROUP=/tmp/group RED="\033[0;31m" GREEN="\033[0;32m" YELLOW="\033[0;33m" diff --git a/bin/common/uid_daemon.sh b/bin/common/uid_daemon.sh new file mode 100755 index 000000000..1ac55d614 --- /dev/null +++ b/bin/common/uid_daemon.sh @@ -0,0 +1,7 @@ +#!/bin/sh +if ! whoami &> /dev/null; then + if [ -w /etc/passwd ]; then + echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default} user:${HOME}:/bin/bash" >> /etc/passwd + fi +fi +exec "$@" diff --git a/bin/common/uid_postgres.sh b/bin/common/uid_postgres.sh new file mode 100755 index 000000000..1c0d24643 --- /dev/null +++ b/bin/common/uid_postgres.sh @@ -0,0 +1,7 @@ +#!/bin/sh +if ! whoami &> /dev/null; then + if [ -w /etc/passwd ]; then + echo "${USER_NAME:-postgres}:x:$(id -u):0:${USER_NAME:-postgres} user:${HOME}:/bin/bash" >> /etc/passwd + fi +fi +exec "$@" diff --git a/bin/grafana/start.sh b/bin/grafana/start.sh index c2d00092b..bd60324aa 100755 --- a/bin/grafana/start.sh +++ b/bin/grafana/start.sh @@ -15,7 +15,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack export PATH=$PATH:/opt/cpm/bin export GRAFANA_HOME=$(find /opt/cpm/bin/ -type d -name 'grafana-[1-9].*') diff --git a/bin/pgadmin4/start-pgadmin4.sh b/bin/pgadmin4/start-pgadmin4.sh index 5e2f83baa..2b7af0139 100755 --- a/bin/pgadmin4/start-pgadmin4.sh +++ b/bin/pgadmin4/start-pgadmin4.sh @@ -15,7 +15,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack export PATH=$PATH:/usr/pgsql-*/bin PGADMIN_DIR='/usr/lib/python2.7/site-packages/pgadmin4-web' diff --git a/bin/postgres/start.sh b/bin/postgres/start.sh index c48d15d7a..eb78bc55b 100755 --- a/bin/postgres/start.sh +++ b/bin/postgres/start.sh @@ -15,7 +15,7 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack +# ose_hack function trap_sigterm() { echo_warn "Signal trap triggered, beginning shutdown.." >> $PGDATA/trap.output diff --git a/bin/prometheus/start.sh b/bin/prometheus/start.sh index 23af59a39..3a710cf1d 100755 --- a/bin/prometheus/start.sh +++ b/bin/prometheus/start.sh @@ -17,7 +17,6 @@ set -e source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack CONF_DIR='/data' PROMETHEUS_PIDFILE=/tmp/prometheus.pid diff --git a/conf/.bash_profile b/conf/.bash_profile index 9605704fa..3ec19dc12 100644 --- a/conf/.bash_profile +++ b/conf/.bash_profile @@ -1,6 +1,6 @@ export PATH=/usr/pgsql-9.*/bin:/opt/cpm/bin:$PATH export LD_LIBRARY_PATH=/usr/pgsql-9.*/lib export PGHOST=/tmp -export LD_PRELOAD=/usr/lib64/libnss_wrapper.so -export NSS_WRAPPER_PASSWD=/tmp/passwd -export NSS_WRAPPER_GROUP=/tmp/group +#export LD_PRELOAD=/usr/lib64/libnss_wrapper.so +#export NSS_WRAPPER_PASSWD=/tmp/passwd +#export NSS_WRAPPER_GROUP=/tmp/group diff --git a/conf/.bashrc b/conf/.bashrc index 9605704fa..3ec19dc12 100644 --- a/conf/.bashrc +++ b/conf/.bashrc @@ -1,6 +1,6 @@ export PATH=/usr/pgsql-9.*/bin:/opt/cpm/bin:$PATH export LD_LIBRARY_PATH=/usr/pgsql-9.*/lib export PGHOST=/tmp -export LD_PRELOAD=/usr/lib64/libnss_wrapper.so -export NSS_WRAPPER_PASSWD=/tmp/passwd -export NSS_WRAPPER_GROUP=/tmp/group +#export LD_PRELOAD=/usr/lib64/libnss_wrapper.so +#export NSS_WRAPPER_PASSWD=/tmp/passwd +#export NSS_WRAPPER_GROUP=/tmp/group diff --git a/rhel7/10/Dockerfile.backrest-restore.rhel7 b/rhel7/10/Dockerfile.backrest-restore.rhel7 index c03874598..9334cc814 100644 --- a/rhel7/10/Dockerfile.backrest-restore.rhel7 +++ b/rhel7/10/Dockerfile.backrest-restore.rhel7 @@ -34,7 +34,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum -y install \ hostname \ gettext \ - nss_wrapper \ procps-ng \ && yum -y clean all @@ -51,10 +50,14 @@ ADD conf/.bash_profile /var/lib/pgsql/ RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgconf /backrestrepo \ /var/lib/pgsql /var/log/pgbackrest -RUN chown -R postgres:postgres /opt/cpm \ +RUN chgrp -R 0 /opt/cpm \ + /pgdata /pgconf /backrestrepo \ + /var/lib/pgsql /var/log/pgbackrest && \ + chmod -R g=u /opt/cpm \ /pgdata /pgconf /backrestrepo \ /var/lib/pgsql /var/log/pgbackrest + # volume pgconf to store pgbackrest.conf # volume backrestrepo for pgbackrest to restore from and log @@ -64,6 +67,9 @@ ADD bin/backrest_restore /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/backrest_restore /opt/cpm/conf -USER 26 +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_entrypoint.sh"] + +USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/10/Dockerfile.backup.rhel7 b/rhel7/10/Dockerfile.backup.rhel7 index 42d953db3..de67bb542 100644 --- a/rhel7/10/Dockerfile.backup.rhel7 +++ b/rhel7/10/Dockerfile.backup.rhel7 @@ -34,7 +34,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum install -y bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ unzip \ && yum -y install postgresql10 postgresql10-server \ @@ -44,10 +43,15 @@ RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata ADD bin/backup/ /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/backup/ /opt/cpm/conf -RUN chown -R postgres:postgres /opt/cpm /pgdata + +RUN chgrp -R 0 /opt/cpm /pgdata && \ + chmod -R g=u /opt/cpm /pgdata VOLUME ["/pgdata"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start-backupjob.sh"] diff --git a/rhel7/10/Dockerfile.collect.rhel7 b/rhel7/10/Dockerfile.collect.rhel7 index d28631cfc..f989a5501 100644 --- a/rhel7/10/Dockerfile.collect.rhel7 +++ b/rhel7/10/Dockerfile.collect.rhel7 @@ -39,7 +39,6 @@ RUN yum install -y epel-release \ gettext \ postgresql10 \ postgresql10-libs \ - nss_wrapper \ hostname \ && yum -y clean all diff --git a/rhel7/10/Dockerfile.pgadmin4.rhel7 b/rhel7/10/Dockerfile.pgadmin4.rhel7 index cbccab5d0..aed5c6cc8 100644 --- a/rhel7/10/Dockerfile.pgadmin4.rhel7 +++ b/rhel7/10/Dockerfile.pgadmin4.rhel7 @@ -39,7 +39,6 @@ RUN yum -y update \ gcc \ gettext \ hostname \ - nss_wrapper \ openssl \ procps-ng \ mod_wsgi mod_ssl \ @@ -58,8 +57,13 @@ ADD conf/pgadmin4/ /opt/cpm/conf RUN cp /opt/cpm/conf/httpd.conf /etc/httpd/conf/httpd.conf \ && rm /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/ssl.conf -RUN chown -R 2:0 /usr/lib/python2.7/site-packages/pgadmin4-web \ - && chown -R 2:0 /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd +# RUN chown -R 2:0 /usr/lib/python2.7/site-packages/pgadmin4-web \ +# && chown -R 2:0 /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd + +RUN chgrp -R 0 /usr/lib/python2.7/site-packages/pgadmin4-web \ + /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd && \ + chmod -R g=u /usr/lib/python2.7/site-packages/pgadmin4-web \ + /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd RUN ln -sf /var/lib/pgadmin/config_local.py /usr/lib/python2.7/site-packages/pgadmin4-web/config_local.py \ && ln -sf /var/lib/pgadmin/pgadmin.conf /etc/httpd/conf.d/pgadmin.conf @@ -68,6 +72,9 @@ EXPOSE 5050 VOLUME ["/var/lib/pgadmin", "/certs", "/run/httpd"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_daemon.sh"] + USER 2 CMD ["/opt/cpm/bin/start-pgadmin4.sh"] diff --git a/rhel7/10/Dockerfile.pgbadger.rhel7 b/rhel7/10/Dockerfile.pgbadger.rhel7 index 108d5e32f..caaebf568 100644 --- a/rhel7/10/Dockerfile.pgbadger.rhel7 +++ b/rhel7/10/Dockerfile.pgbadger.rhel7 @@ -37,11 +37,10 @@ RUN yum -y update \ && yum -y install \ gettext \ hostname \ - nss_wrapper \ pgbadger \ && yum clean all -y -RUN groupadd -g 26 postgres && useradd -g 26 -u 26 postgres +# RUN groupadd -g 26 postgres && useradd -g 26 -u 26 postgres RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /report @@ -49,13 +48,17 @@ ADD conf/pgbadger /opt/cpm/conf ADD bin/common /opt/cpm/bin ADD bin/pgbadger /opt/cpm/bin -RUN chown -R 26:26 /opt/cpm /report +RUN chgrp -R 0 /opt/cpm /report && \ + chmod -R g=u /opt/cpm /report # pgbadger port EXPOSE 10000 VOLUME ["/pgdata", "/report"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start-pgbadger.sh"] diff --git a/rhel7/10/Dockerfile.postgres.rhel7 b/rhel7/10/Dockerfile.postgres.rhel7 index eae8c5b6f..3ad9d5e9f 100644 --- a/rhel7/10/Dockerfile.postgres.rhel7 +++ b/rhel7/10/Dockerfile.postgres.rhel7 @@ -37,7 +37,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum -y install bind-utils \ gettext \ hostname \ - nss_wrapper \ openssh-server \ procps-ng \ rsync \ @@ -61,7 +60,12 @@ ADD conf/.bashrc / # set up cpm directory RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgwal /pgconf /backup /recover /backrestrepo /sshd -RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ +# RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ +# /pgdata /pgwal /pgconf /backup /recover /backrestrepo + +RUN chgrp -R 0 /opt/cpm /var/lib/pgsql \ + /pgdata /pgwal /pgconf /backup /recover /backrestrepo && \ + chmod -R g=u /opt/cpm /var/lib/pgsql \ /pgdata /pgwal /pgconf /backup /recover /backrestrepo # Link pgbackrest.conf to default location for convenience @@ -87,6 +91,10 @@ ADD bin/common /opt/cpm/bin ADD conf/postgres /opt/cpm/conf ADD tools/pgmonitor/exporter/postgres /opt/cpm/bin/pgmonitor +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + + USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/Dockerfile.grafana.rhel7 b/rhel7/Dockerfile.grafana.rhel7 index a6bade697..3313064af 100644 --- a/rhel7/Dockerfile.grafana.rhel7 +++ b/rhel7/Dockerfile.grafana.rhel7 @@ -26,7 +26,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ && yum clean all -y @@ -38,11 +37,15 @@ ADD bin/grafana /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/grafana /opt/cpm/conf -RUN chown -R 2:2 /opt/cpm /data +RUN chgrp -R 0 /opt/cpm /data && \ + chmod -R g=u /opt/cpm /data VOLUME ["/data", "/conf"] EXPOSE 3000 +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_daemon.sh"] + USER 2 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/Dockerfile.prometheus.rhel7 b/rhel7/Dockerfile.prometheus.rhel7 index 8999843b6..a2027a11c 100644 --- a/rhel7/Dockerfile.prometheus.rhel7 +++ b/rhel7/Dockerfile.prometheus.rhel7 @@ -27,7 +27,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ && yum clean all -y @@ -38,11 +37,15 @@ ADD bin/prometheus /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/prometheus /opt/cpm/conf -RUN chown -R 2:2 /opt/cpm /data /conf +RUN chgrp -R 0 /opt/cpm /data /conf && \ + chmod -R g=u /opt/cpm /data EXPOSE 9090 VOLUME ["/data", "/conf"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_daemon.sh"] + USER 2 CMD ["/opt/cpm/bin/start.sh"] From 833983c9024dedbb87aa17dbe0fd4d981a92ed8b Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Wed, 26 Sep 2018 09:29:15 -0400 Subject: [PATCH 036/179] additional updates for 718 --- bin/pgbouncer/start.sh | 4 ++-- bin/pgdump/start.sh | 5 ++--- bin/pgpool/startpgpool.sh | 1 - bin/pgrestore/start.sh | 2 +- rhel7/10/Dockerfile.pgbouncer.rhel7 | 7 +++++-- rhel7/10/Dockerfile.pgdump.rhel7 | 8 ++++++-- rhel7/10/Dockerfile.pgpool.rhel7 | 8 ++++++-- rhel7/10/Dockerfile.pgrestore.rhel7 | 7 +++++-- rhel7/10/Dockerfile.postgres-gis.rhel7 | 9 +++++++-- 9 files changed, 34 insertions(+), 17 deletions(-) diff --git a/bin/pgbouncer/start.sh b/bin/pgbouncer/start.sh index a5919a5e2..ab20ab71c 100755 --- a/bin/pgbouncer/start.sh +++ b/bin/pgbouncer/start.sh @@ -15,7 +15,7 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack + PGBOUNCER_PID=/tmp/pgbouncer-script.pid CONF_DIR=/pgconf @@ -70,7 +70,7 @@ fi export PGPASSFILE=/tmp/.pgpass echo_info "Starting pgBouncer.." -pgbouncer ${CONF_DIR?}/pgbouncer.ini -u daemon & +pgbouncer ${CONF_DIR?}/pgbouncer.ini -u default & echo $! > ${PGBOUNCER_PID?} wait diff --git a/bin/pgdump/start.sh b/bin/pgdump/start.sh index ed2b814fe..0e0e3ef0a 100755 --- a/bin/pgdump/start.sh +++ b/bin/pgdump/start.sh @@ -4,7 +4,6 @@ set -e source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack export PGROOT=$(find /usr/ -type d -name 'pgsql-*') export PGDUMP_PORT=${PGDUMP_PORT:-5432} @@ -25,14 +24,14 @@ cat >> "${PGPASSFILE?}" <<-EOF EOF chmod 600 ${PGPASSFILE?} -chown postgres:postgres ${PGPASSFILE?} +chgrp -R 0 ${PGPASSFILE?} pgisready ${PGDUMP_DB?} ${PGDUMP_HOST?} ${PGDUMP_PORT?} ${PGDUMP_USER?} PGDUMP_BASE=/pgdata/${PGDUMP_HOST?}-backups PGDUMP_PATH=${PGDUMP_BASE?}/$(date +%Y-%m-%d-%H-%M-%S) mkdir -p ${PGDUMP_PATH?} -chown postgres:postgres ${PGDUMP_PATH?} + output_opts="-f ${PGDUMP_PATH?}/${PGDUMP_FILENAME?}" diff --git a/bin/pgpool/startpgpool.sh b/bin/pgpool/startpgpool.sh index 79962cff1..e933d4edd 100755 --- a/bin/pgpool/startpgpool.sh +++ b/bin/pgpool/startpgpool.sh @@ -15,7 +15,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack CONF_DIR=/opt/cpm/conf CONFIGS=/tmp diff --git a/bin/pgrestore/start.sh b/bin/pgrestore/start.sh index c49c88a9d..ccb3e14b7 100755 --- a/bin/pgrestore/start.sh +++ b/bin/pgrestore/start.sh @@ -27,7 +27,7 @@ cat >> "${PGPASSFILE?}" <<-EOF EOF chmod 600 ${PGPASSFILE?} -chown postgres:postgres ${PGPASSFILE?} +# chown postgres:postgres ${PGPASSFILE?} set +e pgisready ${PGRESTORE_DB?} ${PGRESTORE_HOST?} ${PGRESTORE_PORT?} ${PGRESTORE_USER?} diff --git a/rhel7/10/Dockerfile.pgbouncer.rhel7 b/rhel7/10/Dockerfile.pgbouncer.rhel7 index e4b0bf55b..ee3dc9380 100644 --- a/rhel7/10/Dockerfile.pgbouncer.rhel7 +++ b/rhel7/10/Dockerfile.pgbouncer.rhel7 @@ -37,7 +37,6 @@ RUN yum -y update \ && yum -y install \ gettext \ hostname \ - nss_wrapper \ pgbouncer \ postgresql10 \ procps-ng \ @@ -49,12 +48,16 @@ ADD bin/pgbouncer /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/pgbouncer /opt/cpm/conf -RUN chown -R 2:2 /opt/cpm /pgconf +RUN chgrp -R 0 /opt/cpm /pgconf && \ + chmod -R g=u /opt/cpm /pgconf EXPOSE 6432 VOLUME ["/pgconf"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_daemon.sh"] + USER 2 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/10/Dockerfile.pgdump.rhel7 b/rhel7/10/Dockerfile.pgdump.rhel7 index 75c282ee6..160179150 100644 --- a/rhel7/10/Dockerfile.pgdump.rhel7 +++ b/rhel7/10/Dockerfile.pgdump.rhel7 @@ -34,7 +34,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum install -y bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ unzip \ && yum -y install postgresql10 postgresql10-server \ @@ -44,10 +43,15 @@ RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata ADD bin/pgdump/ /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/pgdump/ /opt/cpm/conf -RUN chown -R 26:26 /opt/cpm /pgdata + +RUN chgrp -R 0 /opt/cpm /pgdata && \ + chmod -R g=u /opt/cpm /pgdata VOLUME ["/pgdata"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/10/Dockerfile.pgpool.rhel7 b/rhel7/10/Dockerfile.pgpool.rhel7 index 9ebf11472..ceeb5d4c6 100644 --- a/rhel7/10/Dockerfile.pgpool.rhel7 +++ b/rhel7/10/Dockerfile.pgpool.rhel7 @@ -37,7 +37,6 @@ RUN yum -y update \ && yum -y install \ gettext \ hostname \ - nss_wrapper \ procps-ng \ && yum -y install \ postgresql10 \ @@ -54,7 +53,9 @@ ADD conf/pgpool /opt/cpm/conf RUN ln -sf /opt/cpm/conf/pool_hba.conf /etc/pgpool-II-10/pool_hba.conf \ && ln -sf /opt/cpm/conf/pgpool/pool_passwd /etc/pgpool-II-10/pool_passwd -RUN chown -R 2:2 /opt/cpm +RUN chgrp -R 0 /opt/cpm && \ + chmod -R g=u /opt/cpm + # open up the postgres port EXPOSE 5432 @@ -62,6 +63,9 @@ EXPOSE 5432 # add volumes to allow override of pgpool config files VOLUME ["/pgconf"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_daemon.sh"] + USER 2 CMD ["/opt/cpm/bin/startpgpool.sh"] diff --git a/rhel7/10/Dockerfile.pgrestore.rhel7 b/rhel7/10/Dockerfile.pgrestore.rhel7 index 6ea0858cf..f43250210 100644 --- a/rhel7/10/Dockerfile.pgrestore.rhel7 +++ b/rhel7/10/Dockerfile.pgrestore.rhel7 @@ -34,7 +34,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum install -y bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ unzip \ file \ @@ -45,10 +44,14 @@ RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata ADD bin/pgrestore/ /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/pgrestore/ /opt/cpm/conf -RUN chown -R 26:26 /opt/cpm /pgdata +RUN chgrp -R 0 /opt/cpm /pgdata && \ + chmod -R g=u /opt/cpm /pgdata VOLUME ["/pgdata"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/10/Dockerfile.postgres-gis.rhel7 b/rhel7/10/Dockerfile.postgres-gis.rhel7 index eb02f6652..2e6a3e194 100644 --- a/rhel7/10/Dockerfile.postgres-gis.rhel7 +++ b/rhel7/10/Dockerfile.postgres-gis.rhel7 @@ -38,7 +38,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. gettext \ hostname \ R-core libRmath texinfo-tex texlive-epsf \ - nss_wrapper \ openssh-server \ procps-ng \ rsync \ @@ -63,8 +62,11 @@ ADD conf/.bashrc / # set up cpm directory RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgwal /pgconf /backup /recover /backrestrepo /sshd -RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ +RUN chgrp -R 0 /opt/cpm /var/lib/pgsql \ + /pgdata /pgwal /pgconf /backup /recover /backrestrepo && \ + chmod -R g=u /opt/cpm /var/lib/pgsql \ /pgdata /pgwal /pgconf /backup /recover /backrestrepo + # Link pgbackrest.conf to default location for convenience # Remove nologin file to prevent sshd from being blocked @@ -90,6 +92,9 @@ ADD bin/common /opt/cpm/bin ADD conf/postgres /opt/cpm/conf ADD tools/pgmonitor/exporter/postgres /opt/cpm/bin/pgmonitor +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start.sh"] From 0fdb37c4e86efccce31901769ff98820629e517c Mon Sep 17 00:00:00 2001 From: Paul Cahoon Date: Fri, 28 Sep 2018 09:43:09 -0400 Subject: [PATCH 037/179] key name change --- rhel7/11/Dockerfile.backrest-restore.rhel7 | 4 ++-- rhel7/11/Dockerfile.backup.rhel7 | 4 ++-- rhel7/11/Dockerfile.collect.rhel7 | 4 ++-- rhel7/11/Dockerfile.pgadmin4.rhel7 | 4 ++-- rhel7/11/Dockerfile.pgbadger.rhel7 | 4 ++-- rhel7/11/Dockerfile.pgbouncer.rhel7 | 4 ++-- rhel7/11/Dockerfile.pgdump.rhel7 | 4 ++-- rhel7/11/Dockerfile.pgpool.rhel7 | 4 ++-- rhel7/11/Dockerfile.pgrestore.rhel7 | 4 ++-- rhel7/11/Dockerfile.postgres-gis.rhel7 | 4 ++-- rhel7/11/Dockerfile.postgres.rhel7 | 4 ++-- rhel7/11/Dockerfile.upgrade.rhel7 | 4 ++-- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/rhel7/11/Dockerfile.backrest-restore.rhel7 b/rhel7/11/Dockerfile.backrest-restore.rhel7 index 8a945874e..39d9f4a73 100644 --- a/rhel7/11/Dockerfile.backrest-restore.rhel7 +++ b/rhel7/11/Dockerfile.backrest-restore.rhel7 @@ -26,9 +26,9 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ && yum -y update && yum -y install \ diff --git a/rhel7/11/Dockerfile.backup.rhel7 b/rhel7/11/Dockerfile.backup.rhel7 index 063b6487b..8258884d8 100644 --- a/rhel7/11/Dockerfile.backup.rhel7 +++ b/rhel7/11/Dockerfile.backup.rhel7 @@ -26,9 +26,9 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ && yum -y update && yum install -y bind-utils \ diff --git a/rhel7/11/Dockerfile.collect.rhel7 b/rhel7/11/Dockerfile.collect.rhel7 index 1aed9d60e..26767139b 100644 --- a/rhel7/11/Dockerfile.collect.rhel7 +++ b/rhel7/11/Dockerfile.collect.rhel7 @@ -26,9 +26,9 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm diff --git a/rhel7/11/Dockerfile.pgadmin4.rhel7 b/rhel7/11/Dockerfile.pgadmin4.rhel7 index ab9894366..5cb1cd021 100644 --- a/rhel7/11/Dockerfile.pgadmin4.rhel7 +++ b/rhel7/11/Dockerfile.pgadmin4.rhel7 @@ -26,9 +26,9 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm diff --git a/rhel7/11/Dockerfile.pgbadger.rhel7 b/rhel7/11/Dockerfile.pgbadger.rhel7 index 5ebbc0a95..c0235ba54 100644 --- a/rhel7/11/Dockerfile.pgbadger.rhel7 +++ b/rhel7/11/Dockerfile.pgbadger.rhel7 @@ -26,9 +26,9 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm diff --git a/rhel7/11/Dockerfile.pgbouncer.rhel7 b/rhel7/11/Dockerfile.pgbouncer.rhel7 index 616a95b2b..84c6593e8 100644 --- a/rhel7/11/Dockerfile.pgbouncer.rhel7 +++ b/rhel7/11/Dockerfile.pgbouncer.rhel7 @@ -26,9 +26,9 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm diff --git a/rhel7/11/Dockerfile.pgdump.rhel7 b/rhel7/11/Dockerfile.pgdump.rhel7 index 878a3b3e7..741b262cc 100644 --- a/rhel7/11/Dockerfile.pgdump.rhel7 +++ b/rhel7/11/Dockerfile.pgdump.rhel7 @@ -26,9 +26,9 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ && yum -y update && yum install -y bind-utils \ diff --git a/rhel7/11/Dockerfile.pgpool.rhel7 b/rhel7/11/Dockerfile.pgpool.rhel7 index 5ec98656e..8a2fff7c9 100644 --- a/rhel7/11/Dockerfile.pgpool.rhel7 +++ b/rhel7/11/Dockerfile.pgpool.rhel7 @@ -26,9 +26,9 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm diff --git a/rhel7/11/Dockerfile.pgrestore.rhel7 b/rhel7/11/Dockerfile.pgrestore.rhel7 index 688de714f..84feece5f 100644 --- a/rhel7/11/Dockerfile.pgrestore.rhel7 +++ b/rhel7/11/Dockerfile.pgrestore.rhel7 @@ -26,9 +26,9 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ && yum -y update && yum install -y bind-utils \ diff --git a/rhel7/11/Dockerfile.postgres-gis.rhel7 b/rhel7/11/Dockerfile.postgres-gis.rhel7 index 6e0432b30..92fcfaf9b 100644 --- a/rhel7/11/Dockerfile.postgres-gis.rhel7 +++ b/rhel7/11/Dockerfile.postgres-gis.rhel7 @@ -29,9 +29,9 @@ ENV PGVERSION="11" #RUN sed -i '/nodocs/d' /etc/yum.conf # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ && yum -y update && yum --enablerepo=epel --enablerepo="rhel-7-server-optional-rpms" -y install bind-utils \ diff --git a/rhel7/11/Dockerfile.postgres.rhel7 b/rhel7/11/Dockerfile.postgres.rhel7 index ca8c243da..e31e81c97 100644 --- a/rhel7/11/Dockerfile.postgres.rhel7 +++ b/rhel7/11/Dockerfile.postgres.rhel7 @@ -29,9 +29,9 @@ ENV PGVERSION="11" #RUN sed -i '/nodocs/d' /etc/yum.conf # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ && yum -y update && yum -y install bind-utils \ diff --git a/rhel7/11/Dockerfile.upgrade.rhel7 b/rhel7/11/Dockerfile.upgrade.rhel7 index 7c016d231..54c3357a3 100644 --- a/rhel7/11/Dockerfile.upgrade.rhel7 +++ b/rhel7/11/Dockerfile.upgrade.rhel7 @@ -26,12 +26,12 @@ COPY conf/licenses /licenses ENV PGVERSION="11" # Crunchy Postgres repo -ADD conf/CRUNCHY-GPG-KEY.public / +ADD conf/RPM-GPG-KEY-crunchydata / ADD conf/crunchypg11.repo /etc/yum.repos.d/ ADD conf/crunchypg10.repo /etc/yum.repos.d/ ADD conf/crunchypg96.repo /etc/yum.repos.d/ ADD conf/crunchypg95.repo /etc/yum.repos.d/ -RUN rpm --import CRUNCHY-GPG-KEY.public +RUN rpm --import RPM-GPG-KEY-crunchydata RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ && yum -y update && yum -y update glibc-common \ From ecbebbf124b39f80243d292e7124facdd444abdc Mon Sep 17 00:00:00 2001 From: jmccormick2001 Date: Fri, 28 Sep 2018 13:39:11 -0500 Subject: [PATCH 038/179] add set -e to crunchy-backup script to be consistent with other scripts and handle error condition reporting --- bin/backup/start-backupjob.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/backup/start-backupjob.sh b/bin/backup/start-backupjob.sh index 85c2ac5c7..4f170af71 100755 --- a/bin/backup/start-backupjob.sh +++ b/bin/backup/start-backupjob.sh @@ -25,6 +25,8 @@ # $BACKUP_PASS pg user password we are connecting with # $BACKUP_PORT pg port we are connecting to +set -e + source /opt/cpm/bin/common_lib.sh enable_debugging ose_hack From f3d80e8f0c1f3210e295afd3a8314936014c94f1 Mon Sep 17 00:00:00 2001 From: jmccormick2001 Date: Mon, 1 Oct 2018 08:29:05 -0500 Subject: [PATCH 039/179] update openshift and docker install docs --- .../installation/environment-setup.adoc | 58 +------------------ 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/hugo/content/installation/environment-setup.adoc b/hugo/content/installation/environment-setup.adoc index cb63477cd..d4979f348 100644 --- a/hugo/content/installation/environment-setup.adoc +++ b/hugo/content/installation/environment-setup.adoc @@ -183,74 +183,18 @@ to run Docker commands from your user account. su - someuser .... -You can ensure your *someuser* account is added correctly by running the following -command and ensuring `docker` appears as one of the results: -.... -groups -.... - -Before you start Docker, you might consider configuring Docker storage: -This is described if you run: -.... -man docker-storage-setup -.... - -Follow the instructions available link:https://docs.openshift.com/container-platform/3.4/install_config/install/host_preparation.html#configuring-docker-storage[on the main OpenShift documentation page] -to configure Docker storage appropriately. - -These steps are illustrative of a typical process for setting up Docker storage. You will need to run these commands as root. - -First, add an extra virtual hard disk to your virtual machine (see link:http://catlingmindswipe.blogspot.com/2012/02/how-to-create-new-virtual-disks-in.html[this blog post] for tips on how to do so). - -Run this command to format the drive, where `/dev/sd?` is the new hard drive that was added: - -.... -fdisk /dev/sd? -.... - -Next, create a volume group on the new drive partition within the `fdisk` utility: - -.... -vgcreate docker-vg /dev/sd? -.... - -Then, you'll need to edit the `docker-storage-setup` configuration file in order to override default options. Add these two lines to `/etc/sysconfig/docker-storage-setup`: - -.... -DEVS=/dev/sd? -VG=docker-vg -.... - -Finally, run the command `docker-storage-setup` to use that new volume group. The results should state that the physical volume `/dev/sd?` and the volume group `docker-vg` have both been successfully created. - Next, we enable and start up Docker: .... sudo systemctl enable docker.service sudo systemctl start docker.service .... -Verify that Docker version 1.12.6 was installed, as per the OpenShift 3.6 -link:https://docs.openshift.com/container-platform/3.6/install_config/install/host_preparation.html#installing-docker[requirements.] - -.... -docker version -.... - === OpenShift See the OpenShift installation guide for details on how to install OpenShift Enterprise on your host. The main instructions are here: -https://docs.openshift.com/container-platform/3.6/install_config/install/quick_install.html - -NOTE: If you install OpenShift Enterprise on a server with less than `16GB` memory and `40GB` -of disk, the following Ansible variables need to be added to `~/.config/openshift/installer.cfg.yml` -prior to installation: - -.... -openshift_check_min_host_disk_gb: '10' # min 10gb disk -openshift_check_min_host_memory_gb: '3' # min 3gb memory -.... +https://docs.openshift.com/container-platform/3.10/install/index.html === Kubernetes From 75a3cd5a7f660452313de3df99e55ea7bdc041f2 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Mon, 1 Oct 2018 14:52:29 -0400 Subject: [PATCH 040/179] Additional changes for pg10 in 718 --- bin/backrest_restore/start.sh | 1 - bin/collect/start.sh | 1 - bin/dba/create-backup-job.sh | 1 - bin/dba/create-vac-job.sh | 2 +- bin/dba/start-dba.sh | 2 +- bin/pgbadger/badger-generate.sh | 3 +-- bin/pgbadger/start-pgbadger.sh | 1 - bin/pgrestore/start.sh | 2 +- bin/postgres/custom-configs.sh | 5 ++--- bin/postgres/liveness.sh | 2 -- bin/postgres/pgbouncer.sh | 1 - bin/postgres/readiness.sh | 2 -- bin/postgres/setenv.sh | 12 ++++++------ bin/postgres/start.sh | 3 +-- bin/sample-app/start.sh | 1 - bin/setenv.sh | 1 - bin/upgrade/start.sh | 1 - bin/vacuum/start-vacuum.sh | 3 +-- rhel7/10/Dockerfile.collect.rhel7 | 6 +++++- rhel7/10/Dockerfile.pgbadger.rhel7 | 6 ++++-- rhel7/10/Dockerfile.postgres.rhel7 | 2 +- rhel7/10/Dockerfile.upgrade.rhel7 | 8 ++++++-- rhel7/Dockerfile.dba.rhel7 | 7 +++++-- rhel7/Dockerfile.vacuum.rhel7 | 7 +++++-- 24 files changed, 40 insertions(+), 40 deletions(-) diff --git a/bin/backrest_restore/start.sh b/bin/backrest_restore/start.sh index 99da24b1c..9df862a0d 100755 --- a/bin/backrest_restore/start.sh +++ b/bin/backrest_restore/start.sh @@ -17,7 +17,6 @@ set -e source /opt/cpm/bin/common_lib.sh enable_debugging -# ose_hack env_check_err "STANZA" diff --git a/bin/collect/start.sh b/bin/collect/start.sh index 75c923a5f..279bace23 100755 --- a/bin/collect/start.sh +++ b/bin/collect/start.sh @@ -15,7 +15,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack export PG_EXP_HOME=$(find /opt/cpm/bin/ -type d -name 'postgres_exporter*') export NODE_EXP_HOME=$(find /opt/cpm/bin/ -type d -name 'node_exporter*') diff --git a/bin/dba/create-backup-job.sh b/bin/dba/create-backup-job.sh index 6609e0c69..a25d78b7e 100755 --- a/bin/dba/create-backup-job.sh +++ b/bin/dba/create-backup-job.sh @@ -15,7 +15,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack BACKUP_TEMPLATE=${1?} BACKUP_PVC_TEMPLATE=${2?} diff --git a/bin/dba/create-vac-job.sh b/bin/dba/create-vac-job.sh index 47af13b48..a38f396be 100755 --- a/bin/dba/create-vac-job.sh +++ b/bin/dba/create-vac-job.sh @@ -15,7 +15,7 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack + TEMP_FILE=${1?} JOB_HOST=${2?} diff --git a/bin/dba/start-dba.sh b/bin/dba/start-dba.sh index f324d0d20..af9a7bd4a 100755 --- a/bin/dba/start-dba.sh +++ b/bin/dba/start-dba.sh @@ -15,7 +15,7 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack + export PATH=$PATH:/opt/cpm/bin export TOKEN="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" diff --git a/bin/pgbadger/badger-generate.sh b/bin/pgbadger/badger-generate.sh index 8a69b60b5..1013a9bc1 100755 --- a/bin/pgbadger/badger-generate.sh +++ b/bin/pgbadger/badger-generate.sh @@ -15,7 +15,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack export BADGER_CUSTOM_OPTS=${BADGER_CUSTOM_OPTS:-} TARGET=${HOSTNAME?} @@ -26,4 +25,4 @@ then fi echo_info "Creating pgBadger output.." -/bin/pgbadger ${BADGER_CUSTOM_OPTS} -o /report/index.html /pgdata/${TARGET?}/pg_log/*.log +/bin/pgbadger -f stderr ${BADGER_CUSTOM_OPTS} -o /report/index.html /pgdata/${TARGET?}/pg_log/*.log diff --git a/bin/pgbadger/start-pgbadger.sh b/bin/pgbadger/start-pgbadger.sh index e1e2e372d..d761b10e4 100755 --- a/bin/pgbadger/start-pgbadger.sh +++ b/bin/pgbadger/start-pgbadger.sh @@ -15,7 +15,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack export PATH=$PATH:/opt/cpm/bin export PIDFILE=/tmp/badgerserver.pid diff --git a/bin/pgrestore/start.sh b/bin/pgrestore/start.sh index ccb3e14b7..2b752ceee 100755 --- a/bin/pgrestore/start.sh +++ b/bin/pgrestore/start.sh @@ -4,7 +4,7 @@ set -e source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack + export PGROOT=$(find /usr/ -type d -name 'pgsql-*') export PGPASSFILE=/tmp/pgpass diff --git a/bin/postgres/custom-configs.sh b/bin/postgres/custom-configs.sh index d3d4ffdd6..f66998854 100755 --- a/bin/postgres/custom-configs.sh +++ b/bin/postgres/custom-configs.sh @@ -2,7 +2,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack function custom_config() { src=${1?} @@ -13,8 +12,8 @@ function custom_config() { then echo_info "Custom ${src?} detected. Applying custom configuration.." cp ${src?} ${dest?} - chown ${owner?} ${dest?} - chmod ${mode?} ${dest?} + # chown ${owner?} ${dest?} + # chmod ${mode?} ${dest?} fi } diff --git a/bin/postgres/liveness.sh b/bin/postgres/liveness.sh index afff2214c..659560cc1 100755 --- a/bin/postgres/liveness.sh +++ b/bin/postgres/liveness.sh @@ -18,6 +18,4 @@ enable_debugging source /opt/cpm/bin/setenv.sh -ose_hack - $PGROOT/bin/pg_isready -h $HOSTNAME --dbname=postgres --username=$PG_USER diff --git a/bin/postgres/pgbouncer.sh b/bin/postgres/pgbouncer.sh index 6b25abf52..57edb6722 100755 --- a/bin/postgres/pgbouncer.sh +++ b/bin/postgres/pgbouncer.sh @@ -3,7 +3,6 @@ source /opt/cpm/bin/common_lib.sh export PGHOST="${PGHOST:-/tmp}" enable_debugging -ose_hack pgisready 'postgres' ${PGHOST?} 5432 'postgres' diff --git a/bin/postgres/readiness.sh b/bin/postgres/readiness.sh index a8ee57233..c84107362 100755 --- a/bin/postgres/readiness.sh +++ b/bin/postgres/readiness.sh @@ -17,6 +17,4 @@ source /opt/cpm/bin/common_lib.sh enable_debugging source /opt/cpm/bin/setenv.sh -ose_hack - $PGROOT/bin/psql -f /opt/cpm/bin/readiness.sql -U $PG_USER postgres diff --git a/bin/postgres/setenv.sh b/bin/postgres/setenv.sh index 03c859c65..e04bf1a34 100755 --- a/bin/postgres/setenv.sh +++ b/bin/postgres/setenv.sh @@ -32,10 +32,10 @@ fi export PATH=/opt/cpm/bin:$PGROOT/bin:$PATH export LD_LIBRARY_PATH=$PGROOT/lib -if [[ -d ${PGDATA} ]]; then - chown postgres:postgres ${PGDATA?} -fi +# if [[ -d ${PGDATA} ]]; then +# chown postgres:postgres ${PGDATA?} +# fi -if [[ -d ${PGWAL} ]]; then - chown postgres:postgres ${PGWAL?} -fi +# if [[ -d ${PGWAL} ]]; then +# chown postgres:postgres ${PGWAL?} +# fi diff --git a/bin/postgres/start.sh b/bin/postgres/start.sh index eb78bc55b..9e2222c90 100755 --- a/bin/postgres/start.sh +++ b/bin/postgres/start.sh @@ -15,7 +15,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -# ose_hack function trap_sigterm() { echo_warn "Signal trap triggered, beginning shutdown.." >> $PGDATA/trap.output @@ -112,7 +111,7 @@ function initdb_logic() { if [ $XLOGDIR = "true" ]; then echo_info "XLOGDIR found." mkdir $PGWAL - chown postgres:postgres $PGWAL + if [ -d "$PGWAL" ]; then cmd+=" -X "$PGWAL else diff --git a/bin/sample-app/start.sh b/bin/sample-app/start.sh index 5328aeff3..7d9ba28f0 100644 --- a/bin/sample-app/start.sh +++ b/bin/sample-app/start.sh @@ -15,7 +15,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack export PATH=$PATH:/opt/cpm/bin export PGROOT=$(find /usr/ -type d -name 'pgsql-*') diff --git a/bin/setenv.sh b/bin/setenv.sh index e0e769a82..7f965e554 100755 --- a/bin/setenv.sh +++ b/bin/setenv.sh @@ -16,7 +16,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack export PGROOT=$(find /usr/ -type d -name 'pgsql-*') diff --git a/bin/upgrade/start.sh b/bin/upgrade/start.sh index 361b9674d..6a9eab9ca 100755 --- a/bin/upgrade/start.sh +++ b/bin/upgrade/start.sh @@ -27,7 +27,6 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack function trap_sigterm() { echo_warn "Signal trap triggered, beginning shutdown.." >> $PGDATA/trap.output diff --git a/bin/vacuum/start-vacuum.sh b/bin/vacuum/start-vacuum.sh index c5ffc01fe..bb9424d00 100755 --- a/bin/vacuum/start-vacuum.sh +++ b/bin/vacuum/start-vacuum.sh @@ -15,11 +15,10 @@ source /opt/cpm/bin/common_lib.sh enable_debugging -ose_hack env_check_err "PG_USER" env_check_err "PG_PASSWORD" env_check_err "JOB_HOST" -echo_info "Starting vacuum job.." +echo_info "Starting vacuum job..." /opt/cpm/bin/vacuum diff --git a/rhel7/10/Dockerfile.collect.rhel7 b/rhel7/10/Dockerfile.collect.rhel7 index f989a5501..4b361ebdb 100644 --- a/rhel7/10/Dockerfile.collect.rhel7 +++ b/rhel7/10/Dockerfile.collect.rhel7 @@ -51,7 +51,8 @@ ADD bin/collect /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/collect /opt/cpm/conf -RUN chown -R 2:2 /opt/cpm/bin /opt/cpm/conf +RUN chgrp -R 0 /opt/cpm/bin /opt/cpm/conf && \ + chmod -R g=u /opt/cpm/bin/ opt/cpm/conf VOLUME ["/conf"] @@ -60,6 +61,9 @@ EXPOSE 9187 # node exporter EXPOSE 9100 +RUN chmod g=u /etc/passwd +ENTRYPOINT ["/opt/cpm/bin/uid_postgres.sh"] + USER 2 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/10/Dockerfile.pgbadger.rhel7 b/rhel7/10/Dockerfile.pgbadger.rhel7 index caaebf568..b3c7ebf2e 100644 --- a/rhel7/10/Dockerfile.pgbadger.rhel7 +++ b/rhel7/10/Dockerfile.pgbadger.rhel7 @@ -48,8 +48,8 @@ ADD conf/pgbadger /opt/cpm/conf ADD bin/common /opt/cpm/bin ADD bin/pgbadger /opt/cpm/bin -RUN chgrp -R 0 /opt/cpm /report && \ - chmod -R g=u /opt/cpm /report +RUN chgrp -R 0 /opt/cpm /report /bin && \ + chmod -R g=u /opt/cpm /report /bin # pgbadger port EXPOSE 10000 @@ -59,6 +59,8 @@ VOLUME ["/pgdata", "/report"] RUN chmod g=u /etc/passwd ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] +RUN chgrp -R 0 /pgdata && chmod -R g=u /pgdata + USER 26 CMD ["/opt/cpm/bin/start-pgbadger.sh"] diff --git a/rhel7/10/Dockerfile.postgres.rhel7 b/rhel7/10/Dockerfile.postgres.rhel7 index 3ad9d5e9f..f364f868c 100644 --- a/rhel7/10/Dockerfile.postgres.rhel7 +++ b/rhel7/10/Dockerfile.postgres.rhel7 @@ -92,7 +92,7 @@ ADD conf/postgres /opt/cpm/conf ADD tools/pgmonitor/exporter/postgres /opt/cpm/bin/pgmonitor RUN chmod g=u /etc/passwd -ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] +ENTRYPOINT ["/opt/cpm/bin/uid_postgres.sh"] USER 26 diff --git a/rhel7/10/Dockerfile.upgrade.rhel7 b/rhel7/10/Dockerfile.upgrade.rhel7 index d831f61f3..ca865a930 100644 --- a/rhel7/10/Dockerfile.upgrade.rhel7 +++ b/rhel7/10/Dockerfile.upgrade.rhel7 @@ -37,7 +37,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum install -y bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ unzip \ && yum -y install \ @@ -50,10 +49,15 @@ RUN mkdir -p /opt/cpm/bin /pgolddata /pgnewdata /opt/cpm/conf ADD bin/upgrade/ /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/upgrade/ /opt/cpm/conf -RUN chown -R postgres:postgres /opt/cpm /pgolddata /pgnewdata + +RUN chgrp -R 0 /opt/cpm /pgolddata /pgnewdata && \ + chmod -R g=u /opt/cpm /pgolddata /pgnewdata VOLUME /pgolddata /pgnewdata +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/Dockerfile.dba.rhel7 b/rhel7/Dockerfile.dba.rhel7 index c15c2ab1b..960f56573 100644 --- a/rhel7/Dockerfile.dba.rhel7 +++ b/rhel7/Dockerfile.dba.rhel7 @@ -30,7 +30,6 @@ RUN yum -y update \ gettext \ hostname \ iproute \ - nss_wrapper \ procps-ng \ psmisc \ && yum clean all -y @@ -41,7 +40,11 @@ ADD bin/dba /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/dba /opt/cpm/conf -RUN chown -R 2:2 /opt/cpm +RUN chgrp -R 0 /opt/cpm && \ + chmod -R g=u /opt/cpm + +RUN chmod g=u /etc/passwd +ENTRYPOINT ["/opt/cpm/bin/uid_daemon.sh"] USER 2 diff --git a/rhel7/Dockerfile.vacuum.rhel7 b/rhel7/Dockerfile.vacuum.rhel7 index 6ec2a0f31..f0319a056 100644 --- a/rhel7/Dockerfile.vacuum.rhel7 +++ b/rhel7/Dockerfile.vacuum.rhel7 @@ -29,7 +29,6 @@ RUN yum -y update \ gettext \ hostname \ iproute \ - nss_wrapper \ procps-ng \ && yum clean all -y @@ -39,7 +38,11 @@ ADD bin/vacuum /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/vacuum /opt/cpm/conf -RUN chown -R 2:2 /opt/cpm +RUN chgrp -R 0 /opt/cpm && \ + chmod -R g=u /opt/cpm + +RUN chmod g=u /etc/passwd +ENTRYPOINT ["/opt/cpm/bin/uid_daemon.sh"] USER 2 From 64a176d9fe87b14d0a3254bcc5601c36624f79c0 Mon Sep 17 00:00:00 2001 From: ScalaEnthusiast Date: Tue, 2 Oct 2018 12:56:29 -0400 Subject: [PATCH 041/179] update pg11 docker files; remove comments from pg10 files --- conf/.gitignore | 1 + rhel7/10/Dockerfile.pgadmin4.rhel7 | 2 -- rhel7/10/Dockerfile.pgbadger.rhel7 | 1 - rhel7/10/Dockerfile.postgres.rhel7 | 2 -- rhel7/11/Dockerfile.backrest-restore.rhel7 | 12 +++++++++--- rhel7/11/Dockerfile.backup.rhel7 | 8 ++++++-- rhel7/11/Dockerfile.collect.rhel7 | 7 +++++-- rhel7/11/Dockerfile.pgadmin4.rhel7 | 11 ++++++++--- rhel7/11/Dockerfile.pgbadger.rhel7 | 10 +++++++--- rhel7/11/Dockerfile.pgbouncer.rhel7 | 7 +++++-- rhel7/11/Dockerfile.pgdump.rhel7 | 8 ++++++-- rhel7/11/Dockerfile.pgpool.rhel7 | 12 ++++++++---- rhel7/11/Dockerfile.pgrestore.rhel7 | 7 +++++-- rhel7/11/Dockerfile.postgres-gis.rhel7 | 9 +++++++-- rhel7/11/Dockerfile.postgres.rhel7 | 10 ++++++++-- rhel7/11/Dockerfile.upgrade.rhel7 | 8 ++++++-- 16 files changed, 81 insertions(+), 34 deletions(-) diff --git a/conf/.gitignore b/conf/.gitignore index 4d42b5ee7..b76e1656c 100644 --- a/conf/.gitignore +++ b/conf/.gitignore @@ -1,2 +1,3 @@ crunchypg*.repo CRUNCHY*.public +RPM-GPG-KEY-* diff --git a/rhel7/10/Dockerfile.pgadmin4.rhel7 b/rhel7/10/Dockerfile.pgadmin4.rhel7 index aed5c6cc8..fb1589224 100644 --- a/rhel7/10/Dockerfile.pgadmin4.rhel7 +++ b/rhel7/10/Dockerfile.pgadmin4.rhel7 @@ -57,8 +57,6 @@ ADD conf/pgadmin4/ /opt/cpm/conf RUN cp /opt/cpm/conf/httpd.conf /etc/httpd/conf/httpd.conf \ && rm /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/ssl.conf -# RUN chown -R 2:0 /usr/lib/python2.7/site-packages/pgadmin4-web \ -# && chown -R 2:0 /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd RUN chgrp -R 0 /usr/lib/python2.7/site-packages/pgadmin4-web \ /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd && \ diff --git a/rhel7/10/Dockerfile.pgbadger.rhel7 b/rhel7/10/Dockerfile.pgbadger.rhel7 index b3c7ebf2e..471e0876d 100644 --- a/rhel7/10/Dockerfile.pgbadger.rhel7 +++ b/rhel7/10/Dockerfile.pgbadger.rhel7 @@ -40,7 +40,6 @@ RUN yum -y update \ pgbadger \ && yum clean all -y -# RUN groupadd -g 26 postgres && useradd -g 26 -u 26 postgres RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /report diff --git a/rhel7/10/Dockerfile.postgres.rhel7 b/rhel7/10/Dockerfile.postgres.rhel7 index f364f868c..4b52e3a57 100644 --- a/rhel7/10/Dockerfile.postgres.rhel7 +++ b/rhel7/10/Dockerfile.postgres.rhel7 @@ -60,8 +60,6 @@ ADD conf/.bashrc / # set up cpm directory RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgwal /pgconf /backup /recover /backrestrepo /sshd -# RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ -# /pgdata /pgwal /pgconf /backup /recover /backrestrepo RUN chgrp -R 0 /opt/cpm /var/lib/pgsql \ /pgdata /pgwal /pgconf /backup /recover /backrestrepo && \ diff --git a/rhel7/11/Dockerfile.backrest-restore.rhel7 b/rhel7/11/Dockerfile.backrest-restore.rhel7 index 39d9f4a73..008abeda5 100644 --- a/rhel7/11/Dockerfile.backrest-restore.rhel7 +++ b/rhel7/11/Dockerfile.backrest-restore.rhel7 @@ -34,7 +34,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum -y install \ hostname \ gettext \ - nss_wrapper \ procps-ng \ && yum -y clean all @@ -51,10 +50,14 @@ ADD conf/.bash_profile /var/lib/pgsql/ RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgconf /backrestrepo \ /var/lib/pgsql /var/log/pgbackrest -RUN chown -R postgres:postgres /opt/cpm \ +RUN chgrp -R 0 /opt/cpm \ + /pgdata /pgconf /backrestrepo \ + /var/lib/pgsql /var/log/pgbackrest && \ + chmod -R g=u /opt/cpm \ /pgdata /pgconf /backrestrepo \ /var/lib/pgsql /var/log/pgbackrest + # volume pgconf to store pgbackrest.conf # volume backrestrepo for pgbackrest to restore from and log @@ -64,6 +67,9 @@ ADD bin/backrest_restore /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/backrest_restore /opt/cpm/conf -USER 26 +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_entrypoint.sh"] + +USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.backup.rhel7 b/rhel7/11/Dockerfile.backup.rhel7 index 8258884d8..3d7fabf1c 100644 --- a/rhel7/11/Dockerfile.backup.rhel7 +++ b/rhel7/11/Dockerfile.backup.rhel7 @@ -34,7 +34,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum install -y bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ unzip \ && yum -y install postgresql11 postgresql11-server \ @@ -44,10 +43,15 @@ RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata ADD bin/backup/ /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/backup/ /opt/cpm/conf -RUN chown -R postgres:postgres /opt/cpm /pgdata + +RUN chgrp -R 0 /opt/cpm /pgdata && \ + chmod -R g=u /opt/cpm /pgdata VOLUME ["/pgdata"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start-backupjob.sh"] diff --git a/rhel7/11/Dockerfile.collect.rhel7 b/rhel7/11/Dockerfile.collect.rhel7 index 26767139b..d408bbb07 100644 --- a/rhel7/11/Dockerfile.collect.rhel7 +++ b/rhel7/11/Dockerfile.collect.rhel7 @@ -39,7 +39,6 @@ RUN yum install -y epel-release \ gettext \ postgresql11 \ postgresql11-libs \ - nss_wrapper \ hostname \ && yum -y clean all @@ -52,7 +51,8 @@ ADD bin/collect /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/collect /opt/cpm/conf -RUN chown -R 2:2 /opt/cpm/bin /opt/cpm/conf +RUN chgrp -R 0 /opt/cpm/bin /opt/cpm/conf && \ + chmod -R g=u /opt/cpm/bin/ opt/cpm/conf VOLUME ["/conf"] @@ -61,6 +61,9 @@ EXPOSE 9187 # node exporter EXPOSE 9100 +RUN chmod g=u /etc/passwd +ENTRYPOINT ["/opt/cpm/bin/uid_postgres.sh"] + USER 2 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.pgadmin4.rhel7 b/rhel7/11/Dockerfile.pgadmin4.rhel7 index 5cb1cd021..574a67450 100644 --- a/rhel7/11/Dockerfile.pgadmin4.rhel7 +++ b/rhel7/11/Dockerfile.pgadmin4.rhel7 @@ -39,7 +39,6 @@ RUN yum -y update \ gcc \ gettext \ hostname \ - nss_wrapper \ openssl \ procps-ng \ mod_wsgi mod_ssl \ @@ -58,8 +57,11 @@ ADD conf/pgadmin4/ /opt/cpm/conf RUN cp /opt/cpm/conf/httpd.conf /etc/httpd/conf/httpd.conf \ && rm /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/ssl.conf -RUN chown -R 2:0 /usr/lib/python2.7/site-packages/pgadmin4-web \ - && chown -R 2:0 /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd + +RUN chgrp -R 0 /usr/lib/python2.7/site-packages/pgadmin4-web \ + /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd && \ + chmod -R g=u /usr/lib/python2.7/site-packages/pgadmin4-web \ + /var/lib/pgadmin /certs /etc/httpd /run/httpd /var/log/httpd RUN ln -sf /var/lib/pgadmin/config_local.py /usr/lib/python2.7/site-packages/pgadmin4-web/config_local.py \ && ln -sf /var/lib/pgadmin/pgadmin.conf /etc/httpd/conf.d/pgadmin.conf @@ -68,6 +70,9 @@ EXPOSE 5050 VOLUME ["/var/lib/pgadmin", "/certs", "/run/httpd"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_daemon.sh"] + USER 2 CMD ["/opt/cpm/bin/start-pgadmin4.sh"] diff --git a/rhel7/11/Dockerfile.pgbadger.rhel7 b/rhel7/11/Dockerfile.pgbadger.rhel7 index c0235ba54..59d9f184a 100644 --- a/rhel7/11/Dockerfile.pgbadger.rhel7 +++ b/rhel7/11/Dockerfile.pgbadger.rhel7 @@ -37,11 +37,9 @@ RUN yum -y update \ && yum -y install \ gettext \ hostname \ - nss_wrapper \ pgbadger \ && yum clean all -y -RUN groupadd -g 26 postgres && useradd -g 26 -u 26 postgres RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /report @@ -49,13 +47,19 @@ ADD conf/pgbadger /opt/cpm/conf ADD bin/common /opt/cpm/bin ADD bin/pgbadger /opt/cpm/bin -RUN chown -R 26:26 /opt/cpm /report +RUN chgrp -R 0 /opt/cpm /report /bin && \ + chmod -R g=u /opt/cpm /report /bin # pgbadger port EXPOSE 10000 VOLUME ["/pgdata", "/report"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + +RUN chgrp -R 0 /pgdata && chmod -R g=u /pgdata + USER 26 CMD ["/opt/cpm/bin/start-pgbadger.sh"] diff --git a/rhel7/11/Dockerfile.pgbouncer.rhel7 b/rhel7/11/Dockerfile.pgbouncer.rhel7 index 84c6593e8..47fedf5e6 100644 --- a/rhel7/11/Dockerfile.pgbouncer.rhel7 +++ b/rhel7/11/Dockerfile.pgbouncer.rhel7 @@ -37,7 +37,6 @@ RUN yum -y update \ && yum -y install \ gettext \ hostname \ - nss_wrapper \ pgbouncer \ postgresql11 \ procps-ng \ @@ -49,12 +48,16 @@ ADD bin/pgbouncer /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/pgbouncer /opt/cpm/conf -RUN chown -R 2:2 /opt/cpm /pgconf +RUN chgrp -R 0 /opt/cpm /pgconf && \ + chmod -R g=u /opt/cpm /pgconf EXPOSE 6432 VOLUME ["/pgconf"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_daemon.sh"] + USER 2 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.pgdump.rhel7 b/rhel7/11/Dockerfile.pgdump.rhel7 index 741b262cc..b7c63642f 100644 --- a/rhel7/11/Dockerfile.pgdump.rhel7 +++ b/rhel7/11/Dockerfile.pgdump.rhel7 @@ -34,7 +34,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum install -y bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ unzip \ && yum -y install postgresql11 postgresql11-server \ @@ -44,10 +43,15 @@ RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata ADD bin/pgdump/ /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/pgdump/ /opt/cpm/conf -RUN chown -R 26:26 /opt/cpm /pgdata + +RUN chgrp -R 0 /opt/cpm /pgdata && \ + chmod -R g=u /opt/cpm /pgdata VOLUME ["/pgdata"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.pgpool.rhel7 b/rhel7/11/Dockerfile.pgpool.rhel7 index 8a2fff7c9..1df8cc99c 100644 --- a/rhel7/11/Dockerfile.pgpool.rhel7 +++ b/rhel7/11/Dockerfile.pgpool.rhel7 @@ -37,7 +37,6 @@ RUN yum -y update \ && yum -y install \ gettext \ hostname \ - nss_wrapper \ procps-ng \ && yum -y install \ postgresql11 \ @@ -51,10 +50,12 @@ ADD bin/pgpool /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/pgpool /opt/cpm/conf -RUN ln -sf /opt/cpm/conf/pool_hba.conf /etc/pgpool-II-11/pool_hba.conf \ - && ln -sf /opt/cpm/conf/pgpool/pool_passwd /etc/pgpool-II-11/pool_passwd +RUN ln -sf /opt/cpm/conf/pool_hba.conf /etc/pgpool-II-10/pool_hba.conf \ + && ln -sf /opt/cpm/conf/pgpool/pool_passwd /etc/pgpool-II-10/pool_passwd + +RUN chgrp -R 0 /opt/cpm && \ + chmod -R g=u /opt/cpm -RUN chown -R 2:2 /opt/cpm # open up the postgres port EXPOSE 5432 @@ -62,6 +63,9 @@ EXPOSE 5432 # add volumes to allow override of pgpool config files VOLUME ["/pgconf"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_daemon.sh"] + USER 2 CMD ["/opt/cpm/bin/startpgpool.sh"] diff --git a/rhel7/11/Dockerfile.pgrestore.rhel7 b/rhel7/11/Dockerfile.pgrestore.rhel7 index 84feece5f..5467313d1 100644 --- a/rhel7/11/Dockerfile.pgrestore.rhel7 +++ b/rhel7/11/Dockerfile.pgrestore.rhel7 @@ -34,7 +34,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum install -y bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ unzip \ file \ @@ -45,10 +44,14 @@ RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata ADD bin/pgrestore/ /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/pgrestore/ /opt/cpm/conf -RUN chown -R 26:26 /opt/cpm /pgdata +RUN chgrp -R 0 /opt/cpm /pgdata && \ + chmod -R g=u /opt/cpm /pgdata VOLUME ["/pgdata"] +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.postgres-gis.rhel7 b/rhel7/11/Dockerfile.postgres-gis.rhel7 index 92fcfaf9b..627b7ce76 100644 --- a/rhel7/11/Dockerfile.postgres-gis.rhel7 +++ b/rhel7/11/Dockerfile.postgres-gis.rhel7 @@ -38,7 +38,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. gettext \ hostname \ R-core libRmath texinfo-tex texlive-epsf \ - nss_wrapper \ openssh-server \ procps-ng \ rsync \ @@ -63,8 +62,11 @@ ADD conf/.bashrc / # set up cpm directory RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgwal /pgconf /backup /recover /backrestrepo /sshd -RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ +RUN chgrp -R 0 /opt/cpm /var/lib/pgsql \ + /pgdata /pgwal /pgconf /backup /recover /backrestrepo && \ + chmod -R g=u /opt/cpm /var/lib/pgsql \ /pgdata /pgwal /pgconf /backup /recover /backrestrepo + # Link pgbackrest.conf to default location for convenience # Remove nologin file to prevent sshd from being blocked @@ -90,6 +92,9 @@ ADD bin/common /opt/cpm/bin ADD conf/postgres /opt/cpm/conf ADD tools/pgmonitor/exporter/postgres /opt/cpm/bin/pgmonitor +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.postgres.rhel7 b/rhel7/11/Dockerfile.postgres.rhel7 index e31e81c97..02135f933 100644 --- a/rhel7/11/Dockerfile.postgres.rhel7 +++ b/rhel7/11/Dockerfile.postgres.rhel7 @@ -37,7 +37,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum -y update && yum -y install bind-utils \ gettext \ hostname \ - nss_wrapper \ openssh-server \ procps-ng \ rsync \ @@ -61,7 +60,10 @@ ADD conf/.bashrc / # set up cpm directory RUN mkdir -p /opt/cpm/bin /opt/cpm/conf /pgdata /pgwal /pgconf /backup /recover /backrestrepo /sshd -RUN chown -R postgres:postgres /opt/cpm /var/lib/pgsql \ + +RUN chgrp -R 0 /opt/cpm /var/lib/pgsql \ + /pgdata /pgwal /pgconf /backup /recover /backrestrepo && \ + chmod -R g=u /opt/cpm /var/lib/pgsql \ /pgdata /pgwal /pgconf /backup /recover /backrestrepo # Link pgbackrest.conf to default location for convenience @@ -87,6 +89,10 @@ ADD bin/common /opt/cpm/bin ADD conf/postgres /opt/cpm/conf ADD tools/pgmonitor/exporter/postgres /opt/cpm/bin/pgmonitor +RUN chmod g=u /etc/passwd +ENTRYPOINT ["/opt/cpm/bin/uid_postgres.sh"] + + USER 26 CMD ["/opt/cpm/bin/start.sh"] diff --git a/rhel7/11/Dockerfile.upgrade.rhel7 b/rhel7/11/Dockerfile.upgrade.rhel7 index 54c3357a3..3a9ef47a0 100644 --- a/rhel7/11/Dockerfile.upgrade.rhel7 +++ b/rhel7/11/Dockerfile.upgrade.rhel7 @@ -38,7 +38,6 @@ RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch. && yum install -y bind-utils \ gettext \ hostname \ - nss_wrapper \ procps-ng \ unzip \ && yum -y install \ @@ -52,10 +51,15 @@ RUN mkdir -p /opt/cpm/bin /pgolddata /pgnewdata /opt/cpm/conf ADD bin/upgrade/ /opt/cpm/bin ADD bin/common /opt/cpm/bin ADD conf/upgrade/ /opt/cpm/conf -RUN chown -R postgres:postgres /opt/cpm /pgolddata /pgnewdata + +RUN chgrp -R 0 /opt/cpm /pgolddata /pgnewdata && \ + chmod -R g=u /opt/cpm /pgolddata /pgnewdata VOLUME /pgolddata /pgnewdata +RUN chmod g=u /etc/passwd +ENTRYPOINT ["opt/cpm/bin/uid_postgres.sh"] + USER 26 CMD ["/opt/cpm/bin/start.sh"] From bb240c052092dc3e5a93dd1dad670929655710b4 Mon Sep 17 00:00:00 2001 From: Jason O'Donnell <2160810+jasonodonnell@users.noreply.github.com> Date: Tue, 2 Oct 2018 13:26:48 -0400 Subject: [PATCH 042/179] Remove godep, add dep and vendor code --- Godeps/.gitignore | 1 - Godeps/Godeps.json | 1091 - Godeps/Readme | 5 - Gopkg.lock | 809 + Gopkg.toml | 62 + Makefile | 8 +- bin/install-deps.sh | 7 - centos7/Dockerfile.badgerserver.centos7 | 6 +- centos7/Dockerfile.sample-app-build.centos7 | 2 - centos7/Dockerfile.scheduler-build.centos7 | 3 - .../installation/build-the-containers.adoc | 1 - .../installation/environment-setup.adoc | 2 - rhel7/Dockerfile.badgerserver.rhel7 | 6 +- rhel7/Dockerfile.dba.rhel7 | 48 - rhel7/Dockerfile.scheduler-build.rhel7 | 3 - tools/test-harness/README.md | 29 +- tools/test-harness/backrest_test.go | 36 +- tools/test-harness/backup_test.go | 11 +- tools/test-harness/pgdump_test.go | 13 +- tools/test-harness/pgrestore_test.go | 26 +- tools/test-harness/vacuum_test.go | 13 +- vendor/cloud.google.com/go/AUTHORS | 15 + vendor/cloud.google.com/go/CONTRIBUTORS | 40 + vendor/cloud.google.com/go/LICENSE | 202 + .../go/compute/metadata/metadata.go | 503 + vendor/github.com/Azure/go-ansiterm/LICENSE | 21 + vendor/github.com/Azure/go-ansiterm/README.md | 12 + .../github.com/Azure/go-ansiterm/constants.go | 188 + .../github.com/Azure/go-ansiterm/context.go | 7 + .../Azure/go-ansiterm/csi_entry_state.go | 49 + .../Azure/go-ansiterm/csi_param_state.go | 38 + .../go-ansiterm/escape_intermediate_state.go | 36 + .../Azure/go-ansiterm/escape_state.go | 47 + .../Azure/go-ansiterm/event_handler.go | 90 + .../Azure/go-ansiterm/ground_state.go | 24 + .../Azure/go-ansiterm/osc_string_state.go | 31 + vendor/github.com/Azure/go-ansiterm/parser.go | 151 + .../go-ansiterm/parser_action_helpers.go | 99 + .../Azure/go-ansiterm/parser_actions.go | 119 + vendor/github.com/Azure/go-ansiterm/states.go | 71 + .../github.com/Azure/go-ansiterm/utilities.go | 21 + .../Azure/go-ansiterm/winterm/ansi.go | 182 + .../Azure/go-ansiterm/winterm/api.go | 327 + .../go-ansiterm/winterm/attr_translation.go | 100 + .../go-ansiterm/winterm/cursor_helpers.go | 101 + .../go-ansiterm/winterm/erase_helpers.go | 84 + .../go-ansiterm/winterm/scroll_helper.go | 118 + .../Azure/go-ansiterm/winterm/utilities.go | 9 + .../go-ansiterm/winterm/win_event_handler.go | 743 + .../github.com/Microsoft/go-winio/.gitignore | 1 + vendor/github.com/Microsoft/go-winio/LICENSE | 22 + .../github.com/Microsoft/go-winio/README.md | 22 + .../Microsoft/go-winio/archive/tar/LICENSE | 27 + .../github.com/Microsoft/go-winio/backup.go | 280 + vendor/github.com/Microsoft/go-winio/ea.go | 137 + vendor/github.com/Microsoft/go-winio/file.go | 307 + .../github.com/Microsoft/go-winio/fileinfo.go | 61 + vendor/github.com/Microsoft/go-winio/pipe.go | 421 + .../Microsoft/go-winio/privilege.go | 202 + .../github.com/Microsoft/go-winio/reparse.go | 128 + vendor/github.com/Microsoft/go-winio/sd.go | 98 + .../github.com/Microsoft/go-winio/syscall.go | 3 + .../Microsoft/go-winio/zsyscall_windows.go | 520 + vendor/github.com/Nvveen/Gotty/LICENSE | 26 + vendor/github.com/Nvveen/Gotty/README | 5 + vendor/github.com/Nvveen/Gotty/TODO | 3 + vendor/github.com/Nvveen/Gotty/attributes.go | 514 + vendor/github.com/Nvveen/Gotty/gotty.go | 238 + vendor/github.com/Nvveen/Gotty/parser.go | 362 + vendor/github.com/Nvveen/Gotty/types.go | 23 + .../github.com/PuerkitoBio/purell/.gitignore | 5 + .../github.com/PuerkitoBio/purell/.travis.yml | 7 + vendor/github.com/PuerkitoBio/purell/LICENSE | 12 + .../github.com/PuerkitoBio/purell/README.md | 185 + .../github.com/PuerkitoBio/purell/purell.go | 375 + .../github.com/PuerkitoBio/urlesc/.travis.yml | 11 + vendor/github.com/PuerkitoBio/urlesc/LICENSE | 27 + .../github.com/PuerkitoBio/urlesc/README.md | 16 + .../github.com/PuerkitoBio/urlesc/urlesc.go | 180 + vendor/github.com/cenkalti/backoff/.gitignore | 22 + .../github.com/cenkalti/backoff/.travis.yml | 9 + vendor/github.com/cenkalti/backoff/LICENSE | 20 + vendor/github.com/cenkalti/backoff/README.md | 30 + vendor/github.com/cenkalti/backoff/backoff.go | 66 + vendor/github.com/cenkalti/backoff/context.go | 60 + .../cenkalti/backoff/exponential.go | 156 + vendor/github.com/cenkalti/backoff/retry.go | 78 + vendor/github.com/cenkalti/backoff/ticker.go | 81 + vendor/github.com/cenkalti/backoff/tries.go | 35 + .../github.com/containerd/continuity/AUTHORS | 16 + .../github.com/containerd/continuity/LICENSE | 202 + .../continuity/pathdriver/path_driver.go | 85 + vendor/github.com/docker/docker/AUTHORS | 1984 + vendor/github.com/docker/docker/LICENSE | 191 + vendor/github.com/docker/docker/NOTICE | 19 + .../docker/docker/api/types/auth.go | 22 + .../docker/docker/api/types/blkiodev/blkio.go | 23 + .../docker/docker/api/types/client.go | 406 + .../docker/docker/api/types/configs.go | 57 + .../docker/api/types/container/config.go | 69 + .../api/types/container/container_changes.go | 21 + .../api/types/container/container_create.go | 21 + .../api/types/container/container_top.go | 21 + .../api/types/container/container_update.go | 17 + .../api/types/container/container_wait.go | 29 + .../docker/api/types/container/host_config.go | 412 + .../api/types/container/hostconfig_unix.go | 41 + .../api/types/container/hostconfig_windows.go | 40 + .../api/types/container/waitcondition.go | 22 + .../docker/docker/api/types/error_response.go | 13 + .../docker/docker/api/types/filters/parse.go | 350 + .../docker/api/types/graph_driver_data.go | 17 + .../docker/docker/api/types/id_response.go | 13 + .../api/types/image_delete_response_item.go | 15 + .../docker/docker/api/types/image_summary.go | 49 + .../docker/docker/api/types/mount/mount.go | 130 + .../docker/api/types/network/network.go | 108 + .../docker/docker/api/types/plugin.go | 203 + .../docker/docker/api/types/plugin_device.go | 25 + .../docker/docker/api/types/plugin_env.go | 25 + .../docker/api/types/plugin_interface_type.go | 21 + .../docker/docker/api/types/plugin_mount.go | 37 + .../docker/api/types/plugin_responses.go | 71 + .../docker/docker/api/types/port.go | 23 + .../docker/api/types/registry/authenticate.go | 21 + .../docker/api/types/registry/registry.go | 119 + .../docker/docker/api/types/seccomp.go | 93 + .../api/types/service_update_response.go | 12 + .../docker/docker/api/types/stats.go | 181 + .../docker/api/types/strslice/strslice.go | 30 + .../docker/docker/api/types/swarm/common.go | 40 + .../docker/docker/api/types/swarm/config.go | 35 + .../docker/api/types/swarm/container.go | 74 + .../docker/docker/api/types/swarm/network.go | 121 + .../docker/docker/api/types/swarm/node.go | 115 + .../docker/docker/api/types/swarm/runtime.go | 27 + .../docker/api/types/swarm/runtime/gen.go | 3 + .../api/types/swarm/runtime/plugin.pb.go | 712 + .../api/types/swarm/runtime/plugin.proto | 20 + .../docker/docker/api/types/swarm/secret.go | 36 + .../docker/docker/api/types/swarm/service.go | 124 + .../docker/docker/api/types/swarm/swarm.go | 217 + .../docker/docker/api/types/swarm/task.go | 191 + .../docker/docker/api/types/types.go | 602 + .../docker/api/types/versions/README.md | 14 + .../docker/api/types/versions/compare.go | 62 + .../docker/docker/api/types/volume.go | 69 + .../docker/docker/contrib/syntax/vim/LICENSE | 22 + .../docker/docs/static_files/contributors.png | Bin 0 -> 23100 bytes .../docker/docker/hack/generate-authors.sh | 15 + .../integration-cli/fixtures/https/ca.pem | 1 + .../fixtures/https/client-cert.pem | 1 + .../fixtures/https/client-key.pem | 1 + .../fixtures/https/server-cert.pem | 1 + .../fixtures/https/server-key.pem | 1 + .../docker/docker/opts/address_pools.go | 84 + vendor/github.com/docker/docker/opts/env.go | 48 + vendor/github.com/docker/docker/opts/hosts.go | 165 + .../docker/docker/opts/hosts_unix.go | 8 + .../docker/docker/opts/hosts_windows.go | 4 + vendor/github.com/docker/docker/opts/ip.go | 47 + vendor/github.com/docker/docker/opts/opts.go | 337 + .../docker/docker/opts/opts_unix.go | 6 + .../docker/docker/opts/opts_windows.go | 56 + .../docker/docker/opts/quotedstring.go | 37 + .../github.com/docker/docker/opts/runtime.go | 79 + .../github.com/docker/docker/opts/ulimit.go | 81 + .../docker/docker/pkg/fileutils/fileutils.go | 298 + .../docker/pkg/fileutils/fileutils_darwin.go | 27 + .../docker/pkg/fileutils/fileutils_unix.go | 22 + .../docker/pkg/fileutils/fileutils_windows.go | 7 + .../docker/pkg/homedir/homedir_linux.go | 21 + .../docker/pkg/homedir/homedir_others.go | 13 + .../docker/docker/pkg/homedir/homedir_unix.go | 34 + .../docker/pkg/homedir/homedir_windows.go | 24 + .../docker/docker/pkg/idtools/idtools.go | 266 + .../docker/docker/pkg/idtools/idtools_unix.go | 230 + .../docker/pkg/idtools/idtools_windows.go | 23 + .../docker/pkg/idtools/usergroupadd_linux.go | 164 + .../pkg/idtools/usergroupadd_unsupported.go | 12 + .../docker/docker/pkg/idtools/utils_unix.go | 32 + .../docker/docker/pkg/ioutils/buffer.go | 51 + .../docker/docker/pkg/ioutils/bytespipe.go | 186 + .../docker/docker/pkg/ioutils/fswriters.go | 162 + .../docker/docker/pkg/ioutils/readers.go | 157 + .../docker/docker/pkg/ioutils/temp_unix.go | 10 + .../docker/docker/pkg/ioutils/temp_windows.go | 16 + .../docker/docker/pkg/ioutils/writeflusher.go | 92 + .../docker/docker/pkg/ioutils/writers.go | 66 + .../docker/docker/pkg/longpath/longpath.go | 26 + .../docker/docker/pkg/mount/flags.go | 149 + .../docker/docker/pkg/mount/flags_freebsd.go | 49 + .../docker/docker/pkg/mount/flags_linux.go | 87 + .../docker/pkg/mount/flags_unsupported.go | 31 + .../docker/docker/pkg/mount/mount.go | 141 + .../docker/pkg/mount/mounter_freebsd.go | 60 + .../docker/docker/pkg/mount/mounter_linux.go | 57 + .../docker/pkg/mount/mounter_unsupported.go | 11 + .../docker/docker/pkg/mount/mountinfo.go | 40 + .../docker/pkg/mount/mountinfo_freebsd.go | 55 + .../docker/pkg/mount/mountinfo_linux.go | 132 + .../docker/pkg/mount/mountinfo_unsupported.go | 12 + .../docker/pkg/mount/mountinfo_windows.go | 6 + .../docker/pkg/mount/sharedsubtree_linux.go | 67 + .../docker/docker/pkg/pools/pools.go | 137 + .../docker/docker/pkg/stdcopy/stdcopy.go | 190 + .../docker/docker/pkg/symlink/LICENSE.APACHE | 191 + .../docker/docker/pkg/symlink/LICENSE.BSD | 27 + .../docker/docker/pkg/system/chtimes.go | 31 + .../docker/docker/pkg/system/chtimes_unix.go | 14 + .../docker/pkg/system/chtimes_windows.go | 26 + .../docker/docker/pkg/system/errors.go | 13 + .../docker/docker/pkg/system/exitcode.go | 19 + .../docker/docker/pkg/system/filesys.go | 67 + .../docker/pkg/system/filesys_windows.go | 296 + .../docker/docker/pkg/system/init.go | 22 + .../docker/docker/pkg/system/init_unix.go | 7 + .../docker/docker/pkg/system/init_windows.go | 12 + .../docker/docker/pkg/system/lcow.go | 69 + .../docker/docker/pkg/system/lcow_unix.go | 8 + .../docker/docker/pkg/system/lcow_windows.go | 6 + .../docker/docker/pkg/system/lstat_unix.go | 19 + .../docker/docker/pkg/system/lstat_windows.go | 14 + .../docker/docker/pkg/system/meminfo.go | 17 + .../docker/docker/pkg/system/meminfo_linux.go | 65 + .../docker/pkg/system/meminfo_unsupported.go | 8 + .../docker/pkg/system/meminfo_windows.go | 45 + .../docker/docker/pkg/system/mknod.go | 22 + .../docker/docker/pkg/system/mknod_windows.go | 11 + .../docker/docker/pkg/system/path.go | 60 + .../docker/docker/pkg/system/process_unix.go | 24 + .../docker/pkg/system/process_windows.go | 18 + .../github.com/docker/docker/pkg/system/rm.go | 80 + .../docker/docker/pkg/system/stat_darwin.go | 13 + .../docker/docker/pkg/system/stat_freebsd.go | 13 + .../docker/docker/pkg/system/stat_linux.go | 19 + .../docker/docker/pkg/system/stat_openbsd.go | 13 + .../docker/docker/pkg/system/stat_solaris.go | 13 + .../docker/docker/pkg/system/stat_unix.go | 65 + .../docker/docker/pkg/system/stat_windows.go | 49 + .../docker/docker/pkg/system/syscall_unix.go | 17 + .../docker/pkg/system/syscall_windows.go | 127 + .../docker/docker/pkg/system/umask.go | 13 + .../docker/docker/pkg/system/umask_windows.go | 7 + .../docker/pkg/system/utimes_freebsd.go | 24 + .../docker/docker/pkg/system/utimes_linux.go | 25 + .../docker/pkg/system/utimes_unsupported.go | 10 + .../docker/docker/pkg/system/xattrs_linux.go | 29 + .../docker/pkg/system/xattrs_unsupported.go | 13 + .../docker/docker/project/CONTRIBUTING.md | 1 + .../github.com/docker/go-connections/LICENSE | 191 + .../docker/go-connections/nat/nat.go | 242 + .../docker/go-connections/nat/parse.go | 57 + .../docker/go-connections/nat/sort.go | 96 + .../docker/go-units/CONTRIBUTING.md | 67 + vendor/github.com/docker/go-units/LICENSE | 191 + vendor/github.com/docker/go-units/MAINTAINERS | 46 + vendor/github.com/docker/go-units/README.md | 16 + vendor/github.com/docker/go-units/circle.yml | 11 + vendor/github.com/docker/go-units/duration.go | 35 + vendor/github.com/docker/go-units/size.go | 108 + vendor/github.com/docker/go-units/ulimit.go | 118 + vendor/github.com/docker/libnetwork/LICENSE | 202 + .../docker/libnetwork/client/mflag/LICENSE | 27 + .../docker/libnetwork/ipamutils/utils.go | 96 + .../docker/spdystream/CONTRIBUTING.md | 13 + vendor/github.com/docker/spdystream/LICENSE | 191 + .../github.com/docker/spdystream/LICENSE.docs | 425 + .../github.com/docker/spdystream/MAINTAINERS | 28 + vendor/github.com/docker/spdystream/README.md | 77 + .../docker/spdystream/connection.go | 959 + .../github.com/docker/spdystream/handlers.go | 38 + .../github.com/docker/spdystream/priority.go | 98 + .../docker/spdystream/spdy/dictionary.go | 187 + .../github.com/docker/spdystream/spdy/read.go | 348 + .../docker/spdystream/spdy/types.go | 275 + .../docker/spdystream/spdy/write.go | 318 + vendor/github.com/docker/spdystream/stream.go | 327 + vendor/github.com/docker/spdystream/utils.go | 16 + .../github.com/emicklei/go-restful/.gitignore | 70 + .../emicklei/go-restful/.travis.yml | 6 + .../github.com/emicklei/go-restful/CHANGES.md | 223 + vendor/github.com/emicklei/go-restful/LICENSE | 22 + .../github.com/emicklei/go-restful/Makefile | 7 + .../github.com/emicklei/go-restful/README.md | 74 + vendor/github.com/emicklei/go-restful/Srcfile | 1 + .../emicklei/go-restful/bench_test.sh | 10 + .../emicklei/go-restful/compress.go | 123 + .../emicklei/go-restful/compressor_cache.go | 103 + .../emicklei/go-restful/compressor_pools.go | 91 + .../emicklei/go-restful/compressors.go | 54 + .../emicklei/go-restful/constants.go | 30 + .../emicklei/go-restful/container.go | 366 + .../emicklei/go-restful/cors_filter.go | 202 + .../emicklei/go-restful/coverage.sh | 2 + .../github.com/emicklei/go-restful/curly.go | 164 + .../emicklei/go-restful/curly_route.go | 52 + vendor/github.com/emicklei/go-restful/doc.go | 185 + .../emicklei/go-restful/entity_accessors.go | 163 + .../github.com/emicklei/go-restful/filter.go | 35 + .../github.com/emicklei/go-restful/jsr311.go | 248 + .../github.com/emicklei/go-restful/log/log.go | 34 + .../github.com/emicklei/go-restful/logger.go | 32 + vendor/github.com/emicklei/go-restful/mime.go | 45 + .../emicklei/go-restful/options_filter.go | 26 + .../emicklei/go-restful/parameter.go | 114 + .../emicklei/go-restful/path_expression.go | 69 + .../github.com/emicklei/go-restful/request.go | 113 + .../emicklei/go-restful/response.go | 236 + .../github.com/emicklei/go-restful/route.go | 186 + .../emicklei/go-restful/route_builder.go | 293 + .../github.com/emicklei/go-restful/router.go | 18 + .../emicklei/go-restful/service_error.go | 23 + .../emicklei/go-restful/web_service.go | 290 + .../go-restful/web_service_container.go | 39 + vendor/github.com/fatih/color/.travis.yml | 5 + vendor/github.com/fatih/color/Gopkg.lock | 27 + vendor/github.com/fatih/color/Gopkg.toml | 30 + vendor/github.com/fatih/color/LICENSE.md | 20 + vendor/github.com/fatih/color/README.md | 179 + vendor/github.com/fatih/color/color.go | 600 + vendor/github.com/fatih/color/doc.go | 133 + .../fsnotify/fsnotify/.editorconfig | 5 + .../github.com/fsnotify/fsnotify/.gitignore | 6 + .../github.com/fsnotify/fsnotify/.travis.yml | 30 + vendor/github.com/fsnotify/fsnotify/AUTHORS | 46 + .../github.com/fsnotify/fsnotify/CHANGELOG.md | 307 + .../fsnotify/fsnotify/CONTRIBUTING.md | 77 + vendor/github.com/fsnotify/fsnotify/LICENSE | 28 + vendor/github.com/fsnotify/fsnotify/README.md | 79 + vendor/github.com/fsnotify/fsnotify/fen.go | 37 + .../github.com/fsnotify/fsnotify/fsnotify.go | 66 + .../github.com/fsnotify/fsnotify/inotify.go | 337 + .../fsnotify/fsnotify/inotify_poller.go | 187 + vendor/github.com/fsnotify/fsnotify/kqueue.go | 503 + .../fsnotify/fsnotify/open_mode_bsd.go | 11 + .../fsnotify/fsnotify/open_mode_darwin.go | 12 + .../github.com/fsnotify/fsnotify/windows.go | 561 + .../fsouza/go-dockerclient/.gitignore | 4 + .../fsouza/go-dockerclient/.travis.yml | 30 + .../github.com/fsouza/go-dockerclient/AUTHORS | 194 + .../fsouza/go-dockerclient/DOCKER-LICENSE | 6 + .../fsouza/go-dockerclient/Gopkg.toml | 28 + .../github.com/fsouza/go-dockerclient/LICENSE | 23 + .../fsouza/go-dockerclient/Makefile | 34 + .../fsouza/go-dockerclient/README.markdown | 133 + .../fsouza/go-dockerclient/appveyor.yml | 21 + .../github.com/fsouza/go-dockerclient/auth.go | 185 + .../fsouza/go-dockerclient/change.go | 43 + .../fsouza/go-dockerclient/client.go | 1093 + .../fsouza/go-dockerclient/client_unix.go | 32 + .../fsouza/go-dockerclient/client_windows.go | 45 + .../fsouza/go-dockerclient/container.go | 1623 + .../fsouza/go-dockerclient/distribution.go | 26 + .../github.com/fsouza/go-dockerclient/env.go | 172 + .../fsouza/go-dockerclient/event.go | 410 + .../github.com/fsouza/go-dockerclient/exec.go | 217 + .../fsouza/go-dockerclient/image.go | 720 + .../internal/archive/archive.go | 505 + .../internal/archive/archive_linux.go | 104 + .../internal/archive/archive_other.go | 11 + .../internal/archive/archive_unix.go | 77 + .../internal/archive/archive_windows.go | 71 + .../internal/archive/changes_unix.go | 16 + .../internal/archive/changes_windows.go | 11 + .../go-dockerclient/internal/archive/copy.go | 29 + .../internal/archive/whiteouts.go | 27 + .../internal/jsonmessage/jsonmessage.go | 339 + .../go-dockerclient/internal/term/term.go | 13 + .../go-dockerclient/internal/term/winsize.go | 16 + .../internal/term/winsize_windows.go | 22 + .../github.com/fsouza/go-dockerclient/misc.go | 188 + .../fsouza/go-dockerclient/network.go | 321 + .../fsouza/go-dockerclient/plugin.go | 418 + .../fsouza/go-dockerclient/signal.go | 49 + .../fsouza/go-dockerclient/swarm.go | 156 + .../fsouza/go-dockerclient/swarm_configs.go | 171 + .../fsouza/go-dockerclient/swarm_node.go | 130 + .../fsouza/go-dockerclient/swarm_secrets.go | 171 + .../fsouza/go-dockerclient/swarm_service.go | 213 + .../fsouza/go-dockerclient/swarm_task.go | 70 + .../github.com/fsouza/go-dockerclient/tar.go | 122 + .../github.com/fsouza/go-dockerclient/tls.go | 118 + .../fsouza/go-dockerclient/volume.go | 190 + vendor/github.com/ghodss/yaml/.gitignore | 20 + vendor/github.com/ghodss/yaml/.travis.yml | 7 + vendor/github.com/ghodss/yaml/LICENSE | 50 + vendor/github.com/ghodss/yaml/README.md | 116 + vendor/github.com/ghodss/yaml/fields.go | 497 + vendor/github.com/ghodss/yaml/yaml.go | 277 + .../go-openapi/jsonpointer/.drone.sec | 1 + .../go-openapi/jsonpointer/.drone.yml | 32 + .../go-openapi/jsonpointer/.gitignore | 1 + .../go-openapi/jsonpointer/.pullapprove.yml | 13 + .../go-openapi/jsonpointer/CODE_OF_CONDUCT.md | 74 + .../github.com/go-openapi/jsonpointer/LICENSE | 202 + .../go-openapi/jsonpointer/README.md | 15 + .../go-openapi/jsonpointer/pointer.go | 238 + .../go-openapi/jsonreference/.drone.sec | 1 + .../go-openapi/jsonreference/.drone.yml | 33 + .../go-openapi/jsonreference/.gitignore | 1 + .../go-openapi/jsonreference/.pullapprove.yml | 13 + .../jsonreference/CODE_OF_CONDUCT.md | 74 + .../go-openapi/jsonreference/LICENSE | 202 + .../go-openapi/jsonreference/README.md | 15 + .../go-openapi/jsonreference/reference.go | 156 + .../github.com/go-openapi/spec/.editorconfig | 26 + vendor/github.com/go-openapi/spec/.gitignore | 2 + vendor/github.com/go-openapi/spec/.travis.yml | 16 + .../go-openapi/spec/CODE_OF_CONDUCT.md | 74 + vendor/github.com/go-openapi/spec/LICENSE | 202 + vendor/github.com/go-openapi/spec/README.md | 5 + vendor/github.com/go-openapi/spec/bindata.go | 260 + .../go-openapi/spec/contact_info.go | 24 + vendor/github.com/go-openapi/spec/expander.go | 900 + .../go-openapi/spec/external_docs.go | 24 + vendor/github.com/go-openapi/spec/header.go | 195 + vendor/github.com/go-openapi/spec/info.go | 168 + vendor/github.com/go-openapi/spec/items.go | 219 + vendor/github.com/go-openapi/spec/license.go | 23 + .../github.com/go-openapi/spec/operation.go | 233 + .../github.com/go-openapi/spec/parameter.go | 301 + .../github.com/go-openapi/spec/path_item.go | 90 + vendor/github.com/go-openapi/spec/paths.go | 97 + vendor/github.com/go-openapi/spec/ref.go | 164 + vendor/github.com/go-openapi/spec/response.go | 134 + .../github.com/go-openapi/spec/responses.go | 122 + vendor/github.com/go-openapi/spec/schema.go | 628 + .../go-openapi/spec/security_scheme.go | 142 + vendor/github.com/go-openapi/spec/spec.go | 86 + vendor/github.com/go-openapi/spec/swagger.go | 317 + vendor/github.com/go-openapi/spec/tag.go | 73 + .../github.com/go-openapi/spec/xml_object.go | 68 + .../github.com/go-openapi/swag/.editorconfig | 26 + vendor/github.com/go-openapi/swag/.gitignore | 1 + vendor/github.com/go-openapi/swag/.travis.yml | 14 + .../go-openapi/swag/CODE_OF_CONDUCT.md | 74 + vendor/github.com/go-openapi/swag/LICENSE | 202 + vendor/github.com/go-openapi/swag/README.md | 12 + vendor/github.com/go-openapi/swag/convert.go | 188 + .../go-openapi/swag/convert_types.go | 595 + vendor/github.com/go-openapi/swag/json.go | 295 + vendor/github.com/go-openapi/swag/loading.go | 74 + vendor/github.com/go-openapi/swag/net.go | 24 + vendor/github.com/go-openapi/swag/path.go | 59 + vendor/github.com/go-openapi/swag/util.go | 336 + vendor/github.com/go-openapi/swag/yaml.go | 215 + vendor/github.com/gogo/protobuf/AUTHORS | 14 + vendor/github.com/gogo/protobuf/CONTRIBUTORS | 18 + .../gogo/protobuf/GOLANG_CONTRIBUTORS | 5 + vendor/github.com/gogo/protobuf/LICENSE | 36 + .../github.com/gogo/protobuf/proto/Makefile | 43 + .../github.com/gogo/protobuf/proto/clone.go | 234 + .../github.com/gogo/protobuf/proto/decode.go | 978 + .../gogo/protobuf/proto/decode_gogo.go | 172 + .../gogo/protobuf/proto/duration.go | 100 + .../gogo/protobuf/proto/duration_gogo.go | 203 + .../github.com/gogo/protobuf/proto/encode.go | 1362 + .../gogo/protobuf/proto/encode_gogo.go | 350 + .../github.com/gogo/protobuf/proto/equal.go | 300 + .../gogo/protobuf/proto/extensions.go | 693 + .../gogo/protobuf/proto/extensions_gogo.go | 294 + vendor/github.com/gogo/protobuf/proto/lib.go | 898 + .../gogo/protobuf/proto/lib_gogo.go | 42 + .../gogo/protobuf/proto/message_set.go | 311 + .../gogo/protobuf/proto/pointer_reflect.go | 484 + .../protobuf/proto/pointer_reflect_gogo.go | 85 + .../gogo/protobuf/proto/pointer_unsafe.go | 270 + .../protobuf/proto/pointer_unsafe_gogo.go | 128 + .../gogo/protobuf/proto/properties.go | 968 + .../gogo/protobuf/proto/properties_gogo.go | 111 + .../gogo/protobuf/proto/skip_gogo.go | 119 + vendor/github.com/gogo/protobuf/proto/text.go | 928 + .../gogo/protobuf/proto/text_gogo.go | 57 + .../gogo/protobuf/proto/text_parser.go | 1013 + .../gogo/protobuf/proto/timestamp.go | 113 + .../gogo/protobuf/proto/timestamp_gogo.go | 229 + .../gogo/protobuf/sortkeys/sortkeys.go | 101 + vendor/github.com/golang/glog/LICENSE | 191 + vendor/github.com/golang/glog/README | 44 + vendor/github.com/golang/glog/glog.go | 1177 + vendor/github.com/golang/glog/glog_file.go | 124 + vendor/github.com/golang/protobuf/AUTHORS | 3 + .../github.com/golang/protobuf/CONTRIBUTORS | 3 + vendor/github.com/golang/protobuf/LICENSE | 31 + .../github.com/golang/protobuf/proto/Makefile | 43 + .../github.com/golang/protobuf/proto/clone.go | 229 + .../golang/protobuf/proto/decode.go | 970 + .../golang/protobuf/proto/encode.go | 1362 + .../github.com/golang/protobuf/proto/equal.go | 300 + .../golang/protobuf/proto/extensions.go | 587 + .../github.com/golang/protobuf/proto/lib.go | 897 + .../golang/protobuf/proto/message_set.go | 311 + .../golang/protobuf/proto/pointer_reflect.go | 484 + .../golang/protobuf/proto/pointer_unsafe.go | 270 + .../golang/protobuf/proto/properties.go | 872 + .../github.com/golang/protobuf/proto/text.go | 854 + .../golang/protobuf/proto/text_parser.go | 895 + .../github.com/golang/protobuf/ptypes/any.go | 139 + .../golang/protobuf/ptypes/any/any.pb.go | 178 + .../golang/protobuf/ptypes/any/any.proto | 149 + .../github.com/golang/protobuf/ptypes/doc.go | 35 + .../golang/protobuf/ptypes/duration.go | 102 + .../protobuf/ptypes/duration/duration.pb.go | 144 + .../protobuf/ptypes/duration/duration.proto | 117 + .../golang/protobuf/ptypes/regen.sh | 43 + .../golang/protobuf/ptypes/timestamp.go | 134 + .../protobuf/ptypes/timestamp/timestamp.pb.go | 160 + .../protobuf/ptypes/timestamp/timestamp.proto | 133 + vendor/github.com/google/btree/.travis.yml | 1 + vendor/github.com/google/btree/LICENSE | 202 + vendor/github.com/google/btree/README.md | 12 + vendor/github.com/google/btree/btree.go | 649 + vendor/github.com/google/btree/btree_mem.go | 76 + vendor/github.com/google/gofuzz/.travis.yml | 13 + .../github.com/google/gofuzz/CONTRIBUTING.md | 67 + vendor/github.com/google/gofuzz/LICENSE | 202 + vendor/github.com/google/gofuzz/README.md | 71 + vendor/github.com/google/gofuzz/doc.go | 18 + vendor/github.com/google/gofuzz/fuzz.go | 453 + vendor/github.com/googleapis/gnostic/LICENSE | 203 + .../googleapis/gnostic/OpenAPIv2/OpenAPIv2.go | 8728 +++ .../gnostic/OpenAPIv2/OpenAPIv2.pb.go | 4456 ++ .../gnostic/OpenAPIv2/OpenAPIv2.proto | 663 + .../googleapis/gnostic/OpenAPIv2/README.md | 16 + .../gnostic/OpenAPIv2/openapi-2.0.json | 1610 + .../googleapis/gnostic/compiler/README.md | 3 + .../googleapis/gnostic/compiler/context.go | 43 + .../googleapis/gnostic/compiler/error.go | 61 + .../gnostic/compiler/extension-handler.go | 101 + .../googleapis/gnostic/compiler/helpers.go | 197 + .../googleapis/gnostic/compiler/main.go | 16 + .../googleapis/gnostic/compiler/reader.go | 167 + .../gnostic/extensions/COMPILE-EXTENSION.sh | 5 + .../googleapis/gnostic/extensions/README.md | 5 + .../gnostic/extensions/extension.pb.go | 219 + .../gnostic/extensions/extension.proto | 93 + .../gnostic/extensions/extensions.go | 82 + vendor/github.com/gorilla/context/.travis.yml | 19 + vendor/github.com/gorilla/context/LICENSE | 27 + vendor/github.com/gorilla/context/README.md | 10 + vendor/github.com/gorilla/context/context.go | 143 + vendor/github.com/gorilla/context/doc.go | 88 + vendor/github.com/gorilla/mux/.travis.yml | 22 + .../github.com/gorilla/mux/ISSUE_TEMPLATE.md | 11 + vendor/github.com/gorilla/mux/LICENSE | 27 + vendor/github.com/gorilla/mux/README.md | 560 + .../github.com/gorilla/mux/context_gorilla.go | 26 + .../github.com/gorilla/mux/context_native.go | 24 + vendor/github.com/gorilla/mux/doc.go | 307 + vendor/github.com/gorilla/mux/middleware.go | 28 + vendor/github.com/gorilla/mux/mux.go | 585 + vendor/github.com/gorilla/mux/regexp.go | 332 + vendor/github.com/gorilla/mux/route.go | 761 + vendor/github.com/gorilla/mux/test_helpers.go | 18 + .../gregjones/httpcache/.travis.yml | 18 + .../gregjones/httpcache/LICENSE.txt | 7 + .../github.com/gregjones/httpcache/README.md | 24 + .../httpcache/diskcache/diskcache.go | 61 + .../gregjones/httpcache/httpcache.go | 553 + vendor/github.com/hashicorp/hcl/.gitignore | 9 + vendor/github.com/hashicorp/hcl/.travis.yml | 13 + vendor/github.com/hashicorp/hcl/LICENSE | 354 + vendor/github.com/hashicorp/hcl/Makefile | 18 + vendor/github.com/hashicorp/hcl/README.md | 125 + vendor/github.com/hashicorp/hcl/appveyor.yml | 19 + vendor/github.com/hashicorp/hcl/decoder.go | 729 + vendor/github.com/hashicorp/hcl/hcl.go | 11 + .../github.com/hashicorp/hcl/hcl/ast/ast.go | 219 + .../github.com/hashicorp/hcl/hcl/ast/walk.go | 52 + .../hashicorp/hcl/hcl/parser/error.go | 17 + .../hashicorp/hcl/hcl/parser/parser.go | 526 + .../hashicorp/hcl/hcl/scanner/scanner.go | 651 + .../hashicorp/hcl/hcl/strconv/quote.go | 241 + .../hashicorp/hcl/hcl/token/position.go | 46 + .../hashicorp/hcl/hcl/token/token.go | 219 + .../hashicorp/hcl/json/parser/flatten.go | 117 + .../hashicorp/hcl/json/parser/parser.go | 313 + .../hashicorp/hcl/json/scanner/scanner.go | 451 + .../hashicorp/hcl/json/token/position.go | 46 + .../hashicorp/hcl/json/token/token.go | 118 + vendor/github.com/hashicorp/hcl/lex.go | 38 + vendor/github.com/hashicorp/hcl/parse.go | 39 + vendor/github.com/howeyc/gopass/.travis.yml | 11 + vendor/github.com/howeyc/gopass/LICENSE.txt | 15 + .../howeyc/gopass/OPENSOLARIS.LICENSE | 384 + vendor/github.com/howeyc/gopass/README.md | 27 + vendor/github.com/howeyc/gopass/pass.go | 110 + vendor/github.com/howeyc/gopass/terminal.go | 25 + .../howeyc/gopass/terminal_solaris.go | 69 + vendor/github.com/imdario/mergo/.travis.yml | 2 + vendor/github.com/imdario/mergo/LICENSE | 28 + vendor/github.com/imdario/mergo/README.md | 68 + vendor/github.com/imdario/mergo/doc.go | 44 + vendor/github.com/imdario/mergo/map.go | 146 + vendor/github.com/imdario/mergo/merge.go | 99 + vendor/github.com/imdario/mergo/mergo.go | 90 + .../imdario/mergo/testdata/license.yml | 3 + .../inconshreveable/mousetrap/LICENSE | 13 + .../inconshreveable/mousetrap/README.md | 23 + .../inconshreveable/mousetrap/trap_others.go | 15 + .../inconshreveable/mousetrap/trap_windows.go | 98 + .../mousetrap/trap_windows_1.4.go | 46 + .../github.com/json-iterator/go/.codecov.yml | 3 + vendor/github.com/json-iterator/go/.gitignore | 3 + .../github.com/json-iterator/go/.travis.yml | 13 + vendor/github.com/json-iterator/go/LICENSE | 21 + vendor/github.com/json-iterator/go/README.md | 80 + .../json-iterator/go/feature_adapter.go | 127 + .../json-iterator/go/feature_any.go | 242 + .../json-iterator/go/feature_any_array.go | 278 + .../json-iterator/go/feature_any_bool.go | 137 + .../json-iterator/go/feature_any_float.go | 83 + .../json-iterator/go/feature_any_int32.go | 74 + .../json-iterator/go/feature_any_int64.go | 74 + .../json-iterator/go/feature_any_invalid.go | 82 + .../json-iterator/go/feature_any_nil.go | 69 + .../json-iterator/go/feature_any_number.go | 104 + .../json-iterator/go/feature_any_object.go | 374 + .../json-iterator/go/feature_any_string.go | 166 + .../json-iterator/go/feature_any_uint32.go | 74 + .../json-iterator/go/feature_any_uint64.go | 74 + .../json-iterator/go/feature_config.go | 312 + .../json-iterator/go/feature_iter.go | 307 + .../json-iterator/go/feature_iter_array.go | 58 + .../json-iterator/go/feature_iter_float.go | 341 + .../json-iterator/go/feature_iter_int.go | 258 + .../json-iterator/go/feature_iter_object.go | 212 + .../json-iterator/go/feature_iter_skip.go | 127 + .../go/feature_iter_skip_sloppy.go | 144 + .../go/feature_iter_skip_strict.go | 89 + .../json-iterator/go/feature_iter_string.go | 215 + .../json-iterator/go/feature_json_number.go | 15 + .../json-iterator/go/feature_pool.go | 57 + .../json-iterator/go/feature_reflect.go | 691 + .../json-iterator/go/feature_reflect_array.go | 99 + .../go/feature_reflect_extension.go | 413 + .../json-iterator/go/feature_reflect_map.go | 244 + .../go/feature_reflect_native.go | 672 + .../go/feature_reflect_object.go | 196 + .../json-iterator/go/feature_reflect_slice.go | 149 + .../go/feature_reflect_struct_decoder.go | 916 + .../json-iterator/go/feature_stream.go | 305 + .../json-iterator/go/feature_stream_float.go | 96 + .../json-iterator/go/feature_stream_int.go | 320 + .../json-iterator/go/feature_stream_string.go | 396 + .../go/fuzzy_mode_convert_table.md | 7 + .../github.com/json-iterator/go/jsoniter.go | 18 + .../go/skip_tests/array/skip_test.go | 1 + .../go/skip_tests/object/skip_test.go | 1 + .../go/skip_tests/string/skip_test.go | 1 + vendor/github.com/json-iterator/go/test.sh | 12 + vendor/github.com/juju/ratelimit/LICENSE | 191 + vendor/github.com/juju/ratelimit/README.md | 117 + vendor/github.com/juju/ratelimit/ratelimit.go | 284 + vendor/github.com/juju/ratelimit/reader.go | 51 + vendor/github.com/lib/pq/.gitignore | 4 + vendor/github.com/lib/pq/.travis.sh | 88 + vendor/github.com/lib/pq/.travis.yml | 56 + vendor/github.com/lib/pq/CONTRIBUTING.md | 29 + vendor/github.com/lib/pq/LICENSE.md | 8 + vendor/github.com/lib/pq/README.md | 105 + vendor/github.com/lib/pq/array.go | 756 + vendor/github.com/lib/pq/buf.go | 91 + vendor/github.com/lib/pq/conn.go | 1819 + vendor/github.com/lib/pq/conn_go18.go | 128 + vendor/github.com/lib/pq/copy.go | 282 + vendor/github.com/lib/pq/doc.go | 235 + vendor/github.com/lib/pq/encode.go | 603 + vendor/github.com/lib/pq/error.go | 508 + vendor/github.com/lib/pq/notify.go | 782 + vendor/github.com/lib/pq/oid/doc.go | 6 + vendor/github.com/lib/pq/oid/gen.go | 93 + vendor/github.com/lib/pq/oid/types.go | 343 + vendor/github.com/lib/pq/rows.go | 93 + vendor/github.com/lib/pq/ssl.go | 158 + vendor/github.com/lib/pq/ssl_go1.7.go | 14 + vendor/github.com/lib/pq/ssl_permissions.go | 20 + vendor/github.com/lib/pq/ssl_renegotiation.go | 8 + vendor/github.com/lib/pq/ssl_windows.go | 9 + vendor/github.com/lib/pq/url.go | 76 + vendor/github.com/lib/pq/user_posix.go | 24 + vendor/github.com/lib/pq/user_windows.go | 27 + vendor/github.com/lib/pq/uuid.go | 23 + .../magiconair/properties/.gitignore | 6 + .../magiconair/properties/.travis.yml | 9 + .../magiconair/properties/CHANGELOG.md | 101 + .../github.com/magiconair/properties/LICENSE | 25 + .../magiconair/properties/README.md | 100 + .../magiconair/properties/decode.go | 289 + .../github.com/magiconair/properties/doc.go | 156 + .../magiconair/properties/integrate.go | 34 + .../github.com/magiconair/properties/lex.go | 408 + .../github.com/magiconair/properties/load.go | 241 + .../magiconair/properties/parser.go | 95 + .../magiconair/properties/properties.go | 811 + .../magiconair/properties/rangecheck.go | 31 + vendor/github.com/mailru/easyjson/LICENSE | 7 + .../github.com/mailru/easyjson/buffer/pool.go | 270 + .../mailru/easyjson/jlexer/bytestostr.go | 24 + .../easyjson/jlexer/bytestostr_nounsafe.go | 13 + .../mailru/easyjson/jlexer/error.go | 15 + .../mailru/easyjson/jlexer/lexer.go | 1114 + .../mailru/easyjson/jwriter/writer.go | 328 + .../github.com/mattn/go-colorable/.travis.yml | 9 + vendor/github.com/mattn/go-colorable/LICENSE | 21 + .../github.com/mattn/go-colorable/README.md | 48 + .../mattn/go-colorable/colorable_appengine.go | 29 + .../mattn/go-colorable/colorable_others.go | 30 + .../mattn/go-colorable/colorable_windows.go | 884 + .../mattn/go-colorable/noncolorable.go | 55 + vendor/github.com/mattn/go-isatty/.travis.yml | 13 + vendor/github.com/mattn/go-isatty/LICENSE | 9 + vendor/github.com/mattn/go-isatty/README.md | 50 + vendor/github.com/mattn/go-isatty/doc.go | 2 + .../mattn/go-isatty/isatty_appengine.go | 15 + .../github.com/mattn/go-isatty/isatty_bsd.go | 18 + .../mattn/go-isatty/isatty_linux.go | 18 + .../mattn/go-isatty/isatty_linux_ppc64x.go | 19 + .../mattn/go-isatty/isatty_others.go | 10 + .../mattn/go-isatty/isatty_solaris.go | 16 + .../mattn/go-isatty/isatty_windows.go | 94 + .../mitchellh/mapstructure/.travis.yml | 7 + .../github.com/mitchellh/mapstructure/LICENSE | 21 + .../mitchellh/mapstructure/README.md | 46 + .../mitchellh/mapstructure/decode_hooks.go | 152 + .../mitchellh/mapstructure/error.go | 50 + .../mitchellh/mapstructure/mapstructure.go | 834 + .../opencontainers/go-digest/.mailmap | 1 + .../opencontainers/go-digest/.pullapprove.yml | 12 + .../opencontainers/go-digest/.travis.yml | 4 + .../opencontainers/go-digest/CONTRIBUTING.md | 72 + .../opencontainers/go-digest/LICENSE | 191 + .../opencontainers/go-digest/LICENSE.docs | 425 + .../opencontainers/go-digest/MAINTAINERS | 9 + .../opencontainers/go-digest/README.md | 104 + .../opencontainers/go-digest/algorithm.go | 192 + .../opencontainers/go-digest/digest.go | 156 + .../opencontainers/go-digest/digester.go | 39 + .../opencontainers/go-digest/doc.go | 56 + .../opencontainers/go-digest/verifiers.go | 45 + .../opencontainers/image-spec/LICENSE | 191 + .../image-spec/specs-go/v1/annotations.go | 56 + .../image-spec/specs-go/v1/config.go | 103 + .../image-spec/specs-go/v1/descriptor.go | 64 + .../image-spec/specs-go/v1/index.go | 29 + .../image-spec/specs-go/v1/layout.go | 28 + .../image-spec/specs-go/v1/manifest.go | 32 + .../image-spec/specs-go/v1/mediatype.go | 48 + .../image-spec/specs-go/version.go | 32 + .../image-spec/specs-go/versioned.go | 23 + vendor/github.com/opencontainers/runc/LICENSE | 191 + vendor/github.com/opencontainers/runc/NOTICE | 17 + .../runc/libcontainer/user/MAINTAINERS | 2 + .../runc/libcontainer/user/lookup.go | 41 + .../runc/libcontainer/user/lookup_unix.go | 142 + .../runc/libcontainer/user/lookup_windows.go | 40 + .../runc/libcontainer/user/user.go | 608 + .../github.com/pelletier/go-toml/.gitignore | 1 + .../github.com/pelletier/go-toml/.travis.yml | 23 + vendor/github.com/pelletier/go-toml/LICENSE | 21 + vendor/github.com/pelletier/go-toml/README.md | 119 + .../pelletier/go-toml/benchmark.json | 164 + .../github.com/pelletier/go-toml/benchmark.sh | 32 + .../pelletier/go-toml/benchmark.toml | 244 + .../pelletier/go-toml/benchmark.yml | 121 + vendor/github.com/pelletier/go-toml/doc.go | 23 + .../pelletier/go-toml/example-crlf.toml | 29 + .../github.com/pelletier/go-toml/example.toml | 29 + .../pelletier/go-toml/keysparsing.go | 94 + vendor/github.com/pelletier/go-toml/lexer.go | 651 + .../github.com/pelletier/go-toml/marshal.go | 508 + .../pelletier/go-toml/marshal_test.toml | 38 + vendor/github.com/pelletier/go-toml/parser.go | 383 + .../github.com/pelletier/go-toml/position.go | 29 + vendor/github.com/pelletier/go-toml/test.sh | 90 + vendor/github.com/pelletier/go-toml/token.go | 140 + vendor/github.com/pelletier/go-toml/toml.go | 300 + .../pelletier/go-toml/tomltree_create.go | 142 + .../pelletier/go-toml/tomltree_write.go | 270 + vendor/github.com/petar/GoLLRB/AUTHORS | 4 + vendor/github.com/petar/GoLLRB/LICENSE | 27 + vendor/github.com/petar/GoLLRB/llrb/avgvar.go | 39 + .../github.com/petar/GoLLRB/llrb/iterator.go | 93 + .../petar/GoLLRB/llrb/llrb-stats.go | 46 + vendor/github.com/petar/GoLLRB/llrb/llrb.go | 456 + vendor/github.com/petar/GoLLRB/llrb/util.go | 17 + vendor/github.com/peterbourgon/diskv/LICENSE | 19 + .../github.com/peterbourgon/diskv/README.md | 141 + .../peterbourgon/diskv/compression.go | 64 + vendor/github.com/peterbourgon/diskv/diskv.go | 624 + vendor/github.com/peterbourgon/diskv/index.go | 115 + vendor/github.com/pkg/errors/.gitignore | 24 + vendor/github.com/pkg/errors/.travis.yml | 11 + vendor/github.com/pkg/errors/LICENSE | 23 + vendor/github.com/pkg/errors/README.md | 52 + vendor/github.com/pkg/errors/appveyor.yml | 32 + vendor/github.com/pkg/errors/errors.go | 269 + vendor/github.com/pkg/errors/stack.go | 178 + vendor/github.com/sirupsen/logrus/.gitignore | 1 + vendor/github.com/sirupsen/logrus/.travis.yml | 15 + .../github.com/sirupsen/logrus/CHANGELOG.md | 113 + vendor/github.com/sirupsen/logrus/LICENSE | 21 + vendor/github.com/sirupsen/logrus/README.md | 505 + vendor/github.com/sirupsen/logrus/alt_exit.go | 64 + .../github.com/sirupsen/logrus/appveyor.yml | 14 + vendor/github.com/sirupsen/logrus/doc.go | 26 + vendor/github.com/sirupsen/logrus/entry.go | 276 + vendor/github.com/sirupsen/logrus/exported.go | 193 + .../github.com/sirupsen/logrus/formatter.go | 45 + vendor/github.com/sirupsen/logrus/hooks.go | 34 + .../sirupsen/logrus/json_formatter.go | 79 + vendor/github.com/sirupsen/logrus/logger.go | 317 + vendor/github.com/sirupsen/logrus/logrus.go | 143 + .../sirupsen/logrus/terminal_bsd.go | 10 + .../sirupsen/logrus/terminal_linux.go | 14 + .../sirupsen/logrus/text_formatter.go | 191 + vendor/github.com/sirupsen/logrus/writer.go | 62 + vendor/github.com/spf13/afero/.travis.yml | 21 + vendor/github.com/spf13/afero/LICENSE.txt | 174 + vendor/github.com/spf13/afero/README.md | 452 + vendor/github.com/spf13/afero/afero.go | 108 + vendor/github.com/spf13/afero/appveyor.yml | 15 + vendor/github.com/spf13/afero/basepath.go | 145 + .../github.com/spf13/afero/cacheOnReadFs.go | 290 + vendor/github.com/spf13/afero/const_bsds.go | 22 + .../github.com/spf13/afero/const_win_unix.go | 25 + .../github.com/spf13/afero/copyOnWriteFs.go | 253 + vendor/github.com/spf13/afero/httpFs.go | 110 + vendor/github.com/spf13/afero/ioutil.go | 230 + vendor/github.com/spf13/afero/match.go | 110 + vendor/github.com/spf13/afero/mem/dir.go | 37 + vendor/github.com/spf13/afero/mem/dirmap.go | 43 + vendor/github.com/spf13/afero/mem/file.go | 311 + vendor/github.com/spf13/afero/memmap.go | 365 + vendor/github.com/spf13/afero/os.go | 94 + vendor/github.com/spf13/afero/path.go | 108 + vendor/github.com/spf13/afero/readonlyfs.go | 70 + vendor/github.com/spf13/afero/regexpfs.go | 214 + vendor/github.com/spf13/afero/unionFile.go | 274 + vendor/github.com/spf13/afero/util.go | 331 + vendor/github.com/spf13/cast/.gitignore | 25 + vendor/github.com/spf13/cast/.travis.yml | 14 + vendor/github.com/spf13/cast/LICENSE | 21 + vendor/github.com/spf13/cast/Makefile | 38 + vendor/github.com/spf13/cast/README.md | 75 + vendor/github.com/spf13/cast/cast.go | 159 + vendor/github.com/spf13/cast/caste.go | 1146 + vendor/github.com/spf13/cobra/.gitignore | 36 + vendor/github.com/spf13/cobra/.mailmap | 3 + vendor/github.com/spf13/cobra/.travis.yml | 18 + vendor/github.com/spf13/cobra/LICENSE.txt | 174 + vendor/github.com/spf13/cobra/README.md | 898 + .../spf13/cobra/bash_completions.go | 630 + .../spf13/cobra/bash_completions.md | 206 + vendor/github.com/spf13/cobra/cobra.go | 175 + vendor/github.com/spf13/cobra/command.go | 1256 + .../github.com/spf13/cobra/command_notwin.go | 5 + vendor/github.com/spf13/cobra/command_win.go | 26 + .../spf13/jwalterweatherman/.gitignore | 22 + .../spf13/jwalterweatherman/LICENSE | 21 + .../spf13/jwalterweatherman/README.md | 148 + .../jwalterweatherman/default_notepad.go | 113 + .../spf13/jwalterweatherman/log_counter.go | 55 + .../spf13/jwalterweatherman/notepad.go | 194 + vendor/github.com/spf13/pflag/.gitignore | 2 + vendor/github.com/spf13/pflag/.travis.yml | 20 + vendor/github.com/spf13/pflag/LICENSE | 28 + vendor/github.com/spf13/pflag/README.md | 277 + vendor/github.com/spf13/pflag/bool.go | 94 + vendor/github.com/spf13/pflag/bool_slice.go | 147 + vendor/github.com/spf13/pflag/count.go | 94 + vendor/github.com/spf13/pflag/duration.go | 86 + vendor/github.com/spf13/pflag/flag.go | 1063 + vendor/github.com/spf13/pflag/float32.go | 88 + vendor/github.com/spf13/pflag/float64.go | 84 + vendor/github.com/spf13/pflag/golangflag.go | 101 + vendor/github.com/spf13/pflag/int.go | 84 + vendor/github.com/spf13/pflag/int32.go | 88 + vendor/github.com/spf13/pflag/int64.go | 84 + vendor/github.com/spf13/pflag/int8.go | 88 + vendor/github.com/spf13/pflag/int_slice.go | 128 + vendor/github.com/spf13/pflag/ip.go | 94 + vendor/github.com/spf13/pflag/ip_slice.go | 148 + vendor/github.com/spf13/pflag/ipmask.go | 122 + vendor/github.com/spf13/pflag/ipnet.go | 98 + vendor/github.com/spf13/pflag/string.go | 80 + vendor/github.com/spf13/pflag/string_array.go | 103 + vendor/github.com/spf13/pflag/string_slice.go | 129 + vendor/github.com/spf13/pflag/uint.go | 88 + vendor/github.com/spf13/pflag/uint16.go | 88 + vendor/github.com/spf13/pflag/uint32.go | 88 + vendor/github.com/spf13/pflag/uint64.go | 88 + vendor/github.com/spf13/pflag/uint8.go | 88 + vendor/github.com/spf13/pflag/uint_slice.go | 126 + vendor/github.com/spf13/viper/.gitignore | 24 + vendor/github.com/spf13/viper/.travis.yml | 27 + vendor/github.com/spf13/viper/LICENSE | 21 + vendor/github.com/spf13/viper/README.md | 643 + vendor/github.com/spf13/viper/flags.go | 57 + vendor/github.com/spf13/viper/nohup.out | 1 + vendor/github.com/spf13/viper/util.go | 282 + vendor/github.com/spf13/viper/viper.go | 1574 + vendor/golang.org/x/crypto/AUTHORS | 3 + vendor/golang.org/x/crypto/CONTRIBUTORS | 3 + vendor/golang.org/x/crypto/LICENSE | 27 + vendor/golang.org/x/crypto/PATENTS | 22 + .../x/crypto/curve25519/const_amd64.h | 8 + .../x/crypto/curve25519/const_amd64.s | 20 + .../x/crypto/curve25519/cswap_amd64.s | 65 + .../x/crypto/curve25519/curve25519.go | 834 + vendor/golang.org/x/crypto/curve25519/doc.go | 23 + .../x/crypto/curve25519/freeze_amd64.s | 73 + .../x/crypto/curve25519/ladderstep_amd64.s | 1377 + .../x/crypto/curve25519/mont25519_amd64.go | 240 + .../x/crypto/curve25519/mul_amd64.s | 169 + .../x/crypto/curve25519/square_amd64.s | 132 + vendor/golang.org/x/crypto/ed25519/ed25519.go | 181 + .../ed25519/internal/edwards25519/const.go | 1422 + .../internal/edwards25519/edwards25519.go | 1771 + vendor/golang.org/x/crypto/ssh/buffer.go | 98 + vendor/golang.org/x/crypto/ssh/certs.go | 519 + vendor/golang.org/x/crypto/ssh/channel.go | 633 + vendor/golang.org/x/crypto/ssh/cipher.go | 629 + vendor/golang.org/x/crypto/ssh/client.go | 257 + vendor/golang.org/x/crypto/ssh/client_auth.go | 486 + vendor/golang.org/x/crypto/ssh/common.go | 373 + vendor/golang.org/x/crypto/ssh/connection.go | 143 + vendor/golang.org/x/crypto/ssh/doc.go | 21 + vendor/golang.org/x/crypto/ssh/handshake.go | 640 + vendor/golang.org/x/crypto/ssh/kex.go | 540 + vendor/golang.org/x/crypto/ssh/keys.go | 1006 + vendor/golang.org/x/crypto/ssh/mac.go | 61 + vendor/golang.org/x/crypto/ssh/messages.go | 758 + vendor/golang.org/x/crypto/ssh/mux.go | 330 + vendor/golang.org/x/crypto/ssh/server.go | 563 + vendor/golang.org/x/crypto/ssh/session.go | 647 + vendor/golang.org/x/crypto/ssh/streamlocal.go | 115 + vendor/golang.org/x/crypto/ssh/tcpip.go | 465 + .../x/crypto/ssh/terminal/terminal.go | 951 + .../golang.org/x/crypto/ssh/terminal/util.go | 123 + .../x/crypto/ssh/terminal/util_bsd.go | 12 + .../x/crypto/ssh/terminal/util_linux.go | 10 + .../x/crypto/ssh/terminal/util_plan9.go | 58 + .../x/crypto/ssh/terminal/util_solaris.go | 128 + .../x/crypto/ssh/terminal/util_windows.go | 102 + vendor/golang.org/x/crypto/ssh/transport.go | 375 + vendor/golang.org/x/net/AUTHORS | 3 + vendor/golang.org/x/net/CONTRIBUTORS | 3 + vendor/golang.org/x/net/LICENSE | 27 + vendor/golang.org/x/net/PATENTS | 22 + vendor/golang.org/x/net/context/context.go | 54 + .../x/net/context/ctxhttp/ctxhttp.go | 74 + .../x/net/context/ctxhttp/ctxhttp_pre17.go | 147 + vendor/golang.org/x/net/context/go17.go | 72 + vendor/golang.org/x/net/context/go19.go | 20 + vendor/golang.org/x/net/context/pre_go17.go | 300 + vendor/golang.org/x/net/context/pre_go19.go | 109 + vendor/golang.org/x/net/http2/.gitignore | 2 + vendor/golang.org/x/net/http2/Dockerfile | 51 + vendor/golang.org/x/net/http2/Makefile | 3 + vendor/golang.org/x/net/http2/README | 20 + vendor/golang.org/x/net/http2/ciphers.go | 641 + .../x/net/http2/client_conn_pool.go | 256 + .../x/net/http2/configure_transport.go | 80 + vendor/golang.org/x/net/http2/databuffer.go | 146 + vendor/golang.org/x/net/http2/errors.go | 133 + vendor/golang.org/x/net/http2/flow.go | 50 + vendor/golang.org/x/net/http2/frame.go | 1579 + vendor/golang.org/x/net/http2/go16.go | 16 + vendor/golang.org/x/net/http2/go17.go | 106 + vendor/golang.org/x/net/http2/go17_not18.go | 36 + vendor/golang.org/x/net/http2/go18.go | 56 + vendor/golang.org/x/net/http2/go19.go | 16 + vendor/golang.org/x/net/http2/gotrack.go | 170 + vendor/golang.org/x/net/http2/headermap.go | 78 + vendor/golang.org/x/net/http2/hpack/encode.go | 240 + vendor/golang.org/x/net/http2/hpack/hpack.go | 490 + .../golang.org/x/net/http2/hpack/huffman.go | 212 + vendor/golang.org/x/net/http2/hpack/tables.go | 479 + vendor/golang.org/x/net/http2/http2.go | 391 + vendor/golang.org/x/net/http2/not_go16.go | 21 + vendor/golang.org/x/net/http2/not_go17.go | 87 + vendor/golang.org/x/net/http2/not_go18.go | 29 + vendor/golang.org/x/net/http2/not_go19.go | 16 + vendor/golang.org/x/net/http2/pipe.go | 163 + vendor/golang.org/x/net/http2/server.go | 2857 + vendor/golang.org/x/net/http2/transport.go | 2221 + vendor/golang.org/x/net/http2/write.go | 370 + vendor/golang.org/x/net/http2/writesched.go | 242 + .../x/net/http2/writesched_priority.go | 452 + .../x/net/http2/writesched_random.go | 72 + vendor/golang.org/x/net/idna/idna.go | 680 + vendor/golang.org/x/net/idna/punycode.go | 203 + vendor/golang.org/x/net/idna/tables.go | 4477 ++ vendor/golang.org/x/net/idna/trie.go | 72 + vendor/golang.org/x/net/idna/trieval.go | 114 + .../golang.org/x/net/lex/httplex/httplex.go | 351 + vendor/golang.org/x/oauth2/.travis.yml | 13 + vendor/golang.org/x/oauth2/AUTHORS | 3 + vendor/golang.org/x/oauth2/CONTRIBUTING.md | 26 + vendor/golang.org/x/oauth2/CONTRIBUTORS | 3 + vendor/golang.org/x/oauth2/LICENSE | 27 + vendor/golang.org/x/oauth2/README.md | 77 + .../golang.org/x/oauth2/google/appengine.go | 89 + .../x/oauth2/google/appengine_hook.go | 14 + .../x/oauth2/google/appengineflex_hook.go | 11 + vendor/golang.org/x/oauth2/google/default.go | 115 + vendor/golang.org/x/oauth2/google/doc_go19.go | 42 + .../x/oauth2/google/doc_not_go19.go | 43 + vendor/golang.org/x/oauth2/google/go19.go | 57 + vendor/golang.org/x/oauth2/google/google.go | 192 + vendor/golang.org/x/oauth2/google/jwt.go | 74 + vendor/golang.org/x/oauth2/google/not_go19.go | 54 + vendor/golang.org/x/oauth2/google/sdk.go | 201 + .../x/oauth2/internal/client_appengine.go | 13 + vendor/golang.org/x/oauth2/internal/doc.go | 6 + vendor/golang.org/x/oauth2/internal/oauth2.go | 37 + vendor/golang.org/x/oauth2/internal/token.go | 270 + .../golang.org/x/oauth2/internal/transport.go | 34 + vendor/golang.org/x/oauth2/jws/jws.go | 182 + vendor/golang.org/x/oauth2/jwt/jwt.go | 162 + vendor/golang.org/x/oauth2/oauth2.go | 362 + vendor/golang.org/x/oauth2/token.go | 175 + vendor/golang.org/x/oauth2/transport.go | 144 + vendor/golang.org/x/sys/AUTHORS | 3 + vendor/golang.org/x/sys/CONTRIBUTORS | 3 + vendor/golang.org/x/sys/LICENSE | 27 + vendor/golang.org/x/sys/PATENTS | 22 + vendor/golang.org/x/sys/unix/.gitignore | 1 + vendor/golang.org/x/sys/unix/README.md | 173 + vendor/golang.org/x/sys/unix/asm_darwin_386.s | 29 + .../golang.org/x/sys/unix/asm_darwin_amd64.s | 29 + vendor/golang.org/x/sys/unix/asm_darwin_arm.s | 30 + .../golang.org/x/sys/unix/asm_darwin_arm64.s | 30 + .../x/sys/unix/asm_dragonfly_amd64.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_386.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_amd64.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_arm.s | 29 + vendor/golang.org/x/sys/unix/asm_linux_386.s | 35 + .../golang.org/x/sys/unix/asm_linux_amd64.s | 29 + vendor/golang.org/x/sys/unix/asm_linux_arm.s | 29 + .../golang.org/x/sys/unix/asm_linux_arm64.s | 24 + .../golang.org/x/sys/unix/asm_linux_mips64x.s | 28 + .../golang.org/x/sys/unix/asm_linux_mipsx.s | 31 + .../golang.org/x/sys/unix/asm_linux_ppc64x.s | 28 + .../golang.org/x/sys/unix/asm_linux_s390x.s | 28 + vendor/golang.org/x/sys/unix/asm_netbsd_386.s | 29 + .../golang.org/x/sys/unix/asm_netbsd_amd64.s | 29 + vendor/golang.org/x/sys/unix/asm_netbsd_arm.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_386.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_amd64.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_arm.s | 29 + .../golang.org/x/sys/unix/asm_solaris_amd64.s | 17 + .../golang.org/x/sys/unix/bluetooth_linux.go | 35 + vendor/golang.org/x/sys/unix/cap_freebsd.go | 195 + vendor/golang.org/x/sys/unix/constants.go | 13 + vendor/golang.org/x/sys/unix/dev_darwin.go | 24 + vendor/golang.org/x/sys/unix/dev_dragonfly.go | 30 + vendor/golang.org/x/sys/unix/dev_freebsd.go | 30 + vendor/golang.org/x/sys/unix/dev_linux.go | 42 + vendor/golang.org/x/sys/unix/dev_netbsd.go | 29 + vendor/golang.org/x/sys/unix/dev_openbsd.go | 29 + vendor/golang.org/x/sys/unix/dirent.go | 102 + vendor/golang.org/x/sys/unix/endian_big.go | 9 + vendor/golang.org/x/sys/unix/endian_little.go | 9 + vendor/golang.org/x/sys/unix/env_unix.go | 27 + vendor/golang.org/x/sys/unix/env_unset.go | 14 + .../x/sys/unix/errors_freebsd_386.go | 227 + .../x/sys/unix/errors_freebsd_amd64.go | 227 + .../x/sys/unix/errors_freebsd_arm.go | 226 + vendor/golang.org/x/sys/unix/file_unix.go | 27 + vendor/golang.org/x/sys/unix/flock.go | 22 + .../x/sys/unix/flock_linux_32bit.go | 13 + vendor/golang.org/x/sys/unix/gccgo.go | 46 + vendor/golang.org/x/sys/unix/gccgo_c.c | 41 + .../x/sys/unix/gccgo_linux_amd64.go | 20 + vendor/golang.org/x/sys/unix/mkall.sh | 194 + vendor/golang.org/x/sys/unix/mkerrors.sh | 569 + vendor/golang.org/x/sys/unix/mkpost.go | 93 + vendor/golang.org/x/sys/unix/mksyscall.pl | 328 + .../x/sys/unix/mksyscall_solaris.pl | 289 + .../golang.org/x/sys/unix/mksysctl_openbsd.pl | 264 + .../golang.org/x/sys/unix/mksysnum_darwin.pl | 39 + .../x/sys/unix/mksysnum_dragonfly.pl | 50 + .../golang.org/x/sys/unix/mksysnum_freebsd.pl | 50 + .../golang.org/x/sys/unix/mksysnum_netbsd.pl | 58 + .../golang.org/x/sys/unix/mksysnum_openbsd.pl | 50 + .../golang.org/x/sys/unix/openbsd_pledge.go | 38 + vendor/golang.org/x/sys/unix/pagesize_unix.go | 15 + vendor/golang.org/x/sys/unix/race.go | 30 + vendor/golang.org/x/sys/unix/race0.go | 25 + .../golang.org/x/sys/unix/sockcmsg_linux.go | 36 + vendor/golang.org/x/sys/unix/sockcmsg_unix.go | 104 + vendor/golang.org/x/sys/unix/str.go | 26 + vendor/golang.org/x/sys/unix/syscall.go | 51 + vendor/golang.org/x/sys/unix/syscall_bsd.go | 644 + .../golang.org/x/sys/unix/syscall_darwin.go | 535 + .../x/sys/unix/syscall_darwin_386.go | 68 + .../x/sys/unix/syscall_darwin_amd64.go | 68 + .../x/sys/unix/syscall_darwin_arm.go | 62 + .../x/sys/unix/syscall_darwin_arm64.go | 68 + .../x/sys/unix/syscall_dragonfly.go | 413 + .../x/sys/unix/syscall_dragonfly_amd64.go | 52 + .../golang.org/x/sys/unix/syscall_freebsd.go | 707 + .../x/sys/unix/syscall_freebsd_386.go | 52 + .../x/sys/unix/syscall_freebsd_amd64.go | 52 + .../x/sys/unix/syscall_freebsd_arm.go | 52 + vendor/golang.org/x/sys/unix/syscall_linux.go | 1470 + .../x/sys/unix/syscall_linux_386.go | 390 + .../x/sys/unix/syscall_linux_amd64.go | 143 + .../x/sys/unix/syscall_linux_amd64_gc.go | 13 + .../x/sys/unix/syscall_linux_arm.go | 254 + .../x/sys/unix/syscall_linux_arm64.go | 186 + .../x/sys/unix/syscall_linux_mips64x.go | 205 + .../x/sys/unix/syscall_linux_mipsx.go | 230 + .../x/sys/unix/syscall_linux_ppc64x.go | 126 + .../x/sys/unix/syscall_linux_s390x.go | 319 + .../x/sys/unix/syscall_linux_sparc64.go | 142 + .../golang.org/x/sys/unix/syscall_netbsd.go | 471 + .../x/sys/unix/syscall_netbsd_386.go | 33 + .../x/sys/unix/syscall_netbsd_amd64.go | 33 + .../x/sys/unix/syscall_netbsd_arm.go | 33 + .../golang.org/x/sys/unix/syscall_no_getwd.go | 11 + .../golang.org/x/sys/unix/syscall_openbsd.go | 281 + .../x/sys/unix/syscall_openbsd_386.go | 33 + .../x/sys/unix/syscall_openbsd_amd64.go | 33 + .../x/sys/unix/syscall_openbsd_arm.go | 33 + .../golang.org/x/sys/unix/syscall_solaris.go | 728 + .../x/sys/unix/syscall_solaris_amd64.go | 28 + vendor/golang.org/x/sys/unix/syscall_unix.go | 293 + .../golang.org/x/sys/unix/syscall_unix_gc.go | 15 + vendor/golang.org/x/sys/unix/timestruct.go | 62 + vendor/golang.org/x/sys/unix/types_darwin.go | 272 + .../golang.org/x/sys/unix/types_dragonfly.go | 267 + vendor/golang.org/x/sys/unix/types_freebsd.go | 391 + vendor/golang.org/x/sys/unix/types_netbsd.go | 257 + vendor/golang.org/x/sys/unix/types_openbsd.go | 269 + vendor/golang.org/x/sys/unix/types_solaris.go | 283 + .../x/sys/unix/zerrors_darwin_386.go | 1673 + .../x/sys/unix/zerrors_darwin_amd64.go | 1673 + .../x/sys/unix/zerrors_darwin_arm.go | 1673 + .../x/sys/unix/zerrors_darwin_arm64.go | 1673 + .../x/sys/unix/zerrors_dragonfly_amd64.go | 1568 + .../x/sys/unix/zerrors_freebsd_386.go | 1749 + .../x/sys/unix/zerrors_freebsd_amd64.go | 1750 + .../x/sys/unix/zerrors_freebsd_arm.go | 1758 + .../x/sys/unix/zerrors_linux_386.go | 2244 + .../x/sys/unix/zerrors_linux_amd64.go | 2245 + .../x/sys/unix/zerrors_linux_arm.go | 2249 + .../x/sys/unix/zerrors_linux_arm64.go | 2235 + .../x/sys/unix/zerrors_linux_mips.go | 2254 + .../x/sys/unix/zerrors_linux_mips64.go | 2254 + .../x/sys/unix/zerrors_linux_mips64le.go | 2254 + .../x/sys/unix/zerrors_linux_mipsle.go | 2254 + .../x/sys/unix/zerrors_linux_ppc64.go | 2307 + .../x/sys/unix/zerrors_linux_ppc64le.go | 2307 + .../x/sys/unix/zerrors_linux_s390x.go | 2306 + .../x/sys/unix/zerrors_linux_sparc64.go | 2142 + .../x/sys/unix/zerrors_netbsd_386.go | 1712 + .../x/sys/unix/zerrors_netbsd_amd64.go | 1702 + .../x/sys/unix/zerrors_netbsd_arm.go | 1691 + .../x/sys/unix/zerrors_openbsd_386.go | 1584 + .../x/sys/unix/zerrors_openbsd_amd64.go | 1583 + .../x/sys/unix/zerrors_openbsd_arm.go | 1586 + .../x/sys/unix/zerrors_solaris_amd64.go | 1489 + .../golang.org/x/sys/unix/zptrace386_linux.go | 80 + .../golang.org/x/sys/unix/zptracearm_linux.go | 41 + .../x/sys/unix/zptracemips_linux.go | 50 + .../x/sys/unix/zptracemipsle_linux.go | 50 + .../x/sys/unix/zsyscall_darwin_386.go | 1620 + .../x/sys/unix/zsyscall_darwin_amd64.go | 1620 + .../x/sys/unix/zsyscall_darwin_arm.go | 1620 + .../x/sys/unix/zsyscall_darwin_arm64.go | 1620 + .../x/sys/unix/zsyscall_dragonfly_amd64.go | 1451 + .../x/sys/unix/zsyscall_freebsd_386.go | 1888 + .../x/sys/unix/zsyscall_freebsd_amd64.go | 1888 + .../x/sys/unix/zsyscall_freebsd_arm.go | 1888 + .../x/sys/unix/zsyscall_linux_386.go | 1964 + .../x/sys/unix/zsyscall_linux_amd64.go | 2157 + .../x/sys/unix/zsyscall_linux_arm.go | 2066 + .../x/sys/unix/zsyscall_linux_arm64.go | 2029 + .../x/sys/unix/zsyscall_linux_mips.go | 2122 + .../x/sys/unix/zsyscall_linux_mips64.go | 2105 + .../x/sys/unix/zsyscall_linux_mips64le.go | 2105 + .../x/sys/unix/zsyscall_linux_mipsle.go | 2122 + .../x/sys/unix/zsyscall_linux_ppc64.go | 2168 + .../x/sys/unix/zsyscall_linux_ppc64le.go | 2168 + .../x/sys/unix/zsyscall_linux_s390x.go | 1948 + .../x/sys/unix/zsyscall_linux_sparc64.go | 1833 + .../x/sys/unix/zsyscall_netbsd_386.go | 1357 + .../x/sys/unix/zsyscall_netbsd_amd64.go | 1357 + .../x/sys/unix/zsyscall_netbsd_arm.go | 1357 + .../x/sys/unix/zsyscall_openbsd_386.go | 1415 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 1415 + .../x/sys/unix/zsyscall_openbsd_arm.go | 1415 + .../x/sys/unix/zsyscall_solaris_amd64.go | 1642 + .../x/sys/unix/zsysctl_openbsd_386.go | 270 + .../x/sys/unix/zsysctl_openbsd_amd64.go | 270 + .../x/sys/unix/zsysctl_openbsd_arm.go | 270 + .../x/sys/unix/zsysnum_darwin_386.go | 398 + .../x/sys/unix/zsysnum_darwin_amd64.go | 398 + .../x/sys/unix/zsysnum_darwin_arm.go | 426 + .../x/sys/unix/zsysnum_darwin_arm64.go | 426 + .../x/sys/unix/zsysnum_dragonfly_amd64.go | 315 + .../x/sys/unix/zsysnum_freebsd_386.go | 353 + .../x/sys/unix/zsysnum_freebsd_amd64.go | 353 + .../x/sys/unix/zsysnum_freebsd_arm.go | 353 + .../x/sys/unix/zsysnum_linux_386.go | 390 + .../x/sys/unix/zsysnum_linux_amd64.go | 342 + .../x/sys/unix/zsysnum_linux_arm.go | 362 + .../x/sys/unix/zsysnum_linux_arm64.go | 286 + .../x/sys/unix/zsysnum_linux_mips.go | 375 + .../x/sys/unix/zsysnum_linux_mips64.go | 335 + .../x/sys/unix/zsysnum_linux_mips64le.go | 335 + .../x/sys/unix/zsysnum_linux_mipsle.go | 375 + .../x/sys/unix/zsysnum_linux_ppc64.go | 370 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 370 + .../x/sys/unix/zsysnum_linux_s390x.go | 333 + .../x/sys/unix/zsysnum_linux_sparc64.go | 348 + .../x/sys/unix/zsysnum_netbsd_386.go | 274 + .../x/sys/unix/zsysnum_netbsd_amd64.go | 274 + .../x/sys/unix/zsysnum_netbsd_arm.go | 274 + .../x/sys/unix/zsysnum_openbsd_386.go | 207 + .../x/sys/unix/zsysnum_openbsd_amd64.go | 207 + .../x/sys/unix/zsysnum_openbsd_arm.go | 213 + .../x/sys/unix/zsysnum_solaris_amd64.go | 13 + .../x/sys/unix/ztypes_darwin_386.go | 481 + .../x/sys/unix/ztypes_darwin_amd64.go | 491 + .../x/sys/unix/ztypes_darwin_arm.go | 482 + .../x/sys/unix/ztypes_darwin_arm64.go | 491 + .../x/sys/unix/ztypes_dragonfly_amd64.go | 467 + .../x/sys/unix/ztypes_freebsd_386.go | 541 + .../x/sys/unix/ztypes_freebsd_amd64.go | 544 + .../x/sys/unix/ztypes_freebsd_arm.go | 544 + .../golang.org/x/sys/unix/ztypes_linux_386.go | 793 + .../x/sys/unix/ztypes_linux_amd64.go | 811 + .../golang.org/x/sys/unix/ztypes_linux_arm.go | 782 + .../x/sys/unix/ztypes_linux_arm64.go | 790 + .../x/sys/unix/ztypes_linux_mips.go | 787 + .../x/sys/unix/ztypes_linux_mips64.go | 792 + .../x/sys/unix/ztypes_linux_mips64le.go | 792 + .../x/sys/unix/ztypes_linux_mipsle.go | 787 + .../x/sys/unix/ztypes_linux_ppc64.go | 800 + .../x/sys/unix/ztypes_linux_ppc64le.go | 800 + .../x/sys/unix/ztypes_linux_s390x.go | 817 + .../x/sys/unix/ztypes_linux_sparc64.go | 664 + .../x/sys/unix/ztypes_netbsd_386.go | 420 + .../x/sys/unix/ztypes_netbsd_amd64.go | 427 + .../x/sys/unix/ztypes_netbsd_arm.go | 425 + .../x/sys/unix/ztypes_openbsd_386.go | 465 + .../x/sys/unix/ztypes_openbsd_amd64.go | 472 + .../x/sys/unix/ztypes_openbsd_arm.go | 458 + .../x/sys/unix/ztypes_solaris_amd64.go | 459 + .../x/sys/windows/asm_windows_386.s | 13 + .../x/sys/windows/asm_windows_amd64.s | 13 + .../golang.org/x/sys/windows/dll_windows.go | 378 + vendor/golang.org/x/sys/windows/env_unset.go | 15 + .../golang.org/x/sys/windows/env_windows.go | 25 + vendor/golang.org/x/sys/windows/eventlog.go | 20 + .../golang.org/x/sys/windows/exec_windows.go | 97 + .../x/sys/windows/memory_windows.go | 26 + vendor/golang.org/x/sys/windows/mksyscall.go | 7 + vendor/golang.org/x/sys/windows/race.go | 30 + vendor/golang.org/x/sys/windows/race0.go | 25 + .../x/sys/windows/security_windows.go | 435 + vendor/golang.org/x/sys/windows/service.go | 164 + vendor/golang.org/x/sys/windows/str.go | 22 + vendor/golang.org/x/sys/windows/syscall.go | 71 + .../x/sys/windows/syscall_windows.go | 1024 + .../golang.org/x/sys/windows/types_windows.go | 1282 + .../x/sys/windows/types_windows_386.go | 22 + .../x/sys/windows/types_windows_amd64.go | 22 + .../x/sys/windows/zsyscall_windows.go | 2428 + vendor/golang.org/x/text/AUTHORS | 3 + vendor/golang.org/x/text/CONTRIBUTORS | 3 + vendor/golang.org/x/text/LICENSE | 27 + vendor/golang.org/x/text/PATENTS | 22 + vendor/golang.org/x/text/cases/cases.go | 162 + vendor/golang.org/x/text/cases/context.go | 376 + vendor/golang.org/x/text/cases/fold.go | 34 + vendor/golang.org/x/text/cases/gen.go | 839 + vendor/golang.org/x/text/cases/gen_trieval.go | 219 + vendor/golang.org/x/text/cases/icu.go | 61 + vendor/golang.org/x/text/cases/info.go | 82 + vendor/golang.org/x/text/cases/map.go | 816 + vendor/golang.org/x/text/cases/tables.go | 2211 + vendor/golang.org/x/text/cases/trieval.go | 215 + vendor/golang.org/x/text/internal/gen.go | 52 + vendor/golang.org/x/text/internal/gen/code.go | 351 + vendor/golang.org/x/text/internal/gen/gen.go | 281 + vendor/golang.org/x/text/internal/internal.go | 51 + vendor/golang.org/x/text/internal/match.go | 67 + vendor/golang.org/x/text/internal/tables.go | 117 + vendor/golang.org/x/text/internal/tag/tag.go | 100 + .../x/text/internal/triegen/compact.go | 58 + .../x/text/internal/triegen/print.go | 251 + .../x/text/internal/triegen/triegen.go | 494 + vendor/golang.org/x/text/internal/ucd/ucd.go | 376 + vendor/golang.org/x/text/language/Makefile | 16 + vendor/golang.org/x/text/language/common.go | 16 + vendor/golang.org/x/text/language/coverage.go | 197 + vendor/golang.org/x/text/language/gen.go | 1699 + .../golang.org/x/text/language/gen_common.go | 20 + .../golang.org/x/text/language/gen_index.go | 162 + vendor/golang.org/x/text/language/go1_1.go | 38 + vendor/golang.org/x/text/language/go1_2.go | 11 + vendor/golang.org/x/text/language/index.go | 769 + vendor/golang.org/x/text/language/language.go | 982 + vendor/golang.org/x/text/language/lookup.go | 396 + vendor/golang.org/x/text/language/match.go | 933 + vendor/golang.org/x/text/language/parse.go | 859 + vendor/golang.org/x/text/language/tables.go | 3654 ++ vendor/golang.org/x/text/language/tags.go | 143 + vendor/golang.org/x/text/runes/cond.go | 187 + vendor/golang.org/x/text/runes/runes.go | 355 + .../x/text/secure/bidirule/bidirule.go | 342 + .../golang.org/x/text/secure/precis/class.go | 36 + .../x/text/secure/precis/context.go | 139 + vendor/golang.org/x/text/secure/precis/doc.go | 14 + vendor/golang.org/x/text/secure/precis/gen.go | 310 + .../x/text/secure/precis/gen_trieval.go | 68 + .../x/text/secure/precis/nickname.go | 70 + .../x/text/secure/precis/options.go | 153 + .../x/text/secure/precis/profile.go | 378 + .../x/text/secure/precis/profiles.go | 78 + .../golang.org/x/text/secure/precis/tables.go | 3788 ++ .../x/text/secure/precis/transformer.go | 32 + .../x/text/secure/precis/trieval.go | 64 + .../golang.org/x/text/transform/transform.go | 705 + vendor/golang.org/x/text/unicode/bidi/bidi.go | 198 + .../golang.org/x/text/unicode/bidi/bracket.go | 335 + vendor/golang.org/x/text/unicode/bidi/core.go | 1058 + vendor/golang.org/x/text/unicode/bidi/gen.go | 133 + .../x/text/unicode/bidi/gen_ranges.go | 57 + .../x/text/unicode/bidi/gen_trieval.go | 64 + vendor/golang.org/x/text/unicode/bidi/prop.go | 206 + .../golang.org/x/text/unicode/bidi/tables.go | 1779 + .../golang.org/x/text/unicode/bidi/trieval.go | 60 + vendor/golang.org/x/text/unicode/cldr/base.go | 100 + vendor/golang.org/x/text/unicode/cldr/cldr.go | 130 + .../golang.org/x/text/unicode/cldr/collate.go | 359 + .../golang.org/x/text/unicode/cldr/decode.go | 171 + .../golang.org/x/text/unicode/cldr/makexml.go | 400 + .../golang.org/x/text/unicode/cldr/resolve.go | 602 + .../golang.org/x/text/unicode/cldr/slice.go | 144 + vendor/golang.org/x/text/unicode/cldr/xml.go | 1487 + .../x/text/unicode/norm/composition.go | 508 + .../x/text/unicode/norm/forminfo.go | 259 + .../golang.org/x/text/unicode/norm/input.go | 109 + vendor/golang.org/x/text/unicode/norm/iter.go | 457 + .../x/text/unicode/norm/maketables.go | 976 + .../x/text/unicode/norm/normalize.go | 609 + .../x/text/unicode/norm/readwriter.go | 125 + .../golang.org/x/text/unicode/norm/tables.go | 7631 +++ .../x/text/unicode/norm/transform.go | 88 + vendor/golang.org/x/text/unicode/norm/trie.go | 54 + .../golang.org/x/text/unicode/norm/triegen.go | 117 + .../x/text/unicode/rangetable/gen.go | 113 + .../x/text/unicode/rangetable/merge.go | 260 + .../x/text/unicode/rangetable/rangetable.go | 70 + .../x/text/unicode/rangetable/tables.go | 5735 ++ vendor/golang.org/x/text/width/gen.go | 115 + vendor/golang.org/x/text/width/gen_common.go | 96 + vendor/golang.org/x/text/width/gen_trieval.go | 34 + vendor/golang.org/x/text/width/kind_string.go | 16 + vendor/golang.org/x/text/width/tables.go | 1284 + vendor/golang.org/x/text/width/transform.go | 239 + vendor/golang.org/x/text/width/trieval.go | 30 + vendor/golang.org/x/text/width/width.go | 206 + .../google.golang.org/appengine/.travis.yml | 24 + .../appengine/CONTRIBUTING.md | 90 + vendor/google.golang.org/appengine/LICENSE | 202 + vendor/google.golang.org/appengine/README.md | 73 + .../google.golang.org/appengine/appengine.go | 113 + .../appengine/appengine_vm.go | 20 + vendor/google.golang.org/appengine/errors.go | 46 + vendor/google.golang.org/appengine/go.mod | 7 + vendor/google.golang.org/appengine/go.sum | 3 + .../google.golang.org/appengine/identity.go | 142 + .../appengine/internal/api.go | 660 + .../appengine/internal/api_classic.go | 169 + .../appengine/internal/api_common.go | 123 + .../appengine/internal/api_pre17.go | 682 + .../appengine/internal/app_id.go | 28 + .../app_identity/app_identity_service.pb.go | 611 + .../app_identity/app_identity_service.proto | 64 + .../appengine/internal/base/api_base.pb.go | 308 + .../appengine/internal/base/api_base.proto | 33 + .../internal/datastore/datastore_v3.pb.go | 4367 ++ .../internal/datastore/datastore_v3.proto | 551 + .../appengine/internal/identity.go | 14 + .../appengine/internal/identity_classic.go | 57 + .../appengine/internal/identity_vm.go | 134 + .../appengine/internal/internal.go | 110 + .../appengine/internal/log/log_service.pb.go | 1313 + .../appengine/internal/log/log_service.proto | 150 + .../appengine/internal/main.go | 15 + .../appengine/internal/main_vm.go | 48 + .../appengine/internal/metadata.go | 60 + .../internal/modules/modules_service.pb.go | 786 + .../internal/modules/modules_service.proto | 80 + .../appengine/internal/net.go | 56 + .../appengine/internal/regen.sh | 40 + .../internal/remote_api/remote_api.pb.go | 361 + .../internal/remote_api/remote_api.proto | 44 + .../appengine/internal/transaction.go | 115 + .../internal/urlfetch/urlfetch_service.pb.go | 527 + .../internal/urlfetch/urlfetch_service.proto | 64 + .../google.golang.org/appengine/namespace.go | 25 + vendor/google.golang.org/appengine/timeout.go | 20 + .../appengine/urlfetch/urlfetch.go | 210 + vendor/gopkg.in/inf.v0/LICENSE | 28 + vendor/gopkg.in/inf.v0/dec.go | 615 + vendor/gopkg.in/inf.v0/rounder.go | 145 + .../gopkg.in/ory-am/dockertest.v3/.gitignore | 6 + .../gopkg.in/ory-am/dockertest.v3/.travis.yml | 21 + .../ory-am/dockertest.v3/CONTRIBUTING.md | 127 + .../gopkg.in/ory-am/dockertest.v3/Gopkg.lock | 140 + .../gopkg.in/ory-am/dockertest.v3/Gopkg.toml | 46 + vendor/gopkg.in/ory-am/dockertest.v3/LICENSE | 202 + .../gopkg.in/ory-am/dockertest.v3/README.md | 127 + .../ory-am/dockertest.v3/dockertest.go | 278 + vendor/gopkg.in/robfig/cron.v2/.gitignore | 22 + vendor/gopkg.in/robfig/cron.v2/.travis.yml | 1 + vendor/gopkg.in/robfig/cron.v2/LICENSE | 21 + vendor/gopkg.in/robfig/cron.v2/README.md | 1 + .../gopkg.in/robfig/cron.v2/constantdelay.go | 27 + vendor/gopkg.in/robfig/cron.v2/cron.go | 236 + vendor/gopkg.in/robfig/cron.v2/doc.go | 132 + vendor/gopkg.in/robfig/cron.v2/parser.go | 246 + vendor/gopkg.in/robfig/cron.v2/spec.go | 165 + vendor/gopkg.in/yaml.v2/LICENSE | 188 + vendor/gopkg.in/yaml.v2/LICENSE.libyaml | 31 + vendor/gopkg.in/yaml.v2/README.md | 131 + vendor/gopkg.in/yaml.v2/apic.go | 742 + vendor/gopkg.in/yaml.v2/decode.go | 683 + vendor/gopkg.in/yaml.v2/emitterc.go | 1685 + vendor/gopkg.in/yaml.v2/encode.go | 306 + vendor/gopkg.in/yaml.v2/parserc.go | 1096 + vendor/gopkg.in/yaml.v2/readerc.go | 391 + vendor/gopkg.in/yaml.v2/resolve.go | 203 + vendor/gopkg.in/yaml.v2/scannerc.go | 2710 + vendor/gopkg.in/yaml.v2/sorter.go | 104 + vendor/gopkg.in/yaml.v2/writerc.go | 89 + vendor/gopkg.in/yaml.v2/yaml.go | 346 + vendor/gopkg.in/yaml.v2/yamlh.go | 716 + vendor/gopkg.in/yaml.v2/yamlprivateh.go | 173 + vendor/k8s.io/api/LICENSE | 202 + .../api/admissionregistration/v1alpha1/BUILD | 44 + .../api/admissionregistration/v1alpha1/doc.go | 25 + .../v1alpha1/generated.pb.go | 1028 + .../v1alpha1/generated.proto | 108 + .../v1alpha1/register.go | 51 + .../admissionregistration/v1alpha1/types.go | 106 + .../v1alpha1/types_swagger_doc_generated.go | 71 + .../v1alpha1/zz_generated.deepcopy.go | 147 + .../api/admissionregistration/v1beta1/BUILD | 44 + .../api/admissionregistration/v1beta1/doc.go | 25 + .../v1beta1/generated.pb.go | 2150 + .../v1beta1/generated.proto | 261 + .../admissionregistration/v1beta1/register.go | 53 + .../admissionregistration/v1beta1/types.go | 281 + .../v1beta1/types_swagger_doc_generated.go | 125 + .../v1beta1/zz_generated.deepcopy.go | 321 + vendor/k8s.io/api/apps/v1/BUILD | 43 + vendor/k8s.io/api/apps/v1/doc.go | 20 + vendor/k8s.io/api/apps/v1/generated.pb.go | 6945 +++ vendor/k8s.io/api/apps/v1/generated.proto | 701 + vendor/k8s.io/api/apps/v1/register.go | 60 + vendor/k8s.io/api/apps/v1/types.go | 819 + .../apps/v1/types_swagger_doc_generated.go | 365 + .../api/apps/v1/zz_generated.deepcopy.go | 866 + vendor/k8s.io/api/apps/v1beta1/BUILD | 47 + vendor/k8s.io/api/apps/v1beta1/doc.go | 20 + .../k8s.io/api/apps/v1beta1/generated.pb.go | 5291 ++ .../k8s.io/api/apps/v1beta1/generated.proto | 484 + vendor/k8s.io/api/apps/v1beta1/register.go | 58 + vendor/k8s.io/api/apps/v1beta1/types.go | 568 + .../v1beta1/types_swagger_doc_generated.go | 273 + .../api/apps/v1beta1/zz_generated.deepcopy.go | 666 + vendor/k8s.io/api/apps/v1beta2/BUILD | 47 + vendor/k8s.io/api/apps/v1beta2/doc.go | 20 + .../k8s.io/api/apps/v1beta2/generated.pb.go | 7586 +++ .../k8s.io/api/apps/v1beta2/generated.proto | 752 + vendor/k8s.io/api/apps/v1beta2/register.go | 61 + vendor/k8s.io/api/apps/v1beta2/types.go | 877 + .../v1beta2/types_swagger_doc_generated.go | 396 + .../api/apps/v1beta2/zz_generated.deepcopy.go | 934 + vendor/k8s.io/api/authentication/v1/BUILD | 45 + vendor/k8s.io/api/authentication/v1/doc.go | 20 + .../api/authentication/v1/generated.pb.go | 1302 + .../api/authentication/v1/generated.proto | 99 + .../k8s.io/api/authentication/v1/register.go | 51 + vendor/k8s.io/api/authentication/v1/types.go | 107 + .../v1/types_swagger_doc_generated.go | 72 + .../v1/zz_generated.deepcopy.go | 116 + .../k8s.io/api/authentication/v1beta1/BUILD | 45 + .../k8s.io/api/authentication/v1beta1/doc.go | 20 + .../authentication/v1beta1/generated.pb.go | 1302 + .../authentication/v1beta1/generated.proto | 99 + .../api/authentication/v1beta1/register.go | 51 + .../api/authentication/v1beta1/types.go | 92 + .../v1beta1/types_swagger_doc_generated.go | 72 + .../v1beta1/zz_generated.deepcopy.go | 116 + vendor/k8s.io/api/authorization/v1/BUILD | 45 + vendor/k8s.io/api/authorization/v1/doc.go | 21 + .../api/authorization/v1/generated.pb.go | 3528 ++ .../api/authorization/v1/generated.proto | 273 + .../k8s.io/api/authorization/v1/register.go | 55 + vendor/k8s.io/api/authorization/v1/types.go | 268 + .../v1/types_swagger_doc_generated.go | 173 + .../authorization/v1/zz_generated.deepcopy.go | 378 + vendor/k8s.io/api/authorization/v1beta1/BUILD | 45 + .../k8s.io/api/authorization/v1beta1/doc.go | 21 + .../api/authorization/v1beta1/generated.pb.go | 3529 ++ .../api/authorization/v1beta1/generated.proto | 273 + .../api/authorization/v1beta1/register.go | 55 + .../k8s.io/api/authorization/v1beta1/types.go | 268 + .../v1beta1/types_swagger_doc_generated.go | 173 + .../v1beta1/zz_generated.deepcopy.go | 378 + vendor/k8s.io/api/autoscaling/v1/BUILD | 46 + vendor/k8s.io/api/autoscaling/v1/doc.go | 20 + .../k8s.io/api/autoscaling/v1/generated.pb.go | 3786 ++ .../k8s.io/api/autoscaling/v1/generated.proto | 321 + vendor/k8s.io/api/autoscaling/v1/register.go | 53 + vendor/k8s.io/api/autoscaling/v1/types.go | 337 + .../v1/types_swagger_doc_generated.go | 218 + .../autoscaling/v1/zz_generated.deepcopy.go | 478 + vendor/k8s.io/api/autoscaling/v2beta1/BUILD | 46 + vendor/k8s.io/api/autoscaling/v2beta1/doc.go | 20 + .../api/autoscaling/v2beta1/generated.pb.go | 3401 ++ .../api/autoscaling/v2beta1/generated.proto | 301 + .../api/autoscaling/v2beta1/register.go | 52 + .../k8s.io/api/autoscaling/v2beta1/types.go | 312 + .../v2beta1/types_swagger_doc_generated.go | 189 + .../v2beta1/zz_generated.deepcopy.go | 420 + vendor/k8s.io/api/batch/v1/BUILD | 45 + vendor/k8s.io/api/batch/v1/doc.go | 20 + vendor/k8s.io/api/batch/v1/generated.pb.go | 1615 + vendor/k8s.io/api/batch/v1/generated.proto | 173 + vendor/k8s.io/api/batch/v1/register.go | 52 + vendor/k8s.io/api/batch/v1/types.go | 181 + .../batch/v1/types_swagger_doc_generated.go | 94 + .../api/batch/v1/zz_generated.deepcopy.go | 219 + vendor/k8s.io/api/batch/v1beta1/BUILD | 46 + vendor/k8s.io/api/batch/v1beta1/doc.go | 20 + .../k8s.io/api/batch/v1beta1/generated.pb.go | 1509 + .../k8s.io/api/batch/v1beta1/generated.proto | 138 + vendor/k8s.io/api/batch/v1beta1/register.go | 53 + vendor/k8s.io/api/batch/v1beta1/types.go | 158 + .../v1beta1/types_swagger_doc_generated.go | 96 + .../batch/v1beta1/zz_generated.deepcopy.go | 219 + vendor/k8s.io/api/batch/v2alpha1/BUILD | 46 + vendor/k8s.io/api/batch/v2alpha1/doc.go | 20 + .../k8s.io/api/batch/v2alpha1/generated.pb.go | 1510 + .../k8s.io/api/batch/v2alpha1/generated.proto | 136 + vendor/k8s.io/api/batch/v2alpha1/register.go | 53 + vendor/k8s.io/api/batch/v2alpha1/types.go | 156 + .../v2alpha1/types_swagger_doc_generated.go | 96 + .../batch/v2alpha1/zz_generated.deepcopy.go | 219 + vendor/k8s.io/api/certificates/v1beta1/BUILD | 45 + vendor/k8s.io/api/certificates/v1beta1/doc.go | 21 + .../api/certificates/v1beta1/generated.pb.go | 1693 + .../api/certificates/v1beta1/generated.proto | 122 + .../api/certificates/v1beta1/register.go | 59 + .../k8s.io/api/certificates/v1beta1/types.go | 155 + .../v1beta1/types_swagger_doc_generated.go | 74 + .../v1beta1/zz_generated.deepcopy.go | 172 + vendor/k8s.io/api/core/v1/BUILD | 65 + .../api/core/v1/annotation_key_constants.go | 88 + vendor/k8s.io/api/core/v1/doc.go | 21 + vendor/k8s.io/api/core/v1/generated.pb.go | 49890 ++++++++++++++++ vendor/k8s.io/api/core/v1/generated.proto | 4572 ++ vendor/k8s.io/api/core/v1/meta.go | 108 + vendor/k8s.io/api/core/v1/objectreference.go | 33 + vendor/k8s.io/api/core/v1/register.go | 102 + vendor/k8s.io/api/core/v1/resource.go | 63 + vendor/k8s.io/api/core/v1/taint.go | 33 + vendor/k8s.io/api/core/v1/toleration.go | 56 + vendor/k8s.io/api/core/v1/types.go | 5167 ++ .../core/v1/types_swagger_doc_generated.go | 2231 + .../api/core/v1/zz_generated.deepcopy.go | 5864 ++ vendor/k8s.io/api/events/v1beta1/BUILD | 42 + vendor/k8s.io/api/events/v1beta1/doc.go | 21 + .../k8s.io/api/events/v1beta1/generated.pb.go | 1306 + .../k8s.io/api/events/v1beta1/generated.proto | 122 + vendor/k8s.io/api/events/v1beta1/register.go | 53 + vendor/k8s.io/api/events/v1beta1/types.go | 122 + .../v1beta1/types_swagger_doc_generated.go | 73 + .../events/v1beta1/zz_generated.deepcopy.go | 127 + vendor/k8s.io/api/extensions/v1beta1/BUILD | 49 + vendor/k8s.io/api/extensions/v1beta1/doc.go | 20 + .../api/extensions/v1beta1/generated.pb.go | 12513 ++++ .../api/extensions/v1beta1/generated.proto | 1117 + .../k8s.io/api/extensions/v1beta1/register.go | 66 + vendor/k8s.io/api/extensions/v1beta1/types.go | 1292 + .../v1beta1/types_swagger_doc_generated.go | 644 + .../v1beta1/zz_generated.deepcopy.go | 1603 + vendor/k8s.io/api/networking/v1/BUILD | 46 + vendor/k8s.io/api/networking/v1/doc.go | 20 + .../k8s.io/api/networking/v1/generated.pb.go | 1869 + .../k8s.io/api/networking/v1/generated.proto | 190 + vendor/k8s.io/api/networking/v1/register.go | 53 + vendor/k8s.io/api/networking/v1/types.go | 196 + .../v1/types_swagger_doc_generated.go | 113 + .../networking/v1/zz_generated.deepcopy.go | 284 + vendor/k8s.io/api/policy/v1beta1/BUILD | 46 + vendor/k8s.io/api/policy/v1beta1/doc.go | 23 + .../k8s.io/api/policy/v1beta1/generated.pb.go | 1454 + .../k8s.io/api/policy/v1beta1/generated.proto | 114 + vendor/k8s.io/api/policy/v1beta1/register.go | 54 + vendor/k8s.io/api/policy/v1beta1/types.go | 115 + .../v1beta1/types_swagger_doc_generated.go | 83 + .../policy/v1beta1/zz_generated.deepcopy.go | 192 + vendor/k8s.io/api/rbac/v1/BUILD | 44 + vendor/k8s.io/api/rbac/v1/doc.go | 21 + vendor/k8s.io/api/rbac/v1/generated.pb.go | 2749 + vendor/k8s.io/api/rbac/v1/generated.proto | 197 + vendor/k8s.io/api/rbac/v1/register.go | 58 + vendor/k8s.io/api/rbac/v1/types.go | 233 + .../rbac/v1/types_swagger_doc_generated.go | 158 + .../api/rbac/v1/zz_generated.deepcopy.go | 401 + vendor/k8s.io/api/rbac/v1alpha1/BUILD | 44 + vendor/k8s.io/api/rbac/v1alpha1/doc.go | 21 + .../k8s.io/api/rbac/v1alpha1/generated.pb.go | 2750 + .../k8s.io/api/rbac/v1alpha1/generated.proto | 198 + vendor/k8s.io/api/rbac/v1alpha1/register.go | 58 + vendor/k8s.io/api/rbac/v1alpha1/types.go | 235 + .../v1alpha1/types_swagger_doc_generated.go | 158 + .../rbac/v1alpha1/zz_generated.deepcopy.go | 401 + vendor/k8s.io/api/rbac/v1beta1/BUILD | 44 + vendor/k8s.io/api/rbac/v1beta1/doc.go | 21 + .../k8s.io/api/rbac/v1beta1/generated.pb.go | 2750 + .../k8s.io/api/rbac/v1beta1/generated.proto | 198 + vendor/k8s.io/api/rbac/v1beta1/register.go | 58 + vendor/k8s.io/api/rbac/v1beta1/types.go | 233 + .../v1beta1/types_swagger_doc_generated.go | 158 + .../api/rbac/v1beta1/zz_generated.deepcopy.go | 401 + vendor/k8s.io/api/scheduling/v1alpha1/BUILD | 44 + vendor/k8s.io/api/scheduling/v1alpha1/doc.go | 21 + .../api/scheduling/v1alpha1/generated.pb.go | 641 + .../api/scheduling/v1alpha1/generated.proto | 65 + .../api/scheduling/v1alpha1/register.go | 52 + .../k8s.io/api/scheduling/v1alpha1/types.go | 63 + .../v1alpha1/types_swagger_doc_generated.go | 52 + .../v1alpha1/zz_generated.deepcopy.go | 86 + vendor/k8s.io/api/settings/v1alpha1/BUILD | 45 + vendor/k8s.io/api/settings/v1alpha1/doc.go | 21 + .../api/settings/v1alpha1/generated.pb.go | 930 + .../api/settings/v1alpha1/generated.proto | 76 + .../k8s.io/api/settings/v1alpha1/register.go | 52 + vendor/k8s.io/api/settings/v1alpha1/types.go | 70 + .../v1alpha1/types_swagger_doc_generated.go | 61 + .../v1alpha1/zz_generated.deepcopy.go | 133 + vendor/k8s.io/api/storage/v1/BUILD | 43 + vendor/k8s.io/api/storage/v1/doc.go | 20 + vendor/k8s.io/api/storage/v1/generated.pb.go | 926 + vendor/k8s.io/api/storage/v1/generated.proto | 85 + vendor/k8s.io/api/storage/v1/register.go | 53 + vendor/k8s.io/api/storage/v1/types.go | 98 + .../storage/v1/types_swagger_doc_generated.go | 55 + .../api/storage/v1/zz_generated.deepcopy.go | 126 + vendor/k8s.io/api/storage/v1alpha1/BUILD | 42 + vendor/k8s.io/api/storage/v1alpha1/doc.go | 20 + .../api/storage/v1alpha1/generated.pb.go | 1523 + .../api/storage/v1alpha1/generated.proto | 128 + .../k8s.io/api/storage/v1alpha1/register.go | 50 + vendor/k8s.io/api/storage/v1alpha1/types.go | 126 + .../v1alpha1/types_swagger_doc_generated.go | 93 + .../storage/v1alpha1/zz_generated.deepcopy.go | 188 + vendor/k8s.io/api/storage/v1beta1/BUILD | 43 + vendor/k8s.io/api/storage/v1beta1/doc.go | 20 + .../api/storage/v1beta1/generated.pb.go | 926 + .../api/storage/v1beta1/generated.proto | 85 + vendor/k8s.io/api/storage/v1beta1/register.go | 53 + vendor/k8s.io/api/storage/v1beta1/types.go | 98 + .../v1beta1/types_swagger_doc_generated.go | 55 + .../storage/v1beta1/zz_generated.deepcopy.go | 126 + vendor/k8s.io/apimachinery/LICENSE | 202 + .../k8s.io/apimachinery/pkg/api/errors/BUILD | 48 + .../k8s.io/apimachinery/pkg/api/errors/OWNERS | 25 + .../k8s.io/apimachinery/pkg/api/errors/doc.go | 18 + .../apimachinery/pkg/api/errors/errors.go | 546 + vendor/k8s.io/apimachinery/pkg/api/meta/BUILD | 69 + .../k8s.io/apimachinery/pkg/api/meta/OWNERS | 25 + .../k8s.io/apimachinery/pkg/api/meta/doc.go | 19 + .../apimachinery/pkg/api/meta/errors.go | 105 + .../pkg/api/meta/firsthit_restmapper.go | 97 + .../k8s.io/apimachinery/pkg/api/meta/help.go | 205 + .../apimachinery/pkg/api/meta/interfaces.go | 149 + .../k8s.io/apimachinery/pkg/api/meta/lazy.go | 121 + .../k8s.io/apimachinery/pkg/api/meta/meta.go | 653 + .../pkg/api/meta/multirestmapper.go | 210 + .../apimachinery/pkg/api/meta/priority.go | 222 + .../apimachinery/pkg/api/meta/restmapper.go | 548 + .../apimachinery/pkg/api/meta/unstructured.go | 47 + .../apimachinery/pkg/api/resource/BUILD | 73 + .../apimachinery/pkg/api/resource/OWNERS | 17 + .../apimachinery/pkg/api/resource/amount.go | 299 + .../pkg/api/resource/generated.pb.go | 77 + .../pkg/api/resource/generated.proto | 95 + .../apimachinery/pkg/api/resource/math.go | 314 + .../apimachinery/pkg/api/resource/quantity.go | 793 + .../pkg/api/resource/quantity_proto.go | 284 + .../pkg/api/resource/scale_int.go | 95 + .../apimachinery/pkg/api/resource/suffix.go | 198 + .../pkg/api/resource/zz_generated.deepcopy.go | 27 + .../apimachinery/pkg/apis/meta/v1/BUILD | 105 + .../apimachinery/pkg/apis/meta/v1/OWNERS | 32 + .../pkg/apis/meta/v1/controller_ref.go | 54 + .../pkg/apis/meta/v1/conversion.go | 288 + .../apimachinery/pkg/apis/meta/v1/doc.go | 22 + .../apimachinery/pkg/apis/meta/v1/duration.go | 47 + .../pkg/apis/meta/v1/generated.pb.go | 7961 +++ .../pkg/apis/meta/v1/generated.proto | 837 + .../pkg/apis/meta/v1/group_version.go | 148 + .../apimachinery/pkg/apis/meta/v1/helpers.go | 234 + .../apimachinery/pkg/apis/meta/v1/labels.go | 75 + .../apimachinery/pkg/apis/meta/v1/meta.go | 216 + .../pkg/apis/meta/v1/micro_time.go | 184 + .../pkg/apis/meta/v1/micro_time_proto.go | 72 + .../apimachinery/pkg/apis/meta/v1/register.go | 93 + .../apimachinery/pkg/apis/meta/v1/time.go | 186 + .../pkg/apis/meta/v1/time_proto.go | 92 + .../apimachinery/pkg/apis/meta/v1/types.go | 936 + .../meta/v1/types_swagger_doc_generated.go | 330 + .../pkg/apis/meta/v1/unstructured/BUILD | 54 + .../pkg/apis/meta/v1/unstructured/helpers.go | 453 + .../apis/meta/v1/unstructured/unstructured.go | 379 + .../meta/v1/unstructured/unstructured_list.go | 189 + .../v1/unstructured/zz_generated.deepcopy.go | 57 + .../apimachinery/pkg/apis/meta/v1/watch.go | 89 + .../pkg/apis/meta/v1/zz_generated.deepcopy.go | 942 + .../pkg/apis/meta/v1/zz_generated.defaults.go | 32 + .../apimachinery/pkg/apis/meta/v1alpha1/BUILD | 48 + .../pkg/apis/meta/v1alpha1/conversion.go | 27 + .../pkg/apis/meta/v1alpha1/deepcopy.go | 61 + .../pkg/apis/meta/v1alpha1/doc.go | 22 + .../pkg/apis/meta/v1alpha1/generated.pb.go | 633 + .../pkg/apis/meta/v1alpha1/generated.proto | 58 + .../pkg/apis/meta/v1alpha1/register.go | 57 + .../pkg/apis/meta/v1alpha1/types.go | 161 + .../v1alpha1/types_swagger_doc_generated.go | 104 + .../meta/v1alpha1/zz_generated.deepcopy.go | 194 + .../meta/v1alpha1/zz_generated.defaults.go | 32 + .../k8s.io/apimachinery/pkg/conversion/BUILD | 50 + .../apimachinery/pkg/conversion/converter.go | 898 + .../apimachinery/pkg/conversion/deep_equal.go | 36 + .../k8s.io/apimachinery/pkg/conversion/doc.go | 24 + .../apimachinery/pkg/conversion/helper.go | 39 + .../pkg/conversion/queryparams/BUILD | 40 + .../pkg/conversion/queryparams/convert.go | 195 + .../pkg/conversion/queryparams/doc.go | 19 + vendor/k8s.io/apimachinery/pkg/fields/BUILD | 42 + vendor/k8s.io/apimachinery/pkg/fields/doc.go | 19 + .../k8s.io/apimachinery/pkg/fields/fields.go | 62 + .../apimachinery/pkg/fields/requirements.go | 30 + .../apimachinery/pkg/fields/selector.go | 455 + vendor/k8s.io/apimachinery/pkg/labels/BUILD | 51 + vendor/k8s.io/apimachinery/pkg/labels/doc.go | 19 + .../k8s.io/apimachinery/pkg/labels/labels.go | 181 + .../apimachinery/pkg/labels/selector.go | 879 + .../pkg/labels/zz_generated.deepcopy.go | 42 + vendor/k8s.io/apimachinery/pkg/runtime/BUILD | 100 + .../k8s.io/apimachinery/pkg/runtime/codec.go | 330 + .../apimachinery/pkg/runtime/codec_check.go | 48 + .../apimachinery/pkg/runtime/conversion.go | 113 + .../apimachinery/pkg/runtime/converter.go | 793 + vendor/k8s.io/apimachinery/pkg/runtime/doc.go | 45 + .../apimachinery/pkg/runtime/embedded.go | 142 + .../k8s.io/apimachinery/pkg/runtime/error.go | 113 + .../apimachinery/pkg/runtime/extension.go | 51 + .../apimachinery/pkg/runtime/generated.pb.go | 773 + .../apimachinery/pkg/runtime/generated.proto | 129 + .../k8s.io/apimachinery/pkg/runtime/helper.go | 212 + .../apimachinery/pkg/runtime/interfaces.go | 249 + .../apimachinery/pkg/runtime/register.go | 61 + .../apimachinery/pkg/runtime/schema/BUILD | 44 + .../pkg/runtime/schema/generated.pb.go | 65 + .../pkg/runtime/schema/generated.proto | 28 + .../pkg/runtime/schema/group_version.go | 277 + .../pkg/runtime/schema/interfaces.go | 40 + .../k8s.io/apimachinery/pkg/runtime/scheme.go | 621 + .../pkg/runtime/scheme_builder.go | 48 + .../apimachinery/pkg/runtime/serializer/BUILD | 65 + .../pkg/runtime/serializer/codec_factory.go | 237 + .../pkg/runtime/serializer/json/BUILD | 57 + .../pkg/runtime/serializer/json/json.go | 278 + .../pkg/runtime/serializer/json/meta.go | 63 + .../runtime/serializer/negotiated_codec.go | 43 + .../pkg/runtime/serializer/protobuf/BUILD | 35 + .../pkg/runtime/serializer/protobuf/doc.go | 18 + .../runtime/serializer/protobuf/protobuf.go | 448 + .../runtime/serializer/protobuf_extension.go | 48 + .../pkg/runtime/serializer/recognizer/BUILD | 32 + .../serializer/recognizer/recognizer.go | 127 + .../pkg/runtime/serializer/streaming/BUILD | 42 + .../runtime/serializer/streaming/streaming.go | 137 + .../pkg/runtime/serializer/versioning/BUILD | 42 + .../serializer/versioning/versioning.go | 259 + .../pkg/runtime/swagger_doc_generator.go | 262 + .../k8s.io/apimachinery/pkg/runtime/types.go | 137 + .../apimachinery/pkg/runtime/types_proto.go | 69 + .../pkg/runtime/zz_generated.deepcopy.go | 114 + .../k8s.io/apimachinery/pkg/selection/BUILD | 25 + .../apimachinery/pkg/selection/operator.go | 33 + vendor/k8s.io/apimachinery/pkg/types/BUILD | 31 + vendor/k8s.io/apimachinery/pkg/types/doc.go | 18 + .../apimachinery/pkg/types/namespacedname.go | 60 + .../k8s.io/apimachinery/pkg/types/nodename.go | 43 + vendor/k8s.io/apimachinery/pkg/types/patch.go | 28 + vendor/k8s.io/apimachinery/pkg/types/uid.go | 22 + .../k8s.io/apimachinery/pkg/util/clock/BUILD | 33 + .../apimachinery/pkg/util/clock/clock.go | 327 + .../k8s.io/apimachinery/pkg/util/errors/BUILD | 36 + .../apimachinery/pkg/util/errors/doc.go | 18 + .../apimachinery/pkg/util/errors/errors.go | 201 + .../k8s.io/apimachinery/pkg/util/framer/BUILD | 33 + .../apimachinery/pkg/util/framer/framer.go | 167 + .../apimachinery/pkg/util/httpstream/BUILD | 39 + .../apimachinery/pkg/util/httpstream/doc.go | 19 + .../pkg/util/httpstream/httpstream.go | 149 + .../pkg/util/httpstream/spdy/BUILD | 57 + .../pkg/util/httpstream/spdy/connection.go | 145 + .../pkg/util/httpstream/spdy/roundtripper.go | 326 + .../pkg/util/httpstream/spdy/upgrade.go | 107 + .../k8s.io/apimachinery/pkg/util/intstr/BUILD | 50 + .../pkg/util/intstr/generated.pb.go | 381 + .../pkg/util/intstr/generated.proto | 43 + .../apimachinery/pkg/util/intstr/intstr.go | 177 + .../k8s.io/apimachinery/pkg/util/json/BUILD | 33 + .../k8s.io/apimachinery/pkg/util/json/json.go | 119 + vendor/k8s.io/apimachinery/pkg/util/net/BUILD | 51 + .../k8s.io/apimachinery/pkg/util/net/http.go | 422 + .../apimachinery/pkg/util/net/interface.go | 392 + .../apimachinery/pkg/util/net/port_range.go | 113 + .../apimachinery/pkg/util/net/port_split.go | 77 + .../k8s.io/apimachinery/pkg/util/net/util.go | 56 + .../apimachinery/pkg/util/remotecommand/BUILD | 26 + .../pkg/util/remotecommand/constants.go | 53 + .../apimachinery/pkg/util/runtime/BUILD | 34 + .../apimachinery/pkg/util/runtime/runtime.go | 163 + .../k8s.io/apimachinery/pkg/util/sets/BUILD | 72 + .../k8s.io/apimachinery/pkg/util/sets/byte.go | 203 + .../k8s.io/apimachinery/pkg/util/sets/doc.go | 20 + .../apimachinery/pkg/util/sets/empty.go | 23 + .../k8s.io/apimachinery/pkg/util/sets/int.go | 203 + .../apimachinery/pkg/util/sets/int64.go | 203 + .../apimachinery/pkg/util/sets/string.go | 203 + .../apimachinery/pkg/util/validation/BUILD | 38 + .../pkg/util/validation/field/BUILD | 43 + .../pkg/util/validation/field/errors.go | 259 + .../pkg/util/validation/field/path.go | 91 + .../pkg/util/validation/validation.go | 391 + .../k8s.io/apimachinery/pkg/util/wait/BUILD | 38 + .../k8s.io/apimachinery/pkg/util/wait/doc.go | 19 + .../k8s.io/apimachinery/pkg/util/wait/wait.go | 385 + .../k8s.io/apimachinery/pkg/util/yaml/BUILD | 37 + .../apimachinery/pkg/util/yaml/decoder.go | 346 + vendor/k8s.io/apimachinery/pkg/version/BUILD | 28 + vendor/k8s.io/apimachinery/pkg/version/doc.go | 19 + .../k8s.io/apimachinery/pkg/version/types.go | 37 + vendor/k8s.io/apimachinery/pkg/watch/BUILD | 71 + vendor/k8s.io/apimachinery/pkg/watch/doc.go | 19 + .../k8s.io/apimachinery/pkg/watch/filter.go | 109 + vendor/k8s.io/apimachinery/pkg/watch/mux.go | 264 + .../apimachinery/pkg/watch/streamwatcher.go | 119 + vendor/k8s.io/apimachinery/pkg/watch/until.go | 87 + vendor/k8s.io/apimachinery/pkg/watch/watch.go | 270 + .../pkg/watch/zz_generated.deepcopy.go | 42 + .../third_party/forked/golang/netutil/BUILD | 25 + .../third_party/forked/golang/netutil/addr.go | 27 + .../third_party/forked/golang/reflect/BUILD | 33 + .../forked/golang/reflect/deep_equal.go | 388 + vendor/k8s.io/client-go/LICENSE | 202 + .../client-go/discovery/discovery_client.go | 414 + vendor/k8s.io/client-go/discovery/helper.go | 121 + .../k8s.io/client-go/discovery/restmapper.go | 331 + .../client-go/discovery/unstructured.go | 95 + .../k8s.io/client-go/kubernetes/clientset.go | 596 + vendor/k8s.io/client-go/kubernetes/doc.go | 18 + vendor/k8s.io/client-go/kubernetes/import.go | 19 + .../k8s.io/client-go/kubernetes/scheme/doc.go | 18 + .../client-go/kubernetes/scheme/register.go | 107 + .../v1alpha1/admissionregistration_client.go | 88 + .../admissionregistration/v1alpha1/doc.go | 18 + .../v1alpha1/generated_expansion.go | 19 + .../v1alpha1/initializerconfiguration.go | 145 + .../v1beta1/admissionregistration_client.go | 93 + .../admissionregistration/v1beta1/doc.go | 18 + .../v1beta1/generated_expansion.go | 21 + .../v1beta1/mutatingwebhookconfiguration.go | 145 + .../v1beta1/validatingwebhookconfiguration.go | 145 + .../kubernetes/typed/apps/v1/apps_client.go | 108 + .../typed/apps/v1/controllerrevision.go | 155 + .../kubernetes/typed/apps/v1/daemonset.go | 172 + .../kubernetes/typed/apps/v1/deployment.go | 172 + .../client-go/kubernetes/typed/apps/v1/doc.go | 18 + .../typed/apps/v1/generated_expansion.go | 27 + .../kubernetes/typed/apps/v1/replicaset.go | 172 + .../kubernetes/typed/apps/v1/statefulset.go | 172 + .../typed/apps/v1beta1/apps_client.go | 103 + .../typed/apps/v1beta1/controllerrevision.go | 155 + .../typed/apps/v1beta1/deployment.go | 172 + .../kubernetes/typed/apps/v1beta1/doc.go | 18 + .../typed/apps/v1beta1/generated_expansion.go | 25 + .../kubernetes/typed/apps/v1beta1/scale.go | 46 + .../typed/apps/v1beta1/statefulset.go | 172 + .../typed/apps/v1beta2/apps_client.go | 113 + .../typed/apps/v1beta2/controllerrevision.go | 155 + .../typed/apps/v1beta2/daemonset.go | 172 + .../typed/apps/v1beta2/deployment.go | 172 + .../kubernetes/typed/apps/v1beta2/doc.go | 18 + .../typed/apps/v1beta2/generated_expansion.go | 29 + .../typed/apps/v1beta2/replicaset.go | 172 + .../kubernetes/typed/apps/v1beta2/scale.go | 46 + .../typed/apps/v1beta2/statefulset.go | 203 + .../v1/authentication_client.go | 88 + .../kubernetes/typed/authentication/v1/doc.go | 18 + .../authentication/v1/generated_expansion.go | 17 + .../typed/authentication/v1/tokenreview.go | 44 + .../v1/tokenreview_expansion.go | 35 + .../v1beta1/authentication_client.go | 88 + .../typed/authentication/v1beta1/doc.go | 18 + .../v1beta1/generated_expansion.go | 17 + .../authentication/v1beta1/tokenreview.go | 44 + .../v1beta1/tokenreview_expansion.go | 35 + .../authorization/v1/authorization_client.go | 103 + .../kubernetes/typed/authorization/v1/doc.go | 18 + .../authorization/v1/generated_expansion.go | 17 + .../v1/localsubjectaccessreview.go | 46 + .../v1/localsubjectaccessreview_expansion.go | 36 + .../v1/selfsubjectaccessreview.go | 44 + .../v1/selfsubjectaccessreview_expansion.go | 35 + .../v1/selfsubjectrulesreview.go | 44 + .../v1/selfsubjectrulesreview_expansion.go | 35 + .../authorization/v1/subjectaccessreview.go | 44 + .../v1/subjectaccessreview_expansion.go | 36 + .../v1beta1/authorization_client.go | 103 + .../typed/authorization/v1beta1/doc.go | 18 + .../v1beta1/generated_expansion.go | 17 + .../v1beta1/localsubjectaccessreview.go | 46 + .../localsubjectaccessreview_expansion.go | 36 + .../v1beta1/selfsubjectaccessreview.go | 44 + .../selfsubjectaccessreview_expansion.go | 35 + .../v1beta1/selfsubjectrulesreview.go | 44 + .../selfsubjectrulesreview_expansion.go | 35 + .../v1beta1/subjectaccessreview.go | 44 + .../v1beta1/subjectaccessreview_expansion.go | 36 + .../autoscaling/v1/autoscaling_client.go | 88 + .../kubernetes/typed/autoscaling/v1/doc.go | 18 + .../autoscaling/v1/generated_expansion.go | 19 + .../autoscaling/v1/horizontalpodautoscaler.go | 172 + .../autoscaling/v2beta1/autoscaling_client.go | 88 + .../typed/autoscaling/v2beta1/doc.go | 18 + .../v2beta1/generated_expansion.go | 19 + .../v2beta1/horizontalpodautoscaler.go | 172 + .../kubernetes/typed/batch/v1/batch_client.go | 88 + .../kubernetes/typed/batch/v1/doc.go | 18 + .../typed/batch/v1/generated_expansion.go | 19 + .../kubernetes/typed/batch/v1/job.go | 172 + .../typed/batch/v1beta1/batch_client.go | 88 + .../kubernetes/typed/batch/v1beta1/cronjob.go | 172 + .../kubernetes/typed/batch/v1beta1/doc.go | 18 + .../batch/v1beta1/generated_expansion.go | 19 + .../typed/batch/v2alpha1/batch_client.go | 88 + .../typed/batch/v2alpha1/cronjob.go | 172 + .../kubernetes/typed/batch/v2alpha1/doc.go | 18 + .../batch/v2alpha1/generated_expansion.go | 19 + .../v1beta1/certificates_client.go | 88 + .../v1beta1/certificatesigningrequest.go | 161 + .../certificatesigningrequest_expansion.go | 37 + .../typed/certificates/v1beta1/doc.go | 18 + .../v1beta1/generated_expansion.go | 17 + .../typed/core/v1/componentstatus.go | 145 + .../kubernetes/typed/core/v1/configmap.go | 155 + .../kubernetes/typed/core/v1/core_client.go | 163 + .../client-go/kubernetes/typed/core/v1/doc.go | 18 + .../kubernetes/typed/core/v1/endpoints.go | 155 + .../kubernetes/typed/core/v1/event.go | 155 + .../typed/core/v1/event_expansion.go | 164 + .../typed/core/v1/generated_expansion.go | 39 + .../kubernetes/typed/core/v1/limitrange.go | 155 + .../kubernetes/typed/core/v1/namespace.go | 161 + .../typed/core/v1/namespace_expansion.go | 31 + .../kubernetes/typed/core/v1/node.go | 161 + .../typed/core/v1/node_expansion.go | 43 + .../typed/core/v1/persistentvolume.go | 161 + .../typed/core/v1/persistentvolumeclaim.go | 172 + .../client-go/kubernetes/typed/core/v1/pod.go | 172 + .../kubernetes/typed/core/v1/pod_expansion.go | 45 + .../kubernetes/typed/core/v1/podtemplate.go | 155 + .../typed/core/v1/replicationcontroller.go | 204 + .../kubernetes/typed/core/v1/resourcequota.go | 172 + .../kubernetes/typed/core/v1/secret.go | 155 + .../kubernetes/typed/core/v1/service.go | 172 + .../typed/core/v1/service_expansion.go | 41 + .../typed/core/v1/serviceaccount.go | 155 + .../kubernetes/typed/events/v1beta1/doc.go | 18 + .../kubernetes/typed/events/v1beta1/event.go | 155 + .../typed/events/v1beta1/events_client.go | 88 + .../events/v1beta1/generated_expansion.go | 19 + .../typed/extensions/v1beta1/daemonset.go | 172 + .../typed/extensions/v1beta1/deployment.go | 203 + .../v1beta1/deployment_expansion.go | 29 + .../typed/extensions/v1beta1/doc.go | 18 + .../extensions/v1beta1/extensions_client.go | 113 + .../extensions/v1beta1/generated_expansion.go | 25 + .../typed/extensions/v1beta1/ingress.go | 172 + .../extensions/v1beta1/podsecuritypolicy.go | 145 + .../typed/extensions/v1beta1/replicaset.go | 203 + .../typed/extensions/v1beta1/scale.go | 46 + .../extensions/v1beta1/scale_expansion.go | 65 + .../kubernetes/typed/networking/v1/doc.go | 18 + .../networking/v1/generated_expansion.go | 19 + .../typed/networking/v1/networking_client.go | 88 + .../typed/networking/v1/networkpolicy.go | 155 + .../kubernetes/typed/policy/v1beta1/doc.go | 18 + .../typed/policy/v1beta1/eviction.go | 46 + .../policy/v1beta1/eviction_expansion.go | 38 + .../policy/v1beta1/generated_expansion.go | 19 + .../policy/v1beta1/poddisruptionbudget.go | 172 + .../typed/policy/v1beta1/policy_client.go | 93 + .../kubernetes/typed/rbac/v1/clusterrole.go | 145 + .../typed/rbac/v1/clusterrolebinding.go | 145 + .../client-go/kubernetes/typed/rbac/v1/doc.go | 18 + .../typed/rbac/v1/generated_expansion.go | 25 + .../kubernetes/typed/rbac/v1/rbac_client.go | 103 + .../kubernetes/typed/rbac/v1/role.go | 155 + .../kubernetes/typed/rbac/v1/rolebinding.go | 155 + .../typed/rbac/v1alpha1/clusterrole.go | 145 + .../typed/rbac/v1alpha1/clusterrolebinding.go | 145 + .../kubernetes/typed/rbac/v1alpha1/doc.go | 18 + .../rbac/v1alpha1/generated_expansion.go | 25 + .../typed/rbac/v1alpha1/rbac_client.go | 103 + .../kubernetes/typed/rbac/v1alpha1/role.go | 155 + .../typed/rbac/v1alpha1/rolebinding.go | 155 + .../typed/rbac/v1beta1/clusterrole.go | 145 + .../typed/rbac/v1beta1/clusterrolebinding.go | 145 + .../kubernetes/typed/rbac/v1beta1/doc.go | 18 + .../typed/rbac/v1beta1/generated_expansion.go | 25 + .../typed/rbac/v1beta1/rbac_client.go | 103 + .../kubernetes/typed/rbac/v1beta1/role.go | 155 + .../typed/rbac/v1beta1/rolebinding.go | 155 + .../typed/scheduling/v1alpha1/doc.go | 18 + .../v1alpha1/generated_expansion.go | 19 + .../scheduling/v1alpha1/priorityclass.go | 145 + .../scheduling/v1alpha1/scheduling_client.go | 88 + .../kubernetes/typed/settings/v1alpha1/doc.go | 18 + .../settings/v1alpha1/generated_expansion.go | 19 + .../typed/settings/v1alpha1/podpreset.go | 155 + .../settings/v1alpha1/settings_client.go | 88 + .../kubernetes/typed/storage/v1/doc.go | 18 + .../typed/storage/v1/generated_expansion.go | 19 + .../typed/storage/v1/storage_client.go | 88 + .../typed/storage/v1/storageclass.go | 145 + .../kubernetes/typed/storage/v1alpha1/doc.go | 18 + .../storage/v1alpha1/generated_expansion.go | 19 + .../typed/storage/v1alpha1/storage_client.go | 88 + .../storage/v1alpha1/volumeattachment.go | 161 + .../kubernetes/typed/storage/v1beta1/doc.go | 18 + .../storage/v1beta1/generated_expansion.go | 19 + .../typed/storage/v1beta1/storage_client.go | 88 + .../typed/storage/v1beta1/storageclass.go | 145 + .../client-go/pkg/version/.gitattributes | 1 + vendor/k8s.io/client-go/pkg/version/base.go | 63 + vendor/k8s.io/client-go/pkg/version/def.bzl | 24 + vendor/k8s.io/client-go/pkg/version/doc.go | 20 + .../k8s.io/client-go/pkg/version/version.go | 42 + .../plugin/pkg/client/auth/gcp/OWNERS | 6 + .../plugin/pkg/client/auth/gcp/gcp.go | 315 + vendor/k8s.io/client-go/rest/OWNERS | 24 + vendor/k8s.io/client-go/rest/client.go | 258 + vendor/k8s.io/client-go/rest/config.go | 464 + vendor/k8s.io/client-go/rest/plugin.go | 73 + vendor/k8s.io/client-go/rest/request.go | 1132 + vendor/k8s.io/client-go/rest/transport.go | 101 + vendor/k8s.io/client-go/rest/url_utils.go | 97 + vendor/k8s.io/client-go/rest/urlbackoff.go | 107 + vendor/k8s.io/client-go/rest/versions.go | 88 + vendor/k8s.io/client-go/rest/watch/decoder.go | 72 + vendor/k8s.io/client-go/rest/watch/encoder.go | 56 + .../client-go/rest/zz_generated.deepcopy.go | 52 + .../forked/golang/template/exec.go | 94 + .../forked/golang/template/funcs.go | 599 + .../k8s.io/client-go/tools/auth/clientauth.go | 125 + .../client-go/tools/clientcmd/api/doc.go | 18 + .../client-go/tools/clientcmd/api/helpers.go | 183 + .../tools/clientcmd/api/latest/latest.go | 66 + .../client-go/tools/clientcmd/api/register.go | 46 + .../client-go/tools/clientcmd/api/types.go | 186 + .../tools/clientcmd/api/v1/conversion.go | 227 + .../client-go/tools/clientcmd/api/v1/doc.go | 18 + .../tools/clientcmd/api/v1/register.go | 56 + .../client-go/tools/clientcmd/api/v1/types.go | 171 + .../clientcmd/api/v1/zz_generated.deepcopy.go | 303 + .../clientcmd/api/zz_generated.deepcopy.go | 270 + .../client-go/tools/clientcmd/auth_loaders.go | 106 + .../tools/clientcmd/client_config.go | 549 + .../client-go/tools/clientcmd/config.go | 472 + .../k8s.io/client-go/tools/clientcmd/doc.go | 37 + .../k8s.io/client-go/tools/clientcmd/flag.go | 49 + .../client-go/tools/clientcmd/helpers.go | 35 + .../client-go/tools/clientcmd/loader.go | 612 + .../tools/clientcmd/merged_client_builder.go | 169 + .../client-go/tools/clientcmd/overrides.go | 247 + .../client-go/tools/clientcmd/validation.go | 275 + vendor/k8s.io/client-go/tools/metrics/OWNERS | 7 + .../k8s.io/client-go/tools/metrics/metrics.go | 61 + .../k8s.io/client-go/tools/portforward/doc.go | 19 + .../tools/portforward/portforward.go | 342 + .../k8s.io/client-go/tools/reference/ref.go | 122 + .../client-go/tools/remotecommand/doc.go | 20 + .../tools/remotecommand/errorstream.go | 55 + .../tools/remotecommand/remotecommand.go | 142 + .../client-go/tools/remotecommand/resize.go | 33 + .../client-go/tools/remotecommand/v1.go | 160 + .../client-go/tools/remotecommand/v2.go | 195 + .../client-go/tools/remotecommand/v3.go | 111 + .../client-go/tools/remotecommand/v4.go | 119 + vendor/k8s.io/client-go/transport/OWNERS | 7 + vendor/k8s.io/client-go/transport/cache.go | 92 + vendor/k8s.io/client-go/transport/config.go | 105 + .../client-go/transport/round_trippers.go | 455 + .../k8s.io/client-go/transport/spdy/spdy.go | 94 + .../k8s.io/client-go/transport/transport.go | 141 + vendor/k8s.io/client-go/util/cert/cert.go | 215 + vendor/k8s.io/client-go/util/cert/csr.go | 75 + vendor/k8s.io/client-go/util/cert/io.go | 158 + vendor/k8s.io/client-go/util/cert/pem.go | 269 + vendor/k8s.io/client-go/util/exec/exec.go | 52 + .../client-go/util/flowcontrol/backoff.go | 149 + .../client-go/util/flowcontrol/throttle.go | 148 + .../k8s.io/client-go/util/homedir/homedir.go | 47 + .../k8s.io/client-go/util/integer/integer.go | 67 + vendor/k8s.io/client-go/util/jsonpath/doc.go | 20 + .../client-go/util/jsonpath/jsonpath.go | 517 + vendor/k8s.io/client-go/util/jsonpath/node.go | 255 + .../k8s.io/client-go/util/jsonpath/parser.go | 525 + vendor/k8s.io/kube-openapi/LICENSE | 202 + .../k8s.io/kube-openapi/pkg/common/common.go | 168 + vendor/k8s.io/kube-openapi/pkg/common/doc.go | 19 + 2143 files changed, 656099 insertions(+), 1222 deletions(-) delete mode 100644 Godeps/.gitignore delete mode 100644 Godeps/Godeps.json delete mode 100644 Godeps/Readme create mode 100644 Gopkg.lock create mode 100644 Gopkg.toml delete mode 100644 rhel7/Dockerfile.dba.rhel7 create mode 100644 vendor/cloud.google.com/go/AUTHORS create mode 100644 vendor/cloud.google.com/go/CONTRIBUTORS create mode 100644 vendor/cloud.google.com/go/LICENSE create mode 100644 vendor/cloud.google.com/go/compute/metadata/metadata.go create mode 100644 vendor/github.com/Azure/go-ansiterm/LICENSE create mode 100644 vendor/github.com/Azure/go-ansiterm/README.md create mode 100644 vendor/github.com/Azure/go-ansiterm/constants.go create mode 100644 vendor/github.com/Azure/go-ansiterm/context.go create mode 100644 vendor/github.com/Azure/go-ansiterm/csi_entry_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/csi_param_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/escape_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/event_handler.go create mode 100644 vendor/github.com/Azure/go-ansiterm/ground_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/osc_string_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_actions.go create mode 100644 vendor/github.com/Azure/go-ansiterm/states.go create mode 100644 vendor/github.com/Azure/go-ansiterm/utilities.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/ansi.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/api.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/utilities.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go create mode 100644 vendor/github.com/Microsoft/go-winio/.gitignore create mode 100644 vendor/github.com/Microsoft/go-winio/LICENSE create mode 100644 vendor/github.com/Microsoft/go-winio/README.md create mode 100644 vendor/github.com/Microsoft/go-winio/archive/tar/LICENSE create mode 100644 vendor/github.com/Microsoft/go-winio/backup.go create mode 100644 vendor/github.com/Microsoft/go-winio/ea.go create mode 100644 vendor/github.com/Microsoft/go-winio/file.go create mode 100644 vendor/github.com/Microsoft/go-winio/fileinfo.go create mode 100644 vendor/github.com/Microsoft/go-winio/pipe.go create mode 100644 vendor/github.com/Microsoft/go-winio/privilege.go create mode 100644 vendor/github.com/Microsoft/go-winio/reparse.go create mode 100644 vendor/github.com/Microsoft/go-winio/sd.go create mode 100644 vendor/github.com/Microsoft/go-winio/syscall.go create mode 100644 vendor/github.com/Microsoft/go-winio/zsyscall_windows.go create mode 100644 vendor/github.com/Nvveen/Gotty/LICENSE create mode 100644 vendor/github.com/Nvveen/Gotty/README create mode 100644 vendor/github.com/Nvveen/Gotty/TODO create mode 100644 vendor/github.com/Nvveen/Gotty/attributes.go create mode 100644 vendor/github.com/Nvveen/Gotty/gotty.go create mode 100644 vendor/github.com/Nvveen/Gotty/parser.go create mode 100644 vendor/github.com/Nvveen/Gotty/types.go create mode 100644 vendor/github.com/PuerkitoBio/purell/.gitignore create mode 100644 vendor/github.com/PuerkitoBio/purell/.travis.yml create mode 100644 vendor/github.com/PuerkitoBio/purell/LICENSE create mode 100644 vendor/github.com/PuerkitoBio/purell/README.md create mode 100644 vendor/github.com/PuerkitoBio/purell/purell.go create mode 100644 vendor/github.com/PuerkitoBio/urlesc/.travis.yml create mode 100644 vendor/github.com/PuerkitoBio/urlesc/LICENSE create mode 100644 vendor/github.com/PuerkitoBio/urlesc/README.md create mode 100644 vendor/github.com/PuerkitoBio/urlesc/urlesc.go create mode 100644 vendor/github.com/cenkalti/backoff/.gitignore create mode 100644 vendor/github.com/cenkalti/backoff/.travis.yml create mode 100644 vendor/github.com/cenkalti/backoff/LICENSE create mode 100644 vendor/github.com/cenkalti/backoff/README.md create mode 100644 vendor/github.com/cenkalti/backoff/backoff.go create mode 100644 vendor/github.com/cenkalti/backoff/context.go create mode 100644 vendor/github.com/cenkalti/backoff/exponential.go create mode 100644 vendor/github.com/cenkalti/backoff/retry.go create mode 100644 vendor/github.com/cenkalti/backoff/ticker.go create mode 100644 vendor/github.com/cenkalti/backoff/tries.go create mode 100644 vendor/github.com/containerd/continuity/AUTHORS create mode 100644 vendor/github.com/containerd/continuity/LICENSE create mode 100644 vendor/github.com/containerd/continuity/pathdriver/path_driver.go create mode 100644 vendor/github.com/docker/docker/AUTHORS create mode 100644 vendor/github.com/docker/docker/LICENSE create mode 100644 vendor/github.com/docker/docker/NOTICE create mode 100644 vendor/github.com/docker/docker/api/types/auth.go create mode 100644 vendor/github.com/docker/docker/api/types/blkiodev/blkio.go create mode 100644 vendor/github.com/docker/docker/api/types/client.go create mode 100644 vendor/github.com/docker/docker/api/types/configs.go create mode 100644 vendor/github.com/docker/docker/api/types/container/config.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_changes.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_create.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_top.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_update.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_wait.go create mode 100644 vendor/github.com/docker/docker/api/types/container/host_config.go create mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go create mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go create mode 100644 vendor/github.com/docker/docker/api/types/container/waitcondition.go create mode 100644 vendor/github.com/docker/docker/api/types/error_response.go create mode 100644 vendor/github.com/docker/docker/api/types/filters/parse.go create mode 100644 vendor/github.com/docker/docker/api/types/graph_driver_data.go create mode 100644 vendor/github.com/docker/docker/api/types/id_response.go create mode 100644 vendor/github.com/docker/docker/api/types/image_delete_response_item.go create mode 100644 vendor/github.com/docker/docker/api/types/image_summary.go create mode 100644 vendor/github.com/docker/docker/api/types/mount/mount.go create mode 100644 vendor/github.com/docker/docker/api/types/network/network.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_device.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_env.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_interface_type.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_mount.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_responses.go create mode 100644 vendor/github.com/docker/docker/api/types/port.go create mode 100644 vendor/github.com/docker/docker/api/types/registry/authenticate.go create mode 100644 vendor/github.com/docker/docker/api/types/registry/registry.go create mode 100644 vendor/github.com/docker/docker/api/types/seccomp.go create mode 100644 vendor/github.com/docker/docker/api/types/service_update_response.go create mode 100644 vendor/github.com/docker/docker/api/types/stats.go create mode 100644 vendor/github.com/docker/docker/api/types/strslice/strslice.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/common.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/config.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/container.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/network.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/node.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto create mode 100644 vendor/github.com/docker/docker/api/types/swarm/secret.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/service.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/swarm.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/task.go create mode 100644 vendor/github.com/docker/docker/api/types/types.go create mode 100644 vendor/github.com/docker/docker/api/types/versions/README.md create mode 100644 vendor/github.com/docker/docker/api/types/versions/compare.go create mode 100644 vendor/github.com/docker/docker/api/types/volume.go create mode 100644 vendor/github.com/docker/docker/contrib/syntax/vim/LICENSE create mode 100644 vendor/github.com/docker/docker/docs/static_files/contributors.png create mode 100755 vendor/github.com/docker/docker/hack/generate-authors.sh create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/ca.pem create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/client-cert.pem create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/client-key.pem create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/server-cert.pem create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/server-key.pem create mode 100644 vendor/github.com/docker/docker/opts/address_pools.go create mode 100644 vendor/github.com/docker/docker/opts/env.go create mode 100644 vendor/github.com/docker/docker/opts/hosts.go create mode 100644 vendor/github.com/docker/docker/opts/hosts_unix.go create mode 100644 vendor/github.com/docker/docker/opts/hosts_windows.go create mode 100644 vendor/github.com/docker/docker/opts/ip.go create mode 100644 vendor/github.com/docker/docker/opts/opts.go create mode 100644 vendor/github.com/docker/docker/opts/opts_unix.go create mode 100644 vendor/github.com/docker/docker/opts/opts_windows.go create mode 100644 vendor/github.com/docker/docker/opts/quotedstring.go create mode 100644 vendor/github.com/docker/docker/opts/runtime.go create mode 100644 vendor/github.com/docker/docker/opts/ulimit.go create mode 100644 vendor/github.com/docker/docker/pkg/fileutils/fileutils.go create mode 100644 vendor/github.com/docker/docker/pkg/fileutils/fileutils_darwin.go create mode 100644 vendor/github.com/docker/docker/pkg/fileutils/fileutils_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/fileutils/fileutils_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/homedir/homedir_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/homedir/homedir_others.go create mode 100644 vendor/github.com/docker/docker/pkg/homedir/homedir_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/homedir/homedir_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/idtools.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go create mode 100644 vendor/github.com/docker/docker/pkg/idtools/utils_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/buffer.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/fswriters.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/readers.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/writers.go create mode 100644 vendor/github.com/docker/docker/pkg/longpath/longpath.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/flags.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/flags_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/mount.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/mounter_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/pools/pools.go create mode 100644 vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go create mode 100644 vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE create mode 100644 vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD create mode 100644 vendor/github.com/docker/docker/pkg/system/chtimes.go create mode 100644 vendor/github.com/docker/docker/pkg/system/chtimes_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/system/chtimes_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/errors.go create mode 100644 vendor/github.com/docker/docker/pkg/system/exitcode.go create mode 100644 vendor/github.com/docker/docker/pkg/system/filesys.go create mode 100644 vendor/github.com/docker/docker/pkg/system/filesys_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/init.go create mode 100644 vendor/github.com/docker/docker/pkg/system/init_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/system/init_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/lcow.go create mode 100644 vendor/github.com/docker/docker/pkg/system/lcow_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/system/lcow_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/lstat_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/system/lstat_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/meminfo.go create mode 100644 vendor/github.com/docker/docker/pkg/system/meminfo_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go create mode 100644 vendor/github.com/docker/docker/pkg/system/meminfo_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/mknod.go create mode 100644 vendor/github.com/docker/docker/pkg/system/mknod_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/path.go create mode 100644 vendor/github.com/docker/docker/pkg/system/process_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/system/process_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/rm.go create mode 100644 vendor/github.com/docker/docker/pkg/system/stat_darwin.go create mode 100644 vendor/github.com/docker/docker/pkg/system/stat_freebsd.go create mode 100644 vendor/github.com/docker/docker/pkg/system/stat_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/system/stat_openbsd.go create mode 100644 vendor/github.com/docker/docker/pkg/system/stat_solaris.go create mode 100644 vendor/github.com/docker/docker/pkg/system/stat_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/system/stat_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/syscall_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/system/syscall_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/umask.go create mode 100644 vendor/github.com/docker/docker/pkg/system/umask_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go create mode 100644 vendor/github.com/docker/docker/pkg/system/utimes_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go create mode 100644 vendor/github.com/docker/docker/pkg/system/xattrs_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go create mode 120000 vendor/github.com/docker/docker/project/CONTRIBUTING.md create mode 100644 vendor/github.com/docker/go-connections/LICENSE create mode 100644 vendor/github.com/docker/go-connections/nat/nat.go create mode 100644 vendor/github.com/docker/go-connections/nat/parse.go create mode 100644 vendor/github.com/docker/go-connections/nat/sort.go create mode 100644 vendor/github.com/docker/go-units/CONTRIBUTING.md create mode 100644 vendor/github.com/docker/go-units/LICENSE create mode 100644 vendor/github.com/docker/go-units/MAINTAINERS create mode 100644 vendor/github.com/docker/go-units/README.md create mode 100644 vendor/github.com/docker/go-units/circle.yml create mode 100644 vendor/github.com/docker/go-units/duration.go create mode 100644 vendor/github.com/docker/go-units/size.go create mode 100644 vendor/github.com/docker/go-units/ulimit.go create mode 100644 vendor/github.com/docker/libnetwork/LICENSE create mode 100644 vendor/github.com/docker/libnetwork/client/mflag/LICENSE create mode 100644 vendor/github.com/docker/libnetwork/ipamutils/utils.go create mode 100644 vendor/github.com/docker/spdystream/CONTRIBUTING.md create mode 100644 vendor/github.com/docker/spdystream/LICENSE create mode 100644 vendor/github.com/docker/spdystream/LICENSE.docs create mode 100644 vendor/github.com/docker/spdystream/MAINTAINERS create mode 100644 vendor/github.com/docker/spdystream/README.md create mode 100644 vendor/github.com/docker/spdystream/connection.go create mode 100644 vendor/github.com/docker/spdystream/handlers.go create mode 100644 vendor/github.com/docker/spdystream/priority.go create mode 100644 vendor/github.com/docker/spdystream/spdy/dictionary.go create mode 100644 vendor/github.com/docker/spdystream/spdy/read.go create mode 100644 vendor/github.com/docker/spdystream/spdy/types.go create mode 100644 vendor/github.com/docker/spdystream/spdy/write.go create mode 100644 vendor/github.com/docker/spdystream/stream.go create mode 100644 vendor/github.com/docker/spdystream/utils.go create mode 100644 vendor/github.com/emicklei/go-restful/.gitignore create mode 100644 vendor/github.com/emicklei/go-restful/.travis.yml create mode 100644 vendor/github.com/emicklei/go-restful/CHANGES.md create mode 100644 vendor/github.com/emicklei/go-restful/LICENSE create mode 100644 vendor/github.com/emicklei/go-restful/Makefile create mode 100644 vendor/github.com/emicklei/go-restful/README.md create mode 100644 vendor/github.com/emicklei/go-restful/Srcfile create mode 100644 vendor/github.com/emicklei/go-restful/bench_test.sh create mode 100644 vendor/github.com/emicklei/go-restful/compress.go create mode 100644 vendor/github.com/emicklei/go-restful/compressor_cache.go create mode 100644 vendor/github.com/emicklei/go-restful/compressor_pools.go create mode 100644 vendor/github.com/emicklei/go-restful/compressors.go create mode 100644 vendor/github.com/emicklei/go-restful/constants.go create mode 100644 vendor/github.com/emicklei/go-restful/container.go create mode 100644 vendor/github.com/emicklei/go-restful/cors_filter.go create mode 100644 vendor/github.com/emicklei/go-restful/coverage.sh create mode 100644 vendor/github.com/emicklei/go-restful/curly.go create mode 100644 vendor/github.com/emicklei/go-restful/curly_route.go create mode 100644 vendor/github.com/emicklei/go-restful/doc.go create mode 100644 vendor/github.com/emicklei/go-restful/entity_accessors.go create mode 100644 vendor/github.com/emicklei/go-restful/filter.go create mode 100644 vendor/github.com/emicklei/go-restful/jsr311.go create mode 100644 vendor/github.com/emicklei/go-restful/log/log.go create mode 100644 vendor/github.com/emicklei/go-restful/logger.go create mode 100644 vendor/github.com/emicklei/go-restful/mime.go create mode 100644 vendor/github.com/emicklei/go-restful/options_filter.go create mode 100644 vendor/github.com/emicklei/go-restful/parameter.go create mode 100644 vendor/github.com/emicklei/go-restful/path_expression.go create mode 100644 vendor/github.com/emicklei/go-restful/request.go create mode 100644 vendor/github.com/emicklei/go-restful/response.go create mode 100644 vendor/github.com/emicklei/go-restful/route.go create mode 100644 vendor/github.com/emicklei/go-restful/route_builder.go create mode 100644 vendor/github.com/emicklei/go-restful/router.go create mode 100644 vendor/github.com/emicklei/go-restful/service_error.go create mode 100644 vendor/github.com/emicklei/go-restful/web_service.go create mode 100644 vendor/github.com/emicklei/go-restful/web_service_container.go create mode 100644 vendor/github.com/fatih/color/.travis.yml create mode 100644 vendor/github.com/fatih/color/Gopkg.lock create mode 100644 vendor/github.com/fatih/color/Gopkg.toml create mode 100644 vendor/github.com/fatih/color/LICENSE.md create mode 100644 vendor/github.com/fatih/color/README.md create mode 100644 vendor/github.com/fatih/color/color.go create mode 100644 vendor/github.com/fatih/color/doc.go create mode 100644 vendor/github.com/fsnotify/fsnotify/.editorconfig create mode 100644 vendor/github.com/fsnotify/fsnotify/.gitignore create mode 100644 vendor/github.com/fsnotify/fsnotify/.travis.yml create mode 100644 vendor/github.com/fsnotify/fsnotify/AUTHORS create mode 100644 vendor/github.com/fsnotify/fsnotify/CHANGELOG.md create mode 100644 vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md create mode 100644 vendor/github.com/fsnotify/fsnotify/LICENSE create mode 100644 vendor/github.com/fsnotify/fsnotify/README.md create mode 100644 vendor/github.com/fsnotify/fsnotify/fen.go create mode 100644 vendor/github.com/fsnotify/fsnotify/fsnotify.go create mode 100644 vendor/github.com/fsnotify/fsnotify/inotify.go create mode 100644 vendor/github.com/fsnotify/fsnotify/inotify_poller.go create mode 100644 vendor/github.com/fsnotify/fsnotify/kqueue.go create mode 100644 vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go create mode 100644 vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go create mode 100644 vendor/github.com/fsnotify/fsnotify/windows.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/.gitignore create mode 100644 vendor/github.com/fsouza/go-dockerclient/.travis.yml create mode 100644 vendor/github.com/fsouza/go-dockerclient/AUTHORS create mode 100644 vendor/github.com/fsouza/go-dockerclient/DOCKER-LICENSE create mode 100644 vendor/github.com/fsouza/go-dockerclient/Gopkg.toml create mode 100644 vendor/github.com/fsouza/go-dockerclient/LICENSE create mode 100644 vendor/github.com/fsouza/go-dockerclient/Makefile create mode 100644 vendor/github.com/fsouza/go-dockerclient/README.markdown create mode 100644 vendor/github.com/fsouza/go-dockerclient/appveyor.yml create mode 100644 vendor/github.com/fsouza/go-dockerclient/auth.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/change.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/client.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/client_unix.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/client_windows.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/container.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/distribution.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/env.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/event.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/exec.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/image.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/archive/archive.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_linux.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_other.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_unix.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_windows.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_unix.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_windows.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/archive/copy.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/archive/whiteouts.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/jsonmessage/jsonmessage.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/term/term.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/term/winsize.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/internal/term/winsize_windows.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/misc.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/network.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/plugin.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/signal.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_configs.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_node.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_service.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_task.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/tar.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/tls.go create mode 100644 vendor/github.com/fsouza/go-dockerclient/volume.go create mode 100644 vendor/github.com/ghodss/yaml/.gitignore create mode 100644 vendor/github.com/ghodss/yaml/.travis.yml create mode 100644 vendor/github.com/ghodss/yaml/LICENSE create mode 100644 vendor/github.com/ghodss/yaml/README.md create mode 100644 vendor/github.com/ghodss/yaml/fields.go create mode 100644 vendor/github.com/ghodss/yaml/yaml.go create mode 100644 vendor/github.com/go-openapi/jsonpointer/.drone.sec create mode 100644 vendor/github.com/go-openapi/jsonpointer/.drone.yml create mode 100644 vendor/github.com/go-openapi/jsonpointer/.gitignore create mode 100644 vendor/github.com/go-openapi/jsonpointer/.pullapprove.yml create mode 100644 vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/go-openapi/jsonpointer/LICENSE create mode 100644 vendor/github.com/go-openapi/jsonpointer/README.md create mode 100644 vendor/github.com/go-openapi/jsonpointer/pointer.go create mode 100644 vendor/github.com/go-openapi/jsonreference/.drone.sec create mode 100644 vendor/github.com/go-openapi/jsonreference/.drone.yml create mode 100644 vendor/github.com/go-openapi/jsonreference/.gitignore create mode 100644 vendor/github.com/go-openapi/jsonreference/.pullapprove.yml create mode 100644 vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/go-openapi/jsonreference/LICENSE create mode 100644 vendor/github.com/go-openapi/jsonreference/README.md create mode 100644 vendor/github.com/go-openapi/jsonreference/reference.go create mode 100644 vendor/github.com/go-openapi/spec/.editorconfig create mode 100644 vendor/github.com/go-openapi/spec/.gitignore create mode 100644 vendor/github.com/go-openapi/spec/.travis.yml create mode 100644 vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/go-openapi/spec/LICENSE create mode 100644 vendor/github.com/go-openapi/spec/README.md create mode 100644 vendor/github.com/go-openapi/spec/bindata.go create mode 100644 vendor/github.com/go-openapi/spec/contact_info.go create mode 100644 vendor/github.com/go-openapi/spec/expander.go create mode 100644 vendor/github.com/go-openapi/spec/external_docs.go create mode 100644 vendor/github.com/go-openapi/spec/header.go create mode 100644 vendor/github.com/go-openapi/spec/info.go create mode 100644 vendor/github.com/go-openapi/spec/items.go create mode 100644 vendor/github.com/go-openapi/spec/license.go create mode 100644 vendor/github.com/go-openapi/spec/operation.go create mode 100644 vendor/github.com/go-openapi/spec/parameter.go create mode 100644 vendor/github.com/go-openapi/spec/path_item.go create mode 100644 vendor/github.com/go-openapi/spec/paths.go create mode 100644 vendor/github.com/go-openapi/spec/ref.go create mode 100644 vendor/github.com/go-openapi/spec/response.go create mode 100644 vendor/github.com/go-openapi/spec/responses.go create mode 100644 vendor/github.com/go-openapi/spec/schema.go create mode 100644 vendor/github.com/go-openapi/spec/security_scheme.go create mode 100644 vendor/github.com/go-openapi/spec/spec.go create mode 100644 vendor/github.com/go-openapi/spec/swagger.go create mode 100644 vendor/github.com/go-openapi/spec/tag.go create mode 100644 vendor/github.com/go-openapi/spec/xml_object.go create mode 100644 vendor/github.com/go-openapi/swag/.editorconfig create mode 100644 vendor/github.com/go-openapi/swag/.gitignore create mode 100644 vendor/github.com/go-openapi/swag/.travis.yml create mode 100644 vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/go-openapi/swag/LICENSE create mode 100644 vendor/github.com/go-openapi/swag/README.md create mode 100644 vendor/github.com/go-openapi/swag/convert.go create mode 100644 vendor/github.com/go-openapi/swag/convert_types.go create mode 100644 vendor/github.com/go-openapi/swag/json.go create mode 100644 vendor/github.com/go-openapi/swag/loading.go create mode 100644 vendor/github.com/go-openapi/swag/net.go create mode 100644 vendor/github.com/go-openapi/swag/path.go create mode 100644 vendor/github.com/go-openapi/swag/util.go create mode 100644 vendor/github.com/go-openapi/swag/yaml.go create mode 100644 vendor/github.com/gogo/protobuf/AUTHORS create mode 100644 vendor/github.com/gogo/protobuf/CONTRIBUTORS create mode 100644 vendor/github.com/gogo/protobuf/GOLANG_CONTRIBUTORS create mode 100644 vendor/github.com/gogo/protobuf/LICENSE create mode 100644 vendor/github.com/gogo/protobuf/proto/Makefile create mode 100644 vendor/github.com/gogo/protobuf/proto/clone.go create mode 100644 vendor/github.com/gogo/protobuf/proto/decode.go create mode 100644 vendor/github.com/gogo/protobuf/proto/decode_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/duration.go create mode 100644 vendor/github.com/gogo/protobuf/proto/duration_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/encode.go create mode 100644 vendor/github.com/gogo/protobuf/proto/encode_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/equal.go create mode 100644 vendor/github.com/gogo/protobuf/proto/extensions.go create mode 100644 vendor/github.com/gogo/protobuf/proto/extensions_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/lib.go create mode 100644 vendor/github.com/gogo/protobuf/proto/lib_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/message_set.go create mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_reflect.go create mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go create mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/properties.go create mode 100644 vendor/github.com/gogo/protobuf/proto/properties_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/skip_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/text.go create mode 100644 vendor/github.com/gogo/protobuf/proto/text_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/text_parser.go create mode 100644 vendor/github.com/gogo/protobuf/proto/timestamp.go create mode 100644 vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go create mode 100644 vendor/github.com/golang/glog/LICENSE create mode 100644 vendor/github.com/golang/glog/README create mode 100644 vendor/github.com/golang/glog/glog.go create mode 100644 vendor/github.com/golang/glog/glog_file.go create mode 100644 vendor/github.com/golang/protobuf/AUTHORS create mode 100644 vendor/github.com/golang/protobuf/CONTRIBUTORS create mode 100644 vendor/github.com/golang/protobuf/LICENSE create mode 100644 vendor/github.com/golang/protobuf/proto/Makefile create mode 100644 vendor/github.com/golang/protobuf/proto/clone.go create mode 100644 vendor/github.com/golang/protobuf/proto/decode.go create mode 100644 vendor/github.com/golang/protobuf/proto/encode.go create mode 100644 vendor/github.com/golang/protobuf/proto/equal.go create mode 100644 vendor/github.com/golang/protobuf/proto/extensions.go create mode 100644 vendor/github.com/golang/protobuf/proto/lib.go create mode 100644 vendor/github.com/golang/protobuf/proto/message_set.go create mode 100644 vendor/github.com/golang/protobuf/proto/pointer_reflect.go create mode 100644 vendor/github.com/golang/protobuf/proto/pointer_unsafe.go create mode 100644 vendor/github.com/golang/protobuf/proto/properties.go create mode 100644 vendor/github.com/golang/protobuf/proto/text.go create mode 100644 vendor/github.com/golang/protobuf/proto/text_parser.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/any.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/any/any.pb.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/any/any.proto create mode 100644 vendor/github.com/golang/protobuf/ptypes/doc.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/duration.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/duration/duration.proto create mode 100755 vendor/github.com/golang/protobuf/ptypes/regen.sh create mode 100644 vendor/github.com/golang/protobuf/ptypes/timestamp.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto create mode 100644 vendor/github.com/google/btree/.travis.yml create mode 100644 vendor/github.com/google/btree/LICENSE create mode 100644 vendor/github.com/google/btree/README.md create mode 100644 vendor/github.com/google/btree/btree.go create mode 100644 vendor/github.com/google/btree/btree_mem.go create mode 100644 vendor/github.com/google/gofuzz/.travis.yml create mode 100644 vendor/github.com/google/gofuzz/CONTRIBUTING.md create mode 100644 vendor/github.com/google/gofuzz/LICENSE create mode 100644 vendor/github.com/google/gofuzz/README.md create mode 100644 vendor/github.com/google/gofuzz/doc.go create mode 100644 vendor/github.com/google/gofuzz/fuzz.go create mode 100644 vendor/github.com/googleapis/gnostic/LICENSE create mode 100644 vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.go create mode 100644 vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.pb.go create mode 100644 vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto create mode 100644 vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md create mode 100644 vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json create mode 100644 vendor/github.com/googleapis/gnostic/compiler/README.md create mode 100644 vendor/github.com/googleapis/gnostic/compiler/context.go create mode 100644 vendor/github.com/googleapis/gnostic/compiler/error.go create mode 100644 vendor/github.com/googleapis/gnostic/compiler/extension-handler.go create mode 100644 vendor/github.com/googleapis/gnostic/compiler/helpers.go create mode 100644 vendor/github.com/googleapis/gnostic/compiler/main.go create mode 100644 vendor/github.com/googleapis/gnostic/compiler/reader.go create mode 100755 vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh create mode 100644 vendor/github.com/googleapis/gnostic/extensions/README.md create mode 100644 vendor/github.com/googleapis/gnostic/extensions/extension.pb.go create mode 100644 vendor/github.com/googleapis/gnostic/extensions/extension.proto create mode 100644 vendor/github.com/googleapis/gnostic/extensions/extensions.go create mode 100644 vendor/github.com/gorilla/context/.travis.yml create mode 100644 vendor/github.com/gorilla/context/LICENSE create mode 100644 vendor/github.com/gorilla/context/README.md create mode 100644 vendor/github.com/gorilla/context/context.go create mode 100644 vendor/github.com/gorilla/context/doc.go create mode 100644 vendor/github.com/gorilla/mux/.travis.yml create mode 100644 vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md create mode 100644 vendor/github.com/gorilla/mux/LICENSE create mode 100644 vendor/github.com/gorilla/mux/README.md create mode 100644 vendor/github.com/gorilla/mux/context_gorilla.go create mode 100644 vendor/github.com/gorilla/mux/context_native.go create mode 100644 vendor/github.com/gorilla/mux/doc.go create mode 100644 vendor/github.com/gorilla/mux/middleware.go create mode 100644 vendor/github.com/gorilla/mux/mux.go create mode 100644 vendor/github.com/gorilla/mux/regexp.go create mode 100644 vendor/github.com/gorilla/mux/route.go create mode 100644 vendor/github.com/gorilla/mux/test_helpers.go create mode 100644 vendor/github.com/gregjones/httpcache/.travis.yml create mode 100644 vendor/github.com/gregjones/httpcache/LICENSE.txt create mode 100644 vendor/github.com/gregjones/httpcache/README.md create mode 100644 vendor/github.com/gregjones/httpcache/diskcache/diskcache.go create mode 100644 vendor/github.com/gregjones/httpcache/httpcache.go create mode 100644 vendor/github.com/hashicorp/hcl/.gitignore create mode 100644 vendor/github.com/hashicorp/hcl/.travis.yml create mode 100644 vendor/github.com/hashicorp/hcl/LICENSE create mode 100644 vendor/github.com/hashicorp/hcl/Makefile create mode 100644 vendor/github.com/hashicorp/hcl/README.md create mode 100644 vendor/github.com/hashicorp/hcl/appveyor.yml create mode 100644 vendor/github.com/hashicorp/hcl/decoder.go create mode 100644 vendor/github.com/hashicorp/hcl/hcl.go create mode 100644 vendor/github.com/hashicorp/hcl/hcl/ast/ast.go create mode 100644 vendor/github.com/hashicorp/hcl/hcl/ast/walk.go create mode 100644 vendor/github.com/hashicorp/hcl/hcl/parser/error.go create mode 100644 vendor/github.com/hashicorp/hcl/hcl/parser/parser.go create mode 100644 vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go create mode 100644 vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go create mode 100644 vendor/github.com/hashicorp/hcl/hcl/token/position.go create mode 100644 vendor/github.com/hashicorp/hcl/hcl/token/token.go create mode 100644 vendor/github.com/hashicorp/hcl/json/parser/flatten.go create mode 100644 vendor/github.com/hashicorp/hcl/json/parser/parser.go create mode 100644 vendor/github.com/hashicorp/hcl/json/scanner/scanner.go create mode 100644 vendor/github.com/hashicorp/hcl/json/token/position.go create mode 100644 vendor/github.com/hashicorp/hcl/json/token/token.go create mode 100644 vendor/github.com/hashicorp/hcl/lex.go create mode 100644 vendor/github.com/hashicorp/hcl/parse.go create mode 100644 vendor/github.com/howeyc/gopass/.travis.yml create mode 100644 vendor/github.com/howeyc/gopass/LICENSE.txt create mode 100644 vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE create mode 100644 vendor/github.com/howeyc/gopass/README.md create mode 100644 vendor/github.com/howeyc/gopass/pass.go create mode 100644 vendor/github.com/howeyc/gopass/terminal.go create mode 100644 vendor/github.com/howeyc/gopass/terminal_solaris.go create mode 100644 vendor/github.com/imdario/mergo/.travis.yml create mode 100644 vendor/github.com/imdario/mergo/LICENSE create mode 100644 vendor/github.com/imdario/mergo/README.md create mode 100644 vendor/github.com/imdario/mergo/doc.go create mode 100644 vendor/github.com/imdario/mergo/map.go create mode 100644 vendor/github.com/imdario/mergo/merge.go create mode 100644 vendor/github.com/imdario/mergo/mergo.go create mode 100644 vendor/github.com/imdario/mergo/testdata/license.yml create mode 100644 vendor/github.com/inconshreveable/mousetrap/LICENSE create mode 100644 vendor/github.com/inconshreveable/mousetrap/README.md create mode 100644 vendor/github.com/inconshreveable/mousetrap/trap_others.go create mode 100644 vendor/github.com/inconshreveable/mousetrap/trap_windows.go create mode 100644 vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go create mode 100644 vendor/github.com/json-iterator/go/.codecov.yml create mode 100644 vendor/github.com/json-iterator/go/.gitignore create mode 100644 vendor/github.com/json-iterator/go/.travis.yml create mode 100644 vendor/github.com/json-iterator/go/LICENSE create mode 100644 vendor/github.com/json-iterator/go/README.md create mode 100644 vendor/github.com/json-iterator/go/feature_adapter.go create mode 100644 vendor/github.com/json-iterator/go/feature_any.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_array.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_bool.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_float.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_int32.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_int64.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_invalid.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_nil.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_number.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_object.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_string.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_uint32.go create mode 100644 vendor/github.com/json-iterator/go/feature_any_uint64.go create mode 100644 vendor/github.com/json-iterator/go/feature_config.go create mode 100644 vendor/github.com/json-iterator/go/feature_iter.go create mode 100644 vendor/github.com/json-iterator/go/feature_iter_array.go create mode 100644 vendor/github.com/json-iterator/go/feature_iter_float.go create mode 100644 vendor/github.com/json-iterator/go/feature_iter_int.go create mode 100644 vendor/github.com/json-iterator/go/feature_iter_object.go create mode 100644 vendor/github.com/json-iterator/go/feature_iter_skip.go create mode 100644 vendor/github.com/json-iterator/go/feature_iter_skip_sloppy.go create mode 100644 vendor/github.com/json-iterator/go/feature_iter_skip_strict.go create mode 100644 vendor/github.com/json-iterator/go/feature_iter_string.go create mode 100644 vendor/github.com/json-iterator/go/feature_json_number.go create mode 100644 vendor/github.com/json-iterator/go/feature_pool.go create mode 100644 vendor/github.com/json-iterator/go/feature_reflect.go create mode 100644 vendor/github.com/json-iterator/go/feature_reflect_array.go create mode 100644 vendor/github.com/json-iterator/go/feature_reflect_extension.go create mode 100644 vendor/github.com/json-iterator/go/feature_reflect_map.go create mode 100644 vendor/github.com/json-iterator/go/feature_reflect_native.go create mode 100644 vendor/github.com/json-iterator/go/feature_reflect_object.go create mode 100644 vendor/github.com/json-iterator/go/feature_reflect_slice.go create mode 100644 vendor/github.com/json-iterator/go/feature_reflect_struct_decoder.go create mode 100644 vendor/github.com/json-iterator/go/feature_stream.go create mode 100644 vendor/github.com/json-iterator/go/feature_stream_float.go create mode 100644 vendor/github.com/json-iterator/go/feature_stream_int.go create mode 100644 vendor/github.com/json-iterator/go/feature_stream_string.go create mode 100644 vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md create mode 100644 vendor/github.com/json-iterator/go/jsoniter.go create mode 120000 vendor/github.com/json-iterator/go/skip_tests/array/skip_test.go create mode 120000 vendor/github.com/json-iterator/go/skip_tests/object/skip_test.go create mode 120000 vendor/github.com/json-iterator/go/skip_tests/string/skip_test.go create mode 100755 vendor/github.com/json-iterator/go/test.sh create mode 100644 vendor/github.com/juju/ratelimit/LICENSE create mode 100644 vendor/github.com/juju/ratelimit/README.md create mode 100644 vendor/github.com/juju/ratelimit/ratelimit.go create mode 100644 vendor/github.com/juju/ratelimit/reader.go create mode 100644 vendor/github.com/lib/pq/.gitignore create mode 100755 vendor/github.com/lib/pq/.travis.sh create mode 100644 vendor/github.com/lib/pq/.travis.yml create mode 100644 vendor/github.com/lib/pq/CONTRIBUTING.md create mode 100644 vendor/github.com/lib/pq/LICENSE.md create mode 100644 vendor/github.com/lib/pq/README.md create mode 100644 vendor/github.com/lib/pq/array.go create mode 100644 vendor/github.com/lib/pq/buf.go create mode 100644 vendor/github.com/lib/pq/conn.go create mode 100644 vendor/github.com/lib/pq/conn_go18.go create mode 100644 vendor/github.com/lib/pq/copy.go create mode 100644 vendor/github.com/lib/pq/doc.go create mode 100644 vendor/github.com/lib/pq/encode.go create mode 100644 vendor/github.com/lib/pq/error.go create mode 100644 vendor/github.com/lib/pq/notify.go create mode 100644 vendor/github.com/lib/pq/oid/doc.go create mode 100644 vendor/github.com/lib/pq/oid/gen.go create mode 100644 vendor/github.com/lib/pq/oid/types.go create mode 100644 vendor/github.com/lib/pq/rows.go create mode 100644 vendor/github.com/lib/pq/ssl.go create mode 100644 vendor/github.com/lib/pq/ssl_go1.7.go create mode 100644 vendor/github.com/lib/pq/ssl_permissions.go create mode 100644 vendor/github.com/lib/pq/ssl_renegotiation.go create mode 100644 vendor/github.com/lib/pq/ssl_windows.go create mode 100644 vendor/github.com/lib/pq/url.go create mode 100644 vendor/github.com/lib/pq/user_posix.go create mode 100644 vendor/github.com/lib/pq/user_windows.go create mode 100644 vendor/github.com/lib/pq/uuid.go create mode 100644 vendor/github.com/magiconair/properties/.gitignore create mode 100644 vendor/github.com/magiconair/properties/.travis.yml create mode 100644 vendor/github.com/magiconair/properties/CHANGELOG.md create mode 100644 vendor/github.com/magiconair/properties/LICENSE create mode 100644 vendor/github.com/magiconair/properties/README.md create mode 100644 vendor/github.com/magiconair/properties/decode.go create mode 100644 vendor/github.com/magiconair/properties/doc.go create mode 100644 vendor/github.com/magiconair/properties/integrate.go create mode 100644 vendor/github.com/magiconair/properties/lex.go create mode 100644 vendor/github.com/magiconair/properties/load.go create mode 100644 vendor/github.com/magiconair/properties/parser.go create mode 100644 vendor/github.com/magiconair/properties/properties.go create mode 100644 vendor/github.com/magiconair/properties/rangecheck.go create mode 100644 vendor/github.com/mailru/easyjson/LICENSE create mode 100644 vendor/github.com/mailru/easyjson/buffer/pool.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/bytestostr.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/bytestostr_nounsafe.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/error.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/lexer.go create mode 100644 vendor/github.com/mailru/easyjson/jwriter/writer.go create mode 100644 vendor/github.com/mattn/go-colorable/.travis.yml create mode 100644 vendor/github.com/mattn/go-colorable/LICENSE create mode 100644 vendor/github.com/mattn/go-colorable/README.md create mode 100644 vendor/github.com/mattn/go-colorable/colorable_appengine.go create mode 100644 vendor/github.com/mattn/go-colorable/colorable_others.go create mode 100644 vendor/github.com/mattn/go-colorable/colorable_windows.go create mode 100644 vendor/github.com/mattn/go-colorable/noncolorable.go create mode 100644 vendor/github.com/mattn/go-isatty/.travis.yml create mode 100644 vendor/github.com/mattn/go-isatty/LICENSE create mode 100644 vendor/github.com/mattn/go-isatty/README.md create mode 100644 vendor/github.com/mattn/go-isatty/doc.go create mode 100644 vendor/github.com/mattn/go-isatty/isatty_appengine.go create mode 100644 vendor/github.com/mattn/go-isatty/isatty_bsd.go create mode 100644 vendor/github.com/mattn/go-isatty/isatty_linux.go create mode 100644 vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go create mode 100644 vendor/github.com/mattn/go-isatty/isatty_others.go create mode 100644 vendor/github.com/mattn/go-isatty/isatty_solaris.go create mode 100644 vendor/github.com/mattn/go-isatty/isatty_windows.go create mode 100644 vendor/github.com/mitchellh/mapstructure/.travis.yml create mode 100644 vendor/github.com/mitchellh/mapstructure/LICENSE create mode 100644 vendor/github.com/mitchellh/mapstructure/README.md create mode 100644 vendor/github.com/mitchellh/mapstructure/decode_hooks.go create mode 100644 vendor/github.com/mitchellh/mapstructure/error.go create mode 100644 vendor/github.com/mitchellh/mapstructure/mapstructure.go create mode 100644 vendor/github.com/opencontainers/go-digest/.mailmap create mode 100644 vendor/github.com/opencontainers/go-digest/.pullapprove.yml create mode 100644 vendor/github.com/opencontainers/go-digest/.travis.yml create mode 100644 vendor/github.com/opencontainers/go-digest/CONTRIBUTING.md create mode 100644 vendor/github.com/opencontainers/go-digest/LICENSE create mode 100644 vendor/github.com/opencontainers/go-digest/LICENSE.docs create mode 100644 vendor/github.com/opencontainers/go-digest/MAINTAINERS create mode 100644 vendor/github.com/opencontainers/go-digest/README.md create mode 100644 vendor/github.com/opencontainers/go-digest/algorithm.go create mode 100644 vendor/github.com/opencontainers/go-digest/digest.go create mode 100644 vendor/github.com/opencontainers/go-digest/digester.go create mode 100644 vendor/github.com/opencontainers/go-digest/doc.go create mode 100644 vendor/github.com/opencontainers/go-digest/verifiers.go create mode 100644 vendor/github.com/opencontainers/image-spec/LICENSE create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/index.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/version.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/versioned.go create mode 100644 vendor/github.com/opencontainers/runc/LICENSE create mode 100644 vendor/github.com/opencontainers/runc/NOTICE create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/user/MAINTAINERS create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/user/lookup.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/user/lookup_windows.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/user/user.go create mode 100644 vendor/github.com/pelletier/go-toml/.gitignore create mode 100644 vendor/github.com/pelletier/go-toml/.travis.yml create mode 100644 vendor/github.com/pelletier/go-toml/LICENSE create mode 100644 vendor/github.com/pelletier/go-toml/README.md create mode 100644 vendor/github.com/pelletier/go-toml/benchmark.json create mode 100755 vendor/github.com/pelletier/go-toml/benchmark.sh create mode 100644 vendor/github.com/pelletier/go-toml/benchmark.toml create mode 100644 vendor/github.com/pelletier/go-toml/benchmark.yml create mode 100644 vendor/github.com/pelletier/go-toml/doc.go create mode 100644 vendor/github.com/pelletier/go-toml/example-crlf.toml create mode 100644 vendor/github.com/pelletier/go-toml/example.toml create mode 100644 vendor/github.com/pelletier/go-toml/keysparsing.go create mode 100644 vendor/github.com/pelletier/go-toml/lexer.go create mode 100644 vendor/github.com/pelletier/go-toml/marshal.go create mode 100644 vendor/github.com/pelletier/go-toml/marshal_test.toml create mode 100644 vendor/github.com/pelletier/go-toml/parser.go create mode 100644 vendor/github.com/pelletier/go-toml/position.go create mode 100755 vendor/github.com/pelletier/go-toml/test.sh create mode 100644 vendor/github.com/pelletier/go-toml/token.go create mode 100644 vendor/github.com/pelletier/go-toml/toml.go create mode 100644 vendor/github.com/pelletier/go-toml/tomltree_create.go create mode 100644 vendor/github.com/pelletier/go-toml/tomltree_write.go create mode 100644 vendor/github.com/petar/GoLLRB/AUTHORS create mode 100644 vendor/github.com/petar/GoLLRB/LICENSE create mode 100644 vendor/github.com/petar/GoLLRB/llrb/avgvar.go create mode 100644 vendor/github.com/petar/GoLLRB/llrb/iterator.go create mode 100644 vendor/github.com/petar/GoLLRB/llrb/llrb-stats.go create mode 100644 vendor/github.com/petar/GoLLRB/llrb/llrb.go create mode 100644 vendor/github.com/petar/GoLLRB/llrb/util.go create mode 100644 vendor/github.com/peterbourgon/diskv/LICENSE create mode 100644 vendor/github.com/peterbourgon/diskv/README.md create mode 100644 vendor/github.com/peterbourgon/diskv/compression.go create mode 100644 vendor/github.com/peterbourgon/diskv/diskv.go create mode 100644 vendor/github.com/peterbourgon/diskv/index.go create mode 100644 vendor/github.com/pkg/errors/.gitignore create mode 100644 vendor/github.com/pkg/errors/.travis.yml create mode 100644 vendor/github.com/pkg/errors/LICENSE create mode 100644 vendor/github.com/pkg/errors/README.md create mode 100644 vendor/github.com/pkg/errors/appveyor.yml create mode 100644 vendor/github.com/pkg/errors/errors.go create mode 100644 vendor/github.com/pkg/errors/stack.go create mode 100644 vendor/github.com/sirupsen/logrus/.gitignore create mode 100644 vendor/github.com/sirupsen/logrus/.travis.yml create mode 100644 vendor/github.com/sirupsen/logrus/CHANGELOG.md create mode 100644 vendor/github.com/sirupsen/logrus/LICENSE create mode 100644 vendor/github.com/sirupsen/logrus/README.md create mode 100644 vendor/github.com/sirupsen/logrus/alt_exit.go create mode 100644 vendor/github.com/sirupsen/logrus/appveyor.yml create mode 100644 vendor/github.com/sirupsen/logrus/doc.go create mode 100644 vendor/github.com/sirupsen/logrus/entry.go create mode 100644 vendor/github.com/sirupsen/logrus/exported.go create mode 100644 vendor/github.com/sirupsen/logrus/formatter.go create mode 100644 vendor/github.com/sirupsen/logrus/hooks.go create mode 100644 vendor/github.com/sirupsen/logrus/json_formatter.go create mode 100644 vendor/github.com/sirupsen/logrus/logger.go create mode 100644 vendor/github.com/sirupsen/logrus/logrus.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_bsd.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_linux.go create mode 100644 vendor/github.com/sirupsen/logrus/text_formatter.go create mode 100644 vendor/github.com/sirupsen/logrus/writer.go create mode 100644 vendor/github.com/spf13/afero/.travis.yml create mode 100644 vendor/github.com/spf13/afero/LICENSE.txt create mode 100644 vendor/github.com/spf13/afero/README.md create mode 100644 vendor/github.com/spf13/afero/afero.go create mode 100644 vendor/github.com/spf13/afero/appveyor.yml create mode 100644 vendor/github.com/spf13/afero/basepath.go create mode 100644 vendor/github.com/spf13/afero/cacheOnReadFs.go create mode 100644 vendor/github.com/spf13/afero/const_bsds.go create mode 100644 vendor/github.com/spf13/afero/const_win_unix.go create mode 100644 vendor/github.com/spf13/afero/copyOnWriteFs.go create mode 100644 vendor/github.com/spf13/afero/httpFs.go create mode 100644 vendor/github.com/spf13/afero/ioutil.go create mode 100644 vendor/github.com/spf13/afero/match.go create mode 100644 vendor/github.com/spf13/afero/mem/dir.go create mode 100644 vendor/github.com/spf13/afero/mem/dirmap.go create mode 100644 vendor/github.com/spf13/afero/mem/file.go create mode 100644 vendor/github.com/spf13/afero/memmap.go create mode 100644 vendor/github.com/spf13/afero/os.go create mode 100644 vendor/github.com/spf13/afero/path.go create mode 100644 vendor/github.com/spf13/afero/readonlyfs.go create mode 100644 vendor/github.com/spf13/afero/regexpfs.go create mode 100644 vendor/github.com/spf13/afero/unionFile.go create mode 100644 vendor/github.com/spf13/afero/util.go create mode 100644 vendor/github.com/spf13/cast/.gitignore create mode 100644 vendor/github.com/spf13/cast/.travis.yml create mode 100644 vendor/github.com/spf13/cast/LICENSE create mode 100644 vendor/github.com/spf13/cast/Makefile create mode 100644 vendor/github.com/spf13/cast/README.md create mode 100644 vendor/github.com/spf13/cast/cast.go create mode 100644 vendor/github.com/spf13/cast/caste.go create mode 100644 vendor/github.com/spf13/cobra/.gitignore create mode 100644 vendor/github.com/spf13/cobra/.mailmap create mode 100644 vendor/github.com/spf13/cobra/.travis.yml create mode 100644 vendor/github.com/spf13/cobra/LICENSE.txt create mode 100644 vendor/github.com/spf13/cobra/README.md create mode 100644 vendor/github.com/spf13/cobra/bash_completions.go create mode 100644 vendor/github.com/spf13/cobra/bash_completions.md create mode 100644 vendor/github.com/spf13/cobra/cobra.go create mode 100644 vendor/github.com/spf13/cobra/command.go create mode 100644 vendor/github.com/spf13/cobra/command_notwin.go create mode 100644 vendor/github.com/spf13/cobra/command_win.go create mode 100644 vendor/github.com/spf13/jwalterweatherman/.gitignore create mode 100644 vendor/github.com/spf13/jwalterweatherman/LICENSE create mode 100644 vendor/github.com/spf13/jwalterweatherman/README.md create mode 100644 vendor/github.com/spf13/jwalterweatherman/default_notepad.go create mode 100644 vendor/github.com/spf13/jwalterweatherman/log_counter.go create mode 100644 vendor/github.com/spf13/jwalterweatherman/notepad.go create mode 100644 vendor/github.com/spf13/pflag/.gitignore create mode 100644 vendor/github.com/spf13/pflag/.travis.yml create mode 100644 vendor/github.com/spf13/pflag/LICENSE create mode 100644 vendor/github.com/spf13/pflag/README.md create mode 100644 vendor/github.com/spf13/pflag/bool.go create mode 100644 vendor/github.com/spf13/pflag/bool_slice.go create mode 100644 vendor/github.com/spf13/pflag/count.go create mode 100644 vendor/github.com/spf13/pflag/duration.go create mode 100644 vendor/github.com/spf13/pflag/flag.go create mode 100644 vendor/github.com/spf13/pflag/float32.go create mode 100644 vendor/github.com/spf13/pflag/float64.go create mode 100644 vendor/github.com/spf13/pflag/golangflag.go create mode 100644 vendor/github.com/spf13/pflag/int.go create mode 100644 vendor/github.com/spf13/pflag/int32.go create mode 100644 vendor/github.com/spf13/pflag/int64.go create mode 100644 vendor/github.com/spf13/pflag/int8.go create mode 100644 vendor/github.com/spf13/pflag/int_slice.go create mode 100644 vendor/github.com/spf13/pflag/ip.go create mode 100644 vendor/github.com/spf13/pflag/ip_slice.go create mode 100644 vendor/github.com/spf13/pflag/ipmask.go create mode 100644 vendor/github.com/spf13/pflag/ipnet.go create mode 100644 vendor/github.com/spf13/pflag/string.go create mode 100644 vendor/github.com/spf13/pflag/string_array.go create mode 100644 vendor/github.com/spf13/pflag/string_slice.go create mode 100644 vendor/github.com/spf13/pflag/uint.go create mode 100644 vendor/github.com/spf13/pflag/uint16.go create mode 100644 vendor/github.com/spf13/pflag/uint32.go create mode 100644 vendor/github.com/spf13/pflag/uint64.go create mode 100644 vendor/github.com/spf13/pflag/uint8.go create mode 100644 vendor/github.com/spf13/pflag/uint_slice.go create mode 100644 vendor/github.com/spf13/viper/.gitignore create mode 100644 vendor/github.com/spf13/viper/.travis.yml create mode 100644 vendor/github.com/spf13/viper/LICENSE create mode 100644 vendor/github.com/spf13/viper/README.md create mode 100644 vendor/github.com/spf13/viper/flags.go create mode 100644 vendor/github.com/spf13/viper/nohup.out create mode 100644 vendor/github.com/spf13/viper/util.go create mode 100644 vendor/github.com/spf13/viper/viper.go create mode 100644 vendor/golang.org/x/crypto/AUTHORS create mode 100644 vendor/golang.org/x/crypto/CONTRIBUTORS create mode 100644 vendor/golang.org/x/crypto/LICENSE create mode 100644 vendor/golang.org/x/crypto/PATENTS create mode 100644 vendor/golang.org/x/crypto/curve25519/const_amd64.h create mode 100644 vendor/golang.org/x/crypto/curve25519/const_amd64.s create mode 100644 vendor/golang.org/x/crypto/curve25519/cswap_amd64.s create mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519.go create mode 100644 vendor/golang.org/x/crypto/curve25519/doc.go create mode 100644 vendor/golang.org/x/crypto/curve25519/freeze_amd64.s create mode 100644 vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s create mode 100644 vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go create mode 100644 vendor/golang.org/x/crypto/curve25519/mul_amd64.s create mode 100644 vendor/golang.org/x/crypto/curve25519/square_amd64.s create mode 100644 vendor/golang.org/x/crypto/ed25519/ed25519.go create mode 100644 vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go create mode 100644 vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go create mode 100644 vendor/golang.org/x/crypto/ssh/buffer.go create mode 100644 vendor/golang.org/x/crypto/ssh/certs.go create mode 100644 vendor/golang.org/x/crypto/ssh/channel.go create mode 100644 vendor/golang.org/x/crypto/ssh/cipher.go create mode 100644 vendor/golang.org/x/crypto/ssh/client.go create mode 100644 vendor/golang.org/x/crypto/ssh/client_auth.go create mode 100644 vendor/golang.org/x/crypto/ssh/common.go create mode 100644 vendor/golang.org/x/crypto/ssh/connection.go create mode 100644 vendor/golang.org/x/crypto/ssh/doc.go create mode 100644 vendor/golang.org/x/crypto/ssh/handshake.go create mode 100644 vendor/golang.org/x/crypto/ssh/kex.go create mode 100644 vendor/golang.org/x/crypto/ssh/keys.go create mode 100644 vendor/golang.org/x/crypto/ssh/mac.go create mode 100644 vendor/golang.org/x/crypto/ssh/messages.go create mode 100644 vendor/golang.org/x/crypto/ssh/mux.go create mode 100644 vendor/golang.org/x/crypto/ssh/server.go create mode 100644 vendor/golang.org/x/crypto/ssh/session.go create mode 100644 vendor/golang.org/x/crypto/ssh/streamlocal.go create mode 100644 vendor/golang.org/x/crypto/ssh/tcpip.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/terminal.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_linux.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_windows.go create mode 100644 vendor/golang.org/x/crypto/ssh/transport.go create mode 100644 vendor/golang.org/x/net/AUTHORS create mode 100644 vendor/golang.org/x/net/CONTRIBUTORS create mode 100644 vendor/golang.org/x/net/LICENSE create mode 100644 vendor/golang.org/x/net/PATENTS create mode 100644 vendor/golang.org/x/net/context/context.go create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go create mode 100644 vendor/golang.org/x/net/context/go17.go create mode 100644 vendor/golang.org/x/net/context/go19.go create mode 100644 vendor/golang.org/x/net/context/pre_go17.go create mode 100644 vendor/golang.org/x/net/context/pre_go19.go create mode 100644 vendor/golang.org/x/net/http2/.gitignore create mode 100644 vendor/golang.org/x/net/http2/Dockerfile create mode 100644 vendor/golang.org/x/net/http2/Makefile create mode 100644 vendor/golang.org/x/net/http2/README create mode 100644 vendor/golang.org/x/net/http2/ciphers.go create mode 100644 vendor/golang.org/x/net/http2/client_conn_pool.go create mode 100644 vendor/golang.org/x/net/http2/configure_transport.go create mode 100644 vendor/golang.org/x/net/http2/databuffer.go create mode 100644 vendor/golang.org/x/net/http2/errors.go create mode 100644 vendor/golang.org/x/net/http2/flow.go create mode 100644 vendor/golang.org/x/net/http2/frame.go create mode 100644 vendor/golang.org/x/net/http2/go16.go create mode 100644 vendor/golang.org/x/net/http2/go17.go create mode 100644 vendor/golang.org/x/net/http2/go17_not18.go create mode 100644 vendor/golang.org/x/net/http2/go18.go create mode 100644 vendor/golang.org/x/net/http2/go19.go create mode 100644 vendor/golang.org/x/net/http2/gotrack.go create mode 100644 vendor/golang.org/x/net/http2/headermap.go create mode 100644 vendor/golang.org/x/net/http2/hpack/encode.go create mode 100644 vendor/golang.org/x/net/http2/hpack/hpack.go create mode 100644 vendor/golang.org/x/net/http2/hpack/huffman.go create mode 100644 vendor/golang.org/x/net/http2/hpack/tables.go create mode 100644 vendor/golang.org/x/net/http2/http2.go create mode 100644 vendor/golang.org/x/net/http2/not_go16.go create mode 100644 vendor/golang.org/x/net/http2/not_go17.go create mode 100644 vendor/golang.org/x/net/http2/not_go18.go create mode 100644 vendor/golang.org/x/net/http2/not_go19.go create mode 100644 vendor/golang.org/x/net/http2/pipe.go create mode 100644 vendor/golang.org/x/net/http2/server.go create mode 100644 vendor/golang.org/x/net/http2/transport.go create mode 100644 vendor/golang.org/x/net/http2/write.go create mode 100644 vendor/golang.org/x/net/http2/writesched.go create mode 100644 vendor/golang.org/x/net/http2/writesched_priority.go create mode 100644 vendor/golang.org/x/net/http2/writesched_random.go create mode 100644 vendor/golang.org/x/net/idna/idna.go create mode 100644 vendor/golang.org/x/net/idna/punycode.go create mode 100644 vendor/golang.org/x/net/idna/tables.go create mode 100644 vendor/golang.org/x/net/idna/trie.go create mode 100644 vendor/golang.org/x/net/idna/trieval.go create mode 100644 vendor/golang.org/x/net/lex/httplex/httplex.go create mode 100644 vendor/golang.org/x/oauth2/.travis.yml create mode 100644 vendor/golang.org/x/oauth2/AUTHORS create mode 100644 vendor/golang.org/x/oauth2/CONTRIBUTING.md create mode 100644 vendor/golang.org/x/oauth2/CONTRIBUTORS create mode 100644 vendor/golang.org/x/oauth2/LICENSE create mode 100644 vendor/golang.org/x/oauth2/README.md create mode 100644 vendor/golang.org/x/oauth2/google/appengine.go create mode 100644 vendor/golang.org/x/oauth2/google/appengine_hook.go create mode 100644 vendor/golang.org/x/oauth2/google/appengineflex_hook.go create mode 100644 vendor/golang.org/x/oauth2/google/default.go create mode 100644 vendor/golang.org/x/oauth2/google/doc_go19.go create mode 100644 vendor/golang.org/x/oauth2/google/doc_not_go19.go create mode 100644 vendor/golang.org/x/oauth2/google/go19.go create mode 100644 vendor/golang.org/x/oauth2/google/google.go create mode 100644 vendor/golang.org/x/oauth2/google/jwt.go create mode 100644 vendor/golang.org/x/oauth2/google/not_go19.go create mode 100644 vendor/golang.org/x/oauth2/google/sdk.go create mode 100644 vendor/golang.org/x/oauth2/internal/client_appengine.go create mode 100644 vendor/golang.org/x/oauth2/internal/doc.go create mode 100644 vendor/golang.org/x/oauth2/internal/oauth2.go create mode 100644 vendor/golang.org/x/oauth2/internal/token.go create mode 100644 vendor/golang.org/x/oauth2/internal/transport.go create mode 100644 vendor/golang.org/x/oauth2/jws/jws.go create mode 100644 vendor/golang.org/x/oauth2/jwt/jwt.go create mode 100644 vendor/golang.org/x/oauth2/oauth2.go create mode 100644 vendor/golang.org/x/oauth2/token.go create mode 100644 vendor/golang.org/x/oauth2/transport.go create mode 100644 vendor/golang.org/x/sys/AUTHORS create mode 100644 vendor/golang.org/x/sys/CONTRIBUTORS create mode 100644 vendor/golang.org/x/sys/LICENSE create mode 100644 vendor/golang.org/x/sys/PATENTS create mode 100644 vendor/golang.org/x/sys/unix/.gitignore create mode 100644 vendor/golang.org/x/sys/unix/README.md create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_mips64x.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_mipsx.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_s390x.s create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_solaris_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/bluetooth_linux.go create mode 100644 vendor/golang.org/x/sys/unix/cap_freebsd.go create mode 100644 vendor/golang.org/x/sys/unix/constants.go create mode 100644 vendor/golang.org/x/sys/unix/dev_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/dev_dragonfly.go create mode 100644 vendor/golang.org/x/sys/unix/dev_freebsd.go create mode 100644 vendor/golang.org/x/sys/unix/dev_linux.go create mode 100644 vendor/golang.org/x/sys/unix/dev_netbsd.go create mode 100644 vendor/golang.org/x/sys/unix/dev_openbsd.go create mode 100644 vendor/golang.org/x/sys/unix/dirent.go create mode 100644 vendor/golang.org/x/sys/unix/endian_big.go create mode 100644 vendor/golang.org/x/sys/unix/endian_little.go create mode 100644 vendor/golang.org/x/sys/unix/env_unix.go create mode 100644 vendor/golang.org/x/sys/unix/env_unset.go create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/file_unix.go create mode 100644 vendor/golang.org/x/sys/unix/flock.go create mode 100644 vendor/golang.org/x/sys/unix/flock_linux_32bit.go create mode 100644 vendor/golang.org/x/sys/unix/gccgo.go create mode 100644 vendor/golang.org/x/sys/unix/gccgo_c.c create mode 100644 vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go create mode 100755 vendor/golang.org/x/sys/unix/mkall.sh create mode 100755 vendor/golang.org/x/sys/unix/mkerrors.sh create mode 100644 vendor/golang.org/x/sys/unix/mkpost.go create mode 100755 vendor/golang.org/x/sys/unix/mksyscall.pl create mode 100755 vendor/golang.org/x/sys/unix/mksyscall_solaris.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_darwin.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl create mode 100644 vendor/golang.org/x/sys/unix/openbsd_pledge.go create mode 100644 vendor/golang.org/x/sys/unix/pagesize_unix.go create mode 100644 vendor/golang.org/x/sys/unix/race.go create mode 100644 vendor/golang.org/x/sys/unix/race0.go create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_linux.go create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_unix.go create mode 100644 vendor/golang.org/x/sys/unix/str.go create mode 100644 vendor/golang.org/x/sys/unix/syscall.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_bsd.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_dragonfly.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_no_getwd.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix_gc.go create mode 100644 vendor/golang.org/x/sys/unix/timestruct.go create mode 100644 vendor/golang.org/x/sys/unix/types_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/types_dragonfly.go create mode 100644 vendor/golang.org/x/sys/unix/types_freebsd.go create mode 100644 vendor/golang.org/x/sys/unix/types_netbsd.go create mode 100644 vendor/golang.org/x/sys/unix/types_openbsd.go create mode 100644 vendor/golang.org/x/sys/unix/types_solaris.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zptrace386_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zptracearm_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zptracemips_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zptracemipsle_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_solaris_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go create mode 100644 vendor/golang.org/x/sys/windows/asm_windows_386.s create mode 100644 vendor/golang.org/x/sys/windows/asm_windows_amd64.s create mode 100644 vendor/golang.org/x/sys/windows/dll_windows.go create mode 100644 vendor/golang.org/x/sys/windows/env_unset.go create mode 100644 vendor/golang.org/x/sys/windows/env_windows.go create mode 100644 vendor/golang.org/x/sys/windows/eventlog.go create mode 100644 vendor/golang.org/x/sys/windows/exec_windows.go create mode 100644 vendor/golang.org/x/sys/windows/memory_windows.go create mode 100644 vendor/golang.org/x/sys/windows/mksyscall.go create mode 100644 vendor/golang.org/x/sys/windows/race.go create mode 100644 vendor/golang.org/x/sys/windows/race0.go create mode 100644 vendor/golang.org/x/sys/windows/security_windows.go create mode 100644 vendor/golang.org/x/sys/windows/service.go create mode 100644 vendor/golang.org/x/sys/windows/str.go create mode 100644 vendor/golang.org/x/sys/windows/syscall.go create mode 100644 vendor/golang.org/x/sys/windows/syscall_windows.go create mode 100644 vendor/golang.org/x/sys/windows/types_windows.go create mode 100644 vendor/golang.org/x/sys/windows/types_windows_386.go create mode 100644 vendor/golang.org/x/sys/windows/types_windows_amd64.go create mode 100644 vendor/golang.org/x/sys/windows/zsyscall_windows.go create mode 100644 vendor/golang.org/x/text/AUTHORS create mode 100644 vendor/golang.org/x/text/CONTRIBUTORS create mode 100644 vendor/golang.org/x/text/LICENSE create mode 100644 vendor/golang.org/x/text/PATENTS create mode 100644 vendor/golang.org/x/text/cases/cases.go create mode 100644 vendor/golang.org/x/text/cases/context.go create mode 100644 vendor/golang.org/x/text/cases/fold.go create mode 100644 vendor/golang.org/x/text/cases/gen.go create mode 100644 vendor/golang.org/x/text/cases/gen_trieval.go create mode 100644 vendor/golang.org/x/text/cases/icu.go create mode 100644 vendor/golang.org/x/text/cases/info.go create mode 100644 vendor/golang.org/x/text/cases/map.go create mode 100644 vendor/golang.org/x/text/cases/tables.go create mode 100644 vendor/golang.org/x/text/cases/trieval.go create mode 100644 vendor/golang.org/x/text/internal/gen.go create mode 100644 vendor/golang.org/x/text/internal/gen/code.go create mode 100644 vendor/golang.org/x/text/internal/gen/gen.go create mode 100644 vendor/golang.org/x/text/internal/internal.go create mode 100644 vendor/golang.org/x/text/internal/match.go create mode 100644 vendor/golang.org/x/text/internal/tables.go create mode 100644 vendor/golang.org/x/text/internal/tag/tag.go create mode 100644 vendor/golang.org/x/text/internal/triegen/compact.go create mode 100644 vendor/golang.org/x/text/internal/triegen/print.go create mode 100644 vendor/golang.org/x/text/internal/triegen/triegen.go create mode 100644 vendor/golang.org/x/text/internal/ucd/ucd.go create mode 100644 vendor/golang.org/x/text/language/Makefile create mode 100644 vendor/golang.org/x/text/language/common.go create mode 100644 vendor/golang.org/x/text/language/coverage.go create mode 100644 vendor/golang.org/x/text/language/gen.go create mode 100644 vendor/golang.org/x/text/language/gen_common.go create mode 100644 vendor/golang.org/x/text/language/gen_index.go create mode 100644 vendor/golang.org/x/text/language/go1_1.go create mode 100644 vendor/golang.org/x/text/language/go1_2.go create mode 100644 vendor/golang.org/x/text/language/index.go create mode 100644 vendor/golang.org/x/text/language/language.go create mode 100644 vendor/golang.org/x/text/language/lookup.go create mode 100644 vendor/golang.org/x/text/language/match.go create mode 100644 vendor/golang.org/x/text/language/parse.go create mode 100644 vendor/golang.org/x/text/language/tables.go create mode 100644 vendor/golang.org/x/text/language/tags.go create mode 100644 vendor/golang.org/x/text/runes/cond.go create mode 100644 vendor/golang.org/x/text/runes/runes.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule.go create mode 100644 vendor/golang.org/x/text/secure/precis/class.go create mode 100644 vendor/golang.org/x/text/secure/precis/context.go create mode 100644 vendor/golang.org/x/text/secure/precis/doc.go create mode 100644 vendor/golang.org/x/text/secure/precis/gen.go create mode 100644 vendor/golang.org/x/text/secure/precis/gen_trieval.go create mode 100644 vendor/golang.org/x/text/secure/precis/nickname.go create mode 100644 vendor/golang.org/x/text/secure/precis/options.go create mode 100644 vendor/golang.org/x/text/secure/precis/profile.go create mode 100644 vendor/golang.org/x/text/secure/precis/profiles.go create mode 100644 vendor/golang.org/x/text/secure/precis/tables.go create mode 100644 vendor/golang.org/x/text/secure/precis/transformer.go create mode 100644 vendor/golang.org/x/text/secure/precis/trieval.go create mode 100644 vendor/golang.org/x/text/transform/transform.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/bidi.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/bracket.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/core.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/gen.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/gen_ranges.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/gen_trieval.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/prop.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/trieval.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/base.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/cldr.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/collate.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/decode.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/makexml.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/resolve.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/slice.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/xml.go create mode 100644 vendor/golang.org/x/text/unicode/norm/composition.go create mode 100644 vendor/golang.org/x/text/unicode/norm/forminfo.go create mode 100644 vendor/golang.org/x/text/unicode/norm/input.go create mode 100644 vendor/golang.org/x/text/unicode/norm/iter.go create mode 100644 vendor/golang.org/x/text/unicode/norm/maketables.go create mode 100644 vendor/golang.org/x/text/unicode/norm/normalize.go create mode 100644 vendor/golang.org/x/text/unicode/norm/readwriter.go create mode 100644 vendor/golang.org/x/text/unicode/norm/tables.go create mode 100644 vendor/golang.org/x/text/unicode/norm/transform.go create mode 100644 vendor/golang.org/x/text/unicode/norm/trie.go create mode 100644 vendor/golang.org/x/text/unicode/norm/triegen.go create mode 100644 vendor/golang.org/x/text/unicode/rangetable/gen.go create mode 100644 vendor/golang.org/x/text/unicode/rangetable/merge.go create mode 100644 vendor/golang.org/x/text/unicode/rangetable/rangetable.go create mode 100644 vendor/golang.org/x/text/unicode/rangetable/tables.go create mode 100644 vendor/golang.org/x/text/width/gen.go create mode 100644 vendor/golang.org/x/text/width/gen_common.go create mode 100644 vendor/golang.org/x/text/width/gen_trieval.go create mode 100644 vendor/golang.org/x/text/width/kind_string.go create mode 100644 vendor/golang.org/x/text/width/tables.go create mode 100644 vendor/golang.org/x/text/width/transform.go create mode 100644 vendor/golang.org/x/text/width/trieval.go create mode 100644 vendor/golang.org/x/text/width/width.go create mode 100644 vendor/google.golang.org/appengine/.travis.yml create mode 100644 vendor/google.golang.org/appengine/CONTRIBUTING.md create mode 100644 vendor/google.golang.org/appengine/LICENSE create mode 100644 vendor/google.golang.org/appengine/README.md create mode 100644 vendor/google.golang.org/appengine/appengine.go create mode 100644 vendor/google.golang.org/appengine/appengine_vm.go create mode 100644 vendor/google.golang.org/appengine/errors.go create mode 100644 vendor/google.golang.org/appengine/go.mod create mode 100644 vendor/google.golang.org/appengine/go.sum create mode 100644 vendor/google.golang.org/appengine/identity.go create mode 100644 vendor/google.golang.org/appengine/internal/api.go create mode 100644 vendor/google.golang.org/appengine/internal/api_classic.go create mode 100644 vendor/google.golang.org/appengine/internal/api_common.go create mode 100644 vendor/google.golang.org/appengine/internal/api_pre17.go create mode 100644 vendor/google.golang.org/appengine/internal/app_id.go create mode 100644 vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/base/api_base.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/base/api_base.proto create mode 100644 vendor/google.golang.org/appengine/internal/datastore/datastore_v3.pb.go create mode 100755 vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto create mode 100644 vendor/google.golang.org/appengine/internal/identity.go create mode 100644 vendor/google.golang.org/appengine/internal/identity_classic.go create mode 100644 vendor/google.golang.org/appengine/internal/identity_vm.go create mode 100644 vendor/google.golang.org/appengine/internal/internal.go create mode 100644 vendor/google.golang.org/appengine/internal/log/log_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/log/log_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/main.go create mode 100644 vendor/google.golang.org/appengine/internal/main_vm.go create mode 100644 vendor/google.golang.org/appengine/internal/metadata.go create mode 100644 vendor/google.golang.org/appengine/internal/modules/modules_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/modules/modules_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/net.go create mode 100755 vendor/google.golang.org/appengine/internal/regen.sh create mode 100644 vendor/google.golang.org/appengine/internal/remote_api/remote_api.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/remote_api/remote_api.proto create mode 100644 vendor/google.golang.org/appengine/internal/transaction.go create mode 100644 vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto create mode 100644 vendor/google.golang.org/appengine/namespace.go create mode 100644 vendor/google.golang.org/appengine/timeout.go create mode 100644 vendor/google.golang.org/appengine/urlfetch/urlfetch.go create mode 100644 vendor/gopkg.in/inf.v0/LICENSE create mode 100644 vendor/gopkg.in/inf.v0/dec.go create mode 100644 vendor/gopkg.in/inf.v0/rounder.go create mode 100644 vendor/gopkg.in/ory-am/dockertest.v3/.gitignore create mode 100644 vendor/gopkg.in/ory-am/dockertest.v3/.travis.yml create mode 100644 vendor/gopkg.in/ory-am/dockertest.v3/CONTRIBUTING.md create mode 100644 vendor/gopkg.in/ory-am/dockertest.v3/Gopkg.lock create mode 100644 vendor/gopkg.in/ory-am/dockertest.v3/Gopkg.toml create mode 100644 vendor/gopkg.in/ory-am/dockertest.v3/LICENSE create mode 100644 vendor/gopkg.in/ory-am/dockertest.v3/README.md create mode 100644 vendor/gopkg.in/ory-am/dockertest.v3/dockertest.go create mode 100644 vendor/gopkg.in/robfig/cron.v2/.gitignore create mode 100644 vendor/gopkg.in/robfig/cron.v2/.travis.yml create mode 100644 vendor/gopkg.in/robfig/cron.v2/LICENSE create mode 100644 vendor/gopkg.in/robfig/cron.v2/README.md create mode 100644 vendor/gopkg.in/robfig/cron.v2/constantdelay.go create mode 100644 vendor/gopkg.in/robfig/cron.v2/cron.go create mode 100644 vendor/gopkg.in/robfig/cron.v2/doc.go create mode 100644 vendor/gopkg.in/robfig/cron.v2/parser.go create mode 100644 vendor/gopkg.in/robfig/cron.v2/spec.go create mode 100644 vendor/gopkg.in/yaml.v2/LICENSE create mode 100644 vendor/gopkg.in/yaml.v2/LICENSE.libyaml create mode 100644 vendor/gopkg.in/yaml.v2/README.md create mode 100644 vendor/gopkg.in/yaml.v2/apic.go create mode 100644 vendor/gopkg.in/yaml.v2/decode.go create mode 100644 vendor/gopkg.in/yaml.v2/emitterc.go create mode 100644 vendor/gopkg.in/yaml.v2/encode.go create mode 100644 vendor/gopkg.in/yaml.v2/parserc.go create mode 100644 vendor/gopkg.in/yaml.v2/readerc.go create mode 100644 vendor/gopkg.in/yaml.v2/resolve.go create mode 100644 vendor/gopkg.in/yaml.v2/scannerc.go create mode 100644 vendor/gopkg.in/yaml.v2/sorter.go create mode 100644 vendor/gopkg.in/yaml.v2/writerc.go create mode 100644 vendor/gopkg.in/yaml.v2/yaml.go create mode 100644 vendor/gopkg.in/yaml.v2/yamlh.go create mode 100644 vendor/gopkg.in/yaml.v2/yamlprivateh.go create mode 100644 vendor/k8s.io/api/LICENSE create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/BUILD create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/doc.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/register.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/types.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/register.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/types.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/apps/v1/BUILD create mode 100644 vendor/k8s.io/api/apps/v1/doc.go create mode 100644 vendor/k8s.io/api/apps/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/apps/v1/generated.proto create mode 100644 vendor/k8s.io/api/apps/v1/register.go create mode 100644 vendor/k8s.io/api/apps/v1/types.go create mode 100644 vendor/k8s.io/api/apps/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/apps/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/apps/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/apps/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/apps/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/apps/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/apps/v1beta1/register.go create mode 100644 vendor/k8s.io/api/apps/v1beta1/types.go create mode 100644 vendor/k8s.io/api/apps/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/apps/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/apps/v1beta2/BUILD create mode 100644 vendor/k8s.io/api/apps/v1beta2/doc.go create mode 100644 vendor/k8s.io/api/apps/v1beta2/generated.pb.go create mode 100644 vendor/k8s.io/api/apps/v1beta2/generated.proto create mode 100644 vendor/k8s.io/api/apps/v1beta2/register.go create mode 100644 vendor/k8s.io/api/apps/v1beta2/types.go create mode 100644 vendor/k8s.io/api/apps/v1beta2/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/apps/v1beta2/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/authentication/v1/BUILD create mode 100644 vendor/k8s.io/api/authentication/v1/doc.go create mode 100644 vendor/k8s.io/api/authentication/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/authentication/v1/generated.proto create mode 100644 vendor/k8s.io/api/authentication/v1/register.go create mode 100644 vendor/k8s.io/api/authentication/v1/types.go create mode 100644 vendor/k8s.io/api/authentication/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/authentication/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/authentication/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/authentication/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/authentication/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/authentication/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/authentication/v1beta1/register.go create mode 100644 vendor/k8s.io/api/authentication/v1beta1/types.go create mode 100644 vendor/k8s.io/api/authentication/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/authentication/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/authorization/v1/BUILD create mode 100644 vendor/k8s.io/api/authorization/v1/doc.go create mode 100644 vendor/k8s.io/api/authorization/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/authorization/v1/generated.proto create mode 100644 vendor/k8s.io/api/authorization/v1/register.go create mode 100644 vendor/k8s.io/api/authorization/v1/types.go create mode 100644 vendor/k8s.io/api/authorization/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/authorization/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/authorization/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/authorization/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/authorization/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/authorization/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/authorization/v1beta1/register.go create mode 100644 vendor/k8s.io/api/authorization/v1beta1/types.go create mode 100644 vendor/k8s.io/api/authorization/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/authorization/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/autoscaling/v1/BUILD create mode 100644 vendor/k8s.io/api/autoscaling/v1/doc.go create mode 100644 vendor/k8s.io/api/autoscaling/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/autoscaling/v1/generated.proto create mode 100644 vendor/k8s.io/api/autoscaling/v1/register.go create mode 100644 vendor/k8s.io/api/autoscaling/v1/types.go create mode 100644 vendor/k8s.io/api/autoscaling/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/autoscaling/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/BUILD create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/doc.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/generated.proto create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/register.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/types.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/batch/v1/BUILD create mode 100644 vendor/k8s.io/api/batch/v1/doc.go create mode 100644 vendor/k8s.io/api/batch/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/batch/v1/generated.proto create mode 100644 vendor/k8s.io/api/batch/v1/register.go create mode 100644 vendor/k8s.io/api/batch/v1/types.go create mode 100644 vendor/k8s.io/api/batch/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/batch/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/batch/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/batch/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/batch/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/batch/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/batch/v1beta1/register.go create mode 100644 vendor/k8s.io/api/batch/v1beta1/types.go create mode 100644 vendor/k8s.io/api/batch/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/batch/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/batch/v2alpha1/BUILD create mode 100644 vendor/k8s.io/api/batch/v2alpha1/doc.go create mode 100644 vendor/k8s.io/api/batch/v2alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/batch/v2alpha1/generated.proto create mode 100644 vendor/k8s.io/api/batch/v2alpha1/register.go create mode 100644 vendor/k8s.io/api/batch/v2alpha1/types.go create mode 100644 vendor/k8s.io/api/batch/v2alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/batch/v2alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/certificates/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/certificates/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/certificates/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/certificates/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/certificates/v1beta1/register.go create mode 100644 vendor/k8s.io/api/certificates/v1beta1/types.go create mode 100644 vendor/k8s.io/api/certificates/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/certificates/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/core/v1/BUILD create mode 100644 vendor/k8s.io/api/core/v1/annotation_key_constants.go create mode 100644 vendor/k8s.io/api/core/v1/doc.go create mode 100644 vendor/k8s.io/api/core/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/core/v1/generated.proto create mode 100644 vendor/k8s.io/api/core/v1/meta.go create mode 100644 vendor/k8s.io/api/core/v1/objectreference.go create mode 100644 vendor/k8s.io/api/core/v1/register.go create mode 100644 vendor/k8s.io/api/core/v1/resource.go create mode 100644 vendor/k8s.io/api/core/v1/taint.go create mode 100644 vendor/k8s.io/api/core/v1/toleration.go create mode 100644 vendor/k8s.io/api/core/v1/types.go create mode 100644 vendor/k8s.io/api/core/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/core/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/events/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/events/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/events/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/events/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/events/v1beta1/register.go create mode 100644 vendor/k8s.io/api/events/v1beta1/types.go create mode 100644 vendor/k8s.io/api/events/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/events/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/extensions/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/extensions/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/extensions/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/extensions/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/extensions/v1beta1/register.go create mode 100644 vendor/k8s.io/api/extensions/v1beta1/types.go create mode 100644 vendor/k8s.io/api/extensions/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/extensions/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/networking/v1/BUILD create mode 100644 vendor/k8s.io/api/networking/v1/doc.go create mode 100644 vendor/k8s.io/api/networking/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/networking/v1/generated.proto create mode 100644 vendor/k8s.io/api/networking/v1/register.go create mode 100644 vendor/k8s.io/api/networking/v1/types.go create mode 100644 vendor/k8s.io/api/networking/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/networking/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/policy/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/policy/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/policy/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/policy/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/policy/v1beta1/register.go create mode 100644 vendor/k8s.io/api/policy/v1beta1/types.go create mode 100644 vendor/k8s.io/api/policy/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/policy/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/rbac/v1/BUILD create mode 100644 vendor/k8s.io/api/rbac/v1/doc.go create mode 100644 vendor/k8s.io/api/rbac/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/rbac/v1/generated.proto create mode 100644 vendor/k8s.io/api/rbac/v1/register.go create mode 100644 vendor/k8s.io/api/rbac/v1/types.go create mode 100644 vendor/k8s.io/api/rbac/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/rbac/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/BUILD create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/doc.go create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/register.go create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/types.go create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/rbac/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/rbac/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/rbac/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/rbac/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/rbac/v1beta1/register.go create mode 100644 vendor/k8s.io/api/rbac/v1beta1/types.go create mode 100644 vendor/k8s.io/api/rbac/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/rbac/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/BUILD create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/doc.go create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/register.go create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/types.go create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/settings/v1alpha1/BUILD create mode 100644 vendor/k8s.io/api/settings/v1alpha1/doc.go create mode 100644 vendor/k8s.io/api/settings/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/settings/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/settings/v1alpha1/register.go create mode 100644 vendor/k8s.io/api/settings/v1alpha1/types.go create mode 100644 vendor/k8s.io/api/settings/v1alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/settings/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/storage/v1/BUILD create mode 100644 vendor/k8s.io/api/storage/v1/doc.go create mode 100644 vendor/k8s.io/api/storage/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/storage/v1/generated.proto create mode 100644 vendor/k8s.io/api/storage/v1/register.go create mode 100644 vendor/k8s.io/api/storage/v1/types.go create mode 100644 vendor/k8s.io/api/storage/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/storage/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/storage/v1alpha1/BUILD create mode 100644 vendor/k8s.io/api/storage/v1alpha1/doc.go create mode 100644 vendor/k8s.io/api/storage/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/storage/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/storage/v1alpha1/register.go create mode 100644 vendor/k8s.io/api/storage/v1alpha1/types.go create mode 100644 vendor/k8s.io/api/storage/v1alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/storage/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/storage/v1beta1/BUILD create mode 100644 vendor/k8s.io/api/storage/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/storage/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/storage/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/storage/v1beta1/register.go create mode 100644 vendor/k8s.io/api/storage/v1beta1/types.go create mode 100644 vendor/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/storage/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/apimachinery/LICENSE create mode 100644 vendor/k8s.io/apimachinery/pkg/api/errors/BUILD create mode 100755 vendor/k8s.io/apimachinery/pkg/api/errors/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/api/errors/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/errors/errors.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/BUILD create mode 100755 vendor/k8s.io/apimachinery/pkg/api/meta/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/errors.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/firsthit_restmapper.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/help.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/interfaces.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/lazy.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/meta.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/priority.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/restmapper.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/unstructured.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/BUILD create mode 100755 vendor/k8s.io/apimachinery/pkg/api/resource/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/amount.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/generated.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/math.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/quantity.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/scale_int.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/suffix.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/BUILD create mode 100755 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/conversion.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/meta.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_proto.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/register.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_proto.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/types.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_list.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/watch.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/zz_generated.defaults.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/conversion.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/deepcopy.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/register.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/types.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1/zz_generated.defaults.go create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/converter.go create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/deep_equal.go create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/helper.go create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/queryparams/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert.go create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/fields/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/fields/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/fields/fields.go create mode 100644 vendor/k8s.io/apimachinery/pkg/fields/requirements.go create mode 100644 vendor/k8s.io/apimachinery/pkg/fields/selector.go create mode 100644 vendor/k8s.io/apimachinery/pkg/labels/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/labels/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/labels/labels.go create mode 100644 vendor/k8s.io/apimachinery/pkg/labels/selector.go create mode 100644 vendor/k8s.io/apimachinery/pkg/labels/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/codec.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/codec_check.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/conversion.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/converter.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/embedded.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/error.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/extension.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/generated.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/helper.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/interfaces.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/register.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/schema/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/schema/generated.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/schema/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/schema/group_version.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/schema/interfaces.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/scheme.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/scheme_builder.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/meta.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/negotiated_codec.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf_extension.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer/recognizer.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming/streaming.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/swagger_doc_generator.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/types.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/types_proto.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/apimachinery/pkg/selection/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/selection/operator.go create mode 100644 vendor/k8s.io/apimachinery/pkg/types/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/types/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/types/namespacedname.go create mode 100644 vendor/k8s.io/apimachinery/pkg/types/nodename.go create mode 100644 vendor/k8s.io/apimachinery/pkg/types/patch.go create mode 100644 vendor/k8s.io/apimachinery/pkg/types/uid.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/clock/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/clock/clock.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/errors/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/errors/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/errors/errors.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/framer/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/framer/framer.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/httpstream/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/httpstream/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/httpstream/httpstream.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/connection.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/upgrade.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/intstr/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/intstr/generated.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/intstr/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/util/intstr/intstr.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/json/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/json/json.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/http.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/interface.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/port_range.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/port_split.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/util.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/remotecommand/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/remotecommand/constants.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/runtime/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/sets/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/sets/byte.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/sets/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/sets/empty.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/sets/int.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/sets/int64.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/sets/string.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/validation/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/validation/field/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/validation/field/path.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/validation/validation.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/wait.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/yaml/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/util/yaml/decoder.go create mode 100644 vendor/k8s.io/apimachinery/pkg/version/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/version/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/version/types.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/BUILD create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/doc.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/filter.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/mux.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/streamwatcher.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/until.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/watch.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/apimachinery/third_party/forked/golang/netutil/BUILD create mode 100644 vendor/k8s.io/apimachinery/third_party/forked/golang/netutil/addr.go create mode 100644 vendor/k8s.io/apimachinery/third_party/forked/golang/reflect/BUILD create mode 100644 vendor/k8s.io/apimachinery/third_party/forked/golang/reflect/deep_equal.go create mode 100644 vendor/k8s.io/client-go/LICENSE create mode 100644 vendor/k8s.io/client-go/discovery/discovery_client.go create mode 100644 vendor/k8s.io/client-go/discovery/helper.go create mode 100644 vendor/k8s.io/client-go/discovery/restmapper.go create mode 100644 vendor/k8s.io/client-go/discovery/unstructured.go create mode 100644 vendor/k8s.io/client-go/kubernetes/clientset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/import.go create mode 100644 vendor/k8s.io/client-go/kubernetes/scheme/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/scheme/register.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/admissionregistration_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/initializerconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/admissionregistration_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/mutatingwebhookconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/validatingwebhookconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/apps_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/controllerrevision.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/daemonset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/deployment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/replicaset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/statefulset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/apps_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/controllerrevision.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/deployment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/scale.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/statefulset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/apps_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/controllerrevision.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/daemonset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/deployment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/replicaset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/scale.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/statefulset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/authentication_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/tokenreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/tokenreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/authentication_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/tokenreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/tokenreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/authorization_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/localsubjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/localsubjectaccessreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/selfsubjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/selfsubjectaccessreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/selfsubjectrulesreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/selfsubjectrulesreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/subjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/subjectaccessreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/authorization_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/localsubjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/localsubjectaccessreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/selfsubjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/selfsubjectaccessreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/selfsubjectrulesreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/selfsubjectrulesreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/subjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/subjectaccessreview_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/autoscaling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/horizontalpodautoscaler.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/autoscaling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/horizontalpodautoscaler.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1/batch_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1/job.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/batch_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/cronjob.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v2alpha1/batch_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v2alpha1/cronjob.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v2alpha1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v2alpha1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/certificates_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/certificatesigningrequest.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/certificatesigningrequest_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/componentstatus.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/configmap.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/core_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/endpoints.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/event.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/event_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/limitrange.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/namespace.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/namespace_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/node.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/node_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/persistentvolume.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/persistentvolumeclaim.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/pod.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/pod_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/podtemplate.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/replicationcontroller.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/resourcequota.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/secret.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/service.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/service_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/serviceaccount.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/event.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/events_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/daemonset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/deployment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/deployment_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/extensions_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/ingress.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/podsecuritypolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/replicaset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/scale.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/scale_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1/networking_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1/networkpolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/eviction.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/eviction_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/poddisruptionbudget.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/policy_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/clusterrole.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/clusterrolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/rbac_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/role.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/rolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/clusterrole.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/clusterrolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/rbac_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/role.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/rolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/clusterrole.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/clusterrolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/rbac_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/role.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/rolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/priorityclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/scheduling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/settings/v1alpha1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/settings/v1alpha1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/settings/v1alpha1/podpreset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/settings/v1alpha1/settings_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/storage_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/storageclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/storage_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/volumeattachment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/storage_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/storageclass.go create mode 100644 vendor/k8s.io/client-go/pkg/version/.gitattributes create mode 100644 vendor/k8s.io/client-go/pkg/version/base.go create mode 100644 vendor/k8s.io/client-go/pkg/version/def.bzl create mode 100644 vendor/k8s.io/client-go/pkg/version/doc.go create mode 100644 vendor/k8s.io/client-go/pkg/version/version.go create mode 100644 vendor/k8s.io/client-go/plugin/pkg/client/auth/gcp/OWNERS create mode 100644 vendor/k8s.io/client-go/plugin/pkg/client/auth/gcp/gcp.go create mode 100755 vendor/k8s.io/client-go/rest/OWNERS create mode 100644 vendor/k8s.io/client-go/rest/client.go create mode 100644 vendor/k8s.io/client-go/rest/config.go create mode 100644 vendor/k8s.io/client-go/rest/plugin.go create mode 100644 vendor/k8s.io/client-go/rest/request.go create mode 100644 vendor/k8s.io/client-go/rest/transport.go create mode 100644 vendor/k8s.io/client-go/rest/url_utils.go create mode 100644 vendor/k8s.io/client-go/rest/urlbackoff.go create mode 100644 vendor/k8s.io/client-go/rest/versions.go create mode 100644 vendor/k8s.io/client-go/rest/watch/decoder.go create mode 100644 vendor/k8s.io/client-go/rest/watch/encoder.go create mode 100644 vendor/k8s.io/client-go/rest/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/client-go/third_party/forked/golang/template/exec.go create mode 100644 vendor/k8s.io/client-go/third_party/forked/golang/template/funcs.go create mode 100644 vendor/k8s.io/client-go/tools/auth/clientauth.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/doc.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/helpers.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/latest/latest.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/register.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/types.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/v1/conversion.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/v1/doc.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/v1/register.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/v1/types.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/auth_loaders.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/client_config.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/config.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/doc.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/flag.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/helpers.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/loader.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/merged_client_builder.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/overrides.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/validation.go create mode 100755 vendor/k8s.io/client-go/tools/metrics/OWNERS create mode 100644 vendor/k8s.io/client-go/tools/metrics/metrics.go create mode 100644 vendor/k8s.io/client-go/tools/portforward/doc.go create mode 100644 vendor/k8s.io/client-go/tools/portforward/portforward.go create mode 100644 vendor/k8s.io/client-go/tools/reference/ref.go create mode 100644 vendor/k8s.io/client-go/tools/remotecommand/doc.go create mode 100644 vendor/k8s.io/client-go/tools/remotecommand/errorstream.go create mode 100644 vendor/k8s.io/client-go/tools/remotecommand/remotecommand.go create mode 100644 vendor/k8s.io/client-go/tools/remotecommand/resize.go create mode 100644 vendor/k8s.io/client-go/tools/remotecommand/v1.go create mode 100644 vendor/k8s.io/client-go/tools/remotecommand/v2.go create mode 100644 vendor/k8s.io/client-go/tools/remotecommand/v3.go create mode 100644 vendor/k8s.io/client-go/tools/remotecommand/v4.go create mode 100755 vendor/k8s.io/client-go/transport/OWNERS create mode 100644 vendor/k8s.io/client-go/transport/cache.go create mode 100644 vendor/k8s.io/client-go/transport/config.go create mode 100644 vendor/k8s.io/client-go/transport/round_trippers.go create mode 100644 vendor/k8s.io/client-go/transport/spdy/spdy.go create mode 100644 vendor/k8s.io/client-go/transport/transport.go create mode 100644 vendor/k8s.io/client-go/util/cert/cert.go create mode 100644 vendor/k8s.io/client-go/util/cert/csr.go create mode 100644 vendor/k8s.io/client-go/util/cert/io.go create mode 100644 vendor/k8s.io/client-go/util/cert/pem.go create mode 100644 vendor/k8s.io/client-go/util/exec/exec.go create mode 100644 vendor/k8s.io/client-go/util/flowcontrol/backoff.go create mode 100644 vendor/k8s.io/client-go/util/flowcontrol/throttle.go create mode 100644 vendor/k8s.io/client-go/util/homedir/homedir.go create mode 100644 vendor/k8s.io/client-go/util/integer/integer.go create mode 100644 vendor/k8s.io/client-go/util/jsonpath/doc.go create mode 100644 vendor/k8s.io/client-go/util/jsonpath/jsonpath.go create mode 100644 vendor/k8s.io/client-go/util/jsonpath/node.go create mode 100644 vendor/k8s.io/client-go/util/jsonpath/parser.go create mode 100644 vendor/k8s.io/kube-openapi/LICENSE create mode 100644 vendor/k8s.io/kube-openapi/pkg/common/common.go create mode 100644 vendor/k8s.io/kube-openapi/pkg/common/doc.go diff --git a/Godeps/.gitignore b/Godeps/.gitignore deleted file mode 100644 index ece63be62..000000000 --- a/Godeps/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_workspace diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json deleted file mode 100644 index 3d0896048..000000000 --- a/Godeps/Godeps.json +++ /dev/null @@ -1,1091 +0,0 @@ -{ - "ImportPath": "github.com/crunchydata/crunchy-containers", - "GoVersion": "go1.9", - "GodepVersion": "v80", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "cloud.google.com/go/compute/metadata", - "Comment": "v0.25.0-10-g24ff62b", - "Rev": "24ff62bdf36b8c3c10021d8ffb46ef6f2d82da9c" - }, - { - "ImportPath": "github.com/Azure/go-ansiterm", - "Rev": "d6e3b3328b783f23731bc4d058875b0371ff8109" - }, - { - "ImportPath": "github.com/Azure/go-ansiterm/winterm", - "Rev": "d6e3b3328b783f23731bc4d058875b0371ff8109" - }, - { - "ImportPath": "github.com/Microsoft/go-winio", - "Comment": "v0.4.7-2-gab35fc0", - "Rev": "ab35fc04b6365e8fcb18e6e9e41ea4a02b10b175" - }, - { - "ImportPath": "github.com/Nvveen/Gotty", - "Rev": "cd527374f1e5bff4938207604a14f2e38a9cf512" - }, - { - "ImportPath": "github.com/PuerkitoBio/purell", - "Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4" - }, - { - "ImportPath": "github.com/PuerkitoBio/urlesc", - "Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e" - }, - { - "ImportPath": "github.com/cenkalti/backoff", - "Comment": "v1.1.0-4-g2ea60e5", - "Rev": "2ea60e5f094469f9e65adb9cd103795b73ae743e" - }, - { - "ImportPath": "github.com/containerd/continuity/pathdriver", - "Rev": "246e49050efdf45e8f17fbbcf1547ee376f9939e" - }, - { - "ImportPath": "github.com/docker/docker/api/types", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/blkiodev", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/container", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/filters", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/mount", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/network", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/registry", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/strslice", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/swarm", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/swarm/runtime", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/api/types/versions", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/opts", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/archive", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/fileutils", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/homedir", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/idtools", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/ioutils", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/jsonmessage", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/longpath", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/mount", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/pools", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/stdcopy", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/system", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/term", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/docker/pkg/term/windows", - "Comment": "docs-v1.12.0-rc4-2016-07-15-9062-g5f1731265", - "Rev": "5f17312653c3e4dc5474f86692b09f06262a1ebd" - }, - { - "ImportPath": "github.com/docker/go-connections/nat", - "Comment": "v0.3.0-13-g7395e3f", - "Rev": "7395e3f8aa162843a74ed6d48e79627d9792ac55" - }, - { - "ImportPath": "github.com/docker/go-units", - "Comment": "v0.3.2-4-g47565b4", - "Rev": "47565b4f722fb6ceae66b95f853feed578a4a51c" - }, - { - "ImportPath": "github.com/docker/spdystream", - "Rev": "bc6354cbbc295e925e4c611ffe90c1f287ee54db" - }, - { - "ImportPath": "github.com/docker/spdystream/spdy", - "Rev": "bc6354cbbc295e925e4c611ffe90c1f287ee54db" - }, - { - "ImportPath": "github.com/emicklei/go-restful", - "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" - }, - { - "ImportPath": "github.com/emicklei/go-restful/log", - "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" - }, - { - "ImportPath": "github.com/fsnotify/fsnotify", - "Comment": "v1.4.2-6-g4da3e2c", - "Rev": "4da3e2cfbabc9f751898f250b49f2439785783a1" - }, - { - "ImportPath": "github.com/fsouza/go-dockerclient", - "Comment": "1.2.0-22-gad1213c", - "Rev": "ad1213cc21543085ce0c97f4291994e02b95e459" - }, - { - "ImportPath": "github.com/ghodss/yaml", - "Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee" - }, - { - "ImportPath": "github.com/go-openapi/jsonpointer", - "Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98" - }, - { - "ImportPath": "github.com/go-openapi/jsonreference", - "Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272" - }, - { - "ImportPath": "github.com/go-openapi/spec", - "Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d" - }, - { - "ImportPath": "github.com/go-openapi/swag", - "Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590" - }, - { - "ImportPath": "github.com/gogo/protobuf/proto", - "Comment": "v0.4-3-gc0656edd", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/sortkeys", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/golang/glog", - "Rev": "44145f04b68cf362d9c4df2182967c2275eaefed" - }, - { - "ImportPath": "github.com/golang/protobuf/proto", - "Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9" - }, - { - "ImportPath": "github.com/golang/protobuf/ptypes", - "Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9" - }, - { - "ImportPath": "github.com/golang/protobuf/ptypes/any", - "Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9" - }, - { - "ImportPath": "github.com/golang/protobuf/ptypes/duration", - "Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9" - }, - { - "ImportPath": "github.com/golang/protobuf/ptypes/timestamp", - "Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9" - }, - { - "ImportPath": "github.com/google/btree", - "Rev": "7d79101e329e5a3adf994758c578dab82b90c017" - }, - { - "ImportPath": "github.com/google/gofuzz", - "Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c" - }, - { - "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", - "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba" - }, - { - "ImportPath": "github.com/googleapis/gnostic/compiler", - "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba" - }, - { - "ImportPath": "github.com/googleapis/gnostic/extensions", - "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba" - }, - { - "ImportPath": "github.com/gorilla/mux", - "Rev": "53c1911da2b537f792e7cafcb446b05ffe33b996" - }, - { - "ImportPath": "github.com/gregjones/httpcache", - "Rev": "787624de3eb7bd915c329cba748687a3b22666a6" - }, - { - "ImportPath": "github.com/gregjones/httpcache/diskcache", - "Rev": "787624de3eb7bd915c329cba748687a3b22666a6" - }, - { - "ImportPath": "github.com/hashicorp/hcl", - "Rev": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" - }, - { - "ImportPath": "github.com/hashicorp/hcl/hcl/ast", - "Rev": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" - }, - { - "ImportPath": "github.com/hashicorp/hcl/hcl/parser", - "Rev": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" - }, - { - "ImportPath": "github.com/hashicorp/hcl/hcl/scanner", - "Rev": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" - }, - { - "ImportPath": "github.com/hashicorp/hcl/hcl/strconv", - "Rev": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" - }, - { - "ImportPath": "github.com/hashicorp/hcl/hcl/token", - "Rev": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" - }, - { - "ImportPath": "github.com/hashicorp/hcl/json/parser", - "Rev": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" - }, - { - "ImportPath": "github.com/hashicorp/hcl/json/scanner", - "Rev": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" - }, - { - "ImportPath": "github.com/hashicorp/hcl/json/token", - "Rev": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" - }, - { - "ImportPath": "github.com/howeyc/gopass", - "Rev": "bf9dde6d0d2c004a008c27aaee91170c786f6db8" - }, - { - "ImportPath": "github.com/imdario/mergo", - "Rev": "6633656539c1639d9d78127b7d47c622b5d7b6dc" - }, - { - "ImportPath": "github.com/inconshreveable/mousetrap", - "Comment": "v1.0", - "Rev": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" - }, - { - "ImportPath": "github.com/json-iterator/go", - "Rev": "36b14963da70d11297d313183d7e6388c8510e1e" - }, - { - "ImportPath": "github.com/juju/ratelimit", - "Rev": "5b9ff866471762aa2ab2dced63c9fb6f53921342" - }, - { - "ImportPath": "github.com/lib/pq", - "Comment": "go1.0-cutoff-185-g017e4c1", - "Rev": "017e4c14d80628353eaee677a1aeffe47a10c0dc" - }, - { - "ImportPath": "github.com/lib/pq/oid", - "Comment": "go1.0-cutoff-185-g017e4c1", - "Rev": "017e4c14d80628353eaee677a1aeffe47a10c0dc" - }, - { - "ImportPath": "github.com/magiconair/properties", - "Comment": "v1.7.3-4-g8d7837e", - "Rev": "8d7837e64d3c1ee4e54a880c5a920ab4316fc90a" - }, - { - "ImportPath": "github.com/mailru/easyjson/buffer", - "Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" - }, - { - "ImportPath": "github.com/mailru/easyjson/jlexer", - "Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" - }, - { - "ImportPath": "github.com/mailru/easyjson/jwriter", - "Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" - }, - { - "ImportPath": "github.com/mitchellh/mapstructure", - "Rev": "06020f85339e21b2478f756a78e295255ffa4d6a" - }, - { - "ImportPath": "github.com/opencontainers/go-digest", - "Comment": "v1.0.0-rc1-2-gc928146", - "Rev": "c9281466c8b2f606084ac71339773efd177436e7" - }, - { - "ImportPath": "github.com/opencontainers/image-spec/specs-go", - "Comment": "v1.0.0-35-ge562b04", - "Rev": "e562b04403929d582d449ae5386ff79dd7961a11" - }, - { - "ImportPath": "github.com/opencontainers/image-spec/specs-go/v1", - "Comment": "v1.0.0-35-ge562b04", - "Rev": "e562b04403929d582d449ae5386ff79dd7961a11" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/system", - "Comment": "v1.0.0-rc5-70-gad0f5255", - "Rev": "ad0f5255060d36872be04de22f8731f38ef2d7b1" - }, - { - "ImportPath": "github.com/opencontainers/runc/libcontainer/user", - "Comment": "v1.0.0-rc5-70-gad0f5255", - "Rev": "ad0f5255060d36872be04de22f8731f38ef2d7b1" - }, - { - "ImportPath": "github.com/pelletier/go-toml", - "Comment": "v1.0.1-2-g2009e44", - "Rev": "2009e44b6f182e34d8ce081ac2767622937ea3d4" - }, - { - "ImportPath": "github.com/peterbourgon/diskv", - "Rev": "5f041e8faa004a95c88a202771f4cc3e991971e6" - }, - { - "ImportPath": "github.com/pkg/errors", - "Comment": "v0.8.0-12-g816c908", - "Rev": "816c9085562cd7ee03e7f8188a1cfd942858cded" - }, - { - "ImportPath": "github.com/robfig/cron", - "Comment": "v1.1", - "Rev": "b41be1df696709bb6395fe435af20370037c0b4c" - }, - { - "ImportPath": "github.com/sirupsen/logrus", - "Comment": "v1.0.3", - "Rev": "f006c2ac4710855cf0f916dd6b77acf6b048dc6e" - }, - { - "ImportPath": "github.com/spf13/afero", - "Rev": "e67d870304c4bca21331b02f414f970df13aa694" - }, - { - "ImportPath": "github.com/spf13/afero/mem", - "Rev": "e67d870304c4bca21331b02f414f970df13aa694" - }, - { - "ImportPath": "github.com/spf13/cast", - "Comment": "v1.1.0", - "Rev": "acbeb36b902d72a7a4c18e8f3241075e7ab763e4" - }, - { - "ImportPath": "github.com/spf13/cobra", - "Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57" - }, - { - "ImportPath": "github.com/spf13/jwalterweatherman", - "Rev": "12bd96e66386c1960ab0f74ced1362f66f552f7b" - }, - { - "ImportPath": "github.com/spf13/pflag", - "Rev": "9ff6c6923cfffbcd502984b8e0c80539a94968b7" - }, - { - "ImportPath": "github.com/spf13/viper", - "Comment": "v1.0.0-2-gd9cca5e", - "Rev": "d9cca5ef33035202efb1586825bdbb15ff9ec3ba" - }, - { - "ImportPath": "golang.org/x/crypto/curve25519", - "Rev": "81e90905daefcd6fd217b62423c0908922eadb30" - }, - { - "ImportPath": "golang.org/x/crypto/ed25519", - "Rev": "81e90905daefcd6fd217b62423c0908922eadb30" - }, - { - "ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519", - "Rev": "81e90905daefcd6fd217b62423c0908922eadb30" - }, - { - "ImportPath": "golang.org/x/crypto/ssh", - "Rev": "81e90905daefcd6fd217b62423c0908922eadb30" - }, - { - "ImportPath": "golang.org/x/crypto/ssh/terminal", - "Rev": "81e90905daefcd6fd217b62423c0908922eadb30" - }, - { - "ImportPath": "golang.org/x/net/context", - "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" - }, - { - "ImportPath": "golang.org/x/net/context/ctxhttp", - "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" - }, - { - "ImportPath": "golang.org/x/net/http2", - "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" - }, - { - "ImportPath": "golang.org/x/net/http2/hpack", - "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" - }, - { - "ImportPath": "golang.org/x/net/idna", - "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" - }, - { - "ImportPath": "golang.org/x/net/lex/httplex", - "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" - }, - { - "ImportPath": "golang.org/x/oauth2", - "Rev": "ef147856a6ddbb60760db74283d2424e98c87bff" - }, - { - "ImportPath": "golang.org/x/oauth2/google", - "Rev": "ef147856a6ddbb60760db74283d2424e98c87bff" - }, - { - "ImportPath": "golang.org/x/oauth2/internal", - "Rev": "ef147856a6ddbb60760db74283d2424e98c87bff" - }, - { - "ImportPath": "golang.org/x/oauth2/jws", - "Rev": "ef147856a6ddbb60760db74283d2424e98c87bff" - }, - { - "ImportPath": "golang.org/x/oauth2/jwt", - "Rev": "ef147856a6ddbb60760db74283d2424e98c87bff" - }, - { - "ImportPath": "golang.org/x/sys/unix", - "Rev": "95c6576299259db960f6c5b9b69ea52422860fce" - }, - { - "ImportPath": "golang.org/x/sys/windows", - "Rev": "95c6576299259db960f6c5b9b69ea52422860fce" - }, - { - "ImportPath": "golang.org/x/text/cases", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/internal", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/internal/tag", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/language", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/runes", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/secure/bidirule", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/secure/precis", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/transform", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/unicode/bidi", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/unicode/norm", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/width", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "gopkg.in/inf.v0", - "Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" - }, - { - "ImportPath": "gopkg.in/ory-am/dockertest.v3", - "Comment": "v3.1.6", - "Rev": "15c8e8835bba04e0d7c2b57958ffe294d5e643dc" - }, - { - "ImportPath": "gopkg.in/yaml.v2", - "Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77" - }, - { - "ImportPath": "k8s.io/api/admissionregistration/v1alpha1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/admissionregistration/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/apps/v1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/apps/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/apps/v1beta2", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/authentication/v1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/authentication/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/authorization/v1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/authorization/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/autoscaling/v1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/autoscaling/v2beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/batch/v1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/batch/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/batch/v2alpha1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/certificates/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/core/v1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/events/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/extensions/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/networking/v1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/policy/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/rbac/v1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/rbac/v1alpha1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/rbac/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/scheduling/v1alpha1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/settings/v1alpha1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/storage/v1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/storage/v1alpha1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/api/storage/v1beta1", - "Rev": "acf347b865f29325eb61f4cd2df11e86e073a5ee" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/errors", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/meta", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/resource", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1alpha1", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/conversion", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/fields", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/labels", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/selection", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/types", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/clock", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/errors", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/framer", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy", - "Comment": "kubernetes-1.9.8-beta.0", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/intstr", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/json", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/net", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand", - "Comment": "kubernetes-1.9.8-beta.0", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/runtime", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/sets", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/validation", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/wait", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/yaml", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/version", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/watch", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", - "Rev": "19e3f5aa3adca672c153d324e6b7d82ff8935f03" - }, - { - "ImportPath": "k8s.io/client-go/discovery", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/scheme", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta2", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v2alpha1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/certificates/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/core/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/events/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/extensions/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/networking/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/policy/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/settings/v1alpha1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1alpha1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1beta1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/pkg/version", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/plugin/pkg/client/auth/gcp", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/rest", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/rest/watch", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/third_party/forked/golang/template", - "Comment": "kubernetes-1.9.8-beta.0", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/tools/auth", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/tools/clientcmd", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/tools/clientcmd/api", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/tools/clientcmd/api/latest", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/tools/clientcmd/api/v1", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/tools/metrics", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/tools/portforward", - "Comment": "kubernetes-1.9.8-beta.0", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/tools/reference", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/tools/remotecommand", - "Comment": "kubernetes-1.9.8-beta.0", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/transport", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/transport/spdy", - "Comment": "kubernetes-1.9.8-beta.0", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/util/cert", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/util/exec", - "Comment": "kubernetes-1.9.8-beta.0", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/util/flowcontrol", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/util/homedir", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/util/integer", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/client-go/util/jsonpath", - "Comment": "kubernetes-1.9.8-beta.0", - "Rev": "90539b4e75a8daaf7f67c3874c6180bfb1a63936" - }, - { - "ImportPath": "k8s.io/kube-openapi/pkg/common", - "Rev": "39a7bf85c140f972372c2a0d1ee40adbf0c8bfe1" - }, - { - "ImportPath": "github.com/fatih/color", - "Rev": "507f6050b8568533fb3f5504de8e5205fa62a114" - }, - { - "ImportPath": "github.com/spf13/cobra", - "Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57" - } - ] -} diff --git a/Godeps/Readme b/Godeps/Readme deleted file mode 100644 index 4cdaa53d5..000000000 --- a/Godeps/Readme +++ /dev/null @@ -1,5 +0,0 @@ -This directory tree is generated automatically by godep. - -Please do not edit. - -See https://github.com/tools/godep for more information. diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 000000000..e9d36948f --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,809 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:5c3894b2aa4d6bead0ceeea6831b305d62879c871780e7b76296ded1b004bc57" + name = "cloud.google.com/go" + packages = ["compute/metadata"] + pruneopts = "UT" + revision = "24ff62bdf36b8c3c10021d8ffb46ef6f2d82da9c" + +[[projects]] + branch = "master" + digest = "1:6da51e5ec493ad2b44cb04129e2d0a068c8fb9bd6cb5739d199573558696bb94" + name = "github.com/Azure/go-ansiterm" + packages = [ + ".", + "winterm", + ] + pruneopts = "UT" + revision = "d6e3b3328b783f23731bc4d058875b0371ff8109" + +[[projects]] + digest = "1:f9ae348e1f793dcf9ed930ed47136a67343dbd6809c5c91391322267f4476892" + name = "github.com/Microsoft/go-winio" + packages = ["."] + pruneopts = "UT" + revision = "97e4973ce50b2ff5f09635a57e2b88a037aae829" + version = "v0.4.11" + +[[projects]] + branch = "master" + digest = "1:3721a10686511b80c052323423f0de17a8c06d417dbdd3b392b1578432a33aae" + name = "github.com/Nvveen/Gotty" + packages = ["."] + pruneopts = "UT" + revision = "cd527374f1e5bff4938207604a14f2e38a9cf512" + +[[projects]] + digest = "1:792c6f8317411834d22db5be14276cd87d589cb0f8dcc51c042f0dddf67d60b1" + name = "github.com/PuerkitoBio/purell" + packages = ["."] + pruneopts = "UT" + revision = "8a290539e2e8629dbc4e6bad948158f790ec31f4" + version = "v1.0.0" + +[[projects]] + digest = "1:61e5d7b1fabd5b6734b2595912944dbd9f6e0eaa4adef25e5cbf98754fc91df1" + name = "github.com/PuerkitoBio/urlesc" + packages = ["."] + pruneopts = "UT" + revision = "5bd2802263f21d8788851d5305584c82a5c75d7e" + +[[projects]] + digest = "1:4ba637038f22c9065994c0cd734118fc75e0c744f855fd3edbd3b923d1f41d44" + name = "github.com/cenkalti/backoff" + packages = ["."] + pruneopts = "UT" + revision = "61153c768f31ee5f130071d08fc82b85208528de" + version = "v1.1.0" + +[[projects]] + digest = "1:fc8dbcc2a5de7c093e167828ebbdf551641761d2ad75431d3a167d467a264115" + name = "github.com/containerd/continuity" + packages = ["pathdriver"] + pruneopts = "UT" + revision = "246e49050efdf45e8f17fbbcf1547ee376f9939e" + +[[projects]] + digest = "1:4ec8504b68b75f562efc4b291cba33194f88eaa4e68d9fc449e5b7ca68539329" + name = "github.com/docker/docker" + packages = [ + "api/types", + "api/types/blkiodev", + "api/types/container", + "api/types/filters", + "api/types/mount", + "api/types/network", + "api/types/registry", + "api/types/strslice", + "api/types/swarm", + "api/types/swarm/runtime", + "api/types/versions", + "opts", + "pkg/fileutils", + "pkg/homedir", + "pkg/idtools", + "pkg/ioutils", + "pkg/longpath", + "pkg/mount", + "pkg/pools", + "pkg/stdcopy", + "pkg/system", + ] + pruneopts = "UT" + revision = "3dfb26ab3cbf961298f8ce3f94659b5fe4146ceb" + +[[projects]] + digest = "1:ade935c55cd6d0367c843b109b09c9d748b1982952031414740750fdf94747eb" + name = "github.com/docker/go-connections" + packages = ["nat"] + pruneopts = "UT" + revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55" + version = "v0.4.0" + +[[projects]] + digest = "1:6f82cacd0af5921e99bf3f46748705239b36489464f4529a1589bc895764fb18" + name = "github.com/docker/go-units" + packages = ["."] + pruneopts = "UT" + revision = "47565b4f722fb6ceae66b95f853feed578a4a51c" + version = "v0.3.3" + +[[projects]] + digest = "1:00d0d550a1f1d7ca03270ebc1e136f21f6b9dab37f0c37e9a90d56d2f7afcff9" + name = "github.com/docker/libnetwork" + packages = ["ipamutils"] + pruneopts = "UT" + revision = "19279f0492417475b6bfbd0aa529f73e8f178fb5" + +[[projects]] + branch = "master" + digest = "1:dbb3d1675f5beeb37de6e9b95cc460158ff212902a916e67688b01e0660f41bd" + name = "github.com/docker/spdystream" + packages = [ + ".", + "spdy", + ] + pruneopts = "UT" + revision = "bc6354cbbc295e925e4c611ffe90c1f287ee54db" + +[[projects]] + digest = "1:87c056b4f0548034ade51456237b47f723b901f373d7c11295f80da5d3b91950" + name = "github.com/emicklei/go-restful" + packages = [ + ".", + "log", + ] + pruneopts = "UT" + revision = "ff4f55a206334ef123e4f79bbf348980da81ca46" + +[[projects]] + digest = "1:4bb94bb2d837b5c7489d9e5e1fcffbc81fa1cb43024cbb4fe827787378f01e3b" + name = "github.com/fatih/color" + packages = ["."] + pruneopts = "UT" + revision = "507f6050b8568533fb3f5504de8e5205fa62a114" + version = "v1.6.0" + +[[projects]] + digest = "1:38c783cf85b9454cc02a1a8319239800ed0af6c1c864adf19cea0539e134adad" + name = "github.com/fsnotify/fsnotify" + packages = ["."] + pruneopts = "UT" + revision = "4da3e2cfbabc9f751898f250b49f2439785783a1" + +[[projects]] + digest = "1:027133e2c23fd4ff467e66d928ab4a64f7fd7cb2f77acdb580c483f7389d22d7" + name = "github.com/fsouza/go-dockerclient" + packages = [ + ".", + "internal/archive", + "internal/jsonmessage", + "internal/term", + ] + pruneopts = "UT" + revision = "8842d40dbf5ee062d80f9dc429db31a0fe0cdc73" + version = "v1.2.2" + +[[projects]] + digest = "1:c45cef8e0074ea2f8176a051df38553ba997a3616f1ec2d35222b1cf9864881e" + name = "github.com/ghodss/yaml" + packages = ["."] + pruneopts = "UT" + revision = "73d445a93680fa1a78ae23a5839bad48f32ba1ee" + +[[projects]] + digest = "1:172569c4bdc486213be0121e6039df4c272e9ff29397d9fd3716c31e4b37e15d" + name = "github.com/go-openapi/jsonpointer" + packages = ["."] + pruneopts = "UT" + revision = "46af16f9f7b149af66e5d1bd010e3574dc06de98" + +[[projects]] + digest = "1:f30ccde775458301b306f4576e11de88d3ed0d91e68a5f3591c4ed8afbca76fa" + name = "github.com/go-openapi/jsonreference" + packages = ["."] + pruneopts = "UT" + revision = "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272" + +[[projects]] + digest = "1:dc458a3dd7491bbcbb78050e05ceb428a3b30adc276e62b717a97e79442ba12b" + name = "github.com/go-openapi/spec" + packages = ["."] + pruneopts = "UT" + revision = "7abd5745472fff5eb3685386d5fb8bf38683154d" + +[[projects]] + digest = "1:3a42f9cbdeb4db3a14e0c3bb35852b7426b69f73386d52b606baf5d0fecfb4d7" + name = "github.com/go-openapi/swag" + packages = ["."] + pruneopts = "UT" + revision = "f3f9494671f93fcff853e3c6e9e948b3eb71e590" + +[[projects]] + digest = "1:f83d740263b44fdeef3e1bce6147b5d7283fcad1a693d39639be33993ecf3db1" + name = "github.com/gogo/protobuf" + packages = [ + "proto", + "sortkeys", + ] + pruneopts = "UT" + revision = "c0656edd0d9eab7c66d1eb0c568f9039345796f7" + +[[projects]] + digest = "1:2edd2416f89b4e841df0e4a78802ce14d2bc7ad79eba1a45986e39f0f8cb7d87" + name = "github.com/golang/glog" + packages = ["."] + pruneopts = "UT" + revision = "44145f04b68cf362d9c4df2182967c2275eaefed" + +[[projects]] + digest = "1:8f2df6167daef6f4d56d07f99bbcf4733117db0dedfd959995b9a679c52561f1" + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp", + ] + pruneopts = "UT" + revision = "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9" + +[[projects]] + digest = "1:62dfb39fe3bddeabb02cc001075ed9f951b044da2cd5b0f970ca798b1553bac3" + name = "github.com/google/btree" + packages = ["."] + pruneopts = "UT" + revision = "7d79101e329e5a3adf994758c578dab82b90c017" + +[[projects]] + digest = "1:41bfd4219241b7f7d6e6fdb13fc712576f1337e68e6b895136283b76928fdd66" + name = "github.com/google/gofuzz" + packages = ["."] + pruneopts = "UT" + revision = "44d81051d367757e1c7c6a5a86423ece9afcf63c" + +[[projects]] + digest = "1:75eb87381d25cc75212f52358df9c3a2719584eaa9685cd510ce28699122f39d" + name = "github.com/googleapis/gnostic" + packages = [ + "OpenAPIv2", + "compiler", + "extensions", + ] + pruneopts = "UT" + revision = "0c5108395e2debce0d731cf0287ddf7242066aba" + +[[projects]] + digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1" + name = "github.com/gorilla/context" + packages = ["."] + pruneopts = "UT" + revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42" + version = "v1.1.1" + +[[projects]] + digest = "1:88aa9e326e2bd6045a46e00a922954b3e1a9ac5787109f49ac85366df370e1e5" + name = "github.com/gorilla/mux" + packages = ["."] + pruneopts = "UT" + revision = "53c1911da2b537f792e7cafcb446b05ffe33b996" + version = "v1.6.1" + +[[projects]] + digest = "1:878f0defa9b853f9acfaf4a162ba450a89d0050eff084f9fe7f5bd15948f172a" + name = "github.com/gregjones/httpcache" + packages = [ + ".", + "diskcache", + ] + pruneopts = "UT" + revision = "787624de3eb7bd915c329cba748687a3b22666a6" + +[[projects]] + digest = "1:145eff5207977eb95c3649a27cdc2e467d8a1c104810bc12b6a53745a91d823a" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token", + ] + pruneopts = "UT" + revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" + +[[projects]] + branch = "master" + digest = "1:0778dc7fce1b4669a8bfa7ae506ec1f595b6ab0f8989c1c0d22a8ca1144e9972" + name = "github.com/howeyc/gopass" + packages = ["."] + pruneopts = "UT" + revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8" + +[[projects]] + digest = "1:06ec9147400aabb0d6960dd8557638603b5f320cd4cb8a3eceaae407e782849a" + name = "github.com/imdario/mergo" + packages = ["."] + pruneopts = "UT" + revision = "6633656539c1639d9d78127b7d47c622b5d7b6dc" + +[[projects]] + digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" + name = "github.com/inconshreveable/mousetrap" + packages = ["."] + pruneopts = "UT" + revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + version = "v1.0" + +[[projects]] + digest = "1:be97e109f627d3ba8edfef50c9c74f0d0c17cbe3a2e924a8985e4804a894f282" + name = "github.com/json-iterator/go" + packages = ["."] + pruneopts = "UT" + revision = "36b14963da70d11297d313183d7e6388c8510e1e" + version = "1.0.0" + +[[projects]] + digest = "1:924a04121ca98afac9b02f85ea87bc22526394d3537d58febcd713ada883d720" + name = "github.com/juju/ratelimit" + packages = ["."] + pruneopts = "UT" + revision = "5b9ff866471762aa2ab2dced63c9fb6f53921342" + version = "1.0" + +[[projects]] + digest = "1:7d3480a4f974d4b4e40722e9d3f5892519751d604a19a81892013e3e78e7db33" + name = "github.com/lib/pq" + packages = [ + ".", + "oid", + ] + pruneopts = "UT" + revision = "017e4c14d80628353eaee677a1aeffe47a10c0dc" + +[[projects]] + digest = "1:d1ee0681f10d655d83f1bb8e0922a5ffc420c9a1982b4fb9be7c41ec41781e86" + name = "github.com/magiconair/properties" + packages = ["."] + pruneopts = "UT" + revision = "8d7837e64d3c1ee4e54a880c5a920ab4316fc90a" + +[[projects]] + digest = "1:a867990aee2ebc1ac86614ed702bf1e63061a79eac12d4326203cb9084b61839" + name = "github.com/mailru/easyjson" + packages = [ + "buffer", + "jlexer", + "jwriter", + ] + pruneopts = "UT" + revision = "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" + +[[projects]] + digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67" + name = "github.com/mattn/go-colorable" + packages = ["."] + pruneopts = "UT" + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + +[[projects]] + digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5" + name = "github.com/mattn/go-isatty" + packages = ["."] + pruneopts = "UT" + revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c" + version = "v0.0.4" + +[[projects]] + digest = "1:56a0bd1a1f3809171d1abe0bfd389558be0cd672e858e1f831b88f806aa8764f" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + pruneopts = "UT" + revision = "06020f85339e21b2478f756a78e295255ffa4d6a" + +[[projects]] + branch = "master" + digest = "1:bc62c2c038cc8ae51b68f6d52570501a763bb71e78736a9f65d60762429864a9" + name = "github.com/opencontainers/go-digest" + packages = ["."] + pruneopts = "UT" + revision = "c9281466c8b2f606084ac71339773efd177436e7" + +[[projects]] + digest = "1:72355c470c6667f840653face568d24896ce8ff9888b0304b18e5e7452147206" + name = "github.com/opencontainers/image-spec" + packages = [ + "specs-go", + "specs-go/v1", + ] + pruneopts = "UT" + revision = "e562b04403929d582d449ae5386ff79dd7961a11" + +[[projects]] + digest = "1:5fd4c15ff94e30a6cd726290c5656af965dd271fa975b7ccbc89a48a89b2cd73" + name = "github.com/opencontainers/runc" + packages = ["libcontainer/user"] + pruneopts = "UT" + revision = "ad0f5255060d36872be04de22f8731f38ef2d7b1" + +[[projects]] + digest = "1:e571f41aec111da462297976a646a51d0433c0538953c9ac26fe643723220ff9" + name = "github.com/pelletier/go-toml" + packages = ["."] + pruneopts = "UT" + revision = "2009e44b6f182e34d8ce081ac2767622937ea3d4" + +[[projects]] + branch = "master" + digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2" + name = "github.com/petar/GoLLRB" + packages = ["llrb"] + pruneopts = "UT" + revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" + +[[projects]] + digest = "1:0e7775ebbcf00d8dd28ac663614af924411c868dca3d5aa762af0fae3808d852" + name = "github.com/peterbourgon/diskv" + packages = ["."] + pruneopts = "UT" + revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" + version = "v2.0.1" + +[[projects]] + digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747" + name = "github.com/pkg/errors" + packages = ["."] + pruneopts = "UT" + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + digest = "1:5f2aaa360f48d1711795bd88c7e45a38f86cf81e4bc01453d20983baa67e2d51" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "f006c2ac4710855cf0f916dd6b77acf6b048dc6e" + version = "v1.0.3" + +[[projects]] + digest = "1:929ff9cb53ef18941beb32733b352c92fff0e0be24b29470a487572a528457e0" + name = "github.com/spf13/afero" + packages = [ + ".", + "mem", + ] + pruneopts = "UT" + revision = "e67d870304c4bca21331b02f414f970df13aa694" + +[[projects]] + digest = "1:9b28ee2984c69d78afe2ce52b1650ba91a6381f355ff08c1d0e53d9e66bd62fe" + name = "github.com/spf13/cast" + packages = ["."] + pruneopts = "UT" + revision = "acbeb36b902d72a7a4c18e8f3241075e7ab763e4" + version = "v1.1.0" + +[[projects]] + digest = "1:a56136c27b209402fde83ca18912af54146d51bfac3eeed73c696b70de707a01" + name = "github.com/spf13/cobra" + packages = ["."] + pruneopts = "UT" + revision = "f62e98d28ab7ad31d707ba837a966378465c7b57" + +[[projects]] + digest = "1:9f28b7e326b8cd1db556678b7ce679cf9bf888647e40922f91d9d40f451f942b" + name = "github.com/spf13/jwalterweatherman" + packages = ["."] + pruneopts = "UT" + revision = "12bd96e66386c1960ab0f74ced1362f66f552f7b" + +[[projects]] + digest = "1:b7386dc2acd6ae7a2383c7e35edf894b73df06338c04c49df3887087d2a97bab" + name = "github.com/spf13/pflag" + packages = ["."] + pruneopts = "UT" + revision = "9ff6c6923cfffbcd502984b8e0c80539a94968b7" + +[[projects]] + digest = "1:ed194b4b788139090b74d2fe13c62ae30417e2a2765c9a975a44ae3b1f1675d8" + name = "github.com/spf13/viper" + packages = ["."] + pruneopts = "UT" + revision = "d9cca5ef33035202efb1586825bdbb15ff9ec3ba" + +[[projects]] + digest = "1:14263791cdd53e1379d8363b21fe97145665737a81b73076901d204a26ab6b99" + name = "golang.org/x/crypto" + packages = [ + "curve25519", + "ed25519", + "ed25519/internal/edwards25519", + "ssh", + "ssh/terminal", + ] + pruneopts = "UT" + revision = "81e90905daefcd6fd217b62423c0908922eadb30" + +[[projects]] + digest = "1:1e853578c8a3c5d54c1b54a4821075393b032110170107295f75442f8b41720c" + name = "golang.org/x/net" + packages = [ + "context", + "context/ctxhttp", + "http2", + "http2/hpack", + "idna", + "lex/httplex", + ] + pruneopts = "UT" + revision = "1c05540f6879653db88113bc4a2b70aec4bd491f" + +[[projects]] + digest = "1:bea0314c10bd362ab623af4880d853b5bad3b63d0ab9945c47e461b8d04203ed" + name = "golang.org/x/oauth2" + packages = [ + ".", + "google", + "internal", + "jws", + "jwt", + ] + pruneopts = "UT" + revision = "ef147856a6ddbb60760db74283d2424e98c87bff" + +[[projects]] + digest = "1:e1a85d3648114c446b2874647bf30f646a8594e7e4e45db87fe962aba60e51f5" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows", + ] + pruneopts = "UT" + revision = "95c6576299259db960f6c5b9b69ea52422860fce" + +[[projects]] + digest = "1:52c441d338d4a491f7b2a2e62dbf35bc531c9883c804b3f781afd6990ed72207" + name = "golang.org/x/text" + packages = [ + "cases", + "internal", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "runes", + "secure/bidirule", + "secure/precis", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + "width", + ] + pruneopts = "UT" + revision = "b19bf474d317b857955b12035d2c5acb57ce8b01" + +[[projects]] + digest = "1:193950893ea275f89ed92e5da11ed8fa1436872f755a9ea5d4afa83dc9d9c3a8" + name = "google.golang.org/appengine" + packages = [ + ".", + "internal", + "internal/app_identity", + "internal/base", + "internal/datastore", + "internal/log", + "internal/modules", + "internal/remote_api", + "internal/urlfetch", + "urlfetch", + ] + pruneopts = "UT" + revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06" + version = "v1.2.0" + +[[projects]] + digest = "1:ef72505cf098abdd34efeea032103377bec06abb61d8a06f002d5d296a4b1185" + name = "gopkg.in/inf.v0" + packages = ["."] + pruneopts = "UT" + revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" + version = "v0.9.0" + +[[projects]] + digest = "1:7793f293ffba4ec2f784f3d83e28f2f95f876ac320a612e43fb9282a44b2c032" + name = "gopkg.in/ory-am/dockertest.v3" + packages = ["."] + pruneopts = "UT" + revision = "15c8e8835bba04e0d7c2b57958ffe294d5e643dc" + version = "v3.1.6" + +[[projects]] + branch = "v2" + digest = "1:e8c48aa61ea272e211858e52979ad4d114c60bfe6900d12431ac697482100b0a" + name = "gopkg.in/robfig/cron.v2" + packages = ["."] + pruneopts = "UT" + revision = "be2e0b0deed5a68ffee390b4583a13aff8321535" + +[[projects]] + digest = "1:c27797c5f42d349e2a604510822df7d037415aae58bf1e6fd35624eda757c0aa" + name = "gopkg.in/yaml.v2" + packages = ["."] + pruneopts = "UT" + revision = "53feefa2559fb8dfa8d81baad31be332c97d6c77" + +[[projects]] + digest = "1:4cc7e16ce63fd9c0bff1d2fde9f69d2045b63ca9a7e3d74962b60112a22dbaa8" + name = "k8s.io/api" + packages = [ + "admissionregistration/v1alpha1", + "admissionregistration/v1beta1", + "apps/v1", + "apps/v1beta1", + "apps/v1beta2", + "authentication/v1", + "authentication/v1beta1", + "authorization/v1", + "authorization/v1beta1", + "autoscaling/v1", + "autoscaling/v2beta1", + "batch/v1", + "batch/v1beta1", + "batch/v2alpha1", + "certificates/v1beta1", + "core/v1", + "events/v1beta1", + "extensions/v1beta1", + "networking/v1", + "policy/v1beta1", + "rbac/v1", + "rbac/v1alpha1", + "rbac/v1beta1", + "scheduling/v1alpha1", + "settings/v1alpha1", + "storage/v1", + "storage/v1alpha1", + "storage/v1beta1", + ] + pruneopts = "UT" + revision = "acf347b865f29325eb61f4cd2df11e86e073a5ee" + version = "kubernetes-1.9.3" + +[[projects]] + digest = "1:419ad62da669e1b4be7cca13d0d6889164a7d8c2cc078314fca610a9b5e8ae19" + name = "k8s.io/apimachinery" + packages = [ + "pkg/api/errors", + "pkg/api/meta", + "pkg/api/resource", + "pkg/apis/meta/v1", + "pkg/apis/meta/v1/unstructured", + "pkg/apis/meta/v1alpha1", + "pkg/conversion", + "pkg/conversion/queryparams", + "pkg/fields", + "pkg/labels", + "pkg/runtime", + "pkg/runtime/schema", + "pkg/runtime/serializer", + "pkg/runtime/serializer/json", + "pkg/runtime/serializer/protobuf", + "pkg/runtime/serializer/recognizer", + "pkg/runtime/serializer/streaming", + "pkg/runtime/serializer/versioning", + "pkg/selection", + "pkg/types", + "pkg/util/clock", + "pkg/util/errors", + "pkg/util/framer", + "pkg/util/httpstream", + "pkg/util/httpstream/spdy", + "pkg/util/intstr", + "pkg/util/json", + "pkg/util/net", + "pkg/util/remotecommand", + "pkg/util/runtime", + "pkg/util/sets", + "pkg/util/validation", + "pkg/util/validation/field", + "pkg/util/wait", + "pkg/util/yaml", + "pkg/version", + "pkg/watch", + "third_party/forked/golang/netutil", + "third_party/forked/golang/reflect", + ] + pruneopts = "UT" + revision = "19e3f5aa3adca672c153d324e6b7d82ff8935f03" + version = "kubernetes-1.9.8-beta.0" + +[[projects]] + digest = "1:31bf989f4ae02dabb3d956d02dcac9b21eb27b498d5d2589ab327f46d832c980" + name = "k8s.io/client-go" + packages = [ + "discovery", + "kubernetes", + "kubernetes/scheme", + "kubernetes/typed/admissionregistration/v1alpha1", + "kubernetes/typed/admissionregistration/v1beta1", + "kubernetes/typed/apps/v1", + "kubernetes/typed/apps/v1beta1", + "kubernetes/typed/apps/v1beta2", + "kubernetes/typed/authentication/v1", + "kubernetes/typed/authentication/v1beta1", + "kubernetes/typed/authorization/v1", + "kubernetes/typed/authorization/v1beta1", + "kubernetes/typed/autoscaling/v1", + "kubernetes/typed/autoscaling/v2beta1", + "kubernetes/typed/batch/v1", + "kubernetes/typed/batch/v1beta1", + "kubernetes/typed/batch/v2alpha1", + "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/core/v1", + "kubernetes/typed/events/v1beta1", + "kubernetes/typed/extensions/v1beta1", + "kubernetes/typed/networking/v1", + "kubernetes/typed/policy/v1beta1", + "kubernetes/typed/rbac/v1", + "kubernetes/typed/rbac/v1alpha1", + "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/scheduling/v1alpha1", + "kubernetes/typed/settings/v1alpha1", + "kubernetes/typed/storage/v1", + "kubernetes/typed/storage/v1alpha1", + "kubernetes/typed/storage/v1beta1", + "pkg/version", + "plugin/pkg/client/auth/gcp", + "rest", + "rest/watch", + "third_party/forked/golang/template", + "tools/auth", + "tools/clientcmd", + "tools/clientcmd/api", + "tools/clientcmd/api/latest", + "tools/clientcmd/api/v1", + "tools/metrics", + "tools/portforward", + "tools/reference", + "tools/remotecommand", + "transport", + "transport/spdy", + "util/cert", + "util/exec", + "util/flowcontrol", + "util/homedir", + "util/integer", + "util/jsonpath", + ] + pruneopts = "UT" + revision = "90539b4e75a8daaf7f67c3874c6180bfb1a63936" + version = "kubernetes-1.9.8-beta.0" + +[[projects]] + digest = "1:f5487c07872bdb7c40ffe629430b2fa815f9eca0d2c02bb9e866962eb38a0e70" + name = "k8s.io/kube-openapi" + packages = ["pkg/common"] + pruneopts = "UT" + revision = "39a7bf85c140f972372c2a0d1ee40adbf0c8bfe1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/fatih/color", + "github.com/gorilla/mux", + "github.com/lib/pq", + "github.com/sirupsen/logrus", + "github.com/spf13/cobra", + "github.com/spf13/viper", + "golang.org/x/crypto/ssh", + "gopkg.in/ory-am/dockertest.v3", + "gopkg.in/robfig/cron.v2", + "gopkg.in/yaml.v2", + "k8s.io/api/apps/v1", + "k8s.io/api/batch/v1", + "k8s.io/api/core/v1", + "k8s.io/apimachinery/pkg/api/errors", + "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/client-go/kubernetes", + "k8s.io/client-go/kubernetes/scheme", + "k8s.io/client-go/plugin/pkg/client/auth/gcp", + "k8s.io/client-go/rest", + "k8s.io/client-go/tools/clientcmd", + "k8s.io/client-go/tools/portforward", + "k8s.io/client-go/tools/remotecommand", + "k8s.io/client-go/transport/spdy", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 000000000..f20bf60e9 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,62 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/fatih/color" + version = "1.6.0" + +[[constraint]] + name = "github.com/gorilla/mux" + version = "1.6.1" + +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.0.3" + +[[constraint]] + name = "gopkg.in/ory-am/dockertest.v3" + version = "3.1.6" + +[[constraint]] + branch = "v2" + name = "gopkg.in/robfig/cron.v2" + +[[constraint]] + name = "k8s.io/api" + version = "kubernetes-1.9.3" + +[[constraint]] + name = "k8s.io/apimachinery" + version = "kubernetes-1.9.8-beta.0" + +[[constraint]] + name = "k8s.io/client-go" + version = "kubernetes-1.9.8-beta.0" + +[prune] + go-tests = true + unused-packages = true diff --git a/Makefile b/Makefile index a2722b480..c988956a9 100644 --- a/Makefile +++ b/Makefile @@ -24,10 +24,6 @@ endif setup: $(CCPROOT)/bin/install-deps.sh -gendeps: - godep save \ - github.com/crunchydata/crunchy-containers/badger - docbuild: cd $CCPROOT && ./generate-docs.sh @@ -68,7 +64,7 @@ pgadmin4: versiontest pgbadger: versiontest docker build -t $(CCP_IMAGE_PREFIX)/badgerserver:build -f $(CCP_BASEOS)/Dockerfile.badgerserver.$(CCP_BASEOS) . docker create --name extract $(CCP_IMAGE_PREFIX)/badgerserver:build - docker cp extract:/go/src/github.com/crunchydata/badgerserver/badgerserver ./bin/pgbadger/badgerserver + docker cp extract:/go/src/github.com/crunchydata/crunchy-containers/badgerserver ./bin/pgbadger/badgerserver docker rm -f extract docker build -t crunchy-pgbadger -f $(CCP_BASEOS)/$(CCP_PGVERSION)/Dockerfile.pgbadger.$(CCP_BASEOS) . docker tag crunchy-pgbadger $(CCP_IMAGE_PREFIX)/crunchy-pgbadger:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) @@ -132,7 +128,7 @@ upgrade: versiontest fi vac: versiontest - cd vacuum && godep go install vacuum.go + cd vacuum && go install vacuum.go cp $(GOBIN)/vacuum bin/vacuum docker build -t crunchy-vacuum -f $(CCP_BASEOS)/Dockerfile.vacuum.$(CCP_BASEOS) . docker tag crunchy-vacuum $(CCP_IMAGE_PREFIX)/crunchy-vacuum:$(CCP_BASEOS)-$(CCP_PG_FULLVERSION)-$(CCP_VERSION) diff --git a/bin/install-deps.sh b/bin/install-deps.sh index 7d810964b..69382c095 100755 --- a/bin/install-deps.sh +++ b/bin/install-deps.sh @@ -18,7 +18,6 @@ PROMETHEUS_VERSION=2.3.1 GRAFANA_VERSION=5.2.1 POSTGRES_EXPORTER_VERSION=0.4.6 NODE_EXPORTER_VERSION=0.16.0 -MERCURIAL_RPM='https://www.mercurial-scm.org/release/centos7/RPMS/x86_64/mercurial-4.6.1-1.x86_64.rpm' PGMONITOR_COMMIT='dffb2b5eb04ba13ee47ae81950410738d15e8c76' sudo yum -y install net-tools bind-utils wget unzip git @@ -56,12 +55,6 @@ fi go get github.com/blang/expenv go get github.com/square/certstrap -# pull in godeps and the dependencies for the golang code -go get github.com/tools/godep -sudo yum -y install ${MERCURIAL_RPM?} - -godep restore - # pgMonitor Setup if [[ -d ${CCPROOT?}/tools/pgmonitor ]] then diff --git a/centos7/Dockerfile.badgerserver.centos7 b/centos7/Dockerfile.badgerserver.centos7 index 650c412a7..5efb705ce 100644 --- a/centos7/Dockerfile.badgerserver.centos7 +++ b/centos7/Dockerfile.badgerserver.centos7 @@ -1,4 +1,4 @@ FROM golang:1.9.1 -WORKDIR /go/src/github.com/crunchydata/badgerserver -ADD badger/ . -RUN CGO_ENABLED=0 GOOS=linux go build -a -o badgerserver . +WORKDIR /go/src/github.com/crunchydata/crunchy-containers +ADD . . +RUN CGO_ENABLED=0 GOOS=linux go build -a -o badgerserver ./badger diff --git a/centos7/Dockerfile.sample-app-build.centos7 b/centos7/Dockerfile.sample-app-build.centos7 index bc5e90e2d..7791ccade 100644 --- a/centos7/Dockerfile.sample-app-build.centos7 +++ b/centos7/Dockerfile.sample-app-build.centos7 @@ -1,6 +1,4 @@ FROM golang:1.9.1 WORKDIR /go/src/github.com/crunchydata/sample-app ADD tools/sample-app/ . -RUN go get -d -v github.com/lib/pq \ - && go get -d -v github.com/gorilla/mux RUN CGO_ENABLED=0 GOOS=linux go build -a -o sample-app . diff --git a/centos7/Dockerfile.scheduler-build.centos7 b/centos7/Dockerfile.scheduler-build.centos7 index 3c7b10763..e6019ac81 100644 --- a/centos7/Dockerfile.scheduler-build.centos7 +++ b/centos7/Dockerfile.scheduler-build.centos7 @@ -1,7 +1,4 @@ FROM golang:1.9.1 WORKDIR /go/src/github.com/crunchydata/crunchy-containers ADD . . -RUN go get github.com/tools/godep \ - && godep restore \ - && go get gopkg.in/robfig/cron.v2 RUN CGO_ENABLED=0 GOOS=linux go build -a -o scheduler ./tools/scheduler diff --git a/hugo/content/installation/build-the-containers.adoc b/hugo/content/installation/build-the-containers.adoc index 4e4d06d12..f692a0cc3 100644 --- a/hugo/content/installation/build-the-containers.adoc +++ b/hugo/content/installation/build-the-containers.adoc @@ -25,7 +25,6 @@ Or if you'd rather build the containers from source, perform a container build as follows: .... -godep restore cd $CCPROOT make setup make all diff --git a/hugo/content/installation/environment-setup.adoc b/hugo/content/installation/environment-setup.adoc index d4979f348..1c5f7825e 100644 --- a/hugo/content/installation/environment-setup.adoc +++ b/hugo/content/installation/environment-setup.adoc @@ -71,7 +71,6 @@ mkdir -p $HOME/cdev/src $HOME/cdev/pkg $HOME/cdev/bin .... cd $GOPATH sudo yum -y install golang git docker -go get github.com/tools/godep cd src/github.com mkdir crunchydata cd crunchydata @@ -98,7 +97,6 @@ cd $GOPATH sudo subscription-manager repos --enable=rhel-7-server-optional-rpms sudo yum-config-manager --enable rhel-7-server-extras-rpms sudo yum -y install git golang -go get github.com/tools/godep cd src/github.com mkdir crunchydata cd crunchydata diff --git a/rhel7/Dockerfile.badgerserver.rhel7 b/rhel7/Dockerfile.badgerserver.rhel7 index 650c412a7..5efb705ce 100644 --- a/rhel7/Dockerfile.badgerserver.rhel7 +++ b/rhel7/Dockerfile.badgerserver.rhel7 @@ -1,4 +1,4 @@ FROM golang:1.9.1 -WORKDIR /go/src/github.com/crunchydata/badgerserver -ADD badger/ . -RUN CGO_ENABLED=0 GOOS=linux go build -a -o badgerserver . +WORKDIR /go/src/github.com/crunchydata/crunchy-containers +ADD . . +RUN CGO_ENABLED=0 GOOS=linux go build -a -o badgerserver ./badger diff --git a/rhel7/Dockerfile.dba.rhel7 b/rhel7/Dockerfile.dba.rhel7 deleted file mode 100644 index c15c2ab1b..000000000 --- a/rhel7/Dockerfile.dba.rhel7 +++ /dev/null @@ -1,48 +0,0 @@ -FROM registry.access.redhat.com/rhel7 -MAINTAINER Crunchy Data - -LABEL name="crunchydata/dba" \ - vendor="crunchy data" \ - Version="7.5" \ - Release="2.1.0" \ - url="https://crunchydata.com" \ - summary="Implements a cron scheduler." \ - description="Offers a way to perform simple DBA tasks that occur on some form of schedule such as backup jobs or running a vacuum on a single Postgres database container. You can either run the crunchy-dba container as a single pod or include the container within a database pod. The crunchy-dba container makes use of a Service Account to perform the startup of scheduled jobs. The Kube Job type is used to execute the scheduled jobs with a Restart policy of Never." \ - run="" \ - start="" \ - stop="" \ - io.k8s.description="DBA container" \ - io.k8s.display-name="Crunchy DBA container" \ - io.openshift.expose-services="" \ - io.openshift.tags="crunchy,database" - - -COPY conf/atomic/dba/help.1 /help.1 -COPY conf/atomic/dba/help.md /help.md -COPY conf/licenses /licenses - -RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm - -RUN yum -y update \ - && yum -y install epel-release \ - && yum -y install \ - bind-utils \ - gettext \ - hostname \ - iproute \ - nss_wrapper \ - procps-ng \ - psmisc \ - && yum clean all -y - -RUN mkdir -p /opt/cpm/bin /opt/cpm/conf - -ADD bin/dba /opt/cpm/bin -ADD bin/common /opt/cpm/bin -ADD conf/dba /opt/cpm/conf - -RUN chown -R 2:2 /opt/cpm - -USER 2 - -CMD ["/opt/cpm/bin/start-dba.sh"] diff --git a/rhel7/Dockerfile.scheduler-build.rhel7 b/rhel7/Dockerfile.scheduler-build.rhel7 index 3c7b10763..e6019ac81 100644 --- a/rhel7/Dockerfile.scheduler-build.rhel7 +++ b/rhel7/Dockerfile.scheduler-build.rhel7 @@ -1,7 +1,4 @@ FROM golang:1.9.1 WORKDIR /go/src/github.com/crunchydata/crunchy-containers ADD . . -RUN go get github.com/tools/godep \ - && godep restore \ - && go get gopkg.in/robfig/cron.v2 RUN CGO_ENABLED=0 GOOS=linux go build -a -o scheduler ./tools/scheduler diff --git a/tools/test-harness/README.md b/tools/test-harness/README.md index 659a9bfe4..4b17bfc9a 100644 --- a/tools/test-harness/README.md +++ b/tools/test-harness/README.md @@ -1,7 +1,7 @@ # Automated Test Harness -This test harness is used to verify that the `kube` examples are working as intended as -part of an integration test suite. This harness will deploy the examples, query the Kubeneretes +This test harness is used to verify that the `kube` examples are working as intended as +part of an integration test suite. This harness will deploy the examples, query the Kubeneretes API using `client-go` and run various tests against the deployments. The test harness creates namespaces for each test to avoid collision with object names. @@ -12,26 +12,17 @@ This harness can be run both in and out of a Kubernetes cluster. * An account with sufficient privileges is required (cluster-admin). * It's recommended that all images used in the testing should be pulled prior to running - the harness. Pulling images over the network may be slow and cause timeouts with the - harness. + the harness. Pulling images over the network may be slow and cause timeouts with the + harness. * The `kubeconfig` should be found in `$HOME/.kube/config` -* [Mercurial Version Control installed](https://www.mercurial-scm.org/wiki/Download) (installed in `install-deps.sh` if +* [Mercurial Version Control installed](https://www.mercurial-scm.org/wiki/Download) (installed in `install-deps.sh` if you're using CentOS7) -* `GOMAXPROCS` env should be set to the amount of cores the test harness should use (parallization +* `GOMAXPROCS` env should be set to the amount of cores the test harness should use (parallization option) -### Vendor - -`Godep` should restore vendor code in `$GOPATH` prior to running the harness: - -```bash -cd $CCPROOT -godep restore ./... -``` - ## Running -*Note*: It's recommended to disable the `go test` timeout (it defaults to 10 minutes which +*Note*: It's recommended to disable the `go test` timeout (it defaults to 10 minutes which is not enough time to run all tests): #### Go `1.9` @@ -53,7 +44,7 @@ go test -v -timeout 0 -parallel 2 ### Running Specific Tests -Using regex, run the `TestPrimary` test (`$` is regex for the string ends, +Using regex, run the `TestPrimary` test (`$` is regex for the string ends, meaning it won't match on say `TestPrimaryReplica`) ```bash @@ -63,8 +54,8 @@ go test -v -run TestPrimary$ ### Manual Cleanup -If for some reason the test-harness crashes, it's possible the test-harness namespaces -have not been cleaned up correctly. To manually delete the test harness namespaces, +If for some reason the test-harness crashes, it's possible the test-harness namespaces +have not been cleaned up correctly. To manually delete the test harness namespaces, run the following script: ```bash diff --git a/tools/test-harness/backrest_test.go b/tools/test-harness/backrest_test.go index cab52b8c5..52004f012 100644 --- a/tools/test-harness/backrest_test.go +++ b/tools/test-harness/backrest_test.go @@ -94,9 +94,15 @@ func TestBackrestDeltaRestore(t *testing.T) { defer harness.runExample("examples/kube/backrest/delta/cleanup.sh", env, t) } - if ok, err := harness.Client.IsJobComplete(harness.Namespace, "backrest-delta-restore-job"); !ok { - t.Fatal(err) - } + t.Log("Checking if job has completed...") + job, err := harness.Client.GetJob(harness.Namespace, "backrest-delta-restore-job") + if err != nil { + t.Fatal(err) + } + + if err := harness.Client.IsJobComplete(harness.Namespace, job); err != nil { + t.Fatal(err) + } _, err = harness.runExample("examples/kube/backrest/delta/post-restore.sh", env, t) if err != nil { @@ -157,9 +163,15 @@ func TestBackrestFullRestore(t *testing.T) { defer harness.runExample("examples/kube/backrest/full/cleanup.sh", env, t) } - if ok, err := harness.Client.IsJobComplete(harness.Namespace, "backrest-full-restore-job"); !ok { - t.Fatal(err) - } + t.Log("Checking if job has completed...") + job, err := harness.Client.GetJob(harness.Namespace, "backrest-full-restore-job") + if err != nil { + t.Fatal(err) + } + + if err := harness.Client.IsJobComplete(harness.Namespace, job); err != nil { + t.Fatal(err) + } _, err = harness.runExample("examples/kube/backrest/full/post-restore.sh", env, t) if err != nil { @@ -221,9 +233,15 @@ func TestBackrestPITRRestore(t *testing.T) { defer harness.runExample("examples/kube/backrest/pitr/cleanup.sh", env, t) } - if ok, err := harness.Client.IsJobComplete(harness.Namespace, "backrest-pitr-restore-job"); !ok { - t.Fatal(err) - } + t.Log("Checking if job has completed...") + job, err := harness.Client.GetJob(harness.Namespace, "backrest-pitr-restore-job") + if err != nil { + t.Fatal(err) + } + + if err := harness.Client.IsJobComplete(harness.Namespace, job); err != nil { + t.Fatal(err) + } _, err = harness.runExample("examples/kube/backrest/pitr/post-restore.sh", env, t) if err != nil { diff --git a/tools/test-harness/backup_test.go b/tools/test-harness/backup_test.go index 587d85f37..fb57edd67 100644 --- a/tools/test-harness/backup_test.go +++ b/tools/test-harness/backup_test.go @@ -37,9 +37,14 @@ func TestBackup(t *testing.T) { } t.Log("Checking if job has completed...") - if ok, err := harness.Client.IsJobComplete(harness.Namespace, "backup"); !ok { - t.Fatal(err) - } + job, err := harness.Client.GetJob(harness.Namespace, "backup") + if err != nil { + t.Fatal(err) + } + + if err := harness.Client.IsJobComplete(harness.Namespace, job); err != nil { + t.Fatal(err) + } report, err := harness.createReport() if err != nil { diff --git a/tools/test-harness/pgdump_test.go b/tools/test-harness/pgdump_test.go index a1b25a4ee..e4191bfc3 100644 --- a/tools/test-harness/pgdump_test.go +++ b/tools/test-harness/pgdump_test.go @@ -37,10 +37,15 @@ func TestPGDump(t *testing.T) { defer harness.runExample("examples/kube/pgdump/cleanup.sh", env, t) } - t.Log("Checking if job is completed..") - if ok, err := harness.Client.IsJobComplete(harness.Namespace, "pgdump"); !ok { - t.Fatal(err) - } + t.Log("Checking if job has completed...") + job, err := harness.Client.GetJob(harness.Namespace, "pgdump") + if err != nil { + t.Fatal(err) + } + + if err := harness.Client.IsJobComplete(harness.Namespace, job); err != nil { + t.Fatal(err) + } report, err := harness.createReport() if err != nil { diff --git a/tools/test-harness/pgrestore_test.go b/tools/test-harness/pgrestore_test.go index db08a1a08..464e0f5c7 100644 --- a/tools/test-harness/pgrestore_test.go +++ b/tools/test-harness/pgrestore_test.go @@ -37,10 +37,15 @@ func TestPGRestore(t *testing.T) { defer harness.runExample("examples/kube/pgdump/cleanup.sh", env, t) } - t.Log("Checking if job is completed..") - if ok, err := harness.Client.IsJobComplete(harness.Namespace, "pgdump"); !ok { - t.Fatal(err) - } + t.Log("Checking if job has completed...") + job, err := harness.Client.GetJob(harness.Namespace, "pgdump") + if err != nil { + t.Fatal(err) + } + + if err := harness.Client.IsJobComplete(harness.Namespace, job); err != nil { + t.Fatal(err) + } t.Log("Running the 'pgrestore' example...") _, err = harness.runExample("examples/kube/pgrestore/run.sh", env, t) @@ -52,10 +57,15 @@ func TestPGRestore(t *testing.T) { defer harness.runExample("examples/kube/pgrestore/cleanup.sh", env, t) } - t.Log("Checking if job is completed..") - if ok, err := harness.Client.IsJobComplete(harness.Namespace, "pgrestore"); !ok { - t.Fatal(err) - } + t.Log("Checking if job has completed...") + restoreJob, err := harness.Client.GetJob(harness.Namespace, "pgrestore") + if err != nil { + t.Fatal(err) + } + + if err := harness.Client.IsJobComplete(harness.Namespace, restoreJob); err != nil { + t.Fatal(err) + } report, err := harness.createReport() if err != nil { diff --git a/tools/test-harness/vacuum_test.go b/tools/test-harness/vacuum_test.go index bef5ddd21..6cd466d6c 100644 --- a/tools/test-harness/vacuum_test.go +++ b/tools/test-harness/vacuum_test.go @@ -36,10 +36,15 @@ func TestVacuum(t *testing.T) { defer harness.runExample("examples/kube/vacuum/cleanup.sh", env, t) } - t.Log("Checking if job has completed...") - if ok, err := harness.Client.IsJobComplete(harness.Namespace, "vacuum"); !ok { - t.Fatal(err) - } + t.Log("Checking if job has completed...") + job, err := harness.Client.GetJob(harness.Namespace, "vacuum") + if err != nil { + t.Fatal(err) + } + + if err := harness.Client.IsJobComplete(harness.Namespace, job); err != nil { + t.Fatal(err) + } report, err := harness.createReport() if err != nil { diff --git a/vendor/cloud.google.com/go/AUTHORS b/vendor/cloud.google.com/go/AUTHORS new file mode 100644 index 000000000..c364af1da --- /dev/null +++ b/vendor/cloud.google.com/go/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of cloud authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. + +Filippo Valsorda +Google Inc. +Ingo Oeser +Palm Stone Games, Inc. +Paweł Knap +Péter Szilágyi +Tyler Treat diff --git a/vendor/cloud.google.com/go/CONTRIBUTORS b/vendor/cloud.google.com/go/CONTRIBUTORS new file mode 100644 index 000000000..3b3cbed98 --- /dev/null +++ b/vendor/cloud.google.com/go/CONTRIBUTORS @@ -0,0 +1,40 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# Names should be added to this file as: +# Name + +# Keep the list alphabetically sorted. + +Alexis Hunt +Andreas Litt +Andrew Gerrand +Brad Fitzpatrick +Burcu Dogan +Dave Day +David Sansome +David Symonds +Filippo Valsorda +Glenn Lewis +Ingo Oeser +James Hall +Johan Euphrosine +Jonathan Amsterdam +Kunpei Sakai +Luna Duclos +Magnus Hiie +Mario Castro +Michael McGreevy +Omar Jarjur +Paweł Knap +Péter Szilágyi +Sarah Adams +Thanatat Tamtan +Toby Burress +Tuo Shan +Tyler Treat diff --git a/vendor/cloud.google.com/go/LICENSE b/vendor/cloud.google.com/go/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/cloud.google.com/go/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata.go b/vendor/cloud.google.com/go/compute/metadata/metadata.go new file mode 100644 index 000000000..9d0660be4 --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/metadata.go @@ -0,0 +1,503 @@ +// Copyright 2014 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package metadata provides access to Google Compute Engine (GCE) +// metadata and API service accounts. +// +// This package is a wrapper around the GCE metadata service, +// as documented at https://developers.google.com/compute/docs/metadata. +package metadata // import "cloud.google.com/go/compute/metadata" + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net" + "net/http" + "net/url" + "os" + "runtime" + "strings" + "sync" + "time" + + "golang.org/x/net/context" + "golang.org/x/net/context/ctxhttp" +) + +const ( + // metadataIP is the documented metadata server IP address. + metadataIP = "169.254.169.254" + + // metadataHostEnv is the environment variable specifying the + // GCE metadata hostname. If empty, the default value of + // metadataIP ("169.254.169.254") is used instead. + // This is variable name is not defined by any spec, as far as + // I know; it was made up for the Go package. + metadataHostEnv = "GCE_METADATA_HOST" + + userAgent = "gcloud-golang/0.1" +) + +type cachedValue struct { + k string + trim bool + mu sync.Mutex + v string +} + +var ( + projID = &cachedValue{k: "project/project-id", trim: true} + projNum = &cachedValue{k: "project/numeric-project-id", trim: true} + instID = &cachedValue{k: "instance/id", trim: true} +) + +var ( + defaultClient = &Client{hc: &http.Client{ + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 2 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + ResponseHeaderTimeout: 2 * time.Second, + }, + }} + subscribeClient = &Client{hc: &http.Client{ + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 2 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + }, + }} +) + +// NotDefinedError is returned when requested metadata is not defined. +// +// The underlying string is the suffix after "/computeMetadata/v1/". +// +// This error is not returned if the value is defined to be the empty +// string. +type NotDefinedError string + +func (suffix NotDefinedError) Error() string { + return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix)) +} + +func (c *cachedValue) get(cl *Client) (v string, err error) { + defer c.mu.Unlock() + c.mu.Lock() + if c.v != "" { + return c.v, nil + } + if c.trim { + v, err = cl.getTrimmed(c.k) + } else { + v, err = cl.Get(c.k) + } + if err == nil { + c.v = v + } + return +} + +var ( + onGCEOnce sync.Once + onGCE bool +) + +// OnGCE reports whether this process is running on Google Compute Engine. +func OnGCE() bool { + onGCEOnce.Do(initOnGCE) + return onGCE +} + +func initOnGCE() { + onGCE = testOnGCE() +} + +func testOnGCE() bool { + // The user explicitly said they're on GCE, so trust them. + if os.Getenv(metadataHostEnv) != "" { + return true + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + resc := make(chan bool, 2) + + // Try two strategies in parallel. + // See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194 + go func() { + req, _ := http.NewRequest("GET", "http://"+metadataIP, nil) + req.Header.Set("User-Agent", userAgent) + res, err := ctxhttp.Do(ctx, defaultClient.hc, req) + if err != nil { + resc <- false + return + } + defer res.Body.Close() + resc <- res.Header.Get("Metadata-Flavor") == "Google" + }() + + go func() { + addrs, err := net.LookupHost("metadata.google.internal") + if err != nil || len(addrs) == 0 { + resc <- false + return + } + resc <- strsContains(addrs, metadataIP) + }() + + tryHarder := systemInfoSuggestsGCE() + if tryHarder { + res := <-resc + if res { + // The first strategy succeeded, so let's use it. + return true + } + // Wait for either the DNS or metadata server probe to + // contradict the other one and say we are running on + // GCE. Give it a lot of time to do so, since the system + // info already suggests we're running on a GCE BIOS. + timer := time.NewTimer(5 * time.Second) + defer timer.Stop() + select { + case res = <-resc: + return res + case <-timer.C: + // Too slow. Who knows what this system is. + return false + } + } + + // There's no hint from the system info that we're running on + // GCE, so use the first probe's result as truth, whether it's + // true or false. The goal here is to optimize for speed for + // users who are NOT running on GCE. We can't assume that + // either a DNS lookup or an HTTP request to a blackholed IP + // address is fast. Worst case this should return when the + // metaClient's Transport.ResponseHeaderTimeout or + // Transport.Dial.Timeout fires (in two seconds). + return <-resc +} + +// systemInfoSuggestsGCE reports whether the local system (without +// doing network requests) suggests that we're running on GCE. If this +// returns true, testOnGCE tries a bit harder to reach its metadata +// server. +func systemInfoSuggestsGCE() bool { + if runtime.GOOS != "linux" { + // We don't have any non-Linux clues available, at least yet. + return false + } + slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name") + name := strings.TrimSpace(string(slurp)) + return name == "Google" || name == "Google Compute Engine" +} + +// Subscribe calls Client.Subscribe on a client designed for subscribing (one with no +// ResponseHeaderTimeout). +func Subscribe(suffix string, fn func(v string, ok bool) error) error { + return subscribeClient.Subscribe(suffix, fn) +} + +// Get calls Client.Get on the default client. +func Get(suffix string) (string, error) { return defaultClient.Get(suffix) } + +// ProjectID returns the current instance's project ID string. +func ProjectID() (string, error) { return defaultClient.ProjectID() } + +// NumericProjectID returns the current instance's numeric project ID. +func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() } + +// InternalIP returns the instance's primary internal IP address. +func InternalIP() (string, error) { return defaultClient.InternalIP() } + +// ExternalIP returns the instance's primary external (public) IP address. +func ExternalIP() (string, error) { return defaultClient.ExternalIP() } + +// Hostname returns the instance's hostname. This will be of the form +// ".c..internal". +func Hostname() (string, error) { return defaultClient.Hostname() } + +// InstanceTags returns the list of user-defined instance tags, +// assigned when initially creating a GCE instance. +func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() } + +// InstanceID returns the current VM's numeric instance ID. +func InstanceID() (string, error) { return defaultClient.InstanceID() } + +// InstanceName returns the current VM's instance ID string. +func InstanceName() (string, error) { return defaultClient.InstanceName() } + +// Zone returns the current VM's zone, such as "us-central1-b". +func Zone() (string, error) { return defaultClient.Zone() } + +// InstanceAttributes calls Client.InstanceAttributes on the default client. +func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() } + +// ProjectAttributes calls Client.ProjectAttributes on the default client. +func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() } + +// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client. +func InstanceAttributeValue(attr string) (string, error) { + return defaultClient.InstanceAttributeValue(attr) +} + +// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client. +func ProjectAttributeValue(attr string) (string, error) { + return defaultClient.ProjectAttributeValue(attr) +} + +// Scopes calls Client.Scopes on the default client. +func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) } + +func strsContains(ss []string, s string) bool { + for _, v := range ss { + if v == s { + return true + } + } + return false +} + +// A Client provides metadata. +type Client struct { + hc *http.Client +} + +// NewClient returns a Client that can be used to fetch metadata. All HTTP requests +// will use the given http.Client instead of the default client. +func NewClient(c *http.Client) *Client { + return &Client{hc: c} +} + +// getETag returns a value from the metadata service as well as the associated ETag. +// This func is otherwise equivalent to Get. +func (c *Client) getETag(suffix string) (value, etag string, err error) { + // Using a fixed IP makes it very difficult to spoof the metadata service in + // a container, which is an important use-case for local testing of cloud + // deployments. To enable spoofing of the metadata service, the environment + // variable GCE_METADATA_HOST is first inspected to decide where metadata + // requests shall go. + host := os.Getenv(metadataHostEnv) + if host == "" { + // Using 169.254.169.254 instead of "metadata" here because Go + // binaries built with the "netgo" tag and without cgo won't + // know the search suffix for "metadata" is + // ".google.internal", and this IP address is documented as + // being stable anyway. + host = metadataIP + } + url := "http://" + host + "/computeMetadata/v1/" + suffix + req, _ := http.NewRequest("GET", url, nil) + req.Header.Set("Metadata-Flavor", "Google") + req.Header.Set("User-Agent", userAgent) + res, err := c.hc.Do(req) + if err != nil { + return "", "", err + } + defer res.Body.Close() + if res.StatusCode == http.StatusNotFound { + return "", "", NotDefinedError(suffix) + } + if res.StatusCode != 200 { + return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url) + } + all, err := ioutil.ReadAll(res.Body) + if err != nil { + return "", "", err + } + return string(all), res.Header.Get("Etag"), nil +} + +// Get returns a value from the metadata service. +// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/". +// +// If the GCE_METADATA_HOST environment variable is not defined, a default of +// 169.254.169.254 will be used instead. +// +// If the requested metadata is not defined, the returned error will +// be of type NotDefinedError. +func (c *Client) Get(suffix string) (string, error) { + val, _, err := c.getETag(suffix) + return val, err +} + +func (c *Client) getTrimmed(suffix string) (s string, err error) { + s, err = c.Get(suffix) + s = strings.TrimSpace(s) + return +} + +func (c *Client) lines(suffix string) ([]string, error) { + j, err := c.Get(suffix) + if err != nil { + return nil, err + } + s := strings.Split(strings.TrimSpace(j), "\n") + for i := range s { + s[i] = strings.TrimSpace(s[i]) + } + return s, nil +} + +// ProjectID returns the current instance's project ID string. +func (c *Client) ProjectID() (string, error) { return projID.get(c) } + +// NumericProjectID returns the current instance's numeric project ID. +func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) } + +// InstanceID returns the current VM's numeric instance ID. +func (c *Client) InstanceID() (string, error) { return instID.get(c) } + +// InternalIP returns the instance's primary internal IP address. +func (c *Client) InternalIP() (string, error) { + return c.getTrimmed("instance/network-interfaces/0/ip") +} + +// ExternalIP returns the instance's primary external (public) IP address. +func (c *Client) ExternalIP() (string, error) { + return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip") +} + +// Hostname returns the instance's hostname. This will be of the form +// ".c..internal". +func (c *Client) Hostname() (string, error) { + return c.getTrimmed("instance/hostname") +} + +// InstanceTags returns the list of user-defined instance tags, +// assigned when initially creating a GCE instance. +func (c *Client) InstanceTags() ([]string, error) { + var s []string + j, err := c.Get("instance/tags") + if err != nil { + return nil, err + } + if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil { + return nil, err + } + return s, nil +} + +// InstanceName returns the current VM's instance ID string. +func (c *Client) InstanceName() (string, error) { + host, err := c.Hostname() + if err != nil { + return "", err + } + return strings.Split(host, ".")[0], nil +} + +// Zone returns the current VM's zone, such as "us-central1-b". +func (c *Client) Zone() (string, error) { + zone, err := c.getTrimmed("instance/zone") + // zone is of the form "projects//zones/". + if err != nil { + return "", err + } + return zone[strings.LastIndex(zone, "/")+1:], nil +} + +// InstanceAttributes returns the list of user-defined attributes, +// assigned when initially creating a GCE VM instance. The value of an +// attribute can be obtained with InstanceAttributeValue. +func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") } + +// ProjectAttributes returns the list of user-defined attributes +// applying to the project as a whole, not just this VM. The value of +// an attribute can be obtained with ProjectAttributeValue. +func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") } + +// InstanceAttributeValue returns the value of the provided VM +// instance attribute. +// +// If the requested attribute is not defined, the returned error will +// be of type NotDefinedError. +// +// InstanceAttributeValue may return ("", nil) if the attribute was +// defined to be the empty string. +func (c *Client) InstanceAttributeValue(attr string) (string, error) { + return c.Get("instance/attributes/" + attr) +} + +// ProjectAttributeValue returns the value of the provided +// project attribute. +// +// If the requested attribute is not defined, the returned error will +// be of type NotDefinedError. +// +// ProjectAttributeValue may return ("", nil) if the attribute was +// defined to be the empty string. +func (c *Client) ProjectAttributeValue(attr string) (string, error) { + return c.Get("project/attributes/" + attr) +} + +// Scopes returns the service account scopes for the given account. +// The account may be empty or the string "default" to use the instance's +// main account. +func (c *Client) Scopes(serviceAccount string) ([]string, error) { + if serviceAccount == "" { + serviceAccount = "default" + } + return c.lines("instance/service-accounts/" + serviceAccount + "/scopes") +} + +// Subscribe subscribes to a value from the metadata service. +// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/". +// The suffix may contain query parameters. +// +// Subscribe calls fn with the latest metadata value indicated by the provided +// suffix. If the metadata value is deleted, fn is called with the empty string +// and ok false. Subscribe blocks until fn returns a non-nil error or the value +// is deleted. Subscribe returns the error value returned from the last call to +// fn, which may be nil when ok == false. +func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error { + const failedSubscribeSleep = time.Second * 5 + + // First check to see if the metadata value exists at all. + val, lastETag, err := c.getETag(suffix) + if err != nil { + return err + } + + if err := fn(val, true); err != nil { + return err + } + + ok := true + if strings.ContainsRune(suffix, '?') { + suffix += "&wait_for_change=true&last_etag=" + } else { + suffix += "?wait_for_change=true&last_etag=" + } + for { + val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag)) + if err != nil { + if _, deleted := err.(NotDefinedError); !deleted { + time.Sleep(failedSubscribeSleep) + continue // Retry on other errors. + } + ok = false + } + lastETag = etag + + if err := fn(val, ok); err != nil || !ok { + return err + } + } +} diff --git a/vendor/github.com/Azure/go-ansiterm/LICENSE b/vendor/github.com/Azure/go-ansiterm/LICENSE new file mode 100644 index 000000000..e3d9a64d1 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/Azure/go-ansiterm/README.md b/vendor/github.com/Azure/go-ansiterm/README.md new file mode 100644 index 000000000..261c041e7 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/README.md @@ -0,0 +1,12 @@ +# go-ansiterm + +This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent. + +For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position. + +The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go). + +See parser_test.go for examples exercising the state machine and generating appropriate function calls. + +----- +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/vendor/github.com/Azure/go-ansiterm/constants.go b/vendor/github.com/Azure/go-ansiterm/constants.go new file mode 100644 index 000000000..96504a33b --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/constants.go @@ -0,0 +1,188 @@ +package ansiterm + +const LogEnv = "DEBUG_TERMINAL" + +// ANSI constants +// References: +// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm +// -- http://man7.org/linux/man-pages/man4/console_codes.4.html +// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html +// -- http://en.wikipedia.org/wiki/ANSI_escape_code +// -- http://vt100.net/emu/dec_ansi_parser +// -- http://vt100.net/emu/vt500_parser.svg +// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html +// -- http://www.inwap.com/pdp10/ansicode.txt +const ( + // ECMA-48 Set Graphics Rendition + // Note: + // -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved + // -- Fonts could possibly be supported via SetCurrentConsoleFontEx + // -- Windows does not expose the per-window cursor (i.e., caret) blink times + ANSI_SGR_RESET = 0 + ANSI_SGR_BOLD = 1 + ANSI_SGR_DIM = 2 + _ANSI_SGR_ITALIC = 3 + ANSI_SGR_UNDERLINE = 4 + _ANSI_SGR_BLINKSLOW = 5 + _ANSI_SGR_BLINKFAST = 6 + ANSI_SGR_REVERSE = 7 + _ANSI_SGR_INVISIBLE = 8 + _ANSI_SGR_LINETHROUGH = 9 + _ANSI_SGR_FONT_00 = 10 + _ANSI_SGR_FONT_01 = 11 + _ANSI_SGR_FONT_02 = 12 + _ANSI_SGR_FONT_03 = 13 + _ANSI_SGR_FONT_04 = 14 + _ANSI_SGR_FONT_05 = 15 + _ANSI_SGR_FONT_06 = 16 + _ANSI_SGR_FONT_07 = 17 + _ANSI_SGR_FONT_08 = 18 + _ANSI_SGR_FONT_09 = 19 + _ANSI_SGR_FONT_10 = 20 + _ANSI_SGR_DOUBLEUNDERLINE = 21 + ANSI_SGR_BOLD_DIM_OFF = 22 + _ANSI_SGR_ITALIC_OFF = 23 + ANSI_SGR_UNDERLINE_OFF = 24 + _ANSI_SGR_BLINK_OFF = 25 + _ANSI_SGR_RESERVED_00 = 26 + ANSI_SGR_REVERSE_OFF = 27 + _ANSI_SGR_INVISIBLE_OFF = 28 + _ANSI_SGR_LINETHROUGH_OFF = 29 + ANSI_SGR_FOREGROUND_BLACK = 30 + ANSI_SGR_FOREGROUND_RED = 31 + ANSI_SGR_FOREGROUND_GREEN = 32 + ANSI_SGR_FOREGROUND_YELLOW = 33 + ANSI_SGR_FOREGROUND_BLUE = 34 + ANSI_SGR_FOREGROUND_MAGENTA = 35 + ANSI_SGR_FOREGROUND_CYAN = 36 + ANSI_SGR_FOREGROUND_WHITE = 37 + _ANSI_SGR_RESERVED_01 = 38 + ANSI_SGR_FOREGROUND_DEFAULT = 39 + ANSI_SGR_BACKGROUND_BLACK = 40 + ANSI_SGR_BACKGROUND_RED = 41 + ANSI_SGR_BACKGROUND_GREEN = 42 + ANSI_SGR_BACKGROUND_YELLOW = 43 + ANSI_SGR_BACKGROUND_BLUE = 44 + ANSI_SGR_BACKGROUND_MAGENTA = 45 + ANSI_SGR_BACKGROUND_CYAN = 46 + ANSI_SGR_BACKGROUND_WHITE = 47 + _ANSI_SGR_RESERVED_02 = 48 + ANSI_SGR_BACKGROUND_DEFAULT = 49 + // 50 - 65: Unsupported + + ANSI_MAX_CMD_LENGTH = 4096 + + MAX_INPUT_EVENTS = 128 + DEFAULT_WIDTH = 80 + DEFAULT_HEIGHT = 24 + + ANSI_BEL = 0x07 + ANSI_BACKSPACE = 0x08 + ANSI_TAB = 0x09 + ANSI_LINE_FEED = 0x0A + ANSI_VERTICAL_TAB = 0x0B + ANSI_FORM_FEED = 0x0C + ANSI_CARRIAGE_RETURN = 0x0D + ANSI_ESCAPE_PRIMARY = 0x1B + ANSI_ESCAPE_SECONDARY = 0x5B + ANSI_OSC_STRING_ENTRY = 0x5D + ANSI_COMMAND_FIRST = 0x40 + ANSI_COMMAND_LAST = 0x7E + DCS_ENTRY = 0x90 + CSI_ENTRY = 0x9B + OSC_STRING = 0x9D + ANSI_PARAMETER_SEP = ";" + ANSI_CMD_G0 = '(' + ANSI_CMD_G1 = ')' + ANSI_CMD_G2 = '*' + ANSI_CMD_G3 = '+' + ANSI_CMD_DECPNM = '>' + ANSI_CMD_DECPAM = '=' + ANSI_CMD_OSC = ']' + ANSI_CMD_STR_TERM = '\\' + + KEY_CONTROL_PARAM_2 = ";2" + KEY_CONTROL_PARAM_3 = ";3" + KEY_CONTROL_PARAM_4 = ";4" + KEY_CONTROL_PARAM_5 = ";5" + KEY_CONTROL_PARAM_6 = ";6" + KEY_CONTROL_PARAM_7 = ";7" + KEY_CONTROL_PARAM_8 = ";8" + KEY_ESC_CSI = "\x1B[" + KEY_ESC_N = "\x1BN" + KEY_ESC_O = "\x1BO" + + FILL_CHARACTER = ' ' +) + +func getByteRange(start byte, end byte) []byte { + bytes := make([]byte, 0, 32) + for i := start; i <= end; i++ { + bytes = append(bytes, byte(i)) + } + + return bytes +} + +var toGroundBytes = getToGroundBytes() +var executors = getExecuteBytes() + +// SPACE 20+A0 hex Always and everywhere a blank space +// Intermediate 20-2F hex !"#$%&'()*+,-./ +var intermeds = getByteRange(0x20, 0x2F) + +// Parameters 30-3F hex 0123456789:;<=>? +// CSI Parameters 30-39, 3B hex 0123456789; +var csiParams = getByteRange(0x30, 0x3F) + +var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...) + +// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ +var upperCase = getByteRange(0x40, 0x5F) + +// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~ +var lowerCase = getByteRange(0x60, 0x7E) + +// Alphabetics 40-7E hex (all of upper and lower case) +var alphabetics = append(upperCase, lowerCase...) + +var printables = getByteRange(0x20, 0x7F) + +var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E) +var escapeToGroundBytes = getEscapeToGroundBytes() + +// See http://www.vt100.net/emu/vt500_parser.png for description of the complex +// byte ranges below + +func getEscapeToGroundBytes() []byte { + escapeToGroundBytes := getByteRange(0x30, 0x4F) + escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...) + escapeToGroundBytes = append(escapeToGroundBytes, 0x59) + escapeToGroundBytes = append(escapeToGroundBytes, 0x5A) + escapeToGroundBytes = append(escapeToGroundBytes, 0x5C) + escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...) + return escapeToGroundBytes +} + +func getExecuteBytes() []byte { + executeBytes := getByteRange(0x00, 0x17) + executeBytes = append(executeBytes, 0x19) + executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...) + return executeBytes +} + +func getToGroundBytes() []byte { + groundBytes := []byte{0x18} + groundBytes = append(groundBytes, 0x1A) + groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...) + groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...) + groundBytes = append(groundBytes, 0x99) + groundBytes = append(groundBytes, 0x9A) + groundBytes = append(groundBytes, 0x9C) + return groundBytes +} + +// Delete 7F hex Always and everywhere ignored +// C1 Control 80-9F hex 32 additional control characters +// G1 Displayable A1-FE hex 94 additional displayable characters +// Special A0+FF hex Same as SPACE and DELETE diff --git a/vendor/github.com/Azure/go-ansiterm/context.go b/vendor/github.com/Azure/go-ansiterm/context.go new file mode 100644 index 000000000..8d66e777c --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/context.go @@ -0,0 +1,7 @@ +package ansiterm + +type ansiContext struct { + currentChar byte + paramBuffer []byte + interBuffer []byte +} diff --git a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go new file mode 100644 index 000000000..bcbe00d0c --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go @@ -0,0 +1,49 @@ +package ansiterm + +type csiEntryState struct { + baseState +} + +func (csiState csiEntryState) Handle(b byte) (s state, e error) { + csiState.parser.logf("CsiEntry::Handle %#x", b) + + nextState, err := csiState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(alphabetics, b): + return csiState.parser.ground, nil + case sliceContains(csiCollectables, b): + return csiState.parser.csiParam, nil + case sliceContains(executors, b): + return csiState, csiState.parser.execute() + } + + return csiState, nil +} + +func (csiState csiEntryState) Transition(s state) error { + csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name()) + csiState.baseState.Transition(s) + + switch s { + case csiState.parser.ground: + return csiState.parser.csiDispatch() + case csiState.parser.csiParam: + switch { + case sliceContains(csiParams, csiState.parser.context.currentChar): + csiState.parser.collectParam() + case sliceContains(intermeds, csiState.parser.context.currentChar): + csiState.parser.collectInter() + } + } + + return nil +} + +func (csiState csiEntryState) Enter() error { + csiState.parser.clear() + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go new file mode 100644 index 000000000..7ed5e01c3 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go @@ -0,0 +1,38 @@ +package ansiterm + +type csiParamState struct { + baseState +} + +func (csiState csiParamState) Handle(b byte) (s state, e error) { + csiState.parser.logf("CsiParam::Handle %#x", b) + + nextState, err := csiState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(alphabetics, b): + return csiState.parser.ground, nil + case sliceContains(csiCollectables, b): + csiState.parser.collectParam() + return csiState, nil + case sliceContains(executors, b): + return csiState, csiState.parser.execute() + } + + return csiState, nil +} + +func (csiState csiParamState) Transition(s state) error { + csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name()) + csiState.baseState.Transition(s) + + switch s { + case csiState.parser.ground: + return csiState.parser.csiDispatch() + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go new file mode 100644 index 000000000..1c719db9e --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go @@ -0,0 +1,36 @@ +package ansiterm + +type escapeIntermediateState struct { + baseState +} + +func (escState escapeIntermediateState) Handle(b byte) (s state, e error) { + escState.parser.logf("escapeIntermediateState::Handle %#x", b) + nextState, err := escState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(intermeds, b): + return escState, escState.parser.collectInter() + case sliceContains(executors, b): + return escState, escState.parser.execute() + case sliceContains(escapeIntermediateToGroundBytes, b): + return escState.parser.ground, nil + } + + return escState, nil +} + +func (escState escapeIntermediateState) Transition(s state) error { + escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name()) + escState.baseState.Transition(s) + + switch s { + case escState.parser.ground: + return escState.parser.escDispatch() + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/escape_state.go b/vendor/github.com/Azure/go-ansiterm/escape_state.go new file mode 100644 index 000000000..6390abd23 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/escape_state.go @@ -0,0 +1,47 @@ +package ansiterm + +type escapeState struct { + baseState +} + +func (escState escapeState) Handle(b byte) (s state, e error) { + escState.parser.logf("escapeState::Handle %#x", b) + nextState, err := escState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case b == ANSI_ESCAPE_SECONDARY: + return escState.parser.csiEntry, nil + case b == ANSI_OSC_STRING_ENTRY: + return escState.parser.oscString, nil + case sliceContains(executors, b): + return escState, escState.parser.execute() + case sliceContains(escapeToGroundBytes, b): + return escState.parser.ground, nil + case sliceContains(intermeds, b): + return escState.parser.escapeIntermediate, nil + } + + return escState, nil +} + +func (escState escapeState) Transition(s state) error { + escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name()) + escState.baseState.Transition(s) + + switch s { + case escState.parser.ground: + return escState.parser.escDispatch() + case escState.parser.escapeIntermediate: + return escState.parser.collectInter() + } + + return nil +} + +func (escState escapeState) Enter() error { + escState.parser.clear() + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/event_handler.go b/vendor/github.com/Azure/go-ansiterm/event_handler.go new file mode 100644 index 000000000..98087b38c --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/event_handler.go @@ -0,0 +1,90 @@ +package ansiterm + +type AnsiEventHandler interface { + // Print + Print(b byte) error + + // Execute C0 commands + Execute(b byte) error + + // CUrsor Up + CUU(int) error + + // CUrsor Down + CUD(int) error + + // CUrsor Forward + CUF(int) error + + // CUrsor Backward + CUB(int) error + + // Cursor to Next Line + CNL(int) error + + // Cursor to Previous Line + CPL(int) error + + // Cursor Horizontal position Absolute + CHA(int) error + + // Vertical line Position Absolute + VPA(int) error + + // CUrsor Position + CUP(int, int) error + + // Horizontal and Vertical Position (depends on PUM) + HVP(int, int) error + + // Text Cursor Enable Mode + DECTCEM(bool) error + + // Origin Mode + DECOM(bool) error + + // 132 Column Mode + DECCOLM(bool) error + + // Erase in Display + ED(int) error + + // Erase in Line + EL(int) error + + // Insert Line + IL(int) error + + // Delete Line + DL(int) error + + // Insert Character + ICH(int) error + + // Delete Character + DCH(int) error + + // Set Graphics Rendition + SGR([]int) error + + // Pan Down + SU(int) error + + // Pan Up + SD(int) error + + // Device Attributes + DA([]string) error + + // Set Top and Bottom Margins + DECSTBM(int, int) error + + // Index + IND() error + + // Reverse Index + RI() error + + // Flush updates from previous commands + Flush() error +} diff --git a/vendor/github.com/Azure/go-ansiterm/ground_state.go b/vendor/github.com/Azure/go-ansiterm/ground_state.go new file mode 100644 index 000000000..52451e946 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/ground_state.go @@ -0,0 +1,24 @@ +package ansiterm + +type groundState struct { + baseState +} + +func (gs groundState) Handle(b byte) (s state, e error) { + gs.parser.context.currentChar = b + + nextState, err := gs.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(printables, b): + return gs, gs.parser.print() + + case sliceContains(executors, b): + return gs, gs.parser.execute() + } + + return gs, nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go new file mode 100644 index 000000000..593b10ab6 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go @@ -0,0 +1,31 @@ +package ansiterm + +type oscStringState struct { + baseState +} + +func (oscState oscStringState) Handle(b byte) (s state, e error) { + oscState.parser.logf("OscString::Handle %#x", b) + nextState, err := oscState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case isOscStringTerminator(b): + return oscState.parser.ground, nil + } + + return oscState, nil +} + +// See below for OSC string terminators for linux +// http://man7.org/linux/man-pages/man4/console_codes.4.html +func isOscStringTerminator(b byte) bool { + + if b == ANSI_BEL || b == 0x5C { + return true + } + + return false +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser.go b/vendor/github.com/Azure/go-ansiterm/parser.go new file mode 100644 index 000000000..03cec7ada --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser.go @@ -0,0 +1,151 @@ +package ansiterm + +import ( + "errors" + "log" + "os" +) + +type AnsiParser struct { + currState state + eventHandler AnsiEventHandler + context *ansiContext + csiEntry state + csiParam state + dcsEntry state + escape state + escapeIntermediate state + error state + ground state + oscString state + stateMap []state + + logf func(string, ...interface{}) +} + +type Option func(*AnsiParser) + +func WithLogf(f func(string, ...interface{})) Option { + return func(ap *AnsiParser) { + ap.logf = f + } +} + +func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser { + ap := &AnsiParser{ + eventHandler: evtHandler, + context: &ansiContext{}, + } + for _, o := range opts { + o(ap) + } + + if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" { + logFile, _ := os.Create("ansiParser.log") + logger := log.New(logFile, "", log.LstdFlags) + if ap.logf != nil { + l := ap.logf + ap.logf = func(s string, v ...interface{}) { + l(s, v...) + logger.Printf(s, v...) + } + } else { + ap.logf = logger.Printf + } + } + + if ap.logf == nil { + ap.logf = func(string, ...interface{}) {} + } + + ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}} + ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}} + ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}} + ap.escape = escapeState{baseState{name: "Escape", parser: ap}} + ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}} + ap.error = errorState{baseState{name: "Error", parser: ap}} + ap.ground = groundState{baseState{name: "Ground", parser: ap}} + ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}} + + ap.stateMap = []state{ + ap.csiEntry, + ap.csiParam, + ap.dcsEntry, + ap.escape, + ap.escapeIntermediate, + ap.error, + ap.ground, + ap.oscString, + } + + ap.currState = getState(initialState, ap.stateMap) + + ap.logf("CreateParser: parser %p", ap) + return ap +} + +func getState(name string, states []state) state { + for _, el := range states { + if el.Name() == name { + return el + } + } + + return nil +} + +func (ap *AnsiParser) Parse(bytes []byte) (int, error) { + for i, b := range bytes { + if err := ap.handle(b); err != nil { + return i, err + } + } + + return len(bytes), ap.eventHandler.Flush() +} + +func (ap *AnsiParser) handle(b byte) error { + ap.context.currentChar = b + newState, err := ap.currState.Handle(b) + if err != nil { + return err + } + + if newState == nil { + ap.logf("WARNING: newState is nil") + return errors.New("New state of 'nil' is invalid.") + } + + if newState != ap.currState { + if err := ap.changeState(newState); err != nil { + return err + } + } + + return nil +} + +func (ap *AnsiParser) changeState(newState state) error { + ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name()) + + // Exit old state + if err := ap.currState.Exit(); err != nil { + ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err) + return err + } + + // Perform transition action + if err := ap.currState.Transition(newState); err != nil { + ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err) + return err + } + + // Enter new state + if err := newState.Enter(); err != nil { + ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err) + return err + } + + ap.currState = newState + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go new file mode 100644 index 000000000..de0a1f9cd --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go @@ -0,0 +1,99 @@ +package ansiterm + +import ( + "strconv" +) + +func parseParams(bytes []byte) ([]string, error) { + paramBuff := make([]byte, 0, 0) + params := []string{} + + for _, v := range bytes { + if v == ';' { + if len(paramBuff) > 0 { + // Completed parameter, append it to the list + s := string(paramBuff) + params = append(params, s) + paramBuff = make([]byte, 0, 0) + } + } else { + paramBuff = append(paramBuff, v) + } + } + + // Last parameter may not be terminated with ';' + if len(paramBuff) > 0 { + s := string(paramBuff) + params = append(params, s) + } + + return params, nil +} + +func parseCmd(context ansiContext) (string, error) { + return string(context.currentChar), nil +} + +func getInt(params []string, dflt int) int { + i := getInts(params, 1, dflt)[0] + return i +} + +func getInts(params []string, minCount int, dflt int) []int { + ints := []int{} + + for _, v := range params { + i, _ := strconv.Atoi(v) + // Zero is mapped to the default value in VT100. + if i == 0 { + i = dflt + } + ints = append(ints, i) + } + + if len(ints) < minCount { + remaining := minCount - len(ints) + for i := 0; i < remaining; i++ { + ints = append(ints, dflt) + } + } + + return ints +} + +func (ap *AnsiParser) modeDispatch(param string, set bool) error { + switch param { + case "?3": + return ap.eventHandler.DECCOLM(set) + case "?6": + return ap.eventHandler.DECOM(set) + case "?25": + return ap.eventHandler.DECTCEM(set) + } + return nil +} + +func (ap *AnsiParser) hDispatch(params []string) error { + if len(params) == 1 { + return ap.modeDispatch(params[0], true) + } + + return nil +} + +func (ap *AnsiParser) lDispatch(params []string) error { + if len(params) == 1 { + return ap.modeDispatch(params[0], false) + } + + return nil +} + +func getEraseParam(params []string) int { + param := getInt(params, 0) + if param < 0 || 3 < param { + param = 0 + } + + return param +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_actions.go b/vendor/github.com/Azure/go-ansiterm/parser_actions.go new file mode 100644 index 000000000..0bb5e51e9 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser_actions.go @@ -0,0 +1,119 @@ +package ansiterm + +func (ap *AnsiParser) collectParam() error { + currChar := ap.context.currentChar + ap.logf("collectParam %#x", currChar) + ap.context.paramBuffer = append(ap.context.paramBuffer, currChar) + return nil +} + +func (ap *AnsiParser) collectInter() error { + currChar := ap.context.currentChar + ap.logf("collectInter %#x", currChar) + ap.context.paramBuffer = append(ap.context.interBuffer, currChar) + return nil +} + +func (ap *AnsiParser) escDispatch() error { + cmd, _ := parseCmd(*ap.context) + intermeds := ap.context.interBuffer + ap.logf("escDispatch currentChar: %#x", ap.context.currentChar) + ap.logf("escDispatch: %v(%v)", cmd, intermeds) + + switch cmd { + case "D": // IND + return ap.eventHandler.IND() + case "E": // NEL, equivalent to CRLF + err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN) + if err == nil { + err = ap.eventHandler.Execute(ANSI_LINE_FEED) + } + return err + case "M": // RI + return ap.eventHandler.RI() + } + + return nil +} + +func (ap *AnsiParser) csiDispatch() error { + cmd, _ := parseCmd(*ap.context) + params, _ := parseParams(ap.context.paramBuffer) + ap.logf("Parsed params: %v with length: %d", params, len(params)) + + ap.logf("csiDispatch: %v(%v)", cmd, params) + + switch cmd { + case "@": + return ap.eventHandler.ICH(getInt(params, 1)) + case "A": + return ap.eventHandler.CUU(getInt(params, 1)) + case "B": + return ap.eventHandler.CUD(getInt(params, 1)) + case "C": + return ap.eventHandler.CUF(getInt(params, 1)) + case "D": + return ap.eventHandler.CUB(getInt(params, 1)) + case "E": + return ap.eventHandler.CNL(getInt(params, 1)) + case "F": + return ap.eventHandler.CPL(getInt(params, 1)) + case "G": + return ap.eventHandler.CHA(getInt(params, 1)) + case "H": + ints := getInts(params, 2, 1) + x, y := ints[0], ints[1] + return ap.eventHandler.CUP(x, y) + case "J": + param := getEraseParam(params) + return ap.eventHandler.ED(param) + case "K": + param := getEraseParam(params) + return ap.eventHandler.EL(param) + case "L": + return ap.eventHandler.IL(getInt(params, 1)) + case "M": + return ap.eventHandler.DL(getInt(params, 1)) + case "P": + return ap.eventHandler.DCH(getInt(params, 1)) + case "S": + return ap.eventHandler.SU(getInt(params, 1)) + case "T": + return ap.eventHandler.SD(getInt(params, 1)) + case "c": + return ap.eventHandler.DA(params) + case "d": + return ap.eventHandler.VPA(getInt(params, 1)) + case "f": + ints := getInts(params, 2, 1) + x, y := ints[0], ints[1] + return ap.eventHandler.HVP(x, y) + case "h": + return ap.hDispatch(params) + case "l": + return ap.lDispatch(params) + case "m": + return ap.eventHandler.SGR(getInts(params, 1, 0)) + case "r": + ints := getInts(params, 2, 1) + top, bottom := ints[0], ints[1] + return ap.eventHandler.DECSTBM(top, bottom) + default: + ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context) + return nil + } + +} + +func (ap *AnsiParser) print() error { + return ap.eventHandler.Print(ap.context.currentChar) +} + +func (ap *AnsiParser) clear() error { + ap.context = &ansiContext{} + return nil +} + +func (ap *AnsiParser) execute() error { + return ap.eventHandler.Execute(ap.context.currentChar) +} diff --git a/vendor/github.com/Azure/go-ansiterm/states.go b/vendor/github.com/Azure/go-ansiterm/states.go new file mode 100644 index 000000000..f2ea1fcd1 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/states.go @@ -0,0 +1,71 @@ +package ansiterm + +type stateID int + +type state interface { + Enter() error + Exit() error + Handle(byte) (state, error) + Name() string + Transition(state) error +} + +type baseState struct { + name string + parser *AnsiParser +} + +func (base baseState) Enter() error { + return nil +} + +func (base baseState) Exit() error { + return nil +} + +func (base baseState) Handle(b byte) (s state, e error) { + + switch { + case b == CSI_ENTRY: + return base.parser.csiEntry, nil + case b == DCS_ENTRY: + return base.parser.dcsEntry, nil + case b == ANSI_ESCAPE_PRIMARY: + return base.parser.escape, nil + case b == OSC_STRING: + return base.parser.oscString, nil + case sliceContains(toGroundBytes, b): + return base.parser.ground, nil + } + + return nil, nil +} + +func (base baseState) Name() string { + return base.name +} + +func (base baseState) Transition(s state) error { + if s == base.parser.ground { + execBytes := []byte{0x18} + execBytes = append(execBytes, 0x1A) + execBytes = append(execBytes, getByteRange(0x80, 0x8F)...) + execBytes = append(execBytes, getByteRange(0x91, 0x97)...) + execBytes = append(execBytes, 0x99) + execBytes = append(execBytes, 0x9A) + + if sliceContains(execBytes, base.parser.context.currentChar) { + return base.parser.execute() + } + } + + return nil +} + +type dcsEntryState struct { + baseState +} + +type errorState struct { + baseState +} diff --git a/vendor/github.com/Azure/go-ansiterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/utilities.go new file mode 100644 index 000000000..392114493 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/utilities.go @@ -0,0 +1,21 @@ +package ansiterm + +import ( + "strconv" +) + +func sliceContains(bytes []byte, b byte) bool { + for _, v := range bytes { + if v == b { + return true + } + } + + return false +} + +func convertBytesToInteger(bytes []byte) int { + s := string(bytes) + i, _ := strconv.Atoi(s) + return i +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go new file mode 100644 index 000000000..a67327972 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go @@ -0,0 +1,182 @@ +// +build windows + +package winterm + +import ( + "fmt" + "os" + "strconv" + "strings" + "syscall" + + "github.com/Azure/go-ansiterm" +) + +// Windows keyboard constants +// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx. +const ( + VK_PRIOR = 0x21 // PAGE UP key + VK_NEXT = 0x22 // PAGE DOWN key + VK_END = 0x23 // END key + VK_HOME = 0x24 // HOME key + VK_LEFT = 0x25 // LEFT ARROW key + VK_UP = 0x26 // UP ARROW key + VK_RIGHT = 0x27 // RIGHT ARROW key + VK_DOWN = 0x28 // DOWN ARROW key + VK_SELECT = 0x29 // SELECT key + VK_PRINT = 0x2A // PRINT key + VK_EXECUTE = 0x2B // EXECUTE key + VK_SNAPSHOT = 0x2C // PRINT SCREEN key + VK_INSERT = 0x2D // INS key + VK_DELETE = 0x2E // DEL key + VK_HELP = 0x2F // HELP key + VK_F1 = 0x70 // F1 key + VK_F2 = 0x71 // F2 key + VK_F3 = 0x72 // F3 key + VK_F4 = 0x73 // F4 key + VK_F5 = 0x74 // F5 key + VK_F6 = 0x75 // F6 key + VK_F7 = 0x76 // F7 key + VK_F8 = 0x77 // F8 key + VK_F9 = 0x78 // F9 key + VK_F10 = 0x79 // F10 key + VK_F11 = 0x7A // F11 key + VK_F12 = 0x7B // F12 key + + RIGHT_ALT_PRESSED = 0x0001 + LEFT_ALT_PRESSED = 0x0002 + RIGHT_CTRL_PRESSED = 0x0004 + LEFT_CTRL_PRESSED = 0x0008 + SHIFT_PRESSED = 0x0010 + NUMLOCK_ON = 0x0020 + SCROLLLOCK_ON = 0x0040 + CAPSLOCK_ON = 0x0080 + ENHANCED_KEY = 0x0100 +) + +type ansiCommand struct { + CommandBytes []byte + Command string + Parameters []string + IsSpecial bool +} + +func newAnsiCommand(command []byte) *ansiCommand { + + if isCharacterSelectionCmdChar(command[1]) { + // Is Character Set Selection commands + return &ansiCommand{ + CommandBytes: command, + Command: string(command), + IsSpecial: true, + } + } + + // last char is command character + lastCharIndex := len(command) - 1 + + ac := &ansiCommand{ + CommandBytes: command, + Command: string(command[lastCharIndex]), + IsSpecial: false, + } + + // more than a single escape + if lastCharIndex != 0 { + start := 1 + // skip if double char escape sequence + if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY { + start++ + } + // convert this to GetNextParam method + ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP) + } + + return ac +} + +func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 { + if index < 0 || index >= len(ac.Parameters) { + return defaultValue + } + + param, err := strconv.ParseInt(ac.Parameters[index], 10, 16) + if err != nil { + return defaultValue + } + + return int16(param) +} + +func (ac *ansiCommand) String() string { + return fmt.Sprintf("0x%v \"%v\" (\"%v\")", + bytesToHex(ac.CommandBytes), + ac.Command, + strings.Join(ac.Parameters, "\",\"")) +} + +// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands. +// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html. +func isAnsiCommandChar(b byte) bool { + switch { + case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY: + return true + case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM: + // non-CSI escape sequence terminator + return true + case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL: + // String escape sequence terminator + return true + } + return false +} + +func isXtermOscSequence(command []byte, current byte) bool { + return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL) +} + +func isCharacterSelectionCmdChar(b byte) bool { + return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3) +} + +// bytesToHex converts a slice of bytes to a human-readable string. +func bytesToHex(b []byte) string { + hex := make([]string, len(b)) + for i, ch := range b { + hex[i] = fmt.Sprintf("%X", ch) + } + return strings.Join(hex, "") +} + +// ensureInRange adjusts the passed value, if necessary, to ensure it is within +// the passed min / max range. +func ensureInRange(n int16, min int16, max int16) int16 { + if n < min { + return min + } else if n > max { + return max + } else { + return n + } +} + +func GetStdFile(nFile int) (*os.File, uintptr) { + var file *os.File + switch nFile { + case syscall.STD_INPUT_HANDLE: + file = os.Stdin + case syscall.STD_OUTPUT_HANDLE: + file = os.Stdout + case syscall.STD_ERROR_HANDLE: + file = os.Stderr + default: + panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile)) + } + + fd, err := syscall.GetStdHandle(nFile) + if err != nil { + panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err)) + } + + return file, uintptr(fd) +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/api.go b/vendor/github.com/Azure/go-ansiterm/winterm/api.go new file mode 100644 index 000000000..6055e33b9 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/api.go @@ -0,0 +1,327 @@ +// +build windows + +package winterm + +import ( + "fmt" + "syscall" + "unsafe" +) + +//=========================================================================================================== +// IMPORTANT NOTE: +// +// The methods below make extensive use of the "unsafe" package to obtain the required pointers. +// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack +// variables) the pointers reference *before* the API completes. +// +// As a result, in those cases, the code must hint that the variables remain in active by invoking the +// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer +// require unsafe pointers. +// +// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform +// the garbage collector the variables remain in use if: +// +// -- The value is not a pointer (e.g., int32, struct) +// -- The value is not referenced by the method after passing the pointer to Windows +// +// See http://golang.org/doc/go1.3. +//=========================================================================================================== + +var ( + kernel32DLL = syscall.NewLazyDLL("kernel32.dll") + + getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo") + setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo") + setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition") + setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode") + getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo") + setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize") + scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA") + setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute") + setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo") + writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW") + readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW") + waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject") +) + +// Windows Console constants +const ( + // Console modes + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx. + ENABLE_PROCESSED_INPUT = 0x0001 + ENABLE_LINE_INPUT = 0x0002 + ENABLE_ECHO_INPUT = 0x0004 + ENABLE_WINDOW_INPUT = 0x0008 + ENABLE_MOUSE_INPUT = 0x0010 + ENABLE_INSERT_MODE = 0x0020 + ENABLE_QUICK_EDIT_MODE = 0x0040 + ENABLE_EXTENDED_FLAGS = 0x0080 + ENABLE_AUTO_POSITION = 0x0100 + ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200 + + ENABLE_PROCESSED_OUTPUT = 0x0001 + ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002 + ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 + DISABLE_NEWLINE_AUTO_RETURN = 0x0008 + ENABLE_LVB_GRID_WORLDWIDE = 0x0010 + + // Character attributes + // Note: + // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan). + // Clearing all foreground or background colors results in black; setting all creates white. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes. + FOREGROUND_BLUE uint16 = 0x0001 + FOREGROUND_GREEN uint16 = 0x0002 + FOREGROUND_RED uint16 = 0x0004 + FOREGROUND_INTENSITY uint16 = 0x0008 + FOREGROUND_MASK uint16 = 0x000F + + BACKGROUND_BLUE uint16 = 0x0010 + BACKGROUND_GREEN uint16 = 0x0020 + BACKGROUND_RED uint16 = 0x0040 + BACKGROUND_INTENSITY uint16 = 0x0080 + BACKGROUND_MASK uint16 = 0x00F0 + + COMMON_LVB_MASK uint16 = 0xFF00 + COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000 + COMMON_LVB_UNDERSCORE uint16 = 0x8000 + + // Input event types + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. + KEY_EVENT = 0x0001 + MOUSE_EVENT = 0x0002 + WINDOW_BUFFER_SIZE_EVENT = 0x0004 + MENU_EVENT = 0x0008 + FOCUS_EVENT = 0x0010 + + // WaitForSingleObject return codes + WAIT_ABANDONED = 0x00000080 + WAIT_FAILED = 0xFFFFFFFF + WAIT_SIGNALED = 0x0000000 + WAIT_TIMEOUT = 0x00000102 + + // WaitForSingleObject wait duration + WAIT_INFINITE = 0xFFFFFFFF + WAIT_ONE_SECOND = 1000 + WAIT_HALF_SECOND = 500 + WAIT_QUARTER_SECOND = 250 +) + +// Windows API Console types +// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD) +// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment +type ( + CHAR_INFO struct { + UnicodeChar uint16 + Attributes uint16 + } + + CONSOLE_CURSOR_INFO struct { + Size uint32 + Visible int32 + } + + CONSOLE_SCREEN_BUFFER_INFO struct { + Size COORD + CursorPosition COORD + Attributes uint16 + Window SMALL_RECT + MaximumWindowSize COORD + } + + COORD struct { + X int16 + Y int16 + } + + SMALL_RECT struct { + Left int16 + Top int16 + Right int16 + Bottom int16 + } + + // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. + INPUT_RECORD struct { + EventType uint16 + KeyEvent KEY_EVENT_RECORD + } + + KEY_EVENT_RECORD struct { + KeyDown int32 + RepeatCount uint16 + VirtualKeyCode uint16 + VirtualScanCode uint16 + UnicodeChar uint16 + ControlKeyState uint32 + } + + WINDOW_BUFFER_SIZE struct { + Size COORD + } +) + +// boolToBOOL converts a Go bool into a Windows int32. +func boolToBOOL(f bool) int32 { + if f { + return int32(1) + } else { + return int32(0) + } +} + +// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx. +func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error { + r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0) + return checkError(r1, r2, err) +} + +// SetConsoleCursorInfo sets the size and visiblity of the console cursor. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx. +func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error { + r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0) + return checkError(r1, r2, err) +} + +// SetConsoleCursorPosition location of the console cursor. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx. +func SetConsoleCursorPosition(handle uintptr, coord COORD) error { + r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord)) + use(coord) + return checkError(r1, r2, err) +} + +// GetConsoleMode gets the console mode for given file descriptor +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx. +func GetConsoleMode(handle uintptr) (mode uint32, err error) { + err = syscall.GetConsoleMode(syscall.Handle(handle), &mode) + return mode, err +} + +// SetConsoleMode sets the console mode for given file descriptor +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx. +func SetConsoleMode(handle uintptr, mode uint32) error { + r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0) + use(mode) + return checkError(r1, r2, err) +} + +// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer. +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx. +func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) { + info := CONSOLE_SCREEN_BUFFER_INFO{} + err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)) + if err != nil { + return nil, err + } + return &info, nil +} + +func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error { + r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char))) + use(scrollRect) + use(clipRect) + use(destOrigin) + use(char) + return checkError(r1, r2, err) +} + +// SetConsoleScreenBufferSize sets the size of the console screen buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx. +func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error { + r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord)) + use(coord) + return checkError(r1, r2, err) +} + +// SetConsoleTextAttribute sets the attributes of characters written to the +// console screen buffer by the WriteFile or WriteConsole function. +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx. +func SetConsoleTextAttribute(handle uintptr, attribute uint16) error { + r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0) + use(attribute) + return checkError(r1, r2, err) +} + +// SetConsoleWindowInfo sets the size and position of the console screen buffer's window. +// Note that the size and location must be within and no larger than the backing console screen buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx. +func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error { + r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect))) + use(isAbsolute) + use(rect) + return checkError(r1, r2, err) +} + +// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx. +func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error { + r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion))) + use(buffer) + use(bufferSize) + use(bufferCoord) + return checkError(r1, r2, err) +} + +// ReadConsoleInput reads (and removes) data from the console input buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx. +func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error { + r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count))) + use(buffer) + return checkError(r1, r2, err) +} + +// WaitForSingleObject waits for the passed handle to be signaled. +// It returns true if the handle was signaled; false otherwise. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx. +func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) { + r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait))) + switch r1 { + case WAIT_ABANDONED, WAIT_TIMEOUT: + return false, nil + case WAIT_SIGNALED: + return true, nil + } + use(msWait) + return false, err +} + +// String helpers +func (info CONSOLE_SCREEN_BUFFER_INFO) String() string { + return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize) +} + +func (coord COORD) String() string { + return fmt.Sprintf("%v,%v", coord.X, coord.Y) +} + +func (rect SMALL_RECT) String() string { + return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom) +} + +// checkError evaluates the results of a Windows API call and returns the error if it failed. +func checkError(r1, r2 uintptr, err error) error { + // Windows APIs return non-zero to indicate success + if r1 != 0 { + return nil + } + + // Return the error if provided, otherwise default to EINVAL + if err != nil { + return err + } + return syscall.EINVAL +} + +// coordToPointer converts a COORD into a uintptr (by fooling the type system). +func coordToPointer(c COORD) uintptr { + // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass. + return uintptr(*((*uint32)(unsafe.Pointer(&c)))) +} + +// use is a no-op, but the compiler cannot see that it is. +// Calling use(p) ensures that p is kept live until that point. +func use(p interface{}) {} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go new file mode 100644 index 000000000..cbec8f728 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go @@ -0,0 +1,100 @@ +// +build windows + +package winterm + +import "github.com/Azure/go-ansiterm" + +const ( + FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE + BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE +) + +// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the +// request represented by the passed ANSI mode. +func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) { + switch ansiMode { + + // Mode styles + case ansiterm.ANSI_SGR_BOLD: + windowsMode = windowsMode | FOREGROUND_INTENSITY + + case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF: + windowsMode &^= FOREGROUND_INTENSITY + + case ansiterm.ANSI_SGR_UNDERLINE: + windowsMode = windowsMode | COMMON_LVB_UNDERSCORE + + case ansiterm.ANSI_SGR_REVERSE: + inverted = true + + case ansiterm.ANSI_SGR_REVERSE_OFF: + inverted = false + + case ansiterm.ANSI_SGR_UNDERLINE_OFF: + windowsMode &^= COMMON_LVB_UNDERSCORE + + // Foreground colors + case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT: + windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK) + + case ansiterm.ANSI_SGR_FOREGROUND_BLACK: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) + + case ansiterm.ANSI_SGR_FOREGROUND_RED: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED + + case ansiterm.ANSI_SGR_FOREGROUND_GREEN: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN + + case ansiterm.ANSI_SGR_FOREGROUND_YELLOW: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN + + case ansiterm.ANSI_SGR_FOREGROUND_BLUE: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE + + case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE + + case ansiterm.ANSI_SGR_FOREGROUND_CYAN: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE + + case ansiterm.ANSI_SGR_FOREGROUND_WHITE: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE + + // Background colors + case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT: + // Black with no intensity + windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK) + + case ansiterm.ANSI_SGR_BACKGROUND_BLACK: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) + + case ansiterm.ANSI_SGR_BACKGROUND_RED: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED + + case ansiterm.ANSI_SGR_BACKGROUND_GREEN: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN + + case ansiterm.ANSI_SGR_BACKGROUND_YELLOW: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN + + case ansiterm.ANSI_SGR_BACKGROUND_BLUE: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE + + case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE + + case ansiterm.ANSI_SGR_BACKGROUND_CYAN: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE + + case ansiterm.ANSI_SGR_BACKGROUND_WHITE: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE + } + + return windowsMode, inverted +} + +// invertAttributes inverts the foreground and background colors of a Windows attributes value +func invertAttributes(windowsMode uint16) uint16 { + return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4) +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go new file mode 100644 index 000000000..3ee06ea72 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go @@ -0,0 +1,101 @@ +// +build windows + +package winterm + +const ( + horizontal = iota + vertical +) + +func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT { + if h.originMode { + sr := h.effectiveSr(info.Window) + return SMALL_RECT{ + Top: sr.top, + Bottom: sr.bottom, + Left: 0, + Right: info.Size.X - 1, + } + } else { + return SMALL_RECT{ + Top: info.Window.Top, + Bottom: info.Window.Bottom, + Left: 0, + Right: info.Size.X - 1, + } + } +} + +// setCursorPosition sets the cursor to the specified position, bounded to the screen size +func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error { + position.X = ensureInRange(position.X, window.Left, window.Right) + position.Y = ensureInRange(position.Y, window.Top, window.Bottom) + err := SetConsoleCursorPosition(h.fd, position) + if err != nil { + return err + } + h.logf("Cursor position set: (%d, %d)", position.X, position.Y) + return err +} + +func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error { + return h.moveCursor(vertical, param) +} + +func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error { + return h.moveCursor(horizontal, param) +} + +func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + position := info.CursorPosition + switch moveMode { + case horizontal: + position.X += int16(param) + case vertical: + position.Y += int16(param) + } + + if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) moveCursorLine(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + position := info.CursorPosition + position.X = 0 + position.Y += int16(param) + + if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + position := info.CursorPosition + position.X = int16(param) - 1 + + if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go new file mode 100644 index 000000000..244b5fa25 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go @@ -0,0 +1,84 @@ +// +build windows + +package winterm + +import "github.com/Azure/go-ansiterm" + +func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error { + // Ignore an invalid (negative area) request + if toCoord.Y < fromCoord.Y { + return nil + } + + var err error + + var coordStart = COORD{} + var coordEnd = COORD{} + + xCurrent, yCurrent := fromCoord.X, fromCoord.Y + xEnd, yEnd := toCoord.X, toCoord.Y + + // Clear any partial initial line + if xCurrent > 0 { + coordStart.X, coordStart.Y = xCurrent, yCurrent + coordEnd.X, coordEnd.Y = xEnd, yCurrent + + err = h.clearRect(attributes, coordStart, coordEnd) + if err != nil { + return err + } + + xCurrent = 0 + yCurrent += 1 + } + + // Clear intervening rectangular section + if yCurrent < yEnd { + coordStart.X, coordStart.Y = xCurrent, yCurrent + coordEnd.X, coordEnd.Y = xEnd, yEnd-1 + + err = h.clearRect(attributes, coordStart, coordEnd) + if err != nil { + return err + } + + xCurrent = 0 + yCurrent = yEnd + } + + // Clear remaining partial ending line + coordStart.X, coordStart.Y = xCurrent, yCurrent + coordEnd.X, coordEnd.Y = xEnd, yEnd + + err = h.clearRect(attributes, coordStart, coordEnd) + if err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error { + region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X} + width := toCoord.X - fromCoord.X + 1 + height := toCoord.Y - fromCoord.Y + 1 + size := uint32(width) * uint32(height) + + if size <= 0 { + return nil + } + + buffer := make([]CHAR_INFO, size) + + char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes} + for i := 0; i < int(size); i++ { + buffer[i] = char + } + + err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go new file mode 100644 index 000000000..2d27fa1d0 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go @@ -0,0 +1,118 @@ +// +build windows + +package winterm + +// effectiveSr gets the current effective scroll region in buffer coordinates +func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion { + top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom) + bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom) + if top >= bottom { + top = window.Top + bottom = window.Bottom + } + return scrollRegion{top: top, bottom: bottom} +} + +func (h *windowsAnsiEventHandler) scrollUp(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + sr := h.effectiveSr(info.Window) + return h.scroll(param, sr, info) +} + +func (h *windowsAnsiEventHandler) scrollDown(param int) error { + return h.scrollUp(-param) +} + +func (h *windowsAnsiEventHandler) deleteLines(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + start := info.CursorPosition.Y + sr := h.effectiveSr(info.Window) + // Lines cannot be inserted or deleted outside the scrolling region. + if start >= sr.top && start <= sr.bottom { + sr.top = start + return h.scroll(param, sr, info) + } else { + return nil + } +} + +func (h *windowsAnsiEventHandler) insertLines(param int) error { + return h.deleteLines(-param) +} + +// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates. +func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error { + h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom) + h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom) + + // Copy from and clip to the scroll region (full buffer width) + scrollRect := SMALL_RECT{ + Top: sr.top, + Bottom: sr.bottom, + Left: 0, + Right: info.Size.X - 1, + } + + // Origin to which area should be copied + destOrigin := COORD{ + X: 0, + Y: sr.top - int16(param), + } + + char := CHAR_INFO{ + UnicodeChar: ' ', + Attributes: h.attributes, + } + + if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil { + return err + } + return nil +} + +func (h *windowsAnsiEventHandler) deleteCharacters(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + return h.scrollLine(param, info.CursorPosition, info) +} + +func (h *windowsAnsiEventHandler) insertCharacters(param int) error { + return h.deleteCharacters(-param) +} + +// scrollLine scrolls a line horizontally starting at the provided position by a number of columns. +func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error { + // Copy from and clip to the scroll region (full buffer width) + scrollRect := SMALL_RECT{ + Top: position.Y, + Bottom: position.Y, + Left: position.X, + Right: info.Size.X - 1, + } + + // Origin to which area should be copied + destOrigin := COORD{ + X: position.X - int16(columns), + Y: position.Y, + } + + char := CHAR_INFO{ + UnicodeChar: ' ', + Attributes: h.attributes, + } + + if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go new file mode 100644 index 000000000..afa7635d7 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go @@ -0,0 +1,9 @@ +// +build windows + +package winterm + +// AddInRange increments a value by the passed quantity while ensuring the values +// always remain within the supplied min / max range. +func addInRange(n int16, increment int16, min int16, max int16) int16 { + return ensureInRange(n+increment, min, max) +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go new file mode 100644 index 000000000..2d40fb75a --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go @@ -0,0 +1,743 @@ +// +build windows + +package winterm + +import ( + "bytes" + "log" + "os" + "strconv" + + "github.com/Azure/go-ansiterm" +) + +type windowsAnsiEventHandler struct { + fd uintptr + file *os.File + infoReset *CONSOLE_SCREEN_BUFFER_INFO + sr scrollRegion + buffer bytes.Buffer + attributes uint16 + inverted bool + wrapNext bool + drewMarginByte bool + originMode bool + marginByte byte + curInfo *CONSOLE_SCREEN_BUFFER_INFO + curPos COORD + logf func(string, ...interface{}) +} + +type Option func(*windowsAnsiEventHandler) + +func WithLogf(f func(string, ...interface{})) Option { + return func(w *windowsAnsiEventHandler) { + w.logf = f + } +} + +func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler { + infoReset, err := GetConsoleScreenBufferInfo(fd) + if err != nil { + return nil + } + + h := &windowsAnsiEventHandler{ + fd: fd, + file: file, + infoReset: infoReset, + attributes: infoReset.Attributes, + } + for _, o := range opts { + o(h) + } + + if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" { + logFile, _ := os.Create("winEventHandler.log") + logger := log.New(logFile, "", log.LstdFlags) + if h.logf != nil { + l := h.logf + h.logf = func(s string, v ...interface{}) { + l(s, v...) + logger.Printf(s, v...) + } + } else { + h.logf = logger.Printf + } + } + + if h.logf == nil { + h.logf = func(string, ...interface{}) {} + } + + return h +} + +type scrollRegion struct { + top int16 + bottom int16 +} + +// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the +// current cursor position and scroll region settings, in which case it returns +// true. If no special handling is necessary, then it does nothing and returns +// false. +// +// In the false case, the caller should ensure that a carriage return +// and line feed are inserted or that the text is otherwise wrapped. +func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) { + if h.wrapNext { + if err := h.Flush(); err != nil { + return false, err + } + h.clearWrap() + } + pos, info, err := h.getCurrentInfo() + if err != nil { + return false, err + } + sr := h.effectiveSr(info.Window) + if pos.Y == sr.bottom { + // Scrolling is necessary. Let Windows automatically scroll if the scrolling region + // is the full window. + if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom { + if includeCR { + pos.X = 0 + h.updatePos(pos) + } + return false, nil + } + + // A custom scroll region is active. Scroll the window manually to simulate + // the LF. + if err := h.Flush(); err != nil { + return false, err + } + h.logf("Simulating LF inside scroll region") + if err := h.scrollUp(1); err != nil { + return false, err + } + if includeCR { + pos.X = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return false, err + } + } + return true, nil + + } else if pos.Y < info.Window.Bottom { + // Let Windows handle the LF. + pos.Y++ + if includeCR { + pos.X = 0 + } + h.updatePos(pos) + return false, nil + } else { + // The cursor is at the bottom of the screen but outside the scroll + // region. Skip the LF. + h.logf("Simulating LF outside scroll region") + if includeCR { + if err := h.Flush(); err != nil { + return false, err + } + pos.X = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return false, err + } + } + return true, nil + } +} + +// executeLF executes a LF without a CR. +func (h *windowsAnsiEventHandler) executeLF() error { + handled, err := h.simulateLF(false) + if err != nil { + return err + } + if !handled { + // Windows LF will reset the cursor column position. Write the LF + // and restore the cursor position. + pos, _, err := h.getCurrentInfo() + if err != nil { + return err + } + h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) + if pos.X != 0 { + if err := h.Flush(); err != nil { + return err + } + h.logf("Resetting cursor position for LF without CR") + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return err + } + } + } + return nil +} + +func (h *windowsAnsiEventHandler) Print(b byte) error { + if h.wrapNext { + h.buffer.WriteByte(h.marginByte) + h.clearWrap() + if _, err := h.simulateLF(true); err != nil { + return err + } + } + pos, info, err := h.getCurrentInfo() + if err != nil { + return err + } + if pos.X == info.Size.X-1 { + h.wrapNext = true + h.marginByte = b + } else { + pos.X++ + h.updatePos(pos) + h.buffer.WriteByte(b) + } + return nil +} + +func (h *windowsAnsiEventHandler) Execute(b byte) error { + switch b { + case ansiterm.ANSI_TAB: + h.logf("Execute(TAB)") + // Move to the next tab stop, but preserve auto-wrap if already set. + if !h.wrapNext { + pos, info, err := h.getCurrentInfo() + if err != nil { + return err + } + pos.X = (pos.X + 8) - pos.X%8 + if pos.X >= info.Size.X { + pos.X = info.Size.X - 1 + } + if err := h.Flush(); err != nil { + return err + } + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return err + } + } + return nil + + case ansiterm.ANSI_BEL: + h.buffer.WriteByte(ansiterm.ANSI_BEL) + return nil + + case ansiterm.ANSI_BACKSPACE: + if h.wrapNext { + if err := h.Flush(); err != nil { + return err + } + h.clearWrap() + } + pos, _, err := h.getCurrentInfo() + if err != nil { + return err + } + if pos.X > 0 { + pos.X-- + h.updatePos(pos) + h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE) + } + return nil + + case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED: + // Treat as true LF. + return h.executeLF() + + case ansiterm.ANSI_LINE_FEED: + // Simulate a CR and LF for now since there is no way in go-ansiterm + // to tell if the LF should include CR (and more things break when it's + // missing than when it's incorrectly added). + handled, err := h.simulateLF(true) + if handled || err != nil { + return err + } + return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) + + case ansiterm.ANSI_CARRIAGE_RETURN: + if h.wrapNext { + if err := h.Flush(); err != nil { + return err + } + h.clearWrap() + } + pos, _, err := h.getCurrentInfo() + if err != nil { + return err + } + if pos.X != 0 { + pos.X = 0 + h.updatePos(pos) + h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN) + } + return nil + + default: + return nil + } +} + +func (h *windowsAnsiEventHandler) CUU(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUU: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorVertical(-param) +} + +func (h *windowsAnsiEventHandler) CUD(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUD: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorVertical(param) +} + +func (h *windowsAnsiEventHandler) CUF(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUF: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorHorizontal(param) +} + +func (h *windowsAnsiEventHandler) CUB(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUB: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorHorizontal(-param) +} + +func (h *windowsAnsiEventHandler) CNL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CNL: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorLine(param) +} + +func (h *windowsAnsiEventHandler) CPL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CPL: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorLine(-param) +} + +func (h *windowsAnsiEventHandler) CHA(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CHA: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorColumn(param) +} + +func (h *windowsAnsiEventHandler) VPA(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("VPA: [[%d]]", param) + h.clearWrap() + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + window := h.getCursorWindow(info) + position := info.CursorPosition + position.Y = window.Top + int16(param) - 1 + return h.setCursorPosition(position, window) +} + +func (h *windowsAnsiEventHandler) CUP(row int, col int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUP: [[%d %d]]", row, col) + h.clearWrap() + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + window := h.getCursorWindow(info) + position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1} + return h.setCursorPosition(position, window) +} + +func (h *windowsAnsiEventHandler) HVP(row int, col int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("HVP: [[%d %d]]", row, col) + h.clearWrap() + return h.CUP(row, col) +} + +func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)}) + h.clearWrap() + return nil +} + +func (h *windowsAnsiEventHandler) DECOM(enable bool) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)}) + h.clearWrap() + h.originMode = enable + return h.CUP(1, 1) +} + +func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)}) + h.clearWrap() + if err := h.ED(2); err != nil { + return err + } + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + targetWidth := int16(80) + if use132 { + targetWidth = 132 + } + if info.Size.X < targetWidth { + if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil { + h.logf("set buffer failed: %v", err) + return err + } + } + window := info.Window + window.Left = 0 + window.Right = targetWidth - 1 + if err := SetConsoleWindowInfo(h.fd, true, window); err != nil { + h.logf("set window failed: %v", err) + return err + } + if info.Size.X > targetWidth { + if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil { + h.logf("set buffer failed: %v", err) + return err + } + } + return SetConsoleCursorPosition(h.fd, COORD{0, 0}) +} + +func (h *windowsAnsiEventHandler) ED(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("ED: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + + // [J -- Erases from the cursor to the end of the screen, including the cursor position. + // [1J -- Erases from the beginning of the screen to the cursor, including the cursor position. + // [2J -- Erases the complete display. The cursor does not move. + // Notes: + // -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + var start COORD + var end COORD + + switch param { + case 0: + start = info.CursorPosition + end = COORD{info.Size.X - 1, info.Size.Y - 1} + + case 1: + start = COORD{0, 0} + end = info.CursorPosition + + case 2: + start = COORD{0, 0} + end = COORD{info.Size.X - 1, info.Size.Y - 1} + } + + err = h.clearRange(h.attributes, start, end) + if err != nil { + return err + } + + // If the whole buffer was cleared, move the window to the top while preserving + // the window-relative cursor position. + if param == 2 { + pos := info.CursorPosition + window := info.Window + pos.Y -= window.Top + window.Bottom -= window.Top + window.Top = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return err + } + if err := SetConsoleWindowInfo(h.fd, true, window); err != nil { + return err + } + } + + return nil +} + +func (h *windowsAnsiEventHandler) EL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("EL: [%v]", strconv.Itoa(param)) + h.clearWrap() + + // [K -- Erases from the cursor to the end of the line, including the cursor position. + // [1K -- Erases from the beginning of the line to the cursor, including the cursor position. + // [2K -- Erases the complete line. + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + var start COORD + var end COORD + + switch param { + case 0: + start = info.CursorPosition + end = COORD{info.Size.X, info.CursorPosition.Y} + + case 1: + start = COORD{0, info.CursorPosition.Y} + end = info.CursorPosition + + case 2: + start = COORD{0, info.CursorPosition.Y} + end = COORD{info.Size.X, info.CursorPosition.Y} + } + + err = h.clearRange(h.attributes, start, end) + if err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) IL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("IL: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.insertLines(param) +} + +func (h *windowsAnsiEventHandler) DL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DL: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.deleteLines(param) +} + +func (h *windowsAnsiEventHandler) ICH(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("ICH: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.insertCharacters(param) +} + +func (h *windowsAnsiEventHandler) DCH(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DCH: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.deleteCharacters(param) +} + +func (h *windowsAnsiEventHandler) SGR(params []int) error { + if err := h.Flush(); err != nil { + return err + } + strings := []string{} + for _, v := range params { + strings = append(strings, strconv.Itoa(v)) + } + + h.logf("SGR: [%v]", strings) + + if len(params) <= 0 { + h.attributes = h.infoReset.Attributes + h.inverted = false + } else { + for _, attr := range params { + + if attr == ansiterm.ANSI_SGR_RESET { + h.attributes = h.infoReset.Attributes + h.inverted = false + continue + } + + h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr)) + } + } + + attributes := h.attributes + if h.inverted { + attributes = invertAttributes(attributes) + } + err := SetConsoleTextAttribute(h.fd, attributes) + if err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) SU(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("SU: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.scrollUp(param) +} + +func (h *windowsAnsiEventHandler) SD(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("SD: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.scrollDown(param) +} + +func (h *windowsAnsiEventHandler) DA(params []string) error { + h.logf("DA: [%v]", params) + // DA cannot be implemented because it must send data on the VT100 input stream, + // which is not available to go-ansiterm. + return nil +} + +func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECSTBM: [%d, %d]", top, bottom) + + // Windows is 0 indexed, Linux is 1 indexed + h.sr.top = int16(top - 1) + h.sr.bottom = int16(bottom - 1) + + // This command also moves the cursor to the origin. + h.clearWrap() + return h.CUP(1, 1) +} + +func (h *windowsAnsiEventHandler) RI() error { + if err := h.Flush(); err != nil { + return err + } + h.logf("RI: []") + h.clearWrap() + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + sr := h.effectiveSr(info.Window) + if info.CursorPosition.Y == sr.top { + return h.scrollDown(1) + } + + return h.moveCursorVertical(-1) +} + +func (h *windowsAnsiEventHandler) IND() error { + h.logf("IND: []") + return h.executeLF() +} + +func (h *windowsAnsiEventHandler) Flush() error { + h.curInfo = nil + if h.buffer.Len() > 0 { + h.logf("Flush: [%s]", h.buffer.Bytes()) + if _, err := h.buffer.WriteTo(h.file); err != nil { + return err + } + } + + if h.wrapNext && !h.drewMarginByte { + h.logf("Flush: drawing margin byte '%c'", h.marginByte) + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}} + size := COORD{1, 1} + position := COORD{0, 0} + region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y} + if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil { + return err + } + h.drewMarginByte = true + } + return nil +} + +// cacheConsoleInfo ensures that the current console screen information has been queried +// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos. +func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) { + if h.curInfo == nil { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return COORD{}, nil, err + } + h.curInfo = info + h.curPos = info.CursorPosition + } + return h.curPos, h.curInfo, nil +} + +func (h *windowsAnsiEventHandler) updatePos(pos COORD) { + if h.curInfo == nil { + panic("failed to call getCurrentInfo before calling updatePos") + } + h.curPos = pos +} + +// clearWrap clears the state where the cursor is in the margin +// waiting for the next character before wrapping the line. This must +// be done before most operations that act on the cursor. +func (h *windowsAnsiEventHandler) clearWrap() { + h.wrapNext = false + h.drewMarginByte = false +} diff --git a/vendor/github.com/Microsoft/go-winio/.gitignore b/vendor/github.com/Microsoft/go-winio/.gitignore new file mode 100644 index 000000000..b883f1fdc --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/.gitignore @@ -0,0 +1 @@ +*.exe diff --git a/vendor/github.com/Microsoft/go-winio/LICENSE b/vendor/github.com/Microsoft/go-winio/LICENSE new file mode 100644 index 000000000..b8b569d77 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/Microsoft/go-winio/README.md b/vendor/github.com/Microsoft/go-winio/README.md new file mode 100644 index 000000000..568001057 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/README.md @@ -0,0 +1,22 @@ +# go-winio + +This repository contains utilities for efficiently performing Win32 IO operations in +Go. Currently, this is focused on accessing named pipes and other file handles, and +for using named pipes as a net transport. + +This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go +to reuse the thread to schedule another goroutine. This limits support to Windows Vista and +newer operating systems. This is similar to the implementation of network sockets in Go's net +package. + +Please see the LICENSE file for licensing information. + +This project has adopted the [Microsoft Open Source Code of +Conduct](https://opensource.microsoft.com/codeofconduct/). For more information +see the [Code of Conduct +FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact +[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional +questions or comments. + +Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe +for another named pipe implementation. diff --git a/vendor/github.com/Microsoft/go-winio/archive/tar/LICENSE b/vendor/github.com/Microsoft/go-winio/archive/tar/LICENSE new file mode 100644 index 000000000..744875676 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/archive/tar/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/Microsoft/go-winio/backup.go b/vendor/github.com/Microsoft/go-winio/backup.go new file mode 100644 index 000000000..2be34af43 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/backup.go @@ -0,0 +1,280 @@ +// +build windows + +package winio + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "runtime" + "syscall" + "unicode/utf16" +) + +//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead +//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite + +const ( + BackupData = uint32(iota + 1) + BackupEaData + BackupSecurity + BackupAlternateData + BackupLink + BackupPropertyData + BackupObjectId + BackupReparseData + BackupSparseBlock + BackupTxfsData +) + +const ( + StreamSparseAttributes = uint32(8) +) + +const ( + WRITE_DAC = 0x40000 + WRITE_OWNER = 0x80000 + ACCESS_SYSTEM_SECURITY = 0x1000000 +) + +// BackupHeader represents a backup stream of a file. +type BackupHeader struct { + Id uint32 // The backup stream ID + Attributes uint32 // Stream attributes + Size int64 // The size of the stream in bytes + Name string // The name of the stream (for BackupAlternateData only). + Offset int64 // The offset of the stream in the file (for BackupSparseBlock only). +} + +type win32StreamId struct { + StreamId uint32 + Attributes uint32 + Size uint64 + NameSize uint32 +} + +// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series +// of BackupHeader values. +type BackupStreamReader struct { + r io.Reader + bytesLeft int64 +} + +// NewBackupStreamReader produces a BackupStreamReader from any io.Reader. +func NewBackupStreamReader(r io.Reader) *BackupStreamReader { + return &BackupStreamReader{r, 0} +} + +// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if +// it was not completely read. +func (r *BackupStreamReader) Next() (*BackupHeader, error) { + if r.bytesLeft > 0 { + if s, ok := r.r.(io.Seeker); ok { + // Make sure Seek on io.SeekCurrent sometimes succeeds + // before trying the actual seek. + if _, err := s.Seek(0, io.SeekCurrent); err == nil { + if _, err = s.Seek(r.bytesLeft, io.SeekCurrent); err != nil { + return nil, err + } + r.bytesLeft = 0 + } + } + if _, err := io.Copy(ioutil.Discard, r); err != nil { + return nil, err + } + } + var wsi win32StreamId + if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil { + return nil, err + } + hdr := &BackupHeader{ + Id: wsi.StreamId, + Attributes: wsi.Attributes, + Size: int64(wsi.Size), + } + if wsi.NameSize != 0 { + name := make([]uint16, int(wsi.NameSize/2)) + if err := binary.Read(r.r, binary.LittleEndian, name); err != nil { + return nil, err + } + hdr.Name = syscall.UTF16ToString(name) + } + if wsi.StreamId == BackupSparseBlock { + if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil { + return nil, err + } + hdr.Size -= 8 + } + r.bytesLeft = hdr.Size + return hdr, nil +} + +// Read reads from the current backup stream. +func (r *BackupStreamReader) Read(b []byte) (int, error) { + if r.bytesLeft == 0 { + return 0, io.EOF + } + if int64(len(b)) > r.bytesLeft { + b = b[:r.bytesLeft] + } + n, err := r.r.Read(b) + r.bytesLeft -= int64(n) + if err == io.EOF { + err = io.ErrUnexpectedEOF + } else if r.bytesLeft == 0 && err == nil { + err = io.EOF + } + return n, err +} + +// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API. +type BackupStreamWriter struct { + w io.Writer + bytesLeft int64 +} + +// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer. +func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter { + return &BackupStreamWriter{w, 0} +} + +// WriteHeader writes the next backup stream header and prepares for calls to Write(). +func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error { + if w.bytesLeft != 0 { + return fmt.Errorf("missing %d bytes", w.bytesLeft) + } + name := utf16.Encode([]rune(hdr.Name)) + wsi := win32StreamId{ + StreamId: hdr.Id, + Attributes: hdr.Attributes, + Size: uint64(hdr.Size), + NameSize: uint32(len(name) * 2), + } + if hdr.Id == BackupSparseBlock { + // Include space for the int64 block offset + wsi.Size += 8 + } + if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil { + return err + } + if len(name) != 0 { + if err := binary.Write(w.w, binary.LittleEndian, name); err != nil { + return err + } + } + if hdr.Id == BackupSparseBlock { + if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil { + return err + } + } + w.bytesLeft = hdr.Size + return nil +} + +// Write writes to the current backup stream. +func (w *BackupStreamWriter) Write(b []byte) (int, error) { + if w.bytesLeft < int64(len(b)) { + return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft) + } + n, err := w.w.Write(b) + w.bytesLeft -= int64(n) + return n, err +} + +// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API. +type BackupFileReader struct { + f *os.File + includeSecurity bool + ctx uintptr +} + +// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true, +// Read will attempt to read the security descriptor of the file. +func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader { + r := &BackupFileReader{f, includeSecurity, 0} + return r +} + +// Read reads a backup stream from the file by calling the Win32 API BackupRead(). +func (r *BackupFileReader) Read(b []byte) (int, error) { + var bytesRead uint32 + err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx) + if err != nil { + return 0, &os.PathError{"BackupRead", r.f.Name(), err} + } + runtime.KeepAlive(r.f) + if bytesRead == 0 { + return 0, io.EOF + } + return int(bytesRead), nil +} + +// Close frees Win32 resources associated with the BackupFileReader. It does not close +// the underlying file. +func (r *BackupFileReader) Close() error { + if r.ctx != 0 { + backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx) + runtime.KeepAlive(r.f) + r.ctx = 0 + } + return nil +} + +// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API. +type BackupFileWriter struct { + f *os.File + includeSecurity bool + ctx uintptr +} + +// NewBackupFileWriter returns a new BackupFileWriter from a file handle. If includeSecurity is true, +// Write() will attempt to restore the security descriptor from the stream. +func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter { + w := &BackupFileWriter{f, includeSecurity, 0} + return w +} + +// Write restores a portion of the file using the provided backup stream. +func (w *BackupFileWriter) Write(b []byte) (int, error) { + var bytesWritten uint32 + err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx) + if err != nil { + return 0, &os.PathError{"BackupWrite", w.f.Name(), err} + } + runtime.KeepAlive(w.f) + if int(bytesWritten) != len(b) { + return int(bytesWritten), errors.New("not all bytes could be written") + } + return len(b), nil +} + +// Close frees Win32 resources associated with the BackupFileWriter. It does not +// close the underlying file. +func (w *BackupFileWriter) Close() error { + if w.ctx != 0 { + backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx) + runtime.KeepAlive(w.f) + w.ctx = 0 + } + return nil +} + +// OpenForBackup opens a file or directory, potentially skipping access checks if the backup +// or restore privileges have been acquired. +// +// If the file opened was a directory, it cannot be used with Readdir(). +func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) { + winPath, err := syscall.UTF16FromString(path) + if err != nil { + return nil, err + } + h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0) + if err != nil { + err = &os.PathError{Op: "open", Path: path, Err: err} + return nil, err + } + return os.NewFile(uintptr(h), path), nil +} diff --git a/vendor/github.com/Microsoft/go-winio/ea.go b/vendor/github.com/Microsoft/go-winio/ea.go new file mode 100644 index 000000000..4051c1b33 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/ea.go @@ -0,0 +1,137 @@ +package winio + +import ( + "bytes" + "encoding/binary" + "errors" +) + +type fileFullEaInformation struct { + NextEntryOffset uint32 + Flags uint8 + NameLength uint8 + ValueLength uint16 +} + +var ( + fileFullEaInformationSize = binary.Size(&fileFullEaInformation{}) + + errInvalidEaBuffer = errors.New("invalid extended attribute buffer") + errEaNameTooLarge = errors.New("extended attribute name too large") + errEaValueTooLarge = errors.New("extended attribute value too large") +) + +// ExtendedAttribute represents a single Windows EA. +type ExtendedAttribute struct { + Name string + Value []byte + Flags uint8 +} + +func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) { + var info fileFullEaInformation + err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info) + if err != nil { + err = errInvalidEaBuffer + return + } + + nameOffset := fileFullEaInformationSize + nameLen := int(info.NameLength) + valueOffset := nameOffset + int(info.NameLength) + 1 + valueLen := int(info.ValueLength) + nextOffset := int(info.NextEntryOffset) + if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) { + err = errInvalidEaBuffer + return + } + + ea.Name = string(b[nameOffset : nameOffset+nameLen]) + ea.Value = b[valueOffset : valueOffset+valueLen] + ea.Flags = info.Flags + if info.NextEntryOffset != 0 { + nb = b[info.NextEntryOffset:] + } + return +} + +// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION +// buffer retrieved from BackupRead, ZwQueryEaFile, etc. +func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) { + for len(b) != 0 { + ea, nb, err := parseEa(b) + if err != nil { + return nil, err + } + + eas = append(eas, ea) + b = nb + } + return +} + +func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error { + if int(uint8(len(ea.Name))) != len(ea.Name) { + return errEaNameTooLarge + } + if int(uint16(len(ea.Value))) != len(ea.Value) { + return errEaValueTooLarge + } + entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value)) + withPadding := (entrySize + 3) &^ 3 + nextOffset := uint32(0) + if !last { + nextOffset = withPadding + } + info := fileFullEaInformation{ + NextEntryOffset: nextOffset, + Flags: ea.Flags, + NameLength: uint8(len(ea.Name)), + ValueLength: uint16(len(ea.Value)), + } + + err := binary.Write(buf, binary.LittleEndian, &info) + if err != nil { + return err + } + + _, err = buf.Write([]byte(ea.Name)) + if err != nil { + return err + } + + err = buf.WriteByte(0) + if err != nil { + return err + } + + _, err = buf.Write(ea.Value) + if err != nil { + return err + } + + _, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize]) + if err != nil { + return err + } + + return nil +} + +// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION +// buffer for use with BackupWrite, ZwSetEaFile, etc. +func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) { + var buf bytes.Buffer + for i := range eas { + last := false + if i == len(eas)-1 { + last = true + } + + err := writeEa(&buf, &eas[i], last) + if err != nil { + return nil, err + } + } + return buf.Bytes(), nil +} diff --git a/vendor/github.com/Microsoft/go-winio/file.go b/vendor/github.com/Microsoft/go-winio/file.go new file mode 100644 index 000000000..4334ff1cb --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/file.go @@ -0,0 +1,307 @@ +// +build windows + +package winio + +import ( + "errors" + "io" + "runtime" + "sync" + "sync/atomic" + "syscall" + "time" +) + +//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx +//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort +//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus +//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes + +type atomicBool int32 + +func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } +func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } +func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } +func (b *atomicBool) swap(new bool) bool { + var newInt int32 + if new { + newInt = 1 + } + return atomic.SwapInt32((*int32)(b), newInt) == 1 +} + +const ( + cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 + cFILE_SKIP_SET_EVENT_ON_HANDLE = 2 +) + +var ( + ErrFileClosed = errors.New("file has already been closed") + ErrTimeout = &timeoutError{} +) + +type timeoutError struct{} + +func (e *timeoutError) Error() string { return "i/o timeout" } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } + +type timeoutChan chan struct{} + +var ioInitOnce sync.Once +var ioCompletionPort syscall.Handle + +// ioResult contains the result of an asynchronous IO operation +type ioResult struct { + bytes uint32 + err error +} + +// ioOperation represents an outstanding asynchronous Win32 IO +type ioOperation struct { + o syscall.Overlapped + ch chan ioResult +} + +func initIo() { + h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff) + if err != nil { + panic(err) + } + ioCompletionPort = h + go ioCompletionProcessor(h) +} + +// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall. +// It takes ownership of this handle and will close it if it is garbage collected. +type win32File struct { + handle syscall.Handle + wg sync.WaitGroup + wgLock sync.RWMutex + closing atomicBool + readDeadline deadlineHandler + writeDeadline deadlineHandler +} + +type deadlineHandler struct { + setLock sync.Mutex + channel timeoutChan + channelLock sync.RWMutex + timer *time.Timer + timedout atomicBool +} + +// makeWin32File makes a new win32File from an existing file handle +func makeWin32File(h syscall.Handle) (*win32File, error) { + f := &win32File{handle: h} + ioInitOnce.Do(initIo) + _, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff) + if err != nil { + return nil, err + } + err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE) + if err != nil { + return nil, err + } + f.readDeadline.channel = make(timeoutChan) + f.writeDeadline.channel = make(timeoutChan) + return f, nil +} + +func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) { + return makeWin32File(h) +} + +// closeHandle closes the resources associated with a Win32 handle +func (f *win32File) closeHandle() { + f.wgLock.Lock() + // Atomically set that we are closing, releasing the resources only once. + if !f.closing.swap(true) { + f.wgLock.Unlock() + // cancel all IO and wait for it to complete + cancelIoEx(f.handle, nil) + f.wg.Wait() + // at this point, no new IO can start + syscall.Close(f.handle) + f.handle = 0 + } else { + f.wgLock.Unlock() + } +} + +// Close closes a win32File. +func (f *win32File) Close() error { + f.closeHandle() + return nil +} + +// prepareIo prepares for a new IO operation. +// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning. +func (f *win32File) prepareIo() (*ioOperation, error) { + f.wgLock.RLock() + if f.closing.isSet() { + f.wgLock.RUnlock() + return nil, ErrFileClosed + } + f.wg.Add(1) + f.wgLock.RUnlock() + c := &ioOperation{} + c.ch = make(chan ioResult) + return c, nil +} + +// ioCompletionProcessor processes completed async IOs forever +func ioCompletionProcessor(h syscall.Handle) { + for { + var bytes uint32 + var key uintptr + var op *ioOperation + err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE) + if op == nil { + panic(err) + } + op.ch <- ioResult{bytes, err} + } +} + +// asyncIo processes the return value from ReadFile or WriteFile, blocking until +// the operation has actually completed. +func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) { + if err != syscall.ERROR_IO_PENDING { + return int(bytes), err + } + + if f.closing.isSet() { + cancelIoEx(f.handle, &c.o) + } + + var timeout timeoutChan + if d != nil { + d.channelLock.Lock() + timeout = d.channel + d.channelLock.Unlock() + } + + var r ioResult + select { + case r = <-c.ch: + err = r.err + if err == syscall.ERROR_OPERATION_ABORTED { + if f.closing.isSet() { + err = ErrFileClosed + } + } + case <-timeout: + cancelIoEx(f.handle, &c.o) + r = <-c.ch + err = r.err + if err == syscall.ERROR_OPERATION_ABORTED { + err = ErrTimeout + } + } + + // runtime.KeepAlive is needed, as c is passed via native + // code to ioCompletionProcessor, c must remain alive + // until the channel read is complete. + runtime.KeepAlive(c) + return int(r.bytes), err +} + +// Read reads from a file handle. +func (f *win32File) Read(b []byte) (int, error) { + c, err := f.prepareIo() + if err != nil { + return 0, err + } + defer f.wg.Done() + + if f.readDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + var bytes uint32 + err = syscall.ReadFile(f.handle, b, &bytes, &c.o) + n, err := f.asyncIo(c, &f.readDeadline, bytes, err) + runtime.KeepAlive(b) + + // Handle EOF conditions. + if err == nil && n == 0 && len(b) != 0 { + return 0, io.EOF + } else if err == syscall.ERROR_BROKEN_PIPE { + return 0, io.EOF + } else { + return n, err + } +} + +// Write writes to a file handle. +func (f *win32File) Write(b []byte) (int, error) { + c, err := f.prepareIo() + if err != nil { + return 0, err + } + defer f.wg.Done() + + if f.writeDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + var bytes uint32 + err = syscall.WriteFile(f.handle, b, &bytes, &c.o) + n, err := f.asyncIo(c, &f.writeDeadline, bytes, err) + runtime.KeepAlive(b) + return n, err +} + +func (f *win32File) SetReadDeadline(deadline time.Time) error { + return f.readDeadline.set(deadline) +} + +func (f *win32File) SetWriteDeadline(deadline time.Time) error { + return f.writeDeadline.set(deadline) +} + +func (f *win32File) Flush() error { + return syscall.FlushFileBuffers(f.handle) +} + +func (d *deadlineHandler) set(deadline time.Time) error { + d.setLock.Lock() + defer d.setLock.Unlock() + + if d.timer != nil { + if !d.timer.Stop() { + <-d.channel + } + d.timer = nil + } + d.timedout.setFalse() + + select { + case <-d.channel: + d.channelLock.Lock() + d.channel = make(chan struct{}) + d.channelLock.Unlock() + default: + } + + if deadline.IsZero() { + return nil + } + + timeoutIO := func() { + d.timedout.setTrue() + close(d.channel) + } + + now := time.Now() + duration := deadline.Sub(now) + if deadline.After(now) { + // Deadline is in the future, set a timer to wait + d.timer = time.AfterFunc(duration, timeoutIO) + } else { + // Deadline is in the past. Cancel all pending IO now. + timeoutIO() + } + return nil +} diff --git a/vendor/github.com/Microsoft/go-winio/fileinfo.go b/vendor/github.com/Microsoft/go-winio/fileinfo.go new file mode 100644 index 000000000..ada2fbab6 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/fileinfo.go @@ -0,0 +1,61 @@ +// +build windows + +package winio + +import ( + "os" + "runtime" + "syscall" + "unsafe" +) + +//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx +//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle + +const ( + fileBasicInfo = 0 + fileIDInfo = 0x12 +) + +// FileBasicInfo contains file access time and file attributes information. +type FileBasicInfo struct { + CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime + FileAttributes uint32 + pad uint32 // padding +} + +// GetFileBasicInfo retrieves times and attributes for a file. +func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { + bi := &FileBasicInfo{} + if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { + return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return bi, nil +} + +// SetFileBasicInfo sets times and attributes for a file. +func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error { + if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { + return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return nil +} + +// FileIDInfo contains the volume serial number and file ID for a file. This pair should be +// unique on a system. +type FileIDInfo struct { + VolumeSerialNumber uint64 + FileID [16]byte +} + +// GetFileID retrieves the unique (volume, file ID) pair for a file. +func GetFileID(f *os.File) (*FileIDInfo, error) { + fileID := &FileIDInfo{} + if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil { + return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return fileID, nil +} diff --git a/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/go-winio/pipe.go new file mode 100644 index 000000000..d99eedb64 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pipe.go @@ -0,0 +1,421 @@ +// +build windows + +package winio + +import ( + "errors" + "io" + "net" + "os" + "syscall" + "time" + "unsafe" +) + +//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe +//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW +//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW +//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo +//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW +//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc + +const ( + cERROR_PIPE_BUSY = syscall.Errno(231) + cERROR_NO_DATA = syscall.Errno(232) + cERROR_PIPE_CONNECTED = syscall.Errno(535) + cERROR_SEM_TIMEOUT = syscall.Errno(121) + + cPIPE_ACCESS_DUPLEX = 0x3 + cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000 + cSECURITY_SQOS_PRESENT = 0x100000 + cSECURITY_ANONYMOUS = 0 + + cPIPE_REJECT_REMOTE_CLIENTS = 0x8 + + cPIPE_UNLIMITED_INSTANCES = 255 + + cNMPWAIT_USE_DEFAULT_WAIT = 0 + cNMPWAIT_NOWAIT = 1 + + cPIPE_TYPE_MESSAGE = 4 + + cPIPE_READMODE_MESSAGE = 2 +) + +var ( + // ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed. + // This error should match net.errClosing since docker takes a dependency on its text. + ErrPipeListenerClosed = errors.New("use of closed network connection") + + errPipeWriteClosed = errors.New("pipe has been closed for write") +) + +type win32Pipe struct { + *win32File + path string +} + +type win32MessageBytePipe struct { + win32Pipe + writeClosed bool + readEOF bool +} + +type pipeAddress string + +func (f *win32Pipe) LocalAddr() net.Addr { + return pipeAddress(f.path) +} + +func (f *win32Pipe) RemoteAddr() net.Addr { + return pipeAddress(f.path) +} + +func (f *win32Pipe) SetDeadline(t time.Time) error { + f.SetReadDeadline(t) + f.SetWriteDeadline(t) + return nil +} + +// CloseWrite closes the write side of a message pipe in byte mode. +func (f *win32MessageBytePipe) CloseWrite() error { + if f.writeClosed { + return errPipeWriteClosed + } + err := f.win32File.Flush() + if err != nil { + return err + } + _, err = f.win32File.Write(nil) + if err != nil { + return err + } + f.writeClosed = true + return nil +} + +// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since +// they are used to implement CloseWrite(). +func (f *win32MessageBytePipe) Write(b []byte) (int, error) { + if f.writeClosed { + return 0, errPipeWriteClosed + } + if len(b) == 0 { + return 0, nil + } + return f.win32File.Write(b) +} + +// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message +// mode pipe will return io.EOF, as will all subsequent reads. +func (f *win32MessageBytePipe) Read(b []byte) (int, error) { + if f.readEOF { + return 0, io.EOF + } + n, err := f.win32File.Read(b) + if err == io.EOF { + // If this was the result of a zero-byte read, then + // it is possible that the read was due to a zero-size + // message. Since we are simulating CloseWrite with a + // zero-byte message, ensure that all future Read() calls + // also return EOF. + f.readEOF = true + } else if err == syscall.ERROR_MORE_DATA { + // ERROR_MORE_DATA indicates that the pipe's read mode is message mode + // and the message still has more bytes. Treat this as a success, since + // this package presents all named pipes as byte streams. + err = nil + } + return n, err +} + +func (s pipeAddress) Network() string { + return "pipe" +} + +func (s pipeAddress) String() string { + return string(s) +} + +// DialPipe connects to a named pipe by path, timing out if the connection +// takes longer than the specified duration. If timeout is nil, then we use +// a default timeout of 5 seconds. (We do not use WaitNamedPipe.) +func DialPipe(path string, timeout *time.Duration) (net.Conn, error) { + var absTimeout time.Time + if timeout != nil { + absTimeout = time.Now().Add(*timeout) + } else { + absTimeout = time.Now().Add(time.Second * 2) + } + var err error + var h syscall.Handle + for { + h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) + if err != cERROR_PIPE_BUSY { + break + } + if time.Now().After(absTimeout) { + return nil, ErrTimeout + } + + // Wait 10 msec and try again. This is a rather simplistic + // view, as we always try each 10 milliseconds. + time.Sleep(time.Millisecond * 10) + } + if err != nil { + return nil, &os.PathError{Op: "open", Path: path, Err: err} + } + + var flags uint32 + err = getNamedPipeInfo(h, &flags, nil, nil, nil) + if err != nil { + return nil, err + } + + f, err := makeWin32File(h) + if err != nil { + syscall.Close(h) + return nil, err + } + + // If the pipe is in message mode, return a message byte pipe, which + // supports CloseWrite(). + if flags&cPIPE_TYPE_MESSAGE != 0 { + return &win32MessageBytePipe{ + win32Pipe: win32Pipe{win32File: f, path: path}, + }, nil + } + return &win32Pipe{win32File: f, path: path}, nil +} + +type acceptResponse struct { + f *win32File + err error +} + +type win32PipeListener struct { + firstHandle syscall.Handle + path string + securityDescriptor []byte + config PipeConfig + acceptCh chan (chan acceptResponse) + closeCh chan int + doneCh chan int +} + +func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) { + var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED + if first { + flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE + } + + var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS + if c.MessageMode { + mode |= cPIPE_TYPE_MESSAGE + } + + sa := &syscall.SecurityAttributes{} + sa.Length = uint32(unsafe.Sizeof(*sa)) + if securityDescriptor != nil { + len := uint32(len(securityDescriptor)) + sa.SecurityDescriptor = localAlloc(0, len) + defer localFree(sa.SecurityDescriptor) + copy((*[0xffff]byte)(unsafe.Pointer(sa.SecurityDescriptor))[:], securityDescriptor) + } + h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, sa) + if err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + return h, nil +} + +func (l *win32PipeListener) makeServerPipe() (*win32File, error) { + h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false) + if err != nil { + return nil, err + } + f, err := makeWin32File(h) + if err != nil { + syscall.Close(h) + return nil, err + } + return f, nil +} + +func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) { + p, err := l.makeServerPipe() + if err != nil { + return nil, err + } + + // Wait for the client to connect. + ch := make(chan error) + go func(p *win32File) { + ch <- connectPipe(p) + }(p) + + select { + case err = <-ch: + if err != nil { + p.Close() + p = nil + } + case <-l.closeCh: + // Abort the connect request by closing the handle. + p.Close() + p = nil + err = <-ch + if err == nil || err == ErrFileClosed { + err = ErrPipeListenerClosed + } + } + return p, err +} + +func (l *win32PipeListener) listenerRoutine() { + closed := false + for !closed { + select { + case <-l.closeCh: + closed = true + case responseCh := <-l.acceptCh: + var ( + p *win32File + err error + ) + for { + p, err = l.makeConnectedServerPipe() + // If the connection was immediately closed by the client, try + // again. + if err != cERROR_NO_DATA { + break + } + } + responseCh <- acceptResponse{p, err} + closed = err == ErrPipeListenerClosed + } + } + syscall.Close(l.firstHandle) + l.firstHandle = 0 + // Notify Close() and Accept() callers that the handle has been closed. + close(l.doneCh) +} + +// PipeConfig contain configuration for the pipe listener. +type PipeConfig struct { + // SecurityDescriptor contains a Windows security descriptor in SDDL format. + SecurityDescriptor string + + // MessageMode determines whether the pipe is in byte or message mode. In either + // case the pipe is read in byte mode by default. The only practical difference in + // this implementation is that CloseWrite() is only supported for message mode pipes; + // CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only + // transferred to the reader (and returned as io.EOF in this implementation) + // when the pipe is in message mode. + MessageMode bool + + // InputBufferSize specifies the size the input buffer, in bytes. + InputBufferSize int32 + + // OutputBufferSize specifies the size the input buffer, in bytes. + OutputBufferSize int32 +} + +// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe. +// The pipe must not already exist. +func ListenPipe(path string, c *PipeConfig) (net.Listener, error) { + var ( + sd []byte + err error + ) + if c == nil { + c = &PipeConfig{} + } + if c.SecurityDescriptor != "" { + sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor) + if err != nil { + return nil, err + } + } + h, err := makeServerPipeHandle(path, sd, c, true) + if err != nil { + return nil, err + } + // Create a client handle and connect it. This results in the pipe + // instance always existing, so that clients see ERROR_PIPE_BUSY + // rather than ERROR_FILE_NOT_FOUND. This ties the first instance + // up so that no other instances can be used. This would have been + // cleaner if the Win32 API matched CreateFile with ConnectNamedPipe + // instead of CreateNamedPipe. (Apparently created named pipes are + // considered to be in listening state regardless of whether any + // active calls to ConnectNamedPipe are outstanding.) + h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) + if err != nil { + syscall.Close(h) + return nil, err + } + // Close the client handle. The server side of the instance will + // still be busy, leading to ERROR_PIPE_BUSY instead of + // ERROR_NOT_FOUND, as long as we don't close the server handle, + // or disconnect the client with DisconnectNamedPipe. + syscall.Close(h2) + l := &win32PipeListener{ + firstHandle: h, + path: path, + securityDescriptor: sd, + config: *c, + acceptCh: make(chan (chan acceptResponse)), + closeCh: make(chan int), + doneCh: make(chan int), + } + go l.listenerRoutine() + return l, nil +} + +func connectPipe(p *win32File) error { + c, err := p.prepareIo() + if err != nil { + return err + } + defer p.wg.Done() + + err = connectNamedPipe(p.handle, &c.o) + _, err = p.asyncIo(c, nil, 0, err) + if err != nil && err != cERROR_PIPE_CONNECTED { + return err + } + return nil +} + +func (l *win32PipeListener) Accept() (net.Conn, error) { + ch := make(chan acceptResponse) + select { + case l.acceptCh <- ch: + response := <-ch + err := response.err + if err != nil { + return nil, err + } + if l.config.MessageMode { + return &win32MessageBytePipe{ + win32Pipe: win32Pipe{win32File: response.f, path: l.path}, + }, nil + } + return &win32Pipe{win32File: response.f, path: l.path}, nil + case <-l.doneCh: + return nil, ErrPipeListenerClosed + } +} + +func (l *win32PipeListener) Close() error { + select { + case l.closeCh <- 1: + <-l.doneCh + case <-l.doneCh: + } + return nil +} + +func (l *win32PipeListener) Addr() net.Addr { + return pipeAddress(l.path) +} diff --git a/vendor/github.com/Microsoft/go-winio/privilege.go b/vendor/github.com/Microsoft/go-winio/privilege.go new file mode 100644 index 000000000..9c83d36fe --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/privilege.go @@ -0,0 +1,202 @@ +// +build windows + +package winio + +import ( + "bytes" + "encoding/binary" + "fmt" + "runtime" + "sync" + "syscall" + "unicode/utf16" + + "golang.org/x/sys/windows" +) + +//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges +//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf +//sys revertToSelf() (err error) = advapi32.RevertToSelf +//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken +//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread +//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW +//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW +//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW + +const ( + SE_PRIVILEGE_ENABLED = 2 + + ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300 + + SeBackupPrivilege = "SeBackupPrivilege" + SeRestorePrivilege = "SeRestorePrivilege" +) + +const ( + securityAnonymous = iota + securityIdentification + securityImpersonation + securityDelegation +) + +var ( + privNames = make(map[string]uint64) + privNameMutex sync.Mutex +) + +// PrivilegeError represents an error enabling privileges. +type PrivilegeError struct { + privileges []uint64 +} + +func (e *PrivilegeError) Error() string { + s := "" + if len(e.privileges) > 1 { + s = "Could not enable privileges " + } else { + s = "Could not enable privilege " + } + for i, p := range e.privileges { + if i != 0 { + s += ", " + } + s += `"` + s += getPrivilegeName(p) + s += `"` + } + return s +} + +// RunWithPrivilege enables a single privilege for a function call. +func RunWithPrivilege(name string, fn func() error) error { + return RunWithPrivileges([]string{name}, fn) +} + +// RunWithPrivileges enables privileges for a function call. +func RunWithPrivileges(names []string, fn func() error) error { + privileges, err := mapPrivileges(names) + if err != nil { + return err + } + runtime.LockOSThread() + defer runtime.UnlockOSThread() + token, err := newThreadToken() + if err != nil { + return err + } + defer releaseThreadToken(token) + err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED) + if err != nil { + return err + } + return fn() +} + +func mapPrivileges(names []string) ([]uint64, error) { + var privileges []uint64 + privNameMutex.Lock() + defer privNameMutex.Unlock() + for _, name := range names { + p, ok := privNames[name] + if !ok { + err := lookupPrivilegeValue("", name, &p) + if err != nil { + return nil, err + } + privNames[name] = p + } + privileges = append(privileges, p) + } + return privileges, nil +} + +// EnableProcessPrivileges enables privileges globally for the process. +func EnableProcessPrivileges(names []string) error { + return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED) +} + +// DisableProcessPrivileges disables privileges globally for the process. +func DisableProcessPrivileges(names []string) error { + return enableDisableProcessPrivilege(names, 0) +} + +func enableDisableProcessPrivilege(names []string, action uint32) error { + privileges, err := mapPrivileges(names) + if err != nil { + return err + } + + p, _ := windows.GetCurrentProcess() + var token windows.Token + err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token) + if err != nil { + return err + } + + defer token.Close() + return adjustPrivileges(token, privileges, action) +} + +func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error { + var b bytes.Buffer + binary.Write(&b, binary.LittleEndian, uint32(len(privileges))) + for _, p := range privileges { + binary.Write(&b, binary.LittleEndian, p) + binary.Write(&b, binary.LittleEndian, action) + } + prevState := make([]byte, b.Len()) + reqSize := uint32(0) + success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize) + if !success { + return err + } + if err == ERROR_NOT_ALL_ASSIGNED { + return &PrivilegeError{privileges} + } + return nil +} + +func getPrivilegeName(luid uint64) string { + var nameBuffer [256]uint16 + bufSize := uint32(len(nameBuffer)) + err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize) + if err != nil { + return fmt.Sprintf("", luid) + } + + var displayNameBuffer [256]uint16 + displayBufSize := uint32(len(displayNameBuffer)) + var langID uint32 + err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID) + if err != nil { + return fmt.Sprintf("", string(utf16.Decode(nameBuffer[:bufSize]))) + } + + return string(utf16.Decode(displayNameBuffer[:displayBufSize])) +} + +func newThreadToken() (windows.Token, error) { + err := impersonateSelf(securityImpersonation) + if err != nil { + return 0, err + } + + var token windows.Token + err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token) + if err != nil { + rerr := revertToSelf() + if rerr != nil { + panic(rerr) + } + return 0, err + } + return token, nil +} + +func releaseThreadToken(h windows.Token) { + err := revertToSelf() + if err != nil { + panic(err) + } + h.Close() +} diff --git a/vendor/github.com/Microsoft/go-winio/reparse.go b/vendor/github.com/Microsoft/go-winio/reparse.go new file mode 100644 index 000000000..fc1ee4d3a --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/reparse.go @@ -0,0 +1,128 @@ +package winio + +import ( + "bytes" + "encoding/binary" + "fmt" + "strings" + "unicode/utf16" + "unsafe" +) + +const ( + reparseTagMountPoint = 0xA0000003 + reparseTagSymlink = 0xA000000C +) + +type reparseDataBuffer struct { + ReparseTag uint32 + ReparseDataLength uint16 + Reserved uint16 + SubstituteNameOffset uint16 + SubstituteNameLength uint16 + PrintNameOffset uint16 + PrintNameLength uint16 +} + +// ReparsePoint describes a Win32 symlink or mount point. +type ReparsePoint struct { + Target string + IsMountPoint bool +} + +// UnsupportedReparsePointError is returned when trying to decode a non-symlink or +// mount point reparse point. +type UnsupportedReparsePointError struct { + Tag uint32 +} + +func (e *UnsupportedReparsePointError) Error() string { + return fmt.Sprintf("unsupported reparse point %x", e.Tag) +} + +// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink +// or a mount point. +func DecodeReparsePoint(b []byte) (*ReparsePoint, error) { + tag := binary.LittleEndian.Uint32(b[0:4]) + return DecodeReparsePointData(tag, b[8:]) +} + +func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) { + isMountPoint := false + switch tag { + case reparseTagMountPoint: + isMountPoint = true + case reparseTagSymlink: + default: + return nil, &UnsupportedReparsePointError{tag} + } + nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6]) + if !isMountPoint { + nameOffset += 4 + } + nameLength := binary.LittleEndian.Uint16(b[6:8]) + name := make([]uint16, nameLength/2) + err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name) + if err != nil { + return nil, err + } + return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil +} + +func isDriveLetter(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') +} + +// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or +// mount point. +func EncodeReparsePoint(rp *ReparsePoint) []byte { + // Generate an NT path and determine if this is a relative path. + var ntTarget string + relative := false + if strings.HasPrefix(rp.Target, `\\?\`) { + ntTarget = `\??\` + rp.Target[4:] + } else if strings.HasPrefix(rp.Target, `\\`) { + ntTarget = `\??\UNC\` + rp.Target[2:] + } else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' { + ntTarget = `\??\` + rp.Target + } else { + ntTarget = rp.Target + relative = true + } + + // The paths must be NUL-terminated even though they are counted strings. + target16 := utf16.Encode([]rune(rp.Target + "\x00")) + ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00")) + + size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8 + size += len(ntTarget16)*2 + len(target16)*2 + + tag := uint32(reparseTagMountPoint) + if !rp.IsMountPoint { + tag = reparseTagSymlink + size += 4 // Add room for symlink flags + } + + data := reparseDataBuffer{ + ReparseTag: tag, + ReparseDataLength: uint16(size), + SubstituteNameOffset: 0, + SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2), + PrintNameOffset: uint16(len(ntTarget16) * 2), + PrintNameLength: uint16((len(target16) - 1) * 2), + } + + var b bytes.Buffer + binary.Write(&b, binary.LittleEndian, &data) + if !rp.IsMountPoint { + flags := uint32(0) + if relative { + flags |= 1 + } + binary.Write(&b, binary.LittleEndian, flags) + } + + binary.Write(&b, binary.LittleEndian, ntTarget16) + binary.Write(&b, binary.LittleEndian, target16) + return b.Bytes() +} diff --git a/vendor/github.com/Microsoft/go-winio/sd.go b/vendor/github.com/Microsoft/go-winio/sd.go new file mode 100644 index 000000000..db1b370a1 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/sd.go @@ -0,0 +1,98 @@ +// +build windows + +package winio + +import ( + "syscall" + "unsafe" +) + +//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW +//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW +//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW +//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW +//sys localFree(mem uintptr) = LocalFree +//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength + +const ( + cERROR_NONE_MAPPED = syscall.Errno(1332) +) + +type AccountLookupError struct { + Name string + Err error +} + +func (e *AccountLookupError) Error() string { + if e.Name == "" { + return "lookup account: empty account name specified" + } + var s string + switch e.Err { + case cERROR_NONE_MAPPED: + s = "not found" + default: + s = e.Err.Error() + } + return "lookup account " + e.Name + ": " + s +} + +type SddlConversionError struct { + Sddl string + Err error +} + +func (e *SddlConversionError) Error() string { + return "convert " + e.Sddl + ": " + e.Err.Error() +} + +// LookupSidByName looks up the SID of an account by name +func LookupSidByName(name string) (sid string, err error) { + if name == "" { + return "", &AccountLookupError{name, cERROR_NONE_MAPPED} + } + + var sidSize, sidNameUse, refDomainSize uint32 + err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse) + if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { + return "", &AccountLookupError{name, err} + } + sidBuffer := make([]byte, sidSize) + refDomainBuffer := make([]uint16, refDomainSize) + err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse) + if err != nil { + return "", &AccountLookupError{name, err} + } + var strBuffer *uint16 + err = convertSidToStringSid(&sidBuffer[0], &strBuffer) + if err != nil { + return "", &AccountLookupError{name, err} + } + sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:]) + localFree(uintptr(unsafe.Pointer(strBuffer))) + return sid, nil +} + +func SddlToSecurityDescriptor(sddl string) ([]byte, error) { + var sdBuffer uintptr + err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil) + if err != nil { + return nil, &SddlConversionError{sddl, err} + } + defer localFree(sdBuffer) + sd := make([]byte, getSecurityDescriptorLength(sdBuffer)) + copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)]) + return sd, nil +} + +func SecurityDescriptorToSddl(sd []byte) (string, error) { + var sddl *uint16 + // The returned string length seems to including an aribtrary number of terminating NULs. + // Don't use it. + err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil) + if err != nil { + return "", err + } + defer localFree(uintptr(unsafe.Pointer(sddl))) + return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil +} diff --git a/vendor/github.com/Microsoft/go-winio/syscall.go b/vendor/github.com/Microsoft/go-winio/syscall.go new file mode 100644 index 000000000..20d64cf41 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/syscall.go @@ -0,0 +1,3 @@ +package winio + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go diff --git a/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go new file mode 100644 index 000000000..3f527639a --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go @@ -0,0 +1,520 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package winio + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return nil + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") + + procCancelIoEx = modkernel32.NewProc("CancelIoEx") + procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") + procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") + procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") + procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") + procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") + procCreateFileW = modkernel32.NewProc("CreateFileW") + procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW") + procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") + procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") + procLocalAlloc = modkernel32.NewProc("LocalAlloc") + procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") + procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") + procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") + procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW") + procLocalFree = modkernel32.NewProc("LocalFree") + procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength") + procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx") + procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle") + procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") + procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") + procRevertToSelf = modadvapi32.NewProc("RevertToSelf") + procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") + procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") + procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") + procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW") + procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW") + procBackupRead = modkernel32.NewProc("BackupRead") + procBackupWrite = modkernel32.NewProc("BackupWrite") +) + +func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0) + newport = syscall.Handle(r0) + if newport == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa) +} + +func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) + handle = syscall.Handle(r0) + if handle == syscall.InvalidHandle { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile) +} + +func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) + handle = syscall.Handle(r0) + if handle == syscall.InvalidHandle { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func waitNamedPipe(name string, timeout uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _waitNamedPipe(_p0, timeout) +} + +func _waitNamedPipe(name *uint16, timeout uint32) (err error) { + r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { + r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0) + ptr = uintptr(r0) + return +} + +func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(accountName) + if err != nil { + return + } + return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse) +} + +func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func convertSidToStringSid(sid *byte, str **uint16) (err error) { + r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(str) + if err != nil { + return + } + return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size) +} + +func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func localFree(mem uintptr) { + syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0) + return +} + +func getSecurityDescriptorLength(sd uintptr) (len uint32) { + r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0) + len = uint32(r0) + return +} + +func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { + var _p0 uint32 + if releaseAll { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize))) + success = r0 != 0 + if true { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func impersonateSelf(level uint32) (err error) { + r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func revertToSelf() (err error) { + r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) { + var _p0 uint32 + if openAsSelf { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getCurrentThread() (h syscall.Handle) { + r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) + h = syscall.Handle(r0) + return +} + +func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + var _p1 *uint16 + _p1, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _lookupPrivilegeValue(_p0, _p1, luid) +} + +func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) { + r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + return _lookupPrivilegeName(_p0, luid, buffer, size) +} + +func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId) +} + +func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 uint32 + if abort { + _p1 = 1 + } else { + _p1 = 0 + } + var _p2 uint32 + if processSecurity { + _p2 = 1 + } else { + _p2 = 0 + } + r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 uint32 + if abort { + _p1 = 1 + } else { + _p1 = 0 + } + var _p2 uint32 + if processSecurity { + _p2 = 1 + } else { + _p2 = 0 + } + r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/vendor/github.com/Nvveen/Gotty/LICENSE b/vendor/github.com/Nvveen/Gotty/LICENSE new file mode 100644 index 000000000..0b71c9736 --- /dev/null +++ b/vendor/github.com/Nvveen/Gotty/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2012, Neal van Veen (nealvanveen@gmail.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. diff --git a/vendor/github.com/Nvveen/Gotty/README b/vendor/github.com/Nvveen/Gotty/README new file mode 100644 index 000000000..a6b0d9a8f --- /dev/null +++ b/vendor/github.com/Nvveen/Gotty/README @@ -0,0 +1,5 @@ +Gotty is a library written in Go that determines and reads termcap database +files to produce an interface for interacting with the capabilities of a +terminal. +See the godoc documentation or the source code for more information about +function usage. diff --git a/vendor/github.com/Nvveen/Gotty/TODO b/vendor/github.com/Nvveen/Gotty/TODO new file mode 100644 index 000000000..470460531 --- /dev/null +++ b/vendor/github.com/Nvveen/Gotty/TODO @@ -0,0 +1,3 @@ +gotty.go:// TODO add more concurrency to name lookup, look for more opportunities. +all:// TODO add more documentation, with function usage in a doc.go file. +all:// TODO add more testing/benchmarking with go test. diff --git a/vendor/github.com/Nvveen/Gotty/attributes.go b/vendor/github.com/Nvveen/Gotty/attributes.go new file mode 100644 index 000000000..a4c005fae --- /dev/null +++ b/vendor/github.com/Nvveen/Gotty/attributes.go @@ -0,0 +1,514 @@ +// Copyright 2012 Neal van Veen. All rights reserved. +// Usage of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package gotty + +// Boolean capabilities +var BoolAttr = [...]string{ + "auto_left_margin", "bw", + "auto_right_margin", "am", + "no_esc_ctlc", "xsb", + "ceol_standout_glitch", "xhp", + "eat_newline_glitch", "xenl", + "erase_overstrike", "eo", + "generic_type", "gn", + "hard_copy", "hc", + "has_meta_key", "km", + "has_status_line", "hs", + "insert_null_glitch", "in", + "memory_above", "da", + "memory_below", "db", + "move_insert_mode", "mir", + "move_standout_mode", "msgr", + "over_strike", "os", + "status_line_esc_ok", "eslok", + "dest_tabs_magic_smso", "xt", + "tilde_glitch", "hz", + "transparent_underline", "ul", + "xon_xoff", "nxon", + "needs_xon_xoff", "nxon", + "prtr_silent", "mc5i", + "hard_cursor", "chts", + "non_rev_rmcup", "nrrmc", + "no_pad_char", "npc", + "non_dest_scroll_region", "ndscr", + "can_change", "ccc", + "back_color_erase", "bce", + "hue_lightness_saturation", "hls", + "col_addr_glitch", "xhpa", + "cr_cancels_micro_mode", "crxm", + "has_print_wheel", "daisy", + "row_addr_glitch", "xvpa", + "semi_auto_right_margin", "sam", + "cpi_changes_res", "cpix", + "lpi_changes_res", "lpix", + "backspaces_with_bs", "", + "crt_no_scrolling", "", + "no_correctly_working_cr", "", + "gnu_has_meta_key", "", + "linefeed_is_newline", "", + "has_hardware_tabs", "", + "return_does_clr_eol", "", +} + +// Numerical capabilities +var NumAttr = [...]string{ + "columns", "cols", + "init_tabs", "it", + "lines", "lines", + "lines_of_memory", "lm", + "magic_cookie_glitch", "xmc", + "padding_baud_rate", "pb", + "virtual_terminal", "vt", + "width_status_line", "wsl", + "num_labels", "nlab", + "label_height", "lh", + "label_width", "lw", + "max_attributes", "ma", + "maximum_windows", "wnum", + "max_colors", "colors", + "max_pairs", "pairs", + "no_color_video", "ncv", + "buffer_capacity", "bufsz", + "dot_vert_spacing", "spinv", + "dot_horz_spacing", "spinh", + "max_micro_address", "maddr", + "max_micro_jump", "mjump", + "micro_col_size", "mcs", + "micro_line_size", "mls", + "number_of_pins", "npins", + "output_res_char", "orc", + "output_res_line", "orl", + "output_res_horz_inch", "orhi", + "output_res_vert_inch", "orvi", + "print_rate", "cps", + "wide_char_size", "widcs", + "buttons", "btns", + "bit_image_entwining", "bitwin", + "bit_image_type", "bitype", + "magic_cookie_glitch_ul", "", + "carriage_return_delay", "", + "new_line_delay", "", + "backspace_delay", "", + "horizontal_tab_delay", "", + "number_of_function_keys", "", +} + +// String capabilities +var StrAttr = [...]string{ + "back_tab", "cbt", + "bell", "bel", + "carriage_return", "cr", + "change_scroll_region", "csr", + "clear_all_tabs", "tbc", + "clear_screen", "clear", + "clr_eol", "el", + "clr_eos", "ed", + "column_address", "hpa", + "command_character", "cmdch", + "cursor_address", "cup", + "cursor_down", "cud1", + "cursor_home", "home", + "cursor_invisible", "civis", + "cursor_left", "cub1", + "cursor_mem_address", "mrcup", + "cursor_normal", "cnorm", + "cursor_right", "cuf1", + "cursor_to_ll", "ll", + "cursor_up", "cuu1", + "cursor_visible", "cvvis", + "delete_character", "dch1", + "delete_line", "dl1", + "dis_status_line", "dsl", + "down_half_line", "hd", + "enter_alt_charset_mode", "smacs", + "enter_blink_mode", "blink", + "enter_bold_mode", "bold", + "enter_ca_mode", "smcup", + "enter_delete_mode", "smdc", + "enter_dim_mode", "dim", + "enter_insert_mode", "smir", + "enter_secure_mode", "invis", + "enter_protected_mode", "prot", + "enter_reverse_mode", "rev", + "enter_standout_mode", "smso", + "enter_underline_mode", "smul", + "erase_chars", "ech", + "exit_alt_charset_mode", "rmacs", + "exit_attribute_mode", "sgr0", + "exit_ca_mode", "rmcup", + "exit_delete_mode", "rmdc", + "exit_insert_mode", "rmir", + "exit_standout_mode", "rmso", + "exit_underline_mode", "rmul", + "flash_screen", "flash", + "form_feed", "ff", + "from_status_line", "fsl", + "init_1string", "is1", + "init_2string", "is2", + "init_3string", "is3", + "init_file", "if", + "insert_character", "ich1", + "insert_line", "il1", + "insert_padding", "ip", + "key_backspace", "kbs", + "key_catab", "ktbc", + "key_clear", "kclr", + "key_ctab", "kctab", + "key_dc", "kdch1", + "key_dl", "kdl1", + "key_down", "kcud1", + "key_eic", "krmir", + "key_eol", "kel", + "key_eos", "ked", + "key_f0", "kf0", + "key_f1", "kf1", + "key_f10", "kf10", + "key_f2", "kf2", + "key_f3", "kf3", + "key_f4", "kf4", + "key_f5", "kf5", + "key_f6", "kf6", + "key_f7", "kf7", + "key_f8", "kf8", + "key_f9", "kf9", + "key_home", "khome", + "key_ic", "kich1", + "key_il", "kil1", + "key_left", "kcub1", + "key_ll", "kll", + "key_npage", "knp", + "key_ppage", "kpp", + "key_right", "kcuf1", + "key_sf", "kind", + "key_sr", "kri", + "key_stab", "khts", + "key_up", "kcuu1", + "keypad_local", "rmkx", + "keypad_xmit", "smkx", + "lab_f0", "lf0", + "lab_f1", "lf1", + "lab_f10", "lf10", + "lab_f2", "lf2", + "lab_f3", "lf3", + "lab_f4", "lf4", + "lab_f5", "lf5", + "lab_f6", "lf6", + "lab_f7", "lf7", + "lab_f8", "lf8", + "lab_f9", "lf9", + "meta_off", "rmm", + "meta_on", "smm", + "newline", "_glitch", + "pad_char", "npc", + "parm_dch", "dch", + "parm_delete_line", "dl", + "parm_down_cursor", "cud", + "parm_ich", "ich", + "parm_index", "indn", + "parm_insert_line", "il", + "parm_left_cursor", "cub", + "parm_right_cursor", "cuf", + "parm_rindex", "rin", + "parm_up_cursor", "cuu", + "pkey_key", "pfkey", + "pkey_local", "pfloc", + "pkey_xmit", "pfx", + "print_screen", "mc0", + "prtr_off", "mc4", + "prtr_on", "mc5", + "repeat_char", "rep", + "reset_1string", "rs1", + "reset_2string", "rs2", + "reset_3string", "rs3", + "reset_file", "rf", + "restore_cursor", "rc", + "row_address", "mvpa", + "save_cursor", "row_address", + "scroll_forward", "ind", + "scroll_reverse", "ri", + "set_attributes", "sgr", + "set_tab", "hts", + "set_window", "wind", + "tab", "s_magic_smso", + "to_status_line", "tsl", + "underline_char", "uc", + "up_half_line", "hu", + "init_prog", "iprog", + "key_a1", "ka1", + "key_a3", "ka3", + "key_b2", "kb2", + "key_c1", "kc1", + "key_c3", "kc3", + "prtr_non", "mc5p", + "char_padding", "rmp", + "acs_chars", "acsc", + "plab_norm", "pln", + "key_btab", "kcbt", + "enter_xon_mode", "smxon", + "exit_xon_mode", "rmxon", + "enter_am_mode", "smam", + "exit_am_mode", "rmam", + "xon_character", "xonc", + "xoff_character", "xoffc", + "ena_acs", "enacs", + "label_on", "smln", + "label_off", "rmln", + "key_beg", "kbeg", + "key_cancel", "kcan", + "key_close", "kclo", + "key_command", "kcmd", + "key_copy", "kcpy", + "key_create", "kcrt", + "key_end", "kend", + "key_enter", "kent", + "key_exit", "kext", + "key_find", "kfnd", + "key_help", "khlp", + "key_mark", "kmrk", + "key_message", "kmsg", + "key_move", "kmov", + "key_next", "knxt", + "key_open", "kopn", + "key_options", "kopt", + "key_previous", "kprv", + "key_print", "kprt", + "key_redo", "krdo", + "key_reference", "kref", + "key_refresh", "krfr", + "key_replace", "krpl", + "key_restart", "krst", + "key_resume", "kres", + "key_save", "ksav", + "key_suspend", "kspd", + "key_undo", "kund", + "key_sbeg", "kBEG", + "key_scancel", "kCAN", + "key_scommand", "kCMD", + "key_scopy", "kCPY", + "key_screate", "kCRT", + "key_sdc", "kDC", + "key_sdl", "kDL", + "key_select", "kslt", + "key_send", "kEND", + "key_seol", "kEOL", + "key_sexit", "kEXT", + "key_sfind", "kFND", + "key_shelp", "kHLP", + "key_shome", "kHOM", + "key_sic", "kIC", + "key_sleft", "kLFT", + "key_smessage", "kMSG", + "key_smove", "kMOV", + "key_snext", "kNXT", + "key_soptions", "kOPT", + "key_sprevious", "kPRV", + "key_sprint", "kPRT", + "key_sredo", "kRDO", + "key_sreplace", "kRPL", + "key_sright", "kRIT", + "key_srsume", "kRES", + "key_ssave", "kSAV", + "key_ssuspend", "kSPD", + "key_sundo", "kUND", + "req_for_input", "rfi", + "key_f11", "kf11", + "key_f12", "kf12", + "key_f13", "kf13", + "key_f14", "kf14", + "key_f15", "kf15", + "key_f16", "kf16", + "key_f17", "kf17", + "key_f18", "kf18", + "key_f19", "kf19", + "key_f20", "kf20", + "key_f21", "kf21", + "key_f22", "kf22", + "key_f23", "kf23", + "key_f24", "kf24", + "key_f25", "kf25", + "key_f26", "kf26", + "key_f27", "kf27", + "key_f28", "kf28", + "key_f29", "kf29", + "key_f30", "kf30", + "key_f31", "kf31", + "key_f32", "kf32", + "key_f33", "kf33", + "key_f34", "kf34", + "key_f35", "kf35", + "key_f36", "kf36", + "key_f37", "kf37", + "key_f38", "kf38", + "key_f39", "kf39", + "key_f40", "kf40", + "key_f41", "kf41", + "key_f42", "kf42", + "key_f43", "kf43", + "key_f44", "kf44", + "key_f45", "kf45", + "key_f46", "kf46", + "key_f47", "kf47", + "key_f48", "kf48", + "key_f49", "kf49", + "key_f50", "kf50", + "key_f51", "kf51", + "key_f52", "kf52", + "key_f53", "kf53", + "key_f54", "kf54", + "key_f55", "kf55", + "key_f56", "kf56", + "key_f57", "kf57", + "key_f58", "kf58", + "key_f59", "kf59", + "key_f60", "kf60", + "key_f61", "kf61", + "key_f62", "kf62", + "key_f63", "kf63", + "clr_bol", "el1", + "clear_margins", "mgc", + "set_left_margin", "smgl", + "set_right_margin", "smgr", + "label_format", "fln", + "set_clock", "sclk", + "display_clock", "dclk", + "remove_clock", "rmclk", + "create_window", "cwin", + "goto_window", "wingo", + "hangup", "hup", + "dial_phone", "dial", + "quick_dial", "qdial", + "tone", "tone", + "pulse", "pulse", + "flash_hook", "hook", + "fixed_pause", "pause", + "wait_tone", "wait", + "user0", "u0", + "user1", "u1", + "user2", "u2", + "user3", "u3", + "user4", "u4", + "user5", "u5", + "user6", "u6", + "user7", "u7", + "user8", "u8", + "user9", "u9", + "orig_pair", "op", + "orig_colors", "oc", + "initialize_color", "initc", + "initialize_pair", "initp", + "set_color_pair", "scp", + "set_foreground", "setf", + "set_background", "setb", + "change_char_pitch", "cpi", + "change_line_pitch", "lpi", + "change_res_horz", "chr", + "change_res_vert", "cvr", + "define_char", "defc", + "enter_doublewide_mode", "swidm", + "enter_draft_quality", "sdrfq", + "enter_italics_mode", "sitm", + "enter_leftward_mode", "slm", + "enter_micro_mode", "smicm", + "enter_near_letter_quality", "snlq", + "enter_normal_quality", "snrmq", + "enter_shadow_mode", "sshm", + "enter_subscript_mode", "ssubm", + "enter_superscript_mode", "ssupm", + "enter_upward_mode", "sum", + "exit_doublewide_mode", "rwidm", + "exit_italics_mode", "ritm", + "exit_leftward_mode", "rlm", + "exit_micro_mode", "rmicm", + "exit_shadow_mode", "rshm", + "exit_subscript_mode", "rsubm", + "exit_superscript_mode", "rsupm", + "exit_upward_mode", "rum", + "micro_column_address", "mhpa", + "micro_down", "mcud1", + "micro_left", "mcub1", + "micro_right", "mcuf1", + "micro_row_address", "mvpa", + "micro_up", "mcuu1", + "order_of_pins", "porder", + "parm_down_micro", "mcud", + "parm_left_micro", "mcub", + "parm_right_micro", "mcuf", + "parm_up_micro", "mcuu", + "select_char_set", "scs", + "set_bottom_margin", "smgb", + "set_bottom_margin_parm", "smgbp", + "set_left_margin_parm", "smglp", + "set_right_margin_parm", "smgrp", + "set_top_margin", "smgt", + "set_top_margin_parm", "smgtp", + "start_bit_image", "sbim", + "start_char_set_def", "scsd", + "stop_bit_image", "rbim", + "stop_char_set_def", "rcsd", + "subscript_characters", "subcs", + "superscript_characters", "supcs", + "these_cause_cr", "docr", + "zero_motion", "zerom", + "char_set_names", "csnm", + "key_mouse", "kmous", + "mouse_info", "minfo", + "req_mouse_pos", "reqmp", + "get_mouse", "getm", + "set_a_foreground", "setaf", + "set_a_background", "setab", + "pkey_plab", "pfxl", + "device_type", "devt", + "code_set_init", "csin", + "set0_des_seq", "s0ds", + "set1_des_seq", "s1ds", + "set2_des_seq", "s2ds", + "set3_des_seq", "s3ds", + "set_lr_margin", "smglr", + "set_tb_margin", "smgtb", + "bit_image_repeat", "birep", + "bit_image_newline", "binel", + "bit_image_carriage_return", "bicr", + "color_names", "colornm", + "define_bit_image_region", "defbi", + "end_bit_image_region", "endbi", + "set_color_band", "setcolor", + "set_page_length", "slines", + "display_pc_char", "dispc", + "enter_pc_charset_mode", "smpch", + "exit_pc_charset_mode", "rmpch", + "enter_scancode_mode", "smsc", + "exit_scancode_mode", "rmsc", + "pc_term_options", "pctrm", + "scancode_escape", "scesc", + "alt_scancode_esc", "scesa", + "enter_horizontal_hl_mode", "ehhlm", + "enter_left_hl_mode", "elhlm", + "enter_low_hl_mode", "elohlm", + "enter_right_hl_mode", "erhlm", + "enter_top_hl_mode", "ethlm", + "enter_vertical_hl_mode", "evhlm", + "set_a_attributes", "sgr1", + "set_pglen_inch", "slength", + "termcap_init2", "", + "termcap_reset", "", + "linefeed_if_not_lf", "", + "backspace_if_not_bs", "", + "other_non_function_keys", "", + "arrow_key_map", "", + "acs_ulcorner", "", + "acs_llcorner", "", + "acs_urcorner", "", + "acs_lrcorner", "", + "acs_ltee", "", + "acs_rtee", "", + "acs_btee", "", + "acs_ttee", "", + "acs_hline", "", + "acs_vline", "", + "acs_plus", "", + "memory_lock", "", + "memory_unlock", "", + "box_chars_1", "", +} diff --git a/vendor/github.com/Nvveen/Gotty/gotty.go b/vendor/github.com/Nvveen/Gotty/gotty.go new file mode 100644 index 000000000..093cbf37e --- /dev/null +++ b/vendor/github.com/Nvveen/Gotty/gotty.go @@ -0,0 +1,238 @@ +// Copyright 2012 Neal van Veen. All rights reserved. +// Usage of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Gotty is a Go-package for reading and parsing the terminfo database +package gotty + +// TODO add more concurrency to name lookup, look for more opportunities. + +import ( + "encoding/binary" + "errors" + "fmt" + "os" + "reflect" + "strings" + "sync" +) + +// Open a terminfo file by the name given and construct a TermInfo object. +// If something went wrong reading the terminfo database file, an error is +// returned. +func OpenTermInfo(termName string) (*TermInfo, error) { + var term *TermInfo + var err error + // Find the environment variables + termloc := os.Getenv("TERMINFO") + if len(termloc) == 0 { + // Search like ncurses + locations := []string{os.Getenv("HOME") + "/.terminfo/", "/etc/terminfo/", + "/lib/terminfo/", "/usr/share/terminfo/"} + var path string + for _, str := range locations { + // Construct path + path = str + string(termName[0]) + "/" + termName + // Check if path can be opened + file, _ := os.Open(path) + if file != nil { + // Path can open, fall out and use current path + file.Close() + break + } + } + if len(path) > 0 { + term, err = readTermInfo(path) + } else { + err = errors.New(fmt.Sprintf("No terminfo file(-location) found")) + } + } + return term, err +} + +// Open a terminfo file from the environment variable containing the current +// terminal name and construct a TermInfo object. If something went wrong +// reading the terminfo database file, an error is returned. +func OpenTermInfoEnv() (*TermInfo, error) { + termenv := os.Getenv("TERM") + return OpenTermInfo(termenv) +} + +// Return an attribute by the name attr provided. If none can be found, +// an error is returned. +func (term *TermInfo) GetAttribute(attr string) (stacker, error) { + // Channel to store the main value in. + var value stacker + // Add a blocking WaitGroup + var block sync.WaitGroup + // Keep track of variable being written. + written := false + // Function to put into goroutine. + f := func(ats interface{}) { + var ok bool + var v stacker + // Switch on type of map to use and assign value to it. + switch reflect.TypeOf(ats).Elem().Kind() { + case reflect.Bool: + v, ok = ats.(map[string]bool)[attr] + case reflect.Int16: + v, ok = ats.(map[string]int16)[attr] + case reflect.String: + v, ok = ats.(map[string]string)[attr] + } + // If ok, a value is found, so we can write. + if ok { + value = v + written = true + } + // Goroutine is done + block.Done() + } + block.Add(3) + // Go for all 3 attribute lists. + go f(term.boolAttributes) + go f(term.numAttributes) + go f(term.strAttributes) + // Wait until every goroutine is done. + block.Wait() + // If a value has been written, return it. + if written { + return value, nil + } + // Otherwise, error. + return nil, fmt.Errorf("Erorr finding attribute") +} + +// Return an attribute by the name attr provided. If none can be found, +// an error is returned. A name is first converted to its termcap value. +func (term *TermInfo) GetAttributeName(name string) (stacker, error) { + tc := GetTermcapName(name) + return term.GetAttribute(tc) +} + +// A utility function that finds and returns the termcap equivalent of a +// variable name. +func GetTermcapName(name string) string { + // Termcap name + var tc string + // Blocking group + var wait sync.WaitGroup + // Function to put into a goroutine + f := func(attrs []string) { + // Find the string corresponding to the name + for i, s := range attrs { + if s == name { + tc = attrs[i+1] + } + } + // Goroutine is finished + wait.Done() + } + wait.Add(3) + // Go for all 3 attribute lists + go f(BoolAttr[:]) + go f(NumAttr[:]) + go f(StrAttr[:]) + // Wait until every goroutine is done + wait.Wait() + // Return the termcap name + return tc +} + +// This function takes a path to a terminfo file and reads it in binary +// form to construct the actual TermInfo file. +func readTermInfo(path string) (*TermInfo, error) { + // Open the terminfo file + file, err := os.Open(path) + defer file.Close() + if err != nil { + return nil, err + } + + // magic, nameSize, boolSize, nrSNum, nrOffsetsStr, strSize + // Header is composed of the magic 0432 octal number, size of the name + // section, size of the boolean section, the amount of number values, + // the number of offsets of strings, and the size of the string section. + var header [6]int16 + // Byte array is used to read in byte values + var byteArray []byte + // Short array is used to read in short values + var shArray []int16 + // TermInfo object to store values + var term TermInfo + + // Read in the header + err = binary.Read(file, binary.LittleEndian, &header) + if err != nil { + return nil, err + } + // If magic number isn't there or isn't correct, we have the wrong filetype + if header[0] != 0432 { + return nil, errors.New(fmt.Sprintf("Wrong filetype")) + } + + // Read in the names + byteArray = make([]byte, header[1]) + err = binary.Read(file, binary.LittleEndian, &byteArray) + if err != nil { + return nil, err + } + term.Names = strings.Split(string(byteArray), "|") + + // Read in the booleans + byteArray = make([]byte, header[2]) + err = binary.Read(file, binary.LittleEndian, &byteArray) + if err != nil { + return nil, err + } + term.boolAttributes = make(map[string]bool) + for i, b := range byteArray { + if b == 1 { + term.boolAttributes[BoolAttr[i*2+1]] = true + } + } + // If the number of bytes read is not even, a byte for alignment is added + if len(byteArray)%2 != 0 { + err = binary.Read(file, binary.LittleEndian, make([]byte, 1)) + if err != nil { + return nil, err + } + } + + // Read in shorts + shArray = make([]int16, header[3]) + err = binary.Read(file, binary.LittleEndian, &shArray) + if err != nil { + return nil, err + } + term.numAttributes = make(map[string]int16) + for i, n := range shArray { + if n != 0377 && n > -1 { + term.numAttributes[NumAttr[i*2+1]] = n + } + } + + // Read the offsets into the short array + shArray = make([]int16, header[4]) + err = binary.Read(file, binary.LittleEndian, &shArray) + if err != nil { + return nil, err + } + // Read the actual strings in the byte array + byteArray = make([]byte, header[5]) + err = binary.Read(file, binary.LittleEndian, &byteArray) + if err != nil { + return nil, err + } + term.strAttributes = make(map[string]string) + // We get an offset, and then iterate until the string is null-terminated + for i, offset := range shArray { + if offset > -1 { + r := offset + for ; byteArray[r] != 0; r++ { + } + term.strAttributes[StrAttr[i*2+1]] = string(byteArray[offset:r]) + } + } + return &term, nil +} diff --git a/vendor/github.com/Nvveen/Gotty/parser.go b/vendor/github.com/Nvveen/Gotty/parser.go new file mode 100644 index 000000000..a9d5d23c5 --- /dev/null +++ b/vendor/github.com/Nvveen/Gotty/parser.go @@ -0,0 +1,362 @@ +// Copyright 2012 Neal van Veen. All rights reserved. +// Usage of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package gotty + +import ( + "bytes" + "errors" + "fmt" + "regexp" + "strconv" + "strings" +) + +var exp = [...]string{ + "%%", + "%c", + "%s", + "%p(\\d)", + "%P([A-z])", + "%g([A-z])", + "%'(.)'", + "%{([0-9]+)}", + "%l", + "%\\+|%-|%\\*|%/|%m", + "%&|%\\||%\\^", + "%=|%>|%<", + "%A|%O", + "%!|%~", + "%i", + "%(:[\\ #\\-\\+]{0,4})?(\\d+\\.\\d+|\\d+)?[doxXs]", + "%\\?(.*?);", +} + +var regex *regexp.Regexp +var staticVar map[byte]stacker + +// Parses the attribute that is received with name attr and parameters params. +func (term *TermInfo) Parse(attr string, params ...interface{}) (string, error) { + // Get the attribute name first. + iface, err := term.GetAttribute(attr) + str, ok := iface.(string) + if err != nil { + return "", err + } + if !ok { + return str, errors.New("Only string capabilities can be parsed.") + } + // Construct the hidden parser struct so we can use a recursive stack based + // parser. + ps := &parser{} + // Dynamic variables only exist in this context. + ps.dynamicVar = make(map[byte]stacker, 26) + ps.parameters = make([]stacker, len(params)) + // Convert the parameters to insert them into the parser struct. + for i, x := range params { + ps.parameters[i] = x + } + // Recursively walk and return. + result, err := ps.walk(str) + return result, err +} + +// Parses the attribute that is received with name attr and parameters params. +// Only works on full name of a capability that is given, which it uses to +// search for the termcap name. +func (term *TermInfo) ParseName(attr string, params ...interface{}) (string, error) { + tc := GetTermcapName(attr) + return term.Parse(tc, params) +} + +// Identify each token in a stack based manner and do the actual parsing. +func (ps *parser) walk(attr string) (string, error) { + // We use a buffer to get the modified string. + var buf bytes.Buffer + // Next, find and identify all tokens by their indices and strings. + tokens := regex.FindAllStringSubmatch(attr, -1) + if len(tokens) == 0 { + return attr, nil + } + indices := regex.FindAllStringIndex(attr, -1) + q := 0 // q counts the matches of one token + // Iterate through the string per character. + for i := 0; i < len(attr); i++ { + // If the current position is an identified token, execute the following + // steps. + if q < len(indices) && i >= indices[q][0] && i < indices[q][1] { + // Switch on token. + switch { + case tokens[q][0][:2] == "%%": + // Literal percentage character. + buf.WriteByte('%') + case tokens[q][0][:2] == "%c": + // Pop a character. + c, err := ps.st.pop() + if err != nil { + return buf.String(), err + } + buf.WriteByte(c.(byte)) + case tokens[q][0][:2] == "%s": + // Pop a string. + str, err := ps.st.pop() + if err != nil { + return buf.String(), err + } + if _, ok := str.(string); !ok { + return buf.String(), errors.New("Stack head is not a string") + } + buf.WriteString(str.(string)) + case tokens[q][0][:2] == "%p": + // Push a parameter on the stack. + index, err := strconv.ParseInt(tokens[q][1], 10, 8) + index-- + if err != nil { + return buf.String(), err + } + if int(index) >= len(ps.parameters) { + return buf.String(), errors.New("Parameters index out of bound") + } + ps.st.push(ps.parameters[index]) + case tokens[q][0][:2] == "%P": + // Pop a variable from the stack as a dynamic or static variable. + val, err := ps.st.pop() + if err != nil { + return buf.String(), err + } + index := tokens[q][2] + if len(index) > 1 { + errorStr := fmt.Sprintf("%s is not a valid dynamic variables index", + index) + return buf.String(), errors.New(errorStr) + } + // Specify either dynamic or static. + if index[0] >= 'a' && index[0] <= 'z' { + ps.dynamicVar[index[0]] = val + } else if index[0] >= 'A' && index[0] <= 'Z' { + staticVar[index[0]] = val + } + case tokens[q][0][:2] == "%g": + // Push a variable from the stack as a dynamic or static variable. + index := tokens[q][3] + if len(index) > 1 { + errorStr := fmt.Sprintf("%s is not a valid static variables index", + index) + return buf.String(), errors.New(errorStr) + } + var val stacker + if index[0] >= 'a' && index[0] <= 'z' { + val = ps.dynamicVar[index[0]] + } else if index[0] >= 'A' && index[0] <= 'Z' { + val = staticVar[index[0]] + } + ps.st.push(val) + case tokens[q][0][:2] == "%'": + // Push a character constant. + con := tokens[q][4] + if len(con) > 1 { + errorStr := fmt.Sprintf("%s is not a valid character constant", con) + return buf.String(), errors.New(errorStr) + } + ps.st.push(con[0]) + case tokens[q][0][:2] == "%{": + // Push an integer constant. + con, err := strconv.ParseInt(tokens[q][5], 10, 32) + if err != nil { + return buf.String(), err + } + ps.st.push(con) + case tokens[q][0][:2] == "%l": + // Push the length of the string that is popped from the stack. + popStr, err := ps.st.pop() + if err != nil { + return buf.String(), err + } + if _, ok := popStr.(string); !ok { + errStr := fmt.Sprintf("Stack head is not a string") + return buf.String(), errors.New(errStr) + } + ps.st.push(len(popStr.(string))) + case tokens[q][0][:2] == "%?": + // If-then-else construct. First, the whole string is identified and + // then inside this substring, we can specify which parts to switch on. + ifReg, _ := regexp.Compile("%\\?(.*)%t(.*)%e(.*);|%\\?(.*)%t(.*);") + ifTokens := ifReg.FindStringSubmatch(tokens[q][0]) + var ( + ifStr string + err error + ) + // Parse the if-part to determine if-else. + if len(ifTokens[1]) > 0 { + ifStr, err = ps.walk(ifTokens[1]) + } else { // else + ifStr, err = ps.walk(ifTokens[4]) + } + // Return any errors + if err != nil { + return buf.String(), err + } else if len(ifStr) > 0 { + // Self-defined limitation, not sure if this is correct, but didn't + // seem like it. + return buf.String(), errors.New("If-clause cannot print statements") + } + var thenStr string + // Pop the first value that is set by parsing the if-clause. + choose, err := ps.st.pop() + if err != nil { + return buf.String(), err + } + // Switch to if or else. + if choose.(int) == 0 && len(ifTokens[1]) > 0 { + thenStr, err = ps.walk(ifTokens[3]) + } else if choose.(int) != 0 { + if len(ifTokens[1]) > 0 { + thenStr, err = ps.walk(ifTokens[2]) + } else { + thenStr, err = ps.walk(ifTokens[5]) + } + } + if err != nil { + return buf.String(), err + } + buf.WriteString(thenStr) + case tokens[q][0][len(tokens[q][0])-1] == 'd': // Fallthrough for printing + fallthrough + case tokens[q][0][len(tokens[q][0])-1] == 'o': // digits. + fallthrough + case tokens[q][0][len(tokens[q][0])-1] == 'x': + fallthrough + case tokens[q][0][len(tokens[q][0])-1] == 'X': + fallthrough + case tokens[q][0][len(tokens[q][0])-1] == 's': + token := tokens[q][0] + // Remove the : that comes before a flag. + if token[1] == ':' { + token = token[:1] + token[2:] + } + digit, err := ps.st.pop() + if err != nil { + return buf.String(), err + } + // The rest is determined like the normal formatted prints. + digitStr := fmt.Sprintf(token, digit.(int)) + buf.WriteString(digitStr) + case tokens[q][0][:2] == "%i": + // Increment the parameters by one. + if len(ps.parameters) < 2 { + return buf.String(), errors.New("Not enough parameters to increment.") + } + val1, val2 := ps.parameters[0].(int), ps.parameters[1].(int) + val1++ + val2++ + ps.parameters[0], ps.parameters[1] = val1, val2 + default: + // The rest of the tokens is a special case, where two values are + // popped and then operated on by the token that comes after them. + op1, err := ps.st.pop() + if err != nil { + return buf.String(), err + } + op2, err := ps.st.pop() + if err != nil { + return buf.String(), err + } + var result stacker + switch tokens[q][0][:2] { + case "%+": + // Addition + result = op2.(int) + op1.(int) + case "%-": + // Subtraction + result = op2.(int) - op1.(int) + case "%*": + // Multiplication + result = op2.(int) * op1.(int) + case "%/": + // Division + result = op2.(int) / op1.(int) + case "%m": + // Modulo + result = op2.(int) % op1.(int) + case "%&": + // Bitwise AND + result = op2.(int) & op1.(int) + case "%|": + // Bitwise OR + result = op2.(int) | op1.(int) + case "%^": + // Bitwise XOR + result = op2.(int) ^ op1.(int) + case "%=": + // Equals + result = op2 == op1 + case "%>": + // Greater-than + result = op2.(int) > op1.(int) + case "%<": + // Lesser-than + result = op2.(int) < op1.(int) + case "%A": + // Logical AND + result = op2.(bool) && op1.(bool) + case "%O": + // Logical OR + result = op2.(bool) || op1.(bool) + case "%!": + // Logical complement + result = !op1.(bool) + case "%~": + // Bitwise complement + result = ^(op1.(int)) + } + ps.st.push(result) + } + + i = indices[q][1] - 1 + q++ + } else { + // We are not "inside" a token, so just skip until the end or the next + // token, and add all characters to the buffer. + j := i + if q != len(indices) { + for !(j >= indices[q][0] && j < indices[q][1]) { + j++ + } + } else { + j = len(attr) + } + buf.WriteString(string(attr[i:j])) + i = j + } + } + // Return the buffer as a string. + return buf.String(), nil +} + +// Push a stacker-value onto the stack. +func (st *stack) push(s stacker) { + *st = append(*st, s) +} + +// Pop a stacker-value from the stack. +func (st *stack) pop() (stacker, error) { + if len(*st) == 0 { + return nil, errors.New("Stack is empty.") + } + newStack := make(stack, len(*st)-1) + val := (*st)[len(*st)-1] + copy(newStack, (*st)[:len(*st)-1]) + *st = newStack + return val, nil +} + +// Initialize regexes and the static vars (that don't get changed between +// calls. +func init() { + // Initialize the main regex. + expStr := strings.Join(exp[:], "|") + regex, _ = regexp.Compile(expStr) + // Initialize the static variables. + staticVar = make(map[byte]stacker, 26) +} diff --git a/vendor/github.com/Nvveen/Gotty/types.go b/vendor/github.com/Nvveen/Gotty/types.go new file mode 100644 index 000000000..9bcc65e9b --- /dev/null +++ b/vendor/github.com/Nvveen/Gotty/types.go @@ -0,0 +1,23 @@ +// Copyright 2012 Neal van Veen. All rights reserved. +// Usage of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package gotty + +type TermInfo struct { + boolAttributes map[string]bool + numAttributes map[string]int16 + strAttributes map[string]string + // The various names of the TermInfo file. + Names []string +} + +type stacker interface { +} +type stack []stacker + +type parser struct { + st stack + parameters []stacker + dynamicVar map[byte]stacker +} diff --git a/vendor/github.com/PuerkitoBio/purell/.gitignore b/vendor/github.com/PuerkitoBio/purell/.gitignore new file mode 100644 index 000000000..748e4c807 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/.gitignore @@ -0,0 +1,5 @@ +*.sublime-* +.DS_Store +*.swp +*.swo +tags diff --git a/vendor/github.com/PuerkitoBio/purell/.travis.yml b/vendor/github.com/PuerkitoBio/purell/.travis.yml new file mode 100644 index 000000000..facfc91c6 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/.travis.yml @@ -0,0 +1,7 @@ +language: go + +go: + - 1.4 + - 1.5 + - 1.6 + - tip diff --git a/vendor/github.com/PuerkitoBio/purell/LICENSE b/vendor/github.com/PuerkitoBio/purell/LICENSE new file mode 100644 index 000000000..4b9986dea --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/LICENSE @@ -0,0 +1,12 @@ +Copyright (c) 2012, Martin Angers +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/PuerkitoBio/purell/README.md b/vendor/github.com/PuerkitoBio/purell/README.md new file mode 100644 index 000000000..a78a3df65 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/README.md @@ -0,0 +1,185 @@ +# Purell + +Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know... + +Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc]. + +[![build status](https://secure.travis-ci.org/PuerkitoBio/purell.png)](http://travis-ci.org/PuerkitoBio/purell) + +## Install + +`go get github.com/PuerkitoBio/purell` + +## Changelog + +* **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich). +* **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]). +* **v0.2.0** : Add benchmarks, Attempt IDN support. +* **v0.1.0** : Initial release. + +## Examples + +From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."): + +```go +package purell + +import ( + "fmt" + "net/url" +) + +func ExampleNormalizeURLString() { + if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/", + FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil { + panic(err) + } else { + fmt.Print(normalized) + } + // Output: http://somewebsite.com:80/Amazing%3F/url/ +} + +func ExampleMustNormalizeURLString() { + normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/", + FlagsUnsafeGreedy) + fmt.Print(normalized) + + // Output: http://somewebsite.com/Amazing%FA/url +} + +func ExampleNormalizeURL() { + if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil { + panic(err) + } else { + normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment) + fmt.Print(normalized) + } + + // Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0 +} +``` + +## API + +As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags: + +```go +const ( + // Safe normalizations + FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1 + FlagLowercaseHost // http://HOST -> http://host + FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF + FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA + FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$ + FlagRemoveDefaultPort // http://host:80 -> http://host + FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path + + // Usually safe normalizations + FlagRemoveTrailingSlash // http://host/path/ -> http://host/path + FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags) + FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c + + // Unsafe normalizations + FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/ + FlagRemoveFragment // http://host/path#fragment -> http://host/path + FlagForceHTTP // https://host -> http://host + FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b + FlagRemoveWWW // http://www.host/ -> http://host/ + FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags) + FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3 + + // Normalizations not in the wikipedia article, required to cover tests cases + // submitted by jehiah + FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147 + FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147 + FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147 + FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path + FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path + + // Convenience set of safe normalizations + FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator + + // For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags, + // while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix". + + // Convenience set of usually safe normalizations (includes FlagsSafe) + FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments + FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments + + // Convenience set of unsafe normalizations (includes FlagsUsuallySafe) + FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery + FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery + + // Convenience set of all available flags + FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator + FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator +) +``` + +For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set. + +The [full godoc reference is available on gopkgdoc][godoc]. + +Some things to note: + +* `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it. + +* The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*): + - %24 -> $ + - %26 -> & + - %2B-%3B -> +,-./0123456789:; + - %3D -> = + - %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ + - %5F -> _ + - %61-%7A -> abcdefghijklmnopqrstuvwxyz + - %7E -> ~ + + +* When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization). + +* The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell. + +* The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object. + +### Safe vs Usually Safe vs Unsafe + +Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between. + +Consider the following URL: + +`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid` + +Normalizing with the `FlagsSafe` gives: + +`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid` + +With the `FlagsUsuallySafeGreedy`: + +`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid` + +And with `FlagsUnsafeGreedy`: + +`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3` + +## TODOs + +* Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`. + +## Thanks / Contributions + +@rogpeppe +@jehiah +@opennota +@pchristopher1275 +@zenovich + +## License + +The [BSD 3-Clause license][bsd]. + +[bsd]: http://opensource.org/licenses/BSD-3-Clause +[wiki]: http://en.wikipedia.org/wiki/URL_normalization +[rfc]: http://tools.ietf.org/html/rfc3986#section-6 +[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell +[pr5]: https://github.com/PuerkitoBio/purell/pull/5 +[iss7]: https://github.com/PuerkitoBio/purell/issues/7 diff --git a/vendor/github.com/PuerkitoBio/purell/purell.go b/vendor/github.com/PuerkitoBio/purell/purell.go new file mode 100644 index 000000000..b79da64b3 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/purell.go @@ -0,0 +1,375 @@ +/* +Package purell offers URL normalization as described on the wikipedia page: +http://en.wikipedia.org/wiki/URL_normalization +*/ +package purell + +import ( + "bytes" + "fmt" + "net/url" + "regexp" + "sort" + "strconv" + "strings" + + "github.com/PuerkitoBio/urlesc" + "golang.org/x/net/idna" + "golang.org/x/text/secure/precis" + "golang.org/x/text/unicode/norm" +) + +// A set of normalization flags determines how a URL will +// be normalized. +type NormalizationFlags uint + +const ( + // Safe normalizations + FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1 + FlagLowercaseHost // http://HOST -> http://host + FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF + FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA + FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$ + FlagRemoveDefaultPort // http://host:80 -> http://host + FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path + + // Usually safe normalizations + FlagRemoveTrailingSlash // http://host/path/ -> http://host/path + FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags) + FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c + + // Unsafe normalizations + FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/ + FlagRemoveFragment // http://host/path#fragment -> http://host/path + FlagForceHTTP // https://host -> http://host + FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b + FlagRemoveWWW // http://www.host/ -> http://host/ + FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags) + FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3 + + // Normalizations not in the wikipedia article, required to cover tests cases + // submitted by jehiah + FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147 + FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147 + FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147 + FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path + FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path + + // Convenience set of safe normalizations + FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator + + // For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags, + // while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix". + + // Convenience set of usually safe normalizations (includes FlagsSafe) + FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments + FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments + + // Convenience set of unsafe normalizations (includes FlagsUsuallySafe) + FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery + FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery + + // Convenience set of all available flags + FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator + FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator +) + +const ( + defaultHttpPort = ":80" + defaultHttpsPort = ":443" +) + +// Regular expressions used by the normalizations +var rxPort = regexp.MustCompile(`(:\d+)/?$`) +var rxDirIndex = regexp.MustCompile(`(^|/)((?:default|index)\.\w{1,4})$`) +var rxDupSlashes = regexp.MustCompile(`/{2,}`) +var rxDWORDHost = regexp.MustCompile(`^(\d+)((?:\.+)?(?:\:\d*)?)$`) +var rxOctalHost = regexp.MustCompile(`^(0\d*)\.(0\d*)\.(0\d*)\.(0\d*)((?:\.+)?(?:\:\d*)?)$`) +var rxHexHost = regexp.MustCompile(`^0x([0-9A-Fa-f]+)((?:\.+)?(?:\:\d*)?)$`) +var rxHostDots = regexp.MustCompile(`^(.+?)(:\d+)?$`) +var rxEmptyPort = regexp.MustCompile(`:+$`) + +// Map of flags to implementation function. +// FlagDecodeUnnecessaryEscapes has no action, since it is done automatically +// by parsing the string as an URL. Same for FlagUppercaseEscapes and FlagRemoveEmptyQuerySeparator. + +// Since maps have undefined traversing order, make a slice of ordered keys +var flagsOrder = []NormalizationFlags{ + FlagLowercaseScheme, + FlagLowercaseHost, + FlagRemoveDefaultPort, + FlagRemoveDirectoryIndex, + FlagRemoveDotSegments, + FlagRemoveFragment, + FlagForceHTTP, // Must be after remove default port (because https=443/http=80) + FlagRemoveDuplicateSlashes, + FlagRemoveWWW, + FlagAddWWW, + FlagSortQuery, + FlagDecodeDWORDHost, + FlagDecodeOctalHost, + FlagDecodeHexHost, + FlagRemoveUnnecessaryHostDots, + FlagRemoveEmptyPortSeparator, + FlagRemoveTrailingSlash, // These two (add/remove trailing slash) must be last + FlagAddTrailingSlash, +} + +// ... and then the map, where order is unimportant +var flags = map[NormalizationFlags]func(*url.URL){ + FlagLowercaseScheme: lowercaseScheme, + FlagLowercaseHost: lowercaseHost, + FlagRemoveDefaultPort: removeDefaultPort, + FlagRemoveDirectoryIndex: removeDirectoryIndex, + FlagRemoveDotSegments: removeDotSegments, + FlagRemoveFragment: removeFragment, + FlagForceHTTP: forceHTTP, + FlagRemoveDuplicateSlashes: removeDuplicateSlashes, + FlagRemoveWWW: removeWWW, + FlagAddWWW: addWWW, + FlagSortQuery: sortQuery, + FlagDecodeDWORDHost: decodeDWORDHost, + FlagDecodeOctalHost: decodeOctalHost, + FlagDecodeHexHost: decodeHexHost, + FlagRemoveUnnecessaryHostDots: removeUnncessaryHostDots, + FlagRemoveEmptyPortSeparator: removeEmptyPortSeparator, + FlagRemoveTrailingSlash: removeTrailingSlash, + FlagAddTrailingSlash: addTrailingSlash, +} + +// MustNormalizeURLString returns the normalized string, and panics if an error occurs. +// It takes an URL string as input, as well as the normalization flags. +func MustNormalizeURLString(u string, f NormalizationFlags) string { + result, e := NormalizeURLString(u, f) + if e != nil { + panic(e) + } + return result +} + +// NormalizeURLString returns the normalized string, or an error if it can't be parsed into an URL object. +// It takes an URL string as input, as well as the normalization flags. +func NormalizeURLString(u string, f NormalizationFlags) (string, error) { + if parsed, e := url.Parse(u); e != nil { + return "", e + } else { + options := make([]precis.Option, 1, 3) + options[0] = precis.IgnoreCase + if f&FlagLowercaseHost == FlagLowercaseHost { + options = append(options, precis.FoldCase()) + } + options = append(options, precis.Norm(norm.NFC)) + profile := precis.NewFreeform(options...) + if parsed.Host, e = idna.ToASCII(profile.NewTransformer().String(parsed.Host)); e != nil { + return "", e + } + return NormalizeURL(parsed, f), nil + } + panic("Unreachable code.") +} + +// NormalizeURL returns the normalized string. +// It takes a parsed URL object as input, as well as the normalization flags. +func NormalizeURL(u *url.URL, f NormalizationFlags) string { + for _, k := range flagsOrder { + if f&k == k { + flags[k](u) + } + } + return urlesc.Escape(u) +} + +func lowercaseScheme(u *url.URL) { + if len(u.Scheme) > 0 { + u.Scheme = strings.ToLower(u.Scheme) + } +} + +func lowercaseHost(u *url.URL) { + if len(u.Host) > 0 { + u.Host = strings.ToLower(u.Host) + } +} + +func removeDefaultPort(u *url.URL) { + if len(u.Host) > 0 { + scheme := strings.ToLower(u.Scheme) + u.Host = rxPort.ReplaceAllStringFunc(u.Host, func(val string) string { + if (scheme == "http" && val == defaultHttpPort) || (scheme == "https" && val == defaultHttpsPort) { + return "" + } + return val + }) + } +} + +func removeTrailingSlash(u *url.URL) { + if l := len(u.Path); l > 0 { + if strings.HasSuffix(u.Path, "/") { + u.Path = u.Path[:l-1] + } + } else if l = len(u.Host); l > 0 { + if strings.HasSuffix(u.Host, "/") { + u.Host = u.Host[:l-1] + } + } +} + +func addTrailingSlash(u *url.URL) { + if l := len(u.Path); l > 0 { + if !strings.HasSuffix(u.Path, "/") { + u.Path += "/" + } + } else if l = len(u.Host); l > 0 { + if !strings.HasSuffix(u.Host, "/") { + u.Host += "/" + } + } +} + +func removeDotSegments(u *url.URL) { + if len(u.Path) > 0 { + var dotFree []string + var lastIsDot bool + + sections := strings.Split(u.Path, "/") + for _, s := range sections { + if s == ".." { + if len(dotFree) > 0 { + dotFree = dotFree[:len(dotFree)-1] + } + } else if s != "." { + dotFree = append(dotFree, s) + } + lastIsDot = (s == "." || s == "..") + } + // Special case if host does not end with / and new path does not begin with / + u.Path = strings.Join(dotFree, "/") + if u.Host != "" && !strings.HasSuffix(u.Host, "/") && !strings.HasPrefix(u.Path, "/") { + u.Path = "/" + u.Path + } + // Special case if the last segment was a dot, make sure the path ends with a slash + if lastIsDot && !strings.HasSuffix(u.Path, "/") { + u.Path += "/" + } + } +} + +func removeDirectoryIndex(u *url.URL) { + if len(u.Path) > 0 { + u.Path = rxDirIndex.ReplaceAllString(u.Path, "$1") + } +} + +func removeFragment(u *url.URL) { + u.Fragment = "" +} + +func forceHTTP(u *url.URL) { + if strings.ToLower(u.Scheme) == "https" { + u.Scheme = "http" + } +} + +func removeDuplicateSlashes(u *url.URL) { + if len(u.Path) > 0 { + u.Path = rxDupSlashes.ReplaceAllString(u.Path, "/") + } +} + +func removeWWW(u *url.URL) { + if len(u.Host) > 0 && strings.HasPrefix(strings.ToLower(u.Host), "www.") { + u.Host = u.Host[4:] + } +} + +func addWWW(u *url.URL) { + if len(u.Host) > 0 && !strings.HasPrefix(strings.ToLower(u.Host), "www.") { + u.Host = "www." + u.Host + } +} + +func sortQuery(u *url.URL) { + q := u.Query() + + if len(q) > 0 { + arKeys := make([]string, len(q)) + i := 0 + for k, _ := range q { + arKeys[i] = k + i++ + } + sort.Strings(arKeys) + buf := new(bytes.Buffer) + for _, k := range arKeys { + sort.Strings(q[k]) + for _, v := range q[k] { + if buf.Len() > 0 { + buf.WriteRune('&') + } + buf.WriteString(fmt.Sprintf("%s=%s", k, urlesc.QueryEscape(v))) + } + } + + // Rebuild the raw query string + u.RawQuery = buf.String() + } +} + +func decodeDWORDHost(u *url.URL) { + if len(u.Host) > 0 { + if matches := rxDWORDHost.FindStringSubmatch(u.Host); len(matches) > 2 { + var parts [4]int64 + + dword, _ := strconv.ParseInt(matches[1], 10, 0) + for i, shift := range []uint{24, 16, 8, 0} { + parts[i] = dword >> shift & 0xFF + } + u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[2]) + } + } +} + +func decodeOctalHost(u *url.URL) { + if len(u.Host) > 0 { + if matches := rxOctalHost.FindStringSubmatch(u.Host); len(matches) > 5 { + var parts [4]int64 + + for i := 1; i <= 4; i++ { + parts[i-1], _ = strconv.ParseInt(matches[i], 8, 0) + } + u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[5]) + } + } +} + +func decodeHexHost(u *url.URL) { + if len(u.Host) > 0 { + if matches := rxHexHost.FindStringSubmatch(u.Host); len(matches) > 2 { + // Conversion is safe because of regex validation + parsed, _ := strconv.ParseInt(matches[1], 16, 0) + // Set host as DWORD (base 10) encoded host + u.Host = fmt.Sprintf("%d%s", parsed, matches[2]) + // The rest is the same as decoding a DWORD host + decodeDWORDHost(u) + } + } +} + +func removeUnncessaryHostDots(u *url.URL) { + if len(u.Host) > 0 { + if matches := rxHostDots.FindStringSubmatch(u.Host); len(matches) > 1 { + // Trim the leading and trailing dots + u.Host = strings.Trim(matches[1], ".") + if len(matches) > 2 { + u.Host += matches[2] + } + } + } +} + +func removeEmptyPortSeparator(u *url.URL) { + if len(u.Host) > 0 { + u.Host = rxEmptyPort.ReplaceAllString(u.Host, "") + } +} diff --git a/vendor/github.com/PuerkitoBio/urlesc/.travis.yml b/vendor/github.com/PuerkitoBio/urlesc/.travis.yml new file mode 100644 index 000000000..478630e50 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/urlesc/.travis.yml @@ -0,0 +1,11 @@ +language: go + +go: + - 1.4 + - tip + +install: + - go build . + +script: + - go test -v diff --git a/vendor/github.com/PuerkitoBio/urlesc/LICENSE b/vendor/github.com/PuerkitoBio/urlesc/LICENSE new file mode 100644 index 000000000..744875676 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/urlesc/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/PuerkitoBio/urlesc/README.md b/vendor/github.com/PuerkitoBio/urlesc/README.md new file mode 100644 index 000000000..bebe305e0 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/urlesc/README.md @@ -0,0 +1,16 @@ +urlesc [![Build Status](https://travis-ci.org/PuerkitoBio/urlesc.png?branch=master)](https://travis-ci.org/PuerkitoBio/urlesc) [![GoDoc](http://godoc.org/github.com/PuerkitoBio/urlesc?status.svg)](http://godoc.org/github.com/PuerkitoBio/urlesc) +====== + +Package urlesc implements query escaping as per RFC 3986. + +It contains some parts of the net/url package, modified so as to allow +some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)). + +## Install + + go get github.com/PuerkitoBio/urlesc + +## License + +Go license (BSD-3-Clause) + diff --git a/vendor/github.com/PuerkitoBio/urlesc/urlesc.go b/vendor/github.com/PuerkitoBio/urlesc/urlesc.go new file mode 100644 index 000000000..1b8462459 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/urlesc/urlesc.go @@ -0,0 +1,180 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package urlesc implements query escaping as per RFC 3986. +// It contains some parts of the net/url package, modified so as to allow +// some reserved characters incorrectly escaped by net/url. +// See https://github.com/golang/go/issues/5684 +package urlesc + +import ( + "bytes" + "net/url" + "strings" +) + +type encoding int + +const ( + encodePath encoding = 1 + iota + encodeUserPassword + encodeQueryComponent + encodeFragment +) + +// Return true if the specified character should be escaped when +// appearing in a URL string, according to RFC 3986. +func shouldEscape(c byte, mode encoding) bool { + // §2.3 Unreserved characters (alphanum) + if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' { + return false + } + + switch c { + case '-', '.', '_', '~': // §2.3 Unreserved characters (mark) + return false + + // §2.2 Reserved characters (reserved) + case ':', '/', '?', '#', '[', ']', '@', // gen-delims + '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': // sub-delims + // Different sections of the URL allow a few of + // the reserved characters to appear unescaped. + switch mode { + case encodePath: // §3.3 + // The RFC allows sub-delims and : @. + // '/', '[' and ']' can be used to assign meaning to individual path + // segments. This package only manipulates the path as a whole, + // so we allow those as well. That leaves only ? and # to escape. + return c == '?' || c == '#' + + case encodeUserPassword: // §3.2.1 + // The RFC allows : and sub-delims in + // userinfo. The parsing of userinfo treats ':' as special so we must escape + // all the gen-delims. + return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@' + + case encodeQueryComponent: // §3.4 + // The RFC allows / and ?. + return c != '/' && c != '?' + + case encodeFragment: // §4.1 + // The RFC text is silent but the grammar allows + // everything, so escape nothing but # + return c == '#' + } + } + + // Everything else must be escaped. + return true +} + +// QueryEscape escapes the string so it can be safely placed +// inside a URL query. +func QueryEscape(s string) string { + return escape(s, encodeQueryComponent) +} + +func escape(s string, mode encoding) string { + spaceCount, hexCount := 0, 0 + for i := 0; i < len(s); i++ { + c := s[i] + if shouldEscape(c, mode) { + if c == ' ' && mode == encodeQueryComponent { + spaceCount++ + } else { + hexCount++ + } + } + } + + if spaceCount == 0 && hexCount == 0 { + return s + } + + t := make([]byte, len(s)+2*hexCount) + j := 0 + for i := 0; i < len(s); i++ { + switch c := s[i]; { + case c == ' ' && mode == encodeQueryComponent: + t[j] = '+' + j++ + case shouldEscape(c, mode): + t[j] = '%' + t[j+1] = "0123456789ABCDEF"[c>>4] + t[j+2] = "0123456789ABCDEF"[c&15] + j += 3 + default: + t[j] = s[i] + j++ + } + } + return string(t) +} + +var uiReplacer = strings.NewReplacer( + "%21", "!", + "%27", "'", + "%28", "(", + "%29", ")", + "%2A", "*", +) + +// unescapeUserinfo unescapes some characters that need not to be escaped as per RFC3986. +func unescapeUserinfo(s string) string { + return uiReplacer.Replace(s) +} + +// Escape reassembles the URL into a valid URL string. +// The general form of the result is one of: +// +// scheme:opaque +// scheme://userinfo@host/path?query#fragment +// +// If u.Opaque is non-empty, String uses the first form; +// otherwise it uses the second form. +// +// In the second form, the following rules apply: +// - if u.Scheme is empty, scheme: is omitted. +// - if u.User is nil, userinfo@ is omitted. +// - if u.Host is empty, host/ is omitted. +// - if u.Scheme and u.Host are empty and u.User is nil, +// the entire scheme://userinfo@host/ is omitted. +// - if u.Host is non-empty and u.Path begins with a /, +// the form host/path does not add its own /. +// - if u.RawQuery is empty, ?query is omitted. +// - if u.Fragment is empty, #fragment is omitted. +func Escape(u *url.URL) string { + var buf bytes.Buffer + if u.Scheme != "" { + buf.WriteString(u.Scheme) + buf.WriteByte(':') + } + if u.Opaque != "" { + buf.WriteString(u.Opaque) + } else { + if u.Scheme != "" || u.Host != "" || u.User != nil { + buf.WriteString("//") + if ui := u.User; ui != nil { + buf.WriteString(unescapeUserinfo(ui.String())) + buf.WriteByte('@') + } + if h := u.Host; h != "" { + buf.WriteString(h) + } + } + if u.Path != "" && u.Path[0] != '/' && u.Host != "" { + buf.WriteByte('/') + } + buf.WriteString(escape(u.Path, encodePath)) + } + if u.RawQuery != "" { + buf.WriteByte('?') + buf.WriteString(u.RawQuery) + } + if u.Fragment != "" { + buf.WriteByte('#') + buf.WriteString(escape(u.Fragment, encodeFragment)) + } + return buf.String() +} diff --git a/vendor/github.com/cenkalti/backoff/.gitignore b/vendor/github.com/cenkalti/backoff/.gitignore new file mode 100644 index 000000000..00268614f --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/github.com/cenkalti/backoff/.travis.yml b/vendor/github.com/cenkalti/backoff/.travis.yml new file mode 100644 index 000000000..1040404bf --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/.travis.yml @@ -0,0 +1,9 @@ +language: go +go: + - 1.3.3 + - tip +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover +script: + - $HOME/gopath/bin/goveralls -service=travis-ci diff --git a/vendor/github.com/cenkalti/backoff/LICENSE b/vendor/github.com/cenkalti/backoff/LICENSE new file mode 100644 index 000000000..89b817996 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Cenk Altı + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/cenkalti/backoff/README.md b/vendor/github.com/cenkalti/backoff/README.md new file mode 100644 index 000000000..13b347fb9 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/README.md @@ -0,0 +1,30 @@ +# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls] + +This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client]. + +[Exponential backoff][exponential backoff wiki] +is an algorithm that uses feedback to multiplicatively decrease the rate of some process, +in order to gradually find an acceptable rate. +The retries exponentially increase and stop increasing when a certain threshold is met. + +## Usage + +See https://godoc.org/github.com/cenkalti/backoff#pkg-examples + +## Contributing + +* I would like to keep this library as small as possible. +* Please don't send a PR without opening an issue and discussing it first. +* If proposed change is not a common use case, I will probably not accept it. + +[godoc]: https://godoc.org/github.com/cenkalti/backoff +[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png +[travis]: https://travis-ci.org/cenkalti/backoff +[travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master +[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master +[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master + +[google-http-java-client]: https://github.com/google/google-http-java-client +[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff + +[advanced example]: https://godoc.org/github.com/cenkalti/backoff#example_ diff --git a/vendor/github.com/cenkalti/backoff/backoff.go b/vendor/github.com/cenkalti/backoff/backoff.go new file mode 100644 index 000000000..2102c5f2d --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/backoff.go @@ -0,0 +1,66 @@ +// Package backoff implements backoff algorithms for retrying operations. +// +// Use Retry function for retrying operations that may fail. +// If Retry does not meet your needs, +// copy/paste the function into your project and modify as you wish. +// +// There is also Ticker type similar to time.Ticker. +// You can use it if you need to work with channels. +// +// See Examples section below for usage examples. +package backoff + +import "time" + +// BackOff is a backoff policy for retrying an operation. +type BackOff interface { + // NextBackOff returns the duration to wait before retrying the operation, + // or backoff.Stop to indicate that no more retries should be made. + // + // Example usage: + // + // duration := backoff.NextBackOff(); + // if (duration == backoff.Stop) { + // // Do not retry operation. + // } else { + // // Sleep for duration and retry operation. + // } + // + NextBackOff() time.Duration + + // Reset to initial state. + Reset() +} + +// Stop indicates that no more retries should be made for use in NextBackOff(). +const Stop time.Duration = -1 + +// ZeroBackOff is a fixed backoff policy whose backoff time is always zero, +// meaning that the operation is retried immediately without waiting, indefinitely. +type ZeroBackOff struct{} + +func (b *ZeroBackOff) Reset() {} + +func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 } + +// StopBackOff is a fixed backoff policy that always returns backoff.Stop for +// NextBackOff(), meaning that the operation should never be retried. +type StopBackOff struct{} + +func (b *StopBackOff) Reset() {} + +func (b *StopBackOff) NextBackOff() time.Duration { return Stop } + +// ConstantBackOff is a backoff policy that always returns the same backoff delay. +// This is in contrast to an exponential backoff policy, +// which returns a delay that grows longer as you call NextBackOff() over and over again. +type ConstantBackOff struct { + Interval time.Duration +} + +func (b *ConstantBackOff) Reset() {} +func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval } + +func NewConstantBackOff(d time.Duration) *ConstantBackOff { + return &ConstantBackOff{Interval: d} +} diff --git a/vendor/github.com/cenkalti/backoff/context.go b/vendor/github.com/cenkalti/backoff/context.go new file mode 100644 index 000000000..5d1570925 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/context.go @@ -0,0 +1,60 @@ +package backoff + +import ( + "time" + + "golang.org/x/net/context" +) + +// BackOffContext is a backoff policy that stops retrying after the context +// is canceled. +type BackOffContext interface { + BackOff + Context() context.Context +} + +type backOffContext struct { + BackOff + ctx context.Context +} + +// WithContext returns a BackOffContext with context ctx +// +// ctx must not be nil +func WithContext(b BackOff, ctx context.Context) BackOffContext { + if ctx == nil { + panic("nil context") + } + + if b, ok := b.(*backOffContext); ok { + return &backOffContext{ + BackOff: b.BackOff, + ctx: ctx, + } + } + + return &backOffContext{ + BackOff: b, + ctx: ctx, + } +} + +func ensureContext(b BackOff) BackOffContext { + if cb, ok := b.(BackOffContext); ok { + return cb + } + return WithContext(b, context.Background()) +} + +func (b *backOffContext) Context() context.Context { + return b.ctx +} + +func (b *backOffContext) NextBackOff() time.Duration { + select { + case <-b.Context().Done(): + return Stop + default: + return b.BackOff.NextBackOff() + } +} diff --git a/vendor/github.com/cenkalti/backoff/exponential.go b/vendor/github.com/cenkalti/backoff/exponential.go new file mode 100644 index 000000000..9a6addf07 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/exponential.go @@ -0,0 +1,156 @@ +package backoff + +import ( + "math/rand" + "time" +) + +/* +ExponentialBackOff is a backoff implementation that increases the backoff +period for each retry attempt using a randomization function that grows exponentially. + +NextBackOff() is calculated using the following formula: + + randomized interval = + RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor]) + +In other words NextBackOff() will range between the randomization factor +percentage below and above the retry interval. + +For example, given the following parameters: + + RetryInterval = 2 + RandomizationFactor = 0.5 + Multiplier = 2 + +the actual backoff period used in the next retry attempt will range between 1 and 3 seconds, +multiplied by the exponential, that is, between 2 and 6 seconds. + +Note: MaxInterval caps the RetryInterval and not the randomized interval. + +If the time elapsed since an ExponentialBackOff instance is created goes past the +MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop. + +The elapsed time can be reset by calling Reset(). + +Example: Given the following default arguments, for 10 tries the sequence will be, +and assuming we go over the MaxElapsedTime on the 10th try: + + Request # RetryInterval (seconds) Randomized Interval (seconds) + + 1 0.5 [0.25, 0.75] + 2 0.75 [0.375, 1.125] + 3 1.125 [0.562, 1.687] + 4 1.687 [0.8435, 2.53] + 5 2.53 [1.265, 3.795] + 6 3.795 [1.897, 5.692] + 7 5.692 [2.846, 8.538] + 8 8.538 [4.269, 12.807] + 9 12.807 [6.403, 19.210] + 10 19.210 backoff.Stop + +Note: Implementation is not thread-safe. +*/ +type ExponentialBackOff struct { + InitialInterval time.Duration + RandomizationFactor float64 + Multiplier float64 + MaxInterval time.Duration + // After MaxElapsedTime the ExponentialBackOff stops. + // It never stops if MaxElapsedTime == 0. + MaxElapsedTime time.Duration + Clock Clock + + currentInterval time.Duration + startTime time.Time + random *rand.Rand +} + +// Clock is an interface that returns current time for BackOff. +type Clock interface { + Now() time.Time +} + +// Default values for ExponentialBackOff. +const ( + DefaultInitialInterval = 500 * time.Millisecond + DefaultRandomizationFactor = 0.5 + DefaultMultiplier = 1.5 + DefaultMaxInterval = 60 * time.Second + DefaultMaxElapsedTime = 15 * time.Minute +) + +// NewExponentialBackOff creates an instance of ExponentialBackOff using default values. +func NewExponentialBackOff() *ExponentialBackOff { + b := &ExponentialBackOff{ + InitialInterval: DefaultInitialInterval, + RandomizationFactor: DefaultRandomizationFactor, + Multiplier: DefaultMultiplier, + MaxInterval: DefaultMaxInterval, + MaxElapsedTime: DefaultMaxElapsedTime, + Clock: SystemClock, + random: rand.New(rand.NewSource(time.Now().UnixNano())), + } + b.Reset() + return b +} + +type systemClock struct{} + +func (t systemClock) Now() time.Time { + return time.Now() +} + +// SystemClock implements Clock interface that uses time.Now(). +var SystemClock = systemClock{} + +// Reset the interval back to the initial retry interval and restarts the timer. +func (b *ExponentialBackOff) Reset() { + b.currentInterval = b.InitialInterval + b.startTime = b.Clock.Now() +} + +// NextBackOff calculates the next backoff interval using the formula: +// Randomized interval = RetryInterval +/- (RandomizationFactor * RetryInterval) +func (b *ExponentialBackOff) NextBackOff() time.Duration { + // Make sure we have not gone over the maximum elapsed time. + if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime { + return Stop + } + defer b.incrementCurrentInterval() + if b.random == nil { + b.random = rand.New(rand.NewSource(time.Now().UnixNano())) + } + return getRandomValueFromInterval(b.RandomizationFactor, b.random.Float64(), b.currentInterval) +} + +// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance +// is created and is reset when Reset() is called. +// +// The elapsed time is computed using time.Now().UnixNano(). +func (b *ExponentialBackOff) GetElapsedTime() time.Duration { + return b.Clock.Now().Sub(b.startTime) +} + +// Increments the current interval by multiplying it with the multiplier. +func (b *ExponentialBackOff) incrementCurrentInterval() { + // Check for overflow, if overflow is detected set the current interval to the max interval. + if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier { + b.currentInterval = b.MaxInterval + } else { + b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier) + } +} + +// Returns a random value from the following interval: +// [randomizationFactor * currentInterval, randomizationFactor * currentInterval]. +func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration { + var delta = randomizationFactor * float64(currentInterval) + var minInterval = float64(currentInterval) - delta + var maxInterval = float64(currentInterval) + delta + + // Get a random value from the range [minInterval, maxInterval]. + // The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then + // we want a 33% chance for selecting either 1, 2 or 3. + return time.Duration(minInterval + (random * (maxInterval - minInterval + 1))) +} diff --git a/vendor/github.com/cenkalti/backoff/retry.go b/vendor/github.com/cenkalti/backoff/retry.go new file mode 100644 index 000000000..5dbd825b5 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/retry.go @@ -0,0 +1,78 @@ +package backoff + +import "time" + +// An Operation is executing by Retry() or RetryNotify(). +// The operation will be retried using a backoff policy if it returns an error. +type Operation func() error + +// Notify is a notify-on-error function. It receives an operation error and +// backoff delay if the operation failed (with an error). +// +// NOTE that if the backoff policy stated to stop retrying, +// the notify function isn't called. +type Notify func(error, time.Duration) + +// Retry the operation o until it does not return error or BackOff stops. +// o is guaranteed to be run at least once. +// It is the caller's responsibility to reset b after Retry returns. +// +// If o returns a *PermanentError, the operation is not retried, and the +// wrapped error is returned. +// +// Retry sleeps the goroutine for the duration returned by BackOff after a +// failed operation returns. +func Retry(o Operation, b BackOff) error { return RetryNotify(o, b, nil) } + +// RetryNotify calls notify function with the error and wait duration +// for each failed attempt before sleep. +func RetryNotify(operation Operation, b BackOff, notify Notify) error { + var err error + var next time.Duration + + cb := ensureContext(b) + + b.Reset() + for { + if err = operation(); err == nil { + return nil + } + + if permanent, ok := err.(*PermanentError); ok { + return permanent.Err + } + + if next = b.NextBackOff(); next == Stop { + return err + } + + if notify != nil { + notify(err, next) + } + + t := time.NewTimer(next) + + select { + case <-cb.Context().Done(): + t.Stop() + return err + case <-t.C: + } + } +} + +// PermanentError signals that the operation should not be retried. +type PermanentError struct { + Err error +} + +func (e *PermanentError) Error() string { + return e.Err.Error() +} + +// Permanent wraps the given err in a *PermanentError. +func Permanent(err error) *PermanentError { + return &PermanentError{ + Err: err, + } +} diff --git a/vendor/github.com/cenkalti/backoff/ticker.go b/vendor/github.com/cenkalti/backoff/ticker.go new file mode 100644 index 000000000..49a99718d --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/ticker.go @@ -0,0 +1,81 @@ +package backoff + +import ( + "runtime" + "sync" + "time" +) + +// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff. +// +// Ticks will continue to arrive when the previous operation is still running, +// so operations that take a while to fail could run in quick succession. +type Ticker struct { + C <-chan time.Time + c chan time.Time + b BackOffContext + stop chan struct{} + stopOnce sync.Once +} + +// NewTicker returns a new Ticker containing a channel that will send the time at times +// specified by the BackOff argument. Ticker is guaranteed to tick at least once. +// The channel is closed when Stop method is called or BackOff stops. +func NewTicker(b BackOff) *Ticker { + c := make(chan time.Time) + t := &Ticker{ + C: c, + c: c, + b: ensureContext(b), + stop: make(chan struct{}), + } + go t.run() + runtime.SetFinalizer(t, (*Ticker).Stop) + return t +} + +// Stop turns off a ticker. After Stop, no more ticks will be sent. +func (t *Ticker) Stop() { + t.stopOnce.Do(func() { close(t.stop) }) +} + +func (t *Ticker) run() { + c := t.c + defer close(c) + t.b.Reset() + + // Ticker is guaranteed to tick at least once. + afterC := t.send(time.Now()) + + for { + if afterC == nil { + return + } + + select { + case tick := <-afterC: + afterC = t.send(tick) + case <-t.stop: + t.c = nil // Prevent future ticks from being sent to the channel. + return + case <-t.b.Context().Done(): + return + } + } +} + +func (t *Ticker) send(tick time.Time) <-chan time.Time { + select { + case t.c <- tick: + case <-t.stop: + return nil + } + + next := t.b.NextBackOff() + if next == Stop { + t.Stop() + return nil + } + + return time.After(next) +} diff --git a/vendor/github.com/cenkalti/backoff/tries.go b/vendor/github.com/cenkalti/backoff/tries.go new file mode 100644 index 000000000..d2da7308b --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/tries.go @@ -0,0 +1,35 @@ +package backoff + +import "time" + +/* +WithMaxTries creates a wrapper around another BackOff, which will +return Stop if NextBackOff() has been called too many times since +the last time Reset() was called + +Note: Implementation is not thread-safe. +*/ +func WithMaxTries(b BackOff, max uint64) BackOff { + return &backOffTries{delegate: b, maxTries: max} +} + +type backOffTries struct { + delegate BackOff + maxTries uint64 + numTries uint64 +} + +func (b *backOffTries) NextBackOff() time.Duration { + if b.maxTries > 0 { + if b.maxTries <= b.numTries { + return Stop + } + b.numTries++ + } + return b.delegate.NextBackOff() +} + +func (b *backOffTries) Reset() { + b.numTries = 0 + b.delegate.Reset() +} diff --git a/vendor/github.com/containerd/continuity/AUTHORS b/vendor/github.com/containerd/continuity/AUTHORS new file mode 100644 index 000000000..4043394cc --- /dev/null +++ b/vendor/github.com/containerd/continuity/AUTHORS @@ -0,0 +1,16 @@ +Aaron Lehmann +Akash Gupta +Akihiro Suda +Andrew Pennebaker +Brandon Philips +Christopher Jones +Daniel, Dao Quang Minh +Derek McGowan +Edward Pilatowicz +Ian Campbell +Justin Cormack +Justin Cummins +Phil Estes +Stephen J Day +Tobias Klauser +Tonis Tiigi diff --git a/vendor/github.com/containerd/continuity/LICENSE b/vendor/github.com/containerd/continuity/LICENSE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/vendor/github.com/containerd/continuity/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/containerd/continuity/pathdriver/path_driver.go b/vendor/github.com/containerd/continuity/pathdriver/path_driver.go new file mode 100644 index 000000000..b43d55fe9 --- /dev/null +++ b/vendor/github.com/containerd/continuity/pathdriver/path_driver.go @@ -0,0 +1,85 @@ +package pathdriver + +import ( + "path/filepath" +) + +// PathDriver provides all of the path manipulation functions in a common +// interface. The context should call these and never use the `filepath` +// package or any other package to manipulate paths. +type PathDriver interface { + Join(paths ...string) string + IsAbs(path string) bool + Rel(base, target string) (string, error) + Base(path string) string + Dir(path string) string + Clean(path string) string + Split(path string) (dir, file string) + Separator() byte + Abs(path string) (string, error) + Walk(string, filepath.WalkFunc) error + FromSlash(path string) string + ToSlash(path string) string + Match(pattern, name string) (matched bool, err error) +} + +// pathDriver is a simple default implementation calls the filepath package. +type pathDriver struct{} + +// LocalPathDriver is the exported pathDriver struct for convenience. +var LocalPathDriver PathDriver = &pathDriver{} + +func (*pathDriver) Join(paths ...string) string { + return filepath.Join(paths...) +} + +func (*pathDriver) IsAbs(path string) bool { + return filepath.IsAbs(path) +} + +func (*pathDriver) Rel(base, target string) (string, error) { + return filepath.Rel(base, target) +} + +func (*pathDriver) Base(path string) string { + return filepath.Base(path) +} + +func (*pathDriver) Dir(path string) string { + return filepath.Dir(path) +} + +func (*pathDriver) Clean(path string) string { + return filepath.Clean(path) +} + +func (*pathDriver) Split(path string) (dir, file string) { + return filepath.Split(path) +} + +func (*pathDriver) Separator() byte { + return filepath.Separator +} + +func (*pathDriver) Abs(path string) (string, error) { + return filepath.Abs(path) +} + +// Note that filepath.Walk calls os.Stat, so if the context wants to +// to call Driver.Stat() for Walk, they need to create a new struct that +// overrides this method. +func (*pathDriver) Walk(root string, walkFn filepath.WalkFunc) error { + return filepath.Walk(root, walkFn) +} + +func (*pathDriver) FromSlash(path string) string { + return filepath.FromSlash(path) +} + +func (*pathDriver) ToSlash(path string) string { + return filepath.ToSlash(path) +} + +func (*pathDriver) Match(pattern, name string) (bool, error) { + return filepath.Match(pattern, name) +} diff --git a/vendor/github.com/docker/docker/AUTHORS b/vendor/github.com/docker/docker/AUTHORS new file mode 100644 index 000000000..46102d740 --- /dev/null +++ b/vendor/github.com/docker/docker/AUTHORS @@ -0,0 +1,1984 @@ +# This file lists all individuals having contributed content to the repository. +# For how it is generated, see `hack/generate-authors.sh`. + +Aanand Prasad +Aaron Davidson +Aaron Feng +Aaron Huslage +Aaron L. Xu +Aaron Lehmann +Aaron Welch +Aaron.L.Xu +Abel Muiño +Abhijeet Kasurde +Abhinandan Prativadi +Abhinav Ajgaonkar +Abhishek Chanda +Abhishek Sharma +Abin Shahab +Adam Avilla +Adam Eijdenberg +Adam Kunk +Adam Miller +Adam Mills +Adam Pointer +Adam Singer +Adam Walz +Addam Hardy +Aditi Rajagopal +Aditya +Adnan Khan +Adolfo Ochagavía +Adria Casas +Adrian Moisey +Adrian Mouat +Adrian Oprea +Adrien Folie +Adrien Gallouët +Ahmed Kamal +Ahmet Alp Balkan +Aidan Feldman +Aidan Hobson Sayers +AJ Bowen +Ajey Charantimath +ajneu +Akash Gupta +Akihiro Matsushima +Akihiro Suda +Akim Demaille +Akira Koyasu +Akshay Karle +Al Tobey +alambike +Alan Scherger +Alan Thompson +Albert Callarisa +Albert Zhang +Alejandro González Hevia +Aleksa Sarai +Aleksandrs Fadins +Alena Prokharchyk +Alessandro Boch +Alessio Biancalana +Alex Chan +Alex Chen +Alex Coventry +Alex Crawford +Alex Ellis +Alex Gaynor +Alex Goodman +Alex Olshansky +Alex Samorukov +Alex Warhawk +Alexander Artemenko +Alexander Boyd +Alexander Larsson +Alexander Midlash +Alexander Morozov +Alexander Shopov +Alexandre Beslic +Alexandre Garnier +Alexandre González +Alexandre Jomin +Alexandru Sfirlogea +Alexey Guskov +Alexey Kotlyarov +Alexey Shamrin +Alexis THOMAS +Alfred Landrum +Ali Dehghani +Alicia Lauerman +Alihan Demir +Allen Madsen +Allen Sun +almoehi +Alvaro Saurin +Alvin Deng +Alvin Richards +amangoel +Amen Belayneh +Amir Goldstein +Amit Bakshi +Amit Krishnan +Amit Shukla +Amr Gawish +Amy Lindburg +Anand Patil +AnandkumarPatel +Anatoly Borodin +Anchal Agrawal +Anda Xu +Anders Janmyr +Andre Dublin <81dublin@gmail.com> +Andre Granovsky +Andrea Luzzardi +Andrea Turli +Andreas Elvers +Andreas Köhler +Andreas Savvides +Andreas Tiefenthaler +Andrei Gherzan +Andrew C. Bodine +Andrew Clay Shafer +Andrew Duckworth +Andrew France +Andrew Gerrand +Andrew Guenther +Andrew He +Andrew Hsu +Andrew Kuklewicz +Andrew Macgregor +Andrew Macpherson +Andrew Martin +Andrew McDonnell +Andrew Munsell +Andrew Pennebaker +Andrew Po +Andrew Weiss +Andrew Williams +Andrews Medina +Andrey Petrov +Andrey Stolbovsky +André Martins +andy +Andy Chambers +andy diller +Andy Goldstein +Andy Kipp +Andy Rothfusz +Andy Smith +Andy Wilson +Anes Hasicic +Anil Belur +Anil Madhavapeddy +Ankush Agarwal +Anonmily +Anran Qiao +Anshul Pundir +Anthon van der Neut +Anthony Baire +Anthony Bishopric +Anthony Dahanne +Anthony Sottile +Anton Löfgren +Anton Nikitin +Anton Polonskiy +Anton Tiurin +Antonio Murdaca +Antonis Kalipetis +Antony Messerli +Anuj Bahuguna +Anusha Ragunathan +apocas +Arash Deshmeh +ArikaChen +Arnaud Lefebvre +Arnaud Porterie +Arthur Barr +Arthur Gautier +Artur Meyster +Arun Gupta +Asad Saeeduddin +Asbjørn Enge +averagehuman +Avi Das +Avi Miller +Avi Vaid +ayoshitake +Azat Khuyiyakhmetov +Bardia Keyoumarsi +Barnaby Gray +Barry Allard +Bartłomiej Piotrowski +Bastiaan Bakker +bdevloed +Ben Bonnefoy +Ben Firshman +Ben Golub +Ben Hall +Ben Sargent +Ben Severson +Ben Toews +Ben Wiklund +Benjamin Atkin +Benjamin Boudreau +Benjamin Yolken +Benoit Chesneau +Bernerd Schaefer +Bernhard M. Wiedemann +Bert Goethals +Bharath Thiruveedula +Bhiraj Butala +Bhumika Bayani +Bilal Amarni +Bill Wang +Bin Liu +Bingshen Wang +Blake Geno +Boaz Shuster +bobby abbott +Boris Pruessmann +Boshi Lian +Bouke Haarsma +Boyd Hemphill +boynux +Bradley Cicenas +Bradley Wright +Brandon Liu +Brandon Philips +Brandon Rhodes +Brendan Dixon +Brent Salisbury +Brett Higgins +Brett Kochendorfer +Brett Randall +Brian (bex) Exelbierd +Brian Bland +Brian DeHamer +Brian Dorsey +Brian Flad +Brian Goff +Brian McCallister +Brian Olsen +Brian Schwind +Brian Shumate +Brian Torres-Gil +Brian Trump +Brice Jaglin +Briehan Lombaard +Bruno Bigras +Bruno Binet +Bruno Gazzera +Bruno Renié +Bruno Tavares +Bryan Bess +Bryan Boreham +Bryan Matsuo +Bryan Murphy +Burke Libbey +Byung Kang +Caleb Spare +Calen Pennington +Cameron Boehmer +Cameron Spear +Campbell Allen +Candid Dauth +Cao Weiwei +Carl Henrik Lunde +Carl Loa Odin +Carl X. Su +Carlo Mion +Carlos Alexandro Becker +Carlos Sanchez +Carol Fager-Higgins +Cary +Casey Bisson +Catalin Pirvu +Ce Gao +Cedric Davies +Cezar Sa Espinola +Chad Swenson +Chance Zibolski +Chander Govindarajan +Chanhun Jeong +Chao Wang +Charles Chan +Charles Hooper +Charles Law +Charles Lindsay +Charles Merriam +Charles Sarrazin +Charles Smith +Charlie Drage +Charlie Lewis +Chase Bolt +ChaYoung You +Chen Chao +Chen Chuanliang +Chen Hanxiao +Chen Min +Chen Mingjie +Chen Qiu +Cheng-mean Liu +Chengguang Xu +chenyuzhu +Chetan Birajdar +Chewey +Chia-liang Kao +chli +Cholerae Hu +Chris Alfonso +Chris Armstrong +Chris Dias +Chris Dituri +Chris Fordham +Chris Gavin +Chris Gibson +Chris Khoo +Chris McKinnel +Chris McKinnel +Chris Seto +Chris Snow +Chris St. Pierre +Chris Stivers +Chris Swan +Chris Telfer +Chris Wahl +Chris Weyl +Christian Berendt +Christian Brauner +Christian Böhme +Christian Persson +Christian Rotzoll +Christian Simon +Christian Stefanescu +Christophe Mehay +Christophe Troestler +Christophe Vidal +Christopher Biscardi +Christopher Crone +Christopher Currie +Christopher Jones +Christopher Latham +Christopher Rigor +Christy Perez +Chun Chen +Ciro S. Costa +Clayton Coleman +Clinton Kitson +Cody Roseborough +Coenraad Loubser +Colin Dunklau +Colin Hebert +Colin Rice +Colin Walters +Collin Guarino +Colm Hally +companycy +Corbin Coleman +Corey Farrell +Cory Forsyth +cressie176 +CrimsonGlory +Cristian Staretu +cristiano balducci +Cruceru Calin-Cristian +CUI Wei +Cyprian Gracz +Cyril F +Daan van Berkel +Daehyeok Mun +Dafydd Crosby +dalanlan +Damian Smyth +Damien Nadé +Damien Nozay +Damjan Georgievski +Dan Anolik +Dan Buch +Dan Cotora +Dan Feldman +Dan Griffin +Dan Hirsch +Dan Keder +Dan Levy +Dan McPherson +Dan Stine +Dan Williams +Dani Louca +Daniel Antlinger +Daniel Dao +Daniel Exner +Daniel Farrell +Daniel Garcia +Daniel Gasienica +Daniel Grunwell +Daniel Hiltgen +Daniel J Walsh +Daniel Menet +Daniel Mizyrycki +Daniel Nephin +Daniel Norberg +Daniel Nordberg +Daniel Robinson +Daniel S +Daniel Von Fange +Daniel Watkins +Daniel X Moore +Daniel YC Lin +Daniel Zhang +Danny Berger +Danny Yates +Danyal Khaliq +Darren Coxall +Darren Shepherd +Darren Stahl +Dattatraya Kumbhar +Davanum Srinivas +Dave Barboza +Dave Goodchild +Dave Henderson +Dave MacDonald +Dave Tucker +David Anderson +David Calavera +David Chung +David Corking +David Cramer +David Currie +David Davis +David Dooling +David Gageot +David Gebler +David Glasser +David Lawrence +David Lechner +David M. Karr +David Mackey +David Mat +David Mcanulty +David McKay +David Pelaez +David R. Jenni +David Röthlisberger +David Sheets +David Sissitka +David Trott +David Williamson +David Xia +David Young +Davide Ceretti +Dawn Chen +dbdd +dcylabs +Deborah Gertrude Digges +deed02392 +Deng Guangxing +Deni Bertovic +Denis Defreyne +Denis Gladkikh +Denis Ollier +Dennis Chen +Dennis Chen +Dennis Docter +Derek +Derek +Derek Ch +Derek McGowan +Deric Crago +Deshi Xiao +devmeyster +Devvyn Murphy +Dharmit Shah +Dhawal Yogesh Bhanushali +Diego Romero +Diego Siqueira +Dieter Reuter +Dillon Dixon +Dima Stopel +Dimitri John Ledkov +Dimitris Rozakis +Dimitry Andric +Dinesh Subhraveti +Ding Fei +Diogo Monica +DiuDiugirl +Djibril Koné +dkumor +Dmitri Logvinenko +Dmitri Shuralyov +Dmitry Demeshchuk +Dmitry Gusev +Dmitry Kononenko +Dmitry Shyshkin +Dmitry Smirnov +Dmitry V. Krivenok +Dmitry Vorobev +Dolph Mathews +Dominik Dingel +Dominik Finkbeiner +Dominik Honnef +Don Kirkby +Don Kjer +Don Spaulding +Donald Huang +Dong Chen +Donovan Jones +Doron Podoleanu +Doug Davis +Doug MacEachern +Doug Tangren +Douglas Curtis +Dr Nic Williams +dragon788 +Dražen Lučanin +Drew Erny +Drew Hubl +Dustin Sallings +Ed Costello +Edmund Wagner +Eiichi Tsukata +Eike Herzbach +Eivin Giske Skaaren +Eivind Uggedal +Elan Ruusamäe +Elango Sivanandam +Elena Morozova +Eli Uriegas +Elias Faxö +Elias Probst +Elijah Zupancic +eluck +Elvir Kuric +Emil Davtyan +Emil Hernvall +Emily Maier +Emily Rose +Emir Ozer +Enguerran +Eohyung Lee +epeterso +Eric Barch +Eric Curtin +Eric G. Noriega +Eric Hanchrow +Eric Lee +Eric Myhre +Eric Paris +Eric Rafaloff +Eric Rosenberg +Eric Sage +Eric Soderstrom +Eric Yang +Eric-Olivier Lamey +Erica Windisch +Erik Bray +Erik Dubbelboer +Erik Hollensbe +Erik Inge Bolsø +Erik Kristensen +Erik St. Martin +Erik Weathers +Erno Hopearuoho +Erwin van der Koogh +Ethan Bell +Euan Kemp +Eugen Krizo +Eugene Yakubovich +Evan Allrich +Evan Carmi +Evan Hazlett +Evan Krall +Evan Phoenix +Evan Wies +Evelyn Xu +Everett Toews +Evgeny Shmarnev +Evgeny Vereshchagin +Ewa Czechowska +Eystein Måløy Stenberg +ezbercih +Ezra Silvera +Fabian Lauer +Fabiano Rosas +Fabio Falci +Fabio Kung +Fabio Rapposelli +Fabio Rehm +Fabrizio Regini +Fabrizio Soppelsa +Faiz Khan +falmp +Fangming Fang +Fangyuan Gao <21551127@zju.edu.cn> +Fareed Dudhia +Fathi Boudra +Federico Gimenez +Felipe Oliveira +Felix Abecassis +Felix Geisendörfer +Felix Hupfeld +Felix Rabe +Felix Ruess +Felix Schindler +Feng Yan +Fengtu Wang +Ferenc Szabo +Fernando +Fero Volar +Ferran Rodenas +Filipe Brandenburger +Filipe Oliveira +Flavio Castelli +Flavio Crisciani +Florian +Florian Klein +Florian Maier +Florian Noeding +Florian Weingarten +Florin Asavoaie +Florin Patan +fonglh +Foysal Iqbal +Francesc Campoy +Francis Chuang +Francisco Carriedo +Francisco Souza +Frank Groeneveld +Frank Herrmann +Frank Macreery +Frank Rosquin +Fred Lifton +Frederick F. Kautz IV +Frederik Loeffert +Frederik Nordahl Jul Sabroe +Freek Kalter +Frieder Bluemle +Félix Baylac-Jacqué +Félix Cantournet +Gabe Rosenhouse +Gabor Nagy +Gabriel Linder +Gabriel Monroy +Gabriel Nicolas Avellaneda +Gaetan de Villele +Galen Sampson +Gang Qiao +Gareth Rushgrove +Garrett Barboza +Gary Schaetz +Gaurav +gautam, prasanna +Gaël PORTAY +Genki Takiuchi +GennadySpb +Geoffrey Bachelet +George Kontridze +George MacRorie +George Xie +Georgi Hristozov +Gereon Frey +German DZ +Gert van Valkenhoef +Gerwim Feiken +Ghislain Bourgeois +Giampaolo Mancini +Gianluca Borello +Gildas Cuisinier +gissehel +Giuseppe Mazzotta +Gleb Fotengauer-Malinovskiy +Gleb M Borisov +Glyn Normington +GoBella +Goffert van Gool +Gopikannan Venugopalsamy +Gosuke Miyashita +Gou Rao +Govinda Fichtner +Grant Reaber +Graydon Hoare +Greg Fausak +Greg Pflaum +Greg Stephens +Greg Thornton +Grzegorz Jaśkiewicz +Guilhem Lettron +Guilherme Salgado +Guillaume Dufour +Guillaume J. Charmes +guoxiuyan +Guri +Gurjeet Singh +Guruprasad +Gustav Sinder +gwx296173 +Günter Zöchbauer +Hakan Özler +Hans Kristian Flaatten +Hans Rødtang +Hao Shu Wei +Hao Zhang <21521210@zju.edu.cn> +Harald Albers +Harley Laue +Harold Cooper +Harry Zhang +Harshal Patil +Harshal Patil +He Simei +He Xiaoxi +He Xin +heartlock <21521209@zju.edu.cn> +Hector Castro +Helen Xie +Henning Sprang +Hiroshi Hatake +Hobofan +Hollie Teal +Hong Xu +Hongbin Lu +hsinko <21551195@zju.edu.cn> +Hu Keping +Hu Tao +Huanzhong Zhang +Huayi Zhang +Hugo Duncan +Hugo Marisco <0x6875676f@gmail.com> +Hunter Blanks +huqun +Huu Nguyen +hyeongkyu.lee +Hyzhou Zhy +Iago López Galeiras +Ian Babrou +Ian Bishop +Ian Bull +Ian Calvert +Ian Campbell +Ian Lee +Ian Main +Ian Philpot +Ian Truslove +Iavael +Icaro Seara +Ignacio Capurro +Igor Dolzhikov +Igor Karpovich +Iliana Weller +Ilkka Laukkanen +Ilya Dmitrichenko +Ilya Gusev +Ilya Khlopotov +imre Fitos +inglesp +Ingo Gottwald +Isaac Dupree +Isabel Jimenez +Isao Jonas +Ivan Babrou +Ivan Fraixedes +Ivan Grcic +Ivan Markin +J Bruni +J. Nunn +Jack Danger Canty +Jack Laxson +Jacob Atzen +Jacob Edelman +Jacob Tomlinson +Jacob Vallejo +Jacob Wen +Jaivish Kothari +Jake Champlin +Jake Moshenko +Jake Sanders +jakedt +James Allen +James Carey +James Carr +James DeFelice +James Harrison Fisher +James Kyburz +James Kyle +James Lal +James Mills +James Nesbitt +James Nugent +James Turnbull +Jamie Hannaford +Jamshid Afshar +Jan Keromnes +Jan Koprowski +Jan Pazdziora +Jan Toebes +Jan-Gerd Tenberge +Jan-Jaap Driessen +Jana Radhakrishnan +Jannick Fahlbusch +Januar Wayong +Jared Biel +Jared Hocutt +Jaroslaw Zabiello +jaseg +Jasmine Hegman +Jason Divock +Jason Giedymin +Jason Green +Jason Hall +Jason Heiss +Jason Livesay +Jason McVetta +Jason Plum +Jason Shepherd +Jason Smith +Jason Sommer +Jason Stangroome +jaxgeller +Jay +Jay +Jay Kamat +Jean-Baptiste Barth +Jean-Baptiste Dalido +Jean-Christophe Berthon +Jean-Paul Calderone +Jean-Pierre Huynh +Jean-Tiare Le Bigot +Jeeva S. Chelladhurai +Jeff Anderson +Jeff Hajewski +Jeff Johnston +Jeff Lindsay +Jeff Mickey +Jeff Minard +Jeff Nickoloff +Jeff Silberman +Jeff Welch +Jeffrey Bolle +Jeffrey Morgan +Jeffrey van Gogh +Jenny Gebske +Jeremy Chambers +Jeremy Grosser +Jeremy Price +Jeremy Qian +Jeremy Unruh +Jeremy Yallop +Jeroen Franse +Jeroen Jacobs +Jesse Dearing +Jesse Dubay +Jessica Frazelle +Jezeniel Zapanta +Jhon Honce +Ji.Zhilong +Jian Zhang +Jie Luo +Jihyun Hwang +Jilles Oldenbeuving +Jim Alateras +Jim Galasyn +Jim Minter +Jim Perrin +Jimmy Cuadra +Jimmy Puckett +Jimmy Song +jimmyxian +Jinsoo Park +Jiri Popelka +Jiuyue Ma +Jiří Župka +jjy +jmzwcn +Joao Fernandes +Joe Beda +Joe Doliner +Joe Ferguson +Joe Gordon +Joe Shaw +Joe Van Dyk +Joel Friedly +Joel Handwell +Joel Hansson +Joel Wurtz +Joey Geiger +Joey Geiger +Joey Gibson +Joffrey F +Johan Euphrosine +Johan Rydberg +Johanan Lieberman +Johannes 'fish' Ziemke +John Costa +John Feminella +John Gardiner Myers +John Gossman +John Harris +John Howard (VM) +John Laswell +John Maguire +John Mulhausen +John OBrien III +John Starks +John Stephens +John Tims +John V. Martinez +John Warwick +John Willis +Jon Johnson +Jon Surrell +Jon Wedaman +Jonas Pfenniger +Jonathan A. Sternberg +Jonathan Boulle +Jonathan Camp +Jonathan Choy +Jonathan Dowland +Jonathan Lebon +Jonathan Lomas +Jonathan McCrohan +Jonathan Mueller +Jonathan Pares +Jonathan Rudenberg +Jonathan Stoppani +Jonh Wendell +Joni Sar +Joost Cassee +Jordan Arentsen +Jordan Jennings +Jordan Sissel +Jorge Marin +Jorit Kleine-Möllhoff +Jose Diaz-Gonzalez +Joseph Anthony Pasquale Holsten +Joseph Hager +Joseph Kern +Joseph Rothrock +Josh +Josh Bodah +Josh Bonczkowski +Josh Chorlton +Josh Eveleth +Josh Hawn +Josh Horwitz +Josh Poimboeuf +Josh Soref +Josh Wilson +Josiah Kiehl +José Tomás Albornoz +Joyce Jang +JP +Julian Taylor +Julien Barbier +Julien Bisconti +Julien Bordellier +Julien Dubois +Julien Kassar +Julien Maitrehenry +Julien Pervillé +Julio Montes +Jun-Ru Chang +Jussi Nummelin +Justas Brazauskas +Justin Cormack +Justin Force +Justin Menga +Justin Plock +Justin Simonelis +Justin Terry +Justyn Temme +Jyrki Puttonen +Jérôme Petazzoni +Jörg Thalheim +K. Heller +Kai Blin +Kai Qiang Wu (Kennan) +Kamil Domański +Kamjar Gerami +Kanstantsin Shautsou +Kara Alexandra +Karan Lyons +Kareem Khazem +kargakis +Karl Grzeszczak +Karol Duleba +Karthik Karanth +Karthik Nayak +Kate Heddleston +Katie McLaughlin +Kato Kazuyoshi +Katrina Owen +Kawsar Saiyeed +Kay Yan +kayrus +Ke Li +Ke Xu +Kei Ohmura +Keith Hudgins +Keli Hu +Ken Cochrane +Ken Herner +Ken ICHIKAWA +Kenfe-Mickaël Laventure +Kenjiro Nakayama +Kent Johnson +Kevin "qwazerty" Houdebert +Kevin Burke +Kevin Clark +Kevin Feyrer +Kevin J. Lynagh +Kevin Jing Qiu +Kevin Kern +Kevin Menard +Kevin Meredith +Kevin P. Kucharczyk +Kevin Richardson +Kevin Shi +Kevin Wallace +Kevin Yap +Keyvan Fatehi +kies +Kim BKC Carlbacker +Kim Eik +Kimbro Staken +Kir Kolyshkin +Kiran Gangadharan +Kirill SIbirev +knappe +Kohei Tsuruta +Koichi Shiraishi +Konrad Kleine +Konstantin Gribov +Konstantin L +Konstantin Pelykh +Krasi Georgiev +Krasimir Georgiev +Kris-Mikael Krister +Kristian Haugene +Kristina Zabunova +krrg +Kun Zhang +Kunal Kushwaha +Kyle Conroy +Kyle Linden +kyu +Lachlan Coote +Lai Jiangshan +Lajos Papp +Lakshan Perera +Lalatendu Mohanty +Lance Chen +Lance Kinley +Lars Butler +Lars Kellogg-Stedman +Lars R. Damerow +Lars-Magnus Skog +Laszlo Meszaros +Laura Frank +Laurent Erignoux +Laurie Voss +Leandro Siqueira +Lee Chao <932819864@qq.com> +Lee, Meng-Han +leeplay +Lei Jitang +Len Weincier +Lennie +Leo Gallucci +Leszek Kowalski +Levi Blackstone +Levi Gross +Lewis Daly +Lewis Marshall +Lewis Peckover +Li Yi +Liam Macgillavry +Liana Lo +Liang Mingqiang +Liang-Chi Hsieh +Liao Qingwei +Lily Guo +limsy +Lin Lu +LingFaKe +Linus Heckemann +Liran Tal +Liron Levin +Liu Bo +Liu Hua +liwenqi +lixiaobing10051267 +Liz Zhang +LIZAO LI +Lizzie Dixon <_@lizzie.io> +Lloyd Dewolf +Lokesh Mandvekar +longliqiang88 <394564827@qq.com> +Lorenz Leutgeb +Lorenzo Fontana +Louis Opter +Luca Favatella +Luca Marturana +Luca Orlandi +Luca-Bogdan Grigorescu +Lucas Chan +Lucas Chi +Lucas Molas +Luciano Mores +Luis Martínez de Bartolomé Izquierdo +Luiz Svoboda +Lukas Waslowski +lukaspustina +Lukasz Zajaczkowski +Luke Marsden +Lyn +Lynda O'Leary +Lénaïc Huard +Ma Müller +Ma Shimiao +Mabin +Madhan Raj Mookkandy +Madhav Puri +Madhu Venugopal +Mageee +Mahesh Tiyyagura +malnick +Malte Janduda +Manfred Touron +Manfred Zabarauskas +Manjunath A Kumatagi +Mansi Nahar +Manuel Meurer +Manuel Rüger +Manuel Woelker +mapk0y +Marc Abramowitz +Marc Kuo +Marc Tamsky +Marcel Edmund Franke +Marcelo Horacio Fortino +Marcelo Salazar +Marco Hennings +Marcus Cobden +Marcus Farkas +Marcus Linke +Marcus Martins +Marcus Ramberg +Marek Goldmann +Marian Marinov +Marianna Tessel +Mario Loriedo +Marius Gundersen +Marius Sturm +Marius Voila +Mark Allen +Mark McGranaghan +Mark McKinstry +Mark Milstein +Mark Oates +Mark Parker +Mark West +Markan Patel +Marko Mikulicic +Marko Tibold +Markus Fix +Markus Kortlang +Martijn Dwars +Martijn van Oosterhout +Martin Honermeyer +Martin Kelly +Martin Mosegaard Amdisen +Martin Redmond +Mary Anthony +Masahito Zembutsu +Masato Ohba +Masayuki Morita +Mason Malone +Mateusz Sulima +Mathias Monnerville +Mathieu Champlon +Mathieu Le Marec - Pasquet +Mathieu Parent +Matt Apperson +Matt Bachmann +Matt Bentley +Matt Haggard +Matt Hoyle +Matt McCormick +Matt Moore +Matt Richardson +Matt Rickard +Matt Robenolt +Matt Schurenko +Matt Williams +Matthew Heon +Matthew Lapworth +Matthew Mayer +Matthew Mosesohn +Matthew Mueller +Matthew Riley +Matthias Klumpp +Matthias Kühnle +Matthias Rampke +Matthieu Hauglustaine +Mauricio Garavaglia +mauriyouth +Max Shytikov +Maxim Fedchyshyn +Maxim Ivanov +Maxim Kulkin +Maxim Treskin +Maxime Petazzoni +Meaglith Ma +meejah +Megan Kostick +Mehul Kar +Mei ChunTao +Mengdi Gao +Mert Yazıcıoğlu +mgniu +Micah Zoltu +Michael A. Smith +Michael Bridgen +Michael Brown +Michael Chiang +Michael Crosby +Michael Currie +Michael Friis +Michael Gorsuch +Michael Grauer +Michael Holzheu +Michael Hudson-Doyle +Michael Huettermann +Michael Irwin +Michael Käufl +Michael Neale +Michael Nussbaum +Michael Prokop +Michael Scharf +Michael Spetsiotis +Michael Stapelberg +Michael Steinert +Michael Thies +Michael West +Michal Fojtik +Michal Gebauer +Michal Jemala +Michal Minář +Michal Wieczorek +Michaël Pailloncy +Michał Czeraszkiewicz +Michał Gryko +Michiel@unhosted +Mickaël FORTUNATO +Miguel Angel Fernández +Miguel Morales +Mihai Borobocea +Mihuleacc Sergiu +Mike Brown +Mike Casas +Mike Chelen +Mike Danese +Mike Dillon +Mike Dougherty +Mike Estes +Mike Gaffney +Mike Goelzer +Mike Leone +Mike Lundy +Mike MacCana +Mike Naberezny +Mike Snitzer +mikelinjie <294893458@qq.com> +Mikhail Sobolev +Miklos Szegedi +Milind Chawre +Miloslav Trmač +mingqing +Mingzhen Feng +Misty Stanley-Jones +Mitch Capper +Mizuki Urushida +mlarcher +Mohammad Banikazemi +Mohammed Aaqib Ansari +Mohit Soni +Moorthy RS +Morgan Bauer +Morgante Pell +Morgy93 +Morten Siebuhr +Morton Fox +Moysés Borges +mrfly +Mrunal Patel +Muayyad Alsadi +Mustafa Akın +Muthukumar R +Máximo Cuadros +Médi-Rémi Hashim +Nace Oroz +Nahum Shalman +Nakul Pathak +Nalin Dahyabhai +Nan Monnand Deng +Naoki Orii +Natalie Parker +Natanael Copa +Nate Brennand +Nate Eagleson +Nate Jones +Nathan Hsieh +Nathan Kleyn +Nathan LeClaire +Nathan McCauley +Nathan Williams +Naveed Jamil +Neal McBurnett +Neil Horman +Neil Peterson +Nelson Chen +Neyazul Haque +Nghia Tran +Niall O'Higgins +Nicholas E. Rabenau +Nick DeCoursin +Nick Irvine +Nick Neisen +Nick Parker +Nick Payne +Nick Russo +Nick Stenning +Nick Stinemates +NickrenREN +Nicola Kabar +Nicolas Borboën +Nicolas De Loof +Nicolas Dudebout +Nicolas Goy +Nicolas Kaiser +Nicolas Sterchele +Nicolás Hock Isaza +Nigel Poulton +Nik Nyby +Nikhil Chawla +NikolaMandic +Nikolas Garofil +Nikolay Milovanov +Nirmal Mehta +Nishant Totla +NIWA Hideyuki +Noah Meyerhans +Noah Treuhaft +NobodyOnSE +noducks +Nolan Darilek +nponeccop +Nuutti Kotivuori +nzwsch +O.S. Tezer +objectified +Oguz Bilgic +Oh Jinkyun +Ohad Schneider +ohmystack +Ole Reifschneider +Oliver Neal +Olivier Gambier +Olle Jonsson +Oriol Francès +Oskar Niburski +Otto Kekäläinen +Ouyang Liduo +Ovidio Mallo +Panagiotis Moustafellos +Paolo G. Giarrusso +Pascal +Pascal Borreli +Pascal Hartig +Patrick Böänziger +Patrick Devine +Patrick Hemmer +Patrick Stapleton +Patrik Cyvoct +pattichen +Paul +paul +Paul Annesley +Paul Bellamy +Paul Bowsher +Paul Furtado +Paul Hammond +Paul Jimenez +Paul Kehrer +Paul Lietar +Paul Liljenberg +Paul Morie +Paul Nasrat +Paul Weaver +Paulo Ribeiro +Pavel Lobashov +Pavel Pletenev +Pavel Pospisil +Pavel Sutyrin +Pavel Tikhomirov +Pavlos Ratis +Pavol Vargovcik +Pawel Konczalski +Peeyush Gupta +Peggy Li +Pei Su +Peng Tao +Penghan Wang +Per Weijnitz +perhapszzy@sina.com +Peter Bourgon +Peter Braden +Peter Bücker +Peter Choi +Peter Dave Hello +Peter Edge +Peter Ericson +Peter Esbensen +Peter Jaffe +Peter Malmgren +Peter Salvatore +Peter Volpe +Peter Waller +Petr Švihlík +Phil +Phil Estes +Phil Spitler +Philip Alexander Etling +Philip Monroe +Philipp Gillé +Philipp Wahala +Philipp Weissensteiner +Phillip Alexander +phineas +pidster +Piergiuliano Bossi +Pierre +Pierre Carrier +Pierre Dal-Pra +Pierre Wacrenier +Pierre-Alain RIVIERE +Piotr Bogdan +pixelistik +Porjo +Poul Kjeldager Sørensen +Pradeep Chhetri +Pradip Dhara +Prasanna Gautam +Pratik Karki +Prayag Verma +Priya Wadhwa +Przemek Hejman +Pure White +pysqz +Qiang Huang +Qinglan Peng +qudongfang +Quentin Brossard +Quentin Perez +Quentin Tayssier +r0n22 +Rafal Jeczalik +Rafe Colton +Raghavendra K T +Raghuram Devarakonda +Raja Sami +Rajat Pandit +Rajdeep Dua +Ralf Sippl +Ralle +Ralph Bean +Ramkumar Ramachandra +Ramon Brooker +Ramon van Alteren +Ray Tsang +ReadmeCritic +Recursive Madman +Reficul +Regan McCooey +Remi Rampin +Remy Suen +Renato Riccieri Santos Zannon +Renaud Gaubert +Rhys Hiltner +Ri Xu +Ricardo N Feliciano +Rich Moyse +Rich Seymour +Richard +Richard Burnison +Richard Harvey +Richard Mathie +Richard Metzler +Richard Scothern +Richo Healey +Rick Bradley +Rick van de Loo +Rick Wieman +Rik Nijessen +Riku Voipio +Riley Guerin +Ritesh H Shukla +Riyaz Faizullabhoy +Rob Vesse +Robert Bachmann +Robert Bittle +Robert Obryk +Robert Schneider +Robert Stern +Robert Terhaar +Robert Wallis +Roberto G. Hashioka +Roberto Muñoz Fernández +Robin Naundorf +Robin Schneider +Robin Speekenbrink +robpc +Rodolfo Carvalho +Rodrigo Vaz +Roel Van Nyen +Roger Peppe +Rohit Jnagal +Rohit Kadam +Rojin George +Roland Huß +Roland Kammerer +Roland Moriz +Roma Sokolov +Roman Dudin +Roman Strashkin +Ron Smits +Ron Williams +root +root +root +root +Rory Hunter +Rory McCune +Ross Boucher +Rovanion Luckey +Royce Remer +Rozhnov Alexandr +Rudolph Gottesheim +Rui Lopes +Runshen Zhu +Ryan Abrams +Ryan Anderson +Ryan Aslett +Ryan Belgrave +Ryan Detzel +Ryan Fowler +Ryan Liu +Ryan McLaughlin +Ryan O'Donnell +Ryan Seto +Ryan Simmen +Ryan Stelly +Ryan Thomas +Ryan Trauntvein +Ryan Wallner +Ryan Zhang +ryancooper7 +RyanDeng +Rémy Greinhofer +s. rannou +s00318865 +Sabin Basyal +Sachin Joshi +Sagar Hani +Sainath Grandhi +Sakeven Jiang +Sally O'Malley +Sam Abed +Sam Alba +Sam Bailey +Sam J Sharpe +Sam Neirinck +Sam Reis +Sam Rijs +Sambuddha Basu +Sami Wagiaalla +Samuel Andaya +Samuel Dion-Girardeau +Samuel Karp +Samuel PHAN +Sandeep Bansal +Sankar சங்கர் +Sanket Saurav +Santhosh Manohar +sapphiredev +Sargun Dhillon +Sascha Andres +Satnam Singh +Satoshi Amemiya +Satoshi Tagomori +Scott Bessler +Scott Collier +Scott Johnston +Scott Stamp +Scott Walls +sdreyesg +Sean Christopherson +Sean Cronin +Sean Lee +Sean McIntyre +Sean OMeara +Sean P. Kane +Sean Rodman +Sebastiaan van Steenis +Sebastiaan van Stijn +Senthil Kumar Selvaraj +Senthil Kumaran +SeongJae Park +Seongyeol Lim +Serge Hallyn +Sergey Alekseev +Sergey Evstifeev +Sergii Kabashniuk +Serhat Gülçiçek +Sevki Hasirci +Shane Canon +Shane da Silva +Shaun Kaasten +shaunol +Shawn Landden +Shawn Siefkas +shawnhe +Shayne Wang +Shekhar Gulati +Sheng Yang +Shengbo Song +Shev Yan +Shih-Yuan Lee +Shijiang Wei +Shijun Qin +Shishir Mahajan +Shoubhik Bose +Shourya Sarcar +shuai-z +Shukui Yang +Shuwei Hao +Sian Lerk Lau +Sidhartha Mani +sidharthamani +Silas Sewell +Silvan Jegen +Simei He +Simon Eskildsen +Simon Ferquel +Simon Leinen +Simon Menke +Simon Taranto +Simon Vikstrom +Sindhu S +Sjoerd Langkemper +Solganik Alexander +Solomon Hykes +Song Gao +Soshi Katsuta +Soulou +Spencer Brown +Spencer Smith +Sridatta Thatipamala +Sridhar Ratnakumar +Srini Brahmaroutu +Srinivasan Srivatsan +Stanislav Bondarenko +Steeve Morin +Stefan Berger +Stefan J. Wernli +Stefan Praszalowicz +Stefan S. +Stefan Scherer +Stefan Staudenmeyer +Stefan Weil +Stephan Spindler +Stephen Crosby +Stephen Day +Stephen Drake +Stephen Rust +Steve Desmond +Steve Dougherty +Steve Durrheimer +Steve Francia +Steve Koch +Steven Burgess +Steven Erenst +Steven Hartland +Steven Iveson +Steven Merrill +Steven Richards +Steven Taylor +Subhajit Ghosh +Sujith Haridasan +Sun Gengze <690388648@qq.com> +Sun Jianbo +Sunny Gogoi +Suryakumar Sudar +Sven Dowideit +Swapnil Daingade +Sylvain Baubeau +Sylvain Bellemare +Sébastien +Sébastien HOUZÉ +Sébastien Luttringer +Sébastien Stormacq +Tabakhase +Tadej Janež +TAGOMORI Satoshi +tang0th +Tangi Colin +Tatsuki Sugiura +Tatsushi Inagaki +Taylor Jones +tbonza +Ted M. Young +Tehmasp Chaudhri +Tejesh Mehta +terryding77 <550147740@qq.com> +tgic +Thatcher Peskens +theadactyl +Thell 'Bo' Fowler +Thermionix +Thijs Terlouw +Thomas Bikeev +Thomas Frössman +Thomas Gazagnaire +Thomas Grainger +Thomas Hansen +Thomas Leonard +Thomas Léveil +Thomas Orozco +Thomas Riccardi +Thomas Schroeter +Thomas Sjögren +Thomas Swift +Thomas Tanaka +Thomas Texier +Ti Zhou +Tianon Gravi +Tianyi Wang +Tibor Vass +Tiffany Jernigan +Tiffany Low +Tim Bart +Tim Bosse +Tim Dettrick +Tim Düsterhus +Tim Hockin +Tim Potter +Tim Ruffles +Tim Smith +Tim Terhorst +Tim Wang +Tim Waugh +Tim Wraight +Tim Zju <21651152@zju.edu.cn> +timfeirg +Timothy Hobbs +tjwebb123 +tobe +Tobias Bieniek +Tobias Bradtke +Tobias Gesellchen +Tobias Klauser +Tobias Munk +Tobias Schmidt +Tobias Schwab +Todd Crane +Todd Lunter +Todd Whiteman +Toli Kuznets +Tom Barlow +Tom Booth +Tom Denham +Tom Fotherby +Tom Howe +Tom Hulihan +Tom Maaswinkel +Tom Sweeney +Tom Wilkie +Tom X. Tobin +Tomas Tomecek +Tomasz Kopczynski +Tomasz Lipinski +Tomasz Nurkiewicz +Tommaso Visconti +Tomáš Hrčka +Tonny Xu +Tony Abboud +Tony Daws +Tony Miller +toogley +Torstein Husebø +Tõnis Tiigi +tpng +tracylihui <793912329@qq.com> +Trapier Marshall +Travis Cline +Travis Thieman +Trent Ogren +Trevor +Trevor Pounds +Trevor Sullivan +Trishna Guha +Tristan Carel +Troy Denton +Tycho Andersen +Tyler Brock +Tzu-Jung Lee +uhayate +Ulysse Carion +Umesh Yadav +Utz Bacher +vagrant +Vaidas Jablonskis +vanderliang +Veres Lajos +Victor Algaze +Victor Coisne +Victor Costan +Victor I. Wood +Victor Lyuboslavsky +Victor Marmol +Victor Palma +Victor Vieux +Victoria Bialas +Vijaya Kumar K +Viktor Stanchev +Viktor Vojnovski +VinayRaghavanKS +Vincent Batts +Vincent Bernat +Vincent Demeester +Vincent Giersch +Vincent Mayers +Vincent Woo +Vinod Kulkarni +Vishal Doshi +Vishnu Kannan +Vitaly Ostrosablin +Vitor Monteiro +Vivek Agarwal +Vivek Dasgupta +Vivek Goyal +Vladimir Bulyga +Vladimir Kirillov +Vladimir Pouzanov +Vladimir Rutsky +Vladimir Varankin +VladimirAus +Vlastimil Zeman +Vojtech Vitek (V-Teq) +waitingkuo +Walter Leibbrandt +Walter Stanish +Wang Chao +Wang Guoliang +Wang Jie +Wang Long +Wang Ping +Wang Xing +Wang Yuexiao +Ward Vandewege +WarheadsSE +Wassim Dhif +Wayne Chang +Wayne Song +Weerasak Chongnguluam +Wei Wu +Wei-Ting Kuo +weipeng +weiyan +Weiyang Zhu +Wen Cheng Ma +Wendel Fleming +Wenjun Tang +Wenkai Yin +Wentao Zhang +Wenxuan Zhao +Wenyu You <21551128@zju.edu.cn> +Wenzhi Liang +Wes Morgan +Wewang Xiaorenfine +Will Dietz +Will Rouesnel +Will Weaver +willhf +William Delanoue +William Henry +William Hubbs +William Martin +William Riancho +William Thurston +WiseTrem +Wolfgang Powisch +Wonjun Kim +xamyzhao +Xianglin Gao +Xianlu Bird +XiaoBing Jiang +Xiaoxu Chen +Xiaoyu Zhang +xiekeyang +Xinbo Weng +Xinzi Zhou +Xiuming Chen +Xuecong Liao +xuzhaokui +Yahya +YAMADA Tsuyoshi +Yamasaki Masahide +Yan Feng +Yang Bai +Yang Pengfei +yangchenliang +Yanqiang Miao +Yao Zaiyong +Yassine Tijani +Yasunori Mahata +Yazhong Liu +Yestin Sun +Yi EungJun +Yibai Zhang +Yihang Ho +Ying Li +Yohei Ueda +Yong Tang +Yongzhi Pan +Yosef Fertel +You-Sheng Yang (楊有勝) +Youcef YEKHLEF +Yu Changchun +Yu Chengxia +Yu Peng +Yu-Ju Hong +Yuan Sun +Yuanhong Peng +Yuhao Fang +Yunxiang Huang +Yurii Rashkovskii +Yves Junqueira +Zac Dover +Zach Borboa +Zachary Jaffee +Zain Memon +Zaiste! +Zane DeGraffenried +Zefan Li +Zen Lin(Zhinan Lin) +Zhang Kun +Zhang Wei +Zhang Wentao +ZhangHang +zhangxianwei +Zhenan Ye <21551168@zju.edu.cn> +zhenghenghuo +Zhenkun Bi +Zhou Hao +Zhu Guihua +Zhu Kunjia +Zhuoyun Wei +Zilin Du +zimbatm +Ziming Dong +ZJUshuaizhou <21551191@zju.edu.cn> +zmarouf +Zoltan Tombol +Zou Yu +zqh +Zuhayr Elahi +Zunayed Ali +Álex González +Álvaro Lázaro +Átila Camurça Alves +尹吉峰 +徐俊杰 +慕陶 +搏通 +黄艳红00139573 diff --git a/vendor/github.com/docker/docker/LICENSE b/vendor/github.com/docker/docker/LICENSE new file mode 100644 index 000000000..9c8e20ab8 --- /dev/null +++ b/vendor/github.com/docker/docker/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2013-2017 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/docker/docker/NOTICE b/vendor/github.com/docker/docker/NOTICE new file mode 100644 index 000000000..0c74e15b0 --- /dev/null +++ b/vendor/github.com/docker/docker/NOTICE @@ -0,0 +1,19 @@ +Docker +Copyright 2012-2017 Docker, Inc. + +This product includes software developed at Docker, Inc. (https://www.docker.com). + +This product contains software (https://github.com/kr/pty) developed +by Keith Rarick, licensed under the MIT License. + +The following is courtesy of our legal counsel: + + +Use and transfer of Docker may be subject to certain restrictions by the +United States and other governments. +It is your responsibility to ensure that your use and/or transfer does not +violate applicable laws. + +For more information, please see https://www.bis.doc.gov + +See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. diff --git a/vendor/github.com/docker/docker/api/types/auth.go b/vendor/github.com/docker/docker/api/types/auth.go new file mode 100644 index 000000000..ddf15bb18 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/auth.go @@ -0,0 +1,22 @@ +package types // import "github.com/docker/docker/api/types" + +// AuthConfig contains authorization information for connecting to a Registry +type AuthConfig struct { + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Auth string `json:"auth,omitempty"` + + // Email is an optional value associated with the username. + // This field is deprecated and will be removed in a later + // version of docker. + Email string `json:"email,omitempty"` + + ServerAddress string `json:"serveraddress,omitempty"` + + // IdentityToken is used to authenticate the user and get + // an access token for the registry. + IdentityToken string `json:"identitytoken,omitempty"` + + // RegistryToken is a bearer token to be sent to a registry + RegistryToken string `json:"registrytoken,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/blkiodev/blkio.go b/vendor/github.com/docker/docker/api/types/blkiodev/blkio.go new file mode 100644 index 000000000..bf3463b90 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/blkiodev/blkio.go @@ -0,0 +1,23 @@ +package blkiodev // import "github.com/docker/docker/api/types/blkiodev" + +import "fmt" + +// WeightDevice is a structure that holds device:weight pair +type WeightDevice struct { + Path string + Weight uint16 +} + +func (w *WeightDevice) String() string { + return fmt.Sprintf("%s:%d", w.Path, w.Weight) +} + +// ThrottleDevice is a structure that holds device:rate_per_second pair +type ThrottleDevice struct { + Path string + Rate uint64 +} + +func (t *ThrottleDevice) String() string { + return fmt.Sprintf("%s:%d", t.Path, t.Rate) +} diff --git a/vendor/github.com/docker/docker/api/types/client.go b/vendor/github.com/docker/docker/api/types/client.go new file mode 100644 index 000000000..3df8d2336 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/client.go @@ -0,0 +1,406 @@ +package types // import "github.com/docker/docker/api/types" + +import ( + "bufio" + "io" + "net" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" + "github.com/docker/go-units" +) + +// CheckpointCreateOptions holds parameters to create a checkpoint from a container +type CheckpointCreateOptions struct { + CheckpointID string + CheckpointDir string + Exit bool +} + +// CheckpointListOptions holds parameters to list checkpoints for a container +type CheckpointListOptions struct { + CheckpointDir string +} + +// CheckpointDeleteOptions holds parameters to delete a checkpoint from a container +type CheckpointDeleteOptions struct { + CheckpointID string + CheckpointDir string +} + +// ContainerAttachOptions holds parameters to attach to a container. +type ContainerAttachOptions struct { + Stream bool + Stdin bool + Stdout bool + Stderr bool + DetachKeys string + Logs bool +} + +// ContainerCommitOptions holds parameters to commit changes into a container. +type ContainerCommitOptions struct { + Reference string + Comment string + Author string + Changes []string + Pause bool + Config *container.Config +} + +// ContainerExecInspect holds information returned by exec inspect. +type ContainerExecInspect struct { + ExecID string + ContainerID string + Running bool + ExitCode int + Pid int +} + +// ContainerListOptions holds parameters to list containers with. +type ContainerListOptions struct { + Quiet bool + Size bool + All bool + Latest bool + Since string + Before string + Limit int + Filters filters.Args +} + +// ContainerLogsOptions holds parameters to filter logs with. +type ContainerLogsOptions struct { + ShowStdout bool + ShowStderr bool + Since string + Until string + Timestamps bool + Follow bool + Tail string + Details bool +} + +// ContainerRemoveOptions holds parameters to remove containers. +type ContainerRemoveOptions struct { + RemoveVolumes bool + RemoveLinks bool + Force bool +} + +// ContainerStartOptions holds parameters to start containers. +type ContainerStartOptions struct { + CheckpointID string + CheckpointDir string +} + +// CopyToContainerOptions holds information +// about files to copy into a container +type CopyToContainerOptions struct { + AllowOverwriteDirWithFile bool + CopyUIDGID bool +} + +// EventsOptions holds parameters to filter events with. +type EventsOptions struct { + Since string + Until string + Filters filters.Args +} + +// NetworkListOptions holds parameters to filter the list of networks with. +type NetworkListOptions struct { + Filters filters.Args +} + +// HijackedResponse holds connection information for a hijacked request. +type HijackedResponse struct { + Conn net.Conn + Reader *bufio.Reader +} + +// Close closes the hijacked connection and reader. +func (h *HijackedResponse) Close() { + h.Conn.Close() +} + +// CloseWriter is an interface that implements structs +// that close input streams to prevent from writing. +type CloseWriter interface { + CloseWrite() error +} + +// CloseWrite closes a readWriter for writing. +func (h *HijackedResponse) CloseWrite() error { + if conn, ok := h.Conn.(CloseWriter); ok { + return conn.CloseWrite() + } + return nil +} + +// ImageBuildOptions holds the information +// necessary to build images. +type ImageBuildOptions struct { + Tags []string + SuppressOutput bool + RemoteContext string + NoCache bool + Remove bool + ForceRemove bool + PullParent bool + Isolation container.Isolation + CPUSetCPUs string + CPUSetMems string + CPUShares int64 + CPUQuota int64 + CPUPeriod int64 + Memory int64 + MemorySwap int64 + CgroupParent string + NetworkMode string + ShmSize int64 + Dockerfile string + Ulimits []*units.Ulimit + // BuildArgs needs to be a *string instead of just a string so that + // we can tell the difference between "" (empty string) and no value + // at all (nil). See the parsing of buildArgs in + // api/server/router/build/build_routes.go for even more info. + BuildArgs map[string]*string + AuthConfigs map[string]AuthConfig + Context io.Reader + Labels map[string]string + // squash the resulting image's layers to the parent + // preserves the original image and creates a new one from the parent with all + // the changes applied to a single layer + Squash bool + // CacheFrom specifies images that are used for matching cache. Images + // specified here do not need to have a valid parent chain to match cache. + CacheFrom []string + SecurityOpt []string + ExtraHosts []string // List of extra hosts + Target string + SessionID string + Platform string + // Version specifies the version of the unerlying builder to use + Version BuilderVersion + // BuildID is an optional identifier that can be passed together with the + // build request. The same identifier can be used to gracefully cancel the + // build with the cancel request. + BuildID string +} + +// BuilderVersion sets the version of underlying builder to use +type BuilderVersion string + +const ( + // BuilderV1 is the first generation builder in docker daemon + BuilderV1 BuilderVersion = "1" + // BuilderBuildKit is builder based on moby/buildkit project + BuilderBuildKit = "2" +) + +// ImageBuildResponse holds information +// returned by a server after building +// an image. +type ImageBuildResponse struct { + Body io.ReadCloser + OSType string +} + +// ImageCreateOptions holds information to create images. +type ImageCreateOptions struct { + RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry. + Platform string // Platform is the target platform of the image if it needs to be pulled from the registry. +} + +// ImageImportSource holds source information for ImageImport +type ImageImportSource struct { + Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this. + SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute. +} + +// ImageImportOptions holds information to import images from the client host. +type ImageImportOptions struct { + Tag string // Tag is the name to tag this image with. This attribute is deprecated. + Message string // Message is the message to tag the image with + Changes []string // Changes are the raw changes to apply to this image + Platform string // Platform is the target platform of the image +} + +// ImageListOptions holds parameters to filter the list of images with. +type ImageListOptions struct { + All bool + Filters filters.Args +} + +// ImageLoadResponse returns information to the client about a load process. +type ImageLoadResponse struct { + // Body must be closed to avoid a resource leak + Body io.ReadCloser + JSON bool +} + +// ImagePullOptions holds information to pull images. +type ImagePullOptions struct { + All bool + RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry + PrivilegeFunc RequestPrivilegeFunc + Platform string +} + +// RequestPrivilegeFunc is a function interface that +// clients can supply to retry operations after +// getting an authorization error. +// This function returns the registry authentication +// header value in base 64 format, or an error +// if the privilege request fails. +type RequestPrivilegeFunc func() (string, error) + +//ImagePushOptions holds information to push images. +type ImagePushOptions ImagePullOptions + +// ImageRemoveOptions holds parameters to remove images. +type ImageRemoveOptions struct { + Force bool + PruneChildren bool +} + +// ImageSearchOptions holds parameters to search images with. +type ImageSearchOptions struct { + RegistryAuth string + PrivilegeFunc RequestPrivilegeFunc + Filters filters.Args + Limit int +} + +// ResizeOptions holds parameters to resize a tty. +// It can be used to resize container ttys and +// exec process ttys too. +type ResizeOptions struct { + Height uint + Width uint +} + +// NodeListOptions holds parameters to list nodes with. +type NodeListOptions struct { + Filters filters.Args +} + +// NodeRemoveOptions holds parameters to remove nodes with. +type NodeRemoveOptions struct { + Force bool +} + +// ServiceCreateOptions contains the options to use when creating a service. +type ServiceCreateOptions struct { + // EncodedRegistryAuth is the encoded registry authorization credentials to + // use when updating the service. + // + // This field follows the format of the X-Registry-Auth header. + EncodedRegistryAuth string + + // QueryRegistry indicates whether the service update requires + // contacting a registry. A registry may be contacted to retrieve + // the image digest and manifest, which in turn can be used to update + // platform or other information about the service. + QueryRegistry bool +} + +// ServiceCreateResponse contains the information returned to a client +// on the creation of a new service. +type ServiceCreateResponse struct { + // ID is the ID of the created service. + ID string + // Warnings is a set of non-fatal warning messages to pass on to the user. + Warnings []string `json:",omitempty"` +} + +// Values for RegistryAuthFrom in ServiceUpdateOptions +const ( + RegistryAuthFromSpec = "spec" + RegistryAuthFromPreviousSpec = "previous-spec" +) + +// ServiceUpdateOptions contains the options to be used for updating services. +type ServiceUpdateOptions struct { + // EncodedRegistryAuth is the encoded registry authorization credentials to + // use when updating the service. + // + // This field follows the format of the X-Registry-Auth header. + EncodedRegistryAuth string + + // TODO(stevvooe): Consider moving the version parameter of ServiceUpdate + // into this field. While it does open API users up to racy writes, most + // users may not need that level of consistency in practice. + + // RegistryAuthFrom specifies where to find the registry authorization + // credentials if they are not given in EncodedRegistryAuth. Valid + // values are "spec" and "previous-spec". + RegistryAuthFrom string + + // Rollback indicates whether a server-side rollback should be + // performed. When this is set, the provided spec will be ignored. + // The valid values are "previous" and "none". An empty value is the + // same as "none". + Rollback string + + // QueryRegistry indicates whether the service update requires + // contacting a registry. A registry may be contacted to retrieve + // the image digest and manifest, which in turn can be used to update + // platform or other information about the service. + QueryRegistry bool +} + +// ServiceListOptions holds parameters to list services with. +type ServiceListOptions struct { + Filters filters.Args +} + +// ServiceInspectOptions holds parameters related to the "service inspect" +// operation. +type ServiceInspectOptions struct { + InsertDefaults bool +} + +// TaskListOptions holds parameters to list tasks with. +type TaskListOptions struct { + Filters filters.Args +} + +// PluginRemoveOptions holds parameters to remove plugins. +type PluginRemoveOptions struct { + Force bool +} + +// PluginEnableOptions holds parameters to enable plugins. +type PluginEnableOptions struct { + Timeout int +} + +// PluginDisableOptions holds parameters to disable plugins. +type PluginDisableOptions struct { + Force bool +} + +// PluginInstallOptions holds parameters to install a plugin. +type PluginInstallOptions struct { + Disabled bool + AcceptAllPermissions bool + RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry + RemoteRef string // RemoteRef is the plugin name on the registry + PrivilegeFunc RequestPrivilegeFunc + AcceptPermissionsFunc func(PluginPrivileges) (bool, error) + Args []string +} + +// SwarmUnlockKeyResponse contains the response for Engine API: +// GET /swarm/unlockkey +type SwarmUnlockKeyResponse struct { + // UnlockKey is the unlock key in ASCII-armored format. + UnlockKey string +} + +// PluginCreateOptions hold all options to plugin create. +type PluginCreateOptions struct { + RepoName string +} diff --git a/vendor/github.com/docker/docker/api/types/configs.go b/vendor/github.com/docker/docker/api/types/configs.go new file mode 100644 index 000000000..f6537a27f --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/configs.go @@ -0,0 +1,57 @@ +package types // import "github.com/docker/docker/api/types" + +import ( + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/network" +) + +// configs holds structs used for internal communication between the +// frontend (such as an http server) and the backend (such as the +// docker daemon). + +// ContainerCreateConfig is the parameter set to ContainerCreate() +type ContainerCreateConfig struct { + Name string + Config *container.Config + HostConfig *container.HostConfig + NetworkingConfig *network.NetworkingConfig + AdjustCPUShares bool +} + +// ContainerRmConfig holds arguments for the container remove +// operation. This struct is used to tell the backend what operations +// to perform. +type ContainerRmConfig struct { + ForceRemove, RemoveVolume, RemoveLink bool +} + +// ExecConfig is a small subset of the Config struct that holds the configuration +// for the exec feature of docker. +type ExecConfig struct { + User string // User that will run the command + Privileged bool // Is the container in privileged mode + Tty bool // Attach standard streams to a tty. + AttachStdin bool // Attach the standard input, makes possible user interaction + AttachStderr bool // Attach the standard error + AttachStdout bool // Attach the standard output + Detach bool // Execute in detach mode + DetachKeys string // Escape keys for detach + Env []string // Environment variables + WorkingDir string // Working directory + Cmd []string // Execution commands and args +} + +// PluginRmConfig holds arguments for plugin remove. +type PluginRmConfig struct { + ForceRemove bool +} + +// PluginEnableConfig holds arguments for plugin enable +type PluginEnableConfig struct { + Timeout int +} + +// PluginDisableConfig holds arguments for plugin disable. +type PluginDisableConfig struct { + ForceDisable bool +} diff --git a/vendor/github.com/docker/docker/api/types/container/config.go b/vendor/github.com/docker/docker/api/types/container/config.go new file mode 100644 index 000000000..89ad08c23 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/config.go @@ -0,0 +1,69 @@ +package container // import "github.com/docker/docker/api/types/container" + +import ( + "time" + + "github.com/docker/docker/api/types/strslice" + "github.com/docker/go-connections/nat" +) + +// MinimumDuration puts a minimum on user configured duration. +// This is to prevent API error on time unit. For example, API may +// set 3 as healthcheck interval with intention of 3 seconds, but +// Docker interprets it as 3 nanoseconds. +const MinimumDuration = 1 * time.Millisecond + +// HealthConfig holds configuration settings for the HEALTHCHECK feature. +type HealthConfig struct { + // Test is the test to perform to check that the container is healthy. + // An empty slice means to inherit the default. + // The options are: + // {} : inherit healthcheck + // {"NONE"} : disable healthcheck + // {"CMD", args...} : exec arguments directly + // {"CMD-SHELL", command} : run command with system's default shell + Test []string `json:",omitempty"` + + // Zero means to inherit. Durations are expressed as integer nanoseconds. + Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. + Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. + StartPeriod time.Duration `json:",omitempty"` // The start period for the container to initialize before the retries starts to count down. + + // Retries is the number of consecutive failures needed to consider a container as unhealthy. + // Zero means inherit. + Retries int `json:",omitempty"` +} + +// Config contains the configuration data about a container. +// It should hold only portable information about the container. +// Here, "portable" means "independent from the host we are running on". +// Non-portable information *should* appear in HostConfig. +// All fields added to this struct must be marked `omitempty` to keep getting +// predictable hashes from the old `v1Compatibility` configuration. +type Config struct { + Hostname string // Hostname + Domainname string // Domainname + User string // User that will run the command(s) inside the container, also support user:group + AttachStdin bool // Attach the standard input, makes possible user interaction + AttachStdout bool // Attach the standard output + AttachStderr bool // Attach the standard error + ExposedPorts nat.PortSet `json:",omitempty"` // List of exposed ports + Tty bool // Attach standard streams to a tty, including stdin if it is not closed. + OpenStdin bool // Open stdin + StdinOnce bool // If true, close stdin after the 1 attached client disconnects. + Env []string // List of environment variable to set in the container + Cmd strslice.StrSlice // Command to run when starting the container + Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy + ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific) + Image string // Name of the image as it was passed by the operator (e.g. could be symbolic) + Volumes map[string]struct{} // List of volumes (mounts) used for the container + WorkingDir string // Current directory (PWD) in the command will be launched + Entrypoint strslice.StrSlice // Entrypoint to run when starting the container + NetworkDisabled bool `json:",omitempty"` // Is network disabled + MacAddress string `json:",omitempty"` // Mac Address of the container + OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile + Labels map[string]string // List of labels set to this container + StopSignal string `json:",omitempty"` // Signal to stop a container + StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container + Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT +} diff --git a/vendor/github.com/docker/docker/api/types/container/container_changes.go b/vendor/github.com/docker/docker/api/types/container/container_changes.go new file mode 100644 index 000000000..c909d6ca3 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/container_changes.go @@ -0,0 +1,21 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerChangeResponseItem change item in response to ContainerChanges operation +// swagger:model ContainerChangeResponseItem +type ContainerChangeResponseItem struct { + + // Kind of change + // Required: true + Kind uint8 `json:"Kind"` + + // Path to file that has changed + // Required: true + Path string `json:"Path"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/container_create.go b/vendor/github.com/docker/docker/api/types/container/container_create.go new file mode 100644 index 000000000..49efa0f2c --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/container_create.go @@ -0,0 +1,21 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerCreateCreatedBody OK response to ContainerCreate operation +// swagger:model ContainerCreateCreatedBody +type ContainerCreateCreatedBody struct { + + // The ID of the created container + // Required: true + ID string `json:"Id"` + + // Warnings encountered when creating the container + // Required: true + Warnings []string `json:"Warnings"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/container_top.go b/vendor/github.com/docker/docker/api/types/container/container_top.go new file mode 100644 index 000000000..ba41edcf3 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/container_top.go @@ -0,0 +1,21 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerTopOKBody OK response to ContainerTop operation +// swagger:model ContainerTopOKBody +type ContainerTopOKBody struct { + + // Each process running in the container, where each is process is an array of values corresponding to the titles + // Required: true + Processes [][]string `json:"Processes"` + + // The ps column titles + // Required: true + Titles []string `json:"Titles"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/container_update.go b/vendor/github.com/docker/docker/api/types/container/container_update.go new file mode 100644 index 000000000..7630ae54c --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/container_update.go @@ -0,0 +1,17 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerUpdateOKBody OK response to ContainerUpdate operation +// swagger:model ContainerUpdateOKBody +type ContainerUpdateOKBody struct { + + // warnings + // Required: true + Warnings []string `json:"Warnings"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/container_wait.go b/vendor/github.com/docker/docker/api/types/container/container_wait.go new file mode 100644 index 000000000..9e3910a6b --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/container_wait.go @@ -0,0 +1,29 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerWaitOKBodyError container waiting error, if any +// swagger:model ContainerWaitOKBodyError +type ContainerWaitOKBodyError struct { + + // Details of an error + Message string `json:"Message,omitempty"` +} + +// ContainerWaitOKBody OK response to ContainerWait operation +// swagger:model ContainerWaitOKBody +type ContainerWaitOKBody struct { + + // error + // Required: true + Error *ContainerWaitOKBodyError `json:"Error"` + + // Exit code of the container + // Required: true + StatusCode int64 `json:"StatusCode"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/host_config.go b/vendor/github.com/docker/docker/api/types/container/host_config.go new file mode 100644 index 000000000..4ef26fa6c --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/host_config.go @@ -0,0 +1,412 @@ +package container // import "github.com/docker/docker/api/types/container" + +import ( + "strings" + + "github.com/docker/docker/api/types/blkiodev" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/strslice" + "github.com/docker/go-connections/nat" + "github.com/docker/go-units" +) + +// Isolation represents the isolation technology of a container. The supported +// values are platform specific +type Isolation string + +// IsDefault indicates the default isolation technology of a container. On Linux this +// is the native driver. On Windows, this is a Windows Server Container. +func (i Isolation) IsDefault() bool { + return strings.ToLower(string(i)) == "default" || string(i) == "" +} + +// IsHyperV indicates the use of a Hyper-V partition for isolation +func (i Isolation) IsHyperV() bool { + return strings.ToLower(string(i)) == "hyperv" +} + +// IsProcess indicates the use of process isolation +func (i Isolation) IsProcess() bool { + return strings.ToLower(string(i)) == "process" +} + +const ( + // IsolationEmpty is unspecified (same behavior as default) + IsolationEmpty = Isolation("") + // IsolationDefault is the default isolation mode on current daemon + IsolationDefault = Isolation("default") + // IsolationProcess is process isolation mode + IsolationProcess = Isolation("process") + // IsolationHyperV is HyperV isolation mode + IsolationHyperV = Isolation("hyperv") +) + +// IpcMode represents the container ipc stack. +type IpcMode string + +// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared. +func (n IpcMode) IsPrivate() bool { + return n == "private" +} + +// IsHost indicates whether the container shares the host's ipc namespace. +func (n IpcMode) IsHost() bool { + return n == "host" +} + +// IsShareable indicates whether the container's ipc namespace can be shared with another container. +func (n IpcMode) IsShareable() bool { + return n == "shareable" +} + +// IsContainer indicates whether the container uses another container's ipc namespace. +func (n IpcMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// IsNone indicates whether container IpcMode is set to "none". +func (n IpcMode) IsNone() bool { + return n == "none" +} + +// IsEmpty indicates whether container IpcMode is empty +func (n IpcMode) IsEmpty() bool { + return n == "" +} + +// Valid indicates whether the ipc mode is valid. +func (n IpcMode) Valid() bool { + return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer() +} + +// Container returns the name of the container ipc stack is going to be used. +func (n IpcMode) Container() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 && parts[0] == "container" { + return parts[1] + } + return "" +} + +// NetworkMode represents the container network stack. +type NetworkMode string + +// IsNone indicates whether container isn't using a network stack. +func (n NetworkMode) IsNone() bool { + return n == "none" +} + +// IsDefault indicates whether container uses the default network stack. +func (n NetworkMode) IsDefault() bool { + return n == "default" +} + +// IsPrivate indicates whether container uses its private network stack. +func (n NetworkMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsContainer indicates whether container uses a container network stack. +func (n NetworkMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// ConnectedContainer is the id of the container which network this container is connected to. +func (n NetworkMode) ConnectedContainer() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +//UserDefined indicates user-created network +func (n NetworkMode) UserDefined() string { + if n.IsUserDefined() { + return string(n) + } + return "" +} + +// UsernsMode represents userns mode in the container. +type UsernsMode string + +// IsHost indicates whether the container uses the host's userns. +func (n UsernsMode) IsHost() bool { + return n == "host" +} + +// IsPrivate indicates whether the container uses the a private userns. +func (n UsernsMode) IsPrivate() bool { + return !(n.IsHost()) +} + +// Valid indicates whether the userns is valid. +func (n UsernsMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + default: + return false + } + return true +} + +// CgroupSpec represents the cgroup to use for the container. +type CgroupSpec string + +// IsContainer indicates whether the container is using another container cgroup +func (c CgroupSpec) IsContainer() bool { + parts := strings.SplitN(string(c), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the cgroup spec is valid. +func (c CgroupSpec) Valid() bool { + return c.IsContainer() || c == "" +} + +// Container returns the name of the container whose cgroup will be used. +func (c CgroupSpec) Container() string { + parts := strings.SplitN(string(c), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// UTSMode represents the UTS namespace of the container. +type UTSMode string + +// IsPrivate indicates whether the container uses its private UTS namespace. +func (n UTSMode) IsPrivate() bool { + return !(n.IsHost()) +} + +// IsHost indicates whether the container uses the host's UTS namespace. +func (n UTSMode) IsHost() bool { + return n == "host" +} + +// Valid indicates whether the UTS namespace is valid. +func (n UTSMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + default: + return false + } + return true +} + +// PidMode represents the pid namespace of the container. +type PidMode string + +// IsPrivate indicates whether the container uses its own new pid namespace. +func (n PidMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsHost indicates whether the container uses the host's pid namespace. +func (n PidMode) IsHost() bool { + return n == "host" +} + +// IsContainer indicates whether the container uses a container's pid namespace. +func (n PidMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the pid namespace is valid. +func (n PidMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + case "container": + if len(parts) != 2 || parts[1] == "" { + return false + } + default: + return false + } + return true +} + +// Container returns the name of the container whose pid namespace is going to be used. +func (n PidMode) Container() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// DeviceMapping represents the device mapping between the host and the container. +type DeviceMapping struct { + PathOnHost string + PathInContainer string + CgroupPermissions string +} + +// RestartPolicy represents the restart policies of the container. +type RestartPolicy struct { + Name string + MaximumRetryCount int +} + +// IsNone indicates whether the container has the "no" restart policy. +// This means the container will not automatically restart when exiting. +func (rp *RestartPolicy) IsNone() bool { + return rp.Name == "no" || rp.Name == "" +} + +// IsAlways indicates whether the container has the "always" restart policy. +// This means the container will automatically restart regardless of the exit status. +func (rp *RestartPolicy) IsAlways() bool { + return rp.Name == "always" +} + +// IsOnFailure indicates whether the container has the "on-failure" restart policy. +// This means the container will automatically restart of exiting with a non-zero exit status. +func (rp *RestartPolicy) IsOnFailure() bool { + return rp.Name == "on-failure" +} + +// IsUnlessStopped indicates whether the container has the +// "unless-stopped" restart policy. This means the container will +// automatically restart unless user has put it to stopped state. +func (rp *RestartPolicy) IsUnlessStopped() bool { + return rp.Name == "unless-stopped" +} + +// IsSame compares two RestartPolicy to see if they are the same +func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool { + return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount +} + +// LogMode is a type to define the available modes for logging +// These modes affect how logs are handled when log messages start piling up. +type LogMode string + +// Available logging modes +const ( + LogModeUnset = "" + LogModeBlocking LogMode = "blocking" + LogModeNonBlock LogMode = "non-blocking" +) + +// LogConfig represents the logging configuration of the container. +type LogConfig struct { + Type string + Config map[string]string +} + +// Resources contains container's resources (cgroups config, ulimits...) +type Resources struct { + // Applicable to all platforms + CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers) + Memory int64 // Memory limit (in bytes) + NanoCPUs int64 `json:"NanoCpus"` // CPU quota in units of 10-9 CPUs. + + // Applicable to UNIX platforms + CgroupParent string // Parent cgroup. + BlkioWeight uint16 // Block IO weight (relative weight vs. other containers) + BlkioWeightDevice []*blkiodev.WeightDevice + BlkioDeviceReadBps []*blkiodev.ThrottleDevice + BlkioDeviceWriteBps []*blkiodev.ThrottleDevice + BlkioDeviceReadIOps []*blkiodev.ThrottleDevice + BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice + CPUPeriod int64 `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period + CPUQuota int64 `json:"CpuQuota"` // CPU CFS (Completely Fair Scheduler) quota + CPURealtimePeriod int64 `json:"CpuRealtimePeriod"` // CPU real-time period + CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime"` // CPU real-time runtime + CpusetCpus string // CpusetCpus 0-2, 0,1 + CpusetMems string // CpusetMems 0-2, 0,1 + Devices []DeviceMapping // List of devices to map inside the container + DeviceCgroupRules []string // List of rule to be added to the device cgroup + DiskQuota int64 // Disk limit (in bytes) + KernelMemory int64 // Kernel memory limit (in bytes) + MemoryReservation int64 // Memory soft limit (in bytes) + MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap + MemorySwappiness *int64 // Tuning container memory swappiness behaviour + OomKillDisable *bool // Whether to disable OOM Killer or not + PidsLimit int64 // Setting pids limit for a container + Ulimits []*units.Ulimit // List of ulimits to be set in the container + + // Applicable to Windows + CPUCount int64 `json:"CpuCount"` // CPU count + CPUPercent int64 `json:"CpuPercent"` // CPU percent + IOMaximumIOps uint64 // Maximum IOps for the container system drive + IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive +} + +// UpdateConfig holds the mutable attributes of a Container. +// Those attributes can be updated at runtime. +type UpdateConfig struct { + // Contains container's resources (cgroups, ulimits) + Resources + RestartPolicy RestartPolicy +} + +// HostConfig the non-portable Config structure of a container. +// Here, "non-portable" means "dependent of the host we are running on". +// Portable information *should* appear in Config. +type HostConfig struct { + // Applicable to all platforms + Binds []string // List of volume bindings for this container + ContainerIDFile string // File (path) where the containerId is written + LogConfig LogConfig // Configuration of the logs for this container + NetworkMode NetworkMode // Network mode to use for the container + PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host + RestartPolicy RestartPolicy // Restart policy to be used for the container + AutoRemove bool // Automatically remove container when it exits + VolumeDriver string // Name of the volume driver used to mount volumes + VolumesFrom []string // List of volumes to take from other container + + // Applicable to UNIX platforms + CapAdd strslice.StrSlice // List of kernel capabilities to add to the container + CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container + DNS []string `json:"Dns"` // List of DNS server to lookup + DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for + DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for + ExtraHosts []string // List of extra hosts + GroupAdd []string // List of additional groups that the container process will run as + IpcMode IpcMode // IPC namespace to use for the container + Cgroup CgroupSpec // Cgroup to use for the container + Links []string // List of links (in the name:alias form) + OomScoreAdj int // Container preference for OOM-killing + PidMode PidMode // PID namespace to use for the container + Privileged bool // Is the container in privileged mode + PublishAllPorts bool // Should docker publish all exposed port for the container + ReadonlyRootfs bool // Is the container root filesystem in read-only + SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux. + StorageOpt map[string]string `json:",omitempty"` // Storage driver options per container. + Tmpfs map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container + UTSMode UTSMode // UTS namespace to use for the container + UsernsMode UsernsMode // The user namespace to use for the container + ShmSize int64 // Total shm memory usage + Sysctls map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container + Runtime string `json:",omitempty"` // Runtime to use with this container + + // Applicable to Windows + ConsoleSize [2]uint // Initial console size (height,width) + Isolation Isolation // Isolation technology of the container (e.g. default, hyperv) + + // Contains container's resources (cgroups, ulimits) + Resources + + // Mounts specs used by the container + Mounts []mount.Mount `json:",omitempty"` + + // MaskedPaths is the list of paths to be masked inside the container (this overrides the default set of paths) + MaskedPaths []string + + // ReadonlyPaths is the list of paths to be set as read-only inside the container (this overrides the default set of paths) + ReadonlyPaths []string + + // Run a custom init inside the container, if null, use the daemon's configured settings + Init *bool `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go b/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go new file mode 100644 index 000000000..cf6fdf440 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go @@ -0,0 +1,41 @@ +// +build !windows + +package container // import "github.com/docker/docker/api/types/container" + +// IsValid indicates if an isolation technology is valid +func (i Isolation) IsValid() bool { + return i.IsDefault() +} + +// NetworkName returns the name of the network stack. +func (n NetworkMode) NetworkName() string { + if n.IsBridge() { + return "bridge" + } else if n.IsHost() { + return "host" + } else if n.IsContainer() { + return "container" + } else if n.IsNone() { + return "none" + } else if n.IsDefault() { + return "default" + } else if n.IsUserDefined() { + return n.UserDefined() + } + return "" +} + +// IsBridge indicates whether container uses the bridge network stack +func (n NetworkMode) IsBridge() bool { + return n == "bridge" +} + +// IsHost indicates whether container uses the host network stack. +func (n NetworkMode) IsHost() bool { + return n == "host" +} + +// IsUserDefined indicates user-created network +func (n NetworkMode) IsUserDefined() bool { + return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() +} diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go b/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go new file mode 100644 index 000000000..99f803a5b --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go @@ -0,0 +1,40 @@ +package container // import "github.com/docker/docker/api/types/container" + +// IsBridge indicates whether container uses the bridge network stack +// in windows it is given the name NAT +func (n NetworkMode) IsBridge() bool { + return n == "nat" +} + +// IsHost indicates whether container uses the host network stack. +// returns false as this is not supported by windows +func (n NetworkMode) IsHost() bool { + return false +} + +// IsUserDefined indicates user-created network +func (n NetworkMode) IsUserDefined() bool { + return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer() +} + +// IsValid indicates if an isolation technology is valid +func (i Isolation) IsValid() bool { + return i.IsDefault() || i.IsHyperV() || i.IsProcess() +} + +// NetworkName returns the name of the network stack. +func (n NetworkMode) NetworkName() string { + if n.IsDefault() { + return "default" + } else if n.IsBridge() { + return "nat" + } else if n.IsNone() { + return "none" + } else if n.IsContainer() { + return "container" + } else if n.IsUserDefined() { + return n.UserDefined() + } + + return "" +} diff --git a/vendor/github.com/docker/docker/api/types/container/waitcondition.go b/vendor/github.com/docker/docker/api/types/container/waitcondition.go new file mode 100644 index 000000000..cd8311f99 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/waitcondition.go @@ -0,0 +1,22 @@ +package container // import "github.com/docker/docker/api/types/container" + +// WaitCondition is a type used to specify a container state for which +// to wait. +type WaitCondition string + +// Possible WaitCondition Values. +// +// WaitConditionNotRunning (default) is used to wait for any of the non-running +// states: "created", "exited", "dead", "removing", or "removed". +// +// WaitConditionNextExit is used to wait for the next time the state changes +// to a non-running state. If the state is currently "created" or "exited", +// this would cause Wait() to block until either the container runs and exits +// or is removed. +// +// WaitConditionRemoved is used to wait for the container to be removed. +const ( + WaitConditionNotRunning WaitCondition = "not-running" + WaitConditionNextExit WaitCondition = "next-exit" + WaitConditionRemoved WaitCondition = "removed" +) diff --git a/vendor/github.com/docker/docker/api/types/error_response.go b/vendor/github.com/docker/docker/api/types/error_response.go new file mode 100644 index 000000000..dc942d9d9 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/error_response.go @@ -0,0 +1,13 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// ErrorResponse Represents an error. +// swagger:model ErrorResponse +type ErrorResponse struct { + + // The error message. + // Required: true + Message string `json:"message"` +} diff --git a/vendor/github.com/docker/docker/api/types/filters/parse.go b/vendor/github.com/docker/docker/api/types/filters/parse.go new file mode 100644 index 000000000..a41e3d8d9 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/filters/parse.go @@ -0,0 +1,350 @@ +/*Package filters provides tools for encoding a mapping of keys to a set of +multiple values. +*/ +package filters // import "github.com/docker/docker/api/types/filters" + +import ( + "encoding/json" + "errors" + "regexp" + "strings" + + "github.com/docker/docker/api/types/versions" +) + +// Args stores a mapping of keys to a set of multiple values. +type Args struct { + fields map[string]map[string]bool +} + +// KeyValuePair are used to initialize a new Args +type KeyValuePair struct { + Key string + Value string +} + +// Arg creates a new KeyValuePair for initializing Args +func Arg(key, value string) KeyValuePair { + return KeyValuePair{Key: key, Value: value} +} + +// NewArgs returns a new Args populated with the initial args +func NewArgs(initialArgs ...KeyValuePair) Args { + args := Args{fields: map[string]map[string]bool{}} + for _, arg := range initialArgs { + args.Add(arg.Key, arg.Value) + } + return args +} + +// ParseFlag parses a key=value string and adds it to an Args. +// +// Deprecated: Use Args.Add() +func ParseFlag(arg string, prev Args) (Args, error) { + filters := prev + if len(arg) == 0 { + return filters, nil + } + + if !strings.Contains(arg, "=") { + return filters, ErrBadFormat + } + + f := strings.SplitN(arg, "=", 2) + + name := strings.ToLower(strings.TrimSpace(f[0])) + value := strings.TrimSpace(f[1]) + + filters.Add(name, value) + + return filters, nil +} + +// ErrBadFormat is an error returned when a filter is not in the form key=value +// +// Deprecated: this error will be removed in a future version +var ErrBadFormat = errors.New("bad format of filter (expected name=value)") + +// ToParam encodes the Args as args JSON encoded string +// +// Deprecated: use ToJSON +func ToParam(a Args) (string, error) { + return ToJSON(a) +} + +// MarshalJSON returns a JSON byte representation of the Args +func (args Args) MarshalJSON() ([]byte, error) { + if len(args.fields) == 0 { + return []byte{}, nil + } + return json.Marshal(args.fields) +} + +// ToJSON returns the Args as a JSON encoded string +func ToJSON(a Args) (string, error) { + if a.Len() == 0 { + return "", nil + } + buf, err := json.Marshal(a) + return string(buf), err +} + +// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22 +// then the encoded format will use an older legacy format where the values are a +// list of strings, instead of a set. +// +// Deprecated: Use ToJSON +func ToParamWithVersion(version string, a Args) (string, error) { + if a.Len() == 0 { + return "", nil + } + + if version != "" && versions.LessThan(version, "1.22") { + buf, err := json.Marshal(convertArgsToSlice(a.fields)) + return string(buf), err + } + + return ToJSON(a) +} + +// FromParam decodes a JSON encoded string into Args +// +// Deprecated: use FromJSON +func FromParam(p string) (Args, error) { + return FromJSON(p) +} + +// FromJSON decodes a JSON encoded string into Args +func FromJSON(p string) (Args, error) { + args := NewArgs() + + if p == "" { + return args, nil + } + + raw := []byte(p) + err := json.Unmarshal(raw, &args) + if err == nil { + return args, nil + } + + // Fallback to parsing arguments in the legacy slice format + deprecated := map[string][]string{} + if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil { + return args, err + } + + args.fields = deprecatedArgs(deprecated) + return args, nil +} + +// UnmarshalJSON populates the Args from JSON encode bytes +func (args Args) UnmarshalJSON(raw []byte) error { + if len(raw) == 0 { + return nil + } + return json.Unmarshal(raw, &args.fields) +} + +// Get returns the list of values associated with the key +func (args Args) Get(key string) []string { + values := args.fields[key] + if values == nil { + return make([]string, 0) + } + slice := make([]string, 0, len(values)) + for key := range values { + slice = append(slice, key) + } + return slice +} + +// Add a new value to the set of values +func (args Args) Add(key, value string) { + if _, ok := args.fields[key]; ok { + args.fields[key][value] = true + } else { + args.fields[key] = map[string]bool{value: true} + } +} + +// Del removes a value from the set +func (args Args) Del(key, value string) { + if _, ok := args.fields[key]; ok { + delete(args.fields[key], value) + if len(args.fields[key]) == 0 { + delete(args.fields, key) + } + } +} + +// Len returns the number of keys in the mapping +func (args Args) Len() int { + return len(args.fields) +} + +// MatchKVList returns true if all the pairs in sources exist as key=value +// pairs in the mapping at key, or if there are no values at key. +func (args Args) MatchKVList(key string, sources map[string]string) bool { + fieldValues := args.fields[key] + + //do not filter if there is no filter set or cannot determine filter + if len(fieldValues) == 0 { + return true + } + + if len(sources) == 0 { + return false + } + + for value := range fieldValues { + testKV := strings.SplitN(value, "=", 2) + + v, ok := sources[testKV[0]] + if !ok { + return false + } + if len(testKV) == 2 && testKV[1] != v { + return false + } + } + + return true +} + +// Match returns true if any of the values at key match the source string +func (args Args) Match(field, source string) bool { + if args.ExactMatch(field, source) { + return true + } + + fieldValues := args.fields[field] + for name2match := range fieldValues { + match, err := regexp.MatchString(name2match, source) + if err != nil { + continue + } + if match { + return true + } + } + return false +} + +// ExactMatch returns true if the source matches exactly one of the values. +func (args Args) ExactMatch(key, source string) bool { + fieldValues, ok := args.fields[key] + //do not filter if there is no filter set or cannot determine filter + if !ok || len(fieldValues) == 0 { + return true + } + + // try to match full name value to avoid O(N) regular expression matching + return fieldValues[source] +} + +// UniqueExactMatch returns true if there is only one value and the source +// matches exactly the value. +func (args Args) UniqueExactMatch(key, source string) bool { + fieldValues := args.fields[key] + //do not filter if there is no filter set or cannot determine filter + if len(fieldValues) == 0 { + return true + } + if len(args.fields[key]) != 1 { + return false + } + + // try to match full name value to avoid O(N) regular expression matching + return fieldValues[source] +} + +// FuzzyMatch returns true if the source matches exactly one value, or the +// source has one of the values as a prefix. +func (args Args) FuzzyMatch(key, source string) bool { + if args.ExactMatch(key, source) { + return true + } + + fieldValues := args.fields[key] + for prefix := range fieldValues { + if strings.HasPrefix(source, prefix) { + return true + } + } + return false +} + +// Include returns true if the key exists in the mapping +// +// Deprecated: use Contains +func (args Args) Include(field string) bool { + _, ok := args.fields[field] + return ok +} + +// Contains returns true if the key exists in the mapping +func (args Args) Contains(field string) bool { + _, ok := args.fields[field] + return ok +} + +type invalidFilter string + +func (e invalidFilter) Error() string { + return "Invalid filter '" + string(e) + "'" +} + +func (invalidFilter) InvalidParameter() {} + +// Validate compared the set of accepted keys against the keys in the mapping. +// An error is returned if any mapping keys are not in the accepted set. +func (args Args) Validate(accepted map[string]bool) error { + for name := range args.fields { + if !accepted[name] { + return invalidFilter(name) + } + } + return nil +} + +// WalkValues iterates over the list of values for a key in the mapping and calls +// op() for each value. If op returns an error the iteration stops and the +// error is returned. +func (args Args) WalkValues(field string, op func(value string) error) error { + if _, ok := args.fields[field]; !ok { + return nil + } + for v := range args.fields[field] { + if err := op(v); err != nil { + return err + } + } + return nil +} + +func deprecatedArgs(d map[string][]string) map[string]map[string]bool { + m := map[string]map[string]bool{} + for k, v := range d { + values := map[string]bool{} + for _, vv := range v { + values[vv] = true + } + m[k] = values + } + return m +} + +func convertArgsToSlice(f map[string]map[string]bool) map[string][]string { + m := map[string][]string{} + for k, v := range f { + values := []string{} + for kk := range v { + if v[kk] { + values = append(values, kk) + } + } + m[k] = values + } + return m +} diff --git a/vendor/github.com/docker/docker/api/types/graph_driver_data.go b/vendor/github.com/docker/docker/api/types/graph_driver_data.go new file mode 100644 index 000000000..4d9bf1c62 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/graph_driver_data.go @@ -0,0 +1,17 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// GraphDriverData Information about a container's graph driver. +// swagger:model GraphDriverData +type GraphDriverData struct { + + // data + // Required: true + Data map[string]string `json:"Data"` + + // name + // Required: true + Name string `json:"Name"` +} diff --git a/vendor/github.com/docker/docker/api/types/id_response.go b/vendor/github.com/docker/docker/api/types/id_response.go new file mode 100644 index 000000000..7592d2f8b --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/id_response.go @@ -0,0 +1,13 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// IDResponse Response to an API call that returns just an Id +// swagger:model IdResponse +type IDResponse struct { + + // The id of the newly created object. + // Required: true + ID string `json:"Id"` +} diff --git a/vendor/github.com/docker/docker/api/types/image_delete_response_item.go b/vendor/github.com/docker/docker/api/types/image_delete_response_item.go new file mode 100644 index 000000000..b9a65a0d8 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/image_delete_response_item.go @@ -0,0 +1,15 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// ImageDeleteResponseItem image delete response item +// swagger:model ImageDeleteResponseItem +type ImageDeleteResponseItem struct { + + // The image ID of an image that was deleted + Deleted string `json:"Deleted,omitempty"` + + // The image ID of an image that was untagged + Untagged string `json:"Untagged,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/image_summary.go b/vendor/github.com/docker/docker/api/types/image_summary.go new file mode 100644 index 000000000..e145b3dcf --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/image_summary.go @@ -0,0 +1,49 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// ImageSummary image summary +// swagger:model ImageSummary +type ImageSummary struct { + + // containers + // Required: true + Containers int64 `json:"Containers"` + + // created + // Required: true + Created int64 `json:"Created"` + + // Id + // Required: true + ID string `json:"Id"` + + // labels + // Required: true + Labels map[string]string `json:"Labels"` + + // parent Id + // Required: true + ParentID string `json:"ParentId"` + + // repo digests + // Required: true + RepoDigests []string `json:"RepoDigests"` + + // repo tags + // Required: true + RepoTags []string `json:"RepoTags"` + + // shared size + // Required: true + SharedSize int64 `json:"SharedSize"` + + // size + // Required: true + Size int64 `json:"Size"` + + // virtual size + // Required: true + VirtualSize int64 `json:"VirtualSize"` +} diff --git a/vendor/github.com/docker/docker/api/types/mount/mount.go b/vendor/github.com/docker/docker/api/types/mount/mount.go new file mode 100644 index 000000000..3fef974df --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/mount/mount.go @@ -0,0 +1,130 @@ +package mount // import "github.com/docker/docker/api/types/mount" + +import ( + "os" +) + +// Type represents the type of a mount. +type Type string + +// Type constants +const ( + // TypeBind is the type for mounting host dir + TypeBind Type = "bind" + // TypeVolume is the type for remote storage volumes + TypeVolume Type = "volume" + // TypeTmpfs is the type for mounting tmpfs + TypeTmpfs Type = "tmpfs" + // TypeNamedPipe is the type for mounting Windows named pipes + TypeNamedPipe Type = "npipe" +) + +// Mount represents a mount (volume). +type Mount struct { + Type Type `json:",omitempty"` + // Source specifies the name of the mount. Depending on mount type, this + // may be a volume name or a host path, or even ignored. + // Source is not supported for tmpfs (must be an empty value) + Source string `json:",omitempty"` + Target string `json:",omitempty"` + ReadOnly bool `json:",omitempty"` + Consistency Consistency `json:",omitempty"` + + BindOptions *BindOptions `json:",omitempty"` + VolumeOptions *VolumeOptions `json:",omitempty"` + TmpfsOptions *TmpfsOptions `json:",omitempty"` +} + +// Propagation represents the propagation of a mount. +type Propagation string + +const ( + // PropagationRPrivate RPRIVATE + PropagationRPrivate Propagation = "rprivate" + // PropagationPrivate PRIVATE + PropagationPrivate Propagation = "private" + // PropagationRShared RSHARED + PropagationRShared Propagation = "rshared" + // PropagationShared SHARED + PropagationShared Propagation = "shared" + // PropagationRSlave RSLAVE + PropagationRSlave Propagation = "rslave" + // PropagationSlave SLAVE + PropagationSlave Propagation = "slave" +) + +// Propagations is the list of all valid mount propagations +var Propagations = []Propagation{ + PropagationRPrivate, + PropagationPrivate, + PropagationRShared, + PropagationShared, + PropagationRSlave, + PropagationSlave, +} + +// Consistency represents the consistency requirements of a mount. +type Consistency string + +const ( + // ConsistencyFull guarantees bind mount-like consistency + ConsistencyFull Consistency = "consistent" + // ConsistencyCached mounts can cache read data and FS structure + ConsistencyCached Consistency = "cached" + // ConsistencyDelegated mounts can cache read and written data and structure + ConsistencyDelegated Consistency = "delegated" + // ConsistencyDefault provides "consistent" behavior unless overridden + ConsistencyDefault Consistency = "default" +) + +// BindOptions defines options specific to mounts of type "bind". +type BindOptions struct { + Propagation Propagation `json:",omitempty"` +} + +// VolumeOptions represents the options for a mount of type volume. +type VolumeOptions struct { + NoCopy bool `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + DriverConfig *Driver `json:",omitempty"` +} + +// Driver represents a volume driver. +type Driver struct { + Name string `json:",omitempty"` + Options map[string]string `json:",omitempty"` +} + +// TmpfsOptions defines options specific to mounts of type "tmpfs". +type TmpfsOptions struct { + // Size sets the size of the tmpfs, in bytes. + // + // This will be converted to an operating system specific value + // depending on the host. For example, on linux, it will be converted to + // use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with + // docker, uses a straight byte value. + // + // Percentages are not supported. + SizeBytes int64 `json:",omitempty"` + // Mode of the tmpfs upon creation + Mode os.FileMode `json:",omitempty"` + + // TODO(stevvooe): There are several more tmpfs flags, specified in the + // daemon, that are accepted. Only the most basic are added for now. + // + // From docker/docker/pkg/mount/flags.go: + // + // var validFlags = map[string]bool{ + // "": true, + // "size": true, X + // "mode": true, X + // "uid": true, + // "gid": true, + // "nr_inodes": true, + // "nr_blocks": true, + // "mpol": true, + // } + // + // Some of these may be straightforward to add, but others, such as + // uid/gid have implications in a clustered system. +} diff --git a/vendor/github.com/docker/docker/api/types/network/network.go b/vendor/github.com/docker/docker/api/types/network/network.go new file mode 100644 index 000000000..761d0b34f --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/network/network.go @@ -0,0 +1,108 @@ +package network // import "github.com/docker/docker/api/types/network" + +// Address represents an IP address +type Address struct { + Addr string + PrefixLen int +} + +// IPAM represents IP Address Management +type IPAM struct { + Driver string + Options map[string]string //Per network IPAM driver options + Config []IPAMConfig +} + +// IPAMConfig represents IPAM configurations +type IPAMConfig struct { + Subnet string `json:",omitempty"` + IPRange string `json:",omitempty"` + Gateway string `json:",omitempty"` + AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"` +} + +// EndpointIPAMConfig represents IPAM configurations for the endpoint +type EndpointIPAMConfig struct { + IPv4Address string `json:",omitempty"` + IPv6Address string `json:",omitempty"` + LinkLocalIPs []string `json:",omitempty"` +} + +// Copy makes a copy of the endpoint ipam config +func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig { + cfgCopy := *cfg + cfgCopy.LinkLocalIPs = make([]string, 0, len(cfg.LinkLocalIPs)) + cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, cfg.LinkLocalIPs...) + return &cfgCopy +} + +// PeerInfo represents one peer of an overlay network +type PeerInfo struct { + Name string + IP string +} + +// EndpointSettings stores the network endpoint details +type EndpointSettings struct { + // Configurations + IPAMConfig *EndpointIPAMConfig + Links []string + Aliases []string + // Operational data + NetworkID string + EndpointID string + Gateway string + IPAddress string + IPPrefixLen int + IPv6Gateway string + GlobalIPv6Address string + GlobalIPv6PrefixLen int + MacAddress string + DriverOpts map[string]string +} + +// Task carries the information about one backend task +type Task struct { + Name string + EndpointID string + EndpointIP string + Info map[string]string +} + +// ServiceInfo represents service parameters with the list of service's tasks +type ServiceInfo struct { + VIP string + Ports []string + LocalLBIndex int + Tasks []Task +} + +// Copy makes a deep copy of `EndpointSettings` +func (es *EndpointSettings) Copy() *EndpointSettings { + epCopy := *es + if es.IPAMConfig != nil { + epCopy.IPAMConfig = es.IPAMConfig.Copy() + } + + if es.Links != nil { + links := make([]string, 0, len(es.Links)) + epCopy.Links = append(links, es.Links...) + } + + if es.Aliases != nil { + aliases := make([]string, 0, len(es.Aliases)) + epCopy.Aliases = append(aliases, es.Aliases...) + } + return &epCopy +} + +// NetworkingConfig represents the container's networking configuration for each of its interfaces +// Carries the networking configs specified in the `docker run` and `docker network connect` commands +type NetworkingConfig struct { + EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each connecting network +} + +// ConfigReference specifies the source which provides a network's configuration +type ConfigReference struct { + Network string +} diff --git a/vendor/github.com/docker/docker/api/types/plugin.go b/vendor/github.com/docker/docker/api/types/plugin.go new file mode 100644 index 000000000..abae48b9a --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin.go @@ -0,0 +1,203 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// Plugin A plugin for the Engine API +// swagger:model Plugin +type Plugin struct { + + // config + // Required: true + Config PluginConfig `json:"Config"` + + // True if the plugin is running. False if the plugin is not running, only installed. + // Required: true + Enabled bool `json:"Enabled"` + + // Id + ID string `json:"Id,omitempty"` + + // name + // Required: true + Name string `json:"Name"` + + // plugin remote reference used to push/pull the plugin + PluginReference string `json:"PluginReference,omitempty"` + + // settings + // Required: true + Settings PluginSettings `json:"Settings"` +} + +// PluginConfig The config of a plugin. +// swagger:model PluginConfig +type PluginConfig struct { + + // args + // Required: true + Args PluginConfigArgs `json:"Args"` + + // description + // Required: true + Description string `json:"Description"` + + // Docker Version used to create the plugin + DockerVersion string `json:"DockerVersion,omitempty"` + + // documentation + // Required: true + Documentation string `json:"Documentation"` + + // entrypoint + // Required: true + Entrypoint []string `json:"Entrypoint"` + + // env + // Required: true + Env []PluginEnv `json:"Env"` + + // interface + // Required: true + Interface PluginConfigInterface `json:"Interface"` + + // ipc host + // Required: true + IpcHost bool `json:"IpcHost"` + + // linux + // Required: true + Linux PluginConfigLinux `json:"Linux"` + + // mounts + // Required: true + Mounts []PluginMount `json:"Mounts"` + + // network + // Required: true + Network PluginConfigNetwork `json:"Network"` + + // pid host + // Required: true + PidHost bool `json:"PidHost"` + + // propagated mount + // Required: true + PropagatedMount string `json:"PropagatedMount"` + + // user + User PluginConfigUser `json:"User,omitempty"` + + // work dir + // Required: true + WorkDir string `json:"WorkDir"` + + // rootfs + Rootfs *PluginConfigRootfs `json:"rootfs,omitempty"` +} + +// PluginConfigArgs plugin config args +// swagger:model PluginConfigArgs +type PluginConfigArgs struct { + + // description + // Required: true + Description string `json:"Description"` + + // name + // Required: true + Name string `json:"Name"` + + // settable + // Required: true + Settable []string `json:"Settable"` + + // value + // Required: true + Value []string `json:"Value"` +} + +// PluginConfigInterface The interface between Docker and the plugin +// swagger:model PluginConfigInterface +type PluginConfigInterface struct { + + // Protocol to use for clients connecting to the plugin. + ProtocolScheme string `json:"ProtocolScheme,omitempty"` + + // socket + // Required: true + Socket string `json:"Socket"` + + // types + // Required: true + Types []PluginInterfaceType `json:"Types"` +} + +// PluginConfigLinux plugin config linux +// swagger:model PluginConfigLinux +type PluginConfigLinux struct { + + // allow all devices + // Required: true + AllowAllDevices bool `json:"AllowAllDevices"` + + // capabilities + // Required: true + Capabilities []string `json:"Capabilities"` + + // devices + // Required: true + Devices []PluginDevice `json:"Devices"` +} + +// PluginConfigNetwork plugin config network +// swagger:model PluginConfigNetwork +type PluginConfigNetwork struct { + + // type + // Required: true + Type string `json:"Type"` +} + +// PluginConfigRootfs plugin config rootfs +// swagger:model PluginConfigRootfs +type PluginConfigRootfs struct { + + // diff ids + DiffIds []string `json:"diff_ids"` + + // type + Type string `json:"type,omitempty"` +} + +// PluginConfigUser plugin config user +// swagger:model PluginConfigUser +type PluginConfigUser struct { + + // g ID + GID uint32 `json:"GID,omitempty"` + + // UID + UID uint32 `json:"UID,omitempty"` +} + +// PluginSettings Settings that can be modified by users. +// swagger:model PluginSettings +type PluginSettings struct { + + // args + // Required: true + Args []string `json:"Args"` + + // devices + // Required: true + Devices []PluginDevice `json:"Devices"` + + // env + // Required: true + Env []string `json:"Env"` + + // mounts + // Required: true + Mounts []PluginMount `json:"Mounts"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_device.go b/vendor/github.com/docker/docker/api/types/plugin_device.go new file mode 100644 index 000000000..569901067 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_device.go @@ -0,0 +1,25 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// PluginDevice plugin device +// swagger:model PluginDevice +type PluginDevice struct { + + // description + // Required: true + Description string `json:"Description"` + + // name + // Required: true + Name string `json:"Name"` + + // path + // Required: true + Path *string `json:"Path"` + + // settable + // Required: true + Settable []string `json:"Settable"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_env.go b/vendor/github.com/docker/docker/api/types/plugin_env.go new file mode 100644 index 000000000..32962dc2e --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_env.go @@ -0,0 +1,25 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// PluginEnv plugin env +// swagger:model PluginEnv +type PluginEnv struct { + + // description + // Required: true + Description string `json:"Description"` + + // name + // Required: true + Name string `json:"Name"` + + // settable + // Required: true + Settable []string `json:"Settable"` + + // value + // Required: true + Value *string `json:"Value"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_interface_type.go b/vendor/github.com/docker/docker/api/types/plugin_interface_type.go new file mode 100644 index 000000000..c82f204e8 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_interface_type.go @@ -0,0 +1,21 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// PluginInterfaceType plugin interface type +// swagger:model PluginInterfaceType +type PluginInterfaceType struct { + + // capability + // Required: true + Capability string `json:"Capability"` + + // prefix + // Required: true + Prefix string `json:"Prefix"` + + // version + // Required: true + Version string `json:"Version"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_mount.go b/vendor/github.com/docker/docker/api/types/plugin_mount.go new file mode 100644 index 000000000..5c031cf8b --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_mount.go @@ -0,0 +1,37 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// PluginMount plugin mount +// swagger:model PluginMount +type PluginMount struct { + + // description + // Required: true + Description string `json:"Description"` + + // destination + // Required: true + Destination string `json:"Destination"` + + // name + // Required: true + Name string `json:"Name"` + + // options + // Required: true + Options []string `json:"Options"` + + // settable + // Required: true + Settable []string `json:"Settable"` + + // source + // Required: true + Source *string `json:"Source"` + + // type + // Required: true + Type string `json:"Type"` +} diff --git a/vendor/github.com/docker/docker/api/types/plugin_responses.go b/vendor/github.com/docker/docker/api/types/plugin_responses.go new file mode 100644 index 000000000..60d1fb5ad --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/plugin_responses.go @@ -0,0 +1,71 @@ +package types // import "github.com/docker/docker/api/types" + +import ( + "encoding/json" + "fmt" + "sort" +) + +// PluginsListResponse contains the response for the Engine API +type PluginsListResponse []*Plugin + +// UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType +func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error { + versionIndex := len(p) + prefixIndex := 0 + if len(p) < 2 || p[0] != '"' || p[len(p)-1] != '"' { + return fmt.Errorf("%q is not a plugin interface type", p) + } + p = p[1 : len(p)-1] +loop: + for i, b := range p { + switch b { + case '.': + prefixIndex = i + case '/': + versionIndex = i + break loop + } + } + t.Prefix = string(p[:prefixIndex]) + t.Capability = string(p[prefixIndex+1 : versionIndex]) + if versionIndex < len(p) { + t.Version = string(p[versionIndex+1:]) + } + return nil +} + +// MarshalJSON implements json.Marshaler for PluginInterfaceType +func (t *PluginInterfaceType) MarshalJSON() ([]byte, error) { + return json.Marshal(t.String()) +} + +// String implements fmt.Stringer for PluginInterfaceType +func (t PluginInterfaceType) String() string { + return fmt.Sprintf("%s.%s/%s", t.Prefix, t.Capability, t.Version) +} + +// PluginPrivilege describes a permission the user has to accept +// upon installing a plugin. +type PluginPrivilege struct { + Name string + Description string + Value []string +} + +// PluginPrivileges is a list of PluginPrivilege +type PluginPrivileges []PluginPrivilege + +func (s PluginPrivileges) Len() int { + return len(s) +} + +func (s PluginPrivileges) Less(i, j int) bool { + return s[i].Name < s[j].Name +} + +func (s PluginPrivileges) Swap(i, j int) { + sort.Strings(s[i].Value) + sort.Strings(s[j].Value) + s[i], s[j] = s[j], s[i] +} diff --git a/vendor/github.com/docker/docker/api/types/port.go b/vendor/github.com/docker/docker/api/types/port.go new file mode 100644 index 000000000..d91234744 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/port.go @@ -0,0 +1,23 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// Port An open port on a container +// swagger:model Port +type Port struct { + + // Host IP address that the container's port is mapped to + IP string `json:"IP,omitempty"` + + // Port on the container + // Required: true + PrivatePort uint16 `json:"PrivatePort"` + + // Port exposed on the host + PublicPort uint16 `json:"PublicPort,omitempty"` + + // type + // Required: true + Type string `json:"Type"` +} diff --git a/vendor/github.com/docker/docker/api/types/registry/authenticate.go b/vendor/github.com/docker/docker/api/types/registry/authenticate.go new file mode 100644 index 000000000..f0a2113e4 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/registry/authenticate.go @@ -0,0 +1,21 @@ +package registry // import "github.com/docker/docker/api/types/registry" + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// AuthenticateOKBody authenticate o k body +// swagger:model AuthenticateOKBody +type AuthenticateOKBody struct { + + // An opaque token used to authenticate a user after a successful login + // Required: true + IdentityToken string `json:"IdentityToken"` + + // The status of the authentication + // Required: true + Status string `json:"Status"` +} diff --git a/vendor/github.com/docker/docker/api/types/registry/registry.go b/vendor/github.com/docker/docker/api/types/registry/registry.go new file mode 100644 index 000000000..8789ad3b3 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/registry/registry.go @@ -0,0 +1,119 @@ +package registry // import "github.com/docker/docker/api/types/registry" + +import ( + "encoding/json" + "net" + + "github.com/opencontainers/image-spec/specs-go/v1" +) + +// ServiceConfig stores daemon registry services configuration. +type ServiceConfig struct { + AllowNondistributableArtifactsCIDRs []*NetIPNet + AllowNondistributableArtifactsHostnames []string + InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"` + IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"` + Mirrors []string +} + +// NetIPNet is the net.IPNet type, which can be marshalled and +// unmarshalled to JSON +type NetIPNet net.IPNet + +// String returns the CIDR notation of ipnet +func (ipnet *NetIPNet) String() string { + return (*net.IPNet)(ipnet).String() +} + +// MarshalJSON returns the JSON representation of the IPNet +func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) { + return json.Marshal((*net.IPNet)(ipnet).String()) +} + +// UnmarshalJSON sets the IPNet from a byte array of JSON +func (ipnet *NetIPNet) UnmarshalJSON(b []byte) (err error) { + var ipnetStr string + if err = json.Unmarshal(b, &ipnetStr); err == nil { + var cidr *net.IPNet + if _, cidr, err = net.ParseCIDR(ipnetStr); err == nil { + *ipnet = NetIPNet(*cidr) + } + } + return +} + +// IndexInfo contains information about a registry +// +// RepositoryInfo Examples: +// { +// "Index" : { +// "Name" : "docker.io", +// "Mirrors" : ["https://registry-2.docker.io/v1/", "https://registry-3.docker.io/v1/"], +// "Secure" : true, +// "Official" : true, +// }, +// "RemoteName" : "library/debian", +// "LocalName" : "debian", +// "CanonicalName" : "docker.io/debian" +// "Official" : true, +// } +// +// { +// "Index" : { +// "Name" : "127.0.0.1:5000", +// "Mirrors" : [], +// "Secure" : false, +// "Official" : false, +// }, +// "RemoteName" : "user/repo", +// "LocalName" : "127.0.0.1:5000/user/repo", +// "CanonicalName" : "127.0.0.1:5000/user/repo", +// "Official" : false, +// } +type IndexInfo struct { + // Name is the name of the registry, such as "docker.io" + Name string + // Mirrors is a list of mirrors, expressed as URIs + Mirrors []string + // Secure is set to false if the registry is part of the list of + // insecure registries. Insecure registries accept HTTP and/or accept + // HTTPS with certificates from unknown CAs. + Secure bool + // Official indicates whether this is an official registry + Official bool +} + +// SearchResult describes a search result returned from a registry +type SearchResult struct { + // StarCount indicates the number of stars this repository has + StarCount int `json:"star_count"` + // IsOfficial is true if the result is from an official repository. + IsOfficial bool `json:"is_official"` + // Name is the name of the repository + Name string `json:"name"` + // IsAutomated indicates whether the result is automated + IsAutomated bool `json:"is_automated"` + // Description is a textual description of the repository + Description string `json:"description"` +} + +// SearchResults lists a collection search results returned from a registry +type SearchResults struct { + // Query contains the query string that generated the search results + Query string `json:"query"` + // NumResults indicates the number of results the query returned + NumResults int `json:"num_results"` + // Results is a slice containing the actual results for the search + Results []SearchResult `json:"results"` +} + +// DistributionInspect describes the result obtained from contacting the +// registry to retrieve image metadata +type DistributionInspect struct { + // Descriptor contains information about the manifest, including + // the content addressable digest + Descriptor v1.Descriptor + // Platforms contains the list of platforms supported by the image, + // obtained by parsing the manifest + Platforms []v1.Platform +} diff --git a/vendor/github.com/docker/docker/api/types/seccomp.go b/vendor/github.com/docker/docker/api/types/seccomp.go new file mode 100644 index 000000000..67a41e1a8 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/seccomp.go @@ -0,0 +1,93 @@ +package types // import "github.com/docker/docker/api/types" + +// Seccomp represents the config for a seccomp profile for syscall restriction. +type Seccomp struct { + DefaultAction Action `json:"defaultAction"` + // Architectures is kept to maintain backward compatibility with the old + // seccomp profile. + Architectures []Arch `json:"architectures,omitempty"` + ArchMap []Architecture `json:"archMap,omitempty"` + Syscalls []*Syscall `json:"syscalls"` +} + +// Architecture is used to represent a specific architecture +// and its sub-architectures +type Architecture struct { + Arch Arch `json:"architecture"` + SubArches []Arch `json:"subArchitectures"` +} + +// Arch used for architectures +type Arch string + +// Additional architectures permitted to be used for system calls +// By default only the native architecture of the kernel is permitted +const ( + ArchX86 Arch = "SCMP_ARCH_X86" + ArchX86_64 Arch = "SCMP_ARCH_X86_64" + ArchX32 Arch = "SCMP_ARCH_X32" + ArchARM Arch = "SCMP_ARCH_ARM" + ArchAARCH64 Arch = "SCMP_ARCH_AARCH64" + ArchMIPS Arch = "SCMP_ARCH_MIPS" + ArchMIPS64 Arch = "SCMP_ARCH_MIPS64" + ArchMIPS64N32 Arch = "SCMP_ARCH_MIPS64N32" + ArchMIPSEL Arch = "SCMP_ARCH_MIPSEL" + ArchMIPSEL64 Arch = "SCMP_ARCH_MIPSEL64" + ArchMIPSEL64N32 Arch = "SCMP_ARCH_MIPSEL64N32" + ArchPPC Arch = "SCMP_ARCH_PPC" + ArchPPC64 Arch = "SCMP_ARCH_PPC64" + ArchPPC64LE Arch = "SCMP_ARCH_PPC64LE" + ArchS390 Arch = "SCMP_ARCH_S390" + ArchS390X Arch = "SCMP_ARCH_S390X" +) + +// Action taken upon Seccomp rule match +type Action string + +// Define actions for Seccomp rules +const ( + ActKill Action = "SCMP_ACT_KILL" + ActTrap Action = "SCMP_ACT_TRAP" + ActErrno Action = "SCMP_ACT_ERRNO" + ActTrace Action = "SCMP_ACT_TRACE" + ActAllow Action = "SCMP_ACT_ALLOW" +) + +// Operator used to match syscall arguments in Seccomp +type Operator string + +// Define operators for syscall arguments in Seccomp +const ( + OpNotEqual Operator = "SCMP_CMP_NE" + OpLessThan Operator = "SCMP_CMP_LT" + OpLessEqual Operator = "SCMP_CMP_LE" + OpEqualTo Operator = "SCMP_CMP_EQ" + OpGreaterEqual Operator = "SCMP_CMP_GE" + OpGreaterThan Operator = "SCMP_CMP_GT" + OpMaskedEqual Operator = "SCMP_CMP_MASKED_EQ" +) + +// Arg used for matching specific syscall arguments in Seccomp +type Arg struct { + Index uint `json:"index"` + Value uint64 `json:"value"` + ValueTwo uint64 `json:"valueTwo"` + Op Operator `json:"op"` +} + +// Filter is used to conditionally apply Seccomp rules +type Filter struct { + Caps []string `json:"caps,omitempty"` + Arches []string `json:"arches,omitempty"` +} + +// Syscall is used to match a group of syscalls in Seccomp +type Syscall struct { + Name string `json:"name,omitempty"` + Names []string `json:"names,omitempty"` + Action Action `json:"action"` + Args []*Arg `json:"args"` + Comment string `json:"comment"` + Includes Filter `json:"includes"` + Excludes Filter `json:"excludes"` +} diff --git a/vendor/github.com/docker/docker/api/types/service_update_response.go b/vendor/github.com/docker/docker/api/types/service_update_response.go new file mode 100644 index 000000000..74ea64b1b --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/service_update_response.go @@ -0,0 +1,12 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// ServiceUpdateResponse service update response +// swagger:model ServiceUpdateResponse +type ServiceUpdateResponse struct { + + // Optional warning messages + Warnings []string `json:"Warnings"` +} diff --git a/vendor/github.com/docker/docker/api/types/stats.go b/vendor/github.com/docker/docker/api/types/stats.go new file mode 100644 index 000000000..60175c061 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/stats.go @@ -0,0 +1,181 @@ +// Package types is used for API stability in the types and response to the +// consumers of the API stats endpoint. +package types // import "github.com/docker/docker/api/types" + +import "time" + +// ThrottlingData stores CPU throttling stats of one running container. +// Not used on Windows. +type ThrottlingData struct { + // Number of periods with throttling active + Periods uint64 `json:"periods"` + // Number of periods when the container hits its throttling limit. + ThrottledPeriods uint64 `json:"throttled_periods"` + // Aggregate time the container was throttled for in nanoseconds. + ThrottledTime uint64 `json:"throttled_time"` +} + +// CPUUsage stores All CPU stats aggregated since container inception. +type CPUUsage struct { + // Total CPU time consumed. + // Units: nanoseconds (Linux) + // Units: 100's of nanoseconds (Windows) + TotalUsage uint64 `json:"total_usage"` + + // Total CPU time consumed per core (Linux). Not used on Windows. + // Units: nanoseconds. + PercpuUsage []uint64 `json:"percpu_usage,omitempty"` + + // Time spent by tasks of the cgroup in kernel mode (Linux). + // Time spent by all container processes in kernel mode (Windows). + // Units: nanoseconds (Linux). + // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers. + UsageInKernelmode uint64 `json:"usage_in_kernelmode"` + + // Time spent by tasks of the cgroup in user mode (Linux). + // Time spent by all container processes in user mode (Windows). + // Units: nanoseconds (Linux). + // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers + UsageInUsermode uint64 `json:"usage_in_usermode"` +} + +// CPUStats aggregates and wraps all CPU related info of container +type CPUStats struct { + // CPU Usage. Linux and Windows. + CPUUsage CPUUsage `json:"cpu_usage"` + + // System Usage. Linux only. + SystemUsage uint64 `json:"system_cpu_usage,omitempty"` + + // Online CPUs. Linux only. + OnlineCPUs uint32 `json:"online_cpus,omitempty"` + + // Throttling Data. Linux only. + ThrottlingData ThrottlingData `json:"throttling_data,omitempty"` +} + +// MemoryStats aggregates all memory stats since container inception on Linux. +// Windows returns stats for commit and private working set only. +type MemoryStats struct { + // Linux Memory Stats + + // current res_counter usage for memory + Usage uint64 `json:"usage,omitempty"` + // maximum usage ever recorded. + MaxUsage uint64 `json:"max_usage,omitempty"` + // TODO(vishh): Export these as stronger types. + // all the stats exported via memory.stat. + Stats map[string]uint64 `json:"stats,omitempty"` + // number of times memory usage hits limits. + Failcnt uint64 `json:"failcnt,omitempty"` + Limit uint64 `json:"limit,omitempty"` + + // Windows Memory Stats + // See https://technet.microsoft.com/en-us/magazine/ff382715.aspx + + // committed bytes + Commit uint64 `json:"commitbytes,omitempty"` + // peak committed bytes + CommitPeak uint64 `json:"commitpeakbytes,omitempty"` + // private working set + PrivateWorkingSet uint64 `json:"privateworkingset,omitempty"` +} + +// BlkioStatEntry is one small entity to store a piece of Blkio stats +// Not used on Windows. +type BlkioStatEntry struct { + Major uint64 `json:"major"` + Minor uint64 `json:"minor"` + Op string `json:"op"` + Value uint64 `json:"value"` +} + +// BlkioStats stores All IO service stats for data read and write. +// This is a Linux specific structure as the differences between expressing +// block I/O on Windows and Linux are sufficiently significant to make +// little sense attempting to morph into a combined structure. +type BlkioStats struct { + // number of bytes transferred to and from the block device + IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"` + IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive"` + IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive"` + IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive"` + IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive"` + IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive"` + IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive"` + SectorsRecursive []BlkioStatEntry `json:"sectors_recursive"` +} + +// StorageStats is the disk I/O stats for read/write on Windows. +type StorageStats struct { + ReadCountNormalized uint64 `json:"read_count_normalized,omitempty"` + ReadSizeBytes uint64 `json:"read_size_bytes,omitempty"` + WriteCountNormalized uint64 `json:"write_count_normalized,omitempty"` + WriteSizeBytes uint64 `json:"write_size_bytes,omitempty"` +} + +// NetworkStats aggregates the network stats of one container +type NetworkStats struct { + // Bytes received. Windows and Linux. + RxBytes uint64 `json:"rx_bytes"` + // Packets received. Windows and Linux. + RxPackets uint64 `json:"rx_packets"` + // Received errors. Not used on Windows. Note that we dont `omitempty` this + // field as it is expected in the >=v1.21 API stats structure. + RxErrors uint64 `json:"rx_errors"` + // Incoming packets dropped. Windows and Linux. + RxDropped uint64 `json:"rx_dropped"` + // Bytes sent. Windows and Linux. + TxBytes uint64 `json:"tx_bytes"` + // Packets sent. Windows and Linux. + TxPackets uint64 `json:"tx_packets"` + // Sent errors. Not used on Windows. Note that we dont `omitempty` this + // field as it is expected in the >=v1.21 API stats structure. + TxErrors uint64 `json:"tx_errors"` + // Outgoing packets dropped. Windows and Linux. + TxDropped uint64 `json:"tx_dropped"` + // Endpoint ID. Not used on Linux. + EndpointID string `json:"endpoint_id,omitempty"` + // Instance ID. Not used on Linux. + InstanceID string `json:"instance_id,omitempty"` +} + +// PidsStats contains the stats of a container's pids +type PidsStats struct { + // Current is the number of pids in the cgroup + Current uint64 `json:"current,omitempty"` + // Limit is the hard limit on the number of pids in the cgroup. + // A "Limit" of 0 means that there is no limit. + Limit uint64 `json:"limit,omitempty"` +} + +// Stats is Ultimate struct aggregating all types of stats of one container +type Stats struct { + // Common stats + Read time.Time `json:"read"` + PreRead time.Time `json:"preread"` + + // Linux specific stats, not populated on Windows. + PidsStats PidsStats `json:"pids_stats,omitempty"` + BlkioStats BlkioStats `json:"blkio_stats,omitempty"` + + // Windows specific stats, not populated on Linux. + NumProcs uint32 `json:"num_procs"` + StorageStats StorageStats `json:"storage_stats,omitempty"` + + // Shared stats + CPUStats CPUStats `json:"cpu_stats,omitempty"` + PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous" + MemoryStats MemoryStats `json:"memory_stats,omitempty"` +} + +// StatsJSON is newly used Networks +type StatsJSON struct { + Stats + + Name string `json:"name,omitempty"` + ID string `json:"id,omitempty"` + + // Networks request version >=1.21 + Networks map[string]NetworkStats `json:"networks,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/strslice/strslice.go b/vendor/github.com/docker/docker/api/types/strslice/strslice.go new file mode 100644 index 000000000..82921cebc --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/strslice/strslice.go @@ -0,0 +1,30 @@ +package strslice // import "github.com/docker/docker/api/types/strslice" + +import "encoding/json" + +// StrSlice represents a string or an array of strings. +// We need to override the json decoder to accept both options. +type StrSlice []string + +// UnmarshalJSON decodes the byte slice whether it's a string or an array of +// strings. This method is needed to implement json.Unmarshaler. +func (e *StrSlice) UnmarshalJSON(b []byte) error { + if len(b) == 0 { + // With no input, we preserve the existing value by returning nil and + // leaving the target alone. This allows defining default values for + // the type. + return nil + } + + p := make([]string, 0, 1) + if err := json.Unmarshal(b, &p); err != nil { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + p = append(p, s) + } + + *e = p + return nil +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/common.go b/vendor/github.com/docker/docker/api/types/swarm/common.go new file mode 100644 index 000000000..ef020f458 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/common.go @@ -0,0 +1,40 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import "time" + +// Version represents the internal object version. +type Version struct { + Index uint64 `json:",omitempty"` +} + +// Meta is a base object inherited by most of the other once. +type Meta struct { + Version Version `json:",omitempty"` + CreatedAt time.Time `json:",omitempty"` + UpdatedAt time.Time `json:",omitempty"` +} + +// Annotations represents how to describe an object. +type Annotations struct { + Name string `json:",omitempty"` + Labels map[string]string `json:"Labels"` +} + +// Driver represents a driver (network, logging, secrets backend). +type Driver struct { + Name string `json:",omitempty"` + Options map[string]string `json:",omitempty"` +} + +// TLSInfo represents the TLS information about what CA certificate is trusted, +// and who the issuer for a TLS certificate is +type TLSInfo struct { + // TrustRoot is the trusted CA root certificate in PEM format + TrustRoot string `json:",omitempty"` + + // CertIssuer is the raw subject bytes of the issuer + CertIssuerSubject []byte `json:",omitempty"` + + // CertIssuerPublicKey is the raw public key bytes of the issuer + CertIssuerPublicKey []byte `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/config.go b/vendor/github.com/docker/docker/api/types/swarm/config.go new file mode 100644 index 000000000..a1555cf43 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/config.go @@ -0,0 +1,35 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import "os" + +// Config represents a config. +type Config struct { + ID string + Meta + Spec ConfigSpec +} + +// ConfigSpec represents a config specification from a config in swarm +type ConfigSpec struct { + Annotations + Data []byte `json:",omitempty"` + + // Templating controls whether and how to evaluate the config payload as + // a template. If it is not set, no templating is used. + Templating *Driver `json:",omitempty"` +} + +// ConfigReferenceFileTarget is a file target in a config reference +type ConfigReferenceFileTarget struct { + Name string + UID string + GID string + Mode os.FileMode +} + +// ConfigReference is a reference to a config in swarm +type ConfigReference struct { + File *ConfigReferenceFileTarget + ConfigID string + ConfigName string +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/container.go b/vendor/github.com/docker/docker/api/types/swarm/container.go new file mode 100644 index 000000000..151211ff5 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/container.go @@ -0,0 +1,74 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import ( + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/mount" +) + +// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) +// Detailed documentation is available in: +// http://man7.org/linux/man-pages/man5/resolv.conf.5.html +// `nameserver`, `search`, `options` have been supported. +// TODO: `domain` is not supported yet. +type DNSConfig struct { + // Nameservers specifies the IP addresses of the name servers + Nameservers []string `json:",omitempty"` + // Search specifies the search list for host-name lookup + Search []string `json:",omitempty"` + // Options allows certain internal resolver variables to be modified + Options []string `json:",omitempty"` +} + +// SELinuxContext contains the SELinux labels of the container. +type SELinuxContext struct { + Disable bool + + User string + Role string + Type string + Level string +} + +// CredentialSpec for managed service account (Windows only) +type CredentialSpec struct { + File string + Registry string +} + +// Privileges defines the security options for the container. +type Privileges struct { + CredentialSpec *CredentialSpec + SELinuxContext *SELinuxContext +} + +// ContainerSpec represents the spec of a container. +type ContainerSpec struct { + Image string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + Command []string `json:",omitempty"` + Args []string `json:",omitempty"` + Hostname string `json:",omitempty"` + Env []string `json:",omitempty"` + Dir string `json:",omitempty"` + User string `json:",omitempty"` + Groups []string `json:",omitempty"` + Privileges *Privileges `json:",omitempty"` + Init *bool `json:",omitempty"` + StopSignal string `json:",omitempty"` + TTY bool `json:",omitempty"` + OpenStdin bool `json:",omitempty"` + ReadOnly bool `json:",omitempty"` + Mounts []mount.Mount `json:",omitempty"` + StopGracePeriod *time.Duration `json:",omitempty"` + Healthcheck *container.HealthConfig `json:",omitempty"` + // The format of extra hosts on swarmkit is specified in: + // http://man7.org/linux/man-pages/man5/hosts.5.html + // IP_address canonical_hostname [aliases...] + Hosts []string `json:",omitempty"` + DNSConfig *DNSConfig `json:",omitempty"` + Secrets []*SecretReference `json:",omitempty"` + Configs []*ConfigReference `json:",omitempty"` + Isolation container.Isolation `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/network.go b/vendor/github.com/docker/docker/api/types/swarm/network.go new file mode 100644 index 000000000..98ef3284d --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/network.go @@ -0,0 +1,121 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import ( + "github.com/docker/docker/api/types/network" +) + +// Endpoint represents an endpoint. +type Endpoint struct { + Spec EndpointSpec `json:",omitempty"` + Ports []PortConfig `json:",omitempty"` + VirtualIPs []EndpointVirtualIP `json:",omitempty"` +} + +// EndpointSpec represents the spec of an endpoint. +type EndpointSpec struct { + Mode ResolutionMode `json:",omitempty"` + Ports []PortConfig `json:",omitempty"` +} + +// ResolutionMode represents a resolution mode. +type ResolutionMode string + +const ( + // ResolutionModeVIP VIP + ResolutionModeVIP ResolutionMode = "vip" + // ResolutionModeDNSRR DNSRR + ResolutionModeDNSRR ResolutionMode = "dnsrr" +) + +// PortConfig represents the config of a port. +type PortConfig struct { + Name string `json:",omitempty"` + Protocol PortConfigProtocol `json:",omitempty"` + // TargetPort is the port inside the container + TargetPort uint32 `json:",omitempty"` + // PublishedPort is the port on the swarm hosts + PublishedPort uint32 `json:",omitempty"` + // PublishMode is the mode in which port is published + PublishMode PortConfigPublishMode `json:",omitempty"` +} + +// PortConfigPublishMode represents the mode in which the port is to +// be published. +type PortConfigPublishMode string + +const ( + // PortConfigPublishModeIngress is used for ports published + // for ingress load balancing using routing mesh. + PortConfigPublishModeIngress PortConfigPublishMode = "ingress" + // PortConfigPublishModeHost is used for ports published + // for direct host level access on the host where the task is running. + PortConfigPublishModeHost PortConfigPublishMode = "host" +) + +// PortConfigProtocol represents the protocol of a port. +type PortConfigProtocol string + +const ( + // TODO(stevvooe): These should be used generally, not just for PortConfig. + + // PortConfigProtocolTCP TCP + PortConfigProtocolTCP PortConfigProtocol = "tcp" + // PortConfigProtocolUDP UDP + PortConfigProtocolUDP PortConfigProtocol = "udp" + // PortConfigProtocolSCTP SCTP + PortConfigProtocolSCTP PortConfigProtocol = "sctp" +) + +// EndpointVirtualIP represents the virtual ip of a port. +type EndpointVirtualIP struct { + NetworkID string `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// Network represents a network. +type Network struct { + ID string + Meta + Spec NetworkSpec `json:",omitempty"` + DriverState Driver `json:",omitempty"` + IPAMOptions *IPAMOptions `json:",omitempty"` +} + +// NetworkSpec represents the spec of a network. +type NetworkSpec struct { + Annotations + DriverConfiguration *Driver `json:",omitempty"` + IPv6Enabled bool `json:",omitempty"` + Internal bool `json:",omitempty"` + Attachable bool `json:",omitempty"` + Ingress bool `json:",omitempty"` + IPAMOptions *IPAMOptions `json:",omitempty"` + ConfigFrom *network.ConfigReference `json:",omitempty"` + Scope string `json:",omitempty"` +} + +// NetworkAttachmentConfig represents the configuration of a network attachment. +type NetworkAttachmentConfig struct { + Target string `json:",omitempty"` + Aliases []string `json:",omitempty"` + DriverOpts map[string]string `json:",omitempty"` +} + +// NetworkAttachment represents a network attachment. +type NetworkAttachment struct { + Network Network `json:",omitempty"` + Addresses []string `json:",omitempty"` +} + +// IPAMOptions represents ipam options. +type IPAMOptions struct { + Driver Driver `json:",omitempty"` + Configs []IPAMConfig `json:",omitempty"` +} + +// IPAMConfig represents ipam configuration. +type IPAMConfig struct { + Subnet string `json:",omitempty"` + Range string `json:",omitempty"` + Gateway string `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/node.go b/vendor/github.com/docker/docker/api/types/swarm/node.go new file mode 100644 index 000000000..1e30f5fa1 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/node.go @@ -0,0 +1,115 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +// Node represents a node. +type Node struct { + ID string + Meta + // Spec defines the desired state of the node as specified by the user. + // The system will honor this and will *never* modify it. + Spec NodeSpec `json:",omitempty"` + // Description encapsulates the properties of the Node as reported by the + // agent. + Description NodeDescription `json:",omitempty"` + // Status provides the current status of the node, as seen by the manager. + Status NodeStatus `json:",omitempty"` + // ManagerStatus provides the current status of the node's manager + // component, if the node is a manager. + ManagerStatus *ManagerStatus `json:",omitempty"` +} + +// NodeSpec represents the spec of a node. +type NodeSpec struct { + Annotations + Role NodeRole `json:",omitempty"` + Availability NodeAvailability `json:",omitempty"` +} + +// NodeRole represents the role of a node. +type NodeRole string + +const ( + // NodeRoleWorker WORKER + NodeRoleWorker NodeRole = "worker" + // NodeRoleManager MANAGER + NodeRoleManager NodeRole = "manager" +) + +// NodeAvailability represents the availability of a node. +type NodeAvailability string + +const ( + // NodeAvailabilityActive ACTIVE + NodeAvailabilityActive NodeAvailability = "active" + // NodeAvailabilityPause PAUSE + NodeAvailabilityPause NodeAvailability = "pause" + // NodeAvailabilityDrain DRAIN + NodeAvailabilityDrain NodeAvailability = "drain" +) + +// NodeDescription represents the description of a node. +type NodeDescription struct { + Hostname string `json:",omitempty"` + Platform Platform `json:",omitempty"` + Resources Resources `json:",omitempty"` + Engine EngineDescription `json:",omitempty"` + TLSInfo TLSInfo `json:",omitempty"` +} + +// Platform represents the platform (Arch/OS). +type Platform struct { + Architecture string `json:",omitempty"` + OS string `json:",omitempty"` +} + +// EngineDescription represents the description of an engine. +type EngineDescription struct { + EngineVersion string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + Plugins []PluginDescription `json:",omitempty"` +} + +// PluginDescription represents the description of an engine plugin. +type PluginDescription struct { + Type string `json:",omitempty"` + Name string `json:",omitempty"` +} + +// NodeStatus represents the status of a node. +type NodeStatus struct { + State NodeState `json:",omitempty"` + Message string `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// Reachability represents the reachability of a node. +type Reachability string + +const ( + // ReachabilityUnknown UNKNOWN + ReachabilityUnknown Reachability = "unknown" + // ReachabilityUnreachable UNREACHABLE + ReachabilityUnreachable Reachability = "unreachable" + // ReachabilityReachable REACHABLE + ReachabilityReachable Reachability = "reachable" +) + +// ManagerStatus represents the status of a manager. +type ManagerStatus struct { + Leader bool `json:",omitempty"` + Reachability Reachability `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// NodeState represents the state of a node. +type NodeState string + +const ( + // NodeStateUnknown UNKNOWN + NodeStateUnknown NodeState = "unknown" + // NodeStateDown DOWN + NodeStateDown NodeState = "down" + // NodeStateReady READY + NodeStateReady NodeState = "ready" + // NodeStateDisconnected DISCONNECTED + NodeStateDisconnected NodeState = "disconnected" +) diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime.go b/vendor/github.com/docker/docker/api/types/swarm/runtime.go new file mode 100644 index 000000000..0c77403cc --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/runtime.go @@ -0,0 +1,27 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +// RuntimeType is the type of runtime used for the TaskSpec +type RuntimeType string + +// RuntimeURL is the proto type url +type RuntimeURL string + +const ( + // RuntimeContainer is the container based runtime + RuntimeContainer RuntimeType = "container" + // RuntimePlugin is the plugin based runtime + RuntimePlugin RuntimeType = "plugin" + // RuntimeNetworkAttachment is the network attachment runtime + RuntimeNetworkAttachment RuntimeType = "attachment" + + // RuntimeURLContainer is the proto url for the container type + RuntimeURLContainer RuntimeURL = "types.docker.com/RuntimeContainer" + // RuntimeURLPlugin is the proto url for the plugin type + RuntimeURLPlugin RuntimeURL = "types.docker.com/RuntimePlugin" +) + +// NetworkAttachmentSpec represents the runtime spec type for network +// attachment tasks +type NetworkAttachmentSpec struct { + ContainerID string +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go b/vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go new file mode 100644 index 000000000..98c2806c3 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go @@ -0,0 +1,3 @@ +//go:generate protoc -I . --gogofast_out=import_path=github.com/docker/docker/api/types/swarm/runtime:. plugin.proto + +package runtime // import "github.com/docker/docker/api/types/swarm/runtime" diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go b/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go new file mode 100644 index 000000000..1fdc9b043 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go @@ -0,0 +1,712 @@ +// Code generated by protoc-gen-gogo. +// source: plugin.proto +// DO NOT EDIT! + +/* + Package runtime is a generated protocol buffer package. + + It is generated from these files: + plugin.proto + + It has these top-level messages: + PluginSpec + PluginPrivilege +*/ +package runtime + +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" + +import io "io" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package + +// PluginSpec defines the base payload which clients can specify for creating +// a service with the plugin runtime. +type PluginSpec struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Remote string `protobuf:"bytes,2,opt,name=remote,proto3" json:"remote,omitempty"` + Privileges []*PluginPrivilege `protobuf:"bytes,3,rep,name=privileges" json:"privileges,omitempty"` + Disabled bool `protobuf:"varint,4,opt,name=disabled,proto3" json:"disabled,omitempty"` +} + +func (m *PluginSpec) Reset() { *m = PluginSpec{} } +func (m *PluginSpec) String() string { return proto.CompactTextString(m) } +func (*PluginSpec) ProtoMessage() {} +func (*PluginSpec) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{0} } + +func (m *PluginSpec) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *PluginSpec) GetRemote() string { + if m != nil { + return m.Remote + } + return "" +} + +func (m *PluginSpec) GetPrivileges() []*PluginPrivilege { + if m != nil { + return m.Privileges + } + return nil +} + +func (m *PluginSpec) GetDisabled() bool { + if m != nil { + return m.Disabled + } + return false +} + +// PluginPrivilege describes a permission the user has to accept +// upon installing a plugin. +type PluginPrivilege struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Value []string `protobuf:"bytes,3,rep,name=value" json:"value,omitempty"` +} + +func (m *PluginPrivilege) Reset() { *m = PluginPrivilege{} } +func (m *PluginPrivilege) String() string { return proto.CompactTextString(m) } +func (*PluginPrivilege) ProtoMessage() {} +func (*PluginPrivilege) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{1} } + +func (m *PluginPrivilege) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *PluginPrivilege) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *PluginPrivilege) GetValue() []string { + if m != nil { + return m.Value + } + return nil +} + +func init() { + proto.RegisterType((*PluginSpec)(nil), "PluginSpec") + proto.RegisterType((*PluginPrivilege)(nil), "PluginPrivilege") +} +func (m *PluginSpec) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PluginSpec) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Name) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + } + if len(m.Remote) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintPlugin(dAtA, i, uint64(len(m.Remote))) + i += copy(dAtA[i:], m.Remote) + } + if len(m.Privileges) > 0 { + for _, msg := range m.Privileges { + dAtA[i] = 0x1a + i++ + i = encodeVarintPlugin(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + if m.Disabled { + dAtA[i] = 0x20 + i++ + if m.Disabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + return i, nil +} + +func (m *PluginPrivilege) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PluginPrivilege) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Name) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintPlugin(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + } + if len(m.Description) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintPlugin(dAtA, i, uint64(len(m.Description))) + i += copy(dAtA[i:], m.Description) + } + if len(m.Value) > 0 { + for _, s := range m.Value { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + return i, nil +} + +func encodeFixed64Plugin(dAtA []byte, offset int, v uint64) int { + dAtA[offset] = uint8(v) + dAtA[offset+1] = uint8(v >> 8) + dAtA[offset+2] = uint8(v >> 16) + dAtA[offset+3] = uint8(v >> 24) + dAtA[offset+4] = uint8(v >> 32) + dAtA[offset+5] = uint8(v >> 40) + dAtA[offset+6] = uint8(v >> 48) + dAtA[offset+7] = uint8(v >> 56) + return offset + 8 +} +func encodeFixed32Plugin(dAtA []byte, offset int, v uint32) int { + dAtA[offset] = uint8(v) + dAtA[offset+1] = uint8(v >> 8) + dAtA[offset+2] = uint8(v >> 16) + dAtA[offset+3] = uint8(v >> 24) + return offset + 4 +} +func encodeVarintPlugin(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} +func (m *PluginSpec) Size() (n int) { + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovPlugin(uint64(l)) + } + l = len(m.Remote) + if l > 0 { + n += 1 + l + sovPlugin(uint64(l)) + } + if len(m.Privileges) > 0 { + for _, e := range m.Privileges { + l = e.Size() + n += 1 + l + sovPlugin(uint64(l)) + } + } + if m.Disabled { + n += 2 + } + return n +} + +func (m *PluginPrivilege) Size() (n int) { + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovPlugin(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovPlugin(uint64(l)) + } + if len(m.Value) > 0 { + for _, s := range m.Value { + l = len(s) + n += 1 + l + sovPlugin(uint64(l)) + } + } + return n +} + +func sovPlugin(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozPlugin(x uint64) (n int) { + return sovPlugin(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PluginSpec) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PluginSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PluginSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Remote", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Remote = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Privileges", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Privileges = append(m.Privileges, &PluginPrivilege{}) + if err := m.Privileges[len(m.Privileges)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Disabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Disabled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipPlugin(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPlugin + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PluginPrivilege) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PluginPrivilege: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PluginPrivilege: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPlugin(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPlugin + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipPlugin(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlugin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlugin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlugin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + iNdEx += length + if length < 0 { + return 0, ErrInvalidLengthPlugin + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlugin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipPlugin(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthPlugin = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPlugin = fmt.Errorf("proto: integer overflow") +) + +func init() { proto.RegisterFile("plugin.proto", fileDescriptorPlugin) } + +var fileDescriptorPlugin = []byte{ + // 196 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0xc8, 0x29, 0x4d, + 0xcf, 0xcc, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x6a, 0x63, 0xe4, 0xe2, 0x0a, 0x00, 0x0b, + 0x04, 0x17, 0xa4, 0x26, 0x0b, 0x09, 0x71, 0xb1, 0xe4, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x2a, 0x30, + 0x6a, 0x70, 0x06, 0x81, 0xd9, 0x42, 0x62, 0x5c, 0x6c, 0x45, 0xa9, 0xb9, 0xf9, 0x25, 0xa9, 0x12, + 0x4c, 0x60, 0x51, 0x28, 0x4f, 0xc8, 0x80, 0x8b, 0xab, 0xa0, 0x28, 0xb3, 0x2c, 0x33, 0x27, 0x35, + 0x3d, 0xb5, 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x40, 0x0f, 0x62, 0x58, 0x00, 0x4c, + 0x22, 0x08, 0x49, 0x8d, 0x90, 0x14, 0x17, 0x47, 0x4a, 0x66, 0x71, 0x62, 0x52, 0x4e, 0x6a, 0x8a, + 0x04, 0x8b, 0x02, 0xa3, 0x06, 0x47, 0x10, 0x9c, 0xaf, 0x14, 0xcb, 0xc5, 0x8f, 0xa6, 0x15, 0xab, + 0x63, 0x14, 0xb8, 0xb8, 0x53, 0x52, 0x8b, 0x93, 0x8b, 0x32, 0x0b, 0x4a, 0x32, 0xf3, 0xf3, 0xa0, + 0x2e, 0x42, 0x16, 0x12, 0x12, 0xe1, 0x62, 0x2d, 0x4b, 0xcc, 0x29, 0x4d, 0x05, 0xbb, 0x88, 0x33, + 0x08, 0xc2, 0x71, 0xe2, 0x39, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, + 0x18, 0x93, 0xd8, 0xc0, 0x9e, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xb8, 0x84, 0xad, 0x79, + 0x0c, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto b/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto new file mode 100644 index 000000000..6d63b7783 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +option go_package = "github.com/docker/docker/api/types/swarm/runtime;runtime"; + +// PluginSpec defines the base payload which clients can specify for creating +// a service with the plugin runtime. +message PluginSpec { + string name = 1; + string remote = 2; + repeated PluginPrivilege privileges = 3; + bool disabled = 4; +} + +// PluginPrivilege describes a permission the user has to accept +// upon installing a plugin. +message PluginPrivilege { + string name = 1; + string description = 2; + repeated string value = 3; +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/secret.go b/vendor/github.com/docker/docker/api/types/swarm/secret.go new file mode 100644 index 000000000..d5213ec98 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/secret.go @@ -0,0 +1,36 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import "os" + +// Secret represents a secret. +type Secret struct { + ID string + Meta + Spec SecretSpec +} + +// SecretSpec represents a secret specification from a secret in swarm +type SecretSpec struct { + Annotations + Data []byte `json:",omitempty"` + Driver *Driver `json:",omitempty"` // name of the secrets driver used to fetch the secret's value from an external secret store + + // Templating controls whether and how to evaluate the secret payload as + // a template. If it is not set, no templating is used. + Templating *Driver `json:",omitempty"` +} + +// SecretReferenceFileTarget is a file target in a secret reference +type SecretReferenceFileTarget struct { + Name string + UID string + GID string + Mode os.FileMode +} + +// SecretReference is a reference to a secret in swarm +type SecretReference struct { + File *SecretReferenceFileTarget + SecretID string + SecretName string +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/service.go b/vendor/github.com/docker/docker/api/types/swarm/service.go new file mode 100644 index 000000000..abf192e75 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/service.go @@ -0,0 +1,124 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import "time" + +// Service represents a service. +type Service struct { + ID string + Meta + Spec ServiceSpec `json:",omitempty"` + PreviousSpec *ServiceSpec `json:",omitempty"` + Endpoint Endpoint `json:",omitempty"` + UpdateStatus *UpdateStatus `json:",omitempty"` +} + +// ServiceSpec represents the spec of a service. +type ServiceSpec struct { + Annotations + + // TaskTemplate defines how the service should construct new tasks when + // orchestrating this service. + TaskTemplate TaskSpec `json:",omitempty"` + Mode ServiceMode `json:",omitempty"` + UpdateConfig *UpdateConfig `json:",omitempty"` + RollbackConfig *UpdateConfig `json:",omitempty"` + + // Networks field in ServiceSpec is deprecated. The + // same field in TaskSpec should be used instead. + // This field will be removed in a future release. + Networks []NetworkAttachmentConfig `json:",omitempty"` + EndpointSpec *EndpointSpec `json:",omitempty"` +} + +// ServiceMode represents the mode of a service. +type ServiceMode struct { + Replicated *ReplicatedService `json:",omitempty"` + Global *GlobalService `json:",omitempty"` +} + +// UpdateState is the state of a service update. +type UpdateState string + +const ( + // UpdateStateUpdating is the updating state. + UpdateStateUpdating UpdateState = "updating" + // UpdateStatePaused is the paused state. + UpdateStatePaused UpdateState = "paused" + // UpdateStateCompleted is the completed state. + UpdateStateCompleted UpdateState = "completed" + // UpdateStateRollbackStarted is the state with a rollback in progress. + UpdateStateRollbackStarted UpdateState = "rollback_started" + // UpdateStateRollbackPaused is the state with a rollback in progress. + UpdateStateRollbackPaused UpdateState = "rollback_paused" + // UpdateStateRollbackCompleted is the state with a rollback in progress. + UpdateStateRollbackCompleted UpdateState = "rollback_completed" +) + +// UpdateStatus reports the status of a service update. +type UpdateStatus struct { + State UpdateState `json:",omitempty"` + StartedAt *time.Time `json:",omitempty"` + CompletedAt *time.Time `json:",omitempty"` + Message string `json:",omitempty"` +} + +// ReplicatedService is a kind of ServiceMode. +type ReplicatedService struct { + Replicas *uint64 `json:",omitempty"` +} + +// GlobalService is a kind of ServiceMode. +type GlobalService struct{} + +const ( + // UpdateFailureActionPause PAUSE + UpdateFailureActionPause = "pause" + // UpdateFailureActionContinue CONTINUE + UpdateFailureActionContinue = "continue" + // UpdateFailureActionRollback ROLLBACK + UpdateFailureActionRollback = "rollback" + + // UpdateOrderStopFirst STOP_FIRST + UpdateOrderStopFirst = "stop-first" + // UpdateOrderStartFirst START_FIRST + UpdateOrderStartFirst = "start-first" +) + +// UpdateConfig represents the update configuration. +type UpdateConfig struct { + // Maximum number of tasks to be updated in one iteration. + // 0 means unlimited parallelism. + Parallelism uint64 + + // Amount of time between updates. + Delay time.Duration `json:",omitempty"` + + // FailureAction is the action to take when an update failures. + FailureAction string `json:",omitempty"` + + // Monitor indicates how long to monitor a task for failure after it is + // created. If the task fails by ending up in one of the states + // REJECTED, COMPLETED, or FAILED, within Monitor from its creation, + // this counts as a failure. If it fails after Monitor, it does not + // count as a failure. If Monitor is unspecified, a default value will + // be used. + Monitor time.Duration `json:",omitempty"` + + // MaxFailureRatio is the fraction of tasks that may fail during + // an update before the failure action is invoked. Any task created by + // the current update which ends up in one of the states REJECTED, + // COMPLETED or FAILED within Monitor from its creation counts as a + // failure. The number of failures is divided by the number of tasks + // being updated, and if this fraction is greater than + // MaxFailureRatio, the failure action is invoked. + // + // If the failure action is CONTINUE, there is no effect. + // If the failure action is PAUSE, no more tasks will be updated until + // another update is started. + MaxFailureRatio float32 + + // Order indicates the order of operations when rolling out an updated + // task. Either the old task is shut down before the new task is + // started, or the new task is started before the old task is shut down. + Order string +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/swarm.go b/vendor/github.com/docker/docker/api/types/swarm/swarm.go new file mode 100644 index 000000000..1b111d725 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/swarm.go @@ -0,0 +1,217 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import "time" + +// ClusterInfo represents info about the cluster for outputting in "info" +// it contains the same information as "Swarm", but without the JoinTokens +type ClusterInfo struct { + ID string + Meta + Spec Spec + TLSInfo TLSInfo + RootRotationInProgress bool +} + +// Swarm represents a swarm. +type Swarm struct { + ClusterInfo + JoinTokens JoinTokens +} + +// JoinTokens contains the tokens workers and managers need to join the swarm. +type JoinTokens struct { + // Worker is the join token workers may use to join the swarm. + Worker string + // Manager is the join token managers may use to join the swarm. + Manager string +} + +// Spec represents the spec of a swarm. +type Spec struct { + Annotations + + Orchestration OrchestrationConfig `json:",omitempty"` + Raft RaftConfig `json:",omitempty"` + Dispatcher DispatcherConfig `json:",omitempty"` + CAConfig CAConfig `json:",omitempty"` + TaskDefaults TaskDefaults `json:",omitempty"` + EncryptionConfig EncryptionConfig `json:",omitempty"` +} + +// OrchestrationConfig represents orchestration configuration. +type OrchestrationConfig struct { + // TaskHistoryRetentionLimit is the number of historic tasks to keep per instance or + // node. If negative, never remove completed or failed tasks. + TaskHistoryRetentionLimit *int64 `json:",omitempty"` +} + +// TaskDefaults parameterizes cluster-level task creation with default values. +type TaskDefaults struct { + // LogDriver selects the log driver to use for tasks created in the + // orchestrator if unspecified by a service. + // + // Updating this value will only have an affect on new tasks. Old tasks + // will continue use their previously configured log driver until + // recreated. + LogDriver *Driver `json:",omitempty"` +} + +// EncryptionConfig controls at-rest encryption of data and keys. +type EncryptionConfig struct { + // AutoLockManagers specifies whether or not managers TLS keys and raft data + // should be encrypted at rest in such a way that they must be unlocked + // before the manager node starts up again. + AutoLockManagers bool +} + +// RaftConfig represents raft configuration. +type RaftConfig struct { + // SnapshotInterval is the number of log entries between snapshots. + SnapshotInterval uint64 `json:",omitempty"` + + // KeepOldSnapshots is the number of snapshots to keep beyond the + // current snapshot. + KeepOldSnapshots *uint64 `json:",omitempty"` + + // LogEntriesForSlowFollowers is the number of log entries to keep + // around to sync up slow followers after a snapshot is created. + LogEntriesForSlowFollowers uint64 `json:",omitempty"` + + // ElectionTick is the number of ticks that a follower will wait for a message + // from the leader before becoming a candidate and starting an election. + // ElectionTick must be greater than HeartbeatTick. + // + // A tick currently defaults to one second, so these translate directly to + // seconds currently, but this is NOT guaranteed. + ElectionTick int + + // HeartbeatTick is the number of ticks between heartbeats. Every + // HeartbeatTick ticks, the leader will send a heartbeat to the + // followers. + // + // A tick currently defaults to one second, so these translate directly to + // seconds currently, but this is NOT guaranteed. + HeartbeatTick int +} + +// DispatcherConfig represents dispatcher configuration. +type DispatcherConfig struct { + // HeartbeatPeriod defines how often agent should send heartbeats to + // dispatcher. + HeartbeatPeriod time.Duration `json:",omitempty"` +} + +// CAConfig represents CA configuration. +type CAConfig struct { + // NodeCertExpiry is the duration certificates should be issued for + NodeCertExpiry time.Duration `json:",omitempty"` + + // ExternalCAs is a list of CAs to which a manager node will make + // certificate signing requests for node certificates. + ExternalCAs []*ExternalCA `json:",omitempty"` + + // SigningCACert and SigningCAKey specify the desired signing root CA and + // root CA key for the swarm. When inspecting the cluster, the key will + // be redacted. + SigningCACert string `json:",omitempty"` + SigningCAKey string `json:",omitempty"` + + // If this value changes, and there is no specified signing cert and key, + // then the swarm is forced to generate a new root certificate ane key. + ForceRotate uint64 `json:",omitempty"` +} + +// ExternalCAProtocol represents type of external CA. +type ExternalCAProtocol string + +// ExternalCAProtocolCFSSL CFSSL +const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl" + +// ExternalCA defines external CA to be used by the cluster. +type ExternalCA struct { + // Protocol is the protocol used by this external CA. + Protocol ExternalCAProtocol + + // URL is the URL where the external CA can be reached. + URL string + + // Options is a set of additional key/value pairs whose interpretation + // depends on the specified CA type. + Options map[string]string `json:",omitempty"` + + // CACert specifies which root CA is used by this external CA. This certificate must + // be in PEM format. + CACert string +} + +// InitRequest is the request used to init a swarm. +type InitRequest struct { + ListenAddr string + AdvertiseAddr string + DataPathAddr string + ForceNewCluster bool + Spec Spec + AutoLockManagers bool + Availability NodeAvailability +} + +// JoinRequest is the request used to join a swarm. +type JoinRequest struct { + ListenAddr string + AdvertiseAddr string + DataPathAddr string + RemoteAddrs []string + JoinToken string // accept by secret + Availability NodeAvailability +} + +// UnlockRequest is the request used to unlock a swarm. +type UnlockRequest struct { + // UnlockKey is the unlock key in ASCII-armored format. + UnlockKey string +} + +// LocalNodeState represents the state of the local node. +type LocalNodeState string + +const ( + // LocalNodeStateInactive INACTIVE + LocalNodeStateInactive LocalNodeState = "inactive" + // LocalNodeStatePending PENDING + LocalNodeStatePending LocalNodeState = "pending" + // LocalNodeStateActive ACTIVE + LocalNodeStateActive LocalNodeState = "active" + // LocalNodeStateError ERROR + LocalNodeStateError LocalNodeState = "error" + // LocalNodeStateLocked LOCKED + LocalNodeStateLocked LocalNodeState = "locked" +) + +// Info represents generic information about swarm. +type Info struct { + NodeID string + NodeAddr string + + LocalNodeState LocalNodeState + ControlAvailable bool + Error string + + RemoteManagers []Peer + Nodes int `json:",omitempty"` + Managers int `json:",omitempty"` + + Cluster *ClusterInfo `json:",omitempty"` +} + +// Peer represents a peer. +type Peer struct { + NodeID string + Addr string +} + +// UpdateFlags contains flags for SwarmUpdate. +type UpdateFlags struct { + RotateWorkerToken bool + RotateManagerToken bool + RotateManagerUnlockKey bool +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/task.go b/vendor/github.com/docker/docker/api/types/swarm/task.go new file mode 100644 index 000000000..b35605d12 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/swarm/task.go @@ -0,0 +1,191 @@ +package swarm // import "github.com/docker/docker/api/types/swarm" + +import ( + "time" + + "github.com/docker/docker/api/types/swarm/runtime" +) + +// TaskState represents the state of a task. +type TaskState string + +const ( + // TaskStateNew NEW + TaskStateNew TaskState = "new" + // TaskStateAllocated ALLOCATED + TaskStateAllocated TaskState = "allocated" + // TaskStatePending PENDING + TaskStatePending TaskState = "pending" + // TaskStateAssigned ASSIGNED + TaskStateAssigned TaskState = "assigned" + // TaskStateAccepted ACCEPTED + TaskStateAccepted TaskState = "accepted" + // TaskStatePreparing PREPARING + TaskStatePreparing TaskState = "preparing" + // TaskStateReady READY + TaskStateReady TaskState = "ready" + // TaskStateStarting STARTING + TaskStateStarting TaskState = "starting" + // TaskStateRunning RUNNING + TaskStateRunning TaskState = "running" + // TaskStateComplete COMPLETE + TaskStateComplete TaskState = "complete" + // TaskStateShutdown SHUTDOWN + TaskStateShutdown TaskState = "shutdown" + // TaskStateFailed FAILED + TaskStateFailed TaskState = "failed" + // TaskStateRejected REJECTED + TaskStateRejected TaskState = "rejected" + // TaskStateRemove REMOVE + TaskStateRemove TaskState = "remove" + // TaskStateOrphaned ORPHANED + TaskStateOrphaned TaskState = "orphaned" +) + +// Task represents a task. +type Task struct { + ID string + Meta + Annotations + + Spec TaskSpec `json:",omitempty"` + ServiceID string `json:",omitempty"` + Slot int `json:",omitempty"` + NodeID string `json:",omitempty"` + Status TaskStatus `json:",omitempty"` + DesiredState TaskState `json:",omitempty"` + NetworksAttachments []NetworkAttachment `json:",omitempty"` + GenericResources []GenericResource `json:",omitempty"` +} + +// TaskSpec represents the spec of a task. +type TaskSpec struct { + // ContainerSpec, NetworkAttachmentSpec, and PluginSpec are mutually exclusive. + // PluginSpec is only used when the `Runtime` field is set to `plugin` + // NetworkAttachmentSpec is used if the `Runtime` field is set to + // `attachment`. + ContainerSpec *ContainerSpec `json:",omitempty"` + PluginSpec *runtime.PluginSpec `json:",omitempty"` + NetworkAttachmentSpec *NetworkAttachmentSpec `json:",omitempty"` + + Resources *ResourceRequirements `json:",omitempty"` + RestartPolicy *RestartPolicy `json:",omitempty"` + Placement *Placement `json:",omitempty"` + Networks []NetworkAttachmentConfig `json:",omitempty"` + + // LogDriver specifies the LogDriver to use for tasks created from this + // spec. If not present, the one on cluster default on swarm.Spec will be + // used, finally falling back to the engine default if not specified. + LogDriver *Driver `json:",omitempty"` + + // ForceUpdate is a counter that triggers an update even if no relevant + // parameters have been changed. + ForceUpdate uint64 + + Runtime RuntimeType `json:",omitempty"` +} + +// Resources represents resources (CPU/Memory). +type Resources struct { + NanoCPUs int64 `json:",omitempty"` + MemoryBytes int64 `json:",omitempty"` + GenericResources []GenericResource `json:",omitempty"` +} + +// GenericResource represents a "user defined" resource which can +// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1) +type GenericResource struct { + NamedResourceSpec *NamedGenericResource `json:",omitempty"` + DiscreteResourceSpec *DiscreteGenericResource `json:",omitempty"` +} + +// NamedGenericResource represents a "user defined" resource which is defined +// as a string. +// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...) +// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...) +type NamedGenericResource struct { + Kind string `json:",omitempty"` + Value string `json:",omitempty"` +} + +// DiscreteGenericResource represents a "user defined" resource which is defined +// as an integer +// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...) +// Value is used to count the resource (SSD=5, HDD=3, ...) +type DiscreteGenericResource struct { + Kind string `json:",omitempty"` + Value int64 `json:",omitempty"` +} + +// ResourceRequirements represents resources requirements. +type ResourceRequirements struct { + Limits *Resources `json:",omitempty"` + Reservations *Resources `json:",omitempty"` +} + +// Placement represents orchestration parameters. +type Placement struct { + Constraints []string `json:",omitempty"` + Preferences []PlacementPreference `json:",omitempty"` + + // Platforms stores all the platforms that the image can run on. + // This field is used in the platform filter for scheduling. If empty, + // then the platform filter is off, meaning there are no scheduling restrictions. + Platforms []Platform `json:",omitempty"` +} + +// PlacementPreference provides a way to make the scheduler aware of factors +// such as topology. +type PlacementPreference struct { + Spread *SpreadOver +} + +// SpreadOver is a scheduling preference that instructs the scheduler to spread +// tasks evenly over groups of nodes identified by labels. +type SpreadOver struct { + // label descriptor, such as engine.labels.az + SpreadDescriptor string +} + +// RestartPolicy represents the restart policy. +type RestartPolicy struct { + Condition RestartPolicyCondition `json:",omitempty"` + Delay *time.Duration `json:",omitempty"` + MaxAttempts *uint64 `json:",omitempty"` + Window *time.Duration `json:",omitempty"` +} + +// RestartPolicyCondition represents when to restart. +type RestartPolicyCondition string + +const ( + // RestartPolicyConditionNone NONE + RestartPolicyConditionNone RestartPolicyCondition = "none" + // RestartPolicyConditionOnFailure ON_FAILURE + RestartPolicyConditionOnFailure RestartPolicyCondition = "on-failure" + // RestartPolicyConditionAny ANY + RestartPolicyConditionAny RestartPolicyCondition = "any" +) + +// TaskStatus represents the status of a task. +type TaskStatus struct { + Timestamp time.Time `json:",omitempty"` + State TaskState `json:",omitempty"` + Message string `json:",omitempty"` + Err string `json:",omitempty"` + ContainerStatus *ContainerStatus `json:",omitempty"` + PortStatus PortStatus `json:",omitempty"` +} + +// ContainerStatus represents the status of a container. +type ContainerStatus struct { + ContainerID string + PID int + ExitCode int +} + +// PortStatus represents the port status of a task's host ports whose +// service has published host ports +type PortStatus struct { + Ports []PortConfig `json:",omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/types.go b/vendor/github.com/docker/docker/api/types/types.go new file mode 100644 index 000000000..06c0ca3a6 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/types.go @@ -0,0 +1,602 @@ +package types // import "github.com/docker/docker/api/types" + +import ( + "errors" + "fmt" + "io" + "os" + "strings" + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/go-connections/nat" +) + +// RootFS returns Image's RootFS description including the layer IDs. +type RootFS struct { + Type string + Layers []string `json:",omitempty"` + BaseLayer string `json:",omitempty"` +} + +// ImageInspect contains response of Engine API: +// GET "/images/{name:.*}/json" +type ImageInspect struct { + ID string `json:"Id"` + RepoTags []string + RepoDigests []string + Parent string + Comment string + Created string + Container string + ContainerConfig *container.Config + DockerVersion string + Author string + Config *container.Config + Architecture string + Os string + OsVersion string `json:",omitempty"` + Size int64 + VirtualSize int64 + GraphDriver GraphDriverData + RootFS RootFS + Metadata ImageMetadata +} + +// ImageMetadata contains engine-local data about the image +type ImageMetadata struct { + LastTagTime time.Time `json:",omitempty"` +} + +// Container contains response of Engine API: +// GET "/containers/json" +type Container struct { + ID string `json:"Id"` + Names []string + Image string + ImageID string + Command string + Created int64 + Ports []Port + SizeRw int64 `json:",omitempty"` + SizeRootFs int64 `json:",omitempty"` + Labels map[string]string + State string + Status string + HostConfig struct { + NetworkMode string `json:",omitempty"` + } + NetworkSettings *SummaryNetworkSettings + Mounts []MountPoint +} + +// CopyConfig contains request body of Engine API: +// POST "/containers/"+containerID+"/copy" +type CopyConfig struct { + Resource string +} + +// ContainerPathStat is used to encode the header from +// GET "/containers/{name:.*}/archive" +// "Name" is the file or directory name. +type ContainerPathStat struct { + Name string `json:"name"` + Size int64 `json:"size"` + Mode os.FileMode `json:"mode"` + Mtime time.Time `json:"mtime"` + LinkTarget string `json:"linkTarget"` +} + +// ContainerStats contains response of Engine API: +// GET "/stats" +type ContainerStats struct { + Body io.ReadCloser `json:"body"` + OSType string `json:"ostype"` +} + +// Ping contains response of Engine API: +// GET "/_ping" +type Ping struct { + APIVersion string + OSType string + Experimental bool +} + +// ComponentVersion describes the version information for a specific component. +type ComponentVersion struct { + Name string + Version string + Details map[string]string `json:",omitempty"` +} + +// Version contains response of Engine API: +// GET "/version" +type Version struct { + Platform struct{ Name string } `json:",omitempty"` + Components []ComponentVersion `json:",omitempty"` + + // The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility + + Version string + APIVersion string `json:"ApiVersion"` + MinAPIVersion string `json:"MinAPIVersion,omitempty"` + GitCommit string + GoVersion string + Os string + Arch string + KernelVersion string `json:",omitempty"` + Experimental bool `json:",omitempty"` + BuildTime string `json:",omitempty"` +} + +// Commit holds the Git-commit (SHA1) that a binary was built from, as reported +// in the version-string of external tools, such as containerd, or runC. +type Commit struct { + ID string // ID is the actual commit ID of external tool. + Expected string // Expected is the commit ID of external tool expected by dockerd as set at build time. +} + +// Info contains response of Engine API: +// GET "/info" +type Info struct { + ID string + Containers int + ContainersRunning int + ContainersPaused int + ContainersStopped int + Images int + Driver string + DriverStatus [][2]string + SystemStatus [][2]string + Plugins PluginsInfo + MemoryLimit bool + SwapLimit bool + KernelMemory bool + CPUCfsPeriod bool `json:"CpuCfsPeriod"` + CPUCfsQuota bool `json:"CpuCfsQuota"` + CPUShares bool + CPUSet bool + IPv4Forwarding bool + BridgeNfIptables bool + BridgeNfIP6tables bool `json:"BridgeNfIp6tables"` + Debug bool + NFd int + OomKillDisable bool + NGoroutines int + SystemTime string + LoggingDriver string + CgroupDriver string + NEventsListener int + KernelVersion string + OperatingSystem string + OSType string + Architecture string + IndexServerAddress string + RegistryConfig *registry.ServiceConfig + NCPU int + MemTotal int64 + GenericResources []swarm.GenericResource + DockerRootDir string + HTTPProxy string `json:"HttpProxy"` + HTTPSProxy string `json:"HttpsProxy"` + NoProxy string + Name string + Labels []string + ExperimentalBuild bool + ServerVersion string + ClusterStore string + ClusterAdvertise string + Runtimes map[string]Runtime + DefaultRuntime string + Swarm swarm.Info + // LiveRestoreEnabled determines whether containers should be kept + // running when the daemon is shutdown or upon daemon start if + // running containers are detected + LiveRestoreEnabled bool + Isolation container.Isolation + InitBinary string + ContainerdCommit Commit + RuncCommit Commit + InitCommit Commit + SecurityOptions []string +} + +// KeyValue holds a key/value pair +type KeyValue struct { + Key, Value string +} + +// SecurityOpt contains the name and options of a security option +type SecurityOpt struct { + Name string + Options []KeyValue +} + +// DecodeSecurityOptions decodes a security options string slice to a type safe +// SecurityOpt +func DecodeSecurityOptions(opts []string) ([]SecurityOpt, error) { + so := []SecurityOpt{} + for _, opt := range opts { + // support output from a < 1.13 docker daemon + if !strings.Contains(opt, "=") { + so = append(so, SecurityOpt{Name: opt}) + continue + } + secopt := SecurityOpt{} + split := strings.Split(opt, ",") + for _, s := range split { + kv := strings.SplitN(s, "=", 2) + if len(kv) != 2 { + return nil, fmt.Errorf("invalid security option %q", s) + } + if kv[0] == "" || kv[1] == "" { + return nil, errors.New("invalid empty security option") + } + if kv[0] == "name" { + secopt.Name = kv[1] + continue + } + secopt.Options = append(secopt.Options, KeyValue{Key: kv[0], Value: kv[1]}) + } + so = append(so, secopt) + } + return so, nil +} + +// PluginsInfo is a temp struct holding Plugins name +// registered with docker daemon. It is used by Info struct +type PluginsInfo struct { + // List of Volume plugins registered + Volume []string + // List of Network plugins registered + Network []string + // List of Authorization plugins registered + Authorization []string + // List of Log plugins registered + Log []string +} + +// ExecStartCheck is a temp struct used by execStart +// Config fields is part of ExecConfig in runconfig package +type ExecStartCheck struct { + // ExecStart will first check if it's detached + Detach bool + // Check if there's a tty + Tty bool +} + +// HealthcheckResult stores information about a single run of a healthcheck probe +type HealthcheckResult struct { + Start time.Time // Start is the time this check started + End time.Time // End is the time this check ended + ExitCode int // ExitCode meanings: 0=healthy, 1=unhealthy, 2=reserved (considered unhealthy), else=error running probe + Output string // Output from last check +} + +// Health states +const ( + NoHealthcheck = "none" // Indicates there is no healthcheck + Starting = "starting" // Starting indicates that the container is not yet ready + Healthy = "healthy" // Healthy indicates that the container is running correctly + Unhealthy = "unhealthy" // Unhealthy indicates that the container has a problem +) + +// Health stores information about the container's healthcheck results +type Health struct { + Status string // Status is one of Starting, Healthy or Unhealthy + FailingStreak int // FailingStreak is the number of consecutive failures + Log []*HealthcheckResult // Log contains the last few results (oldest first) +} + +// ContainerState stores container's running state +// it's part of ContainerJSONBase and will return by "inspect" command +type ContainerState struct { + Status string // String representation of the container state. Can be one of "created", "running", "paused", "restarting", "removing", "exited", or "dead" + Running bool + Paused bool + Restarting bool + OOMKilled bool + Dead bool + Pid int + ExitCode int + Error string + StartedAt string + FinishedAt string + Health *Health `json:",omitempty"` +} + +// ContainerNode stores information about the node that a container +// is running on. It's only available in Docker Swarm +type ContainerNode struct { + ID string + IPAddress string `json:"IP"` + Addr string + Name string + Cpus int + Memory int64 + Labels map[string]string +} + +// ContainerJSONBase contains response of Engine API: +// GET "/containers/{name:.*}/json" +type ContainerJSONBase struct { + ID string `json:"Id"` + Created string + Path string + Args []string + State *ContainerState + Image string + ResolvConfPath string + HostnamePath string + HostsPath string + LogPath string + Node *ContainerNode `json:",omitempty"` + Name string + RestartCount int + Driver string + Platform string + MountLabel string + ProcessLabel string + AppArmorProfile string + ExecIDs []string + HostConfig *container.HostConfig + GraphDriver GraphDriverData + SizeRw *int64 `json:",omitempty"` + SizeRootFs *int64 `json:",omitempty"` +} + +// ContainerJSON is newly used struct along with MountPoint +type ContainerJSON struct { + *ContainerJSONBase + Mounts []MountPoint + Config *container.Config + NetworkSettings *NetworkSettings +} + +// NetworkSettings exposes the network settings in the api +type NetworkSettings struct { + NetworkSettingsBase + DefaultNetworkSettings + Networks map[string]*network.EndpointSettings +} + +// SummaryNetworkSettings provides a summary of container's networks +// in /containers/json +type SummaryNetworkSettings struct { + Networks map[string]*network.EndpointSettings +} + +// NetworkSettingsBase holds basic information about networks +type NetworkSettingsBase struct { + Bridge string // Bridge is the Bridge name the network uses(e.g. `docker0`) + SandboxID string // SandboxID uniquely represents a container's network stack + HairpinMode bool // HairpinMode specifies if hairpin NAT should be enabled on the virtual interface + LinkLocalIPv6Address string // LinkLocalIPv6Address is an IPv6 unicast address using the link-local prefix + LinkLocalIPv6PrefixLen int // LinkLocalIPv6PrefixLen is the prefix length of an IPv6 unicast address + Ports nat.PortMap // Ports is a collection of PortBinding indexed by Port + SandboxKey string // SandboxKey identifies the sandbox + SecondaryIPAddresses []network.Address + SecondaryIPv6Addresses []network.Address +} + +// DefaultNetworkSettings holds network information +// during the 2 release deprecation period. +// It will be removed in Docker 1.11. +type DefaultNetworkSettings struct { + EndpointID string // EndpointID uniquely represents a service endpoint in a Sandbox + Gateway string // Gateway holds the gateway address for the network + GlobalIPv6Address string // GlobalIPv6Address holds network's global IPv6 address + GlobalIPv6PrefixLen int // GlobalIPv6PrefixLen represents mask length of network's global IPv6 address + IPAddress string // IPAddress holds the IPv4 address for the network + IPPrefixLen int // IPPrefixLen represents mask length of network's IPv4 address + IPv6Gateway string // IPv6Gateway holds gateway address specific for IPv6 + MacAddress string // MacAddress holds the MAC address for the network +} + +// MountPoint represents a mount point configuration inside the container. +// This is used for reporting the mountpoints in use by a container. +type MountPoint struct { + Type mount.Type `json:",omitempty"` + Name string `json:",omitempty"` + Source string + Destination string + Driver string `json:",omitempty"` + Mode string + RW bool + Propagation mount.Propagation +} + +// NetworkResource is the body of the "get network" http response message +type NetworkResource struct { + Name string // Name is the requested name of the network + ID string `json:"Id"` // ID uniquely identifies a network on a single machine + Created time.Time // Created is the time the network created + Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level) + Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`) + EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6 + IPAM network.IPAM // IPAM is the network's IP Address Management + Internal bool // Internal represents if the network is used internal only + Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. + Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. + ConfigFrom network.ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. + ConfigOnly bool // ConfigOnly networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services. + Containers map[string]EndpointResource // Containers contains endpoints belonging to the network + Options map[string]string // Options holds the network specific options to use for when creating the network + Labels map[string]string // Labels holds metadata specific to the network being created + Peers []network.PeerInfo `json:",omitempty"` // List of peer nodes for an overlay network + Services map[string]network.ServiceInfo `json:",omitempty"` +} + +// EndpointResource contains network resources allocated and used for a container in a network +type EndpointResource struct { + Name string + EndpointID string + MacAddress string + IPv4Address string + IPv6Address string +} + +// NetworkCreate is the expected body of the "create network" http request message +type NetworkCreate struct { + // Check for networks with duplicate names. + // Network is primarily keyed based on a random ID and not on the name. + // Network name is strictly a user-friendly alias to the network + // which is uniquely identified using ID. + // And there is no guaranteed way to check for duplicates. + // Option CheckDuplicate is there to provide a best effort checking of any networks + // which has the same name but it is not guaranteed to catch all name collisions. + CheckDuplicate bool + Driver string + Scope string + EnableIPv6 bool + IPAM *network.IPAM + Internal bool + Attachable bool + Ingress bool + ConfigOnly bool + ConfigFrom *network.ConfigReference + Options map[string]string + Labels map[string]string +} + +// NetworkCreateRequest is the request message sent to the server for network create call. +type NetworkCreateRequest struct { + NetworkCreate + Name string +} + +// NetworkCreateResponse is the response message sent by the server for network create call +type NetworkCreateResponse struct { + ID string `json:"Id"` + Warning string +} + +// NetworkConnect represents the data to be used to connect a container to the network +type NetworkConnect struct { + Container string + EndpointConfig *network.EndpointSettings `json:",omitempty"` +} + +// NetworkDisconnect represents the data to be used to disconnect a container from the network +type NetworkDisconnect struct { + Container string + Force bool +} + +// NetworkInspectOptions holds parameters to inspect network +type NetworkInspectOptions struct { + Scope string + Verbose bool +} + +// Checkpoint represents the details of a checkpoint +type Checkpoint struct { + Name string // Name is the name of the checkpoint +} + +// Runtime describes an OCI runtime +type Runtime struct { + Path string `json:"path"` + Args []string `json:"runtimeArgs,omitempty"` +} + +// DiskUsage contains response of Engine API: +// GET "/system/df" +type DiskUsage struct { + LayersSize int64 + Images []*ImageSummary + Containers []*Container + Volumes []*Volume + BuildCache []*BuildCache + BuilderSize int64 // deprecated +} + +// ContainersPruneReport contains the response for Engine API: +// POST "/containers/prune" +type ContainersPruneReport struct { + ContainersDeleted []string + SpaceReclaimed uint64 +} + +// VolumesPruneReport contains the response for Engine API: +// POST "/volumes/prune" +type VolumesPruneReport struct { + VolumesDeleted []string + SpaceReclaimed uint64 +} + +// ImagesPruneReport contains the response for Engine API: +// POST "/images/prune" +type ImagesPruneReport struct { + ImagesDeleted []ImageDeleteResponseItem + SpaceReclaimed uint64 +} + +// BuildCachePruneReport contains the response for Engine API: +// POST "/build/prune" +type BuildCachePruneReport struct { + SpaceReclaimed uint64 +} + +// NetworksPruneReport contains the response for Engine API: +// POST "/networks/prune" +type NetworksPruneReport struct { + NetworksDeleted []string +} + +// SecretCreateResponse contains the information returned to a client +// on the creation of a new secret. +type SecretCreateResponse struct { + // ID is the id of the created secret. + ID string +} + +// SecretListOptions holds parameters to list secrets +type SecretListOptions struct { + Filters filters.Args +} + +// ConfigCreateResponse contains the information returned to a client +// on the creation of a new config. +type ConfigCreateResponse struct { + // ID is the id of the created config. + ID string +} + +// ConfigListOptions holds parameters to list configs +type ConfigListOptions struct { + Filters filters.Args +} + +// PushResult contains the tag, manifest digest, and manifest size from the +// push. It's used to signal this information to the trust code in the client +// so it can sign the manifest if necessary. +type PushResult struct { + Tag string + Digest string + Size int +} + +// BuildResult contains the image id of a successful build +type BuildResult struct { + ID string +} + +// BuildCache contains information about a build cache record +type BuildCache struct { + ID string + Mutable bool + InUse bool + Size int64 + + CreatedAt time.Time + LastUsedAt *time.Time + UsageCount int + Parent string + Description string +} diff --git a/vendor/github.com/docker/docker/api/types/versions/README.md b/vendor/github.com/docker/docker/api/types/versions/README.md new file mode 100644 index 000000000..1ef911edb --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/versions/README.md @@ -0,0 +1,14 @@ +# Legacy API type versions + +This package includes types for legacy API versions. The stable version of the API types live in `api/types/*.go`. + +Consider moving a type here when you need to keep backwards compatibility in the API. This legacy types are organized by the latest API version they appear in. For instance, types in the `v1p19` package are valid for API versions below or equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, since the versions below that will use the legacy types in `v1p19`. + +## Package name conventions + +The package name convention is to use `v` as a prefix for the version number and `p`(patch) as a separator. We use this nomenclature due to a few restrictions in the Go package name convention: + +1. We cannot use `.` because it's interpreted by the language, think of `v1.20.CallFunction`. +2. We cannot use `_` because golint complains about it. The code is actually valid, but it looks probably more weird: `v1_20.CallFunction`. + +For instance, if you want to modify a type that was available in the version `1.21` of the API but it will have different fields in the version `1.22`, you want to create a new package under `api/types/versions/v1p21`. diff --git a/vendor/github.com/docker/docker/api/types/versions/compare.go b/vendor/github.com/docker/docker/api/types/versions/compare.go new file mode 100644 index 000000000..8ccb0aa92 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/versions/compare.go @@ -0,0 +1,62 @@ +package versions // import "github.com/docker/docker/api/types/versions" + +import ( + "strconv" + "strings" +) + +// compare compares two version strings +// returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise. +func compare(v1, v2 string) int { + var ( + currTab = strings.Split(v1, ".") + otherTab = strings.Split(v2, ".") + ) + + max := len(currTab) + if len(otherTab) > max { + max = len(otherTab) + } + for i := 0; i < max; i++ { + var currInt, otherInt int + + if len(currTab) > i { + currInt, _ = strconv.Atoi(currTab[i]) + } + if len(otherTab) > i { + otherInt, _ = strconv.Atoi(otherTab[i]) + } + if currInt > otherInt { + return 1 + } + if otherInt > currInt { + return -1 + } + } + return 0 +} + +// LessThan checks if a version is less than another +func LessThan(v, other string) bool { + return compare(v, other) == -1 +} + +// LessThanOrEqualTo checks if a version is less than or equal to another +func LessThanOrEqualTo(v, other string) bool { + return compare(v, other) <= 0 +} + +// GreaterThan checks if a version is greater than another +func GreaterThan(v, other string) bool { + return compare(v, other) == 1 +} + +// GreaterThanOrEqualTo checks if a version is greater than or equal to another +func GreaterThanOrEqualTo(v, other string) bool { + return compare(v, other) >= 0 +} + +// Equal checks if a version is equal to another +func Equal(v, other string) bool { + return compare(v, other) == 0 +} diff --git a/vendor/github.com/docker/docker/api/types/volume.go b/vendor/github.com/docker/docker/api/types/volume.go new file mode 100644 index 000000000..b5ee96a50 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/volume.go @@ -0,0 +1,69 @@ +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// Volume volume +// swagger:model Volume +type Volume struct { + + // Date/Time the volume was created. + CreatedAt string `json:"CreatedAt,omitempty"` + + // Name of the volume driver used by the volume. + // Required: true + Driver string `json:"Driver"` + + // User-defined key/value metadata. + // Required: true + Labels map[string]string `json:"Labels"` + + // Mount path of the volume on the host. + // Required: true + Mountpoint string `json:"Mountpoint"` + + // Name of the volume. + // Required: true + Name string `json:"Name"` + + // The driver specific options used when creating the volume. + // Required: true + Options map[string]string `json:"Options"` + + // The level at which the volume exists. Either `global` for cluster-wide, or `local` for machine level. + // Required: true + Scope string `json:"Scope"` + + // Low-level details about the volume, provided by the volume driver. + // Details are returned as a map with key/value pairs: + // `{"key":"value","key2":"value2"}`. + // + // The `Status` field is optional, and is omitted if the volume driver + // does not support this feature. + // + Status map[string]interface{} `json:"Status,omitempty"` + + // usage data + UsageData *VolumeUsageData `json:"UsageData,omitempty"` +} + +// VolumeUsageData Usage details about the volume. This information is used by the +// `GET /system/df` endpoint, and omitted in other endpoints. +// +// swagger:model VolumeUsageData +type VolumeUsageData struct { + + // The number of containers referencing this volume. This field + // is set to `-1` if the reference-count is not available. + // + // Required: true + RefCount int64 `json:"RefCount"` + + // Amount of disk space used by the volume (in bytes). This information + // is only available for volumes created with the `"local"` volume + // driver. For volumes created with other volume drivers, this field + // is set to `-1` ("not available") + // + // Required: true + Size int64 `json:"Size"` +} diff --git a/vendor/github.com/docker/docker/contrib/syntax/vim/LICENSE b/vendor/github.com/docker/docker/contrib/syntax/vim/LICENSE new file mode 100644 index 000000000..e67cdabd2 --- /dev/null +++ b/vendor/github.com/docker/docker/contrib/syntax/vim/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013 Honza Pokorny +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/docker/docker/docs/static_files/contributors.png b/vendor/github.com/docker/docker/docs/static_files/contributors.png new file mode 100644 index 0000000000000000000000000000000000000000..63c0a0c09b58bce2e1ade867760a937612934202 GIT binary patch literal 23100 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 literal 0 HcmV?d00001 diff --git a/vendor/github.com/docker/docker/hack/generate-authors.sh b/vendor/github.com/docker/docker/hack/generate-authors.sh new file mode 100755 index 000000000..680bdb7b3 --- /dev/null +++ b/vendor/github.com/docker/docker/hack/generate-authors.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -e + +cd "$(dirname "$(readlink -f "$BASH_SOURCE")")/.." + +# see also ".mailmap" for how email addresses and names are deduplicated + +{ + cat <<-'EOH' + # This file lists all individuals having contributed content to the repository. + # For how it is generated, see `hack/generate-authors.sh`. + EOH + echo + git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf +} > AUTHORS diff --git a/vendor/github.com/docker/docker/integration-cli/fixtures/https/ca.pem b/vendor/github.com/docker/docker/integration-cli/fixtures/https/ca.pem new file mode 120000 index 000000000..70a3e6ce5 --- /dev/null +++ b/vendor/github.com/docker/docker/integration-cli/fixtures/https/ca.pem @@ -0,0 +1 @@ +../../../integration/testdata/https/ca.pem \ No newline at end of file diff --git a/vendor/github.com/docker/docker/integration-cli/fixtures/https/client-cert.pem b/vendor/github.com/docker/docker/integration-cli/fixtures/https/client-cert.pem new file mode 120000 index 000000000..458882026 --- /dev/null +++ b/vendor/github.com/docker/docker/integration-cli/fixtures/https/client-cert.pem @@ -0,0 +1 @@ +../../../integration/testdata/https/client-cert.pem \ No newline at end of file diff --git a/vendor/github.com/docker/docker/integration-cli/fixtures/https/client-key.pem b/vendor/github.com/docker/docker/integration-cli/fixtures/https/client-key.pem new file mode 120000 index 000000000..d5f6bbee5 --- /dev/null +++ b/vendor/github.com/docker/docker/integration-cli/fixtures/https/client-key.pem @@ -0,0 +1 @@ +../../../integration/testdata/https/client-key.pem \ No newline at end of file diff --git a/vendor/github.com/docker/docker/integration-cli/fixtures/https/server-cert.pem b/vendor/github.com/docker/docker/integration-cli/fixtures/https/server-cert.pem new file mode 120000 index 000000000..c18601067 --- /dev/null +++ b/vendor/github.com/docker/docker/integration-cli/fixtures/https/server-cert.pem @@ -0,0 +1 @@ +../../../integration/testdata/https/server-cert.pem \ No newline at end of file diff --git a/vendor/github.com/docker/docker/integration-cli/fixtures/https/server-key.pem b/vendor/github.com/docker/docker/integration-cli/fixtures/https/server-key.pem new file mode 120000 index 000000000..48b9c2df6 --- /dev/null +++ b/vendor/github.com/docker/docker/integration-cli/fixtures/https/server-key.pem @@ -0,0 +1 @@ +../../../integration/testdata/https/server-key.pem \ No newline at end of file diff --git a/vendor/github.com/docker/docker/opts/address_pools.go b/vendor/github.com/docker/docker/opts/address_pools.go new file mode 100644 index 000000000..9b27a6285 --- /dev/null +++ b/vendor/github.com/docker/docker/opts/address_pools.go @@ -0,0 +1,84 @@ +package opts + +import ( + "encoding/csv" + "encoding/json" + "fmt" + "strconv" + "strings" + + types "github.com/docker/libnetwork/ipamutils" +) + +// PoolsOpt is a Value type for parsing the default address pools definitions +type PoolsOpt struct { + values []*types.NetworkToSplit +} + +// UnmarshalJSON fills values structure info from JSON input +func (p *PoolsOpt) UnmarshalJSON(raw []byte) error { + return json.Unmarshal(raw, &(p.values)) +} + +// Set predefined pools +func (p *PoolsOpt) Set(value string) error { + csvReader := csv.NewReader(strings.NewReader(value)) + fields, err := csvReader.Read() + if err != nil { + return err + } + + poolsDef := types.NetworkToSplit{} + + for _, field := range fields { + parts := strings.SplitN(field, "=", 2) + if len(parts) != 2 { + return fmt.Errorf("invalid field '%s' must be a key=value pair", field) + } + + key := strings.ToLower(parts[0]) + value := strings.ToLower(parts[1]) + + switch key { + case "base": + poolsDef.Base = value + case "size": + size, err := strconv.Atoi(value) + if err != nil { + return fmt.Errorf("invalid size value: %q (must be integer): %v", value, err) + } + poolsDef.Size = size + default: + return fmt.Errorf("unexpected key '%s' in '%s'", key, field) + } + } + + p.values = append(p.values, &poolsDef) + + return nil +} + +// Type returns the type of this option +func (p *PoolsOpt) Type() string { + return "pool-options" +} + +// String returns a string repr of this option +func (p *PoolsOpt) String() string { + var pools []string + for _, pool := range p.values { + repr := fmt.Sprintf("%s %d", pool.Base, pool.Size) + pools = append(pools, repr) + } + return strings.Join(pools, ", ") +} + +// Value returns the mounts +func (p *PoolsOpt) Value() []*types.NetworkToSplit { + return p.values +} + +// Name returns the flag name of this option +func (p *PoolsOpt) Name() string { + return "default-address-pools" +} diff --git a/vendor/github.com/docker/docker/opts/env.go b/vendor/github.com/docker/docker/opts/env.go new file mode 100644 index 000000000..f6e5e9074 --- /dev/null +++ b/vendor/github.com/docker/docker/opts/env.go @@ -0,0 +1,48 @@ +package opts // import "github.com/docker/docker/opts" + +import ( + "fmt" + "os" + "runtime" + "strings" + + "github.com/pkg/errors" +) + +// ValidateEnv validates an environment variable and returns it. +// If no value is specified, it returns the current value using os.Getenv. +// +// As on ParseEnvFile and related to #16585, environment variable names +// are not validate what so ever, it's up to application inside docker +// to validate them or not. +// +// The only validation here is to check if name is empty, per #25099 +func ValidateEnv(val string) (string, error) { + arr := strings.Split(val, "=") + if arr[0] == "" { + return "", errors.Errorf("invalid environment variable: %s", val) + } + if len(arr) > 1 { + return val, nil + } + if !doesEnvExist(val) { + return val, nil + } + return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil +} + +func doesEnvExist(name string) bool { + for _, entry := range os.Environ() { + parts := strings.SplitN(entry, "=", 2) + if runtime.GOOS == "windows" { + // Environment variable are case-insensitive on Windows. PaTh, path and PATH are equivalent. + if strings.EqualFold(parts[0], name) { + return true + } + } + if parts[0] == name { + return true + } + } + return false +} diff --git a/vendor/github.com/docker/docker/opts/hosts.go b/vendor/github.com/docker/docker/opts/hosts.go new file mode 100644 index 000000000..2adf4211d --- /dev/null +++ b/vendor/github.com/docker/docker/opts/hosts.go @@ -0,0 +1,165 @@ +package opts // import "github.com/docker/docker/opts" + +import ( + "fmt" + "net" + "net/url" + "strconv" + "strings" +) + +var ( + // DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. dockerd -H tcp:// + // These are the IANA registered port numbers for use with Docker + // see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker + DefaultHTTPPort = 2375 // Default HTTP Port + // DefaultTLSHTTPPort Default HTTP Port used when TLS enabled + DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port + // DefaultUnixSocket Path for the unix socket. + // Docker daemon by default always listens on the default unix socket + DefaultUnixSocket = "/var/run/docker.sock" + // DefaultTCPHost constant defines the default host string used by docker on Windows + DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort) + // DefaultTLSHost constant defines the default host string used by docker for TLS sockets + DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort) + // DefaultNamedPipe defines the default named pipe used by docker on Windows + DefaultNamedPipe = `//./pipe/docker_engine` +) + +// ValidateHost validates that the specified string is a valid host and returns it. +func ValidateHost(val string) (string, error) { + host := strings.TrimSpace(val) + // The empty string means default and is not handled by parseDaemonHost + if host != "" { + _, err := parseDaemonHost(host) + if err != nil { + return val, err + } + } + // Note: unlike most flag validators, we don't return the mutated value here + // we need to know what the user entered later (using ParseHost) to adjust for TLS + return val, nil +} + +// ParseHost and set defaults for a Daemon host string +func ParseHost(defaultToTLS bool, val string) (string, error) { + host := strings.TrimSpace(val) + if host == "" { + if defaultToTLS { + host = DefaultTLSHost + } else { + host = DefaultHost + } + } else { + var err error + host, err = parseDaemonHost(host) + if err != nil { + return val, err + } + } + return host, nil +} + +// parseDaemonHost parses the specified address and returns an address that will be used as the host. +// Depending of the address specified, this may return one of the global Default* strings defined in hosts.go. +func parseDaemonHost(addr string) (string, error) { + addrParts := strings.SplitN(addr, "://", 2) + if len(addrParts) == 1 && addrParts[0] != "" { + addrParts = []string{"tcp", addrParts[0]} + } + + switch addrParts[0] { + case "tcp": + return ParseTCPAddr(addrParts[1], DefaultTCPHost) + case "unix": + return parseSimpleProtoAddr("unix", addrParts[1], DefaultUnixSocket) + case "npipe": + return parseSimpleProtoAddr("npipe", addrParts[1], DefaultNamedPipe) + case "fd": + return addr, nil + default: + return "", fmt.Errorf("Invalid bind address format: %s", addr) + } +} + +// parseSimpleProtoAddr parses and validates that the specified address is a valid +// socket address for simple protocols like unix and npipe. It returns a formatted +// socket address, either using the address parsed from addr, or the contents of +// defaultAddr if addr is a blank string. +func parseSimpleProtoAddr(proto, addr, defaultAddr string) (string, error) { + addr = strings.TrimPrefix(addr, proto+"://") + if strings.Contains(addr, "://") { + return "", fmt.Errorf("Invalid proto, expected %s: %s", proto, addr) + } + if addr == "" { + addr = defaultAddr + } + return fmt.Sprintf("%s://%s", proto, addr), nil +} + +// ParseTCPAddr parses and validates that the specified address is a valid TCP +// address. It returns a formatted TCP address, either using the address parsed +// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string. +// tryAddr is expected to have already been Trim()'d +// defaultAddr must be in the full `tcp://host:port` form +func ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) { + if tryAddr == "" || tryAddr == "tcp://" { + return defaultAddr, nil + } + addr := strings.TrimPrefix(tryAddr, "tcp://") + if strings.Contains(addr, "://") || addr == "" { + return "", fmt.Errorf("Invalid proto, expected tcp: %s", tryAddr) + } + + defaultAddr = strings.TrimPrefix(defaultAddr, "tcp://") + defaultHost, defaultPort, err := net.SplitHostPort(defaultAddr) + if err != nil { + return "", err + } + // url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but + // not 1.4. See https://github.com/golang/go/issues/12200 and + // https://github.com/golang/go/issues/6530. + if strings.HasSuffix(addr, "]:") { + addr += defaultPort + } + + u, err := url.Parse("tcp://" + addr) + if err != nil { + return "", err + } + host, port, err := net.SplitHostPort(u.Host) + if err != nil { + // try port addition once + host, port, err = net.SplitHostPort(net.JoinHostPort(u.Host, defaultPort)) + } + if err != nil { + return "", fmt.Errorf("Invalid bind address format: %s", tryAddr) + } + + if host == "" { + host = defaultHost + } + if port == "" { + port = defaultPort + } + p, err := strconv.Atoi(port) + if err != nil && p == 0 { + return "", fmt.Errorf("Invalid bind address format: %s", tryAddr) + } + + return fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path), nil +} + +// ValidateExtraHost validates that the specified string is a valid extrahost and returns it. +// ExtraHost is in the form of name:ip where the ip has to be a valid ip (IPv4 or IPv6). +func ValidateExtraHost(val string) (string, error) { + // allow for IPv6 addresses in extra hosts by only splitting on first ":" + arr := strings.SplitN(val, ":", 2) + if len(arr) != 2 || len(arr[0]) == 0 { + return "", fmt.Errorf("bad format for add-host: %q", val) + } + if _, err := ValidateIPAddress(arr[1]); err != nil { + return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1]) + } + return val, nil +} diff --git a/vendor/github.com/docker/docker/opts/hosts_unix.go b/vendor/github.com/docker/docker/opts/hosts_unix.go new file mode 100644 index 000000000..9d5bb6456 --- /dev/null +++ b/vendor/github.com/docker/docker/opts/hosts_unix.go @@ -0,0 +1,8 @@ +// +build !windows + +package opts // import "github.com/docker/docker/opts" + +import "fmt" + +// DefaultHost constant defines the default host string used by docker on other hosts than Windows +var DefaultHost = fmt.Sprintf("unix://%s", DefaultUnixSocket) diff --git a/vendor/github.com/docker/docker/opts/hosts_windows.go b/vendor/github.com/docker/docker/opts/hosts_windows.go new file mode 100644 index 000000000..906eba53e --- /dev/null +++ b/vendor/github.com/docker/docker/opts/hosts_windows.go @@ -0,0 +1,4 @@ +package opts // import "github.com/docker/docker/opts" + +// DefaultHost constant defines the default host string used by docker on Windows +var DefaultHost = "npipe://" + DefaultNamedPipe diff --git a/vendor/github.com/docker/docker/opts/ip.go b/vendor/github.com/docker/docker/opts/ip.go new file mode 100644 index 000000000..cfbff3a9f --- /dev/null +++ b/vendor/github.com/docker/docker/opts/ip.go @@ -0,0 +1,47 @@ +package opts // import "github.com/docker/docker/opts" + +import ( + "fmt" + "net" +) + +// IPOpt holds an IP. It is used to store values from CLI flags. +type IPOpt struct { + *net.IP +} + +// NewIPOpt creates a new IPOpt from a reference net.IP and a +// string representation of an IP. If the string is not a valid +// IP it will fallback to the specified reference. +func NewIPOpt(ref *net.IP, defaultVal string) *IPOpt { + o := &IPOpt{ + IP: ref, + } + o.Set(defaultVal) + return o +} + +// Set sets an IPv4 or IPv6 address from a given string. If the given +// string is not parsable as an IP address it returns an error. +func (o *IPOpt) Set(val string) error { + ip := net.ParseIP(val) + if ip == nil { + return fmt.Errorf("%s is not an ip address", val) + } + *o.IP = ip + return nil +} + +// String returns the IP address stored in the IPOpt. If stored IP is a +// nil pointer, it returns an empty string. +func (o *IPOpt) String() string { + if *o.IP == nil { + return "" + } + return o.IP.String() +} + +// Type returns the type of the option +func (o *IPOpt) Type() string { + return "ip" +} diff --git a/vendor/github.com/docker/docker/opts/opts.go b/vendor/github.com/docker/docker/opts/opts.go new file mode 100644 index 000000000..de8aacb80 --- /dev/null +++ b/vendor/github.com/docker/docker/opts/opts.go @@ -0,0 +1,337 @@ +package opts // import "github.com/docker/docker/opts" + +import ( + "fmt" + "net" + "path" + "regexp" + "strings" + + "github.com/docker/go-units" +) + +var ( + alphaRegexp = regexp.MustCompile(`[a-zA-Z]`) + domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`) +) + +// ListOpts holds a list of values and a validation function. +type ListOpts struct { + values *[]string + validator ValidatorFctType +} + +// NewListOpts creates a new ListOpts with the specified validator. +func NewListOpts(validator ValidatorFctType) ListOpts { + var values []string + return *NewListOptsRef(&values, validator) +} + +// NewListOptsRef creates a new ListOpts with the specified values and validator. +func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts { + return &ListOpts{ + values: values, + validator: validator, + } +} + +func (opts *ListOpts) String() string { + if len(*opts.values) == 0 { + return "" + } + return fmt.Sprintf("%v", *opts.values) +} + +// Set validates if needed the input value and adds it to the +// internal slice. +func (opts *ListOpts) Set(value string) error { + if opts.validator != nil { + v, err := opts.validator(value) + if err != nil { + return err + } + value = v + } + *opts.values = append(*opts.values, value) + return nil +} + +// Delete removes the specified element from the slice. +func (opts *ListOpts) Delete(key string) { + for i, k := range *opts.values { + if k == key { + *opts.values = append((*opts.values)[:i], (*opts.values)[i+1:]...) + return + } + } +} + +// GetMap returns the content of values in a map in order to avoid +// duplicates. +func (opts *ListOpts) GetMap() map[string]struct{} { + ret := make(map[string]struct{}) + for _, k := range *opts.values { + ret[k] = struct{}{} + } + return ret +} + +// GetAll returns the values of slice. +func (opts *ListOpts) GetAll() []string { + return *opts.values +} + +// GetAllOrEmpty returns the values of the slice +// or an empty slice when there are no values. +func (opts *ListOpts) GetAllOrEmpty() []string { + v := *opts.values + if v == nil { + return make([]string, 0) + } + return v +} + +// Get checks the existence of the specified key. +func (opts *ListOpts) Get(key string) bool { + for _, k := range *opts.values { + if k == key { + return true + } + } + return false +} + +// Len returns the amount of element in the slice. +func (opts *ListOpts) Len() int { + return len(*opts.values) +} + +// Type returns a string name for this Option type +func (opts *ListOpts) Type() string { + return "list" +} + +// WithValidator returns the ListOpts with validator set. +func (opts *ListOpts) WithValidator(validator ValidatorFctType) *ListOpts { + opts.validator = validator + return opts +} + +// NamedOption is an interface that list and map options +// with names implement. +type NamedOption interface { + Name() string +} + +// NamedListOpts is a ListOpts with a configuration name. +// This struct is useful to keep reference to the assigned +// field name in the internal configuration struct. +type NamedListOpts struct { + name string + ListOpts +} + +var _ NamedOption = &NamedListOpts{} + +// NewNamedListOptsRef creates a reference to a new NamedListOpts struct. +func NewNamedListOptsRef(name string, values *[]string, validator ValidatorFctType) *NamedListOpts { + return &NamedListOpts{ + name: name, + ListOpts: *NewListOptsRef(values, validator), + } +} + +// Name returns the name of the NamedListOpts in the configuration. +func (o *NamedListOpts) Name() string { + return o.name +} + +// MapOpts holds a map of values and a validation function. +type MapOpts struct { + values map[string]string + validator ValidatorFctType +} + +// Set validates if needed the input value and add it to the +// internal map, by splitting on '='. +func (opts *MapOpts) Set(value string) error { + if opts.validator != nil { + v, err := opts.validator(value) + if err != nil { + return err + } + value = v + } + vals := strings.SplitN(value, "=", 2) + if len(vals) == 1 { + (opts.values)[vals[0]] = "" + } else { + (opts.values)[vals[0]] = vals[1] + } + return nil +} + +// GetAll returns the values of MapOpts as a map. +func (opts *MapOpts) GetAll() map[string]string { + return opts.values +} + +func (opts *MapOpts) String() string { + return fmt.Sprintf("%v", opts.values) +} + +// Type returns a string name for this Option type +func (opts *MapOpts) Type() string { + return "map" +} + +// NewMapOpts creates a new MapOpts with the specified map of values and a validator. +func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts { + if values == nil { + values = make(map[string]string) + } + return &MapOpts{ + values: values, + validator: validator, + } +} + +// NamedMapOpts is a MapOpts struct with a configuration name. +// This struct is useful to keep reference to the assigned +// field name in the internal configuration struct. +type NamedMapOpts struct { + name string + MapOpts +} + +var _ NamedOption = &NamedMapOpts{} + +// NewNamedMapOpts creates a reference to a new NamedMapOpts struct. +func NewNamedMapOpts(name string, values map[string]string, validator ValidatorFctType) *NamedMapOpts { + return &NamedMapOpts{ + name: name, + MapOpts: *NewMapOpts(values, validator), + } +} + +// Name returns the name of the NamedMapOpts in the configuration. +func (o *NamedMapOpts) Name() string { + return o.name +} + +// ValidatorFctType defines a validator function that returns a validated string and/or an error. +type ValidatorFctType func(val string) (string, error) + +// ValidatorFctListType defines a validator function that returns a validated list of string and/or an error +type ValidatorFctListType func(val string) ([]string, error) + +// ValidateIPAddress validates an Ip address. +func ValidateIPAddress(val string) (string, error) { + var ip = net.ParseIP(strings.TrimSpace(val)) + if ip != nil { + return ip.String(), nil + } + return "", fmt.Errorf("%s is not an ip address", val) +} + +// ValidateDNSSearch validates domain for resolvconf search configuration. +// A zero length domain is represented by a dot (.). +func ValidateDNSSearch(val string) (string, error) { + if val = strings.Trim(val, " "); val == "." { + return val, nil + } + return validateDomain(val) +} + +func validateDomain(val string) (string, error) { + if alphaRegexp.FindString(val) == "" { + return "", fmt.Errorf("%s is not a valid domain", val) + } + ns := domainRegexp.FindSubmatch([]byte(val)) + if len(ns) > 0 && len(ns[1]) < 255 { + return string(ns[1]), nil + } + return "", fmt.Errorf("%s is not a valid domain", val) +} + +// ValidateLabel validates that the specified string is a valid label, and returns it. +// Labels are in the form on key=value. +func ValidateLabel(val string) (string, error) { + if strings.Count(val, "=") < 1 { + return "", fmt.Errorf("bad attribute format: %s", val) + } + return val, nil +} + +// ValidateSingleGenericResource validates that a single entry in the +// generic resource list is valid. +// i.e 'GPU=UID1' is valid however 'GPU:UID1' or 'UID1' isn't +func ValidateSingleGenericResource(val string) (string, error) { + if strings.Count(val, "=") < 1 { + return "", fmt.Errorf("invalid node-generic-resource format `%s` expected `name=value`", val) + } + return val, nil +} + +// ParseLink parses and validates the specified string as a link format (name:alias) +func ParseLink(val string) (string, string, error) { + if val == "" { + return "", "", fmt.Errorf("empty string specified for links") + } + arr := strings.Split(val, ":") + if len(arr) > 2 { + return "", "", fmt.Errorf("bad format for links: %s", val) + } + if len(arr) == 1 { + return val, val, nil + } + // This is kept because we can actually get a HostConfig with links + // from an already created container and the format is not `foo:bar` + // but `/foo:/c1/bar` + if strings.HasPrefix(arr[0], "/") { + _, alias := path.Split(arr[1]) + return arr[0][1:], alias, nil + } + return arr[0], arr[1], nil +} + +// MemBytes is a type for human readable memory bytes (like 128M, 2g, etc) +type MemBytes int64 + +// String returns the string format of the human readable memory bytes +func (m *MemBytes) String() string { + // NOTE: In spf13/pflag/flag.go, "0" is considered as "zero value" while "0 B" is not. + // We return "0" in case value is 0 here so that the default value is hidden. + // (Sometimes "default 0 B" is actually misleading) + if m.Value() != 0 { + return units.BytesSize(float64(m.Value())) + } + return "0" +} + +// Set sets the value of the MemBytes by passing a string +func (m *MemBytes) Set(value string) error { + val, err := units.RAMInBytes(value) + *m = MemBytes(val) + return err +} + +// Type returns the type +func (m *MemBytes) Type() string { + return "bytes" +} + +// Value returns the value in int64 +func (m *MemBytes) Value() int64 { + return int64(*m) +} + +// UnmarshalJSON is the customized unmarshaler for MemBytes +func (m *MemBytes) UnmarshalJSON(s []byte) error { + if len(s) <= 2 || s[0] != '"' || s[len(s)-1] != '"' { + return fmt.Errorf("invalid size: %q", s) + } + val, err := units.RAMInBytes(string(s[1 : len(s)-1])) + *m = MemBytes(val) + return err +} diff --git a/vendor/github.com/docker/docker/opts/opts_unix.go b/vendor/github.com/docker/docker/opts/opts_unix.go new file mode 100644 index 000000000..0c32367cb --- /dev/null +++ b/vendor/github.com/docker/docker/opts/opts_unix.go @@ -0,0 +1,6 @@ +// +build !windows + +package opts // import "github.com/docker/docker/opts" + +// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080 +const DefaultHTTPHost = "localhost" diff --git a/vendor/github.com/docker/docker/opts/opts_windows.go b/vendor/github.com/docker/docker/opts/opts_windows.go new file mode 100644 index 000000000..0e1b6c6d1 --- /dev/null +++ b/vendor/github.com/docker/docker/opts/opts_windows.go @@ -0,0 +1,56 @@ +package opts // import "github.com/docker/docker/opts" + +// TODO Windows. Identify bug in GOLang 1.5.1+ and/or Windows Server 2016 TP5. +// @jhowardmsft, @swernli. +// +// On Windows, this mitigates a problem with the default options of running +// a docker client against a local docker daemon on TP5. +// +// What was found that if the default host is "localhost", even if the client +// (and daemon as this is local) is not physically on a network, and the DNS +// cache is flushed (ipconfig /flushdns), then the client will pause for +// exactly one second when connecting to the daemon for calls. For example +// using docker run windowsservercore cmd, the CLI will send a create followed +// by an attach. You see the delay between the attach finishing and the attach +// being seen by the daemon. +// +// Here's some daemon debug logs with additional debug spew put in. The +// AfterWriteJSON log is the very last thing the daemon does as part of the +// create call. The POST /attach is the second CLI call. Notice the second +// time gap. +// +// time="2015-11-06T13:38:37.259627400-08:00" level=debug msg="After createRootfs" +// time="2015-11-06T13:38:37.263626300-08:00" level=debug msg="After setHostConfig" +// time="2015-11-06T13:38:37.267631200-08:00" level=debug msg="before createContainerPl...." +// time="2015-11-06T13:38:37.271629500-08:00" level=debug msg=ToDiskLocking.... +// time="2015-11-06T13:38:37.275643200-08:00" level=debug msg="loggin event...." +// time="2015-11-06T13:38:37.277627600-08:00" level=debug msg="logged event...." +// time="2015-11-06T13:38:37.279631800-08:00" level=debug msg="In defer func" +// time="2015-11-06T13:38:37.282628100-08:00" level=debug msg="After daemon.create" +// time="2015-11-06T13:38:37.286651700-08:00" level=debug msg="return 2" +// time="2015-11-06T13:38:37.289629500-08:00" level=debug msg="Returned from daemon.ContainerCreate" +// time="2015-11-06T13:38:37.311629100-08:00" level=debug msg="After WriteJSON" +// ... 1 second gap here.... +// time="2015-11-06T13:38:38.317866200-08:00" level=debug msg="Calling POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach" +// time="2015-11-06T13:38:38.326882500-08:00" level=info msg="POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach?stderr=1&stdin=1&stdout=1&stream=1" +// +// We suspect this is either a bug introduced in GOLang 1.5.1, or that a change +// in GOLang 1.5.1 (from 1.4.3) is exposing a bug in Windows. In theory, +// the Windows networking stack is supposed to resolve "localhost" internally, +// without hitting DNS, or even reading the hosts file (which is why localhost +// is commented out in the hosts file on Windows). +// +// We have validated that working around this using the actual IPv4 localhost +// address does not cause the delay. +// +// This does not occur with the docker client built with 1.4.3 on the same +// Windows build, regardless of whether the daemon is built using 1.5.1 +// or 1.4.3. It does not occur on Linux. We also verified we see the same thing +// on a cross-compiled Windows binary (from Linux). +// +// Final note: This is a mitigation, not a 'real' fix. It is still susceptible +// to the delay if a user were to do 'docker run -H=tcp://localhost:2375...' +// explicitly. + +// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080 +const DefaultHTTPHost = "127.0.0.1" diff --git a/vendor/github.com/docker/docker/opts/quotedstring.go b/vendor/github.com/docker/docker/opts/quotedstring.go new file mode 100644 index 000000000..6c889070e --- /dev/null +++ b/vendor/github.com/docker/docker/opts/quotedstring.go @@ -0,0 +1,37 @@ +package opts // import "github.com/docker/docker/opts" + +// QuotedString is a string that may have extra quotes around the value. The +// quotes are stripped from the value. +type QuotedString struct { + value *string +} + +// Set sets a new value +func (s *QuotedString) Set(val string) error { + *s.value = trimQuotes(val) + return nil +} + +// Type returns the type of the value +func (s *QuotedString) Type() string { + return "string" +} + +func (s *QuotedString) String() string { + return *s.value +} + +func trimQuotes(value string) string { + lastIndex := len(value) - 1 + for _, char := range []byte{'\'', '"'} { + if value[0] == char && value[lastIndex] == char { + return value[1:lastIndex] + } + } + return value +} + +// NewQuotedString returns a new quoted string option +func NewQuotedString(value *string) *QuotedString { + return &QuotedString{value: value} +} diff --git a/vendor/github.com/docker/docker/opts/runtime.go b/vendor/github.com/docker/docker/opts/runtime.go new file mode 100644 index 000000000..4b9babf0a --- /dev/null +++ b/vendor/github.com/docker/docker/opts/runtime.go @@ -0,0 +1,79 @@ +package opts // import "github.com/docker/docker/opts" + +import ( + "fmt" + "strings" + + "github.com/docker/docker/api/types" +) + +// RuntimeOpt defines a map of Runtimes +type RuntimeOpt struct { + name string + stockRuntimeName string + values *map[string]types.Runtime +} + +// NewNamedRuntimeOpt creates a new RuntimeOpt +func NewNamedRuntimeOpt(name string, ref *map[string]types.Runtime, stockRuntime string) *RuntimeOpt { + if ref == nil { + ref = &map[string]types.Runtime{} + } + return &RuntimeOpt{name: name, values: ref, stockRuntimeName: stockRuntime} +} + +// Name returns the name of the NamedListOpts in the configuration. +func (o *RuntimeOpt) Name() string { + return o.name +} + +// Set validates and updates the list of Runtimes +func (o *RuntimeOpt) Set(val string) error { + parts := strings.SplitN(val, "=", 2) + if len(parts) != 2 { + return fmt.Errorf("invalid runtime argument: %s", val) + } + + parts[0] = strings.TrimSpace(parts[0]) + parts[1] = strings.TrimSpace(parts[1]) + if parts[0] == "" || parts[1] == "" { + return fmt.Errorf("invalid runtime argument: %s", val) + } + + parts[0] = strings.ToLower(parts[0]) + if parts[0] == o.stockRuntimeName { + return fmt.Errorf("runtime name '%s' is reserved", o.stockRuntimeName) + } + + if _, ok := (*o.values)[parts[0]]; ok { + return fmt.Errorf("runtime '%s' was already defined", parts[0]) + } + + (*o.values)[parts[0]] = types.Runtime{Path: parts[1]} + + return nil +} + +// String returns Runtime values as a string. +func (o *RuntimeOpt) String() string { + var out []string + for k := range *o.values { + out = append(out, k) + } + + return fmt.Sprintf("%v", out) +} + +// GetMap returns a map of Runtimes (name: path) +func (o *RuntimeOpt) GetMap() map[string]types.Runtime { + if o.values != nil { + return *o.values + } + + return map[string]types.Runtime{} +} + +// Type returns the type of the option +func (o *RuntimeOpt) Type() string { + return "runtime" +} diff --git a/vendor/github.com/docker/docker/opts/ulimit.go b/vendor/github.com/docker/docker/opts/ulimit.go new file mode 100644 index 000000000..0e2a36236 --- /dev/null +++ b/vendor/github.com/docker/docker/opts/ulimit.go @@ -0,0 +1,81 @@ +package opts // import "github.com/docker/docker/opts" + +import ( + "fmt" + + "github.com/docker/go-units" +) + +// UlimitOpt defines a map of Ulimits +type UlimitOpt struct { + values *map[string]*units.Ulimit +} + +// NewUlimitOpt creates a new UlimitOpt +func NewUlimitOpt(ref *map[string]*units.Ulimit) *UlimitOpt { + if ref == nil { + ref = &map[string]*units.Ulimit{} + } + return &UlimitOpt{ref} +} + +// Set validates a Ulimit and sets its name as a key in UlimitOpt +func (o *UlimitOpt) Set(val string) error { + l, err := units.ParseUlimit(val) + if err != nil { + return err + } + + (*o.values)[l.Name] = l + + return nil +} + +// String returns Ulimit values as a string. +func (o *UlimitOpt) String() string { + var out []string + for _, v := range *o.values { + out = append(out, v.String()) + } + + return fmt.Sprintf("%v", out) +} + +// GetList returns a slice of pointers to Ulimits. +func (o *UlimitOpt) GetList() []*units.Ulimit { + var ulimits []*units.Ulimit + for _, v := range *o.values { + ulimits = append(ulimits, v) + } + + return ulimits +} + +// Type returns the option type +func (o *UlimitOpt) Type() string { + return "ulimit" +} + +// NamedUlimitOpt defines a named map of Ulimits +type NamedUlimitOpt struct { + name string + UlimitOpt +} + +var _ NamedOption = &NamedUlimitOpt{} + +// NewNamedUlimitOpt creates a new NamedUlimitOpt +func NewNamedUlimitOpt(name string, ref *map[string]*units.Ulimit) *NamedUlimitOpt { + if ref == nil { + ref = &map[string]*units.Ulimit{} + } + return &NamedUlimitOpt{ + name: name, + UlimitOpt: *NewUlimitOpt(ref), + } +} + +// Name returns the option name +func (o *NamedUlimitOpt) Name() string { + return o.name +} diff --git a/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go b/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go new file mode 100644 index 000000000..28cad499a --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go @@ -0,0 +1,298 @@ +package fileutils // import "github.com/docker/docker/pkg/fileutils" + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + "regexp" + "strings" + "text/scanner" + + "github.com/sirupsen/logrus" +) + +// PatternMatcher allows checking paths against a list of patterns +type PatternMatcher struct { + patterns []*Pattern + exclusions bool +} + +// NewPatternMatcher creates a new matcher object for specific patterns that can +// be used later to match against patterns against paths +func NewPatternMatcher(patterns []string) (*PatternMatcher, error) { + pm := &PatternMatcher{ + patterns: make([]*Pattern, 0, len(patterns)), + } + for _, p := range patterns { + // Eliminate leading and trailing whitespace. + p = strings.TrimSpace(p) + if p == "" { + continue + } + p = filepath.Clean(p) + newp := &Pattern{} + if p[0] == '!' { + if len(p) == 1 { + return nil, errors.New("illegal exclusion pattern: \"!\"") + } + newp.exclusion = true + p = p[1:] + pm.exclusions = true + } + // Do some syntax checking on the pattern. + // filepath's Match() has some really weird rules that are inconsistent + // so instead of trying to dup their logic, just call Match() for its + // error state and if there is an error in the pattern return it. + // If this becomes an issue we can remove this since its really only + // needed in the error (syntax) case - which isn't really critical. + if _, err := filepath.Match(p, "."); err != nil { + return nil, err + } + newp.cleanedPattern = p + newp.dirs = strings.Split(p, string(os.PathSeparator)) + pm.patterns = append(pm.patterns, newp) + } + return pm, nil +} + +// Matches matches path against all the patterns. Matches is not safe to be +// called concurrently +func (pm *PatternMatcher) Matches(file string) (bool, error) { + matched := false + file = filepath.FromSlash(file) + parentPath := filepath.Dir(file) + parentPathDirs := strings.Split(parentPath, string(os.PathSeparator)) + + for _, pattern := range pm.patterns { + negative := false + + if pattern.exclusion { + negative = true + } + + match, err := pattern.match(file) + if err != nil { + return false, err + } + + if !match && parentPath != "." { + // Check to see if the pattern matches one of our parent dirs. + if len(pattern.dirs) <= len(parentPathDirs) { + match, _ = pattern.match(strings.Join(parentPathDirs[:len(pattern.dirs)], string(os.PathSeparator))) + } + } + + if match { + matched = !negative + } + } + + if matched { + logrus.Debugf("Skipping excluded path: %s", file) + } + + return matched, nil +} + +// Exclusions returns true if any of the patterns define exclusions +func (pm *PatternMatcher) Exclusions() bool { + return pm.exclusions +} + +// Patterns returns array of active patterns +func (pm *PatternMatcher) Patterns() []*Pattern { + return pm.patterns +} + +// Pattern defines a single regexp used used to filter file paths. +type Pattern struct { + cleanedPattern string + dirs []string + regexp *regexp.Regexp + exclusion bool +} + +func (p *Pattern) String() string { + return p.cleanedPattern +} + +// Exclusion returns true if this pattern defines exclusion +func (p *Pattern) Exclusion() bool { + return p.exclusion +} + +func (p *Pattern) match(path string) (bool, error) { + + if p.regexp == nil { + if err := p.compile(); err != nil { + return false, filepath.ErrBadPattern + } + } + + b := p.regexp.MatchString(path) + + return b, nil +} + +func (p *Pattern) compile() error { + regStr := "^" + pattern := p.cleanedPattern + // Go through the pattern and convert it to a regexp. + // We use a scanner so we can support utf-8 chars. + var scan scanner.Scanner + scan.Init(strings.NewReader(pattern)) + + sl := string(os.PathSeparator) + escSL := sl + if sl == `\` { + escSL += `\` + } + + for scan.Peek() != scanner.EOF { + ch := scan.Next() + + if ch == '*' { + if scan.Peek() == '*' { + // is some flavor of "**" + scan.Next() + + // Treat **/ as ** so eat the "/" + if string(scan.Peek()) == sl { + scan.Next() + } + + if scan.Peek() == scanner.EOF { + // is "**EOF" - to align with .gitignore just accept all + regStr += ".*" + } else { + // is "**" + // Note that this allows for any # of /'s (even 0) because + // the .* will eat everything, even /'s + regStr += "(.*" + escSL + ")?" + } + } else { + // is "*" so map it to anything but "/" + regStr += "[^" + escSL + "]*" + } + } else if ch == '?' { + // "?" is any char except "/" + regStr += "[^" + escSL + "]" + } else if ch == '.' || ch == '$' { + // Escape some regexp special chars that have no meaning + // in golang's filepath.Match + regStr += `\` + string(ch) + } else if ch == '\\' { + // escape next char. Note that a trailing \ in the pattern + // will be left alone (but need to escape it) + if sl == `\` { + // On windows map "\" to "\\", meaning an escaped backslash, + // and then just continue because filepath.Match on + // Windows doesn't allow escaping at all + regStr += escSL + continue + } + if scan.Peek() != scanner.EOF { + regStr += `\` + string(scan.Next()) + } else { + regStr += `\` + } + } else { + regStr += string(ch) + } + } + + regStr += "$" + + re, err := regexp.Compile(regStr) + if err != nil { + return err + } + + p.regexp = re + return nil +} + +// Matches returns true if file matches any of the patterns +// and isn't excluded by any of the subsequent patterns. +func Matches(file string, patterns []string) (bool, error) { + pm, err := NewPatternMatcher(patterns) + if err != nil { + return false, err + } + file = filepath.Clean(file) + + if file == "." { + // Don't let them exclude everything, kind of silly. + return false, nil + } + + return pm.Matches(file) +} + +// CopyFile copies from src to dst until either EOF is reached +// on src or an error occurs. It verifies src exists and removes +// the dst if it exists. +func CopyFile(src, dst string) (int64, error) { + cleanSrc := filepath.Clean(src) + cleanDst := filepath.Clean(dst) + if cleanSrc == cleanDst { + return 0, nil + } + sf, err := os.Open(cleanSrc) + if err != nil { + return 0, err + } + defer sf.Close() + if err := os.Remove(cleanDst); err != nil && !os.IsNotExist(err) { + return 0, err + } + df, err := os.Create(cleanDst) + if err != nil { + return 0, err + } + defer df.Close() + return io.Copy(df, sf) +} + +// ReadSymlinkedDirectory returns the target directory of a symlink. +// The target of the symbolic link may not be a file. +func ReadSymlinkedDirectory(path string) (string, error) { + var realPath string + var err error + if realPath, err = filepath.Abs(path); err != nil { + return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err) + } + if realPath, err = filepath.EvalSymlinks(realPath); err != nil { + return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err) + } + realPathInfo, err := os.Stat(realPath) + if err != nil { + return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err) + } + if !realPathInfo.Mode().IsDir() { + return "", fmt.Errorf("canonical path points to a file '%s'", realPath) + } + return realPath, nil +} + +// CreateIfNotExists creates a file or a directory only if it does not already exist. +func CreateIfNotExists(path string, isDir bool) error { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + if isDir { + return os.MkdirAll(path, 0755) + } + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + f, err := os.OpenFile(path, os.O_CREATE, 0755) + if err != nil { + return err + } + f.Close() + } + } + return nil +} diff --git a/vendor/github.com/docker/docker/pkg/fileutils/fileutils_darwin.go b/vendor/github.com/docker/docker/pkg/fileutils/fileutils_darwin.go new file mode 100644 index 000000000..e40cc271b --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/fileutils/fileutils_darwin.go @@ -0,0 +1,27 @@ +package fileutils // import "github.com/docker/docker/pkg/fileutils" + +import ( + "os" + "os/exec" + "strconv" + "strings" +) + +// GetTotalUsedFds returns the number of used File Descriptors by +// executing `lsof -p PID` +func GetTotalUsedFds() int { + pid := os.Getpid() + + cmd := exec.Command("lsof", "-p", strconv.Itoa(pid)) + + output, err := cmd.CombinedOutput() + if err != nil { + return -1 + } + + outputStr := strings.TrimSpace(string(output)) + + fds := strings.Split(outputStr, "\n") + + return len(fds) - 1 +} diff --git a/vendor/github.com/docker/docker/pkg/fileutils/fileutils_unix.go b/vendor/github.com/docker/docker/pkg/fileutils/fileutils_unix.go new file mode 100644 index 000000000..565396f1c --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/fileutils/fileutils_unix.go @@ -0,0 +1,22 @@ +// +build linux freebsd + +package fileutils // import "github.com/docker/docker/pkg/fileutils" + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/sirupsen/logrus" +) + +// GetTotalUsedFds Returns the number of used File Descriptors by +// reading it via /proc filesystem. +func GetTotalUsedFds() int { + if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil { + logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err) + } else { + return len(fds) + } + return -1 +} diff --git a/vendor/github.com/docker/docker/pkg/fileutils/fileutils_windows.go b/vendor/github.com/docker/docker/pkg/fileutils/fileutils_windows.go new file mode 100644 index 000000000..3f1ebb656 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/fileutils/fileutils_windows.go @@ -0,0 +1,7 @@ +package fileutils // import "github.com/docker/docker/pkg/fileutils" + +// GetTotalUsedFds Returns the number of used File Descriptors. Not supported +// on Windows. +func GetTotalUsedFds() int { + return -1 +} diff --git a/vendor/github.com/docker/docker/pkg/homedir/homedir_linux.go b/vendor/github.com/docker/docker/pkg/homedir/homedir_linux.go new file mode 100644 index 000000000..ee15ed52b --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/homedir/homedir_linux.go @@ -0,0 +1,21 @@ +package homedir // import "github.com/docker/docker/pkg/homedir" + +import ( + "os" + + "github.com/docker/docker/pkg/idtools" +) + +// GetStatic returns the home directory for the current user without calling +// os/user.Current(). This is useful for static-linked binary on glibc-based +// system, because a call to os/user.Current() in a static binary leads to +// segfault due to a glibc issue that won't be fixed in a short term. +// (#29344, golang/go#13470, https://sourceware.org/bugzilla/show_bug.cgi?id=19341) +func GetStatic() (string, error) { + uid := os.Getuid() + usr, err := idtools.LookupUID(uid) + if err != nil { + return "", err + } + return usr.Home, nil +} diff --git a/vendor/github.com/docker/docker/pkg/homedir/homedir_others.go b/vendor/github.com/docker/docker/pkg/homedir/homedir_others.go new file mode 100644 index 000000000..75ada2fe5 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/homedir/homedir_others.go @@ -0,0 +1,13 @@ +// +build !linux + +package homedir // import "github.com/docker/docker/pkg/homedir" + +import ( + "errors" +) + +// GetStatic is not needed for non-linux systems. +// (Precisely, it is needed only for glibc-based linux systems.) +func GetStatic() (string, error) { + return "", errors.New("homedir.GetStatic() is not supported on this system") +} diff --git a/vendor/github.com/docker/docker/pkg/homedir/homedir_unix.go b/vendor/github.com/docker/docker/pkg/homedir/homedir_unix.go new file mode 100644 index 000000000..d85e12448 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/homedir/homedir_unix.go @@ -0,0 +1,34 @@ +// +build !windows + +package homedir // import "github.com/docker/docker/pkg/homedir" + +import ( + "os" + + "github.com/opencontainers/runc/libcontainer/user" +) + +// Key returns the env var name for the user's home dir based on +// the platform being run on +func Key() string { + return "HOME" +} + +// Get returns the home directory of the current user with the help of +// environment variables depending on the target operating system. +// Returned path should be used with "path/filepath" to form new paths. +func Get() string { + home := os.Getenv(Key()) + if home == "" { + if u, err := user.CurrentUser(); err == nil { + return u.Home + } + } + return home +} + +// GetShortcutString returns the string that is shortcut to user's home directory +// in the native shell of the platform running on. +func GetShortcutString() string { + return "~" +} diff --git a/vendor/github.com/docker/docker/pkg/homedir/homedir_windows.go b/vendor/github.com/docker/docker/pkg/homedir/homedir_windows.go new file mode 100644 index 000000000..2f81813b2 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/homedir/homedir_windows.go @@ -0,0 +1,24 @@ +package homedir // import "github.com/docker/docker/pkg/homedir" + +import ( + "os" +) + +// Key returns the env var name for the user's home dir based on +// the platform being run on +func Key() string { + return "USERPROFILE" +} + +// Get returns the home directory of the current user with the help of +// environment variables depending on the target operating system. +// Returned path should be used with "path/filepath" to form new paths. +func Get() string { + return os.Getenv(Key()) +} + +// GetShortcutString returns the string that is shortcut to user's home directory +// in the native shell of the platform running on. +func GetShortcutString() string { + return "%USERPROFILE%" // be careful while using in format functions +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools.go b/vendor/github.com/docker/docker/pkg/idtools/idtools.go new file mode 100644 index 000000000..d1f173a31 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools.go @@ -0,0 +1,266 @@ +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "bufio" + "fmt" + "os" + "sort" + "strconv" + "strings" +) + +// IDMap contains a single entry for user namespace range remapping. An array +// of IDMap entries represents the structure that will be provided to the Linux +// kernel for creating a user namespace. +type IDMap struct { + ContainerID int `json:"container_id"` + HostID int `json:"host_id"` + Size int `json:"size"` +} + +type subIDRange struct { + Start int + Length int +} + +type ranges []subIDRange + +func (e ranges) Len() int { return len(e) } +func (e ranges) Swap(i, j int) { e[i], e[j] = e[j], e[i] } +func (e ranges) Less(i, j int) bool { return e[i].Start < e[j].Start } + +const ( + subuidFileName = "/etc/subuid" + subgidFileName = "/etc/subgid" +) + +// MkdirAllAndChown creates a directory (include any along the path) and then modifies +// ownership to the requested uid/gid. If the directory already exists, this +// function will still change ownership to the requested uid/gid pair. +func MkdirAllAndChown(path string, mode os.FileMode, owner IDPair) error { + return mkdirAs(path, mode, owner.UID, owner.GID, true, true) +} + +// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid. +// If the directory already exists, this function still changes ownership. +// Note that unlike os.Mkdir(), this function does not return IsExist error +// in case path already exists. +func MkdirAndChown(path string, mode os.FileMode, owner IDPair) error { + return mkdirAs(path, mode, owner.UID, owner.GID, false, true) +} + +// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies +// ownership ONLY of newly created directories to the requested uid/gid. If the +// directories along the path exist, no change of ownership will be performed +func MkdirAllAndChownNew(path string, mode os.FileMode, owner IDPair) error { + return mkdirAs(path, mode, owner.UID, owner.GID, true, false) +} + +// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps. +// If the maps are empty, then the root uid/gid will default to "real" 0/0 +func GetRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) { + uid, err := toHost(0, uidMap) + if err != nil { + return -1, -1, err + } + gid, err := toHost(0, gidMap) + if err != nil { + return -1, -1, err + } + return uid, gid, nil +} + +// toContainer takes an id mapping, and uses it to translate a +// host ID to the remapped ID. If no map is provided, then the translation +// assumes a 1-to-1 mapping and returns the passed in id +func toContainer(hostID int, idMap []IDMap) (int, error) { + if idMap == nil { + return hostID, nil + } + for _, m := range idMap { + if (hostID >= m.HostID) && (hostID <= (m.HostID + m.Size - 1)) { + contID := m.ContainerID + (hostID - m.HostID) + return contID, nil + } + } + return -1, fmt.Errorf("Host ID %d cannot be mapped to a container ID", hostID) +} + +// toHost takes an id mapping and a remapped ID, and translates the +// ID to the mapped host ID. If no map is provided, then the translation +// assumes a 1-to-1 mapping and returns the passed in id # +func toHost(contID int, idMap []IDMap) (int, error) { + if idMap == nil { + return contID, nil + } + for _, m := range idMap { + if (contID >= m.ContainerID) && (contID <= (m.ContainerID + m.Size - 1)) { + hostID := m.HostID + (contID - m.ContainerID) + return hostID, nil + } + } + return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID) +} + +// IDPair is a UID and GID pair +type IDPair struct { + UID int + GID int +} + +// IDMappings contains a mappings of UIDs and GIDs +type IDMappings struct { + uids []IDMap + gids []IDMap +} + +// NewIDMappings takes a requested user and group name and +// using the data from /etc/sub{uid,gid} ranges, creates the +// proper uid and gid remapping ranges for that user/group pair +func NewIDMappings(username, groupname string) (*IDMappings, error) { + subuidRanges, err := parseSubuid(username) + if err != nil { + return nil, err + } + subgidRanges, err := parseSubgid(groupname) + if err != nil { + return nil, err + } + if len(subuidRanges) == 0 { + return nil, fmt.Errorf("No subuid ranges found for user %q", username) + } + if len(subgidRanges) == 0 { + return nil, fmt.Errorf("No subgid ranges found for group %q", groupname) + } + + return &IDMappings{ + uids: createIDMap(subuidRanges), + gids: createIDMap(subgidRanges), + }, nil +} + +// NewIDMappingsFromMaps creates a new mapping from two slices +// Deprecated: this is a temporary shim while transitioning to IDMapping +func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IDMappings { + return &IDMappings{uids: uids, gids: gids} +} + +// RootPair returns a uid and gid pair for the root user. The error is ignored +// because a root user always exists, and the defaults are correct when the uid +// and gid maps are empty. +func (i *IDMappings) RootPair() IDPair { + uid, gid, _ := GetRootUIDGID(i.uids, i.gids) + return IDPair{UID: uid, GID: gid} +} + +// ToHost returns the host UID and GID for the container uid, gid. +// Remapping is only performed if the ids aren't already the remapped root ids +func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) { + var err error + target := i.RootPair() + + if pair.UID != target.UID { + target.UID, err = toHost(pair.UID, i.uids) + if err != nil { + return target, err + } + } + + if pair.GID != target.GID { + target.GID, err = toHost(pair.GID, i.gids) + } + return target, err +} + +// ToContainer returns the container UID and GID for the host uid and gid +func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) { + uid, err := toContainer(pair.UID, i.uids) + if err != nil { + return -1, -1, err + } + gid, err := toContainer(pair.GID, i.gids) + return uid, gid, err +} + +// Empty returns true if there are no id mappings +func (i *IDMappings) Empty() bool { + return len(i.uids) == 0 && len(i.gids) == 0 +} + +// UIDs return the UID mapping +// TODO: remove this once everything has been refactored to use pairs +func (i *IDMappings) UIDs() []IDMap { + return i.uids +} + +// GIDs return the UID mapping +// TODO: remove this once everything has been refactored to use pairs +func (i *IDMappings) GIDs() []IDMap { + return i.gids +} + +func createIDMap(subidRanges ranges) []IDMap { + idMap := []IDMap{} + + // sort the ranges by lowest ID first + sort.Sort(subidRanges) + containerID := 0 + for _, idrange := range subidRanges { + idMap = append(idMap, IDMap{ + ContainerID: containerID, + HostID: idrange.Start, + Size: idrange.Length, + }) + containerID = containerID + idrange.Length + } + return idMap +} + +func parseSubuid(username string) (ranges, error) { + return parseSubidFile(subuidFileName, username) +} + +func parseSubgid(username string) (ranges, error) { + return parseSubidFile(subgidFileName, username) +} + +// parseSubidFile will read the appropriate file (/etc/subuid or /etc/subgid) +// and return all found ranges for a specified username. If the special value +// "ALL" is supplied for username, then all ranges in the file will be returned +func parseSubidFile(path, username string) (ranges, error) { + var rangeList ranges + + subidFile, err := os.Open(path) + if err != nil { + return rangeList, err + } + defer subidFile.Close() + + s := bufio.NewScanner(subidFile) + for s.Scan() { + if err := s.Err(); err != nil { + return rangeList, err + } + + text := strings.TrimSpace(s.Text()) + if text == "" || strings.HasPrefix(text, "#") { + continue + } + parts := strings.Split(text, ":") + if len(parts) != 3 { + return rangeList, fmt.Errorf("Cannot parse subuid/gid information: Format not correct for %s file", path) + } + if parts[0] == username || username == "ALL" { + startid, err := strconv.Atoi(parts[1]) + if err != nil { + return rangeList, fmt.Errorf("String to int conversion failed during subuid/gid parsing of %s: %v", path, err) + } + length, err := strconv.Atoi(parts[2]) + if err != nil { + return rangeList, fmt.Errorf("String to int conversion failed during subuid/gid parsing of %s: %v", path, err) + } + rangeList = append(rangeList, subIDRange{startid, length}) + } + } + return rangeList, nil +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go b/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go new file mode 100644 index 000000000..1d87ea3bc --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go @@ -0,0 +1,230 @@ +// +build !windows + +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "syscall" + + "github.com/docker/docker/pkg/system" + "github.com/opencontainers/runc/libcontainer/user" +) + +var ( + entOnce sync.Once + getentCmd string +) + +func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error { + // make an array containing the original path asked for, plus (for mkAll == true) + // all path components leading up to the complete path that don't exist before we MkdirAll + // so that we can chown all of them properly at the end. If chownExisting is false, we won't + // chown the full directory path if it exists + var paths []string + + stat, err := system.Stat(path) + if err == nil { + if !stat.IsDir() { + return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} + } + if !chownExisting { + return nil + } + + // short-circuit--we were called with an existing directory and chown was requested + return lazyChown(path, ownerUID, ownerGID, stat) + } + + if os.IsNotExist(err) { + paths = []string{path} + } + + if mkAll { + // walk back to "/" looking for directories which do not exist + // and add them to the paths array for chown after creation + dirPath := path + for { + dirPath = filepath.Dir(dirPath) + if dirPath == "/" { + break + } + if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) { + paths = append(paths, dirPath) + } + } + if err := system.MkdirAll(path, mode, ""); err != nil { + return err + } + } else { + if err := os.Mkdir(path, mode); err != nil && !os.IsExist(err) { + return err + } + } + // even if it existed, we will chown the requested path + any subpaths that + // didn't exist when we called MkdirAll + for _, pathComponent := range paths { + if err := lazyChown(pathComponent, ownerUID, ownerGID, nil); err != nil { + return err + } + } + return nil +} + +// CanAccess takes a valid (existing) directory and a uid, gid pair and determines +// if that uid, gid pair has access (execute bit) to the directory +func CanAccess(path string, pair IDPair) bool { + statInfo, err := system.Stat(path) + if err != nil { + return false + } + fileMode := os.FileMode(statInfo.Mode()) + permBits := fileMode.Perm() + return accessible(statInfo.UID() == uint32(pair.UID), + statInfo.GID() == uint32(pair.GID), permBits) +} + +func accessible(isOwner, isGroup bool, perms os.FileMode) bool { + if isOwner && (perms&0100 == 0100) { + return true + } + if isGroup && (perms&0010 == 0010) { + return true + } + if perms&0001 == 0001 { + return true + } + return false +} + +// LookupUser uses traditional local system files lookup (from libcontainer/user) on a username, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupUser(username string) (user.User, error) { + // first try a local system files lookup using existing capabilities + usr, err := user.LookupUser(username) + if err == nil { + return usr, nil + } + // local files lookup failed; attempt to call `getent` to query configured passwd dbs + usr, err = getentUser(fmt.Sprintf("%s %s", "passwd", username)) + if err != nil { + return user.User{}, err + } + return usr, nil +} + +// LookupUID uses traditional local system files lookup (from libcontainer/user) on a uid, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupUID(uid int) (user.User, error) { + // first try a local system files lookup using existing capabilities + usr, err := user.LookupUid(uid) + if err == nil { + return usr, nil + } + // local files lookup failed; attempt to call `getent` to query configured passwd dbs + return getentUser(fmt.Sprintf("%s %d", "passwd", uid)) +} + +func getentUser(args string) (user.User, error) { + reader, err := callGetent(args) + if err != nil { + return user.User{}, err + } + users, err := user.ParsePasswd(reader) + if err != nil { + return user.User{}, err + } + if len(users) == 0 { + return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", strings.Split(args, " ")[1]) + } + return users[0], nil +} + +// LookupGroup uses traditional local system files lookup (from libcontainer/user) on a group name, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupGroup(groupname string) (user.Group, error) { + // first try a local system files lookup using existing capabilities + group, err := user.LookupGroup(groupname) + if err == nil { + return group, nil + } + // local files lookup failed; attempt to call `getent` to query configured group dbs + return getentGroup(fmt.Sprintf("%s %s", "group", groupname)) +} + +// LookupGID uses traditional local system files lookup (from libcontainer/user) on a group ID, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupGID(gid int) (user.Group, error) { + // first try a local system files lookup using existing capabilities + group, err := user.LookupGid(gid) + if err == nil { + return group, nil + } + // local files lookup failed; attempt to call `getent` to query configured group dbs + return getentGroup(fmt.Sprintf("%s %d", "group", gid)) +} + +func getentGroup(args string) (user.Group, error) { + reader, err := callGetent(args) + if err != nil { + return user.Group{}, err + } + groups, err := user.ParseGroup(reader) + if err != nil { + return user.Group{}, err + } + if len(groups) == 0 { + return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", strings.Split(args, " ")[1]) + } + return groups[0], nil +} + +func callGetent(args string) (io.Reader, error) { + entOnce.Do(func() { getentCmd, _ = resolveBinary("getent") }) + // if no `getent` command on host, can't do anything else + if getentCmd == "" { + return nil, fmt.Errorf("") + } + out, err := execCmd(getentCmd, args) + if err != nil { + exitCode, errC := system.GetExitCode(err) + if errC != nil { + return nil, err + } + switch exitCode { + case 1: + return nil, fmt.Errorf("getent reported invalid parameters/database unknown") + case 2: + terms := strings.Split(args, " ") + return nil, fmt.Errorf("getent unable to find entry %q in %s database", terms[1], terms[0]) + case 3: + return nil, fmt.Errorf("getent database doesn't support enumeration") + default: + return nil, err + } + + } + return bytes.NewReader(out), nil +} + +// lazyChown performs a chown only if the uid/gid don't match what's requested +// Normally a Chown is a no-op if uid/gid match, but in some cases this can still cause an error, e.g. if the +// dir is on an NFS share, so don't call chown unless we absolutely must. +func lazyChown(p string, uid, gid int, stat *system.StatT) error { + if stat == nil { + var err error + stat, err = system.Stat(p) + if err != nil { + return err + } + } + if stat.UID() == uint32(uid) && stat.GID() == uint32(gid) { + return nil + } + return os.Chown(p, uid, gid) +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go b/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go new file mode 100644 index 000000000..d72cc2892 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go @@ -0,0 +1,23 @@ +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "os" + + "github.com/docker/docker/pkg/system" +) + +// Platforms such as Windows do not support the UID/GID concept. So make this +// just a wrapper around system.MkdirAll. +func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error { + if err := system.MkdirAll(path, mode, ""); err != nil { + return err + } + return nil +} + +// CanAccess takes a valid (existing) directory and a uid, gid pair and determines +// if that uid, gid pair has access (execute bit) to the directory +// Windows does not require/support this function, so always return true +func CanAccess(path string, pair IDPair) bool { + return true +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go new file mode 100644 index 000000000..6272c5a40 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go @@ -0,0 +1,164 @@ +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "fmt" + "regexp" + "sort" + "strconv" + "strings" + "sync" +) + +// add a user and/or group to Linux /etc/passwd, /etc/group using standard +// Linux distribution commands: +// adduser --system --shell /bin/false --disabled-login --disabled-password --no-create-home --group +// useradd -r -s /bin/false + +var ( + once sync.Once + userCommand string + + cmdTemplates = map[string]string{ + "adduser": "--system --shell /bin/false --no-create-home --disabled-login --disabled-password --group %s", + "useradd": "-r -s /bin/false %s", + "usermod": "-%s %d-%d %s", + } + + idOutRegexp = regexp.MustCompile(`uid=([0-9]+).*gid=([0-9]+)`) + // default length for a UID/GID subordinate range + defaultRangeLen = 65536 + defaultRangeStart = 100000 + userMod = "usermod" +) + +// AddNamespaceRangesUser takes a username and uses the standard system +// utility to create a system user/group pair used to hold the +// /etc/sub{uid,gid} ranges which will be used for user namespace +// mapping ranges in containers. +func AddNamespaceRangesUser(name string) (int, int, error) { + if err := addUser(name); err != nil { + return -1, -1, fmt.Errorf("Error adding user %q: %v", name, err) + } + + // Query the system for the created uid and gid pair + out, err := execCmd("id", name) + if err != nil { + return -1, -1, fmt.Errorf("Error trying to find uid/gid for new user %q: %v", name, err) + } + matches := idOutRegexp.FindStringSubmatch(strings.TrimSpace(string(out))) + if len(matches) != 3 { + return -1, -1, fmt.Errorf("Can't find uid, gid from `id` output: %q", string(out)) + } + uid, err := strconv.Atoi(matches[1]) + if err != nil { + return -1, -1, fmt.Errorf("Can't convert found uid (%s) to int: %v", matches[1], err) + } + gid, err := strconv.Atoi(matches[2]) + if err != nil { + return -1, -1, fmt.Errorf("Can't convert found gid (%s) to int: %v", matches[2], err) + } + + // Now we need to create the subuid/subgid ranges for our new user/group (system users + // do not get auto-created ranges in subuid/subgid) + + if err := createSubordinateRanges(name); err != nil { + return -1, -1, fmt.Errorf("Couldn't create subordinate ID ranges: %v", err) + } + return uid, gid, nil +} + +func addUser(userName string) error { + once.Do(func() { + // set up which commands are used for adding users/groups dependent on distro + if _, err := resolveBinary("adduser"); err == nil { + userCommand = "adduser" + } else if _, err := resolveBinary("useradd"); err == nil { + userCommand = "useradd" + } + }) + if userCommand == "" { + return fmt.Errorf("Cannot add user; no useradd/adduser binary found") + } + args := fmt.Sprintf(cmdTemplates[userCommand], userName) + out, err := execCmd(userCommand, args) + if err != nil { + return fmt.Errorf("Failed to add user with error: %v; output: %q", err, string(out)) + } + return nil +} + +func createSubordinateRanges(name string) error { + + // first, we should verify that ranges weren't automatically created + // by the distro tooling + ranges, err := parseSubuid(name) + if err != nil { + return fmt.Errorf("Error while looking for subuid ranges for user %q: %v", name, err) + } + if len(ranges) == 0 { + // no UID ranges; let's create one + startID, err := findNextUIDRange() + if err != nil { + return fmt.Errorf("Can't find available subuid range: %v", err) + } + out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "v", startID, startID+defaultRangeLen-1, name)) + if err != nil { + return fmt.Errorf("Unable to add subuid range to user: %q; output: %s, err: %v", name, out, err) + } + } + + ranges, err = parseSubgid(name) + if err != nil { + return fmt.Errorf("Error while looking for subgid ranges for user %q: %v", name, err) + } + if len(ranges) == 0 { + // no GID ranges; let's create one + startID, err := findNextGIDRange() + if err != nil { + return fmt.Errorf("Can't find available subgid range: %v", err) + } + out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "w", startID, startID+defaultRangeLen-1, name)) + if err != nil { + return fmt.Errorf("Unable to add subgid range to user: %q; output: %s, err: %v", name, out, err) + } + } + return nil +} + +func findNextUIDRange() (int, error) { + ranges, err := parseSubuid("ALL") + if err != nil { + return -1, fmt.Errorf("Couldn't parse all ranges in /etc/subuid file: %v", err) + } + sort.Sort(ranges) + return findNextRangeStart(ranges) +} + +func findNextGIDRange() (int, error) { + ranges, err := parseSubgid("ALL") + if err != nil { + return -1, fmt.Errorf("Couldn't parse all ranges in /etc/subgid file: %v", err) + } + sort.Sort(ranges) + return findNextRangeStart(ranges) +} + +func findNextRangeStart(rangeList ranges) (int, error) { + startID := defaultRangeStart + for _, arange := range rangeList { + if wouldOverlap(arange, startID) { + startID = arange.Start + arange.Length + } + } + return startID, nil +} + +func wouldOverlap(arange subIDRange, ID int) bool { + low := ID + high := ID + defaultRangeLen + if (low >= arange.Start && low <= arange.Start+arange.Length) || + (high <= arange.Start+arange.Length && high >= arange.Start) { + return true + } + return false +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go new file mode 100644 index 000000000..e7c4d6311 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go @@ -0,0 +1,12 @@ +// +build !linux + +package idtools // import "github.com/docker/docker/pkg/idtools" + +import "fmt" + +// AddNamespaceRangesUser takes a name and finds an unused uid, gid pair +// and calls the appropriate helper function to add the group and then +// the user to the group in /etc/group and /etc/passwd respectively. +func AddNamespaceRangesUser(name string) (int, int, error) { + return -1, -1, fmt.Errorf("No support for adding users or groups on this OS") +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/utils_unix.go b/vendor/github.com/docker/docker/pkg/idtools/utils_unix.go new file mode 100644 index 000000000..903ac4501 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/utils_unix.go @@ -0,0 +1,32 @@ +// +build !windows + +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "fmt" + "os/exec" + "path/filepath" + "strings" +) + +func resolveBinary(binname string) (string, error) { + binaryPath, err := exec.LookPath(binname) + if err != nil { + return "", err + } + resolvedPath, err := filepath.EvalSymlinks(binaryPath) + if err != nil { + return "", err + } + //only return no error if the final resolved binary basename + //matches what was searched for + if filepath.Base(resolvedPath) == binname { + return resolvedPath, nil + } + return "", fmt.Errorf("Binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath) +} + +func execCmd(cmd, args string) ([]byte, error) { + execCmd := exec.Command(cmd, strings.Split(args, " ")...) + return execCmd.CombinedOutput() +} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/buffer.go b/vendor/github.com/docker/docker/pkg/ioutils/buffer.go new file mode 100644 index 000000000..466f79294 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/ioutils/buffer.go @@ -0,0 +1,51 @@ +package ioutils // import "github.com/docker/docker/pkg/ioutils" + +import ( + "errors" + "io" +) + +var errBufferFull = errors.New("buffer is full") + +type fixedBuffer struct { + buf []byte + pos int + lastRead int +} + +func (b *fixedBuffer) Write(p []byte) (int, error) { + n := copy(b.buf[b.pos:cap(b.buf)], p) + b.pos += n + + if n < len(p) { + if b.pos == cap(b.buf) { + return n, errBufferFull + } + return n, io.ErrShortWrite + } + return n, nil +} + +func (b *fixedBuffer) Read(p []byte) (int, error) { + n := copy(p, b.buf[b.lastRead:b.pos]) + b.lastRead += n + return n, nil +} + +func (b *fixedBuffer) Len() int { + return b.pos - b.lastRead +} + +func (b *fixedBuffer) Cap() int { + return cap(b.buf) +} + +func (b *fixedBuffer) Reset() { + b.pos = 0 + b.lastRead = 0 + b.buf = b.buf[:0] +} + +func (b *fixedBuffer) String() string { + return string(b.buf[b.lastRead:b.pos]) +} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go b/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go new file mode 100644 index 000000000..d4bbf3c9d --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go @@ -0,0 +1,186 @@ +package ioutils // import "github.com/docker/docker/pkg/ioutils" + +import ( + "errors" + "io" + "sync" +) + +// maxCap is the highest capacity to use in byte slices that buffer data. +const maxCap = 1e6 + +// minCap is the lowest capacity to use in byte slices that buffer data +const minCap = 64 + +// blockThreshold is the minimum number of bytes in the buffer which will cause +// a write to BytesPipe to block when allocating a new slice. +const blockThreshold = 1e6 + +var ( + // ErrClosed is returned when Write is called on a closed BytesPipe. + ErrClosed = errors.New("write to closed BytesPipe") + + bufPools = make(map[int]*sync.Pool) + bufPoolsLock sync.Mutex +) + +// BytesPipe is io.ReadWriteCloser which works similarly to pipe(queue). +// All written data may be read at most once. Also, BytesPipe allocates +// and releases new byte slices to adjust to current needs, so the buffer +// won't be overgrown after peak loads. +type BytesPipe struct { + mu sync.Mutex + wait *sync.Cond + buf []*fixedBuffer + bufLen int + closeErr error // error to return from next Read. set to nil if not closed. +} + +// NewBytesPipe creates new BytesPipe, initialized by specified slice. +// If buf is nil, then it will be initialized with slice which cap is 64. +// buf will be adjusted in a way that len(buf) == 0, cap(buf) == cap(buf). +func NewBytesPipe() *BytesPipe { + bp := &BytesPipe{} + bp.buf = append(bp.buf, getBuffer(minCap)) + bp.wait = sync.NewCond(&bp.mu) + return bp +} + +// Write writes p to BytesPipe. +// It can allocate new []byte slices in a process of writing. +func (bp *BytesPipe) Write(p []byte) (int, error) { + bp.mu.Lock() + + written := 0 +loop0: + for { + if bp.closeErr != nil { + bp.mu.Unlock() + return written, ErrClosed + } + + if len(bp.buf) == 0 { + bp.buf = append(bp.buf, getBuffer(64)) + } + // get the last buffer + b := bp.buf[len(bp.buf)-1] + + n, err := b.Write(p) + written += n + bp.bufLen += n + + // errBufferFull is an error we expect to get if the buffer is full + if err != nil && err != errBufferFull { + bp.wait.Broadcast() + bp.mu.Unlock() + return written, err + } + + // if there was enough room to write all then break + if len(p) == n { + break + } + + // more data: write to the next slice + p = p[n:] + + // make sure the buffer doesn't grow too big from this write + for bp.bufLen >= blockThreshold { + bp.wait.Wait() + if bp.closeErr != nil { + continue loop0 + } + } + + // add new byte slice to the buffers slice and continue writing + nextCap := b.Cap() * 2 + if nextCap > maxCap { + nextCap = maxCap + } + bp.buf = append(bp.buf, getBuffer(nextCap)) + } + bp.wait.Broadcast() + bp.mu.Unlock() + return written, nil +} + +// CloseWithError causes further reads from a BytesPipe to return immediately. +func (bp *BytesPipe) CloseWithError(err error) error { + bp.mu.Lock() + if err != nil { + bp.closeErr = err + } else { + bp.closeErr = io.EOF + } + bp.wait.Broadcast() + bp.mu.Unlock() + return nil +} + +// Close causes further reads from a BytesPipe to return immediately. +func (bp *BytesPipe) Close() error { + return bp.CloseWithError(nil) +} + +// Read reads bytes from BytesPipe. +// Data could be read only once. +func (bp *BytesPipe) Read(p []byte) (n int, err error) { + bp.mu.Lock() + if bp.bufLen == 0 { + if bp.closeErr != nil { + bp.mu.Unlock() + return 0, bp.closeErr + } + bp.wait.Wait() + if bp.bufLen == 0 && bp.closeErr != nil { + err := bp.closeErr + bp.mu.Unlock() + return 0, err + } + } + + for bp.bufLen > 0 { + b := bp.buf[0] + read, _ := b.Read(p) // ignore error since fixedBuffer doesn't really return an error + n += read + bp.bufLen -= read + + if b.Len() == 0 { + // it's empty so return it to the pool and move to the next one + returnBuffer(b) + bp.buf[0] = nil + bp.buf = bp.buf[1:] + } + + if len(p) == read { + break + } + + p = p[read:] + } + + bp.wait.Broadcast() + bp.mu.Unlock() + return +} + +func returnBuffer(b *fixedBuffer) { + b.Reset() + bufPoolsLock.Lock() + pool := bufPools[b.Cap()] + bufPoolsLock.Unlock() + if pool != nil { + pool.Put(b) + } +} + +func getBuffer(size int) *fixedBuffer { + bufPoolsLock.Lock() + pool, ok := bufPools[size] + if !ok { + pool = &sync.Pool{New: func() interface{} { return &fixedBuffer{buf: make([]byte, 0, size)} }} + bufPools[size] = pool + } + bufPoolsLock.Unlock() + return pool.Get().(*fixedBuffer) +} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go b/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go new file mode 100644 index 000000000..534d66ac2 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go @@ -0,0 +1,162 @@ +package ioutils // import "github.com/docker/docker/pkg/ioutils" + +import ( + "io" + "io/ioutil" + "os" + "path/filepath" +) + +// NewAtomicFileWriter returns WriteCloser so that writing to it writes to a +// temporary file and closing it atomically changes the temporary file to +// destination path. Writing and closing concurrently is not allowed. +func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, error) { + f, err := ioutil.TempFile(filepath.Dir(filename), ".tmp-"+filepath.Base(filename)) + if err != nil { + return nil, err + } + + abspath, err := filepath.Abs(filename) + if err != nil { + return nil, err + } + return &atomicFileWriter{ + f: f, + fn: abspath, + perm: perm, + }, nil +} + +// AtomicWriteFile atomically writes data to a file named by filename. +func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error { + f, err := NewAtomicFileWriter(filename, perm) + if err != nil { + return err + } + n, err := f.Write(data) + if err == nil && n < len(data) { + err = io.ErrShortWrite + f.(*atomicFileWriter).writeErr = err + } + if err1 := f.Close(); err == nil { + err = err1 + } + return err +} + +type atomicFileWriter struct { + f *os.File + fn string + writeErr error + perm os.FileMode +} + +func (w *atomicFileWriter) Write(dt []byte) (int, error) { + n, err := w.f.Write(dt) + if err != nil { + w.writeErr = err + } + return n, err +} + +func (w *atomicFileWriter) Close() (retErr error) { + defer func() { + if retErr != nil || w.writeErr != nil { + os.Remove(w.f.Name()) + } + }() + if err := w.f.Sync(); err != nil { + w.f.Close() + return err + } + if err := w.f.Close(); err != nil { + return err + } + if err := os.Chmod(w.f.Name(), w.perm); err != nil { + return err + } + if w.writeErr == nil { + return os.Rename(w.f.Name(), w.fn) + } + return nil +} + +// AtomicWriteSet is used to atomically write a set +// of files and ensure they are visible at the same time. +// Must be committed to a new directory. +type AtomicWriteSet struct { + root string +} + +// NewAtomicWriteSet creates a new atomic write set to +// atomically create a set of files. The given directory +// is used as the base directory for storing files before +// commit. If no temporary directory is given the system +// default is used. +func NewAtomicWriteSet(tmpDir string) (*AtomicWriteSet, error) { + td, err := ioutil.TempDir(tmpDir, "write-set-") + if err != nil { + return nil, err + } + + return &AtomicWriteSet{ + root: td, + }, nil +} + +// WriteFile writes a file to the set, guaranteeing the file +// has been synced. +func (ws *AtomicWriteSet) WriteFile(filename string, data []byte, perm os.FileMode) error { + f, err := ws.FileWriter(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + if err != nil { + return err + } + n, err := f.Write(data) + if err == nil && n < len(data) { + err = io.ErrShortWrite + } + if err1 := f.Close(); err == nil { + err = err1 + } + return err +} + +type syncFileCloser struct { + *os.File +} + +func (w syncFileCloser) Close() error { + err := w.File.Sync() + if err1 := w.File.Close(); err == nil { + err = err1 + } + return err +} + +// FileWriter opens a file writer inside the set. The file +// should be synced and closed before calling commit. +func (ws *AtomicWriteSet) FileWriter(name string, flag int, perm os.FileMode) (io.WriteCloser, error) { + f, err := os.OpenFile(filepath.Join(ws.root, name), flag, perm) + if err != nil { + return nil, err + } + return syncFileCloser{f}, nil +} + +// Cancel cancels the set and removes all temporary data +// created in the set. +func (ws *AtomicWriteSet) Cancel() error { + return os.RemoveAll(ws.root) +} + +// Commit moves all created files to the target directory. The +// target directory must not exist and the parent of the target +// directory must exist. +func (ws *AtomicWriteSet) Commit(target string) error { + return os.Rename(ws.root, target) +} + +// String returns the location the set is writing to. +func (ws *AtomicWriteSet) String() string { + return ws.root +} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/readers.go b/vendor/github.com/docker/docker/pkg/ioutils/readers.go new file mode 100644 index 000000000..1f657bd3d --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/ioutils/readers.go @@ -0,0 +1,157 @@ +package ioutils // import "github.com/docker/docker/pkg/ioutils" + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "io" +) + +// ReadCloserWrapper wraps an io.Reader, and implements an io.ReadCloser +// It calls the given callback function when closed. It should be constructed +// with NewReadCloserWrapper +type ReadCloserWrapper struct { + io.Reader + closer func() error +} + +// Close calls back the passed closer function +func (r *ReadCloserWrapper) Close() error { + return r.closer() +} + +// NewReadCloserWrapper returns a new io.ReadCloser. +func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser { + return &ReadCloserWrapper{ + Reader: r, + closer: closer, + } +} + +type readerErrWrapper struct { + reader io.Reader + closer func() +} + +func (r *readerErrWrapper) Read(p []byte) (int, error) { + n, err := r.reader.Read(p) + if err != nil { + r.closer() + } + return n, err +} + +// NewReaderErrWrapper returns a new io.Reader. +func NewReaderErrWrapper(r io.Reader, closer func()) io.Reader { + return &readerErrWrapper{ + reader: r, + closer: closer, + } +} + +// HashData returns the sha256 sum of src. +func HashData(src io.Reader) (string, error) { + h := sha256.New() + if _, err := io.Copy(h, src); err != nil { + return "", err + } + return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil +} + +// OnEOFReader wraps an io.ReadCloser and a function +// the function will run at the end of file or close the file. +type OnEOFReader struct { + Rc io.ReadCloser + Fn func() +} + +func (r *OnEOFReader) Read(p []byte) (n int, err error) { + n, err = r.Rc.Read(p) + if err == io.EOF { + r.runFunc() + } + return +} + +// Close closes the file and run the function. +func (r *OnEOFReader) Close() error { + err := r.Rc.Close() + r.runFunc() + return err +} + +func (r *OnEOFReader) runFunc() { + if fn := r.Fn; fn != nil { + fn() + r.Fn = nil + } +} + +// cancelReadCloser wraps an io.ReadCloser with a context for cancelling read +// operations. +type cancelReadCloser struct { + cancel func() + pR *io.PipeReader // Stream to read from + pW *io.PipeWriter +} + +// NewCancelReadCloser creates a wrapper that closes the ReadCloser when the +// context is cancelled. The returned io.ReadCloser must be closed when it is +// no longer needed. +func NewCancelReadCloser(ctx context.Context, in io.ReadCloser) io.ReadCloser { + pR, pW := io.Pipe() + + // Create a context used to signal when the pipe is closed + doneCtx, cancel := context.WithCancel(context.Background()) + + p := &cancelReadCloser{ + cancel: cancel, + pR: pR, + pW: pW, + } + + go func() { + _, err := io.Copy(pW, in) + select { + case <-ctx.Done(): + // If the context was closed, p.closeWithError + // was already called. Calling it again would + // change the error that Read returns. + default: + p.closeWithError(err) + } + in.Close() + }() + go func() { + for { + select { + case <-ctx.Done(): + p.closeWithError(ctx.Err()) + case <-doneCtx.Done(): + return + } + } + }() + + return p +} + +// Read wraps the Read method of the pipe that provides data from the wrapped +// ReadCloser. +func (p *cancelReadCloser) Read(buf []byte) (n int, err error) { + return p.pR.Read(buf) +} + +// closeWithError closes the wrapper and its underlying reader. It will +// cause future calls to Read to return err. +func (p *cancelReadCloser) closeWithError(err error) { + p.pW.CloseWithError(err) + p.cancel() +} + +// Close closes the wrapper its underlying reader. It will cause +// future calls to Read to return io.EOF. +func (p *cancelReadCloser) Close() error { + p.closeWithError(io.EOF) + return nil +} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go b/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go new file mode 100644 index 000000000..dc894f913 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go @@ -0,0 +1,10 @@ +// +build !windows + +package ioutils // import "github.com/docker/docker/pkg/ioutils" + +import "io/ioutil" + +// TempDir on Unix systems is equivalent to ioutil.TempDir. +func TempDir(dir, prefix string) (string, error) { + return ioutil.TempDir(dir, prefix) +} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go b/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go new file mode 100644 index 000000000..ecaba2e36 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go @@ -0,0 +1,16 @@ +package ioutils // import "github.com/docker/docker/pkg/ioutils" + +import ( + "io/ioutil" + + "github.com/docker/docker/pkg/longpath" +) + +// TempDir is the equivalent of ioutil.TempDir, except that the result is in Windows longpath format. +func TempDir(dir, prefix string) (string, error) { + tempDir, err := ioutil.TempDir(dir, prefix) + if err != nil { + return "", err + } + return longpath.AddPrefix(tempDir), nil +} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go b/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go new file mode 100644 index 000000000..91b8d1826 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go @@ -0,0 +1,92 @@ +package ioutils // import "github.com/docker/docker/pkg/ioutils" + +import ( + "io" + "sync" +) + +// WriteFlusher wraps the Write and Flush operation ensuring that every write +// is a flush. In addition, the Close method can be called to intercept +// Read/Write calls if the targets lifecycle has already ended. +type WriteFlusher struct { + w io.Writer + flusher flusher + flushed chan struct{} + flushedOnce sync.Once + closed chan struct{} + closeLock sync.Mutex +} + +type flusher interface { + Flush() +} + +var errWriteFlusherClosed = io.EOF + +func (wf *WriteFlusher) Write(b []byte) (n int, err error) { + select { + case <-wf.closed: + return 0, errWriteFlusherClosed + default: + } + + n, err = wf.w.Write(b) + wf.Flush() // every write is a flush. + return n, err +} + +// Flush the stream immediately. +func (wf *WriteFlusher) Flush() { + select { + case <-wf.closed: + return + default: + } + + wf.flushedOnce.Do(func() { + close(wf.flushed) + }) + wf.flusher.Flush() +} + +// Flushed returns the state of flushed. +// If it's flushed, return true, or else it return false. +func (wf *WriteFlusher) Flushed() bool { + // BUG(stevvooe): Remove this method. Its use is inherently racy. Seems to + // be used to detect whether or a response code has been issued or not. + // Another hook should be used instead. + var flushed bool + select { + case <-wf.flushed: + flushed = true + default: + } + return flushed +} + +// Close closes the write flusher, disallowing any further writes to the +// target. After the flusher is closed, all calls to write or flush will +// result in an error. +func (wf *WriteFlusher) Close() error { + wf.closeLock.Lock() + defer wf.closeLock.Unlock() + + select { + case <-wf.closed: + return errWriteFlusherClosed + default: + close(wf.closed) + } + return nil +} + +// NewWriteFlusher returns a new WriteFlusher. +func NewWriteFlusher(w io.Writer) *WriteFlusher { + var fl flusher + if f, ok := w.(flusher); ok { + fl = f + } else { + fl = &NopFlusher{} + } + return &WriteFlusher{w: w, flusher: fl, closed: make(chan struct{}), flushed: make(chan struct{})} +} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/writers.go b/vendor/github.com/docker/docker/pkg/ioutils/writers.go new file mode 100644 index 000000000..61c679497 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/ioutils/writers.go @@ -0,0 +1,66 @@ +package ioutils // import "github.com/docker/docker/pkg/ioutils" + +import "io" + +// NopWriter represents a type which write operation is nop. +type NopWriter struct{} + +func (*NopWriter) Write(buf []byte) (int, error) { + return len(buf), nil +} + +type nopWriteCloser struct { + io.Writer +} + +func (w *nopWriteCloser) Close() error { return nil } + +// NopWriteCloser returns a nopWriteCloser. +func NopWriteCloser(w io.Writer) io.WriteCloser { + return &nopWriteCloser{w} +} + +// NopFlusher represents a type which flush operation is nop. +type NopFlusher struct{} + +// Flush is a nop operation. +func (f *NopFlusher) Flush() {} + +type writeCloserWrapper struct { + io.Writer + closer func() error +} + +func (r *writeCloserWrapper) Close() error { + return r.closer() +} + +// NewWriteCloserWrapper returns a new io.WriteCloser. +func NewWriteCloserWrapper(r io.Writer, closer func() error) io.WriteCloser { + return &writeCloserWrapper{ + Writer: r, + closer: closer, + } +} + +// WriteCounter wraps a concrete io.Writer and hold a count of the number +// of bytes written to the writer during a "session". +// This can be convenient when write return is masked +// (e.g., json.Encoder.Encode()) +type WriteCounter struct { + Count int64 + Writer io.Writer +} + +// NewWriteCounter returns a new WriteCounter. +func NewWriteCounter(w io.Writer) *WriteCounter { + return &WriteCounter{ + Writer: w, + } +} + +func (wc *WriteCounter) Write(p []byte) (count int, err error) { + count, err = wc.Writer.Write(p) + wc.Count += int64(count) + return +} diff --git a/vendor/github.com/docker/docker/pkg/longpath/longpath.go b/vendor/github.com/docker/docker/pkg/longpath/longpath.go new file mode 100644 index 000000000..4177affba --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/longpath/longpath.go @@ -0,0 +1,26 @@ +// longpath introduces some constants and helper functions for handling long paths +// in Windows, which are expected to be prepended with `\\?\` and followed by either +// a drive letter, a UNC server\share, or a volume identifier. + +package longpath // import "github.com/docker/docker/pkg/longpath" + +import ( + "strings" +) + +// Prefix is the longpath prefix for Windows file paths. +const Prefix = `\\?\` + +// AddPrefix will add the Windows long path prefix to the path provided if +// it does not already have it. +func AddPrefix(path string) string { + if !strings.HasPrefix(path, Prefix) { + if strings.HasPrefix(path, `\\`) { + // This is a UNC path, so we need to add 'UNC' to the path as well. + path = Prefix + `UNC` + path[1:] + } else { + path = Prefix + path + } + } + return path +} diff --git a/vendor/github.com/docker/docker/pkg/mount/flags.go b/vendor/github.com/docker/docker/pkg/mount/flags.go new file mode 100644 index 000000000..272363b68 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/flags.go @@ -0,0 +1,149 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +import ( + "fmt" + "strings" +) + +var flags = map[string]struct { + clear bool + flag int +}{ + "defaults": {false, 0}, + "ro": {false, RDONLY}, + "rw": {true, RDONLY}, + "suid": {true, NOSUID}, + "nosuid": {false, NOSUID}, + "dev": {true, NODEV}, + "nodev": {false, NODEV}, + "exec": {true, NOEXEC}, + "noexec": {false, NOEXEC}, + "sync": {false, SYNCHRONOUS}, + "async": {true, SYNCHRONOUS}, + "dirsync": {false, DIRSYNC}, + "remount": {false, REMOUNT}, + "mand": {false, MANDLOCK}, + "nomand": {true, MANDLOCK}, + "atime": {true, NOATIME}, + "noatime": {false, NOATIME}, + "diratime": {true, NODIRATIME}, + "nodiratime": {false, NODIRATIME}, + "bind": {false, BIND}, + "rbind": {false, RBIND}, + "unbindable": {false, UNBINDABLE}, + "runbindable": {false, RUNBINDABLE}, + "private": {false, PRIVATE}, + "rprivate": {false, RPRIVATE}, + "shared": {false, SHARED}, + "rshared": {false, RSHARED}, + "slave": {false, SLAVE}, + "rslave": {false, RSLAVE}, + "relatime": {false, RELATIME}, + "norelatime": {true, RELATIME}, + "strictatime": {false, STRICTATIME}, + "nostrictatime": {true, STRICTATIME}, +} + +var validFlags = map[string]bool{ + "": true, + "size": true, + "mode": true, + "uid": true, + "gid": true, + "nr_inodes": true, + "nr_blocks": true, + "mpol": true, +} + +var propagationFlags = map[string]bool{ + "bind": true, + "rbind": true, + "unbindable": true, + "runbindable": true, + "private": true, + "rprivate": true, + "shared": true, + "rshared": true, + "slave": true, + "rslave": true, +} + +// MergeTmpfsOptions merge mount options to make sure there is no duplicate. +func MergeTmpfsOptions(options []string) ([]string, error) { + // We use collisions maps to remove duplicates. + // For flag, the key is the flag value (the key for propagation flag is -1) + // For data=value, the key is the data + flagCollisions := map[int]bool{} + dataCollisions := map[string]bool{} + + var newOptions []string + // We process in reverse order + for i := len(options) - 1; i >= 0; i-- { + option := options[i] + if option == "defaults" { + continue + } + if f, ok := flags[option]; ok && f.flag != 0 { + // There is only one propagation mode + key := f.flag + if propagationFlags[option] { + key = -1 + } + // Check to see if there is collision for flag + if !flagCollisions[key] { + // We prepend the option and add to collision map + newOptions = append([]string{option}, newOptions...) + flagCollisions[key] = true + } + continue + } + opt := strings.SplitN(option, "=", 2) + if len(opt) != 2 || !validFlags[opt[0]] { + return nil, fmt.Errorf("Invalid tmpfs option %q", opt) + } + if !dataCollisions[opt[0]] { + // We prepend the option and add to collision map + newOptions = append([]string{option}, newOptions...) + dataCollisions[opt[0]] = true + } + } + + return newOptions, nil +} + +// Parse fstab type mount options into mount() flags +// and device specific data +func parseOptions(options string) (int, string) { + var ( + flag int + data []string + ) + + for _, o := range strings.Split(options, ",") { + // If the option does not exist in the flags table or the flag + // is not supported on the platform, + // then it is a data value for a specific fs type + if f, exists := flags[o]; exists && f.flag != 0 { + if f.clear { + flag &= ^f.flag + } else { + flag |= f.flag + } + } else { + data = append(data, o) + } + } + return flag, strings.Join(data, ",") +} + +// ParseTmpfsOptions parse fstab type mount options into flags and data +func ParseTmpfsOptions(options string) (int, string, error) { + flags, data := parseOptions(options) + for _, o := range strings.Split(data, ",") { + opt := strings.SplitN(o, "=", 2) + if !validFlags[opt[0]] { + return 0, "", fmt.Errorf("Invalid tmpfs option %q", opt) + } + } + return flags, data, nil +} diff --git a/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go b/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go new file mode 100644 index 000000000..ef35ef905 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go @@ -0,0 +1,49 @@ +// +build freebsd,cgo + +package mount // import "github.com/docker/docker/pkg/mount" + +/* +#include +*/ +import "C" + +const ( + // RDONLY will mount the filesystem as read-only. + RDONLY = C.MNT_RDONLY + + // NOSUID will not allow set-user-identifier or set-group-identifier bits to + // take effect. + NOSUID = C.MNT_NOSUID + + // NOEXEC will not allow execution of any binaries on the mounted file system. + NOEXEC = C.MNT_NOEXEC + + // SYNCHRONOUS will allow any I/O to the file system to be done synchronously. + SYNCHRONOUS = C.MNT_SYNCHRONOUS + + // NOATIME will not update the file access time when reading from a file. + NOATIME = C.MNT_NOATIME +) + +// These flags are unsupported. +const ( + BIND = 0 + DIRSYNC = 0 + MANDLOCK = 0 + NODEV = 0 + NODIRATIME = 0 + UNBINDABLE = 0 + RUNBINDABLE = 0 + PRIVATE = 0 + RPRIVATE = 0 + SHARED = 0 + RSHARED = 0 + SLAVE = 0 + RSLAVE = 0 + RBIND = 0 + RELATIVE = 0 + RELATIME = 0 + REMOUNT = 0 + STRICTATIME = 0 + mntDetach = 0 +) diff --git a/vendor/github.com/docker/docker/pkg/mount/flags_linux.go b/vendor/github.com/docker/docker/pkg/mount/flags_linux.go new file mode 100644 index 000000000..a1b199a31 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/flags_linux.go @@ -0,0 +1,87 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +import ( + "golang.org/x/sys/unix" +) + +const ( + // RDONLY will mount the file system read-only. + RDONLY = unix.MS_RDONLY + + // NOSUID will not allow set-user-identifier or set-group-identifier bits to + // take effect. + NOSUID = unix.MS_NOSUID + + // NODEV will not interpret character or block special devices on the file + // system. + NODEV = unix.MS_NODEV + + // NOEXEC will not allow execution of any binaries on the mounted file system. + NOEXEC = unix.MS_NOEXEC + + // SYNCHRONOUS will allow I/O to the file system to be done synchronously. + SYNCHRONOUS = unix.MS_SYNCHRONOUS + + // DIRSYNC will force all directory updates within the file system to be done + // synchronously. This affects the following system calls: create, link, + // unlink, symlink, mkdir, rmdir, mknod and rename. + DIRSYNC = unix.MS_DIRSYNC + + // REMOUNT will attempt to remount an already-mounted file system. This is + // commonly used to change the mount flags for a file system, especially to + // make a readonly file system writeable. It does not change device or mount + // point. + REMOUNT = unix.MS_REMOUNT + + // MANDLOCK will force mandatory locks on a filesystem. + MANDLOCK = unix.MS_MANDLOCK + + // NOATIME will not update the file access time when reading from a file. + NOATIME = unix.MS_NOATIME + + // NODIRATIME will not update the directory access time. + NODIRATIME = unix.MS_NODIRATIME + + // BIND remounts a subtree somewhere else. + BIND = unix.MS_BIND + + // RBIND remounts a subtree and all possible submounts somewhere else. + RBIND = unix.MS_BIND | unix.MS_REC + + // UNBINDABLE creates a mount which cannot be cloned through a bind operation. + UNBINDABLE = unix.MS_UNBINDABLE + + // RUNBINDABLE marks the entire mount tree as UNBINDABLE. + RUNBINDABLE = unix.MS_UNBINDABLE | unix.MS_REC + + // PRIVATE creates a mount which carries no propagation abilities. + PRIVATE = unix.MS_PRIVATE + + // RPRIVATE marks the entire mount tree as PRIVATE. + RPRIVATE = unix.MS_PRIVATE | unix.MS_REC + + // SLAVE creates a mount which receives propagation from its master, but not + // vice versa. + SLAVE = unix.MS_SLAVE + + // RSLAVE marks the entire mount tree as SLAVE. + RSLAVE = unix.MS_SLAVE | unix.MS_REC + + // SHARED creates a mount which provides the ability to create mirrors of + // that mount such that mounts and unmounts within any of the mirrors + // propagate to the other mirrors. + SHARED = unix.MS_SHARED + + // RSHARED marks the entire mount tree as SHARED. + RSHARED = unix.MS_SHARED | unix.MS_REC + + // RELATIME updates inode access times relative to modify or change time. + RELATIME = unix.MS_RELATIME + + // STRICTATIME allows to explicitly request full atime updates. This makes + // it possible for the kernel to default to relatime or noatime but still + // allow userspace to override it. + STRICTATIME = unix.MS_STRICTATIME + + mntDetach = unix.MNT_DETACH +) diff --git a/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go new file mode 100644 index 000000000..cc6c47590 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go @@ -0,0 +1,31 @@ +// +build !linux,!freebsd freebsd,!cgo + +package mount // import "github.com/docker/docker/pkg/mount" + +// These flags are unsupported. +const ( + BIND = 0 + DIRSYNC = 0 + MANDLOCK = 0 + NOATIME = 0 + NODEV = 0 + NODIRATIME = 0 + NOEXEC = 0 + NOSUID = 0 + UNBINDABLE = 0 + RUNBINDABLE = 0 + PRIVATE = 0 + RPRIVATE = 0 + SHARED = 0 + RSHARED = 0 + SLAVE = 0 + RSLAVE = 0 + RBIND = 0 + RELATIME = 0 + RELATIVE = 0 + REMOUNT = 0 + STRICTATIME = 0 + SYNCHRONOUS = 0 + RDONLY = 0 + mntDetach = 0 +) diff --git a/vendor/github.com/docker/docker/pkg/mount/mount.go b/vendor/github.com/docker/docker/pkg/mount/mount.go new file mode 100644 index 000000000..874aff654 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/mount.go @@ -0,0 +1,141 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +import ( + "sort" + "strings" + "syscall" + + "github.com/sirupsen/logrus" +) + +// FilterFunc is a type defining a callback function +// to filter out unwanted entries. It takes a pointer +// to an Info struct (not fully populated, currently +// only Mountpoint is filled in), and returns two booleans: +// - skip: true if the entry should be skipped +// - stop: true if parsing should be stopped after the entry +type FilterFunc func(*Info) (skip, stop bool) + +// PrefixFilter discards all entries whose mount points +// do not start with a prefix specified +func PrefixFilter(prefix string) FilterFunc { + return func(m *Info) (bool, bool) { + skip := !strings.HasPrefix(m.Mountpoint, prefix) + return skip, false + } +} + +// SingleEntryFilter looks for a specific entry +func SingleEntryFilter(mp string) FilterFunc { + return func(m *Info) (bool, bool) { + if m.Mountpoint == mp { + return false, true // don't skip, stop now + } + return true, false // skip, keep going + } +} + +// ParentsFilter returns all entries whose mount points +// can be parents of a path specified, discarding others. +// For example, given `/var/lib/docker/something`, entries +// like `/var/lib/docker`, `/var` and `/` are returned. +func ParentsFilter(path string) FilterFunc { + return func(m *Info) (bool, bool) { + skip := !strings.HasPrefix(path, m.Mountpoint) + return skip, false + } +} + +// GetMounts retrieves a list of mounts for the current running process, +// with an optional filter applied (use nil for no filter). +func GetMounts(f FilterFunc) ([]*Info, error) { + return parseMountTable(f) +} + +// Mounted determines if a specified mountpoint has been mounted. +// On Linux it looks at /proc/self/mountinfo. +func Mounted(mountpoint string) (bool, error) { + entries, err := GetMounts(SingleEntryFilter(mountpoint)) + if err != nil { + return false, err + } + + return len(entries) > 0, nil +} + +// Mount will mount filesystem according to the specified configuration, on the +// condition that the target path is *not* already mounted. Options must be +// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See +// flags.go for supported option flags. +func Mount(device, target, mType, options string) error { + flag, _ := parseOptions(options) + if flag&REMOUNT != REMOUNT { + if mounted, err := Mounted(target); err != nil || mounted { + return err + } + } + return ForceMount(device, target, mType, options) +} + +// ForceMount will mount a filesystem according to the specified configuration, +// *regardless* if the target path is not already mounted. Options must be +// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See +// flags.go for supported option flags. +func ForceMount(device, target, mType, options string) error { + flag, data := parseOptions(options) + return mount(device, target, mType, uintptr(flag), data) +} + +// Unmount lazily unmounts a filesystem on supported platforms, otherwise +// does a normal unmount. +func Unmount(target string) error { + err := unmount(target, mntDetach) + if err == syscall.EINVAL { + // ignore "not mounted" error + err = nil + } + return err +} + +// RecursiveUnmount unmounts the target and all mounts underneath, starting with +// the deepsest mount first. +func RecursiveUnmount(target string) error { + mounts, err := parseMountTable(PrefixFilter(target)) + if err != nil { + return err + } + + // Make the deepest mount be first + sort.Slice(mounts, func(i, j int) bool { + return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint) + }) + + for i, m := range mounts { + logrus.Debugf("Trying to unmount %s", m.Mountpoint) + err = unmount(m.Mountpoint, mntDetach) + if err != nil { + // If the error is EINVAL either this whole package is wrong (invalid flags passed to unmount(2)) or this is + // not a mountpoint (which is ok in this case). + // Meanwhile calling `Mounted()` is very expensive. + // + // We've purposefully used `syscall.EINVAL` here instead of `unix.EINVAL` to avoid platform branching + // Since `EINVAL` is defined for both Windows and Linux in the `syscall` package (and other platforms), + // this is nicer than defining a custom value that we can refer to in each platform file. + if err == syscall.EINVAL { + continue + } + if i == len(mounts)-1 { + if mounted, e := Mounted(m.Mountpoint); e != nil || mounted { + return err + } + continue + } + // This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem + logrus.WithError(err).Warnf("Failed to unmount submount %s", m.Mountpoint) + continue + } + + logrus.Debugf("Unmounted %s", m.Mountpoint) + } + return nil +} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go b/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go new file mode 100644 index 000000000..b6ab83a23 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go @@ -0,0 +1,60 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +/* +#include +#include +#include +#include +#include +#include +*/ +import "C" + +import ( + "fmt" + "strings" + "unsafe" + + "golang.org/x/sys/unix" +) + +func allocateIOVecs(options []string) []C.struct_iovec { + out := make([]C.struct_iovec, len(options)) + for i, option := range options { + out[i].iov_base = unsafe.Pointer(C.CString(option)) + out[i].iov_len = C.size_t(len(option) + 1) + } + return out +} + +func mount(device, target, mType string, flag uintptr, data string) error { + isNullFS := false + + xs := strings.Split(data, ",") + for _, x := range xs { + if x == "bind" { + isNullFS = true + } + } + + options := []string{"fspath", target} + if isNullFS { + options = append(options, "fstype", "nullfs", "target", device) + } else { + options = append(options, "fstype", mType, "from", device) + } + rawOptions := allocateIOVecs(options) + for _, rawOption := range rawOptions { + defer C.free(rawOption.iov_base) + } + + if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 { + reason := C.GoString(C.strerror(*C.__error())) + return fmt.Errorf("Failed to call nmount: %s", reason) + } + return nil +} + +func unmount(target string, flag int) error { + return unix.Unmount(target, flag) +} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go b/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go new file mode 100644 index 000000000..631daf10a --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go @@ -0,0 +1,57 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +import ( + "golang.org/x/sys/unix" +) + +const ( + // ptypes is the set propagation types. + ptypes = unix.MS_SHARED | unix.MS_PRIVATE | unix.MS_SLAVE | unix.MS_UNBINDABLE + + // pflags is the full set valid flags for a change propagation call. + pflags = ptypes | unix.MS_REC | unix.MS_SILENT + + // broflags is the combination of bind and read only + broflags = unix.MS_BIND | unix.MS_RDONLY +) + +// isremount returns true if either device name or flags identify a remount request, false otherwise. +func isremount(device string, flags uintptr) bool { + switch { + // We treat device "" and "none" as a remount request to provide compatibility with + // requests that don't explicitly set MS_REMOUNT such as those manipulating bind mounts. + case flags&unix.MS_REMOUNT != 0, device == "", device == "none": + return true + default: + return false + } +} + +func mount(device, target, mType string, flags uintptr, data string) error { + oflags := flags &^ ptypes + if !isremount(device, flags) || data != "" { + // Initial call applying all non-propagation flags for mount + // or remount with changed data + if err := unix.Mount(device, target, mType, oflags, data); err != nil { + return err + } + } + + if flags&ptypes != 0 { + // Change the propagation type. + if err := unix.Mount("", target, "", flags&pflags, ""); err != nil { + return err + } + } + + if oflags&broflags == broflags { + // Remount the bind to apply read only. + return unix.Mount("", target, "", oflags|unix.MS_REMOUNT, "") + } + + return nil +} + +func unmount(target string, flag int) error { + return unix.Unmount(target, flag) +} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go new file mode 100644 index 000000000..1428dffa5 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go @@ -0,0 +1,11 @@ +// +build !linux,!freebsd freebsd,!cgo + +package mount // import "github.com/docker/docker/pkg/mount" + +func mount(device, target, mType string, flag uintptr, data string) error { + panic("Not implemented") +} + +func unmount(target string, flag int) error { + panic("Not implemented") +} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo.go new file mode 100644 index 000000000..ecd03fc02 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/mountinfo.go @@ -0,0 +1,40 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +// Info reveals information about a particular mounted filesystem. This +// struct is populated from the content in the /proc//mountinfo file. +type Info struct { + // ID is a unique identifier of the mount (may be reused after umount). + ID int + + // Parent indicates the ID of the mount parent (or of self for the top of the + // mount tree). + Parent int + + // Major indicates one half of the device ID which identifies the device class. + Major int + + // Minor indicates one half of the device ID which identifies a specific + // instance of device. + Minor int + + // Root of the mount within the filesystem. + Root string + + // Mountpoint indicates the mount point relative to the process's root. + Mountpoint string + + // Opts represents mount-specific options. + Opts string + + // Optional represents optional fields. + Optional string + + // Fstype indicates the type of filesystem, such as EXT3. + Fstype string + + // Source indicates filesystem specific information or "none". + Source string + + // VfsOpts represents per super block options. + VfsOpts string +} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go new file mode 100644 index 000000000..36c89dc1a --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go @@ -0,0 +1,55 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +/* +#include +#include +#include +*/ +import "C" + +import ( + "fmt" + "reflect" + "unsafe" +) + +// Parse /proc/self/mountinfo because comparing Dev and ino does not work from +// bind mounts. +func parseMountTable(filter FilterFunc) ([]*Info, error) { + var rawEntries *C.struct_statfs + + count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT)) + if count == 0 { + return nil, fmt.Errorf("Failed to call getmntinfo") + } + + var entries []C.struct_statfs + header := (*reflect.SliceHeader)(unsafe.Pointer(&entries)) + header.Cap = count + header.Len = count + header.Data = uintptr(unsafe.Pointer(rawEntries)) + + var out []*Info + for _, entry := range entries { + var mountinfo Info + var skip, stop bool + mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0]) + + if filter != nil { + // filter out entries we're not interested in + skip, stop = filter(p) + if skip { + continue + } + } + + mountinfo.Source = C.GoString(&entry.f_mntfromname[0]) + mountinfo.Fstype = C.GoString(&entry.f_fstypename[0]) + + out = append(out, &mountinfo) + if stop { + break + } + } + return out, nil +} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go new file mode 100644 index 000000000..c1dba01fc --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go @@ -0,0 +1,132 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +import ( + "bufio" + "fmt" + "io" + "os" + "strconv" + "strings" +) + +func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) { + s := bufio.NewScanner(r) + out := []*Info{} + for s.Scan() { + if err := s.Err(); err != nil { + return nil, err + } + /* + 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue + (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) + + (1) mount ID: unique identifier of the mount (may be reused after umount) + (2) parent ID: ID of parent (or of self for the top of the mount tree) + (3) major:minor: value of st_dev for files on filesystem + (4) root: root of the mount within the filesystem + (5) mount point: mount point relative to the process's root + (6) mount options: per mount options + (7) optional fields: zero or more fields of the form "tag[:value]" + (8) separator: marks the end of the optional fields + (9) filesystem type: name of filesystem of the form "type[.subtype]" + (10) mount source: filesystem specific information or "none" + (11) super options: per super block options + */ + + text := s.Text() + fields := strings.Split(text, " ") + numFields := len(fields) + if numFields < 10 { + // should be at least 10 fields + return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields) + } + + p := &Info{} + // ignore any numbers parsing errors, as there should not be any + p.ID, _ = strconv.Atoi(fields[0]) + p.Parent, _ = strconv.Atoi(fields[1]) + mm := strings.Split(fields[2], ":") + if len(mm) != 2 { + return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm) + } + p.Major, _ = strconv.Atoi(mm[0]) + p.Minor, _ = strconv.Atoi(mm[1]) + + p.Root = fields[3] + p.Mountpoint = fields[4] + p.Opts = fields[5] + + var skip, stop bool + if filter != nil { + // filter out entries we're not interested in + skip, stop = filter(p) + if skip { + continue + } + } + + // one or more optional fields, when a separator (-) + i := 6 + for ; i < numFields && fields[i] != "-"; i++ { + switch i { + case 6: + p.Optional = fields[6] + default: + /* NOTE there might be more optional fields before the such as + fields[7]...fields[N] (where N < sepIndex), although + as of Linux kernel 4.15 the only known ones are + mount propagation flags in fields[6]. The correct + behavior is to ignore any unknown optional fields. + */ + break + } + } + if i == numFields { + return nil, fmt.Errorf("Parsing '%s' failed: missing separator ('-')", text) + } + + // There should be 3 fields after the separator... + if i+4 > numFields { + return nil, fmt.Errorf("Parsing '%s' failed: not enough fields after a separator", text) + } + // ... but in Linux <= 3.9 mounting a cifs with spaces in a share name + // (like "//serv/My Documents") _may_ end up having a space in the last field + // of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs + // option unc= is ignored, so a space should not appear. In here we ignore + // those "extra" fields caused by extra spaces. + p.Fstype = fields[i+1] + p.Source = fields[i+2] + p.VfsOpts = fields[i+3] + + out = append(out, p) + if stop { + break + } + } + return out, nil +} + +// Parse /proc/self/mountinfo because comparing Dev and ino does not work from +// bind mounts +func parseMountTable(filter FilterFunc) ([]*Info, error) { + f, err := os.Open("/proc/self/mountinfo") + if err != nil { + return nil, err + } + defer f.Close() + + return parseInfoFile(f, filter) +} + +// PidMountInfo collects the mounts for a specific process ID. If the process +// ID is unknown, it is better to use `GetMounts` which will inspect +// "/proc/self/mountinfo" instead. +func PidMountInfo(pid int) ([]*Info, error) { + f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) + if err != nil { + return nil, err + } + defer f.Close() + + return parseInfoFile(f, nil) +} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go new file mode 100644 index 000000000..fd16d3ed6 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go @@ -0,0 +1,12 @@ +// +build !windows,!linux,!freebsd freebsd,!cgo + +package mount // import "github.com/docker/docker/pkg/mount" + +import ( + "fmt" + "runtime" +) + +func parseMountTable(f FilterFunc) ([]*Info, error) { + return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go new file mode 100644 index 000000000..27e0f6976 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go @@ -0,0 +1,6 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +func parseMountTable(f FilterFunc) ([]*Info, error) { + // Do NOT return an error! + return nil, nil +} diff --git a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go b/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go new file mode 100644 index 000000000..538f6637a --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go @@ -0,0 +1,67 @@ +package mount // import "github.com/docker/docker/pkg/mount" + +// MakeShared ensures a mounted filesystem has the SHARED mount option enabled. +// See the supported options in flags.go for further reference. +func MakeShared(mountPoint string) error { + return ensureMountedAs(mountPoint, "shared") +} + +// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. +// See the supported options in flags.go for further reference. +func MakeRShared(mountPoint string) error { + return ensureMountedAs(mountPoint, "rshared") +} + +// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. +// See the supported options in flags.go for further reference. +func MakePrivate(mountPoint string) error { + return ensureMountedAs(mountPoint, "private") +} + +// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option +// enabled. See the supported options in flags.go for further reference. +func MakeRPrivate(mountPoint string) error { + return ensureMountedAs(mountPoint, "rprivate") +} + +// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. +// See the supported options in flags.go for further reference. +func MakeSlave(mountPoint string) error { + return ensureMountedAs(mountPoint, "slave") +} + +// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. +// See the supported options in flags.go for further reference. +func MakeRSlave(mountPoint string) error { + return ensureMountedAs(mountPoint, "rslave") +} + +// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option +// enabled. See the supported options in flags.go for further reference. +func MakeUnbindable(mountPoint string) error { + return ensureMountedAs(mountPoint, "unbindable") +} + +// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount +// option enabled. See the supported options in flags.go for further reference. +func MakeRUnbindable(mountPoint string) error { + return ensureMountedAs(mountPoint, "runbindable") +} + +func ensureMountedAs(mountPoint, options string) error { + mounted, err := Mounted(mountPoint) + if err != nil { + return err + } + + if !mounted { + if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { + return err + } + } + if _, err = Mounted(mountPoint); err != nil { + return err + } + + return ForceMount("", mountPoint, "none", options) +} diff --git a/vendor/github.com/docker/docker/pkg/pools/pools.go b/vendor/github.com/docker/docker/pkg/pools/pools.go new file mode 100644 index 000000000..46339c282 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/pools/pools.go @@ -0,0 +1,137 @@ +// Package pools provides a collection of pools which provide various +// data types with buffers. These can be used to lower the number of +// memory allocations and reuse buffers. +// +// New pools should be added to this package to allow them to be +// shared across packages. +// +// Utility functions which operate on pools should be added to this +// package to allow them to be reused. +package pools // import "github.com/docker/docker/pkg/pools" + +import ( + "bufio" + "io" + "sync" + + "github.com/docker/docker/pkg/ioutils" +) + +const buffer32K = 32 * 1024 + +var ( + // BufioReader32KPool is a pool which returns bufio.Reader with a 32K buffer. + BufioReader32KPool = newBufioReaderPoolWithSize(buffer32K) + // BufioWriter32KPool is a pool which returns bufio.Writer with a 32K buffer. + BufioWriter32KPool = newBufioWriterPoolWithSize(buffer32K) + buffer32KPool = newBufferPoolWithSize(buffer32K) +) + +// BufioReaderPool is a bufio reader that uses sync.Pool. +type BufioReaderPool struct { + pool sync.Pool +} + +// newBufioReaderPoolWithSize is unexported because new pools should be +// added here to be shared where required. +func newBufioReaderPoolWithSize(size int) *BufioReaderPool { + return &BufioReaderPool{ + pool: sync.Pool{ + New: func() interface{} { return bufio.NewReaderSize(nil, size) }, + }, + } +} + +// Get returns a bufio.Reader which reads from r. The buffer size is that of the pool. +func (bufPool *BufioReaderPool) Get(r io.Reader) *bufio.Reader { + buf := bufPool.pool.Get().(*bufio.Reader) + buf.Reset(r) + return buf +} + +// Put puts the bufio.Reader back into the pool. +func (bufPool *BufioReaderPool) Put(b *bufio.Reader) { + b.Reset(nil) + bufPool.pool.Put(b) +} + +type bufferPool struct { + pool sync.Pool +} + +func newBufferPoolWithSize(size int) *bufferPool { + return &bufferPool{ + pool: sync.Pool{ + New: func() interface{} { return make([]byte, size) }, + }, + } +} + +func (bp *bufferPool) Get() []byte { + return bp.pool.Get().([]byte) +} + +func (bp *bufferPool) Put(b []byte) { + bp.pool.Put(b) +} + +// Copy is a convenience wrapper which uses a buffer to avoid allocation in io.Copy. +func Copy(dst io.Writer, src io.Reader) (written int64, err error) { + buf := buffer32KPool.Get() + written, err = io.CopyBuffer(dst, src, buf) + buffer32KPool.Put(buf) + return +} + +// NewReadCloserWrapper returns a wrapper which puts the bufio.Reader back +// into the pool and closes the reader if it's an io.ReadCloser. +func (bufPool *BufioReaderPool) NewReadCloserWrapper(buf *bufio.Reader, r io.Reader) io.ReadCloser { + return ioutils.NewReadCloserWrapper(r, func() error { + if readCloser, ok := r.(io.ReadCloser); ok { + readCloser.Close() + } + bufPool.Put(buf) + return nil + }) +} + +// BufioWriterPool is a bufio writer that uses sync.Pool. +type BufioWriterPool struct { + pool sync.Pool +} + +// newBufioWriterPoolWithSize is unexported because new pools should be +// added here to be shared where required. +func newBufioWriterPoolWithSize(size int) *BufioWriterPool { + return &BufioWriterPool{ + pool: sync.Pool{ + New: func() interface{} { return bufio.NewWriterSize(nil, size) }, + }, + } +} + +// Get returns a bufio.Writer which writes to w. The buffer size is that of the pool. +func (bufPool *BufioWriterPool) Get(w io.Writer) *bufio.Writer { + buf := bufPool.pool.Get().(*bufio.Writer) + buf.Reset(w) + return buf +} + +// Put puts the bufio.Writer back into the pool. +func (bufPool *BufioWriterPool) Put(b *bufio.Writer) { + b.Reset(nil) + bufPool.pool.Put(b) +} + +// NewWriteCloserWrapper returns a wrapper which puts the bufio.Writer back +// into the pool and closes the writer if it's an io.Writecloser. +func (bufPool *BufioWriterPool) NewWriteCloserWrapper(buf *bufio.Writer, w io.Writer) io.WriteCloser { + return ioutils.NewWriteCloserWrapper(w, func() error { + buf.Flush() + if writeCloser, ok := w.(io.WriteCloser); ok { + writeCloser.Close() + } + bufPool.Put(buf) + return nil + }) +} diff --git a/vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go b/vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go new file mode 100644 index 000000000..8f6e0a737 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go @@ -0,0 +1,190 @@ +package stdcopy // import "github.com/docker/docker/pkg/stdcopy" + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "sync" +) + +// StdType is the type of standard stream +// a writer can multiplex to. +type StdType byte + +const ( + // Stdin represents standard input stream type. + Stdin StdType = iota + // Stdout represents standard output stream type. + Stdout + // Stderr represents standard error steam type. + Stderr + // Systemerr represents errors originating from the system that make it + // into the multiplexed stream. + Systemerr + + stdWriterPrefixLen = 8 + stdWriterFdIndex = 0 + stdWriterSizeIndex = 4 + + startingBufLen = 32*1024 + stdWriterPrefixLen + 1 +) + +var bufPool = &sync.Pool{New: func() interface{} { return bytes.NewBuffer(nil) }} + +// stdWriter is wrapper of io.Writer with extra customized info. +type stdWriter struct { + io.Writer + prefix byte +} + +// Write sends the buffer to the underneath writer. +// It inserts the prefix header before the buffer, +// so stdcopy.StdCopy knows where to multiplex the output. +// It makes stdWriter to implement io.Writer. +func (w *stdWriter) Write(p []byte) (n int, err error) { + if w == nil || w.Writer == nil { + return 0, errors.New("Writer not instantiated") + } + if p == nil { + return 0, nil + } + + header := [stdWriterPrefixLen]byte{stdWriterFdIndex: w.prefix} + binary.BigEndian.PutUint32(header[stdWriterSizeIndex:], uint32(len(p))) + buf := bufPool.Get().(*bytes.Buffer) + buf.Write(header[:]) + buf.Write(p) + + n, err = w.Writer.Write(buf.Bytes()) + n -= stdWriterPrefixLen + if n < 0 { + n = 0 + } + + buf.Reset() + bufPool.Put(buf) + return +} + +// NewStdWriter instantiates a new Writer. +// Everything written to it will be encapsulated using a custom format, +// and written to the underlying `w` stream. +// This allows multiple write streams (e.g. stdout and stderr) to be muxed into a single connection. +// `t` indicates the id of the stream to encapsulate. +// It can be stdcopy.Stdin, stdcopy.Stdout, stdcopy.Stderr. +func NewStdWriter(w io.Writer, t StdType) io.Writer { + return &stdWriter{ + Writer: w, + prefix: byte(t), + } +} + +// StdCopy is a modified version of io.Copy. +// +// StdCopy will demultiplex `src`, assuming that it contains two streams, +// previously multiplexed together using a StdWriter instance. +// As it reads from `src`, StdCopy will write to `dstout` and `dsterr`. +// +// StdCopy will read until it hits EOF on `src`. It will then return a nil error. +// In other words: if `err` is non nil, it indicates a real underlying error. +// +// `written` will hold the total number of bytes written to `dstout` and `dsterr`. +func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) { + var ( + buf = make([]byte, startingBufLen) + bufLen = len(buf) + nr, nw int + er, ew error + out io.Writer + frameSize int + ) + + for { + // Make sure we have at least a full header + for nr < stdWriterPrefixLen { + var nr2 int + nr2, er = src.Read(buf[nr:]) + nr += nr2 + if er == io.EOF { + if nr < stdWriterPrefixLen { + return written, nil + } + break + } + if er != nil { + return 0, er + } + } + + stream := StdType(buf[stdWriterFdIndex]) + // Check the first byte to know where to write + switch stream { + case Stdin: + fallthrough + case Stdout: + // Write on stdout + out = dstout + case Stderr: + // Write on stderr + out = dsterr + case Systemerr: + // If we're on Systemerr, we won't write anywhere. + // NB: if this code changes later, make sure you don't try to write + // to outstream if Systemerr is the stream + out = nil + default: + return 0, fmt.Errorf("Unrecognized input header: %d", buf[stdWriterFdIndex]) + } + + // Retrieve the size of the frame + frameSize = int(binary.BigEndian.Uint32(buf[stdWriterSizeIndex : stdWriterSizeIndex+4])) + + // Check if the buffer is big enough to read the frame. + // Extend it if necessary. + if frameSize+stdWriterPrefixLen > bufLen { + buf = append(buf, make([]byte, frameSize+stdWriterPrefixLen-bufLen+1)...) + bufLen = len(buf) + } + + // While the amount of bytes read is less than the size of the frame + header, we keep reading + for nr < frameSize+stdWriterPrefixLen { + var nr2 int + nr2, er = src.Read(buf[nr:]) + nr += nr2 + if er == io.EOF { + if nr < frameSize+stdWriterPrefixLen { + return written, nil + } + break + } + if er != nil { + return 0, er + } + } + + // we might have an error from the source mixed up in our multiplexed + // stream. if we do, return it. + if stream == Systemerr { + return written, fmt.Errorf("error from daemon in stream: %s", string(buf[stdWriterPrefixLen:frameSize+stdWriterPrefixLen])) + } + + // Write the retrieved frame (without header) + nw, ew = out.Write(buf[stdWriterPrefixLen : frameSize+stdWriterPrefixLen]) + if ew != nil { + return 0, ew + } + + // If the frame has not been fully written: error + if nw != frameSize { + return 0, io.ErrShortWrite + } + written += int64(nw) + + // Move the rest of the buffer to the beginning + copy(buf, buf[frameSize+stdWriterPrefixLen:]) + // Move the index + nr -= frameSize + stdWriterPrefixLen + } +} diff --git a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE new file mode 100644 index 000000000..b9fbf3c98 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2014-2017 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD new file mode 100644 index 000000000..4c056c5ed --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD @@ -0,0 +1,27 @@ +Copyright (c) 2014-2017 The Docker & Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/docker/docker/pkg/system/chtimes.go b/vendor/github.com/docker/docker/pkg/system/chtimes.go new file mode 100644 index 000000000..c26a4e24b --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/chtimes.go @@ -0,0 +1,31 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "os" + "time" +) + +// Chtimes changes the access time and modified time of a file at the given path +func Chtimes(name string, atime time.Time, mtime time.Time) error { + unixMinTime := time.Unix(0, 0) + unixMaxTime := maxTime + + // If the modified time is prior to the Unix Epoch, or after the + // end of Unix Time, os.Chtimes has undefined behavior + // default to Unix Epoch in this case, just in case + + if atime.Before(unixMinTime) || atime.After(unixMaxTime) { + atime = unixMinTime + } + + if mtime.Before(unixMinTime) || mtime.After(unixMaxTime) { + mtime = unixMinTime + } + + if err := os.Chtimes(name, atime, mtime); err != nil { + return err + } + + // Take platform specific action for setting create time. + return setCTime(name, mtime) +} diff --git a/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go b/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go new file mode 100644 index 000000000..259138a45 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go @@ -0,0 +1,14 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +import ( + "time" +) + +//setCTime will set the create time on a file. On Unix, the create +//time is updated as a side effect of setting the modified time, so +//no action is required. +func setCTime(path string, ctime time.Time) error { + return nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go b/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go new file mode 100644 index 000000000..d3a115ff4 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go @@ -0,0 +1,26 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "time" + + "golang.org/x/sys/windows" +) + +//setCTime will set the create time on a file. On Windows, this requires +//calling SetFileTime and explicitly including the create time. +func setCTime(path string, ctime time.Time) error { + ctimespec := windows.NsecToTimespec(ctime.UnixNano()) + pathp, e := windows.UTF16PtrFromString(path) + if e != nil { + return e + } + h, e := windows.CreateFile(pathp, + windows.FILE_WRITE_ATTRIBUTES, windows.FILE_SHARE_WRITE, nil, + windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS, 0) + if e != nil { + return e + } + defer windows.Close(h) + c := windows.NsecToFiletime(windows.TimespecToNsec(ctimespec)) + return windows.SetFileTime(h, &c, nil, nil) +} diff --git a/vendor/github.com/docker/docker/pkg/system/errors.go b/vendor/github.com/docker/docker/pkg/system/errors.go new file mode 100644 index 000000000..2573d7162 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/errors.go @@ -0,0 +1,13 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "errors" +) + +var ( + // ErrNotSupportedPlatform means the platform is not supported. + ErrNotSupportedPlatform = errors.New("platform and architecture is not supported") + + // ErrNotSupportedOperatingSystem means the operating system is not supported. + ErrNotSupportedOperatingSystem = errors.New("operating system is not supported") +) diff --git a/vendor/github.com/docker/docker/pkg/system/exitcode.go b/vendor/github.com/docker/docker/pkg/system/exitcode.go new file mode 100644 index 000000000..4ba8fe35b --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/exitcode.go @@ -0,0 +1,19 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "fmt" + "os/exec" + "syscall" +) + +// GetExitCode returns the ExitStatus of the specified error if its type is +// exec.ExitError, returns 0 and an error otherwise. +func GetExitCode(err error) (int, error) { + exitCode := 0 + if exiterr, ok := err.(*exec.ExitError); ok { + if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok { + return procExit.ExitStatus(), nil + } + } + return exitCode, fmt.Errorf("failed to get exit code") +} diff --git a/vendor/github.com/docker/docker/pkg/system/filesys.go b/vendor/github.com/docker/docker/pkg/system/filesys.go new file mode 100644 index 000000000..adeb16305 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/filesys.go @@ -0,0 +1,67 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +import ( + "io/ioutil" + "os" + "path/filepath" +) + +// MkdirAllWithACL is a wrapper for MkdirAll on unix systems. +func MkdirAllWithACL(path string, perm os.FileMode, sddl string) error { + return MkdirAll(path, perm, sddl) +} + +// MkdirAll creates a directory named path along with any necessary parents, +// with permission specified by attribute perm for all dir created. +func MkdirAll(path string, perm os.FileMode, sddl string) error { + return os.MkdirAll(path, perm) +} + +// IsAbs is a platform-specific wrapper for filepath.IsAbs. +func IsAbs(path string) bool { + return filepath.IsAbs(path) +} + +// The functions below here are wrappers for the equivalents in the os and ioutils packages. +// They are passthrough on Unix platforms, and only relevant on Windows. + +// CreateSequential creates the named file with mode 0666 (before umask), truncating +// it if it already exists. If successful, methods on the returned +// File can be used for I/O; the associated file descriptor has mode +// O_RDWR. +// If there is an error, it will be of type *PathError. +func CreateSequential(name string) (*os.File, error) { + return os.Create(name) +} + +// OpenSequential opens the named file for reading. If successful, methods on +// the returned file can be used for reading; the associated file +// descriptor has mode O_RDONLY. +// If there is an error, it will be of type *PathError. +func OpenSequential(name string) (*os.File, error) { + return os.Open(name) +} + +// OpenFileSequential is the generalized open call; most users will use Open +// or Create instead. It opens the named file with specified flag +// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, +// methods on the returned File can be used for I/O. +// If there is an error, it will be of type *PathError. +func OpenFileSequential(name string, flag int, perm os.FileMode) (*os.File, error) { + return os.OpenFile(name, flag, perm) +} + +// TempFileSequential creates a new temporary file in the directory dir +// with a name beginning with prefix, opens the file for reading +// and writing, and returns the resulting *os.File. +// If dir is the empty string, TempFile uses the default directory +// for temporary files (see os.TempDir). +// Multiple programs calling TempFile simultaneously +// will not choose the same file. The caller can use f.Name() +// to find the pathname of the file. It is the caller's responsibility +// to remove the file when no longer needed. +func TempFileSequential(dir, prefix string) (f *os.File, err error) { + return ioutil.TempFile(dir, prefix) +} diff --git a/vendor/github.com/docker/docker/pkg/system/filesys_windows.go b/vendor/github.com/docker/docker/pkg/system/filesys_windows.go new file mode 100644 index 000000000..a1f6013f1 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/filesys_windows.go @@ -0,0 +1,296 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + "sync" + "syscall" + "time" + "unsafe" + + winio "github.com/Microsoft/go-winio" + "golang.org/x/sys/windows" +) + +const ( + // SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System + SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" + // SddlNtvmAdministratorsLocalSystem is NT VIRTUAL MACHINE\Virtual Machines plus local administrators plus NT AUTHORITY\System + SddlNtvmAdministratorsLocalSystem = "D:P(A;OICI;GA;;;S-1-5-83-0)(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" +) + +// MkdirAllWithACL is a wrapper for MkdirAll that creates a directory +// with an appropriate SDDL defined ACL. +func MkdirAllWithACL(path string, perm os.FileMode, sddl string) error { + return mkdirall(path, true, sddl) +} + +// MkdirAll implementation that is volume path aware for Windows. +func MkdirAll(path string, _ os.FileMode, sddl string) error { + return mkdirall(path, false, sddl) +} + +// mkdirall is a custom version of os.MkdirAll modified for use on Windows +// so that it is both volume path aware, and can create a directory with +// a DACL. +func mkdirall(path string, applyACL bool, sddl string) error { + if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) { + return nil + } + + // The rest of this method is largely copied from os.MkdirAll and should be kept + // as-is to ensure compatibility. + + // Fast path: if we can tell whether path is a directory or file, stop with success or error. + dir, err := os.Stat(path) + if err == nil { + if dir.IsDir() { + return nil + } + return &os.PathError{ + Op: "mkdir", + Path: path, + Err: syscall.ENOTDIR, + } + } + + // Slow path: make sure parent exists and then call Mkdir for path. + i := len(path) + for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. + i-- + } + + j := i + for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. + j-- + } + + if j > 1 { + // Create parent + err = mkdirall(path[0:j-1], false, sddl) + if err != nil { + return err + } + } + + // Parent now exists; invoke os.Mkdir or mkdirWithACL and use its result. + if applyACL { + err = mkdirWithACL(path, sddl) + } else { + err = os.Mkdir(path, 0) + } + + if err != nil { + // Handle arguments like "foo/." by + // double-checking that directory doesn't exist. + dir, err1 := os.Lstat(path) + if err1 == nil && dir.IsDir() { + return nil + } + return err + } + return nil +} + +// mkdirWithACL creates a new directory. If there is an error, it will be of +// type *PathError. . +// +// This is a modified and combined version of os.Mkdir and windows.Mkdir +// in golang to cater for creating a directory am ACL permitting full +// access, with inheritance, to any subfolder/file for Built-in Administrators +// and Local System. +func mkdirWithACL(name string, sddl string) error { + sa := windows.SecurityAttributes{Length: 0} + sd, err := winio.SddlToSecurityDescriptor(sddl) + if err != nil { + return &os.PathError{Op: "mkdir", Path: name, Err: err} + } + sa.Length = uint32(unsafe.Sizeof(sa)) + sa.InheritHandle = 1 + sa.SecurityDescriptor = uintptr(unsafe.Pointer(&sd[0])) + + namep, err := windows.UTF16PtrFromString(name) + if err != nil { + return &os.PathError{Op: "mkdir", Path: name, Err: err} + } + + e := windows.CreateDirectory(namep, &sa) + if e != nil { + return &os.PathError{Op: "mkdir", Path: name, Err: e} + } + return nil +} + +// IsAbs is a platform-specific wrapper for filepath.IsAbs. On Windows, +// golang filepath.IsAbs does not consider a path \windows\system32 as absolute +// as it doesn't start with a drive-letter/colon combination. However, in +// docker we need to verify things such as WORKDIR /windows/system32 in +// a Dockerfile (which gets translated to \windows\system32 when being processed +// by the daemon. This SHOULD be treated as absolute from a docker processing +// perspective. +func IsAbs(path string) bool { + if !filepath.IsAbs(path) { + if !strings.HasPrefix(path, string(os.PathSeparator)) { + return false + } + } + return true +} + +// The origin of the functions below here are the golang OS and windows packages, +// slightly modified to only cope with files, not directories due to the +// specific use case. +// +// The alteration is to allow a file on Windows to be opened with +// FILE_FLAG_SEQUENTIAL_SCAN (particular for docker load), to avoid eating +// the standby list, particularly when accessing large files such as layer.tar. + +// CreateSequential creates the named file with mode 0666 (before umask), truncating +// it if it already exists. If successful, methods on the returned +// File can be used for I/O; the associated file descriptor has mode +// O_RDWR. +// If there is an error, it will be of type *PathError. +func CreateSequential(name string) (*os.File, error) { + return OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0) +} + +// OpenSequential opens the named file for reading. If successful, methods on +// the returned file can be used for reading; the associated file +// descriptor has mode O_RDONLY. +// If there is an error, it will be of type *PathError. +func OpenSequential(name string) (*os.File, error) { + return OpenFileSequential(name, os.O_RDONLY, 0) +} + +// OpenFileSequential is the generalized open call; most users will use Open +// or Create instead. +// If there is an error, it will be of type *PathError. +func OpenFileSequential(name string, flag int, _ os.FileMode) (*os.File, error) { + if name == "" { + return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT} + } + r, errf := windowsOpenFileSequential(name, flag, 0) + if errf == nil { + return r, nil + } + return nil, &os.PathError{Op: "open", Path: name, Err: errf} +} + +func windowsOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) { + r, e := windowsOpenSequential(name, flag|windows.O_CLOEXEC, 0) + if e != nil { + return nil, e + } + return os.NewFile(uintptr(r), name), nil +} + +func makeInheritSa() *windows.SecurityAttributes { + var sa windows.SecurityAttributes + sa.Length = uint32(unsafe.Sizeof(sa)) + sa.InheritHandle = 1 + return &sa +} + +func windowsOpenSequential(path string, mode int, _ uint32) (fd windows.Handle, err error) { + if len(path) == 0 { + return windows.InvalidHandle, windows.ERROR_FILE_NOT_FOUND + } + pathp, err := windows.UTF16PtrFromString(path) + if err != nil { + return windows.InvalidHandle, err + } + var access uint32 + switch mode & (windows.O_RDONLY | windows.O_WRONLY | windows.O_RDWR) { + case windows.O_RDONLY: + access = windows.GENERIC_READ + case windows.O_WRONLY: + access = windows.GENERIC_WRITE + case windows.O_RDWR: + access = windows.GENERIC_READ | windows.GENERIC_WRITE + } + if mode&windows.O_CREAT != 0 { + access |= windows.GENERIC_WRITE + } + if mode&windows.O_APPEND != 0 { + access &^= windows.GENERIC_WRITE + access |= windows.FILE_APPEND_DATA + } + sharemode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE) + var sa *windows.SecurityAttributes + if mode&windows.O_CLOEXEC == 0 { + sa = makeInheritSa() + } + var createmode uint32 + switch { + case mode&(windows.O_CREAT|windows.O_EXCL) == (windows.O_CREAT | windows.O_EXCL): + createmode = windows.CREATE_NEW + case mode&(windows.O_CREAT|windows.O_TRUNC) == (windows.O_CREAT | windows.O_TRUNC): + createmode = windows.CREATE_ALWAYS + case mode&windows.O_CREAT == windows.O_CREAT: + createmode = windows.OPEN_ALWAYS + case mode&windows.O_TRUNC == windows.O_TRUNC: + createmode = windows.TRUNCATE_EXISTING + default: + createmode = windows.OPEN_EXISTING + } + // Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang. + //https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx + const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN + h, e := windows.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0) + return h, e +} + +// Helpers for TempFileSequential +var rand uint32 +var randmu sync.Mutex + +func reseed() uint32 { + return uint32(time.Now().UnixNano() + int64(os.Getpid())) +} +func nextSuffix() string { + randmu.Lock() + r := rand + if r == 0 { + r = reseed() + } + r = r*1664525 + 1013904223 // constants from Numerical Recipes + rand = r + randmu.Unlock() + return strconv.Itoa(int(1e9 + r%1e9))[1:] +} + +// TempFileSequential is a copy of ioutil.TempFile, modified to use sequential +// file access. Below is the original comment from golang: +// TempFile creates a new temporary file in the directory dir +// with a name beginning with prefix, opens the file for reading +// and writing, and returns the resulting *os.File. +// If dir is the empty string, TempFile uses the default directory +// for temporary files (see os.TempDir). +// Multiple programs calling TempFile simultaneously +// will not choose the same file. The caller can use f.Name() +// to find the pathname of the file. It is the caller's responsibility +// to remove the file when no longer needed. +func TempFileSequential(dir, prefix string) (f *os.File, err error) { + if dir == "" { + dir = os.TempDir() + } + + nconflict := 0 + for i := 0; i < 10000; i++ { + name := filepath.Join(dir, prefix+nextSuffix()) + f, err = OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) + if os.IsExist(err) { + if nconflict++; nconflict > 10 { + randmu.Lock() + rand = reseed() + randmu.Unlock() + } + continue + } + break + } + return +} diff --git a/vendor/github.com/docker/docker/pkg/system/init.go b/vendor/github.com/docker/docker/pkg/system/init.go new file mode 100644 index 000000000..a17597aab --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/init.go @@ -0,0 +1,22 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "syscall" + "time" + "unsafe" +) + +// Used by chtimes +var maxTime time.Time + +func init() { + // chtimes initialization + if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 { + // This is a 64 bit timespec + // os.Chtimes limits time to the following + maxTime = time.Unix(0, 1<<63-1) + } else { + // This is a 32 bit timespec + maxTime = time.Unix(1<<31-1, 0) + } +} diff --git a/vendor/github.com/docker/docker/pkg/system/init_unix.go b/vendor/github.com/docker/docker/pkg/system/init_unix.go new file mode 100644 index 000000000..4996a67c1 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/init_unix.go @@ -0,0 +1,7 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +// InitLCOW does nothing since LCOW is a windows only feature +func InitLCOW(experimental bool) { +} diff --git a/vendor/github.com/docker/docker/pkg/system/init_windows.go b/vendor/github.com/docker/docker/pkg/system/init_windows.go new file mode 100644 index 000000000..4910ff69d --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/init_windows.go @@ -0,0 +1,12 @@ +package system // import "github.com/docker/docker/pkg/system" + +// lcowSupported determines if Linux Containers on Windows are supported. +var lcowSupported = false + +// InitLCOW sets whether LCOW is supported or not +func InitLCOW(experimental bool) { + v := GetOSVersion() + if experimental && v.Build >= 16299 { + lcowSupported = true + } +} diff --git a/vendor/github.com/docker/docker/pkg/system/lcow.go b/vendor/github.com/docker/docker/pkg/system/lcow.go new file mode 100644 index 000000000..5c3fbfe6f --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/lcow.go @@ -0,0 +1,69 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "fmt" + "runtime" + "strings" + + specs "github.com/opencontainers/image-spec/specs-go/v1" +) + +// ValidatePlatform determines if a platform structure is valid. +// TODO This is a temporary function - can be replaced by parsing from +// https://github.com/containerd/containerd/pull/1403/files at a later date. +// @jhowardmsft +func ValidatePlatform(platform *specs.Platform) error { + platform.Architecture = strings.ToLower(platform.Architecture) + platform.OS = strings.ToLower(platform.OS) + // Based on https://github.com/moby/moby/pull/34642#issuecomment-330375350, do + // not support anything except operating system. + if platform.Architecture != "" { + return fmt.Errorf("invalid platform architecture %q", platform.Architecture) + } + if platform.OS != "" { + if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) { + return fmt.Errorf("invalid platform os %q", platform.OS) + } + } + if len(platform.OSFeatures) != 0 { + return fmt.Errorf("invalid platform osfeatures %q", platform.OSFeatures) + } + if platform.OSVersion != "" { + return fmt.Errorf("invalid platform osversion %q", platform.OSVersion) + } + if platform.Variant != "" { + return fmt.Errorf("invalid platform variant %q", platform.Variant) + } + return nil +} + +// ParsePlatform parses a platform string in the format os[/arch[/variant] +// into an OCI image-spec platform structure. +// TODO This is a temporary function - can be replaced by parsing from +// https://github.com/containerd/containerd/pull/1403/files at a later date. +// @jhowardmsft +func ParsePlatform(in string) *specs.Platform { + p := &specs.Platform{} + elements := strings.SplitN(strings.ToLower(in), "/", 3) + if len(elements) == 3 { + p.Variant = elements[2] + } + if len(elements) >= 2 { + p.Architecture = elements[1] + } + if len(elements) >= 1 { + p.OS = elements[0] + } + return p +} + +// IsOSSupported determines if an operating system is supported by the host +func IsOSSupported(os string) bool { + if runtime.GOOS == os { + return true + } + if LCOWSupported() && os == "linux" { + return true + } + return false +} diff --git a/vendor/github.com/docker/docker/pkg/system/lcow_unix.go b/vendor/github.com/docker/docker/pkg/system/lcow_unix.go new file mode 100644 index 000000000..26397fb8a --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/lcow_unix.go @@ -0,0 +1,8 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +// LCOWSupported returns true if Linux containers on Windows are supported. +func LCOWSupported() bool { + return false +} diff --git a/vendor/github.com/docker/docker/pkg/system/lcow_windows.go b/vendor/github.com/docker/docker/pkg/system/lcow_windows.go new file mode 100644 index 000000000..f0139df8f --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/lcow_windows.go @@ -0,0 +1,6 @@ +package system // import "github.com/docker/docker/pkg/system" + +// LCOWSupported returns true if Linux containers on Windows are supported. +func LCOWSupported() bool { + return lcowSupported +} diff --git a/vendor/github.com/docker/docker/pkg/system/lstat_unix.go b/vendor/github.com/docker/docker/pkg/system/lstat_unix.go new file mode 100644 index 000000000..7477995f1 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/lstat_unix.go @@ -0,0 +1,19 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +import ( + "syscall" +) + +// Lstat takes a path to a file and returns +// a system.StatT type pertaining to that file. +// +// Throws an error if the file does not exist +func Lstat(path string) (*StatT, error) { + s := &syscall.Stat_t{} + if err := syscall.Lstat(path, s); err != nil { + return nil, err + } + return fromStatT(s) +} diff --git a/vendor/github.com/docker/docker/pkg/system/lstat_windows.go b/vendor/github.com/docker/docker/pkg/system/lstat_windows.go new file mode 100644 index 000000000..359c791d9 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/lstat_windows.go @@ -0,0 +1,14 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "os" + +// Lstat calls os.Lstat to get a fileinfo interface back. +// This is then copied into our own locally defined structure. +func Lstat(path string) (*StatT, error) { + fi, err := os.Lstat(path) + if err != nil { + return nil, err + } + + return fromStatT(&fi) +} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo.go b/vendor/github.com/docker/docker/pkg/system/meminfo.go new file mode 100644 index 000000000..6667eb84d --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/meminfo.go @@ -0,0 +1,17 @@ +package system // import "github.com/docker/docker/pkg/system" + +// MemInfo contains memory statistics of the host system. +type MemInfo struct { + // Total usable RAM (i.e. physical RAM minus a few reserved bits and the + // kernel binary code). + MemTotal int64 + + // Amount of free memory. + MemFree int64 + + // Total amount of swap space available. + SwapTotal int64 + + // Amount of swap space that is currently unused. + SwapFree int64 +} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go b/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go new file mode 100644 index 000000000..d79e8b076 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go @@ -0,0 +1,65 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "bufio" + "io" + "os" + "strconv" + "strings" + + "github.com/docker/go-units" +) + +// ReadMemInfo retrieves memory statistics of the host system and returns a +// MemInfo type. +func ReadMemInfo() (*MemInfo, error) { + file, err := os.Open("/proc/meminfo") + if err != nil { + return nil, err + } + defer file.Close() + return parseMemInfo(file) +} + +// parseMemInfo parses the /proc/meminfo file into +// a MemInfo object given an io.Reader to the file. +// Throws error if there are problems reading from the file +func parseMemInfo(reader io.Reader) (*MemInfo, error) { + meminfo := &MemInfo{} + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + // Expected format: ["MemTotal:", "1234", "kB"] + parts := strings.Fields(scanner.Text()) + + // Sanity checks: Skip malformed entries. + if len(parts) < 3 || parts[2] != "kB" { + continue + } + + // Convert to bytes. + size, err := strconv.Atoi(parts[1]) + if err != nil { + continue + } + bytes := int64(size) * units.KiB + + switch parts[0] { + case "MemTotal:": + meminfo.MemTotal = bytes + case "MemFree:": + meminfo.MemFree = bytes + case "SwapTotal:": + meminfo.SwapTotal = bytes + case "SwapFree:": + meminfo.SwapFree = bytes + } + + } + + // Handle errors that may have occurred during the reading of the file. + if err := scanner.Err(); err != nil { + return nil, err + } + + return meminfo, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go b/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go new file mode 100644 index 000000000..56f449426 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go @@ -0,0 +1,8 @@ +// +build !linux,!windows + +package system // import "github.com/docker/docker/pkg/system" + +// ReadMemInfo is not supported on platforms other than linux and windows. +func ReadMemInfo() (*MemInfo, error) { + return nil, ErrNotSupportedPlatform +} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go b/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go new file mode 100644 index 000000000..6ed93f2fe --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go @@ -0,0 +1,45 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "unsafe" + + "golang.org/x/sys/windows" +) + +var ( + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + + procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") +) + +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx +type memorystatusex struct { + dwLength uint32 + dwMemoryLoad uint32 + ullTotalPhys uint64 + ullAvailPhys uint64 + ullTotalPageFile uint64 + ullAvailPageFile uint64 + ullTotalVirtual uint64 + ullAvailVirtual uint64 + ullAvailExtendedVirtual uint64 +} + +// ReadMemInfo retrieves memory statistics of the host system and returns a +// MemInfo type. +func ReadMemInfo() (*MemInfo, error) { + msi := &memorystatusex{ + dwLength: 64, + } + r1, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(msi))) + if r1 == 0 { + return &MemInfo{}, nil + } + return &MemInfo{ + MemTotal: int64(msi.ullTotalPhys), + MemFree: int64(msi.ullAvailPhys), + SwapTotal: int64(msi.ullTotalPageFile), + SwapFree: int64(msi.ullAvailPageFile), + }, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/mknod.go b/vendor/github.com/docker/docker/pkg/system/mknod.go new file mode 100644 index 000000000..b132482e0 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/mknod.go @@ -0,0 +1,22 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +import ( + "golang.org/x/sys/unix" +) + +// Mknod creates a filesystem node (file, device special file or named pipe) named path +// with attributes specified by mode and dev. +func Mknod(path string, mode uint32, dev int) error { + return unix.Mknod(path, mode, dev) +} + +// Mkdev is used to build the value of linux devices (in /dev/) which specifies major +// and minor number of the newly created device special file. +// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes. +// They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major, +// then the top 12 bits of the minor. +func Mkdev(major int64, minor int64) uint32 { + return uint32(unix.Mkdev(uint32(major), uint32(minor))) +} diff --git a/vendor/github.com/docker/docker/pkg/system/mknod_windows.go b/vendor/github.com/docker/docker/pkg/system/mknod_windows.go new file mode 100644 index 000000000..ec89d7a15 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/mknod_windows.go @@ -0,0 +1,11 @@ +package system // import "github.com/docker/docker/pkg/system" + +// Mknod is not implemented on Windows. +func Mknod(path string, mode uint32, dev int) error { + return ErrNotSupportedPlatform +} + +// Mkdev is not implemented on Windows. +func Mkdev(major int64, minor int64) uint32 { + panic("Mkdev not implemented on Windows.") +} diff --git a/vendor/github.com/docker/docker/pkg/system/path.go b/vendor/github.com/docker/docker/pkg/system/path.go new file mode 100644 index 000000000..a3d957afa --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/path.go @@ -0,0 +1,60 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "fmt" + "path/filepath" + "runtime" + "strings" + + "github.com/containerd/continuity/pathdriver" +) + +const defaultUnixPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +// DefaultPathEnv is unix style list of directories to search for +// executables. Each directory is separated from the next by a colon +// ':' character . +func DefaultPathEnv(os string) string { + if runtime.GOOS == "windows" { + if os != runtime.GOOS { + return defaultUnixPathEnv + } + // Deliberately empty on Windows containers on Windows as the default path will be set by + // the container. Docker has no context of what the default path should be. + return "" + } + return defaultUnixPathEnv + +} + +// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter, +// is the system drive. +// On Linux: this is a no-op. +// On Windows: this does the following> +// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path. +// This is used, for example, when validating a user provided path in docker cp. +// If a drive letter is supplied, it must be the system drive. The drive letter +// is always removed. Also, it translates it to OS semantics (IOW / to \). We +// need the path in this syntax so that it can ultimately be concatenated with +// a Windows long-path which doesn't support drive-letters. Examples: +// C: --> Fail +// C:\ --> \ +// a --> a +// /a --> \a +// d:\ --> Fail +func CheckSystemDriveAndRemoveDriveLetter(path string, driver pathdriver.PathDriver) (string, error) { + if runtime.GOOS != "windows" || LCOWSupported() { + return path, nil + } + + if len(path) == 2 && string(path[1]) == ":" { + return "", fmt.Errorf("No relative path specified in %q", path) + } + if !driver.IsAbs(path) || len(path) < 2 { + return filepath.FromSlash(path), nil + } + if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") { + return "", fmt.Errorf("The specified path is not on the system drive (C:)") + } + return filepath.FromSlash(path[2:]), nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/process_unix.go b/vendor/github.com/docker/docker/pkg/system/process_unix.go new file mode 100644 index 000000000..0195a891b --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/process_unix.go @@ -0,0 +1,24 @@ +// +build linux freebsd darwin + +package system // import "github.com/docker/docker/pkg/system" + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +// IsProcessAlive returns true if process with a given pid is running. +func IsProcessAlive(pid int) bool { + err := unix.Kill(pid, syscall.Signal(0)) + if err == nil || err == unix.EPERM { + return true + } + + return false +} + +// KillProcess force-stops a process. +func KillProcess(pid int) { + unix.Kill(pid, unix.SIGKILL) +} diff --git a/vendor/github.com/docker/docker/pkg/system/process_windows.go b/vendor/github.com/docker/docker/pkg/system/process_windows.go new file mode 100644 index 000000000..4e70c97b1 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/process_windows.go @@ -0,0 +1,18 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "os" + +// IsProcessAlive returns true if process with a given pid is running. +func IsProcessAlive(pid int) bool { + _, err := os.FindProcess(pid) + + return err == nil +} + +// KillProcess force-stops a process. +func KillProcess(pid int) { + p, err := os.FindProcess(pid) + if err == nil { + p.Kill() + } +} diff --git a/vendor/github.com/docker/docker/pkg/system/rm.go b/vendor/github.com/docker/docker/pkg/system/rm.go new file mode 100644 index 000000000..02e4d2622 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/rm.go @@ -0,0 +1,80 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "os" + "syscall" + "time" + + "github.com/docker/docker/pkg/mount" + "github.com/pkg/errors" +) + +// EnsureRemoveAll wraps `os.RemoveAll` to check for specific errors that can +// often be remedied. +// Only use `EnsureRemoveAll` if you really want to make every effort to remove +// a directory. +// +// Because of the way `os.Remove` (and by extension `os.RemoveAll`) works, there +// can be a race between reading directory entries and then actually attempting +// to remove everything in the directory. +// These types of errors do not need to be returned since it's ok for the dir to +// be gone we can just retry the remove operation. +// +// This should not return a `os.ErrNotExist` kind of error under any circumstances +func EnsureRemoveAll(dir string) error { + notExistErr := make(map[string]bool) + + // track retries + exitOnErr := make(map[string]int) + maxRetry := 50 + + // Attempt to unmount anything beneath this dir first + mount.RecursiveUnmount(dir) + + for { + err := os.RemoveAll(dir) + if err == nil { + return err + } + + pe, ok := err.(*os.PathError) + if !ok { + return err + } + + if os.IsNotExist(err) { + if notExistErr[pe.Path] { + return err + } + notExistErr[pe.Path] = true + + // There is a race where some subdir can be removed but after the parent + // dir entries have been read. + // So the path could be from `os.Remove(subdir)` + // If the reported non-existent path is not the passed in `dir` we + // should just retry, but otherwise return with no error. + if pe.Path == dir { + return nil + } + continue + } + + if pe.Err != syscall.EBUSY { + return err + } + + if mounted, _ := mount.Mounted(pe.Path); mounted { + if e := mount.Unmount(pe.Path); e != nil { + if mounted, _ := mount.Mounted(pe.Path); mounted { + return errors.Wrapf(e, "error while removing %s", dir) + } + } + } + + if exitOnErr[pe.Path] == maxRetry { + return err + } + exitOnErr[pe.Path]++ + time.Sleep(100 * time.Millisecond) + } +} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_darwin.go b/vendor/github.com/docker/docker/pkg/system/stat_darwin.go new file mode 100644 index 000000000..c1c0ee9f3 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/stat_darwin.go @@ -0,0 +1,13 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "syscall" + +// fromStatT converts a syscall.Stat_t type to a system.Stat_t type +func fromStatT(s *syscall.Stat_t) (*StatT, error) { + return &StatT{size: s.Size, + mode: uint32(s.Mode), + uid: s.Uid, + gid: s.Gid, + rdev: uint64(s.Rdev), + mtim: s.Mtimespec}, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go b/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go new file mode 100644 index 000000000..c1c0ee9f3 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go @@ -0,0 +1,13 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "syscall" + +// fromStatT converts a syscall.Stat_t type to a system.Stat_t type +func fromStatT(s *syscall.Stat_t) (*StatT, error) { + return &StatT{size: s.Size, + mode: uint32(s.Mode), + uid: s.Uid, + gid: s.Gid, + rdev: uint64(s.Rdev), + mtim: s.Mtimespec}, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_linux.go b/vendor/github.com/docker/docker/pkg/system/stat_linux.go new file mode 100644 index 000000000..98c9eb18d --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/stat_linux.go @@ -0,0 +1,19 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "syscall" + +// fromStatT converts a syscall.Stat_t type to a system.Stat_t type +func fromStatT(s *syscall.Stat_t) (*StatT, error) { + return &StatT{size: s.Size, + mode: s.Mode, + uid: s.Uid, + gid: s.Gid, + rdev: s.Rdev, + mtim: s.Mtim}, nil +} + +// FromStatT converts a syscall.Stat_t type to a system.Stat_t type +// This is exposed on Linux as pkg/archive/changes uses it. +func FromStatT(s *syscall.Stat_t) (*StatT, error) { + return fromStatT(s) +} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go b/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go new file mode 100644 index 000000000..756b92d1e --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go @@ -0,0 +1,13 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "syscall" + +// fromStatT converts a syscall.Stat_t type to a system.Stat_t type +func fromStatT(s *syscall.Stat_t) (*StatT, error) { + return &StatT{size: s.Size, + mode: uint32(s.Mode), + uid: s.Uid, + gid: s.Gid, + rdev: uint64(s.Rdev), + mtim: s.Mtim}, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_solaris.go b/vendor/github.com/docker/docker/pkg/system/stat_solaris.go new file mode 100644 index 000000000..756b92d1e --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/stat_solaris.go @@ -0,0 +1,13 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "syscall" + +// fromStatT converts a syscall.Stat_t type to a system.Stat_t type +func fromStatT(s *syscall.Stat_t) (*StatT, error) { + return &StatT{size: s.Size, + mode: uint32(s.Mode), + uid: s.Uid, + gid: s.Gid, + rdev: uint64(s.Rdev), + mtim: s.Mtim}, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_unix.go b/vendor/github.com/docker/docker/pkg/system/stat_unix.go new file mode 100644 index 000000000..3d7e2ebbe --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/stat_unix.go @@ -0,0 +1,65 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +import ( + "syscall" +) + +// StatT type contains status of a file. It contains metadata +// like permission, owner, group, size, etc about a file. +type StatT struct { + mode uint32 + uid uint32 + gid uint32 + rdev uint64 + size int64 + mtim syscall.Timespec +} + +// Mode returns file's permission mode. +func (s StatT) Mode() uint32 { + return s.mode +} + +// UID returns file's user id of owner. +func (s StatT) UID() uint32 { + return s.uid +} + +// GID returns file's group id of owner. +func (s StatT) GID() uint32 { + return s.gid +} + +// Rdev returns file's device ID (if it's special file). +func (s StatT) Rdev() uint64 { + return s.rdev +} + +// Size returns file's size. +func (s StatT) Size() int64 { + return s.size +} + +// Mtim returns file's last modification time. +func (s StatT) Mtim() syscall.Timespec { + return s.mtim +} + +// IsDir reports whether s describes a directory. +func (s StatT) IsDir() bool { + return s.mode&syscall.S_IFDIR != 0 +} + +// Stat takes a path to a file and returns +// a system.StatT type pertaining to that file. +// +// Throws an error if the file does not exist +func Stat(path string) (*StatT, error) { + s := &syscall.Stat_t{} + if err := syscall.Stat(path, s); err != nil { + return nil, err + } + return fromStatT(s) +} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_windows.go b/vendor/github.com/docker/docker/pkg/system/stat_windows.go new file mode 100644 index 000000000..b2456cb88 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/stat_windows.go @@ -0,0 +1,49 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "os" + "time" +) + +// StatT type contains status of a file. It contains metadata +// like permission, size, etc about a file. +type StatT struct { + mode os.FileMode + size int64 + mtim time.Time +} + +// Size returns file's size. +func (s StatT) Size() int64 { + return s.size +} + +// Mode returns file's permission mode. +func (s StatT) Mode() os.FileMode { + return os.FileMode(s.mode) +} + +// Mtim returns file's last modification time. +func (s StatT) Mtim() time.Time { + return time.Time(s.mtim) +} + +// Stat takes a path to a file and returns +// a system.StatT type pertaining to that file. +// +// Throws an error if the file does not exist +func Stat(path string) (*StatT, error) { + fi, err := os.Stat(path) + if err != nil { + return nil, err + } + return fromStatT(&fi) +} + +// fromStatT converts a os.FileInfo type to a system.StatT type +func fromStatT(fi *os.FileInfo) (*StatT, error) { + return &StatT{ + size: (*fi).Size(), + mode: (*fi).Mode(), + mtim: (*fi).ModTime()}, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/syscall_unix.go b/vendor/github.com/docker/docker/pkg/system/syscall_unix.go new file mode 100644 index 000000000..919a412a7 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/syscall_unix.go @@ -0,0 +1,17 @@ +// +build linux freebsd + +package system // import "github.com/docker/docker/pkg/system" + +import "golang.org/x/sys/unix" + +// Unmount is a platform-specific helper function to call +// the unmount syscall. +func Unmount(dest string) error { + return unix.Unmount(dest, 0) +} + +// CommandLineToArgv should not be used on Unix. +// It simply returns commandLine in the only element in the returned array. +func CommandLineToArgv(commandLine string) ([]string, error) { + return []string{commandLine}, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/syscall_windows.go b/vendor/github.com/docker/docker/pkg/system/syscall_windows.go new file mode 100644 index 000000000..ee7e0256f --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/syscall_windows.go @@ -0,0 +1,127 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "fmt" + "unsafe" + + "github.com/sirupsen/logrus" + "golang.org/x/sys/windows" +) + +var ( + ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") + procGetVersionExW = modkernel32.NewProc("GetVersionExW") + procGetProductInfo = modkernel32.NewProc("GetProductInfo") +) + +// OSVersion is a wrapper for Windows version information +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx +type OSVersion struct { + Version uint32 + MajorVersion uint8 + MinorVersion uint8 + Build uint16 +} + +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx +type osVersionInfoEx struct { + OSVersionInfoSize uint32 + MajorVersion uint32 + MinorVersion uint32 + BuildNumber uint32 + PlatformID uint32 + CSDVersion [128]uint16 + ServicePackMajor uint16 + ServicePackMinor uint16 + SuiteMask uint16 + ProductType byte + Reserve byte +} + +// GetOSVersion gets the operating system version on Windows. Note that +// docker.exe must be manifested to get the correct version information. +func GetOSVersion() OSVersion { + var err error + osv := OSVersion{} + osv.Version, err = windows.GetVersion() + if err != nil { + // GetVersion never fails. + panic(err) + } + osv.MajorVersion = uint8(osv.Version & 0xFF) + osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF) + osv.Build = uint16(osv.Version >> 16) + return osv +} + +func (osv OSVersion) ToString() string { + return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build) +} + +// IsWindowsClient returns true if the SKU is client +// @engine maintainers - this function should not be removed or modified as it +// is used to enforce licensing restrictions on Windows. +func IsWindowsClient() bool { + osviex := &osVersionInfoEx{OSVersionInfoSize: 284} + r1, _, err := procGetVersionExW.Call(uintptr(unsafe.Pointer(osviex))) + if r1 == 0 { + logrus.Warnf("GetVersionExW failed - assuming server SKU: %v", err) + return false + } + const verNTWorkstation = 0x00000001 + return osviex.ProductType == verNTWorkstation +} + +// IsIoTCore returns true if the currently running image is based off of +// Windows 10 IoT Core. +// @engine maintainers - this function should not be removed or modified as it +// is used to enforce licensing restrictions on Windows. +func IsIoTCore() bool { + var returnedProductType uint32 + r1, _, err := procGetProductInfo.Call(6, 1, 0, 0, uintptr(unsafe.Pointer(&returnedProductType))) + if r1 == 0 { + logrus.Warnf("GetProductInfo failed - assuming this is not IoT: %v", err) + return false + } + const productIoTUAP = 0x0000007B + const productIoTUAPCommercial = 0x00000083 + return returnedProductType == productIoTUAP || returnedProductType == productIoTUAPCommercial +} + +// Unmount is a platform-specific helper function to call +// the unmount syscall. Not supported on Windows +func Unmount(dest string) error { + return nil +} + +// CommandLineToArgv wraps the Windows syscall to turn a commandline into an argument array. +func CommandLineToArgv(commandLine string) ([]string, error) { + var argc int32 + + argsPtr, err := windows.UTF16PtrFromString(commandLine) + if err != nil { + return nil, err + } + + argv, err := windows.CommandLineToArgv(argsPtr, &argc) + if err != nil { + return nil, err + } + defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(argv)))) + + newArgs := make([]string, argc) + for i, v := range (*argv)[:argc] { + newArgs[i] = string(windows.UTF16ToString((*v)[:])) + } + + return newArgs, nil +} + +// HasWin32KSupport determines whether containers that depend on win32k can +// run on this machine. Win32k is the driver used to implement windowing. +func HasWin32KSupport() bool { + // For now, check for ntuser API support on the host. In the future, a host + // may support win32k in containers even if the host does not support ntuser + // APIs. + return ntuserApiset.Load() == nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/umask.go b/vendor/github.com/docker/docker/pkg/system/umask.go new file mode 100644 index 000000000..9912a2bab --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/umask.go @@ -0,0 +1,13 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +import ( + "golang.org/x/sys/unix" +) + +// Umask sets current process's file mode creation mask to newmask +// and returns oldmask. +func Umask(newmask int) (oldmask int, err error) { + return unix.Umask(newmask), nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/umask_windows.go b/vendor/github.com/docker/docker/pkg/system/umask_windows.go new file mode 100644 index 000000000..fc62388c3 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/umask_windows.go @@ -0,0 +1,7 @@ +package system // import "github.com/docker/docker/pkg/system" + +// Umask is not supported on the windows platform. +func Umask(newmask int) (oldmask int, err error) { + // should not be called on cli code path + return 0, ErrNotSupportedPlatform +} diff --git a/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go b/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go new file mode 100644 index 000000000..ed1b9fad5 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go @@ -0,0 +1,24 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/unix" +) + +// LUtimesNano is used to change access and modification time of the specified path. +// It's used for symbol link file because unix.UtimesNano doesn't support a NOFOLLOW flag atm. +func LUtimesNano(path string, ts []syscall.Timespec) error { + var _path *byte + _path, err := unix.BytePtrFromString(path) + if err != nil { + return err + } + + if _, _, err := unix.Syscall(unix.SYS_LUTIMES, uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), 0); err != 0 && err != unix.ENOSYS { + return err + } + + return nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/utimes_linux.go b/vendor/github.com/docker/docker/pkg/system/utimes_linux.go new file mode 100644 index 000000000..0afe85458 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/utimes_linux.go @@ -0,0 +1,25 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/unix" +) + +// LUtimesNano is used to change access and modification time of the specified path. +// It's used for symbol link file because unix.UtimesNano doesn't support a NOFOLLOW flag atm. +func LUtimesNano(path string, ts []syscall.Timespec) error { + atFdCwd := unix.AT_FDCWD + + var _path *byte + _path, err := unix.BytePtrFromString(path) + if err != nil { + return err + } + if _, _, err := unix.Syscall6(unix.SYS_UTIMENSAT, uintptr(atFdCwd), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), unix.AT_SYMLINK_NOFOLLOW, 0, 0); err != 0 && err != unix.ENOSYS { + return err + } + + return nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go b/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go new file mode 100644 index 000000000..095e072e1 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go @@ -0,0 +1,10 @@ +// +build !linux,!freebsd + +package system // import "github.com/docker/docker/pkg/system" + +import "syscall" + +// LUtimesNano is only supported on linux and freebsd. +func LUtimesNano(path string, ts []syscall.Timespec) error { + return ErrNotSupportedPlatform +} diff --git a/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go b/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go new file mode 100644 index 000000000..66d4895b2 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go @@ -0,0 +1,29 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "golang.org/x/sys/unix" + +// Lgetxattr retrieves the value of the extended attribute identified by attr +// and associated with the given path in the file system. +// It will returns a nil slice and nil error if the xattr is not set. +func Lgetxattr(path string, attr string) ([]byte, error) { + dest := make([]byte, 128) + sz, errno := unix.Lgetxattr(path, attr, dest) + if errno == unix.ENODATA { + return nil, nil + } + if errno == unix.ERANGE { + dest = make([]byte, sz) + sz, errno = unix.Lgetxattr(path, attr, dest) + } + if errno != nil { + return nil, errno + } + + return dest[:sz], nil +} + +// Lsetxattr sets the value of the extended attribute identified by attr +// and associated with the given path in the file system. +func Lsetxattr(path string, attr string, data []byte, flags int) error { + return unix.Lsetxattr(path, attr, data, flags) +} diff --git a/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go b/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go new file mode 100644 index 000000000..d780a90cd --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go @@ -0,0 +1,13 @@ +// +build !linux + +package system // import "github.com/docker/docker/pkg/system" + +// Lgetxattr is not supported on platforms other than linux. +func Lgetxattr(path string, attr string) ([]byte, error) { + return nil, ErrNotSupportedPlatform +} + +// Lsetxattr is not supported on platforms other than linux. +func Lsetxattr(path string, attr string, data []byte, flags int) error { + return ErrNotSupportedPlatform +} diff --git a/vendor/github.com/docker/docker/project/CONTRIBUTING.md b/vendor/github.com/docker/docker/project/CONTRIBUTING.md new file mode 120000 index 000000000..44fcc6343 --- /dev/null +++ b/vendor/github.com/docker/docker/project/CONTRIBUTING.md @@ -0,0 +1 @@ +../CONTRIBUTING.md \ No newline at end of file diff --git a/vendor/github.com/docker/go-connections/LICENSE b/vendor/github.com/docker/go-connections/LICENSE new file mode 100644 index 000000000..b55b37bc3 --- /dev/null +++ b/vendor/github.com/docker/go-connections/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/docker/go-connections/nat/nat.go b/vendor/github.com/docker/go-connections/nat/nat.go new file mode 100644 index 000000000..bb7e4e336 --- /dev/null +++ b/vendor/github.com/docker/go-connections/nat/nat.go @@ -0,0 +1,242 @@ +// Package nat is a convenience package for manipulation of strings describing network ports. +package nat + +import ( + "fmt" + "net" + "strconv" + "strings" +) + +const ( + // portSpecTemplate is the expected format for port specifications + portSpecTemplate = "ip:hostPort:containerPort" +) + +// PortBinding represents a binding between a Host IP address and a Host Port +type PortBinding struct { + // HostIP is the host IP Address + HostIP string `json:"HostIp"` + // HostPort is the host port number + HostPort string +} + +// PortMap is a collection of PortBinding indexed by Port +type PortMap map[Port][]PortBinding + +// PortSet is a collection of structs indexed by Port +type PortSet map[Port]struct{} + +// Port is a string containing port number and protocol in the format "80/tcp" +type Port string + +// NewPort creates a new instance of a Port given a protocol and port number or port range +func NewPort(proto, port string) (Port, error) { + // Check for parsing issues on "port" now so we can avoid having + // to check it later on. + + portStartInt, portEndInt, err := ParsePortRangeToInt(port) + if err != nil { + return "", err + } + + if portStartInt == portEndInt { + return Port(fmt.Sprintf("%d/%s", portStartInt, proto)), nil + } + return Port(fmt.Sprintf("%d-%d/%s", portStartInt, portEndInt, proto)), nil +} + +// ParsePort parses the port number string and returns an int +func ParsePort(rawPort string) (int, error) { + if len(rawPort) == 0 { + return 0, nil + } + port, err := strconv.ParseUint(rawPort, 10, 16) + if err != nil { + return 0, err + } + return int(port), nil +} + +// ParsePortRangeToInt parses the port range string and returns start/end ints +func ParsePortRangeToInt(rawPort string) (int, int, error) { + if len(rawPort) == 0 { + return 0, 0, nil + } + start, end, err := ParsePortRange(rawPort) + if err != nil { + return 0, 0, err + } + return int(start), int(end), nil +} + +// Proto returns the protocol of a Port +func (p Port) Proto() string { + proto, _ := SplitProtoPort(string(p)) + return proto +} + +// Port returns the port number of a Port +func (p Port) Port() string { + _, port := SplitProtoPort(string(p)) + return port +} + +// Int returns the port number of a Port as an int +func (p Port) Int() int { + portStr := p.Port() + // We don't need to check for an error because we're going to + // assume that any error would have been found, and reported, in NewPort() + port, _ := ParsePort(portStr) + return port +} + +// Range returns the start/end port numbers of a Port range as ints +func (p Port) Range() (int, int, error) { + return ParsePortRangeToInt(p.Port()) +} + +// SplitProtoPort splits a port in the format of proto/port +func SplitProtoPort(rawPort string) (string, string) { + parts := strings.Split(rawPort, "/") + l := len(parts) + if len(rawPort) == 0 || l == 0 || len(parts[0]) == 0 { + return "", "" + } + if l == 1 { + return "tcp", rawPort + } + if len(parts[1]) == 0 { + return "tcp", parts[0] + } + return parts[1], parts[0] +} + +func validateProto(proto string) bool { + for _, availableProto := range []string{"tcp", "udp", "sctp"} { + if availableProto == proto { + return true + } + } + return false +} + +// ParsePortSpecs receives port specs in the format of ip:public:private/proto and parses +// these in to the internal types +func ParsePortSpecs(ports []string) (map[Port]struct{}, map[Port][]PortBinding, error) { + var ( + exposedPorts = make(map[Port]struct{}, len(ports)) + bindings = make(map[Port][]PortBinding) + ) + for _, rawPort := range ports { + portMappings, err := ParsePortSpec(rawPort) + if err != nil { + return nil, nil, err + } + + for _, portMapping := range portMappings { + port := portMapping.Port + if _, exists := exposedPorts[port]; !exists { + exposedPorts[port] = struct{}{} + } + bslice, exists := bindings[port] + if !exists { + bslice = []PortBinding{} + } + bindings[port] = append(bslice, portMapping.Binding) + } + } + return exposedPorts, bindings, nil +} + +// PortMapping is a data object mapping a Port to a PortBinding +type PortMapping struct { + Port Port + Binding PortBinding +} + +func splitParts(rawport string) (string, string, string) { + parts := strings.Split(rawport, ":") + n := len(parts) + containerport := parts[n-1] + + switch n { + case 1: + return "", "", containerport + case 2: + return "", parts[0], containerport + case 3: + return parts[0], parts[1], containerport + default: + return strings.Join(parts[:n-2], ":"), parts[n-2], containerport + } +} + +// ParsePortSpec parses a port specification string into a slice of PortMappings +func ParsePortSpec(rawPort string) ([]PortMapping, error) { + var proto string + rawIP, hostPort, containerPort := splitParts(rawPort) + proto, containerPort = SplitProtoPort(containerPort) + + // Strip [] from IPV6 addresses + ip, _, err := net.SplitHostPort(rawIP + ":") + if err != nil { + return nil, fmt.Errorf("Invalid ip address %v: %s", rawIP, err) + } + if ip != "" && net.ParseIP(ip) == nil { + return nil, fmt.Errorf("Invalid ip address: %s", ip) + } + if containerPort == "" { + return nil, fmt.Errorf("No port specified: %s", rawPort) + } + + startPort, endPort, err := ParsePortRange(containerPort) + if err != nil { + return nil, fmt.Errorf("Invalid containerPort: %s", containerPort) + } + + var startHostPort, endHostPort uint64 = 0, 0 + if len(hostPort) > 0 { + startHostPort, endHostPort, err = ParsePortRange(hostPort) + if err != nil { + return nil, fmt.Errorf("Invalid hostPort: %s", hostPort) + } + } + + if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) { + // Allow host port range iff containerPort is not a range. + // In this case, use the host port range as the dynamic + // host port range to allocate into. + if endPort != startPort { + return nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort) + } + } + + if !validateProto(strings.ToLower(proto)) { + return nil, fmt.Errorf("Invalid proto: %s", proto) + } + + ports := []PortMapping{} + for i := uint64(0); i <= (endPort - startPort); i++ { + containerPort = strconv.FormatUint(startPort+i, 10) + if len(hostPort) > 0 { + hostPort = strconv.FormatUint(startHostPort+i, 10) + } + // Set hostPort to a range only if there is a single container port + // and a dynamic host port. + if startPort == endPort && startHostPort != endHostPort { + hostPort = fmt.Sprintf("%s-%s", hostPort, strconv.FormatUint(endHostPort, 10)) + } + port, err := NewPort(strings.ToLower(proto), containerPort) + if err != nil { + return nil, err + } + + binding := PortBinding{ + HostIP: ip, + HostPort: hostPort, + } + ports = append(ports, PortMapping{Port: port, Binding: binding}) + } + return ports, nil +} diff --git a/vendor/github.com/docker/go-connections/nat/parse.go b/vendor/github.com/docker/go-connections/nat/parse.go new file mode 100644 index 000000000..892adf8c6 --- /dev/null +++ b/vendor/github.com/docker/go-connections/nat/parse.go @@ -0,0 +1,57 @@ +package nat + +import ( + "fmt" + "strconv" + "strings" +) + +// PartParser parses and validates the specified string (data) using the specified template +// e.g. ip:public:private -> 192.168.0.1:80:8000 +// DEPRECATED: do not use, this function may be removed in a future version +func PartParser(template, data string) (map[string]string, error) { + // ip:public:private + var ( + templateParts = strings.Split(template, ":") + parts = strings.Split(data, ":") + out = make(map[string]string, len(templateParts)) + ) + if len(parts) != len(templateParts) { + return nil, fmt.Errorf("Invalid format to parse. %s should match template %s", data, template) + } + + for i, t := range templateParts { + value := "" + if len(parts) > i { + value = parts[i] + } + out[t] = value + } + return out, nil +} + +// ParsePortRange parses and validates the specified string as a port-range (8000-9000) +func ParsePortRange(ports string) (uint64, uint64, error) { + if ports == "" { + return 0, 0, fmt.Errorf("Empty string specified for ports.") + } + if !strings.Contains(ports, "-") { + start, err := strconv.ParseUint(ports, 10, 16) + end := start + return start, end, err + } + + parts := strings.Split(ports, "-") + start, err := strconv.ParseUint(parts[0], 10, 16) + if err != nil { + return 0, 0, err + } + end, err := strconv.ParseUint(parts[1], 10, 16) + if err != nil { + return 0, 0, err + } + if end < start { + return 0, 0, fmt.Errorf("Invalid range specified for the Port: %s", ports) + } + return start, end, nil +} diff --git a/vendor/github.com/docker/go-connections/nat/sort.go b/vendor/github.com/docker/go-connections/nat/sort.go new file mode 100644 index 000000000..ce950171e --- /dev/null +++ b/vendor/github.com/docker/go-connections/nat/sort.go @@ -0,0 +1,96 @@ +package nat + +import ( + "sort" + "strings" +) + +type portSorter struct { + ports []Port + by func(i, j Port) bool +} + +func (s *portSorter) Len() int { + return len(s.ports) +} + +func (s *portSorter) Swap(i, j int) { + s.ports[i], s.ports[j] = s.ports[j], s.ports[i] +} + +func (s *portSorter) Less(i, j int) bool { + ip := s.ports[i] + jp := s.ports[j] + + return s.by(ip, jp) +} + +// Sort sorts a list of ports using the provided predicate +// This function should compare `i` and `j`, returning true if `i` is +// considered to be less than `j` +func Sort(ports []Port, predicate func(i, j Port) bool) { + s := &portSorter{ports, predicate} + sort.Sort(s) +} + +type portMapEntry struct { + port Port + binding PortBinding +} + +type portMapSorter []portMapEntry + +func (s portMapSorter) Len() int { return len(s) } +func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// sort the port so that the order is: +// 1. port with larger specified bindings +// 2. larger port +// 3. port with tcp protocol +func (s portMapSorter) Less(i, j int) bool { + pi, pj := s[i].port, s[j].port + hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort) + return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp") +} + +// SortPortMap sorts the list of ports and their respected mapping. The ports +// will explicit HostPort will be placed first. +func SortPortMap(ports []Port, bindings PortMap) { + s := portMapSorter{} + for _, p := range ports { + if binding, ok := bindings[p]; ok { + for _, b := range binding { + s = append(s, portMapEntry{port: p, binding: b}) + } + bindings[p] = []PortBinding{} + } else { + s = append(s, portMapEntry{port: p}) + } + } + + sort.Sort(s) + var ( + i int + pm = make(map[Port]struct{}) + ) + // reorder ports + for _, entry := range s { + if _, ok := pm[entry.port]; !ok { + ports[i] = entry.port + pm[entry.port] = struct{}{} + i++ + } + // reorder bindings for this port + if _, ok := bindings[entry.port]; ok { + bindings[entry.port] = append(bindings[entry.port], entry.binding) + } + } +} + +func toInt(s string) uint64 { + i, _, err := ParsePortRange(s) + if err != nil { + i = 0 + } + return i +} diff --git a/vendor/github.com/docker/go-units/CONTRIBUTING.md b/vendor/github.com/docker/go-units/CONTRIBUTING.md new file mode 100644 index 000000000..9ea86d784 --- /dev/null +++ b/vendor/github.com/docker/go-units/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# Contributing to go-units + +Want to hack on go-units? Awesome! Here are instructions to get you started. + +go-units is a part of the [Docker](https://www.docker.com) project, and follows +the same rules and principles. If you're already familiar with the way +Docker does things, you'll feel right at home. + +Otherwise, go read Docker's +[contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), +[issue triaging](https://github.com/docker/docker/blob/master/project/ISSUE-TRIAGE.md), +[review process](https://github.com/docker/docker/blob/master/project/REVIEWING.md) and +[branches and tags](https://github.com/docker/docker/blob/master/project/BRANCHES-AND-TAGS.md). + +### Sign your work + +The sign-off is a simple line at the end of the explanation for the patch. Your +signature certifies that you wrote the patch or otherwise have the right to pass +it on as an open-source patch. The rules are pretty simple: if you can certify +the below (from [developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +Then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +If you set your `user.name` and `user.email` git configs, you can sign your +commit automatically with `git commit -s`. diff --git a/vendor/github.com/docker/go-units/LICENSE b/vendor/github.com/docker/go-units/LICENSE new file mode 100644 index 000000000..b55b37bc3 --- /dev/null +++ b/vendor/github.com/docker/go-units/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/docker/go-units/MAINTAINERS b/vendor/github.com/docker/go-units/MAINTAINERS new file mode 100644 index 000000000..9b3b6b101 --- /dev/null +++ b/vendor/github.com/docker/go-units/MAINTAINERS @@ -0,0 +1,46 @@ +# go-units maintainers file +# +# This file describes who runs the docker/go-units project and how. +# This is a living document - if you see something out of date or missing, speak up! +# +# It is structured to be consumable by both humans and programs. +# To extract its contents programmatically, use any TOML-compliant parser. +# +# This file is compiled into the MAINTAINERS file in docker/opensource. +# +[Org] + [Org."Core maintainers"] + people = [ + "akihirosuda", + "dnephin", + "thajeztah", + "vdemeester", + ] + +[people] + +# A reference list of all people associated with the project. +# All other sections should refer to people by their canonical key +# in the people section. + + # ADD YOURSELF HERE IN ALPHABETICAL ORDER + + [people.akihirosuda] + Name = "Akihiro Suda" + Email = "suda.akihiro@lab.ntt.co.jp" + GitHub = "AkihiroSuda" + + [people.dnephin] + Name = "Daniel Nephin" + Email = "dnephin@gmail.com" + GitHub = "dnephin" + + [people.thajeztah] + Name = "Sebastiaan van Stijn" + Email = "github@gone.nl" + GitHub = "thaJeztah" + + [people.vdemeester] + Name = "Vincent Demeester" + Email = "vincent@sbr.pm" + GitHub = "vdemeester" \ No newline at end of file diff --git a/vendor/github.com/docker/go-units/README.md b/vendor/github.com/docker/go-units/README.md new file mode 100644 index 000000000..4f70a4e13 --- /dev/null +++ b/vendor/github.com/docker/go-units/README.md @@ -0,0 +1,16 @@ +[![GoDoc](https://godoc.org/github.com/docker/go-units?status.svg)](https://godoc.org/github.com/docker/go-units) + +# Introduction + +go-units is a library to transform human friendly measurements into machine friendly values. + +## Usage + +See the [docs in godoc](https://godoc.org/github.com/docker/go-units) for examples and documentation. + +## Copyright and license + +Copyright © 2015 Docker, Inc. + +go-units is licensed under the Apache License, Version 2.0. +See [LICENSE](LICENSE) for the full text of the license. diff --git a/vendor/github.com/docker/go-units/circle.yml b/vendor/github.com/docker/go-units/circle.yml new file mode 100644 index 000000000..9043b3547 --- /dev/null +++ b/vendor/github.com/docker/go-units/circle.yml @@ -0,0 +1,11 @@ +dependencies: + post: + # install golint + - go get github.com/golang/lint/golint + +test: + pre: + # run analysis before tests + - go vet ./... + - test -z "$(golint ./... | tee /dev/stderr)" + - test -z "$(gofmt -s -l . | tee /dev/stderr)" diff --git a/vendor/github.com/docker/go-units/duration.go b/vendor/github.com/docker/go-units/duration.go new file mode 100644 index 000000000..ba02af26d --- /dev/null +++ b/vendor/github.com/docker/go-units/duration.go @@ -0,0 +1,35 @@ +// Package units provides helper function to parse and print size and time units +// in human-readable format. +package units + +import ( + "fmt" + "time" +) + +// HumanDuration returns a human-readable approximation of a duration +// (eg. "About a minute", "4 hours ago", etc.). +func HumanDuration(d time.Duration) string { + if seconds := int(d.Seconds()); seconds < 1 { + return "Less than a second" + } else if seconds == 1 { + return "1 second" + } else if seconds < 60 { + return fmt.Sprintf("%d seconds", seconds) + } else if minutes := int(d.Minutes()); minutes == 1 { + return "About a minute" + } else if minutes < 46 { + return fmt.Sprintf("%d minutes", minutes) + } else if hours := int(d.Hours() + 0.5); hours == 1 { + return "About an hour" + } else if hours < 48 { + return fmt.Sprintf("%d hours", hours) + } else if hours < 24*7*2 { + return fmt.Sprintf("%d days", hours/24) + } else if hours < 24*30*2 { + return fmt.Sprintf("%d weeks", hours/24/7) + } else if hours < 24*365*2 { + return fmt.Sprintf("%d months", hours/24/30) + } + return fmt.Sprintf("%d years", int(d.Hours())/24/365) +} diff --git a/vendor/github.com/docker/go-units/size.go b/vendor/github.com/docker/go-units/size.go new file mode 100644 index 000000000..85f6ab071 --- /dev/null +++ b/vendor/github.com/docker/go-units/size.go @@ -0,0 +1,108 @@ +package units + +import ( + "fmt" + "regexp" + "strconv" + "strings" +) + +// See: http://en.wikipedia.org/wiki/Binary_prefix +const ( + // Decimal + + KB = 1000 + MB = 1000 * KB + GB = 1000 * MB + TB = 1000 * GB + PB = 1000 * TB + + // Binary + + KiB = 1024 + MiB = 1024 * KiB + GiB = 1024 * MiB + TiB = 1024 * GiB + PiB = 1024 * TiB +) + +type unitMap map[string]int64 + +var ( + decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB} + binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB} + sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[iI]?[bB]?$`) +) + +var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"} +var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"} + +func getSizeAndUnit(size float64, base float64, _map []string) (float64, string) { + i := 0 + unitsLimit := len(_map) - 1 + for size >= base && i < unitsLimit { + size = size / base + i++ + } + return size, _map[i] +} + +// CustomSize returns a human-readable approximation of a size +// using custom format. +func CustomSize(format string, size float64, base float64, _map []string) string { + size, unit := getSizeAndUnit(size, base, _map) + return fmt.Sprintf(format, size, unit) +} + +// HumanSizeWithPrecision allows the size to be in any precision, +// instead of 4 digit precision used in units.HumanSize. +func HumanSizeWithPrecision(size float64, precision int) string { + size, unit := getSizeAndUnit(size, 1000.0, decimapAbbrs) + return fmt.Sprintf("%.*g%s", precision, size, unit) +} + +// HumanSize returns a human-readable approximation of a size +// capped at 4 valid numbers (eg. "2.746 MB", "796 KB"). +func HumanSize(size float64) string { + return HumanSizeWithPrecision(size, 4) +} + +// BytesSize returns a human-readable size in bytes, kibibytes, +// mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB"). +func BytesSize(size float64) string { + return CustomSize("%.4g%s", size, 1024.0, binaryAbbrs) +} + +// FromHumanSize returns an integer from a human-readable specification of a +// size using SI standard (eg. "44kB", "17MB"). +func FromHumanSize(size string) (int64, error) { + return parseSize(size, decimalMap) +} + +// RAMInBytes parses a human-readable string representing an amount of RAM +// in bytes, kibibytes, mebibytes, gibibytes, or tebibytes and +// returns the number of bytes, or -1 if the string is unparseable. +// Units are case-insensitive, and the 'b' suffix is optional. +func RAMInBytes(size string) (int64, error) { + return parseSize(size, binaryMap) +} + +// Parses the human-readable size string into the amount it represents. +func parseSize(sizeStr string, uMap unitMap) (int64, error) { + matches := sizeRegex.FindStringSubmatch(sizeStr) + if len(matches) != 4 { + return -1, fmt.Errorf("invalid size: '%s'", sizeStr) + } + + size, err := strconv.ParseFloat(matches[1], 64) + if err != nil { + return -1, err + } + + unitPrefix := strings.ToLower(matches[3]) + if mul, ok := uMap[unitPrefix]; ok { + size *= float64(mul) + } + + return int64(size), nil +} diff --git a/vendor/github.com/docker/go-units/ulimit.go b/vendor/github.com/docker/go-units/ulimit.go new file mode 100644 index 000000000..5ac7fd825 --- /dev/null +++ b/vendor/github.com/docker/go-units/ulimit.go @@ -0,0 +1,118 @@ +package units + +import ( + "fmt" + "strconv" + "strings" +) + +// Ulimit is a human friendly version of Rlimit. +type Ulimit struct { + Name string + Hard int64 + Soft int64 +} + +// Rlimit specifies the resource limits, such as max open files. +type Rlimit struct { + Type int `json:"type,omitempty"` + Hard uint64 `json:"hard,omitempty"` + Soft uint64 `json:"soft,omitempty"` +} + +const ( + // magic numbers for making the syscall + // some of these are defined in the syscall package, but not all. + // Also since Windows client doesn't get access to the syscall package, need to + // define these here + rlimitAs = 9 + rlimitCore = 4 + rlimitCPU = 0 + rlimitData = 2 + rlimitFsize = 1 + rlimitLocks = 10 + rlimitMemlock = 8 + rlimitMsgqueue = 12 + rlimitNice = 13 + rlimitNofile = 7 + rlimitNproc = 6 + rlimitRss = 5 + rlimitRtprio = 14 + rlimitRttime = 15 + rlimitSigpending = 11 + rlimitStack = 3 +) + +var ulimitNameMapping = map[string]int{ + //"as": rlimitAs, // Disabled since this doesn't seem usable with the way Docker inits a container. + "core": rlimitCore, + "cpu": rlimitCPU, + "data": rlimitData, + "fsize": rlimitFsize, + "locks": rlimitLocks, + "memlock": rlimitMemlock, + "msgqueue": rlimitMsgqueue, + "nice": rlimitNice, + "nofile": rlimitNofile, + "nproc": rlimitNproc, + "rss": rlimitRss, + "rtprio": rlimitRtprio, + "rttime": rlimitRttime, + "sigpending": rlimitSigpending, + "stack": rlimitStack, +} + +// ParseUlimit parses and returns a Ulimit from the specified string. +func ParseUlimit(val string) (*Ulimit, error) { + parts := strings.SplitN(val, "=", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("invalid ulimit argument: %s", val) + } + + if _, exists := ulimitNameMapping[parts[0]]; !exists { + return nil, fmt.Errorf("invalid ulimit type: %s", parts[0]) + } + + var ( + soft int64 + hard = &soft // default to soft in case no hard was set + temp int64 + err error + ) + switch limitVals := strings.Split(parts[1], ":"); len(limitVals) { + case 2: + temp, err = strconv.ParseInt(limitVals[1], 10, 64) + if err != nil { + return nil, err + } + hard = &temp + fallthrough + case 1: + soft, err = strconv.ParseInt(limitVals[0], 10, 64) + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1]) + } + + if soft > *hard { + return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: %d > %d", soft, *hard) + } + + return &Ulimit{Name: parts[0], Soft: soft, Hard: *hard}, nil +} + +// GetRlimit returns the RLimit corresponding to Ulimit. +func (u *Ulimit) GetRlimit() (*Rlimit, error) { + t, exists := ulimitNameMapping[u.Name] + if !exists { + return nil, fmt.Errorf("invalid ulimit name %s", u.Name) + } + + return &Rlimit{Type: t, Soft: uint64(u.Soft), Hard: uint64(u.Hard)}, nil +} + +func (u *Ulimit) String() string { + return fmt.Sprintf("%s=%d:%d", u.Name, u.Soft, u.Hard) +} diff --git a/vendor/github.com/docker/libnetwork/LICENSE b/vendor/github.com/docker/libnetwork/LICENSE new file mode 100644 index 000000000..e06d20818 --- /dev/null +++ b/vendor/github.com/docker/libnetwork/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/docker/libnetwork/client/mflag/LICENSE b/vendor/github.com/docker/libnetwork/client/mflag/LICENSE new file mode 100644 index 000000000..9b4f4a294 --- /dev/null +++ b/vendor/github.com/docker/libnetwork/client/mflag/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014-2016 The Docker & Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/docker/libnetwork/ipamutils/utils.go b/vendor/github.com/docker/libnetwork/ipamutils/utils.go new file mode 100644 index 000000000..f8eca58e8 --- /dev/null +++ b/vendor/github.com/docker/libnetwork/ipamutils/utils.go @@ -0,0 +1,96 @@ +// Package ipamutils provides utility functions for ipam management +package ipamutils + +import ( + "fmt" + "net" + "sync" + + "github.com/sirupsen/logrus" +) + +var ( + // PredefinedBroadNetworks contains a list of 31 IPv4 private networks with host size 16 and 12 + // (172.17-31.x.x/16, 192.168.x.x/20) which do not overlap with the networks in `PredefinedGranularNetworks` + PredefinedBroadNetworks []*net.IPNet + // PredefinedGranularNetworks contains a list of 64K IPv4 private networks with host size 8 + // (10.x.x.x/24) which do not overlap with the networks in `PredefinedBroadNetworks` + PredefinedGranularNetworks []*net.IPNet + initNetworksOnce sync.Once + + defaultBroadNetwork = []*NetworkToSplit{{"172.17.0.0/16", 16}, {"172.18.0.0/16", 16}, {"172.19.0.0/16", 16}, + {"172.20.0.0/14", 16}, {"172.24.0.0/14", 16}, {"172.28.0.0/14", 16}, + {"192.168.0.0/16", 20}} + defaultGranularNetwork = []*NetworkToSplit{{"10.0.0.0/8", 24}} +) + +// NetworkToSplit represent a network that has to be split in chunks with mask length Size. +// Each subnet in the set is derived from the Base pool. Base is to be passed +// in CIDR format. +// Example: a Base "10.10.0.0/16 with Size 24 will define the set of 256 +// 10.10.[0-255].0/24 address pools +type NetworkToSplit struct { + Base string `json:"base"` + Size int `json:"size"` +} + +// InitNetworks initializes the broad network pool and the granular network pool +func InitNetworks(defaultAddressPool []*NetworkToSplit) { + initNetworksOnce.Do(func() { + // error ingnored should never fail + PredefinedGranularNetworks, _ = splitNetworks(defaultGranularNetwork) + if defaultAddressPool == nil { + defaultAddressPool = defaultBroadNetwork + } + var err error + if PredefinedBroadNetworks, err = splitNetworks(defaultAddressPool); err != nil { + logrus.WithError(err).Error("InitAddressPools failed to initialize the default address pool") + } + }) +} + +// splitNetworks takes a slice of networks, split them accordingly and returns them +func splitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) { + localPools := make([]*net.IPNet, 0, len(list)) + + for _, p := range list { + _, b, err := net.ParseCIDR(p.Base) + if err != nil { + return nil, fmt.Errorf("invalid base pool %q: %v", p.Base, err) + } + ones, _ := b.Mask.Size() + if p.Size <= 0 || p.Size < ones { + return nil, fmt.Errorf("invalid pools size: %d", p.Size) + } + localPools = append(localPools, splitNetwork(p.Size, b)...) + } + return localPools, nil +} + +func splitNetwork(size int, base *net.IPNet) []*net.IPNet { + one, bits := base.Mask.Size() + mask := net.CIDRMask(size, bits) + n := 1 << uint(size-one) + s := uint(bits - size) + list := make([]*net.IPNet, 0, n) + + for i := 0; i < n; i++ { + ip := copyIP(base.IP) + addIntToIP(ip, uint(i<= 0; i-- { + array[i] |= (byte)(ordinal & 0xff) + ordinal >>= 8 + } +} diff --git a/vendor/github.com/docker/spdystream/CONTRIBUTING.md b/vendor/github.com/docker/spdystream/CONTRIBUTING.md new file mode 100644 index 000000000..d4eddcc53 --- /dev/null +++ b/vendor/github.com/docker/spdystream/CONTRIBUTING.md @@ -0,0 +1,13 @@ +# Contributing to SpdyStream + +Want to hack on spdystream? Awesome! Here are instructions to get you +started. + +SpdyStream is a part of the [Docker](https://docker.io) project, and follows +the same rules and principles. If you're already familiar with the way +Docker does things, you'll feel right at home. + +Otherwise, go read +[Docker's contributions guidelines](https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md). + +Happy hacking! diff --git a/vendor/github.com/docker/spdystream/LICENSE b/vendor/github.com/docker/spdystream/LICENSE new file mode 100644 index 000000000..9e4bd4dbe --- /dev/null +++ b/vendor/github.com/docker/spdystream/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2014-2015 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/docker/spdystream/LICENSE.docs b/vendor/github.com/docker/spdystream/LICENSE.docs new file mode 100644 index 000000000..e26cd4fc8 --- /dev/null +++ b/vendor/github.com/docker/spdystream/LICENSE.docs @@ -0,0 +1,425 @@ +Attribution-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-ShareAlike 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-ShareAlike 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + + including for purposes of Section 3(b); and + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public +licenses to material it publishes and in those instances will be +considered the "Licensor." Except for the limited purpose of indicating +that material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the public +licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/vendor/github.com/docker/spdystream/MAINTAINERS b/vendor/github.com/docker/spdystream/MAINTAINERS new file mode 100644 index 000000000..14e263325 --- /dev/null +++ b/vendor/github.com/docker/spdystream/MAINTAINERS @@ -0,0 +1,28 @@ +# Spdystream maintainers file +# +# This file describes who runs the docker/spdystream project and how. +# This is a living document - if you see something out of date or missing, speak up! +# +# It is structured to be consumable by both humans and programs. +# To extract its contents programmatically, use any TOML-compliant parser. +# +# This file is compiled into the MAINTAINERS file in docker/opensource. +# +[Org] + [Org."Core maintainers"] + people = [ + "dmcgowan", + ] + +[people] + +# A reference list of all people associated with the project. +# All other sections should refer to people by their canonical key +# in the people section. + + # ADD YOURSELF HERE IN ALPHABETICAL ORDER + + [people.dmcgowan] + Name = "Derek McGowan" + Email = "derek@docker.com" + GitHub = "dmcgowan" diff --git a/vendor/github.com/docker/spdystream/README.md b/vendor/github.com/docker/spdystream/README.md new file mode 100644 index 000000000..11cccd0a0 --- /dev/null +++ b/vendor/github.com/docker/spdystream/README.md @@ -0,0 +1,77 @@ +# SpdyStream + +A multiplexed stream library using spdy + +## Usage + +Client example (connecting to mirroring server without auth) + +```go +package main + +import ( + "fmt" + "github.com/docker/spdystream" + "net" + "net/http" +) + +func main() { + conn, err := net.Dial("tcp", "localhost:8080") + if err != nil { + panic(err) + } + spdyConn, err := spdystream.NewConnection(conn, false) + if err != nil { + panic(err) + } + go spdyConn.Serve(spdystream.NoOpStreamHandler) + stream, err := spdyConn.CreateStream(http.Header{}, nil, false) + if err != nil { + panic(err) + } + + stream.Wait() + + fmt.Fprint(stream, "Writing to stream") + + buf := make([]byte, 25) + stream.Read(buf) + fmt.Println(string(buf)) + + stream.Close() +} +``` + +Server example (mirroring server without auth) + +```go +package main + +import ( + "github.com/docker/spdystream" + "net" +) + +func main() { + listener, err := net.Listen("tcp", "localhost:8080") + if err != nil { + panic(err) + } + for { + conn, err := listener.Accept() + if err != nil { + panic(err) + } + spdyConn, err := spdystream.NewConnection(conn, true) + if err != nil { + panic(err) + } + go spdyConn.Serve(spdystream.MirrorStreamHandler) + } +} +``` + +## Copyright and license + +Copyright © 2014-2015 Docker, Inc. All rights reserved, except as follows. Code is released under the Apache 2.0 license. The README.md file, and files in the "docs" folder are licensed under the Creative Commons Attribution 4.0 International License under the terms and conditions set forth in the file "LICENSE.docs". You may obtain a duplicate copy of the same license, titled CC-BY-SA-4.0, at http://creativecommons.org/licenses/by/4.0/. diff --git a/vendor/github.com/docker/spdystream/connection.go b/vendor/github.com/docker/spdystream/connection.go new file mode 100644 index 000000000..2023ecf84 --- /dev/null +++ b/vendor/github.com/docker/spdystream/connection.go @@ -0,0 +1,959 @@ +package spdystream + +import ( + "errors" + "fmt" + "io" + "net" + "net/http" + "sync" + "time" + + "github.com/docker/spdystream/spdy" +) + +var ( + ErrInvalidStreamId = errors.New("Invalid stream id") + ErrTimeout = errors.New("Timeout occurred") + ErrReset = errors.New("Stream reset") + ErrWriteClosedStream = errors.New("Write on closed stream") +) + +const ( + FRAME_WORKERS = 5 + QUEUE_SIZE = 50 +) + +type StreamHandler func(stream *Stream) + +type AuthHandler func(header http.Header, slot uint8, parent uint32) bool + +type idleAwareFramer struct { + f *spdy.Framer + conn *Connection + writeLock sync.Mutex + resetChan chan struct{} + setTimeoutLock sync.Mutex + setTimeoutChan chan time.Duration + timeout time.Duration +} + +func newIdleAwareFramer(framer *spdy.Framer) *idleAwareFramer { + iaf := &idleAwareFramer{ + f: framer, + resetChan: make(chan struct{}, 2), + // setTimeoutChan needs to be buffered to avoid deadlocks when calling setIdleTimeout at about + // the same time the connection is being closed + setTimeoutChan: make(chan time.Duration, 1), + } + return iaf +} + +func (i *idleAwareFramer) monitor() { + var ( + timer *time.Timer + expired <-chan time.Time + resetChan = i.resetChan + setTimeoutChan = i.setTimeoutChan + ) +Loop: + for { + select { + case timeout := <-i.setTimeoutChan: + i.timeout = timeout + if timeout == 0 { + if timer != nil { + timer.Stop() + } + } else { + if timer == nil { + timer = time.NewTimer(timeout) + expired = timer.C + } else { + timer.Reset(timeout) + } + } + case <-resetChan: + if timer != nil && i.timeout > 0 { + timer.Reset(i.timeout) + } + case <-expired: + i.conn.streamCond.L.Lock() + streams := i.conn.streams + i.conn.streams = make(map[spdy.StreamId]*Stream) + i.conn.streamCond.Broadcast() + i.conn.streamCond.L.Unlock() + go func() { + for _, stream := range streams { + stream.resetStream() + } + i.conn.Close() + }() + case <-i.conn.closeChan: + if timer != nil { + timer.Stop() + } + + // Start a goroutine to drain resetChan. This is needed because we've seen + // some unit tests with large numbers of goroutines get into a situation + // where resetChan fills up, at least 1 call to Write() is still trying to + // send to resetChan, the connection gets closed, and this case statement + // attempts to grab the write lock that Write() already has, causing a + // deadlock. + // + // See https://github.com/docker/spdystream/issues/49 for more details. + go func() { + for _ = range resetChan { + } + }() + + go func() { + for _ = range setTimeoutChan { + } + }() + + i.writeLock.Lock() + close(resetChan) + i.resetChan = nil + i.writeLock.Unlock() + + i.setTimeoutLock.Lock() + close(i.setTimeoutChan) + i.setTimeoutChan = nil + i.setTimeoutLock.Unlock() + + break Loop + } + } + + // Drain resetChan + for _ = range resetChan { + } +} + +func (i *idleAwareFramer) WriteFrame(frame spdy.Frame) error { + i.writeLock.Lock() + defer i.writeLock.Unlock() + if i.resetChan == nil { + return io.EOF + } + err := i.f.WriteFrame(frame) + if err != nil { + return err + } + + i.resetChan <- struct{}{} + + return nil +} + +func (i *idleAwareFramer) ReadFrame() (spdy.Frame, error) { + frame, err := i.f.ReadFrame() + if err != nil { + return nil, err + } + + // resetChan should never be closed since it is only closed + // when the connection has closed its closeChan. This closure + // only occurs after all Reads have finished + // TODO (dmcgowan): refactor relationship into connection + i.resetChan <- struct{}{} + + return frame, nil +} + +func (i *idleAwareFramer) setIdleTimeout(timeout time.Duration) { + i.setTimeoutLock.Lock() + defer i.setTimeoutLock.Unlock() + + if i.setTimeoutChan == nil { + return + } + + i.setTimeoutChan <- timeout +} + +type Connection struct { + conn net.Conn + framer *idleAwareFramer + + closeChan chan bool + goneAway bool + lastStreamChan chan<- *Stream + goAwayTimeout time.Duration + closeTimeout time.Duration + + streamLock *sync.RWMutex + streamCond *sync.Cond + streams map[spdy.StreamId]*Stream + + nextIdLock sync.Mutex + receiveIdLock sync.Mutex + nextStreamId spdy.StreamId + receivedStreamId spdy.StreamId + + pingIdLock sync.Mutex + pingId uint32 + pingChans map[uint32]chan error + + shutdownLock sync.Mutex + shutdownChan chan error + hasShutdown bool + + // for testing https://github.com/docker/spdystream/pull/56 + dataFrameHandler func(*spdy.DataFrame) error +} + +// NewConnection creates a new spdy connection from an existing +// network connection. +func NewConnection(conn net.Conn, server bool) (*Connection, error) { + framer, framerErr := spdy.NewFramer(conn, conn) + if framerErr != nil { + return nil, framerErr + } + idleAwareFramer := newIdleAwareFramer(framer) + var sid spdy.StreamId + var rid spdy.StreamId + var pid uint32 + if server { + sid = 2 + rid = 1 + pid = 2 + } else { + sid = 1 + rid = 2 + pid = 1 + } + + streamLock := new(sync.RWMutex) + streamCond := sync.NewCond(streamLock) + + session := &Connection{ + conn: conn, + framer: idleAwareFramer, + + closeChan: make(chan bool), + goAwayTimeout: time.Duration(0), + closeTimeout: time.Duration(0), + + streamLock: streamLock, + streamCond: streamCond, + streams: make(map[spdy.StreamId]*Stream), + nextStreamId: sid, + receivedStreamId: rid, + + pingId: pid, + pingChans: make(map[uint32]chan error), + + shutdownChan: make(chan error), + } + session.dataFrameHandler = session.handleDataFrame + idleAwareFramer.conn = session + go idleAwareFramer.monitor() + + return session, nil +} + +// Ping sends a ping frame across the connection and +// returns the response time +func (s *Connection) Ping() (time.Duration, error) { + pid := s.pingId + s.pingIdLock.Lock() + if s.pingId > 0x7ffffffe { + s.pingId = s.pingId - 0x7ffffffe + } else { + s.pingId = s.pingId + 2 + } + s.pingIdLock.Unlock() + pingChan := make(chan error) + s.pingChans[pid] = pingChan + defer delete(s.pingChans, pid) + + frame := &spdy.PingFrame{Id: pid} + startTime := time.Now() + writeErr := s.framer.WriteFrame(frame) + if writeErr != nil { + return time.Duration(0), writeErr + } + select { + case <-s.closeChan: + return time.Duration(0), errors.New("connection closed") + case err, ok := <-pingChan: + if ok && err != nil { + return time.Duration(0), err + } + break + } + return time.Now().Sub(startTime), nil +} + +// Serve handles frames sent from the server, including reply frames +// which are needed to fully initiate connections. Both clients and servers +// should call Serve in a separate goroutine before creating streams. +func (s *Connection) Serve(newHandler StreamHandler) { + // use a WaitGroup to wait for all frames to be drained after receiving + // go-away. + var wg sync.WaitGroup + + // Parition queues to ensure stream frames are handled + // by the same worker, ensuring order is maintained + frameQueues := make([]*PriorityFrameQueue, FRAME_WORKERS) + for i := 0; i < FRAME_WORKERS; i++ { + frameQueues[i] = NewPriorityFrameQueue(QUEUE_SIZE) + + // Ensure frame queue is drained when connection is closed + go func(frameQueue *PriorityFrameQueue) { + <-s.closeChan + frameQueue.Drain() + }(frameQueues[i]) + + wg.Add(1) + go func(frameQueue *PriorityFrameQueue) { + // let the WaitGroup know this worker is done + defer wg.Done() + + s.frameHandler(frameQueue, newHandler) + }(frameQueues[i]) + } + + var ( + partitionRoundRobin int + goAwayFrame *spdy.GoAwayFrame + ) +Loop: + for { + readFrame, err := s.framer.ReadFrame() + if err != nil { + if err != io.EOF { + debugMessage("frame read error: %s", err) + } else { + debugMessage("(%p) EOF received", s) + } + break + } + var priority uint8 + var partition int + switch frame := readFrame.(type) { + case *spdy.SynStreamFrame: + if s.checkStreamFrame(frame) { + priority = frame.Priority + partition = int(frame.StreamId % FRAME_WORKERS) + debugMessage("(%p) Add stream frame: %d ", s, frame.StreamId) + s.addStreamFrame(frame) + } else { + debugMessage("(%p) Rejected stream frame: %d ", s, frame.StreamId) + continue + } + case *spdy.SynReplyFrame: + priority = s.getStreamPriority(frame.StreamId) + partition = int(frame.StreamId % FRAME_WORKERS) + case *spdy.DataFrame: + priority = s.getStreamPriority(frame.StreamId) + partition = int(frame.StreamId % FRAME_WORKERS) + case *spdy.RstStreamFrame: + priority = s.getStreamPriority(frame.StreamId) + partition = int(frame.StreamId % FRAME_WORKERS) + case *spdy.HeadersFrame: + priority = s.getStreamPriority(frame.StreamId) + partition = int(frame.StreamId % FRAME_WORKERS) + case *spdy.PingFrame: + priority = 0 + partition = partitionRoundRobin + partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS + case *spdy.GoAwayFrame: + // hold on to the go away frame and exit the loop + goAwayFrame = frame + break Loop + default: + priority = 7 + partition = partitionRoundRobin + partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS + } + frameQueues[partition].Push(readFrame, priority) + } + close(s.closeChan) + + // wait for all frame handler workers to indicate they've drained their queues + // before handling the go away frame + wg.Wait() + + if goAwayFrame != nil { + s.handleGoAwayFrame(goAwayFrame) + } + + // now it's safe to close remote channels and empty s.streams + s.streamCond.L.Lock() + // notify streams that they're now closed, which will + // unblock any stream Read() calls + for _, stream := range s.streams { + stream.closeRemoteChannels() + } + s.streams = make(map[spdy.StreamId]*Stream) + s.streamCond.Broadcast() + s.streamCond.L.Unlock() +} + +func (s *Connection) frameHandler(frameQueue *PriorityFrameQueue, newHandler StreamHandler) { + for { + popFrame := frameQueue.Pop() + if popFrame == nil { + return + } + + var frameErr error + switch frame := popFrame.(type) { + case *spdy.SynStreamFrame: + frameErr = s.handleStreamFrame(frame, newHandler) + case *spdy.SynReplyFrame: + frameErr = s.handleReplyFrame(frame) + case *spdy.DataFrame: + frameErr = s.dataFrameHandler(frame) + case *spdy.RstStreamFrame: + frameErr = s.handleResetFrame(frame) + case *spdy.HeadersFrame: + frameErr = s.handleHeaderFrame(frame) + case *spdy.PingFrame: + frameErr = s.handlePingFrame(frame) + case *spdy.GoAwayFrame: + frameErr = s.handleGoAwayFrame(frame) + default: + frameErr = fmt.Errorf("unhandled frame type: %T", frame) + } + + if frameErr != nil { + debugMessage("frame handling error: %s", frameErr) + } + } +} + +func (s *Connection) getStreamPriority(streamId spdy.StreamId) uint8 { + stream, streamOk := s.getStream(streamId) + if !streamOk { + return 7 + } + return stream.priority +} + +func (s *Connection) addStreamFrame(frame *spdy.SynStreamFrame) { + var parent *Stream + if frame.AssociatedToStreamId != spdy.StreamId(0) { + parent, _ = s.getStream(frame.AssociatedToStreamId) + } + + stream := &Stream{ + streamId: frame.StreamId, + parent: parent, + conn: s, + startChan: make(chan error), + headers: frame.Headers, + finished: (frame.CFHeader.Flags & spdy.ControlFlagUnidirectional) != 0x00, + replyCond: sync.NewCond(new(sync.Mutex)), + dataChan: make(chan []byte), + headerChan: make(chan http.Header), + closeChan: make(chan bool), + priority: frame.Priority, + } + if frame.CFHeader.Flags&spdy.ControlFlagFin != 0x00 { + stream.closeRemoteChannels() + } + + s.addStream(stream) +} + +// checkStreamFrame checks to see if a stream frame is allowed. +// If the stream is invalid, then a reset frame with protocol error +// will be returned. +func (s *Connection) checkStreamFrame(frame *spdy.SynStreamFrame) bool { + s.receiveIdLock.Lock() + defer s.receiveIdLock.Unlock() + if s.goneAway { + return false + } + validationErr := s.validateStreamId(frame.StreamId) + if validationErr != nil { + go func() { + resetErr := s.sendResetFrame(spdy.ProtocolError, frame.StreamId) + if resetErr != nil { + debugMessage("reset error: %s", resetErr) + } + }() + return false + } + return true +} + +func (s *Connection) handleStreamFrame(frame *spdy.SynStreamFrame, newHandler StreamHandler) error { + stream, ok := s.getStream(frame.StreamId) + if !ok { + return fmt.Errorf("Missing stream: %d", frame.StreamId) + } + + newHandler(stream) + + return nil +} + +func (s *Connection) handleReplyFrame(frame *spdy.SynReplyFrame) error { + debugMessage("(%p) Reply frame received for %d", s, frame.StreamId) + stream, streamOk := s.getStream(frame.StreamId) + if !streamOk { + debugMessage("Reply frame gone away for %d", frame.StreamId) + // Stream has already gone away + return nil + } + if stream.replied { + // Stream has already received reply + return nil + } + stream.replied = true + + // TODO Check for error + if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 { + s.remoteStreamFinish(stream) + } + + close(stream.startChan) + + return nil +} + +func (s *Connection) handleResetFrame(frame *spdy.RstStreamFrame) error { + stream, streamOk := s.getStream(frame.StreamId) + if !streamOk { + // Stream has already been removed + return nil + } + s.removeStream(stream) + stream.closeRemoteChannels() + + if !stream.replied { + stream.replied = true + stream.startChan <- ErrReset + close(stream.startChan) + } + + stream.finishLock.Lock() + stream.finished = true + stream.finishLock.Unlock() + + return nil +} + +func (s *Connection) handleHeaderFrame(frame *spdy.HeadersFrame) error { + stream, streamOk := s.getStream(frame.StreamId) + if !streamOk { + // Stream has already gone away + return nil + } + if !stream.replied { + // No reply received...Protocol error? + return nil + } + + // TODO limit headers while not blocking (use buffered chan or goroutine?) + select { + case <-stream.closeChan: + return nil + case stream.headerChan <- frame.Headers: + } + + if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 { + s.remoteStreamFinish(stream) + } + + return nil +} + +func (s *Connection) handleDataFrame(frame *spdy.DataFrame) error { + debugMessage("(%p) Data frame received for %d", s, frame.StreamId) + stream, streamOk := s.getStream(frame.StreamId) + if !streamOk { + debugMessage("(%p) Data frame gone away for %d", s, frame.StreamId) + // Stream has already gone away + return nil + } + if !stream.replied { + debugMessage("(%p) Data frame not replied %d", s, frame.StreamId) + // No reply received...Protocol error? + return nil + } + + debugMessage("(%p) (%d) Data frame handling", stream, stream.streamId) + if len(frame.Data) > 0 { + stream.dataLock.RLock() + select { + case <-stream.closeChan: + debugMessage("(%p) (%d) Data frame not sent (stream shut down)", stream, stream.streamId) + case stream.dataChan <- frame.Data: + debugMessage("(%p) (%d) Data frame sent", stream, stream.streamId) + } + stream.dataLock.RUnlock() + } + if (frame.Flags & spdy.DataFlagFin) != 0x00 { + s.remoteStreamFinish(stream) + } + return nil +} + +func (s *Connection) handlePingFrame(frame *spdy.PingFrame) error { + if s.pingId&0x01 != frame.Id&0x01 { + return s.framer.WriteFrame(frame) + } + pingChan, pingOk := s.pingChans[frame.Id] + if pingOk { + close(pingChan) + } + return nil +} + +func (s *Connection) handleGoAwayFrame(frame *spdy.GoAwayFrame) error { + debugMessage("(%p) Go away received", s) + s.receiveIdLock.Lock() + if s.goneAway { + s.receiveIdLock.Unlock() + return nil + } + s.goneAway = true + s.receiveIdLock.Unlock() + + if s.lastStreamChan != nil { + stream, _ := s.getStream(frame.LastGoodStreamId) + go func() { + s.lastStreamChan <- stream + }() + } + + // Do not block frame handler waiting for closure + go s.shutdown(s.goAwayTimeout) + + return nil +} + +func (s *Connection) remoteStreamFinish(stream *Stream) { + stream.closeRemoteChannels() + + stream.finishLock.Lock() + if stream.finished { + // Stream is fully closed, cleanup + s.removeStream(stream) + } + stream.finishLock.Unlock() +} + +// CreateStream creates a new spdy stream using the parameters for +// creating the stream frame. The stream frame will be sent upon +// calling this function, however this function does not wait for +// the reply frame. If waiting for the reply is desired, use +// the stream Wait or WaitTimeout function on the stream returned +// by this function. +func (s *Connection) CreateStream(headers http.Header, parent *Stream, fin bool) (*Stream, error) { + // MUST synchronize stream creation (all the way to writing the frame) + // as stream IDs **MUST** increase monotonically. + s.nextIdLock.Lock() + defer s.nextIdLock.Unlock() + + streamId := s.getNextStreamId() + if streamId == 0 { + return nil, fmt.Errorf("Unable to get new stream id") + } + + stream := &Stream{ + streamId: streamId, + parent: parent, + conn: s, + startChan: make(chan error), + headers: headers, + dataChan: make(chan []byte), + headerChan: make(chan http.Header), + closeChan: make(chan bool), + } + + debugMessage("(%p) (%p) Create stream", s, stream) + + s.addStream(stream) + + return stream, s.sendStream(stream, fin) +} + +func (s *Connection) shutdown(closeTimeout time.Duration) { + // TODO Ensure this isn't called multiple times + s.shutdownLock.Lock() + if s.hasShutdown { + s.shutdownLock.Unlock() + return + } + s.hasShutdown = true + s.shutdownLock.Unlock() + + var timeout <-chan time.Time + if closeTimeout > time.Duration(0) { + timeout = time.After(closeTimeout) + } + streamsClosed := make(chan bool) + + go func() { + s.streamCond.L.Lock() + for len(s.streams) > 0 { + debugMessage("Streams opened: %d, %#v", len(s.streams), s.streams) + s.streamCond.Wait() + } + s.streamCond.L.Unlock() + close(streamsClosed) + }() + + var err error + select { + case <-streamsClosed: + // No active streams, close should be safe + err = s.conn.Close() + case <-timeout: + // Force ungraceful close + err = s.conn.Close() + // Wait for cleanup to clear active streams + <-streamsClosed + } + + if err != nil { + duration := 10 * time.Minute + time.AfterFunc(duration, func() { + select { + case err, ok := <-s.shutdownChan: + if ok { + debugMessage("Unhandled close error after %s: %s", duration, err) + } + default: + } + }) + s.shutdownChan <- err + } + close(s.shutdownChan) + + return +} + +// Closes spdy connection by sending GoAway frame and initiating shutdown +func (s *Connection) Close() error { + s.receiveIdLock.Lock() + if s.goneAway { + s.receiveIdLock.Unlock() + return nil + } + s.goneAway = true + s.receiveIdLock.Unlock() + + var lastStreamId spdy.StreamId + if s.receivedStreamId > 2 { + lastStreamId = s.receivedStreamId - 2 + } + + goAwayFrame := &spdy.GoAwayFrame{ + LastGoodStreamId: lastStreamId, + Status: spdy.GoAwayOK, + } + + err := s.framer.WriteFrame(goAwayFrame) + if err != nil { + return err + } + + go s.shutdown(s.closeTimeout) + + return nil +} + +// CloseWait closes the connection and waits for shutdown +// to finish. Note the underlying network Connection +// is not closed until the end of shutdown. +func (s *Connection) CloseWait() error { + closeErr := s.Close() + if closeErr != nil { + return closeErr + } + shutdownErr, ok := <-s.shutdownChan + if ok { + return shutdownErr + } + return nil +} + +// Wait waits for the connection to finish shutdown or for +// the wait timeout duration to expire. This needs to be +// called either after Close has been called or the GOAWAYFRAME +// has been received. If the wait timeout is 0, this function +// will block until shutdown finishes. If wait is never called +// and a shutdown error occurs, that error will be logged as an +// unhandled error. +func (s *Connection) Wait(waitTimeout time.Duration) error { + var timeout <-chan time.Time + if waitTimeout > time.Duration(0) { + timeout = time.After(waitTimeout) + } + + select { + case err, ok := <-s.shutdownChan: + if ok { + return err + } + case <-timeout: + return ErrTimeout + } + return nil +} + +// NotifyClose registers a channel to be called when the remote +// peer inidicates connection closure. The last stream to be +// received by the remote will be sent on the channel. The notify +// timeout will determine the duration between go away received +// and the connection being closed. +func (s *Connection) NotifyClose(c chan<- *Stream, timeout time.Duration) { + s.goAwayTimeout = timeout + s.lastStreamChan = c +} + +// SetCloseTimeout sets the amount of time close will wait for +// streams to finish before terminating the underlying network +// connection. Setting the timeout to 0 will cause close to +// wait forever, which is the default. +func (s *Connection) SetCloseTimeout(timeout time.Duration) { + s.closeTimeout = timeout +} + +// SetIdleTimeout sets the amount of time the connection may sit idle before +// it is forcefully terminated. +func (s *Connection) SetIdleTimeout(timeout time.Duration) { + s.framer.setIdleTimeout(timeout) +} + +func (s *Connection) sendHeaders(headers http.Header, stream *Stream, fin bool) error { + var flags spdy.ControlFlags + if fin { + flags = spdy.ControlFlagFin + } + + headerFrame := &spdy.HeadersFrame{ + StreamId: stream.streamId, + Headers: headers, + CFHeader: spdy.ControlFrameHeader{Flags: flags}, + } + + return s.framer.WriteFrame(headerFrame) +} + +func (s *Connection) sendReply(headers http.Header, stream *Stream, fin bool) error { + var flags spdy.ControlFlags + if fin { + flags = spdy.ControlFlagFin + } + + replyFrame := &spdy.SynReplyFrame{ + StreamId: stream.streamId, + Headers: headers, + CFHeader: spdy.ControlFrameHeader{Flags: flags}, + } + + return s.framer.WriteFrame(replyFrame) +} + +func (s *Connection) sendResetFrame(status spdy.RstStreamStatus, streamId spdy.StreamId) error { + resetFrame := &spdy.RstStreamFrame{ + StreamId: streamId, + Status: status, + } + + return s.framer.WriteFrame(resetFrame) +} + +func (s *Connection) sendReset(status spdy.RstStreamStatus, stream *Stream) error { + return s.sendResetFrame(status, stream.streamId) +} + +func (s *Connection) sendStream(stream *Stream, fin bool) error { + var flags spdy.ControlFlags + if fin { + flags = spdy.ControlFlagFin + stream.finished = true + } + + var parentId spdy.StreamId + if stream.parent != nil { + parentId = stream.parent.streamId + } + + streamFrame := &spdy.SynStreamFrame{ + StreamId: spdy.StreamId(stream.streamId), + AssociatedToStreamId: spdy.StreamId(parentId), + Headers: stream.headers, + CFHeader: spdy.ControlFrameHeader{Flags: flags}, + } + + return s.framer.WriteFrame(streamFrame) +} + +// getNextStreamId returns the next sequential id +// every call should produce a unique value or an error +func (s *Connection) getNextStreamId() spdy.StreamId { + sid := s.nextStreamId + if sid > 0x7fffffff { + return 0 + } + s.nextStreamId = s.nextStreamId + 2 + return sid +} + +// PeekNextStreamId returns the next sequential id and keeps the next id untouched +func (s *Connection) PeekNextStreamId() spdy.StreamId { + sid := s.nextStreamId + return sid +} + +func (s *Connection) validateStreamId(rid spdy.StreamId) error { + if rid > 0x7fffffff || rid < s.receivedStreamId { + return ErrInvalidStreamId + } + s.receivedStreamId = rid + 2 + return nil +} + +func (s *Connection) addStream(stream *Stream) { + s.streamCond.L.Lock() + s.streams[stream.streamId] = stream + debugMessage("(%p) (%p) Stream added, broadcasting: %d", s, stream, stream.streamId) + s.streamCond.Broadcast() + s.streamCond.L.Unlock() +} + +func (s *Connection) removeStream(stream *Stream) { + s.streamCond.L.Lock() + delete(s.streams, stream.streamId) + debugMessage("(%p) (%p) Stream removed, broadcasting: %d", s, stream, stream.streamId) + s.streamCond.Broadcast() + s.streamCond.L.Unlock() +} + +func (s *Connection) getStream(streamId spdy.StreamId) (stream *Stream, ok bool) { + s.streamLock.RLock() + stream, ok = s.streams[streamId] + s.streamLock.RUnlock() + return +} + +// FindStream looks up the given stream id and either waits for the +// stream to be found or returns nil if the stream id is no longer +// valid. +func (s *Connection) FindStream(streamId uint32) *Stream { + var stream *Stream + var ok bool + s.streamCond.L.Lock() + stream, ok = s.streams[spdy.StreamId(streamId)] + debugMessage("(%p) Found stream %d? %t", s, spdy.StreamId(streamId), ok) + for !ok && streamId >= uint32(s.receivedStreamId) { + s.streamCond.Wait() + stream, ok = s.streams[spdy.StreamId(streamId)] + } + s.streamCond.L.Unlock() + return stream +} + +func (s *Connection) CloseChan() <-chan bool { + return s.closeChan +} diff --git a/vendor/github.com/docker/spdystream/handlers.go b/vendor/github.com/docker/spdystream/handlers.go new file mode 100644 index 000000000..b59fa5fdc --- /dev/null +++ b/vendor/github.com/docker/spdystream/handlers.go @@ -0,0 +1,38 @@ +package spdystream + +import ( + "io" + "net/http" +) + +// MirrorStreamHandler mirrors all streams. +func MirrorStreamHandler(stream *Stream) { + replyErr := stream.SendReply(http.Header{}, false) + if replyErr != nil { + return + } + + go func() { + io.Copy(stream, stream) + stream.Close() + }() + go func() { + for { + header, receiveErr := stream.ReceiveHeader() + if receiveErr != nil { + return + } + sendErr := stream.SendHeader(header, false) + if sendErr != nil { + return + } + } + }() +} + +// NoopStreamHandler does nothing when stream connects, most +// likely used with RejectAuthHandler which will not allow any +// streams to make it to the stream handler. +func NoOpStreamHandler(stream *Stream) { + stream.SendReply(http.Header{}, false) +} diff --git a/vendor/github.com/docker/spdystream/priority.go b/vendor/github.com/docker/spdystream/priority.go new file mode 100644 index 000000000..fc8582b5c --- /dev/null +++ b/vendor/github.com/docker/spdystream/priority.go @@ -0,0 +1,98 @@ +package spdystream + +import ( + "container/heap" + "sync" + + "github.com/docker/spdystream/spdy" +) + +type prioritizedFrame struct { + frame spdy.Frame + priority uint8 + insertId uint64 +} + +type frameQueue []*prioritizedFrame + +func (fq frameQueue) Len() int { + return len(fq) +} + +func (fq frameQueue) Less(i, j int) bool { + if fq[i].priority == fq[j].priority { + return fq[i].insertId < fq[j].insertId + } + return fq[i].priority < fq[j].priority +} + +func (fq frameQueue) Swap(i, j int) { + fq[i], fq[j] = fq[j], fq[i] +} + +func (fq *frameQueue) Push(x interface{}) { + *fq = append(*fq, x.(*prioritizedFrame)) +} + +func (fq *frameQueue) Pop() interface{} { + old := *fq + n := len(old) + *fq = old[0 : n-1] + return old[n-1] +} + +type PriorityFrameQueue struct { + queue *frameQueue + c *sync.Cond + size int + nextInsertId uint64 + drain bool +} + +func NewPriorityFrameQueue(size int) *PriorityFrameQueue { + queue := make(frameQueue, 0, size) + heap.Init(&queue) + + return &PriorityFrameQueue{ + queue: &queue, + size: size, + c: sync.NewCond(&sync.Mutex{}), + } +} + +func (q *PriorityFrameQueue) Push(frame spdy.Frame, priority uint8) { + q.c.L.Lock() + defer q.c.L.Unlock() + for q.queue.Len() >= q.size { + q.c.Wait() + } + pFrame := &prioritizedFrame{ + frame: frame, + priority: priority, + insertId: q.nextInsertId, + } + q.nextInsertId = q.nextInsertId + 1 + heap.Push(q.queue, pFrame) + q.c.Signal() +} + +func (q *PriorityFrameQueue) Pop() spdy.Frame { + q.c.L.Lock() + defer q.c.L.Unlock() + for q.queue.Len() == 0 { + if q.drain { + return nil + } + q.c.Wait() + } + frame := heap.Pop(q.queue).(*prioritizedFrame).frame + q.c.Signal() + return frame +} + +func (q *PriorityFrameQueue) Drain() { + q.c.L.Lock() + defer q.c.L.Unlock() + q.drain = true + q.c.Broadcast() +} diff --git a/vendor/github.com/docker/spdystream/spdy/dictionary.go b/vendor/github.com/docker/spdystream/spdy/dictionary.go new file mode 100644 index 000000000..5a5ff0e14 --- /dev/null +++ b/vendor/github.com/docker/spdystream/spdy/dictionary.go @@ -0,0 +1,187 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package spdy + +// headerDictionary is the dictionary sent to the zlib compressor/decompressor. +var headerDictionary = []byte{ + 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, + 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, + 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, + 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, + 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, + 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, + 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, + 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, + 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, + 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, + 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, + 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, + 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, + 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, + 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, + 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, + 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, + 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, + 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, + 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, + 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, + 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, + 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, + 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, + 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, + 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, + 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, + 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, + 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, + 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, + 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, + 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, + 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, + 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, + 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, + 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, + 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, + 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, + 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, + 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, + 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, + 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, + 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, + 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, + 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, + 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, + 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, + 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, + 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, + 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, + 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, + 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, + 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, + 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, + 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, + 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, + 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, + 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, + 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, + 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, + 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, + 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, + 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, + 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, + 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, + 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, + 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, + 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, + 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, + 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, + 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, + 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, + 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, + 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, + 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, + 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, + 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, + 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, + 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, + 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, + 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, + 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, + 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, + 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, + 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, + 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, + 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, + 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, + 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, + 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, + 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, + 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, + 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, + 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, + 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, + 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, + 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, + 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, + 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, + 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, + 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, + 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, + 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, + 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, + 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, + 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, + 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, + 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, + 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, + 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, + 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, + 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, + 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, + 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e, +} diff --git a/vendor/github.com/docker/spdystream/spdy/read.go b/vendor/github.com/docker/spdystream/spdy/read.go new file mode 100644 index 000000000..9359a9501 --- /dev/null +++ b/vendor/github.com/docker/spdystream/spdy/read.go @@ -0,0 +1,348 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package spdy + +import ( + "compress/zlib" + "encoding/binary" + "io" + "net/http" + "strings" +) + +func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) error { + return f.readSynStreamFrame(h, frame) +} + +func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) error { + return f.readSynReplyFrame(h, frame) +} + +func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) error { + frame.CFHeader = h + if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { + return err + } + if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil { + return err + } + if frame.Status == 0 { + return &Error{InvalidControlFrame, frame.StreamId} + } + if frame.StreamId == 0 { + return &Error{ZeroStreamId, 0} + } + return nil +} + +func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) error { + frame.CFHeader = h + var numSettings uint32 + if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil { + return err + } + frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings) + for i := uint32(0); i < numSettings; i++ { + if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil { + return err + } + frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24) + frame.FlagIdValues[i].Id &= 0xffffff + if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil { + return err + } + } + return nil +} + +func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) error { + frame.CFHeader = h + if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil { + return err + } + if frame.Id == 0 { + return &Error{ZeroStreamId, 0} + } + if frame.CFHeader.Flags != 0 { + return &Error{InvalidControlFrame, StreamId(frame.Id)} + } + return nil +} + +func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) error { + frame.CFHeader = h + if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil { + return err + } + if frame.CFHeader.Flags != 0 { + return &Error{InvalidControlFrame, frame.LastGoodStreamId} + } + if frame.CFHeader.length != 8 { + return &Error{InvalidControlFrame, frame.LastGoodStreamId} + } + if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil { + return err + } + return nil +} + +func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) error { + return f.readHeadersFrame(h, frame) +} + +func (frame *WindowUpdateFrame) read(h ControlFrameHeader, f *Framer) error { + frame.CFHeader = h + if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { + return err + } + if frame.CFHeader.Flags != 0 { + return &Error{InvalidControlFrame, frame.StreamId} + } + if frame.CFHeader.length != 8 { + return &Error{InvalidControlFrame, frame.StreamId} + } + if err := binary.Read(f.r, binary.BigEndian, &frame.DeltaWindowSize); err != nil { + return err + } + return nil +} + +func newControlFrame(frameType ControlFrameType) (controlFrame, error) { + ctor, ok := cframeCtor[frameType] + if !ok { + return nil, &Error{Err: InvalidControlFrame} + } + return ctor(), nil +} + +var cframeCtor = map[ControlFrameType]func() controlFrame{ + TypeSynStream: func() controlFrame { return new(SynStreamFrame) }, + TypeSynReply: func() controlFrame { return new(SynReplyFrame) }, + TypeRstStream: func() controlFrame { return new(RstStreamFrame) }, + TypeSettings: func() controlFrame { return new(SettingsFrame) }, + TypePing: func() controlFrame { return new(PingFrame) }, + TypeGoAway: func() controlFrame { return new(GoAwayFrame) }, + TypeHeaders: func() controlFrame { return new(HeadersFrame) }, + TypeWindowUpdate: func() controlFrame { return new(WindowUpdateFrame) }, +} + +func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) error { + if f.headerDecompressor != nil { + f.headerReader.N = payloadSize + return nil + } + f.headerReader = io.LimitedReader{R: f.r, N: payloadSize} + decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(headerDictionary)) + if err != nil { + return err + } + f.headerDecompressor = decompressor + return nil +} + +// ReadFrame reads SPDY encoded data and returns a decompressed Frame. +func (f *Framer) ReadFrame() (Frame, error) { + var firstWord uint32 + if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil { + return nil, err + } + if firstWord&0x80000000 != 0 { + frameType := ControlFrameType(firstWord & 0xffff) + version := uint16(firstWord >> 16 & 0x7fff) + return f.parseControlFrame(version, frameType) + } + return f.parseDataFrame(StreamId(firstWord & 0x7fffffff)) +} + +func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, error) { + var length uint32 + if err := binary.Read(f.r, binary.BigEndian, &length); err != nil { + return nil, err + } + flags := ControlFlags((length & 0xff000000) >> 24) + length &= 0xffffff + header := ControlFrameHeader{version, frameType, flags, length} + cframe, err := newControlFrame(frameType) + if err != nil { + return nil, err + } + if err = cframe.read(header, f); err != nil { + return nil, err + } + return cframe, nil +} + +func parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) { + var numHeaders uint32 + if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil { + return nil, err + } + var e error + h := make(http.Header, int(numHeaders)) + for i := 0; i < int(numHeaders); i++ { + var length uint32 + if err := binary.Read(r, binary.BigEndian, &length); err != nil { + return nil, err + } + nameBytes := make([]byte, length) + if _, err := io.ReadFull(r, nameBytes); err != nil { + return nil, err + } + name := string(nameBytes) + if name != strings.ToLower(name) { + e = &Error{UnlowercasedHeaderName, streamId} + name = strings.ToLower(name) + } + if h[name] != nil { + e = &Error{DuplicateHeaders, streamId} + } + if err := binary.Read(r, binary.BigEndian, &length); err != nil { + return nil, err + } + value := make([]byte, length) + if _, err := io.ReadFull(r, value); err != nil { + return nil, err + } + valueList := strings.Split(string(value), headerValueSeparator) + for _, v := range valueList { + h.Add(name, v) + } + } + if e != nil { + return h, e + } + return h, nil +} + +func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) error { + frame.CFHeader = h + var err error + if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { + return err + } + if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil { + return err + } + if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil { + return err + } + frame.Priority >>= 5 + if err = binary.Read(f.r, binary.BigEndian, &frame.Slot); err != nil { + return err + } + reader := f.r + if !f.headerCompressionDisabled { + err := f.uncorkHeaderDecompressor(int64(h.length - 10)) + if err != nil { + return err + } + reader = f.headerDecompressor + } + frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) + if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { + err = &Error{WrongCompressedPayloadSize, 0} + } + if err != nil { + return err + } + for h := range frame.Headers { + if invalidReqHeaders[h] { + return &Error{InvalidHeaderPresent, frame.StreamId} + } + } + if frame.StreamId == 0 { + return &Error{ZeroStreamId, 0} + } + return nil +} + +func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) error { + frame.CFHeader = h + var err error + if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { + return err + } + reader := f.r + if !f.headerCompressionDisabled { + err := f.uncorkHeaderDecompressor(int64(h.length - 4)) + if err != nil { + return err + } + reader = f.headerDecompressor + } + frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) + if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { + err = &Error{WrongCompressedPayloadSize, 0} + } + if err != nil { + return err + } + for h := range frame.Headers { + if invalidRespHeaders[h] { + return &Error{InvalidHeaderPresent, frame.StreamId} + } + } + if frame.StreamId == 0 { + return &Error{ZeroStreamId, 0} + } + return nil +} + +func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) error { + frame.CFHeader = h + var err error + if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { + return err + } + reader := f.r + if !f.headerCompressionDisabled { + err := f.uncorkHeaderDecompressor(int64(h.length - 4)) + if err != nil { + return err + } + reader = f.headerDecompressor + } + frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) + if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { + err = &Error{WrongCompressedPayloadSize, 0} + } + if err != nil { + return err + } + var invalidHeaders map[string]bool + if frame.StreamId%2 == 0 { + invalidHeaders = invalidReqHeaders + } else { + invalidHeaders = invalidRespHeaders + } + for h := range frame.Headers { + if invalidHeaders[h] { + return &Error{InvalidHeaderPresent, frame.StreamId} + } + } + if frame.StreamId == 0 { + return &Error{ZeroStreamId, 0} + } + return nil +} + +func (f *Framer) parseDataFrame(streamId StreamId) (*DataFrame, error) { + var length uint32 + if err := binary.Read(f.r, binary.BigEndian, &length); err != nil { + return nil, err + } + var frame DataFrame + frame.StreamId = streamId + frame.Flags = DataFlags(length >> 24) + length &= 0xffffff + frame.Data = make([]byte, length) + if _, err := io.ReadFull(f.r, frame.Data); err != nil { + return nil, err + } + if frame.StreamId == 0 { + return nil, &Error{ZeroStreamId, 0} + } + return &frame, nil +} diff --git a/vendor/github.com/docker/spdystream/spdy/types.go b/vendor/github.com/docker/spdystream/spdy/types.go new file mode 100644 index 000000000..7b6ee9c6f --- /dev/null +++ b/vendor/github.com/docker/spdystream/spdy/types.go @@ -0,0 +1,275 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package spdy implements the SPDY protocol (currently SPDY/3), described in +// http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3. +package spdy + +import ( + "bytes" + "compress/zlib" + "io" + "net/http" +) + +// Version is the protocol version number that this package implements. +const Version = 3 + +// ControlFrameType stores the type field in a control frame header. +type ControlFrameType uint16 + +const ( + TypeSynStream ControlFrameType = 0x0001 + TypeSynReply = 0x0002 + TypeRstStream = 0x0003 + TypeSettings = 0x0004 + TypePing = 0x0006 + TypeGoAway = 0x0007 + TypeHeaders = 0x0008 + TypeWindowUpdate = 0x0009 +) + +// ControlFlags are the flags that can be set on a control frame. +type ControlFlags uint8 + +const ( + ControlFlagFin ControlFlags = 0x01 + ControlFlagUnidirectional = 0x02 + ControlFlagSettingsClearSettings = 0x01 +) + +// DataFlags are the flags that can be set on a data frame. +type DataFlags uint8 + +const ( + DataFlagFin DataFlags = 0x01 +) + +// MaxDataLength is the maximum number of bytes that can be stored in one frame. +const MaxDataLength = 1<<24 - 1 + +// headerValueSepator separates multiple header values. +const headerValueSeparator = "\x00" + +// Frame is a single SPDY frame in its unpacked in-memory representation. Use +// Framer to read and write it. +type Frame interface { + write(f *Framer) error +} + +// ControlFrameHeader contains all the fields in a control frame header, +// in its unpacked in-memory representation. +type ControlFrameHeader struct { + // Note, high bit is the "Control" bit. + version uint16 // spdy version number + frameType ControlFrameType + Flags ControlFlags + length uint32 // length of data field +} + +type controlFrame interface { + Frame + read(h ControlFrameHeader, f *Framer) error +} + +// StreamId represents a 31-bit value identifying the stream. +type StreamId uint32 + +// SynStreamFrame is the unpacked, in-memory representation of a SYN_STREAM +// frame. +type SynStreamFrame struct { + CFHeader ControlFrameHeader + StreamId StreamId + AssociatedToStreamId StreamId // stream id for a stream which this stream is associated to + Priority uint8 // priority of this frame (3-bit) + Slot uint8 // index in the server's credential vector of the client certificate + Headers http.Header +} + +// SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame. +type SynReplyFrame struct { + CFHeader ControlFrameHeader + StreamId StreamId + Headers http.Header +} + +// RstStreamStatus represents the status that led to a RST_STREAM. +type RstStreamStatus uint32 + +const ( + ProtocolError RstStreamStatus = iota + 1 + InvalidStream + RefusedStream + UnsupportedVersion + Cancel + InternalError + FlowControlError + StreamInUse + StreamAlreadyClosed + InvalidCredentials + FrameTooLarge +) + +// RstStreamFrame is the unpacked, in-memory representation of a RST_STREAM +// frame. +type RstStreamFrame struct { + CFHeader ControlFrameHeader + StreamId StreamId + Status RstStreamStatus +} + +// SettingsFlag represents a flag in a SETTINGS frame. +type SettingsFlag uint8 + +const ( + FlagSettingsPersistValue SettingsFlag = 0x1 + FlagSettingsPersisted = 0x2 +) + +// SettingsFlag represents the id of an id/value pair in a SETTINGS frame. +type SettingsId uint32 + +const ( + SettingsUploadBandwidth SettingsId = iota + 1 + SettingsDownloadBandwidth + SettingsRoundTripTime + SettingsMaxConcurrentStreams + SettingsCurrentCwnd + SettingsDownloadRetransRate + SettingsInitialWindowSize + SettingsClientCretificateVectorSize +) + +// SettingsFlagIdValue is the unpacked, in-memory representation of the +// combined flag/id/value for a setting in a SETTINGS frame. +type SettingsFlagIdValue struct { + Flag SettingsFlag + Id SettingsId + Value uint32 +} + +// SettingsFrame is the unpacked, in-memory representation of a SPDY +// SETTINGS frame. +type SettingsFrame struct { + CFHeader ControlFrameHeader + FlagIdValues []SettingsFlagIdValue +} + +// PingFrame is the unpacked, in-memory representation of a PING frame. +type PingFrame struct { + CFHeader ControlFrameHeader + Id uint32 // unique id for this ping, from server is even, from client is odd. +} + +// GoAwayStatus represents the status in a GoAwayFrame. +type GoAwayStatus uint32 + +const ( + GoAwayOK GoAwayStatus = iota + GoAwayProtocolError + GoAwayInternalError +) + +// GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame. +type GoAwayFrame struct { + CFHeader ControlFrameHeader + LastGoodStreamId StreamId // last stream id which was accepted by sender + Status GoAwayStatus +} + +// HeadersFrame is the unpacked, in-memory representation of a HEADERS frame. +type HeadersFrame struct { + CFHeader ControlFrameHeader + StreamId StreamId + Headers http.Header +} + +// WindowUpdateFrame is the unpacked, in-memory representation of a +// WINDOW_UPDATE frame. +type WindowUpdateFrame struct { + CFHeader ControlFrameHeader + StreamId StreamId + DeltaWindowSize uint32 // additional number of bytes to existing window size +} + +// TODO: Implement credential frame and related methods. + +// DataFrame is the unpacked, in-memory representation of a DATA frame. +type DataFrame struct { + // Note, high bit is the "Control" bit. Should be 0 for data frames. + StreamId StreamId + Flags DataFlags + Data []byte // payload data of this frame +} + +// A SPDY specific error. +type ErrorCode string + +const ( + UnlowercasedHeaderName ErrorCode = "header was not lowercased" + DuplicateHeaders = "multiple headers with same name" + WrongCompressedPayloadSize = "compressed payload size was incorrect" + UnknownFrameType = "unknown frame type" + InvalidControlFrame = "invalid control frame" + InvalidDataFrame = "invalid data frame" + InvalidHeaderPresent = "frame contained invalid header" + ZeroStreamId = "stream id zero is disallowed" +) + +// Error contains both the type of error and additional values. StreamId is 0 +// if Error is not associated with a stream. +type Error struct { + Err ErrorCode + StreamId StreamId +} + +func (e *Error) Error() string { + return string(e.Err) +} + +var invalidReqHeaders = map[string]bool{ + "Connection": true, + "Host": true, + "Keep-Alive": true, + "Proxy-Connection": true, + "Transfer-Encoding": true, +} + +var invalidRespHeaders = map[string]bool{ + "Connection": true, + "Keep-Alive": true, + "Proxy-Connection": true, + "Transfer-Encoding": true, +} + +// Framer handles serializing/deserializing SPDY frames, including compressing/ +// decompressing payloads. +type Framer struct { + headerCompressionDisabled bool + w io.Writer + headerBuf *bytes.Buffer + headerCompressor *zlib.Writer + r io.Reader + headerReader io.LimitedReader + headerDecompressor io.ReadCloser +} + +// NewFramer allocates a new Framer for a given SPDY connection, represented by +// a io.Writer and io.Reader. Note that Framer will read and write individual fields +// from/to the Reader and Writer, so the caller should pass in an appropriately +// buffered implementation to optimize performance. +func NewFramer(w io.Writer, r io.Reader) (*Framer, error) { + compressBuf := new(bytes.Buffer) + compressor, err := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(headerDictionary)) + if err != nil { + return nil, err + } + framer := &Framer{ + w: w, + headerBuf: compressBuf, + headerCompressor: compressor, + r: r, + } + return framer, nil +} diff --git a/vendor/github.com/docker/spdystream/spdy/write.go b/vendor/github.com/docker/spdystream/spdy/write.go new file mode 100644 index 000000000..b212f66a2 --- /dev/null +++ b/vendor/github.com/docker/spdystream/spdy/write.go @@ -0,0 +1,318 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package spdy + +import ( + "encoding/binary" + "io" + "net/http" + "strings" +) + +func (frame *SynStreamFrame) write(f *Framer) error { + return f.writeSynStreamFrame(frame) +} + +func (frame *SynReplyFrame) write(f *Framer) error { + return f.writeSynReplyFrame(frame) +} + +func (frame *RstStreamFrame) write(f *Framer) (err error) { + if frame.StreamId == 0 { + return &Error{ZeroStreamId, 0} + } + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeRstStream + frame.CFHeader.Flags = 0 + frame.CFHeader.length = 8 + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { + return + } + if frame.Status == 0 { + return &Error{InvalidControlFrame, frame.StreamId} + } + if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil { + return + } + return +} + +func (frame *SettingsFrame) write(f *Framer) (err error) { + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeSettings + frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4) + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil { + return + } + for _, flagIdValue := range frame.FlagIdValues { + flagId := uint32(flagIdValue.Flag)<<24 | uint32(flagIdValue.Id) + if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil { + return + } + } + return +} + +func (frame *PingFrame) write(f *Framer) (err error) { + if frame.Id == 0 { + return &Error{ZeroStreamId, 0} + } + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypePing + frame.CFHeader.Flags = 0 + frame.CFHeader.length = 4 + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil { + return + } + return +} + +func (frame *GoAwayFrame) write(f *Framer) (err error) { + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeGoAway + frame.CFHeader.Flags = 0 + frame.CFHeader.length = 8 + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil { + return + } + return nil +} + +func (frame *HeadersFrame) write(f *Framer) error { + return f.writeHeadersFrame(frame) +} + +func (frame *WindowUpdateFrame) write(f *Framer) (err error) { + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeWindowUpdate + frame.CFHeader.Flags = 0 + frame.CFHeader.length = 8 + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, frame.DeltaWindowSize); err != nil { + return + } + return nil +} + +func (frame *DataFrame) write(f *Framer) error { + return f.writeDataFrame(frame) +} + +// WriteFrame writes a frame. +func (f *Framer) WriteFrame(frame Frame) error { + return frame.write(f) +} + +func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error { + if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil { + return err + } + if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil { + return err + } + flagsAndLength := uint32(h.Flags)<<24 | h.length + if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil { + return err + } + return nil +} + +func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) { + n = 0 + if err = binary.Write(w, binary.BigEndian, uint32(len(h))); err != nil { + return + } + n += 2 + for name, values := range h { + if err = binary.Write(w, binary.BigEndian, uint32(len(name))); err != nil { + return + } + n += 2 + name = strings.ToLower(name) + if _, err = io.WriteString(w, name); err != nil { + return + } + n += len(name) + v := strings.Join(values, headerValueSeparator) + if err = binary.Write(w, binary.BigEndian, uint32(len(v))); err != nil { + return + } + n += 2 + if _, err = io.WriteString(w, v); err != nil { + return + } + n += len(v) + } + return +} + +func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) { + if frame.StreamId == 0 { + return &Error{ZeroStreamId, 0} + } + // Marshal the headers. + var writer io.Writer = f.headerBuf + if !f.headerCompressionDisabled { + writer = f.headerCompressor + } + if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil { + return + } + if !f.headerCompressionDisabled { + f.headerCompressor.Flush() + } + + // Set ControlFrameHeader. + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeSynStream + frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10) + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { + return err + } + if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { + return err + } + if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil { + return err + } + if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<5); err != nil { + return err + } + if err = binary.Write(f.w, binary.BigEndian, frame.Slot); err != nil { + return err + } + if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil { + return err + } + f.headerBuf.Reset() + return nil +} + +func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) { + if frame.StreamId == 0 { + return &Error{ZeroStreamId, 0} + } + // Marshal the headers. + var writer io.Writer = f.headerBuf + if !f.headerCompressionDisabled { + writer = f.headerCompressor + } + if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil { + return + } + if !f.headerCompressionDisabled { + f.headerCompressor.Flush() + } + + // Set ControlFrameHeader. + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeSynReply + frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4) + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { + return + } + if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil { + return + } + f.headerBuf.Reset() + return +} + +func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) { + if frame.StreamId == 0 { + return &Error{ZeroStreamId, 0} + } + // Marshal the headers. + var writer io.Writer = f.headerBuf + if !f.headerCompressionDisabled { + writer = f.headerCompressor + } + if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil { + return + } + if !f.headerCompressionDisabled { + f.headerCompressor.Flush() + } + + // Set ControlFrameHeader. + frame.CFHeader.version = Version + frame.CFHeader.frameType = TypeHeaders + frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4) + + // Serialize frame to Writer. + if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { + return + } + if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { + return + } + if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil { + return + } + f.headerBuf.Reset() + return +} + +func (f *Framer) writeDataFrame(frame *DataFrame) (err error) { + if frame.StreamId == 0 { + return &Error{ZeroStreamId, 0} + } + if frame.StreamId&0x80000000 != 0 || len(frame.Data) > MaxDataLength { + return &Error{InvalidDataFrame, frame.StreamId} + } + + // Serialize frame to Writer. + if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { + return + } + flagsAndLength := uint32(frame.Flags)<<24 | uint32(len(frame.Data)) + if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil { + return + } + if _, err = f.w.Write(frame.Data); err != nil { + return + } + return nil +} diff --git a/vendor/github.com/docker/spdystream/stream.go b/vendor/github.com/docker/spdystream/stream.go new file mode 100644 index 000000000..f9e9ee267 --- /dev/null +++ b/vendor/github.com/docker/spdystream/stream.go @@ -0,0 +1,327 @@ +package spdystream + +import ( + "errors" + "fmt" + "io" + "net" + "net/http" + "sync" + "time" + + "github.com/docker/spdystream/spdy" +) + +var ( + ErrUnreadPartialData = errors.New("unread partial data") +) + +type Stream struct { + streamId spdy.StreamId + parent *Stream + conn *Connection + startChan chan error + + dataLock sync.RWMutex + dataChan chan []byte + unread []byte + + priority uint8 + headers http.Header + headerChan chan http.Header + finishLock sync.Mutex + finished bool + replyCond *sync.Cond + replied bool + closeLock sync.Mutex + closeChan chan bool +} + +// WriteData writes data to stream, sending a dataframe per call +func (s *Stream) WriteData(data []byte, fin bool) error { + s.waitWriteReply() + var flags spdy.DataFlags + + if fin { + flags = spdy.DataFlagFin + s.finishLock.Lock() + if s.finished { + s.finishLock.Unlock() + return ErrWriteClosedStream + } + s.finished = true + s.finishLock.Unlock() + } + + dataFrame := &spdy.DataFrame{ + StreamId: s.streamId, + Flags: flags, + Data: data, + } + + debugMessage("(%p) (%d) Writing data frame", s, s.streamId) + return s.conn.framer.WriteFrame(dataFrame) +} + +// Write writes bytes to a stream, calling write data for each call. +func (s *Stream) Write(data []byte) (n int, err error) { + err = s.WriteData(data, false) + if err == nil { + n = len(data) + } + return +} + +// Read reads bytes from a stream, a single read will never get more +// than what is sent on a single data frame, but a multiple calls to +// read may get data from the same data frame. +func (s *Stream) Read(p []byte) (n int, err error) { + if s.unread == nil { + select { + case <-s.closeChan: + return 0, io.EOF + case read, ok := <-s.dataChan: + if !ok { + return 0, io.EOF + } + s.unread = read + } + } + n = copy(p, s.unread) + if n < len(s.unread) { + s.unread = s.unread[n:] + } else { + s.unread = nil + } + return +} + +// ReadData reads an entire data frame and returns the byte array +// from the data frame. If there is unread data from the result +// of a Read call, this function will return an ErrUnreadPartialData. +func (s *Stream) ReadData() ([]byte, error) { + debugMessage("(%p) Reading data from %d", s, s.streamId) + if s.unread != nil { + return nil, ErrUnreadPartialData + } + select { + case <-s.closeChan: + return nil, io.EOF + case read, ok := <-s.dataChan: + if !ok { + return nil, io.EOF + } + return read, nil + } +} + +func (s *Stream) waitWriteReply() { + if s.replyCond != nil { + s.replyCond.L.Lock() + for !s.replied { + s.replyCond.Wait() + } + s.replyCond.L.Unlock() + } +} + +// Wait waits for the stream to receive a reply. +func (s *Stream) Wait() error { + return s.WaitTimeout(time.Duration(0)) +} + +// WaitTimeout waits for the stream to receive a reply or for timeout. +// When the timeout is reached, ErrTimeout will be returned. +func (s *Stream) WaitTimeout(timeout time.Duration) error { + var timeoutChan <-chan time.Time + if timeout > time.Duration(0) { + timeoutChan = time.After(timeout) + } + + select { + case err := <-s.startChan: + if err != nil { + return err + } + break + case <-timeoutChan: + return ErrTimeout + } + return nil +} + +// Close closes the stream by sending an empty data frame with the +// finish flag set, indicating this side is finished with the stream. +func (s *Stream) Close() error { + select { + case <-s.closeChan: + // Stream is now fully closed + s.conn.removeStream(s) + default: + break + } + return s.WriteData([]byte{}, true) +} + +// Reset sends a reset frame, putting the stream into the fully closed state. +func (s *Stream) Reset() error { + s.conn.removeStream(s) + return s.resetStream() +} + +func (s *Stream) resetStream() error { + // Always call closeRemoteChannels, even if s.finished is already true. + // This makes it so that stream.Close() followed by stream.Reset() allows + // stream.Read() to unblock. + s.closeRemoteChannels() + + s.finishLock.Lock() + if s.finished { + s.finishLock.Unlock() + return nil + } + s.finished = true + s.finishLock.Unlock() + + resetFrame := &spdy.RstStreamFrame{ + StreamId: s.streamId, + Status: spdy.Cancel, + } + return s.conn.framer.WriteFrame(resetFrame) +} + +// CreateSubStream creates a stream using the current as the parent +func (s *Stream) CreateSubStream(headers http.Header, fin bool) (*Stream, error) { + return s.conn.CreateStream(headers, s, fin) +} + +// SetPriority sets the stream priority, does not affect the +// remote priority of this stream after Open has been called. +// Valid values are 0 through 7, 0 being the highest priority +// and 7 the lowest. +func (s *Stream) SetPriority(priority uint8) { + s.priority = priority +} + +// SendHeader sends a header frame across the stream +func (s *Stream) SendHeader(headers http.Header, fin bool) error { + return s.conn.sendHeaders(headers, s, fin) +} + +// SendReply sends a reply on a stream, only valid to be called once +// when handling a new stream +func (s *Stream) SendReply(headers http.Header, fin bool) error { + if s.replyCond == nil { + return errors.New("cannot reply on initiated stream") + } + s.replyCond.L.Lock() + defer s.replyCond.L.Unlock() + if s.replied { + return nil + } + + err := s.conn.sendReply(headers, s, fin) + if err != nil { + return err + } + + s.replied = true + s.replyCond.Broadcast() + return nil +} + +// Refuse sends a reset frame with the status refuse, only +// valid to be called once when handling a new stream. This +// may be used to indicate that a stream is not allowed +// when http status codes are not being used. +func (s *Stream) Refuse() error { + if s.replied { + return nil + } + s.replied = true + return s.conn.sendReset(spdy.RefusedStream, s) +} + +// Cancel sends a reset frame with the status canceled. This +// can be used at any time by the creator of the Stream to +// indicate the stream is no longer needed. +func (s *Stream) Cancel() error { + return s.conn.sendReset(spdy.Cancel, s) +} + +// ReceiveHeader receives a header sent on the other side +// of the stream. This function will block until a header +// is received or stream is closed. +func (s *Stream) ReceiveHeader() (http.Header, error) { + select { + case <-s.closeChan: + break + case header, ok := <-s.headerChan: + if !ok { + return nil, fmt.Errorf("header chan closed") + } + return header, nil + } + return nil, fmt.Errorf("stream closed") +} + +// Parent returns the parent stream +func (s *Stream) Parent() *Stream { + return s.parent +} + +// Headers returns the headers used to create the stream +func (s *Stream) Headers() http.Header { + return s.headers +} + +// String returns the string version of stream using the +// streamId to uniquely identify the stream +func (s *Stream) String() string { + return fmt.Sprintf("stream:%d", s.streamId) +} + +// Identifier returns a 32 bit identifier for the stream +func (s *Stream) Identifier() uint32 { + return uint32(s.streamId) +} + +// IsFinished returns whether the stream has finished +// sending data +func (s *Stream) IsFinished() bool { + return s.finished +} + +// Implement net.Conn interface + +func (s *Stream) LocalAddr() net.Addr { + return s.conn.conn.LocalAddr() +} + +func (s *Stream) RemoteAddr() net.Addr { + return s.conn.conn.RemoteAddr() +} + +// TODO set per stream values instead of connection-wide + +func (s *Stream) SetDeadline(t time.Time) error { + return s.conn.conn.SetDeadline(t) +} + +func (s *Stream) SetReadDeadline(t time.Time) error { + return s.conn.conn.SetReadDeadline(t) +} + +func (s *Stream) SetWriteDeadline(t time.Time) error { + return s.conn.conn.SetWriteDeadline(t) +} + +func (s *Stream) closeRemoteChannels() { + s.closeLock.Lock() + defer s.closeLock.Unlock() + select { + case <-s.closeChan: + default: + close(s.closeChan) + } +} diff --git a/vendor/github.com/docker/spdystream/utils.go b/vendor/github.com/docker/spdystream/utils.go new file mode 100644 index 000000000..1b2c199a4 --- /dev/null +++ b/vendor/github.com/docker/spdystream/utils.go @@ -0,0 +1,16 @@ +package spdystream + +import ( + "log" + "os" +) + +var ( + DEBUG = os.Getenv("DEBUG") +) + +func debugMessage(fmt string, args ...interface{}) { + if DEBUG != "" { + log.Printf(fmt, args...) + } +} diff --git a/vendor/github.com/emicklei/go-restful/.gitignore b/vendor/github.com/emicklei/go-restful/.gitignore new file mode 100644 index 000000000..cece7be66 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/.gitignore @@ -0,0 +1,70 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe + +restful.html + +*.out + +tmp.prof + +go-restful.test + +examples/restful-basic-authentication + +examples/restful-encoding-filter + +examples/restful-filters + +examples/restful-hello-world + +examples/restful-resource-functions + +examples/restful-serve-static + +examples/restful-user-service + +*.DS_Store +examples/restful-user-resource + +examples/restful-multi-containers + +examples/restful-form-handling + +examples/restful-CORS-filter + +examples/restful-options-filter + +examples/restful-curly-router + +examples/restful-cpuprofiler-service + +examples/restful-pre-post-filters + +curly.prof + +examples/restful-NCSA-logging + +examples/restful-html-template + +s.html +restful-path-tail diff --git a/vendor/github.com/emicklei/go-restful/.travis.yml b/vendor/github.com/emicklei/go-restful/.travis.yml new file mode 100644 index 000000000..b22f8f547 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/.travis.yml @@ -0,0 +1,6 @@ +language: go + +go: + - 1.x + +script: go test -v \ No newline at end of file diff --git a/vendor/github.com/emicklei/go-restful/CHANGES.md b/vendor/github.com/emicklei/go-restful/CHANGES.md new file mode 100644 index 000000000..0adca766f --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/CHANGES.md @@ -0,0 +1,223 @@ +Change history of go-restful += +2017-02-16 +- solved issue #304, make operation names unique + +2017-01-30 + + [IMPORTANT] For swagger users, change your import statement to: + swagger "github.com/emicklei/go-restful-swagger12" + +- moved swagger 1.2 code to go-restful-swagger12 +- created TAG 2.0.0 + +2017-01-27 + +- remove defer request body close +- expose Dispatch for testing filters and Routefunctions +- swagger response model cannot be array +- created TAG 1.0.0 + +2016-12-22 + +- (API change) Remove code related to caching request content. Removes SetCacheReadEntity(doCache bool) + +2016-11-26 + +- Default change! now use CurlyRouter (was RouterJSR311) +- Default change! no more caching of request content +- Default change! do not recover from panics + +2016-09-22 + +- fix the DefaultRequestContentType feature + +2016-02-14 + +- take the qualify factor of the Accept header mediatype into account when deciding the contentype of the response +- add constructors for custom entity accessors for xml and json + +2015-09-27 + +- rename new WriteStatusAnd... to WriteHeaderAnd... for consistency + +2015-09-25 + +- fixed problem with changing Header after WriteHeader (issue 235) + +2015-09-14 + +- changed behavior of WriteHeader (immediate write) and WriteEntity (no status write) +- added support for custom EntityReaderWriters. + +2015-08-06 + +- add support for reading entities from compressed request content +- use sync.Pool for compressors of http response and request body +- add Description to Parameter for documentation in Swagger UI + +2015-03-20 + +- add configurable logging + +2015-03-18 + +- if not specified, the Operation is derived from the Route function + +2015-03-17 + +- expose Parameter creation functions +- make trace logger an interface +- fix OPTIONSFilter +- customize rendering of ServiceError +- JSR311 router now handles wildcards +- add Notes to Route + +2014-11-27 + +- (api add) PrettyPrint per response. (as proposed in #167) + +2014-11-12 + +- (api add) ApiVersion(.) for documentation in Swagger UI + +2014-11-10 + +- (api change) struct fields tagged with "description" show up in Swagger UI + +2014-10-31 + +- (api change) ReturnsError -> Returns +- (api add) RouteBuilder.Do(aBuilder) for DRY use of RouteBuilder +- fix swagger nested structs +- sort Swagger response messages by code + +2014-10-23 + +- (api add) ReturnsError allows you to document Http codes in swagger +- fixed problem with greedy CurlyRouter +- (api add) Access-Control-Max-Age in CORS +- add tracing functionality (injectable) for debugging purposes +- support JSON parse 64bit int +- fix empty parameters for swagger +- WebServicesUrl is now optional for swagger +- fixed duplicate AccessControlAllowOrigin in CORS +- (api change) expose ServeMux in container +- (api add) added AllowedDomains in CORS +- (api add) ParameterNamed for detailed documentation + +2014-04-16 + +- (api add) expose constructor of Request for testing. + +2014-06-27 + +- (api add) ParameterNamed gives access to a Parameter definition and its data (for further specification). +- (api add) SetCacheReadEntity allow scontrol over whether or not the request body is being cached (default true for compatibility reasons). + +2014-07-03 + +- (api add) CORS can be configured with a list of allowed domains + +2014-03-12 + +- (api add) Route path parameters can use wildcard or regular expressions. (requires CurlyRouter) + +2014-02-26 + +- (api add) Request now provides information about the matched Route, see method SelectedRoutePath + +2014-02-17 + +- (api change) renamed parameter constants (go-lint checks) + +2014-01-10 + +- (api add) support for CloseNotify, see http://golang.org/pkg/net/http/#CloseNotifier + +2014-01-07 + +- (api change) Write* methods in Response now return the error or nil. +- added example of serving HTML from a Go template. +- fixed comparing Allowed headers in CORS (is now case-insensitive) + +2013-11-13 + +- (api add) Response knows how many bytes are written to the response body. + +2013-10-29 + +- (api add) RecoverHandler(handler RecoverHandleFunction) to change how panic recovery is handled. Default behavior is to log and return a stacktrace. This may be a security issue as it exposes sourcecode information. + +2013-10-04 + +- (api add) Response knows what HTTP status has been written +- (api add) Request can have attributes (map of string->interface, also called request-scoped variables + +2013-09-12 + +- (api change) Router interface simplified +- Implemented CurlyRouter, a Router that does not use|allow regular expressions in paths + +2013-08-05 + - add OPTIONS support + - add CORS support + +2013-08-27 + +- fixed some reported issues (see github) +- (api change) deprecated use of WriteError; use WriteErrorString instead + +2014-04-15 + +- (fix) v1.0.1 tag: fix Issue 111: WriteErrorString + +2013-08-08 + +- (api add) Added implementation Container: a WebServices collection with its own http.ServeMux allowing multiple endpoints per program. Existing uses of go-restful will register their services to the DefaultContainer. +- (api add) the swagger package has be extended to have a UI per container. +- if panic is detected then a small stack trace is printed (thanks to runner-mei) +- (api add) WriteErrorString to Response + +Important API changes: + +- (api remove) package variable DoNotRecover no longer works ; use restful.DefaultContainer.DoNotRecover(true) instead. +- (api remove) package variable EnableContentEncoding no longer works ; use restful.DefaultContainer.EnableContentEncoding(true) instead. + + +2013-07-06 + +- (api add) Added support for response encoding (gzip and deflate(zlib)). This feature is disabled on default (for backwards compatibility). Use restful.EnableContentEncoding = true in your initialization to enable this feature. + +2013-06-19 + +- (improve) DoNotRecover option, moved request body closer, improved ReadEntity + +2013-06-03 + +- (api change) removed Dispatcher interface, hide PathExpression +- changed receiver names of type functions to be more idiomatic Go + +2013-06-02 + +- (optimize) Cache the RegExp compilation of Paths. + +2013-05-22 + +- (api add) Added support for request/response filter functions + +2013-05-18 + + +- (api add) Added feature to change the default Http Request Dispatch function (travis cline) +- (api change) Moved Swagger Webservice to swagger package (see example restful-user) + +[2012-11-14 .. 2013-05-18> + +- See https://github.com/emicklei/go-restful/commits + +2012-11-14 + +- Initial commit + + diff --git a/vendor/github.com/emicklei/go-restful/LICENSE b/vendor/github.com/emicklei/go-restful/LICENSE new file mode 100644 index 000000000..ece7ec61e --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2012,2013 Ernest Micklei + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/emicklei/go-restful/Makefile b/vendor/github.com/emicklei/go-restful/Makefile new file mode 100644 index 000000000..b40081cc0 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/Makefile @@ -0,0 +1,7 @@ +all: test + +test: + go test -v . + +ex: + cd examples && ls *.go | xargs go build -o /tmp/ignore \ No newline at end of file diff --git a/vendor/github.com/emicklei/go-restful/README.md b/vendor/github.com/emicklei/go-restful/README.md new file mode 100644 index 000000000..cd1f2d0cc --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/README.md @@ -0,0 +1,74 @@ +go-restful +========== +package for building REST-style Web Services using Google Go + +[![Build Status](https://travis-ci.org/emicklei/go-restful.png)](https://travis-ci.org/emicklei/go-restful) +[![Go Report Card](https://goreportcard.com/badge/github.com/emicklei/go-restful)](https://goreportcard.com/report/github.com/emicklei/go-restful) +[![GoDoc](https://godoc.org/github.com/emicklei/go-restful?status.svg)](https://godoc.org/github.com/emicklei/go-restful) + +- [Code examples](https://github.com/emicklei/go-restful/tree/master/examples) + +REST asks developers to use HTTP methods explicitly and in a way that's consistent with the protocol definition. This basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods. According to this mapping: + +- GET = Retrieve a representation of a resource +- POST = Create if you are sending content to the server to create a subordinate of the specified resource collection, using some server-side algorithm. +- PUT = Create if you are sending the full content of the specified resource (URI). +- PUT = Update if you are updating the full content of the specified resource. +- DELETE = Delete if you are requesting the server to delete the resource +- PATCH = Update partial content of a resource +- OPTIONS = Get information about the communication options for the request URI + +### Example + +```Go +ws := new(restful.WebService) +ws. + Path("/users"). + Consumes(restful.MIME_XML, restful.MIME_JSON). + Produces(restful.MIME_JSON, restful.MIME_XML) + +ws.Route(ws.GET("/{user-id}").To(u.findUser). + Doc("get a user"). + Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")). + Writes(User{})) +... + +func (u UserResource) findUser(request *restful.Request, response *restful.Response) { + id := request.PathParameter("user-id") + ... +} +``` + +[Full API of a UserResource](https://github.com/emicklei/go-restful/tree/master/examples/restful-user-resource.go) + +### Features + +- Routes for request → function mapping with path parameter (e.g. {id}) support +- Configurable router: + - (default) Fast routing algorithm that allows static elements, regular expressions and dynamic parameters in the URL path (e.g. /meetings/{id} or /static/{subpath:*} + - Routing algorithm after [JSR311](http://jsr311.java.net/nonav/releases/1.1/spec/spec.html) that is implemented using (but does **not** accept) regular expressions +- Request API for reading structs from JSON/XML and accesing parameters (path,query,header) +- Response API for writing structs to JSON/XML and setting headers +- Customizable encoding using EntityReaderWriter registration +- Filters for intercepting the request → response flow on Service or Route level +- Request-scoped variables using attributes +- Containers for WebServices on different HTTP endpoints +- Content encoding (gzip,deflate) of request and response payloads +- Automatic responses on OPTIONS (using a filter) +- Automatic CORS request handling (using a filter) +- API declaration for Swagger UI (see [go-restful-swagger12](https://github.com/emicklei/go-restful-swagger12),[go-restful-openapi](https://github.com/emicklei/go-restful-openapi)) +- Panic recovery to produce HTTP 500, customizable using RecoverHandler(...) +- Route errors produce HTTP 404/405/406/415 errors, customizable using ServiceErrorHandler(...) +- Configurable (trace) logging +- Customizable gzip/deflate readers and writers using CompressorProvider registration + +### Resources + +- [Example posted on blog](http://ernestmicklei.com/2012/11/go-restful-first-working-example/) +- [Design explained on blog](http://ernestmicklei.com/2012/11/go-restful-api-design/) +- [sourcegraph](https://sourcegraph.com/github.com/emicklei/go-restful) +- [showcase: Mora - MongoDB REST Api server](https://github.com/emicklei/mora) + +Type ```git shortlog -s``` for a full list of contributors. + +© 2012 - 2017, http://ernestmicklei.com. MIT License. Contributions are welcome. \ No newline at end of file diff --git a/vendor/github.com/emicklei/go-restful/Srcfile b/vendor/github.com/emicklei/go-restful/Srcfile new file mode 100644 index 000000000..16fd18689 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/Srcfile @@ -0,0 +1 @@ +{"SkipDirs": ["examples"]} diff --git a/vendor/github.com/emicklei/go-restful/bench_test.sh b/vendor/github.com/emicklei/go-restful/bench_test.sh new file mode 100644 index 000000000..47ffbe4ac --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/bench_test.sh @@ -0,0 +1,10 @@ +#go test -run=none -file bench_test.go -test.bench . -cpuprofile=bench_test.out + +go test -c +./go-restful.test -test.run=none -test.cpuprofile=tmp.prof -test.bench=BenchmarkMany +./go-restful.test -test.run=none -test.cpuprofile=curly.prof -test.bench=BenchmarkManyCurly + +#go tool pprof go-restful.test tmp.prof +go tool pprof go-restful.test curly.prof + + diff --git a/vendor/github.com/emicklei/go-restful/compress.go b/vendor/github.com/emicklei/go-restful/compress.go new file mode 100644 index 000000000..220b37712 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/compress.go @@ -0,0 +1,123 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "bufio" + "compress/gzip" + "compress/zlib" + "errors" + "io" + "net" + "net/http" + "strings" +) + +// OBSOLETE : use restful.DefaultContainer.EnableContentEncoding(true) to change this setting. +var EnableContentEncoding = false + +// CompressingResponseWriter is a http.ResponseWriter that can perform content encoding (gzip and zlib) +type CompressingResponseWriter struct { + writer http.ResponseWriter + compressor io.WriteCloser + encoding string +} + +// Header is part of http.ResponseWriter interface +func (c *CompressingResponseWriter) Header() http.Header { + return c.writer.Header() +} + +// WriteHeader is part of http.ResponseWriter interface +func (c *CompressingResponseWriter) WriteHeader(status int) { + c.writer.WriteHeader(status) +} + +// Write is part of http.ResponseWriter interface +// It is passed through the compressor +func (c *CompressingResponseWriter) Write(bytes []byte) (int, error) { + if c.isCompressorClosed() { + return -1, errors.New("Compressing error: tried to write data using closed compressor") + } + return c.compressor.Write(bytes) +} + +// CloseNotify is part of http.CloseNotifier interface +func (c *CompressingResponseWriter) CloseNotify() <-chan bool { + return c.writer.(http.CloseNotifier).CloseNotify() +} + +// Close the underlying compressor +func (c *CompressingResponseWriter) Close() error { + if c.isCompressorClosed() { + return errors.New("Compressing error: tried to close already closed compressor") + } + + c.compressor.Close() + if ENCODING_GZIP == c.encoding { + currentCompressorProvider.ReleaseGzipWriter(c.compressor.(*gzip.Writer)) + } + if ENCODING_DEFLATE == c.encoding { + currentCompressorProvider.ReleaseZlibWriter(c.compressor.(*zlib.Writer)) + } + // gc hint needed? + c.compressor = nil + return nil +} + +func (c *CompressingResponseWriter) isCompressorClosed() bool { + return nil == c.compressor +} + +// Hijack implements the Hijacker interface +// This is especially useful when combining Container.EnabledContentEncoding +// in combination with websockets (for instance gorilla/websocket) +func (c *CompressingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hijacker, ok := c.writer.(http.Hijacker) + if !ok { + return nil, nil, errors.New("ResponseWriter doesn't support Hijacker interface") + } + return hijacker.Hijack() +} + +// WantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested. +func wantsCompressedResponse(httpRequest *http.Request) (bool, string) { + header := httpRequest.Header.Get(HEADER_AcceptEncoding) + gi := strings.Index(header, ENCODING_GZIP) + zi := strings.Index(header, ENCODING_DEFLATE) + // use in order of appearance + if gi == -1 { + return zi != -1, ENCODING_DEFLATE + } else if zi == -1 { + return gi != -1, ENCODING_GZIP + } else { + if gi < zi { + return true, ENCODING_GZIP + } + return true, ENCODING_DEFLATE + } +} + +// NewCompressingResponseWriter create a CompressingResponseWriter for a known encoding = {gzip,deflate} +func NewCompressingResponseWriter(httpWriter http.ResponseWriter, encoding string) (*CompressingResponseWriter, error) { + httpWriter.Header().Set(HEADER_ContentEncoding, encoding) + c := new(CompressingResponseWriter) + c.writer = httpWriter + var err error + if ENCODING_GZIP == encoding { + w := currentCompressorProvider.AcquireGzipWriter() + w.Reset(httpWriter) + c.compressor = w + c.encoding = ENCODING_GZIP + } else if ENCODING_DEFLATE == encoding { + w := currentCompressorProvider.AcquireZlibWriter() + w.Reset(httpWriter) + c.compressor = w + c.encoding = ENCODING_DEFLATE + } else { + return nil, errors.New("Unknown encoding:" + encoding) + } + return c, err +} diff --git a/vendor/github.com/emicklei/go-restful/compressor_cache.go b/vendor/github.com/emicklei/go-restful/compressor_cache.go new file mode 100644 index 000000000..ee426010a --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/compressor_cache.go @@ -0,0 +1,103 @@ +package restful + +// Copyright 2015 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "compress/gzip" + "compress/zlib" +) + +// BoundedCachedCompressors is a CompressorProvider that uses a cache with a fixed amount +// of writers and readers (resources). +// If a new resource is acquired and all are in use, it will return a new unmanaged resource. +type BoundedCachedCompressors struct { + gzipWriters chan *gzip.Writer + gzipReaders chan *gzip.Reader + zlibWriters chan *zlib.Writer + writersCapacity int + readersCapacity int +} + +// NewBoundedCachedCompressors returns a new, with filled cache, BoundedCachedCompressors. +func NewBoundedCachedCompressors(writersCapacity, readersCapacity int) *BoundedCachedCompressors { + b := &BoundedCachedCompressors{ + gzipWriters: make(chan *gzip.Writer, writersCapacity), + gzipReaders: make(chan *gzip.Reader, readersCapacity), + zlibWriters: make(chan *zlib.Writer, writersCapacity), + writersCapacity: writersCapacity, + readersCapacity: readersCapacity, + } + for ix := 0; ix < writersCapacity; ix++ { + b.gzipWriters <- newGzipWriter() + b.zlibWriters <- newZlibWriter() + } + for ix := 0; ix < readersCapacity; ix++ { + b.gzipReaders <- newGzipReader() + } + return b +} + +// AcquireGzipWriter returns an resettable *gzip.Writer. Needs to be released. +func (b *BoundedCachedCompressors) AcquireGzipWriter() *gzip.Writer { + var writer *gzip.Writer + select { + case writer, _ = <-b.gzipWriters: + default: + // return a new unmanaged one + writer = newGzipWriter() + } + return writer +} + +// ReleaseGzipWriter accepts a writer (does not have to be one that was cached) +// only when the cache has room for it. It will ignore it otherwise. +func (b *BoundedCachedCompressors) ReleaseGzipWriter(w *gzip.Writer) { + // forget the unmanaged ones + if len(b.gzipWriters) < b.writersCapacity { + b.gzipWriters <- w + } +} + +// AcquireGzipReader returns a *gzip.Reader. Needs to be released. +func (b *BoundedCachedCompressors) AcquireGzipReader() *gzip.Reader { + var reader *gzip.Reader + select { + case reader, _ = <-b.gzipReaders: + default: + // return a new unmanaged one + reader = newGzipReader() + } + return reader +} + +// ReleaseGzipReader accepts a reader (does not have to be one that was cached) +// only when the cache has room for it. It will ignore it otherwise. +func (b *BoundedCachedCompressors) ReleaseGzipReader(r *gzip.Reader) { + // forget the unmanaged ones + if len(b.gzipReaders) < b.readersCapacity { + b.gzipReaders <- r + } +} + +// AcquireZlibWriter returns an resettable *zlib.Writer. Needs to be released. +func (b *BoundedCachedCompressors) AcquireZlibWriter() *zlib.Writer { + var writer *zlib.Writer + select { + case writer, _ = <-b.zlibWriters: + default: + // return a new unmanaged one + writer = newZlibWriter() + } + return writer +} + +// ReleaseZlibWriter accepts a writer (does not have to be one that was cached) +// only when the cache has room for it. It will ignore it otherwise. +func (b *BoundedCachedCompressors) ReleaseZlibWriter(w *zlib.Writer) { + // forget the unmanaged ones + if len(b.zlibWriters) < b.writersCapacity { + b.zlibWriters <- w + } +} diff --git a/vendor/github.com/emicklei/go-restful/compressor_pools.go b/vendor/github.com/emicklei/go-restful/compressor_pools.go new file mode 100644 index 000000000..d866ce64b --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/compressor_pools.go @@ -0,0 +1,91 @@ +package restful + +// Copyright 2015 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "bytes" + "compress/gzip" + "compress/zlib" + "sync" +) + +// SyncPoolCompessors is a CompressorProvider that use the standard sync.Pool. +type SyncPoolCompessors struct { + GzipWriterPool *sync.Pool + GzipReaderPool *sync.Pool + ZlibWriterPool *sync.Pool +} + +// NewSyncPoolCompessors returns a new ("empty") SyncPoolCompessors. +func NewSyncPoolCompessors() *SyncPoolCompessors { + return &SyncPoolCompessors{ + GzipWriterPool: &sync.Pool{ + New: func() interface{} { return newGzipWriter() }, + }, + GzipReaderPool: &sync.Pool{ + New: func() interface{} { return newGzipReader() }, + }, + ZlibWriterPool: &sync.Pool{ + New: func() interface{} { return newZlibWriter() }, + }, + } +} + +func (s *SyncPoolCompessors) AcquireGzipWriter() *gzip.Writer { + return s.GzipWriterPool.Get().(*gzip.Writer) +} + +func (s *SyncPoolCompessors) ReleaseGzipWriter(w *gzip.Writer) { + s.GzipWriterPool.Put(w) +} + +func (s *SyncPoolCompessors) AcquireGzipReader() *gzip.Reader { + return s.GzipReaderPool.Get().(*gzip.Reader) +} + +func (s *SyncPoolCompessors) ReleaseGzipReader(r *gzip.Reader) { + s.GzipReaderPool.Put(r) +} + +func (s *SyncPoolCompessors) AcquireZlibWriter() *zlib.Writer { + return s.ZlibWriterPool.Get().(*zlib.Writer) +} + +func (s *SyncPoolCompessors) ReleaseZlibWriter(w *zlib.Writer) { + s.ZlibWriterPool.Put(w) +} + +func newGzipWriter() *gzip.Writer { + // create with an empty bytes writer; it will be replaced before using the gzipWriter + writer, err := gzip.NewWriterLevel(new(bytes.Buffer), gzip.BestSpeed) + if err != nil { + panic(err.Error()) + } + return writer +} + +func newGzipReader() *gzip.Reader { + // create with an empty reader (but with GZIP header); it will be replaced before using the gzipReader + // we can safely use currentCompressProvider because it is set on package initialization. + w := currentCompressorProvider.AcquireGzipWriter() + defer currentCompressorProvider.ReleaseGzipWriter(w) + b := new(bytes.Buffer) + w.Reset(b) + w.Flush() + w.Close() + reader, err := gzip.NewReader(bytes.NewReader(b.Bytes())) + if err != nil { + panic(err.Error()) + } + return reader +} + +func newZlibWriter() *zlib.Writer { + writer, err := zlib.NewWriterLevel(new(bytes.Buffer), gzip.BestSpeed) + if err != nil { + panic(err.Error()) + } + return writer +} diff --git a/vendor/github.com/emicklei/go-restful/compressors.go b/vendor/github.com/emicklei/go-restful/compressors.go new file mode 100644 index 000000000..cb32f7ef5 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/compressors.go @@ -0,0 +1,54 @@ +package restful + +// Copyright 2015 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "compress/gzip" + "compress/zlib" +) + +// CompressorProvider describes a component that can provider compressors for the std methods. +type CompressorProvider interface { + // Returns a *gzip.Writer which needs to be released later. + // Before using it, call Reset(). + AcquireGzipWriter() *gzip.Writer + + // Releases an aqcuired *gzip.Writer. + ReleaseGzipWriter(w *gzip.Writer) + + // Returns a *gzip.Reader which needs to be released later. + AcquireGzipReader() *gzip.Reader + + // Releases an aqcuired *gzip.Reader. + ReleaseGzipReader(w *gzip.Reader) + + // Returns a *zlib.Writer which needs to be released later. + // Before using it, call Reset(). + AcquireZlibWriter() *zlib.Writer + + // Releases an aqcuired *zlib.Writer. + ReleaseZlibWriter(w *zlib.Writer) +} + +// DefaultCompressorProvider is the actual provider of compressors (zlib or gzip). +var currentCompressorProvider CompressorProvider + +func init() { + currentCompressorProvider = NewSyncPoolCompessors() +} + +// CurrentCompressorProvider returns the current CompressorProvider. +// It is initialized using a SyncPoolCompessors. +func CurrentCompressorProvider() CompressorProvider { + return currentCompressorProvider +} + +// CompressorProvider sets the actual provider of compressors (zlib or gzip). +func SetCompressorProvider(p CompressorProvider) { + if p == nil { + panic("cannot set compressor provider to nil") + } + currentCompressorProvider = p +} diff --git a/vendor/github.com/emicklei/go-restful/constants.go b/vendor/github.com/emicklei/go-restful/constants.go new file mode 100644 index 000000000..203439c5e --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/constants.go @@ -0,0 +1,30 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +const ( + MIME_XML = "application/xml" // Accept or Content-Type used in Consumes() and/or Produces() + MIME_JSON = "application/json" // Accept or Content-Type used in Consumes() and/or Produces() + MIME_OCTET = "application/octet-stream" // If Content-Type is not present in request, use the default + + HEADER_Allow = "Allow" + HEADER_Accept = "Accept" + HEADER_Origin = "Origin" + HEADER_ContentType = "Content-Type" + HEADER_LastModified = "Last-Modified" + HEADER_AcceptEncoding = "Accept-Encoding" + HEADER_ContentEncoding = "Content-Encoding" + HEADER_AccessControlExposeHeaders = "Access-Control-Expose-Headers" + HEADER_AccessControlRequestMethod = "Access-Control-Request-Method" + HEADER_AccessControlRequestHeaders = "Access-Control-Request-Headers" + HEADER_AccessControlAllowMethods = "Access-Control-Allow-Methods" + HEADER_AccessControlAllowOrigin = "Access-Control-Allow-Origin" + HEADER_AccessControlAllowCredentials = "Access-Control-Allow-Credentials" + HEADER_AccessControlAllowHeaders = "Access-Control-Allow-Headers" + HEADER_AccessControlMaxAge = "Access-Control-Max-Age" + + ENCODING_GZIP = "gzip" + ENCODING_DEFLATE = "deflate" +) diff --git a/vendor/github.com/emicklei/go-restful/container.go b/vendor/github.com/emicklei/go-restful/container.go new file mode 100644 index 000000000..657d5b6dd --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/container.go @@ -0,0 +1,366 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "bytes" + "errors" + "fmt" + "net/http" + "os" + "runtime" + "strings" + "sync" + + "github.com/emicklei/go-restful/log" +) + +// Container holds a collection of WebServices and a http.ServeMux to dispatch http requests. +// The requests are further dispatched to routes of WebServices using a RouteSelector +type Container struct { + webServicesLock sync.RWMutex + webServices []*WebService + ServeMux *http.ServeMux + isRegisteredOnRoot bool + containerFilters []FilterFunction + doNotRecover bool // default is true + recoverHandleFunc RecoverHandleFunction + serviceErrorHandleFunc ServiceErrorHandleFunction + router RouteSelector // default is a CurlyRouter (RouterJSR311 is a slower alternative) + contentEncodingEnabled bool // default is false +} + +// NewContainer creates a new Container using a new ServeMux and default router (CurlyRouter) +func NewContainer() *Container { + return &Container{ + webServices: []*WebService{}, + ServeMux: http.NewServeMux(), + isRegisteredOnRoot: false, + containerFilters: []FilterFunction{}, + doNotRecover: true, + recoverHandleFunc: logStackOnRecover, + serviceErrorHandleFunc: writeServiceError, + router: CurlyRouter{}, + contentEncodingEnabled: false} +} + +// RecoverHandleFunction declares functions that can be used to handle a panic situation. +// The first argument is what recover() returns. The second must be used to communicate an error response. +type RecoverHandleFunction func(interface{}, http.ResponseWriter) + +// RecoverHandler changes the default function (logStackOnRecover) to be called +// when a panic is detected. DoNotRecover must be have its default value (=false). +func (c *Container) RecoverHandler(handler RecoverHandleFunction) { + c.recoverHandleFunc = handler +} + +// ServiceErrorHandleFunction declares functions that can be used to handle a service error situation. +// The first argument is the service error, the second is the request that resulted in the error and +// the third must be used to communicate an error response. +type ServiceErrorHandleFunction func(ServiceError, *Request, *Response) + +// ServiceErrorHandler changes the default function (writeServiceError) to be called +// when a ServiceError is detected. +func (c *Container) ServiceErrorHandler(handler ServiceErrorHandleFunction) { + c.serviceErrorHandleFunc = handler +} + +// DoNotRecover controls whether panics will be caught to return HTTP 500. +// If set to true, Route functions are responsible for handling any error situation. +// Default value is true. +func (c *Container) DoNotRecover(doNot bool) { + c.doNotRecover = doNot +} + +// Router changes the default Router (currently CurlyRouter) +func (c *Container) Router(aRouter RouteSelector) { + c.router = aRouter +} + +// EnableContentEncoding (default=false) allows for GZIP or DEFLATE encoding of responses. +func (c *Container) EnableContentEncoding(enabled bool) { + c.contentEncodingEnabled = enabled +} + +// Add a WebService to the Container. It will detect duplicate root paths and exit in that case. +func (c *Container) Add(service *WebService) *Container { + c.webServicesLock.Lock() + defer c.webServicesLock.Unlock() + + // if rootPath was not set then lazy initialize it + if len(service.rootPath) == 0 { + service.Path("/") + } + + // cannot have duplicate root paths + for _, each := range c.webServices { + if each.RootPath() == service.RootPath() { + log.Printf("[restful] WebService with duplicate root path detected:['%v']", each) + os.Exit(1) + } + } + + // If not registered on root then add specific mapping + if !c.isRegisteredOnRoot { + c.isRegisteredOnRoot = c.addHandler(service, c.ServeMux) + } + c.webServices = append(c.webServices, service) + return c +} + +// addHandler may set a new HandleFunc for the serveMux +// this function must run inside the critical region protected by the webServicesLock. +// returns true if the function was registered on root ("/") +func (c *Container) addHandler(service *WebService, serveMux *http.ServeMux) bool { + pattern := fixedPrefixPath(service.RootPath()) + // check if root path registration is needed + if "/" == pattern || "" == pattern { + serveMux.HandleFunc("/", c.dispatch) + return true + } + // detect if registration already exists + alreadyMapped := false + for _, each := range c.webServices { + if each.RootPath() == service.RootPath() { + alreadyMapped = true + break + } + } + if !alreadyMapped { + serveMux.HandleFunc(pattern, c.dispatch) + if !strings.HasSuffix(pattern, "/") { + serveMux.HandleFunc(pattern+"/", c.dispatch) + } + } + return false +} + +func (c *Container) Remove(ws *WebService) error { + if c.ServeMux == http.DefaultServeMux { + errMsg := fmt.Sprintf("[restful] cannot remove a WebService from a Container using the DefaultServeMux: ['%v']", ws) + log.Printf(errMsg) + return errors.New(errMsg) + } + c.webServicesLock.Lock() + defer c.webServicesLock.Unlock() + // build a new ServeMux and re-register all WebServices + newServeMux := http.NewServeMux() + newServices := []*WebService{} + newIsRegisteredOnRoot := false + for _, each := range c.webServices { + if each.rootPath != ws.rootPath { + // If not registered on root then add specific mapping + if !newIsRegisteredOnRoot { + newIsRegisteredOnRoot = c.addHandler(each, newServeMux) + } + newServices = append(newServices, each) + } + } + c.webServices, c.ServeMux, c.isRegisteredOnRoot = newServices, newServeMux, newIsRegisteredOnRoot + return nil +} + +// logStackOnRecover is the default RecoverHandleFunction and is called +// when DoNotRecover is false and the recoverHandleFunc is not set for the container. +// Default implementation logs the stacktrace and writes the stacktrace on the response. +// This may be a security issue as it exposes sourcecode information. +func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter) { + var buffer bytes.Buffer + buffer.WriteString(fmt.Sprintf("[restful] recover from panic situation: - %v\r\n", panicReason)) + for i := 2; ; i += 1 { + _, file, line, ok := runtime.Caller(i) + if !ok { + break + } + buffer.WriteString(fmt.Sprintf(" %s:%d\r\n", file, line)) + } + log.Print(buffer.String()) + httpWriter.WriteHeader(http.StatusInternalServerError) + httpWriter.Write(buffer.Bytes()) +} + +// writeServiceError is the default ServiceErrorHandleFunction and is called +// when a ServiceError is returned during route selection. Default implementation +// calls resp.WriteErrorString(err.Code, err.Message) +func writeServiceError(err ServiceError, req *Request, resp *Response) { + resp.WriteErrorString(err.Code, err.Message) +} + +// Dispatch the incoming Http Request to a matching WebService. +func (c *Container) Dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) { + if httpWriter == nil { + panic("httpWriter cannot be nil") + } + if httpRequest == nil { + panic("httpRequest cannot be nil") + } + c.dispatch(httpWriter, httpRequest) +} + +// Dispatch the incoming Http Request to a matching WebService. +func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) { + writer := httpWriter + + // CompressingResponseWriter should be closed after all operations are done + defer func() { + if compressWriter, ok := writer.(*CompressingResponseWriter); ok { + compressWriter.Close() + } + }() + + // Instal panic recovery unless told otherwise + if !c.doNotRecover { // catch all for 500 response + defer func() { + if r := recover(); r != nil { + c.recoverHandleFunc(r, writer) + return + } + }() + } + + // Detect if compression is needed + // assume without compression, test for override + if c.contentEncodingEnabled { + doCompress, encoding := wantsCompressedResponse(httpRequest) + if doCompress { + var err error + writer, err = NewCompressingResponseWriter(httpWriter, encoding) + if err != nil { + log.Print("[restful] unable to install compressor: ", err) + httpWriter.WriteHeader(http.StatusInternalServerError) + return + } + } + } + // Find best match Route ; err is non nil if no match was found + var webService *WebService + var route *Route + var err error + func() { + c.webServicesLock.RLock() + defer c.webServicesLock.RUnlock() + webService, route, err = c.router.SelectRoute( + c.webServices, + httpRequest) + }() + if err != nil { + // a non-200 response has already been written + // run container filters anyway ; they should not touch the response... + chain := FilterChain{Filters: c.containerFilters, Target: func(req *Request, resp *Response) { + switch err.(type) { + case ServiceError: + ser := err.(ServiceError) + c.serviceErrorHandleFunc(ser, req, resp) + } + // TODO + }} + chain.ProcessFilter(NewRequest(httpRequest), NewResponse(writer)) + return + } + wrappedRequest, wrappedResponse := route.wrapRequestResponse(writer, httpRequest) + // pass through filters (if any) + if len(c.containerFilters)+len(webService.filters)+len(route.Filters) > 0 { + // compose filter chain + allFilters := []FilterFunction{} + allFilters = append(allFilters, c.containerFilters...) + allFilters = append(allFilters, webService.filters...) + allFilters = append(allFilters, route.Filters...) + chain := FilterChain{Filters: allFilters, Target: func(req *Request, resp *Response) { + // handle request by route after passing all filters + route.Function(wrappedRequest, wrappedResponse) + }} + chain.ProcessFilter(wrappedRequest, wrappedResponse) + } else { + // no filters, handle request by route + route.Function(wrappedRequest, wrappedResponse) + } +} + +// fixedPrefixPath returns the fixed part of the partspec ; it may include template vars {} +func fixedPrefixPath(pathspec string) string { + varBegin := strings.Index(pathspec, "{") + if -1 == varBegin { + return pathspec + } + return pathspec[:varBegin] +} + +// ServeHTTP implements net/http.Handler therefore a Container can be a Handler in a http.Server +func (c *Container) ServeHTTP(httpwriter http.ResponseWriter, httpRequest *http.Request) { + c.ServeMux.ServeHTTP(httpwriter, httpRequest) +} + +// Handle registers the handler for the given pattern. If a handler already exists for pattern, Handle panics. +func (c *Container) Handle(pattern string, handler http.Handler) { + c.ServeMux.Handle(pattern, handler) +} + +// HandleWithFilter registers the handler for the given pattern. +// Container's filter chain is applied for handler. +// If a handler already exists for pattern, HandleWithFilter panics. +func (c *Container) HandleWithFilter(pattern string, handler http.Handler) { + f := func(httpResponse http.ResponseWriter, httpRequest *http.Request) { + if len(c.containerFilters) == 0 { + handler.ServeHTTP(httpResponse, httpRequest) + return + } + + chain := FilterChain{Filters: c.containerFilters, Target: func(req *Request, resp *Response) { + handler.ServeHTTP(httpResponse, httpRequest) + }} + chain.ProcessFilter(NewRequest(httpRequest), NewResponse(httpResponse)) + } + + c.Handle(pattern, http.HandlerFunc(f)) +} + +// Filter appends a container FilterFunction. These are called before dispatching +// a http.Request to a WebService from the container +func (c *Container) Filter(filter FilterFunction) { + c.containerFilters = append(c.containerFilters, filter) +} + +// RegisteredWebServices returns the collections of added WebServices +func (c *Container) RegisteredWebServices() []*WebService { + c.webServicesLock.RLock() + defer c.webServicesLock.RUnlock() + result := make([]*WebService, len(c.webServices)) + for ix := range c.webServices { + result[ix] = c.webServices[ix] + } + return result +} + +// computeAllowedMethods returns a list of HTTP methods that are valid for a Request +func (c *Container) computeAllowedMethods(req *Request) []string { + // Go through all RegisteredWebServices() and all its Routes to collect the options + methods := []string{} + requestPath := req.Request.URL.Path + for _, ws := range c.RegisteredWebServices() { + matches := ws.pathExpr.Matcher.FindStringSubmatch(requestPath) + if matches != nil { + finalMatch := matches[len(matches)-1] + for _, rt := range ws.Routes() { + matches := rt.pathExpr.Matcher.FindStringSubmatch(finalMatch) + if matches != nil { + lastMatch := matches[len(matches)-1] + if lastMatch == "" || lastMatch == "/" { // do not include if value is neither empty nor ‘/’. + methods = append(methods, rt.Method) + } + } + } + } + } + // methods = append(methods, "OPTIONS") not sure about this + return methods +} + +// newBasicRequestResponse creates a pair of Request,Response from its http versions. +// It is basic because no parameter or (produces) content-type information is given. +func newBasicRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request) (*Request, *Response) { + resp := NewResponse(httpWriter) + resp.requestAccept = httpRequest.Header.Get(HEADER_Accept) + return NewRequest(httpRequest), resp +} diff --git a/vendor/github.com/emicklei/go-restful/cors_filter.go b/vendor/github.com/emicklei/go-restful/cors_filter.go new file mode 100644 index 000000000..1efeef072 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/cors_filter.go @@ -0,0 +1,202 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "regexp" + "strconv" + "strings" +) + +// CrossOriginResourceSharing is used to create a Container Filter that implements CORS. +// Cross-origin resource sharing (CORS) is a mechanism that allows JavaScript on a web page +// to make XMLHttpRequests to another domain, not the domain the JavaScript originated from. +// +// http://en.wikipedia.org/wiki/Cross-origin_resource_sharing +// http://enable-cors.org/server.html +// http://www.html5rocks.com/en/tutorials/cors/#toc-handling-a-not-so-simple-request +type CrossOriginResourceSharing struct { + ExposeHeaders []string // list of Header names + AllowedHeaders []string // list of Header names + AllowedDomains []string // list of allowed values for Http Origin. An allowed value can be a regular expression to support subdomain matching. If empty all are allowed. + AllowedMethods []string + MaxAge int // number of seconds before requiring new Options request + CookiesAllowed bool + Container *Container + + allowedOriginPatterns []*regexp.Regexp // internal field for origin regexp check. +} + +// Filter is a filter function that implements the CORS flow as documented on http://enable-cors.org/server.html +// and http://www.html5rocks.com/static/images/cors_server_flowchart.png +func (c CrossOriginResourceSharing) Filter(req *Request, resp *Response, chain *FilterChain) { + origin := req.Request.Header.Get(HEADER_Origin) + if len(origin) == 0 { + if trace { + traceLogger.Print("no Http header Origin set") + } + chain.ProcessFilter(req, resp) + return + } + if !c.isOriginAllowed(origin) { // check whether this origin is allowed + if trace { + traceLogger.Printf("HTTP Origin:%s is not part of %v, neither matches any part of %v", origin, c.AllowedDomains, c.allowedOriginPatterns) + } + chain.ProcessFilter(req, resp) + return + } + if req.Request.Method != "OPTIONS" { + c.doActualRequest(req, resp) + chain.ProcessFilter(req, resp) + return + } + if acrm := req.Request.Header.Get(HEADER_AccessControlRequestMethod); acrm != "" { + c.doPreflightRequest(req, resp) + } else { + c.doActualRequest(req, resp) + chain.ProcessFilter(req, resp) + return + } +} + +func (c CrossOriginResourceSharing) doActualRequest(req *Request, resp *Response) { + c.setOptionsHeaders(req, resp) + // continue processing the response +} + +func (c *CrossOriginResourceSharing) doPreflightRequest(req *Request, resp *Response) { + if len(c.AllowedMethods) == 0 { + if c.Container == nil { + c.AllowedMethods = DefaultContainer.computeAllowedMethods(req) + } else { + c.AllowedMethods = c.Container.computeAllowedMethods(req) + } + } + + acrm := req.Request.Header.Get(HEADER_AccessControlRequestMethod) + if !c.isValidAccessControlRequestMethod(acrm, c.AllowedMethods) { + if trace { + traceLogger.Printf("Http header %s:%s is not in %v", + HEADER_AccessControlRequestMethod, + acrm, + c.AllowedMethods) + } + return + } + acrhs := req.Request.Header.Get(HEADER_AccessControlRequestHeaders) + if len(acrhs) > 0 { + for _, each := range strings.Split(acrhs, ",") { + if !c.isValidAccessControlRequestHeader(strings.Trim(each, " ")) { + if trace { + traceLogger.Printf("Http header %s:%s is not in %v", + HEADER_AccessControlRequestHeaders, + acrhs, + c.AllowedHeaders) + } + return + } + } + } + resp.AddHeader(HEADER_AccessControlAllowMethods, strings.Join(c.AllowedMethods, ",")) + resp.AddHeader(HEADER_AccessControlAllowHeaders, acrhs) + c.setOptionsHeaders(req, resp) + + // return http 200 response, no body +} + +func (c CrossOriginResourceSharing) setOptionsHeaders(req *Request, resp *Response) { + c.checkAndSetExposeHeaders(resp) + c.setAllowOriginHeader(req, resp) + c.checkAndSetAllowCredentials(resp) + if c.MaxAge > 0 { + resp.AddHeader(HEADER_AccessControlMaxAge, strconv.Itoa(c.MaxAge)) + } +} + +func (c CrossOriginResourceSharing) isOriginAllowed(origin string) bool { + if len(origin) == 0 { + return false + } + if len(c.AllowedDomains) == 0 { + return true + } + + allowed := false + for _, domain := range c.AllowedDomains { + if domain == origin { + allowed = true + break + } + } + + if !allowed { + if len(c.allowedOriginPatterns) == 0 { + // compile allowed domains to allowed origin patterns + allowedOriginRegexps, err := compileRegexps(c.AllowedDomains) + if err != nil { + return false + } + c.allowedOriginPatterns = allowedOriginRegexps + } + + for _, pattern := range c.allowedOriginPatterns { + if allowed = pattern.MatchString(origin); allowed { + break + } + } + } + + return allowed +} + +func (c CrossOriginResourceSharing) setAllowOriginHeader(req *Request, resp *Response) { + origin := req.Request.Header.Get(HEADER_Origin) + if c.isOriginAllowed(origin) { + resp.AddHeader(HEADER_AccessControlAllowOrigin, origin) + } +} + +func (c CrossOriginResourceSharing) checkAndSetExposeHeaders(resp *Response) { + if len(c.ExposeHeaders) > 0 { + resp.AddHeader(HEADER_AccessControlExposeHeaders, strings.Join(c.ExposeHeaders, ",")) + } +} + +func (c CrossOriginResourceSharing) checkAndSetAllowCredentials(resp *Response) { + if c.CookiesAllowed { + resp.AddHeader(HEADER_AccessControlAllowCredentials, "true") + } +} + +func (c CrossOriginResourceSharing) isValidAccessControlRequestMethod(method string, allowedMethods []string) bool { + for _, each := range allowedMethods { + if each == method { + return true + } + } + return false +} + +func (c CrossOriginResourceSharing) isValidAccessControlRequestHeader(header string) bool { + for _, each := range c.AllowedHeaders { + if strings.ToLower(each) == strings.ToLower(header) { + return true + } + } + return false +} + +// Take a list of strings and compile them into a list of regular expressions. +func compileRegexps(regexpStrings []string) ([]*regexp.Regexp, error) { + regexps := []*regexp.Regexp{} + for _, regexpStr := range regexpStrings { + r, err := regexp.Compile(regexpStr) + if err != nil { + return regexps, err + } + regexps = append(regexps, r) + } + return regexps, nil +} diff --git a/vendor/github.com/emicklei/go-restful/coverage.sh b/vendor/github.com/emicklei/go-restful/coverage.sh new file mode 100644 index 000000000..e27dbf1a9 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/coverage.sh @@ -0,0 +1,2 @@ +go test -coverprofile=coverage.out +go tool cover -html=coverage.out \ No newline at end of file diff --git a/vendor/github.com/emicklei/go-restful/curly.go b/vendor/github.com/emicklei/go-restful/curly.go new file mode 100644 index 000000000..79f1f5aa2 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/curly.go @@ -0,0 +1,164 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "net/http" + "regexp" + "sort" + "strings" +) + +// CurlyRouter expects Routes with paths that contain zero or more parameters in curly brackets. +type CurlyRouter struct{} + +// SelectRoute is part of the Router interface and returns the best match +// for the WebService and its Route for the given Request. +func (c CurlyRouter) SelectRoute( + webServices []*WebService, + httpRequest *http.Request) (selectedService *WebService, selected *Route, err error) { + + requestTokens := tokenizePath(httpRequest.URL.Path) + + detectedService := c.detectWebService(requestTokens, webServices) + if detectedService == nil { + if trace { + traceLogger.Printf("no WebService was found to match URL path:%s\n", httpRequest.URL.Path) + } + return nil, nil, NewError(http.StatusNotFound, "404: Page Not Found") + } + candidateRoutes := c.selectRoutes(detectedService, requestTokens) + if len(candidateRoutes) == 0 { + if trace { + traceLogger.Printf("no Route in WebService with path %s was found to match URL path:%s\n", detectedService.rootPath, httpRequest.URL.Path) + } + return detectedService, nil, NewError(http.StatusNotFound, "404: Page Not Found") + } + selectedRoute, err := c.detectRoute(candidateRoutes, httpRequest) + if selectedRoute == nil { + return detectedService, nil, err + } + return detectedService, selectedRoute, nil +} + +// selectRoutes return a collection of Route from a WebService that matches the path tokens from the request. +func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortableCurlyRoutes { + candidates := sortableCurlyRoutes{} + for _, each := range ws.routes { + matches, paramCount, staticCount := c.matchesRouteByPathTokens(each.pathParts, requestTokens) + if matches { + candidates.add(curlyRoute{each, paramCount, staticCount}) // TODO make sure Routes() return pointers? + } + } + sort.Sort(sort.Reverse(candidates)) + return candidates +} + +// matchesRouteByPathTokens computes whether it matches, howmany parameters do match and what the number of static path elements are. +func (c CurlyRouter) matchesRouteByPathTokens(routeTokens, requestTokens []string) (matches bool, paramCount int, staticCount int) { + if len(routeTokens) < len(requestTokens) { + // proceed in matching only if last routeToken is wildcard + count := len(routeTokens) + if count == 0 || !strings.HasSuffix(routeTokens[count-1], "*}") { + return false, 0, 0 + } + // proceed + } + for i, routeToken := range routeTokens { + if i == len(requestTokens) { + // reached end of request path + return false, 0, 0 + } + requestToken := requestTokens[i] + if strings.HasPrefix(routeToken, "{") { + paramCount++ + if colon := strings.Index(routeToken, ":"); colon != -1 { + // match by regex + matchesToken, matchesRemainder := c.regularMatchesPathToken(routeToken, colon, requestToken) + if !matchesToken { + return false, 0, 0 + } + if matchesRemainder { + break + } + } + } else { // no { prefix + if requestToken != routeToken { + return false, 0, 0 + } + staticCount++ + } + } + return true, paramCount, staticCount +} + +// regularMatchesPathToken tests whether the regular expression part of routeToken matches the requestToken or all remaining tokens +// format routeToken is {someVar:someExpression}, e.g. {zipcode:[\d][\d][\d][\d][A-Z][A-Z]} +func (c CurlyRouter) regularMatchesPathToken(routeToken string, colon int, requestToken string) (matchesToken bool, matchesRemainder bool) { + regPart := routeToken[colon+1 : len(routeToken)-1] + if regPart == "*" { + if trace { + traceLogger.Printf("wildcard parameter detected in route token %s that matches %s\n", routeToken, requestToken) + } + return true, true + } + matched, err := regexp.MatchString(regPart, requestToken) + return (matched && err == nil), false +} + +var jsr311Router = RouterJSR311{} + +// detectRoute selectes from a list of Route the first match by inspecting both the Accept and Content-Type +// headers of the Request. See also RouterJSR311 in jsr311.go +func (c CurlyRouter) detectRoute(candidateRoutes sortableCurlyRoutes, httpRequest *http.Request) (*Route, error) { + // tracing is done inside detectRoute + return jsr311Router.detectRoute(candidateRoutes.routes(), httpRequest) +} + +// detectWebService returns the best matching webService given the list of path tokens. +// see also computeWebserviceScore +func (c CurlyRouter) detectWebService(requestTokens []string, webServices []*WebService) *WebService { + var best *WebService + score := -1 + for _, each := range webServices { + matches, eachScore := c.computeWebserviceScore(requestTokens, each.pathExpr.tokens) + if matches && (eachScore > score) { + best = each + score = eachScore + } + } + return best +} + +// computeWebserviceScore returns whether tokens match and +// the weighted score of the longest matching consecutive tokens from the beginning. +func (c CurlyRouter) computeWebserviceScore(requestTokens []string, tokens []string) (bool, int) { + if len(tokens) > len(requestTokens) { + return false, 0 + } + score := 0 + for i := 0; i < len(tokens); i++ { + each := requestTokens[i] + other := tokens[i] + if len(each) == 0 && len(other) == 0 { + score++ + continue + } + if len(other) > 0 && strings.HasPrefix(other, "{") { + // no empty match + if len(each) == 0 { + return false, score + } + score += 1 + } else { + // not a parameter + if each != other { + return false, score + } + score += (len(tokens) - i) * 10 //fuzzy + } + } + return true, score +} diff --git a/vendor/github.com/emicklei/go-restful/curly_route.go b/vendor/github.com/emicklei/go-restful/curly_route.go new file mode 100644 index 000000000..296f94650 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/curly_route.go @@ -0,0 +1,52 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +// curlyRoute exits for sorting Routes by the CurlyRouter based on number of parameters and number of static path elements. +type curlyRoute struct { + route Route + paramCount int + staticCount int +} + +type sortableCurlyRoutes []curlyRoute + +func (s *sortableCurlyRoutes) add(route curlyRoute) { + *s = append(*s, route) +} + +func (s sortableCurlyRoutes) routes() (routes []Route) { + for _, each := range s { + routes = append(routes, each.route) // TODO change return type + } + return routes +} + +func (s sortableCurlyRoutes) Len() int { + return len(s) +} +func (s sortableCurlyRoutes) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} +func (s sortableCurlyRoutes) Less(i, j int) bool { + ci := s[i] + cj := s[j] + + // primary key + if ci.staticCount < cj.staticCount { + return true + } + if ci.staticCount > cj.staticCount { + return false + } + // secundary key + if ci.paramCount < cj.paramCount { + return true + } + if ci.paramCount > cj.paramCount { + return false + } + return ci.route.Path < cj.route.Path +} diff --git a/vendor/github.com/emicklei/go-restful/doc.go b/vendor/github.com/emicklei/go-restful/doc.go new file mode 100644 index 000000000..f7c16b01f --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/doc.go @@ -0,0 +1,185 @@ +/* +Package restful , a lean package for creating REST-style WebServices without magic. + +WebServices and Routes + +A WebService has a collection of Route objects that dispatch incoming Http Requests to a function calls. +Typically, a WebService has a root path (e.g. /users) and defines common MIME types for its routes. +WebServices must be added to a container (see below) in order to handler Http requests from a server. + +A Route is defined by a HTTP method, an URL path and (optionally) the MIME types it consumes (Content-Type) and produces (Accept). +This package has the logic to find the best matching Route and if found, call its Function. + + ws := new(restful.WebService) + ws. + Path("/users"). + Consumes(restful.MIME_JSON, restful.MIME_XML). + Produces(restful.MIME_JSON, restful.MIME_XML) + + ws.Route(ws.GET("/{user-id}").To(u.findUser)) // u is a UserResource + + ... + + // GET http://localhost:8080/users/1 + func (u UserResource) findUser(request *restful.Request, response *restful.Response) { + id := request.PathParameter("user-id") + ... + } + +The (*Request, *Response) arguments provide functions for reading information from the request and writing information back to the response. + +See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-user-resource.go with a full implementation. + +Regular expression matching Routes + +A Route parameter can be specified using the format "uri/{var[:regexp]}" or the special version "uri/{var:*}" for matching the tail of the path. +For example, /persons/{name:[A-Z][A-Z]} can be used to restrict values for the parameter "name" to only contain capital alphabetic characters. +Regular expressions must use the standard Go syntax as described in the regexp package. (https://code.google.com/p/re2/wiki/Syntax) +This feature requires the use of a CurlyRouter. + +Containers + +A Container holds a collection of WebServices, Filters and a http.ServeMux for multiplexing http requests. +Using the statements "restful.Add(...) and restful.Filter(...)" will register WebServices and Filters to the Default Container. +The Default container of go-restful uses the http.DefaultServeMux. +You can create your own Container and create a new http.Server for that particular container. + + container := restful.NewContainer() + server := &http.Server{Addr: ":8081", Handler: container} + +Filters + +A filter dynamically intercepts requests and responses to transform or use the information contained in the requests or responses. +You can use filters to perform generic logging, measurement, authentication, redirect, set response headers etc. +In the restful package there are three hooks into the request,response flow where filters can be added. +Each filter must define a FilterFunction: + + func (req *restful.Request, resp *restful.Response, chain *restful.FilterChain) + +Use the following statement to pass the request,response pair to the next filter or RouteFunction + + chain.ProcessFilter(req, resp) + +Container Filters + +These are processed before any registered WebService. + + // install a (global) filter for the default container (processed before any webservice) + restful.Filter(globalLogging) + +WebService Filters + +These are processed before any Route of a WebService. + + // install a webservice filter (processed before any route) + ws.Filter(webserviceLogging).Filter(measureTime) + + +Route Filters + +These are processed before calling the function associated with the Route. + + // install 2 chained route filters (processed before calling findUser) + ws.Route(ws.GET("/{user-id}").Filter(routeLogging).Filter(NewCountFilter().routeCounter).To(findUser)) + +See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-filters.go with full implementations. + +Response Encoding + +Two encodings are supported: gzip and deflate. To enable this for all responses: + + restful.DefaultContainer.EnableContentEncoding(true) + +If a Http request includes the Accept-Encoding header then the response content will be compressed using the specified encoding. +Alternatively, you can create a Filter that performs the encoding and install it per WebService or Route. + +See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-encoding-filter.go + +OPTIONS support + +By installing a pre-defined container filter, your Webservice(s) can respond to the OPTIONS Http request. + + Filter(OPTIONSFilter()) + +CORS + +By installing the filter of a CrossOriginResourceSharing (CORS), your WebService(s) can handle CORS requests. + + cors := CrossOriginResourceSharing{ExposeHeaders: []string{"X-My-Header"}, CookiesAllowed: false, Container: DefaultContainer} + Filter(cors.Filter) + +Error Handling + +Unexpected things happen. If a request cannot be processed because of a failure, your service needs to tell via the response what happened and why. +For this reason HTTP status codes exist and it is important to use the correct code in every exceptional situation. + + 400: Bad Request + +If path or query parameters are not valid (content or type) then use http.StatusBadRequest. + + 404: Not Found + +Despite a valid URI, the resource requested may not be available + + 500: Internal Server Error + +If the application logic could not process the request (or write the response) then use http.StatusInternalServerError. + + 405: Method Not Allowed + +The request has a valid URL but the method (GET,PUT,POST,...) is not allowed. + + 406: Not Acceptable + +The request does not have or has an unknown Accept Header set for this operation. + + 415: Unsupported Media Type + +The request does not have or has an unknown Content-Type Header set for this operation. + +ServiceError + +In addition to setting the correct (error) Http status code, you can choose to write a ServiceError message on the response. + +Performance options + +This package has several options that affect the performance of your service. It is important to understand them and how you can change it. + + restful.DefaultContainer.DoNotRecover(false) + +DoNotRecover controls whether panics will be caught to return HTTP 500. +If set to false, the container will recover from panics. +Default value is true + + restful.SetCompressorProvider(NewBoundedCachedCompressors(20, 20)) + +If content encoding is enabled then the default strategy for getting new gzip/zlib writers and readers is to use a sync.Pool. +Because writers are expensive structures, performance is even more improved when using a preloaded cache. You can also inject your own implementation. + +Trouble shooting + +This package has the means to produce detail logging of the complete Http request matching process and filter invocation. +Enabling this feature requires you to set an implementation of restful.StdLogger (e.g. log.Logger) instance such as: + + restful.TraceLogger(log.New(os.Stdout, "[restful] ", log.LstdFlags|log.Lshortfile)) + +Logging + +The restful.SetLogger() method allows you to override the logger used by the package. By default restful +uses the standard library `log` package and logs to stdout. Different logging packages are supported as +long as they conform to `StdLogger` interface defined in the `log` sub-package, writing an adapter for your +preferred package is simple. + +Resources + +[project]: https://github.com/emicklei/go-restful + +[examples]: https://github.com/emicklei/go-restful/blob/master/examples + +[design]: http://ernestmicklei.com/2012/11/11/go-restful-api-design/ + +[showcases]: https://github.com/emicklei/mora, https://github.com/emicklei/landskape + +(c) 2012-2015, http://ernestmicklei.com. MIT License +*/ +package restful diff --git a/vendor/github.com/emicklei/go-restful/entity_accessors.go b/vendor/github.com/emicklei/go-restful/entity_accessors.go new file mode 100644 index 000000000..6ecf6c7f8 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/entity_accessors.go @@ -0,0 +1,163 @@ +package restful + +// Copyright 2015 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "encoding/json" + "encoding/xml" + "strings" + "sync" +) + +// EntityReaderWriter can read and write values using an encoding such as JSON,XML. +type EntityReaderWriter interface { + // Read a serialized version of the value from the request. + // The Request may have a decompressing reader. Depends on Content-Encoding. + Read(req *Request, v interface{}) error + + // Write a serialized version of the value on the response. + // The Response may have a compressing writer. Depends on Accept-Encoding. + // status should be a valid Http Status code + Write(resp *Response, status int, v interface{}) error +} + +// entityAccessRegistry is a singleton +var entityAccessRegistry = &entityReaderWriters{ + protection: new(sync.RWMutex), + accessors: map[string]EntityReaderWriter{}, +} + +// entityReaderWriters associates MIME to an EntityReaderWriter +type entityReaderWriters struct { + protection *sync.RWMutex + accessors map[string]EntityReaderWriter +} + +func init() { + RegisterEntityAccessor(MIME_JSON, NewEntityAccessorJSON(MIME_JSON)) + RegisterEntityAccessor(MIME_XML, NewEntityAccessorXML(MIME_XML)) +} + +// RegisterEntityAccessor add/overrides the ReaderWriter for encoding content with this MIME type. +func RegisterEntityAccessor(mime string, erw EntityReaderWriter) { + entityAccessRegistry.protection.Lock() + defer entityAccessRegistry.protection.Unlock() + entityAccessRegistry.accessors[mime] = erw +} + +// NewEntityAccessorJSON returns a new EntityReaderWriter for accessing JSON content. +// This package is already initialized with such an accessor using the MIME_JSON contentType. +func NewEntityAccessorJSON(contentType string) EntityReaderWriter { + return entityJSONAccess{ContentType: contentType} +} + +// NewEntityAccessorXML returns a new EntityReaderWriter for accessing XML content. +// This package is already initialized with such an accessor using the MIME_XML contentType. +func NewEntityAccessorXML(contentType string) EntityReaderWriter { + return entityXMLAccess{ContentType: contentType} +} + +// accessorAt returns the registered ReaderWriter for this MIME type. +func (r *entityReaderWriters) accessorAt(mime string) (EntityReaderWriter, bool) { + r.protection.RLock() + defer r.protection.RUnlock() + er, ok := r.accessors[mime] + if !ok { + // retry with reverse lookup + // more expensive but we are in an exceptional situation anyway + for k, v := range r.accessors { + if strings.Contains(mime, k) { + return v, true + } + } + } + return er, ok +} + +// entityXMLAccess is a EntityReaderWriter for XML encoding +type entityXMLAccess struct { + // This is used for setting the Content-Type header when writing + ContentType string +} + +// Read unmarshalls the value from XML +func (e entityXMLAccess) Read(req *Request, v interface{}) error { + return xml.NewDecoder(req.Request.Body).Decode(v) +} + +// Write marshalls the value to JSON and set the Content-Type Header. +func (e entityXMLAccess) Write(resp *Response, status int, v interface{}) error { + return writeXML(resp, status, e.ContentType, v) +} + +// writeXML marshalls the value to JSON and set the Content-Type Header. +func writeXML(resp *Response, status int, contentType string, v interface{}) error { + if v == nil { + resp.WriteHeader(status) + // do not write a nil representation + return nil + } + if resp.prettyPrint { + // pretty output must be created and written explicitly + output, err := xml.MarshalIndent(v, " ", " ") + if err != nil { + return err + } + resp.Header().Set(HEADER_ContentType, contentType) + resp.WriteHeader(status) + _, err = resp.Write([]byte(xml.Header)) + if err != nil { + return err + } + _, err = resp.Write(output) + return err + } + // not-so-pretty + resp.Header().Set(HEADER_ContentType, contentType) + resp.WriteHeader(status) + return xml.NewEncoder(resp).Encode(v) +} + +// entityJSONAccess is a EntityReaderWriter for JSON encoding +type entityJSONAccess struct { + // This is used for setting the Content-Type header when writing + ContentType string +} + +// Read unmarshalls the value from JSON +func (e entityJSONAccess) Read(req *Request, v interface{}) error { + decoder := json.NewDecoder(req.Request.Body) + decoder.UseNumber() + return decoder.Decode(v) +} + +// Write marshalls the value to JSON and set the Content-Type Header. +func (e entityJSONAccess) Write(resp *Response, status int, v interface{}) error { + return writeJSON(resp, status, e.ContentType, v) +} + +// write marshalls the value to JSON and set the Content-Type Header. +func writeJSON(resp *Response, status int, contentType string, v interface{}) error { + if v == nil { + resp.WriteHeader(status) + // do not write a nil representation + return nil + } + if resp.prettyPrint { + // pretty output must be created and written explicitly + output, err := json.MarshalIndent(v, " ", " ") + if err != nil { + return err + } + resp.Header().Set(HEADER_ContentType, contentType) + resp.WriteHeader(status) + _, err = resp.Write(output) + return err + } + // not-so-pretty + resp.Header().Set(HEADER_ContentType, contentType) + resp.WriteHeader(status) + return json.NewEncoder(resp).Encode(v) +} diff --git a/vendor/github.com/emicklei/go-restful/filter.go b/vendor/github.com/emicklei/go-restful/filter.go new file mode 100644 index 000000000..c23bfb591 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/filter.go @@ -0,0 +1,35 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +// FilterChain is a request scoped object to process one or more filters before calling the target RouteFunction. +type FilterChain struct { + Filters []FilterFunction // ordered list of FilterFunction + Index int // index into filters that is currently in progress + Target RouteFunction // function to call after passing all filters +} + +// ProcessFilter passes the request,response pair through the next of Filters. +// Each filter can decide to proceed to the next Filter or handle the Response itself. +func (f *FilterChain) ProcessFilter(request *Request, response *Response) { + if f.Index < len(f.Filters) { + f.Index++ + f.Filters[f.Index-1](request, response, f) + } else { + f.Target(request, response) + } +} + +// FilterFunction definitions must call ProcessFilter on the FilterChain to pass on the control and eventually call the RouteFunction +type FilterFunction func(*Request, *Response, *FilterChain) + +// NoBrowserCacheFilter is a filter function to set HTTP headers that disable browser caching +// See examples/restful-no-cache-filter.go for usage +func NoBrowserCacheFilter(req *Request, resp *Response, chain *FilterChain) { + resp.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1. + resp.Header().Set("Pragma", "no-cache") // HTTP 1.0. + resp.Header().Set("Expires", "0") // Proxies. + chain.ProcessFilter(req, resp) +} diff --git a/vendor/github.com/emicklei/go-restful/jsr311.go b/vendor/github.com/emicklei/go-restful/jsr311.go new file mode 100644 index 000000000..511444ac6 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/jsr311.go @@ -0,0 +1,248 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "errors" + "fmt" + "net/http" + "sort" +) + +// RouterJSR311 implements the flow for matching Requests to Routes (and consequently Resource Functions) +// as specified by the JSR311 http://jsr311.java.net/nonav/releases/1.1/spec/spec.html. +// RouterJSR311 implements the Router interface. +// Concept of locators is not implemented. +type RouterJSR311 struct{} + +// SelectRoute is part of the Router interface and returns the best match +// for the WebService and its Route for the given Request. +func (r RouterJSR311) SelectRoute( + webServices []*WebService, + httpRequest *http.Request) (selectedService *WebService, selectedRoute *Route, err error) { + + // Identify the root resource class (WebService) + dispatcher, finalMatch, err := r.detectDispatcher(httpRequest.URL.Path, webServices) + if err != nil { + return nil, nil, NewError(http.StatusNotFound, "") + } + // Obtain the set of candidate methods (Routes) + routes := r.selectRoutes(dispatcher, finalMatch) + if len(routes) == 0 { + return dispatcher, nil, NewError(http.StatusNotFound, "404: Page Not Found") + } + + // Identify the method (Route) that will handle the request + route, ok := r.detectRoute(routes, httpRequest) + return dispatcher, route, ok +} + +// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 +func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*Route, error) { + // http method + methodOk := []Route{} + for _, each := range routes { + if httpRequest.Method == each.Method { + methodOk = append(methodOk, each) + } + } + if len(methodOk) == 0 { + if trace { + traceLogger.Printf("no Route found (in %d routes) that matches HTTP method %s\n", len(routes), httpRequest.Method) + } + return nil, NewError(http.StatusMethodNotAllowed, "405: Method Not Allowed") + } + inputMediaOk := methodOk + + // content-type + contentType := httpRequest.Header.Get(HEADER_ContentType) + inputMediaOk = []Route{} + for _, each := range methodOk { + if each.matchesContentType(contentType) { + inputMediaOk = append(inputMediaOk, each) + } + } + if len(inputMediaOk) == 0 { + if trace { + traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(methodOk), contentType) + } + return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type") + } + + // accept + outputMediaOk := []Route{} + accept := httpRequest.Header.Get(HEADER_Accept) + if len(accept) == 0 { + accept = "*/*" + } + for _, each := range inputMediaOk { + if each.matchesAccept(accept) { + outputMediaOk = append(outputMediaOk, each) + } + } + if len(outputMediaOk) == 0 { + if trace { + traceLogger.Printf("no Route found (from %d) that matches HTTP Accept: %s\n", len(inputMediaOk), accept) + } + return nil, NewError(http.StatusNotAcceptable, "406: Not Acceptable") + } + // return r.bestMatchByMedia(outputMediaOk, contentType, accept), nil + return &outputMediaOk[0], nil +} + +// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 +// n/m > n/* > */* +func (r RouterJSR311) bestMatchByMedia(routes []Route, contentType string, accept string) *Route { + // TODO + return &routes[0] +} + +// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 (step 2) +func (r RouterJSR311) selectRoutes(dispatcher *WebService, pathRemainder string) []Route { + filtered := &sortableRouteCandidates{} + for _, each := range dispatcher.Routes() { + pathExpr := each.pathExpr + matches := pathExpr.Matcher.FindStringSubmatch(pathRemainder) + if matches != nil { + lastMatch := matches[len(matches)-1] + if len(lastMatch) == 0 || lastMatch == "/" { // do not include if value is neither empty nor ‘/’. + filtered.candidates = append(filtered.candidates, + routeCandidate{each, len(matches) - 1, pathExpr.LiteralCount, pathExpr.VarCount}) + } + } + } + if len(filtered.candidates) == 0 { + if trace { + traceLogger.Printf("WebService on path %s has no routes that match URL path remainder:%s\n", dispatcher.rootPath, pathRemainder) + } + return []Route{} + } + sort.Sort(sort.Reverse(filtered)) + + // select other routes from candidates whoes expression matches rmatch + matchingRoutes := []Route{filtered.candidates[0].route} + for c := 1; c < len(filtered.candidates); c++ { + each := filtered.candidates[c] + if each.route.pathExpr.Matcher.MatchString(pathRemainder) { + matchingRoutes = append(matchingRoutes, each.route) + } + } + return matchingRoutes +} + +// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 (step 1) +func (r RouterJSR311) detectDispatcher(requestPath string, dispatchers []*WebService) (*WebService, string, error) { + filtered := &sortableDispatcherCandidates{} + for _, each := range dispatchers { + matches := each.pathExpr.Matcher.FindStringSubmatch(requestPath) + if matches != nil { + filtered.candidates = append(filtered.candidates, + dispatcherCandidate{each, matches[len(matches)-1], len(matches), each.pathExpr.LiteralCount, each.pathExpr.VarCount}) + } + } + if len(filtered.candidates) == 0 { + if trace { + traceLogger.Printf("no WebService was found to match URL path:%s\n", requestPath) + } + return nil, "", errors.New("not found") + } + sort.Sort(sort.Reverse(filtered)) + return filtered.candidates[0].dispatcher, filtered.candidates[0].finalMatch, nil +} + +// Types and functions to support the sorting of Routes + +type routeCandidate struct { + route Route + matchesCount int // the number of capturing groups + literalCount int // the number of literal characters (means those not resulting from template variable substitution) + nonDefaultCount int // the number of capturing groups with non-default regular expressions (i.e. not ‘([^ /]+?)’) +} + +func (r routeCandidate) expressionToMatch() string { + return r.route.pathExpr.Source +} + +func (r routeCandidate) String() string { + return fmt.Sprintf("(m=%d,l=%d,n=%d)", r.matchesCount, r.literalCount, r.nonDefaultCount) +} + +type sortableRouteCandidates struct { + candidates []routeCandidate +} + +func (rcs *sortableRouteCandidates) Len() int { + return len(rcs.candidates) +} +func (rcs *sortableRouteCandidates) Swap(i, j int) { + rcs.candidates[i], rcs.candidates[j] = rcs.candidates[j], rcs.candidates[i] +} +func (rcs *sortableRouteCandidates) Less(i, j int) bool { + ci := rcs.candidates[i] + cj := rcs.candidates[j] + // primary key + if ci.literalCount < cj.literalCount { + return true + } + if ci.literalCount > cj.literalCount { + return false + } + // secundary key + if ci.matchesCount < cj.matchesCount { + return true + } + if ci.matchesCount > cj.matchesCount { + return false + } + // tertiary key + if ci.nonDefaultCount < cj.nonDefaultCount { + return true + } + if ci.nonDefaultCount > cj.nonDefaultCount { + return false + } + // quaternary key ("source" is interpreted as Path) + return ci.route.Path < cj.route.Path +} + +// Types and functions to support the sorting of Dispatchers + +type dispatcherCandidate struct { + dispatcher *WebService + finalMatch string + matchesCount int // the number of capturing groups + literalCount int // the number of literal characters (means those not resulting from template variable substitution) + nonDefaultCount int // the number of capturing groups with non-default regular expressions (i.e. not ‘([^ /]+?)’) +} +type sortableDispatcherCandidates struct { + candidates []dispatcherCandidate +} + +func (dc *sortableDispatcherCandidates) Len() int { + return len(dc.candidates) +} +func (dc *sortableDispatcherCandidates) Swap(i, j int) { + dc.candidates[i], dc.candidates[j] = dc.candidates[j], dc.candidates[i] +} +func (dc *sortableDispatcherCandidates) Less(i, j int) bool { + ci := dc.candidates[i] + cj := dc.candidates[j] + // primary key + if ci.matchesCount < cj.matchesCount { + return true + } + if ci.matchesCount > cj.matchesCount { + return false + } + // secundary key + if ci.literalCount < cj.literalCount { + return true + } + if ci.literalCount > cj.literalCount { + return false + } + // tertiary key + return ci.nonDefaultCount < cj.nonDefaultCount +} diff --git a/vendor/github.com/emicklei/go-restful/log/log.go b/vendor/github.com/emicklei/go-restful/log/log.go new file mode 100644 index 000000000..6cd44c7a5 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/log/log.go @@ -0,0 +1,34 @@ +package log + +import ( + stdlog "log" + "os" +) + +// StdLogger corresponds to a minimal subset of the interface satisfied by stdlib log.Logger +type StdLogger interface { + Print(v ...interface{}) + Printf(format string, v ...interface{}) +} + +var Logger StdLogger + +func init() { + // default Logger + SetLogger(stdlog.New(os.Stderr, "[restful] ", stdlog.LstdFlags|stdlog.Lshortfile)) +} + +// SetLogger sets the logger for this package +func SetLogger(customLogger StdLogger) { + Logger = customLogger +} + +// Print delegates to the Logger +func Print(v ...interface{}) { + Logger.Print(v...) +} + +// Printf delegates to the Logger +func Printf(format string, v ...interface{}) { + Logger.Printf(format, v...) +} diff --git a/vendor/github.com/emicklei/go-restful/logger.go b/vendor/github.com/emicklei/go-restful/logger.go new file mode 100644 index 000000000..3f1c4db86 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/logger.go @@ -0,0 +1,32 @@ +package restful + +// Copyright 2014 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. +import ( + "github.com/emicklei/go-restful/log" +) + +var trace bool = false +var traceLogger log.StdLogger + +func init() { + traceLogger = log.Logger // use the package logger by default +} + +// TraceLogger enables detailed logging of Http request matching and filter invocation. Default no logger is set. +// You may call EnableTracing() directly to enable trace logging to the package-wide logger. +func TraceLogger(logger log.StdLogger) { + traceLogger = logger + EnableTracing(logger != nil) +} + +// expose the setter for the global logger on the top-level package +func SetLogger(customLogger log.StdLogger) { + log.SetLogger(customLogger) +} + +// EnableTracing can be used to Trace logging on and off. +func EnableTracing(enabled bool) { + trace = enabled +} diff --git a/vendor/github.com/emicklei/go-restful/mime.go b/vendor/github.com/emicklei/go-restful/mime.go new file mode 100644 index 000000000..d7ea2b615 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/mime.go @@ -0,0 +1,45 @@ +package restful + +import ( + "strconv" + "strings" +) + +type mime struct { + media string + quality float64 +} + +// insertMime adds a mime to a list and keeps it sorted by quality. +func insertMime(l []mime, e mime) []mime { + for i, each := range l { + // if current mime has lower quality then insert before + if e.quality > each.quality { + left := append([]mime{}, l[0:i]...) + return append(append(left, e), l[i:]...) + } + } + return append(l, e) +} + +// sortedMimes returns a list of mime sorted (desc) by its specified quality. +func sortedMimes(accept string) (sorted []mime) { + for _, each := range strings.Split(accept, ",") { + typeAndQuality := strings.Split(strings.Trim(each, " "), ";") + if len(typeAndQuality) == 1 { + sorted = insertMime(sorted, mime{typeAndQuality[0], 1.0}) + } else { + // take factor + parts := strings.Split(typeAndQuality[1], "=") + if len(parts) == 2 { + f, err := strconv.ParseFloat(parts[1], 64) + if err != nil { + traceLogger.Printf("unable to parse quality in %s, %v", each, err) + } else { + sorted = insertMime(sorted, mime{typeAndQuality[0], f}) + } + } + } + } + return +} diff --git a/vendor/github.com/emicklei/go-restful/options_filter.go b/vendor/github.com/emicklei/go-restful/options_filter.go new file mode 100644 index 000000000..4514eadcf --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/options_filter.go @@ -0,0 +1,26 @@ +package restful + +import "strings" + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +// OPTIONSFilter is a filter function that inspects the Http Request for the OPTIONS method +// and provides the response with a set of allowed methods for the request URL Path. +// As for any filter, you can also install it for a particular WebService within a Container. +// Note: this filter is not needed when using CrossOriginResourceSharing (for CORS). +func (c *Container) OPTIONSFilter(req *Request, resp *Response, chain *FilterChain) { + if "OPTIONS" != req.Request.Method { + chain.ProcessFilter(req, resp) + return + } + resp.AddHeader(HEADER_Allow, strings.Join(c.computeAllowedMethods(req), ",")) +} + +// OPTIONSFilter is a filter function that inspects the Http Request for the OPTIONS method +// and provides the response with a set of allowed methods for the request URL Path. +// Note: this filter is not needed when using CrossOriginResourceSharing (for CORS). +func OPTIONSFilter() FilterFunction { + return DefaultContainer.OPTIONSFilter +} diff --git a/vendor/github.com/emicklei/go-restful/parameter.go b/vendor/github.com/emicklei/go-restful/parameter.go new file mode 100644 index 000000000..e11c8162a --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/parameter.go @@ -0,0 +1,114 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +const ( + // PathParameterKind = indicator of Request parameter type "path" + PathParameterKind = iota + + // QueryParameterKind = indicator of Request parameter type "query" + QueryParameterKind + + // BodyParameterKind = indicator of Request parameter type "body" + BodyParameterKind + + // HeaderParameterKind = indicator of Request parameter type "header" + HeaderParameterKind + + // FormParameterKind = indicator of Request parameter type "form" + FormParameterKind +) + +// Parameter is for documententing the parameter used in a Http Request +// ParameterData kinds are Path,Query and Body +type Parameter struct { + data *ParameterData +} + +// ParameterData represents the state of a Parameter. +// It is made public to make it accessible to e.g. the Swagger package. +type ParameterData struct { + Name, Description, DataType, DataFormat string + Kind int + Required bool + AllowableValues map[string]string + AllowMultiple bool + DefaultValue string +} + +// Data returns the state of the Parameter +func (p *Parameter) Data() ParameterData { + return *p.data +} + +// Kind returns the parameter type indicator (see const for valid values) +func (p *Parameter) Kind() int { + return p.data.Kind +} + +func (p *Parameter) bePath() *Parameter { + p.data.Kind = PathParameterKind + return p +} +func (p *Parameter) beQuery() *Parameter { + p.data.Kind = QueryParameterKind + return p +} +func (p *Parameter) beBody() *Parameter { + p.data.Kind = BodyParameterKind + return p +} + +func (p *Parameter) beHeader() *Parameter { + p.data.Kind = HeaderParameterKind + return p +} + +func (p *Parameter) beForm() *Parameter { + p.data.Kind = FormParameterKind + return p +} + +// Required sets the required field and returns the receiver +func (p *Parameter) Required(required bool) *Parameter { + p.data.Required = required + return p +} + +// AllowMultiple sets the allowMultiple field and returns the receiver +func (p *Parameter) AllowMultiple(multiple bool) *Parameter { + p.data.AllowMultiple = multiple + return p +} + +// AllowableValues sets the allowableValues field and returns the receiver +func (p *Parameter) AllowableValues(values map[string]string) *Parameter { + p.data.AllowableValues = values + return p +} + +// DataType sets the dataType field and returns the receiver +func (p *Parameter) DataType(typeName string) *Parameter { + p.data.DataType = typeName + return p +} + +// DataFormat sets the dataFormat field for Swagger UI +func (p *Parameter) DataFormat(formatName string) *Parameter { + p.data.DataFormat = formatName + return p +} + +// DefaultValue sets the default value field and returns the receiver +func (p *Parameter) DefaultValue(stringRepresentation string) *Parameter { + p.data.DefaultValue = stringRepresentation + return p +} + +// Description sets the description value field and returns the receiver +func (p *Parameter) Description(doc string) *Parameter { + p.data.Description = doc + return p +} diff --git a/vendor/github.com/emicklei/go-restful/path_expression.go b/vendor/github.com/emicklei/go-restful/path_expression.go new file mode 100644 index 000000000..a921e6f22 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/path_expression.go @@ -0,0 +1,69 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "bytes" + "fmt" + "regexp" + "strings" +) + +// PathExpression holds a compiled path expression (RegExp) needed to match against +// Http request paths and to extract path parameter values. +type pathExpression struct { + LiteralCount int // the number of literal characters (means those not resulting from template variable substitution) + VarCount int // the number of named parameters (enclosed by {}) in the path + Matcher *regexp.Regexp + Source string // Path as defined by the RouteBuilder + tokens []string +} + +// NewPathExpression creates a PathExpression from the input URL path. +// Returns an error if the path is invalid. +func newPathExpression(path string) (*pathExpression, error) { + expression, literalCount, varCount, tokens := templateToRegularExpression(path) + compiled, err := regexp.Compile(expression) + if err != nil { + return nil, err + } + return &pathExpression{literalCount, varCount, compiled, expression, tokens}, nil +} + +// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-370003.7.3 +func templateToRegularExpression(template string) (expression string, literalCount int, varCount int, tokens []string) { + var buffer bytes.Buffer + buffer.WriteString("^") + //tokens = strings.Split(template, "/") + tokens = tokenizePath(template) + for _, each := range tokens { + if each == "" { + continue + } + buffer.WriteString("/") + if strings.HasPrefix(each, "{") { + // check for regular expression in variable + colon := strings.Index(each, ":") + if colon != -1 { + // extract expression + paramExpr := strings.TrimSpace(each[colon+1 : len(each)-1]) + if paramExpr == "*" { // special case + buffer.WriteString("(.*)") + } else { + buffer.WriteString(fmt.Sprintf("(%s)", paramExpr)) // between colon and closing moustache + } + } else { + // plain var + buffer.WriteString("([^/]+?)") + } + varCount += 1 + } else { + literalCount += len(each) + encoded := each // TODO URI encode + buffer.WriteString(regexp.QuoteMeta(encoded)) + } + } + return strings.TrimRight(buffer.String(), "/") + "(/.*)?$", literalCount, varCount, tokens +} diff --git a/vendor/github.com/emicklei/go-restful/request.go b/vendor/github.com/emicklei/go-restful/request.go new file mode 100644 index 000000000..8c23af12c --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/request.go @@ -0,0 +1,113 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "compress/zlib" + "net/http" +) + +var defaultRequestContentType string + +// Request is a wrapper for a http Request that provides convenience methods +type Request struct { + Request *http.Request + pathParameters map[string]string + attributes map[string]interface{} // for storing request-scoped values + selectedRoutePath string // root path + route path that matched the request, e.g. /meetings/{id}/attendees +} + +func NewRequest(httpRequest *http.Request) *Request { + return &Request{ + Request: httpRequest, + pathParameters: map[string]string{}, + attributes: map[string]interface{}{}, + } // empty parameters, attributes +} + +// If ContentType is missing or */* is given then fall back to this type, otherwise +// a "Unable to unmarshal content of type:" response is returned. +// Valid values are restful.MIME_JSON and restful.MIME_XML +// Example: +// restful.DefaultRequestContentType(restful.MIME_JSON) +func DefaultRequestContentType(mime string) { + defaultRequestContentType = mime +} + +// PathParameter accesses the Path parameter value by its name +func (r *Request) PathParameter(name string) string { + return r.pathParameters[name] +} + +// PathParameters accesses the Path parameter values +func (r *Request) PathParameters() map[string]string { + return r.pathParameters +} + +// QueryParameter returns the (first) Query parameter value by its name +func (r *Request) QueryParameter(name string) string { + return r.Request.FormValue(name) +} + +// BodyParameter parses the body of the request (once for typically a POST or a PUT) and returns the value of the given name or an error. +func (r *Request) BodyParameter(name string) (string, error) { + err := r.Request.ParseForm() + if err != nil { + return "", err + } + return r.Request.PostFormValue(name), nil +} + +// HeaderParameter returns the HTTP Header value of a Header name or empty if missing +func (r *Request) HeaderParameter(name string) string { + return r.Request.Header.Get(name) +} + +// ReadEntity checks the Accept header and reads the content into the entityPointer. +func (r *Request) ReadEntity(entityPointer interface{}) (err error) { + contentType := r.Request.Header.Get(HEADER_ContentType) + contentEncoding := r.Request.Header.Get(HEADER_ContentEncoding) + + // check if the request body needs decompression + if ENCODING_GZIP == contentEncoding { + gzipReader := currentCompressorProvider.AcquireGzipReader() + defer currentCompressorProvider.ReleaseGzipReader(gzipReader) + gzipReader.Reset(r.Request.Body) + r.Request.Body = gzipReader + } else if ENCODING_DEFLATE == contentEncoding { + zlibReader, err := zlib.NewReader(r.Request.Body) + if err != nil { + return err + } + r.Request.Body = zlibReader + } + + // lookup the EntityReader, use defaultRequestContentType if needed and provided + entityReader, ok := entityAccessRegistry.accessorAt(contentType) + if !ok { + if len(defaultRequestContentType) != 0 { + entityReader, ok = entityAccessRegistry.accessorAt(defaultRequestContentType) + } + if !ok { + return NewError(http.StatusBadRequest, "Unable to unmarshal content of type:"+contentType) + } + } + return entityReader.Read(r, entityPointer) +} + +// SetAttribute adds or replaces the attribute with the given value. +func (r *Request) SetAttribute(name string, value interface{}) { + r.attributes[name] = value +} + +// Attribute returns the value associated to the given name. Returns nil if absent. +func (r Request) Attribute(name string) interface{} { + return r.attributes[name] +} + +// SelectedRoutePath root path + route path that matched the request, e.g. /meetings/{id}/attendees +func (r Request) SelectedRoutePath() string { + return r.selectedRoutePath +} diff --git a/vendor/github.com/emicklei/go-restful/response.go b/vendor/github.com/emicklei/go-restful/response.go new file mode 100644 index 000000000..3b33ab220 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/response.go @@ -0,0 +1,236 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "errors" + "net/http" +) + +// DefaultResponseMimeType is DEPRECATED, use DefaultResponseContentType(mime) +var DefaultResponseMimeType string + +//PrettyPrintResponses controls the indentation feature of XML and JSON serialization +var PrettyPrintResponses = true + +// Response is a wrapper on the actual http ResponseWriter +// It provides several convenience methods to prepare and write response content. +type Response struct { + http.ResponseWriter + requestAccept string // mime-type what the Http Request says it wants to receive + routeProduces []string // mime-types what the Route says it can produce + statusCode int // HTTP status code that has been written explicity (if zero then net/http has written 200) + contentLength int // number of bytes written for the response body + prettyPrint bool // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses. + err error // err property is kept when WriteError is called +} + +// NewResponse creates a new response based on a http ResponseWriter. +func NewResponse(httpWriter http.ResponseWriter) *Response { + return &Response{httpWriter, "", []string{}, http.StatusOK, 0, PrettyPrintResponses, nil} // empty content-types +} + +// DefaultResponseContentType set a default. +// If Accept header matching fails, fall back to this type. +// Valid values are restful.MIME_JSON and restful.MIME_XML +// Example: +// restful.DefaultResponseContentType(restful.MIME_JSON) +func DefaultResponseContentType(mime string) { + DefaultResponseMimeType = mime +} + +// InternalServerError writes the StatusInternalServerError header. +// DEPRECATED, use WriteErrorString(http.StatusInternalServerError,reason) +func (r Response) InternalServerError() Response { + r.WriteHeader(http.StatusInternalServerError) + return r +} + +// PrettyPrint changes whether this response must produce pretty (line-by-line, indented) JSON or XML output. +func (r *Response) PrettyPrint(bePretty bool) { + r.prettyPrint = bePretty +} + +// AddHeader is a shortcut for .Header().Add(header,value) +func (r Response) AddHeader(header string, value string) Response { + r.Header().Add(header, value) + return r +} + +// SetRequestAccepts tells the response what Mime-type(s) the HTTP request said it wants to accept. Exposed for testing. +func (r *Response) SetRequestAccepts(mime string) { + r.requestAccept = mime +} + +// EntityWriter returns the registered EntityWriter that the entity (requested resource) +// can write according to what the request wants (Accept) and what the Route can produce or what the restful defaults say. +// If called before WriteEntity and WriteHeader then a false return value can be used to write a 406: Not Acceptable. +func (r *Response) EntityWriter() (EntityReaderWriter, bool) { + sorted := sortedMimes(r.requestAccept) + for _, eachAccept := range sorted { + for _, eachProduce := range r.routeProduces { + if eachProduce == eachAccept.media { + if w, ok := entityAccessRegistry.accessorAt(eachAccept.media); ok { + return w, true + } + } + } + if eachAccept.media == "*/*" { + for _, each := range r.routeProduces { + if w, ok := entityAccessRegistry.accessorAt(each); ok { + return w, true + } + } + } + } + // if requestAccept is empty + writer, ok := entityAccessRegistry.accessorAt(r.requestAccept) + if !ok { + // if not registered then fallback to the defaults (if set) + if DefaultResponseMimeType == MIME_JSON { + return entityAccessRegistry.accessorAt(MIME_JSON) + } + if DefaultResponseMimeType == MIME_XML { + return entityAccessRegistry.accessorAt(MIME_XML) + } + // Fallback to whatever the route says it can produce. + // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + for _, each := range r.routeProduces { + if w, ok := entityAccessRegistry.accessorAt(each); ok { + return w, true + } + } + if trace { + traceLogger.Printf("no registered EntityReaderWriter found for %s", r.requestAccept) + } + } + return writer, ok +} + +// WriteEntity calls WriteHeaderAndEntity with Http Status OK (200) +func (r *Response) WriteEntity(value interface{}) error { + return r.WriteHeaderAndEntity(http.StatusOK, value) +} + +// WriteHeaderAndEntity marshals the value using the representation denoted by the Accept Header and the registered EntityWriters. +// If no Accept header is specified (or */*) then respond with the Content-Type as specified by the first in the Route.Produces. +// If an Accept header is specified then respond with the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header. +// If the value is nil then no response is send except for the Http status. You may want to call WriteHeader(http.StatusNotFound) instead. +// If there is no writer available that can represent the value in the requested MIME type then Http Status NotAcceptable is written. +// Current implementation ignores any q-parameters in the Accept Header. +// Returns an error if the value could not be written on the response. +func (r *Response) WriteHeaderAndEntity(status int, value interface{}) error { + writer, ok := r.EntityWriter() + if !ok { + r.WriteHeader(http.StatusNotAcceptable) + return nil + } + return writer.Write(r, status, value) +} + +// WriteAsXml is a convenience method for writing a value in xml (requires Xml tags on the value) +// It uses the standard encoding/xml package for marshalling the value ; not using a registered EntityReaderWriter. +func (r *Response) WriteAsXml(value interface{}) error { + return writeXML(r, http.StatusOK, MIME_XML, value) +} + +// WriteHeaderAndXml is a convenience method for writing a status and value in xml (requires Xml tags on the value) +// It uses the standard encoding/xml package for marshalling the value ; not using a registered EntityReaderWriter. +func (r *Response) WriteHeaderAndXml(status int, value interface{}) error { + return writeXML(r, status, MIME_XML, value) +} + +// WriteAsJson is a convenience method for writing a value in json. +// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter. +func (r *Response) WriteAsJson(value interface{}) error { + return writeJSON(r, http.StatusOK, MIME_JSON, value) +} + +// WriteJson is a convenience method for writing a value in Json with a given Content-Type. +// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter. +func (r *Response) WriteJson(value interface{}, contentType string) error { + return writeJSON(r, http.StatusOK, contentType, value) +} + +// WriteHeaderAndJson is a convenience method for writing the status and a value in Json with a given Content-Type. +// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter. +func (r *Response) WriteHeaderAndJson(status int, value interface{}, contentType string) error { + return writeJSON(r, status, contentType, value) +} + +// WriteError write the http status and the error string on the response. +func (r *Response) WriteError(httpStatus int, err error) error { + r.err = err + return r.WriteErrorString(httpStatus, err.Error()) +} + +// WriteServiceError is a convenience method for a responding with a status and a ServiceError +func (r *Response) WriteServiceError(httpStatus int, err ServiceError) error { + r.err = err + return r.WriteHeaderAndEntity(httpStatus, err) +} + +// WriteErrorString is a convenience method for an error status with the actual error +func (r *Response) WriteErrorString(httpStatus int, errorReason string) error { + if r.err == nil { + // if not called from WriteError + r.err = errors.New(errorReason) + } + r.WriteHeader(httpStatus) + if _, err := r.Write([]byte(errorReason)); err != nil { + return err + } + return nil +} + +// Flush implements http.Flusher interface, which sends any buffered data to the client. +func (r *Response) Flush() { + if f, ok := r.ResponseWriter.(http.Flusher); ok { + f.Flush() + } else if trace { + traceLogger.Printf("ResponseWriter %v doesn't support Flush", r) + } +} + +// WriteHeader is overridden to remember the Status Code that has been written. +// Changes to the Header of the response have no effect after this. +func (r *Response) WriteHeader(httpStatus int) { + r.statusCode = httpStatus + r.ResponseWriter.WriteHeader(httpStatus) +} + +// StatusCode returns the code that has been written using WriteHeader. +func (r Response) StatusCode() int { + if 0 == r.statusCode { + // no status code has been written yet; assume OK + return http.StatusOK + } + return r.statusCode +} + +// Write writes the data to the connection as part of an HTTP reply. +// Write is part of http.ResponseWriter interface. +func (r *Response) Write(bytes []byte) (int, error) { + written, err := r.ResponseWriter.Write(bytes) + r.contentLength += written + return written, err +} + +// ContentLength returns the number of bytes written for the response content. +// Note that this value is only correct if all data is written through the Response using its Write* methods. +// Data written directly using the underlying http.ResponseWriter is not accounted for. +func (r Response) ContentLength() int { + return r.contentLength +} + +// CloseNotify is part of http.CloseNotifier interface +func (r Response) CloseNotify() <-chan bool { + return r.ResponseWriter.(http.CloseNotifier).CloseNotify() +} + +// Error returns the err created by WriteError +func (r Response) Error() error { + return r.err +} diff --git a/vendor/github.com/emicklei/go-restful/route.go b/vendor/github.com/emicklei/go-restful/route.go new file mode 100644 index 000000000..3dd520eec --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/route.go @@ -0,0 +1,186 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "bytes" + "net/http" + "strings" +) + +// RouteFunction declares the signature of a function that can be bound to a Route. +type RouteFunction func(*Request, *Response) + +// Route binds a HTTP Method,Path,Consumes combination to a RouteFunction. +type Route struct { + Method string + Produces []string + Consumes []string + Path string // webservice root path + described path + Function RouteFunction + Filters []FilterFunction + + // cached values for dispatching + relativePath string + pathParts []string + pathExpr *pathExpression // cached compilation of relativePath as RegExp + + // documentation + Doc string + Notes string + Operation string + ParameterDocs []*Parameter + ResponseErrors map[int]ResponseError + ReadSample, WriteSample interface{} // structs that model an example request or response payload + + // Extra information used to store custom information about the route. + Metadata map[string]interface{} +} + +// Initialize for Route +func (r *Route) postBuild() { + r.pathParts = tokenizePath(r.Path) +} + +// Create Request and Response from their http versions +func (r *Route) wrapRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request) (*Request, *Response) { + params := r.extractParameters(httpRequest.URL.Path) + wrappedRequest := NewRequest(httpRequest) + wrappedRequest.pathParameters = params + wrappedRequest.selectedRoutePath = r.Path + wrappedResponse := NewResponse(httpWriter) + wrappedResponse.requestAccept = httpRequest.Header.Get(HEADER_Accept) + wrappedResponse.routeProduces = r.Produces + return wrappedRequest, wrappedResponse +} + +// dispatchWithFilters call the function after passing through its own filters +func (r *Route) dispatchWithFilters(wrappedRequest *Request, wrappedResponse *Response) { + if len(r.Filters) > 0 { + chain := FilterChain{Filters: r.Filters, Target: r.Function} + chain.ProcessFilter(wrappedRequest, wrappedResponse) + } else { + // unfiltered + r.Function(wrappedRequest, wrappedResponse) + } +} + +// Return whether the mimeType matches to what this Route can produce. +func (r Route) matchesAccept(mimeTypesWithQuality string) bool { + parts := strings.Split(mimeTypesWithQuality, ",") + for _, each := range parts { + var withoutQuality string + if strings.Contains(each, ";") { + withoutQuality = strings.Split(each, ";")[0] + } else { + withoutQuality = each + } + // trim before compare + withoutQuality = strings.Trim(withoutQuality, " ") + if withoutQuality == "*/*" { + return true + } + for _, producibleType := range r.Produces { + if producibleType == "*/*" || producibleType == withoutQuality { + return true + } + } + } + return false +} + +// Return whether this Route can consume content with a type specified by mimeTypes (can be empty). +func (r Route) matchesContentType(mimeTypes string) bool { + + if len(r.Consumes) == 0 { + // did not specify what it can consume ; any media type (“*/*”) is assumed + return true + } + + if len(mimeTypes) == 0 { + // idempotent methods with (most-likely or garanteed) empty content match missing Content-Type + m := r.Method + if m == "GET" || m == "HEAD" || m == "OPTIONS" || m == "DELETE" || m == "TRACE" { + return true + } + // proceed with default + mimeTypes = MIME_OCTET + } + + parts := strings.Split(mimeTypes, ",") + for _, each := range parts { + var contentType string + if strings.Contains(each, ";") { + contentType = strings.Split(each, ";")[0] + } else { + contentType = each + } + // trim before compare + contentType = strings.Trim(contentType, " ") + for _, consumeableType := range r.Consumes { + if consumeableType == "*/*" || consumeableType == contentType { + return true + } + } + } + return false +} + +// Extract the parameters from the request url path +func (r Route) extractParameters(urlPath string) map[string]string { + urlParts := tokenizePath(urlPath) + pathParameters := map[string]string{} + for i, key := range r.pathParts { + var value string + if i >= len(urlParts) { + value = "" + } else { + value = urlParts[i] + } + if strings.HasPrefix(key, "{") { // path-parameter + if colon := strings.Index(key, ":"); colon != -1 { + // extract by regex + regPart := key[colon+1 : len(key)-1] + keyPart := key[1:colon] + if regPart == "*" { + pathParameters[keyPart] = untokenizePath(i, urlParts) + break + } else { + pathParameters[keyPart] = value + } + } else { + // without enclosing {} + pathParameters[key[1:len(key)-1]] = value + } + } + } + return pathParameters +} + +// Untokenize back into an URL path using the slash separator +func untokenizePath(offset int, parts []string) string { + var buffer bytes.Buffer + for p := offset; p < len(parts); p++ { + buffer.WriteString(parts[p]) + // do not end + if p < len(parts)-1 { + buffer.WriteString("/") + } + } + return buffer.String() +} + +// Tokenize an URL path using the slash separator ; the result does not have empty tokens +func tokenizePath(path string) []string { + if "/" == path { + return []string{} + } + return strings.Split(strings.Trim(path, "/"), "/") +} + +// for debugging +func (r Route) String() string { + return r.Method + " " + r.Path +} diff --git a/vendor/github.com/emicklei/go-restful/route_builder.go b/vendor/github.com/emicklei/go-restful/route_builder.go new file mode 100644 index 000000000..5ad4a3a7c --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/route_builder.go @@ -0,0 +1,293 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "fmt" + "os" + "reflect" + "runtime" + "strings" + "sync/atomic" + + "github.com/emicklei/go-restful/log" +) + +// RouteBuilder is a helper to construct Routes. +type RouteBuilder struct { + rootPath string + currentPath string + produces []string + consumes []string + httpMethod string // required + function RouteFunction // required + filters []FilterFunction + + typeNameHandleFunc TypeNameHandleFunction // required + + // documentation + doc string + notes string + operation string + readSample, writeSample interface{} + parameters []*Parameter + errorMap map[int]ResponseError + metadata map[string]interface{} +} + +// Do evaluates each argument with the RouteBuilder itself. +// This allows you to follow DRY principles without breaking the fluent programming style. +// Example: +// ws.Route(ws.DELETE("/{name}").To(t.deletePerson).Do(Returns200, Returns500)) +// +// func Returns500(b *RouteBuilder) { +// b.Returns(500, "Internal Server Error", restful.ServiceError{}) +// } +func (b *RouteBuilder) Do(oneArgBlocks ...func(*RouteBuilder)) *RouteBuilder { + for _, each := range oneArgBlocks { + each(b) + } + return b +} + +// To bind the route to a function. +// If this route is matched with the incoming Http Request then call this function with the *Request,*Response pair. Required. +func (b *RouteBuilder) To(function RouteFunction) *RouteBuilder { + b.function = function + return b +} + +// Method specifies what HTTP method to match. Required. +func (b *RouteBuilder) Method(method string) *RouteBuilder { + b.httpMethod = method + return b +} + +// Produces specifies what MIME types can be produced ; the matched one will appear in the Content-Type Http header. +func (b *RouteBuilder) Produces(mimeTypes ...string) *RouteBuilder { + b.produces = mimeTypes + return b +} + +// Consumes specifies what MIME types can be consumes ; the Accept Http header must matched any of these +func (b *RouteBuilder) Consumes(mimeTypes ...string) *RouteBuilder { + b.consumes = mimeTypes + return b +} + +// Path specifies the relative (w.r.t WebService root path) URL path to match. Default is "/". +func (b *RouteBuilder) Path(subPath string) *RouteBuilder { + b.currentPath = subPath + return b +} + +// Doc tells what this route is all about. Optional. +func (b *RouteBuilder) Doc(documentation string) *RouteBuilder { + b.doc = documentation + return b +} + +// A verbose explanation of the operation behavior. Optional. +func (b *RouteBuilder) Notes(notes string) *RouteBuilder { + b.notes = notes + return b +} + +// Reads tells what resource type will be read from the request payload. Optional. +// A parameter of type "body" is added ,required is set to true and the dataType is set to the qualified name of the sample's type. +func (b *RouteBuilder) Reads(sample interface{}) *RouteBuilder { + fn := b.typeNameHandleFunc + if fn == nil { + fn = reflectTypeName + } + typeAsName := fn(sample) + + b.readSample = sample + bodyParameter := &Parameter{&ParameterData{Name: "body"}} + bodyParameter.beBody() + bodyParameter.Required(true) + bodyParameter.DataType(typeAsName) + b.Param(bodyParameter) + return b +} + +// ParameterNamed returns a Parameter already known to the RouteBuilder. Returns nil if not. +// Use this to modify or extend information for the Parameter (through its Data()). +func (b RouteBuilder) ParameterNamed(name string) (p *Parameter) { + for _, each := range b.parameters { + if each.Data().Name == name { + return each + } + } + return p +} + +// Writes tells what resource type will be written as the response payload. Optional. +func (b *RouteBuilder) Writes(sample interface{}) *RouteBuilder { + b.writeSample = sample + return b +} + +// Param allows you to document the parameters of the Route. It adds a new Parameter (does not check for duplicates). +func (b *RouteBuilder) Param(parameter *Parameter) *RouteBuilder { + if b.parameters == nil { + b.parameters = []*Parameter{} + } + b.parameters = append(b.parameters, parameter) + return b +} + +// Operation allows you to document what the actual method/function call is of the Route. +// Unless called, the operation name is derived from the RouteFunction set using To(..). +func (b *RouteBuilder) Operation(name string) *RouteBuilder { + b.operation = name + return b +} + +// ReturnsError is deprecated, use Returns instead. +func (b *RouteBuilder) ReturnsError(code int, message string, model interface{}) *RouteBuilder { + log.Print("ReturnsError is deprecated, use Returns instead.") + return b.Returns(code, message, model) +} + +// Returns allows you to document what responses (errors or regular) can be expected. +// The model parameter is optional ; either pass a struct instance or use nil if not applicable. +func (b *RouteBuilder) Returns(code int, message string, model interface{}) *RouteBuilder { + err := ResponseError{ + Code: code, + Message: message, + Model: model, + IsDefault: false, + } + // lazy init because there is no NewRouteBuilder (yet) + if b.errorMap == nil { + b.errorMap = map[int]ResponseError{} + } + b.errorMap[code] = err + return b +} + +// DefaultReturns is a special Returns call that sets the default of the response ; the code is zero. +func (b *RouteBuilder) DefaultReturns(message string, model interface{}) *RouteBuilder { + b.Returns(0, message, model) + // Modify the ResponseError just added/updated + re := b.errorMap[0] + // errorMap is initialized + b.errorMap[0] = ResponseError{ + Code: re.Code, + Message: re.Message, + Model: re.Model, + IsDefault: true, + } + return b +} + +// Metadata adds or updates a key=value pair to the metadata map. +func (b *RouteBuilder) Metadata(key string, value interface{}) *RouteBuilder { + if b.metadata == nil { + b.metadata = map[string]interface{}{} + } + b.metadata[key] = value + return b +} + +// ResponseError represents a response; not necessarily an error. +type ResponseError struct { + Code int + Message string + Model interface{} + IsDefault bool +} + +func (b *RouteBuilder) servicePath(path string) *RouteBuilder { + b.rootPath = path + return b +} + +// Filter appends a FilterFunction to the end of filters for this Route to build. +func (b *RouteBuilder) Filter(filter FilterFunction) *RouteBuilder { + b.filters = append(b.filters, filter) + return b +} + +// If no specific Route path then set to rootPath +// If no specific Produces then set to rootProduces +// If no specific Consumes then set to rootConsumes +func (b *RouteBuilder) copyDefaults(rootProduces, rootConsumes []string) { + if len(b.produces) == 0 { + b.produces = rootProduces + } + if len(b.consumes) == 0 { + b.consumes = rootConsumes + } +} + +// typeNameHandler sets the function that will convert types to strings in the parameter +// and model definitions. +func (b *RouteBuilder) typeNameHandler(handler TypeNameHandleFunction) *RouteBuilder { + b.typeNameHandleFunc = handler + return b +} + +// Build creates a new Route using the specification details collected by the RouteBuilder +func (b *RouteBuilder) Build() Route { + pathExpr, err := newPathExpression(b.currentPath) + if err != nil { + log.Printf("[restful] Invalid path:%s because:%v", b.currentPath, err) + os.Exit(1) + } + if b.function == nil { + log.Printf("[restful] No function specified for route:" + b.currentPath) + os.Exit(1) + } + operationName := b.operation + if len(operationName) == 0 && b.function != nil { + // extract from definition + operationName = nameOfFunction(b.function) + } + route := Route{ + Method: b.httpMethod, + Path: concatPath(b.rootPath, b.currentPath), + Produces: b.produces, + Consumes: b.consumes, + Function: b.function, + Filters: b.filters, + relativePath: b.currentPath, + pathExpr: pathExpr, + Doc: b.doc, + Notes: b.notes, + Operation: operationName, + ParameterDocs: b.parameters, + ResponseErrors: b.errorMap, + ReadSample: b.readSample, + WriteSample: b.writeSample, + Metadata: b.metadata} + route.postBuild() + return route +} + +func concatPath(path1, path2 string) string { + return strings.TrimRight(path1, "/") + "/" + strings.TrimLeft(path2, "/") +} + +var anonymousFuncCount int32 + +// nameOfFunction returns the short name of the function f for documentation. +// It uses a runtime feature for debugging ; its value may change for later Go versions. +func nameOfFunction(f interface{}) string { + fun := runtime.FuncForPC(reflect.ValueOf(f).Pointer()) + tokenized := strings.Split(fun.Name(), ".") + last := tokenized[len(tokenized)-1] + last = strings.TrimSuffix(last, ")·fm") // < Go 1.5 + last = strings.TrimSuffix(last, ")-fm") // Go 1.5 + last = strings.TrimSuffix(last, "·fm") // < Go 1.5 + last = strings.TrimSuffix(last, "-fm") // Go 1.5 + if last == "func1" { // this could mean conflicts in API docs + val := atomic.AddInt32(&anonymousFuncCount, 1) + last = "func" + fmt.Sprintf("%d", val) + atomic.StoreInt32(&anonymousFuncCount, val) + } + return last +} diff --git a/vendor/github.com/emicklei/go-restful/router.go b/vendor/github.com/emicklei/go-restful/router.go new file mode 100644 index 000000000..9b32fb675 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/router.go @@ -0,0 +1,18 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import "net/http" + +// A RouteSelector finds the best matching Route given the input HTTP Request +type RouteSelector interface { + + // SelectRoute finds a Route given the input HTTP Request and a list of WebServices. + // It returns a selected Route and its containing WebService or an error indicating + // a problem. + SelectRoute( + webServices []*WebService, + httpRequest *http.Request) (selectedService *WebService, selected *Route, err error) +} diff --git a/vendor/github.com/emicklei/go-restful/service_error.go b/vendor/github.com/emicklei/go-restful/service_error.go new file mode 100644 index 000000000..62d1108bb --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/service_error.go @@ -0,0 +1,23 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import "fmt" + +// ServiceError is a transport object to pass information about a non-Http error occurred in a WebService while processing a request. +type ServiceError struct { + Code int + Message string +} + +// NewError returns a ServiceError using the code and reason +func NewError(code int, message string) ServiceError { + return ServiceError{Code: code, Message: message} +} + +// Error returns a text representation of the service error +func (s ServiceError) Error() string { + return fmt.Sprintf("[ServiceError:%v] %v", s.Code, s.Message) +} diff --git a/vendor/github.com/emicklei/go-restful/web_service.go b/vendor/github.com/emicklei/go-restful/web_service.go new file mode 100644 index 000000000..7af60233a --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/web_service.go @@ -0,0 +1,290 @@ +package restful + +import ( + "errors" + "os" + "reflect" + "sync" + + "github.com/emicklei/go-restful/log" +) + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +// WebService holds a collection of Route values that bind a Http Method + URL Path to a function. +type WebService struct { + rootPath string + pathExpr *pathExpression // cached compilation of rootPath as RegExp + routes []Route + produces []string + consumes []string + pathParameters []*Parameter + filters []FilterFunction + documentation string + apiVersion string + + typeNameHandleFunc TypeNameHandleFunction + + dynamicRoutes bool + + // protects 'routes' if dynamic routes are enabled + routesLock sync.RWMutex +} + +func (w *WebService) SetDynamicRoutes(enable bool) { + w.dynamicRoutes = enable +} + +// TypeNameHandleFunction declares functions that can handle translating the name of a sample object +// into the restful documentation for the service. +type TypeNameHandleFunction func(sample interface{}) string + +// TypeNameHandler sets the function that will convert types to strings in the parameter +// and model definitions. If not set, the web service will invoke +// reflect.TypeOf(object).String(). +func (w *WebService) TypeNameHandler(handler TypeNameHandleFunction) *WebService { + w.typeNameHandleFunc = handler + return w +} + +// reflectTypeName is the default TypeNameHandleFunction and for a given object +// returns the name that Go identifies it with (e.g. "string" or "v1.Object") via +// the reflection API. +func reflectTypeName(sample interface{}) string { + return reflect.TypeOf(sample).String() +} + +// compilePathExpression ensures that the path is compiled into a RegEx for those routers that need it. +func (w *WebService) compilePathExpression() { + compiled, err := newPathExpression(w.rootPath) + if err != nil { + log.Printf("[restful] invalid path:%s because:%v", w.rootPath, err) + os.Exit(1) + } + w.pathExpr = compiled +} + +// ApiVersion sets the API version for documentation purposes. +func (w *WebService) ApiVersion(apiVersion string) *WebService { + w.apiVersion = apiVersion + return w +} + +// Version returns the API version for documentation purposes. +func (w *WebService) Version() string { return w.apiVersion } + +// Path specifies the root URL template path of the WebService. +// All Routes will be relative to this path. +func (w *WebService) Path(root string) *WebService { + w.rootPath = root + if len(w.rootPath) == 0 { + w.rootPath = "/" + } + w.compilePathExpression() + return w +} + +// Param adds a PathParameter to document parameters used in the root path. +func (w *WebService) Param(parameter *Parameter) *WebService { + if w.pathParameters == nil { + w.pathParameters = []*Parameter{} + } + w.pathParameters = append(w.pathParameters, parameter) + return w +} + +// PathParameter creates a new Parameter of kind Path for documentation purposes. +// It is initialized as required with string as its DataType. +func (w *WebService) PathParameter(name, description string) *Parameter { + return PathParameter(name, description) +} + +// PathParameter creates a new Parameter of kind Path for documentation purposes. +// It is initialized as required with string as its DataType. +func PathParameter(name, description string) *Parameter { + p := &Parameter{&ParameterData{Name: name, Description: description, Required: true, DataType: "string"}} + p.bePath() + return p +} + +// QueryParameter creates a new Parameter of kind Query for documentation purposes. +// It is initialized as not required with string as its DataType. +func (w *WebService) QueryParameter(name, description string) *Parameter { + return QueryParameter(name, description) +} + +// QueryParameter creates a new Parameter of kind Query for documentation purposes. +// It is initialized as not required with string as its DataType. +func QueryParameter(name, description string) *Parameter { + p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}} + p.beQuery() + return p +} + +// BodyParameter creates a new Parameter of kind Body for documentation purposes. +// It is initialized as required without a DataType. +func (w *WebService) BodyParameter(name, description string) *Parameter { + return BodyParameter(name, description) +} + +// BodyParameter creates a new Parameter of kind Body for documentation purposes. +// It is initialized as required without a DataType. +func BodyParameter(name, description string) *Parameter { + p := &Parameter{&ParameterData{Name: name, Description: description, Required: true}} + p.beBody() + return p +} + +// HeaderParameter creates a new Parameter of kind (Http) Header for documentation purposes. +// It is initialized as not required with string as its DataType. +func (w *WebService) HeaderParameter(name, description string) *Parameter { + return HeaderParameter(name, description) +} + +// HeaderParameter creates a new Parameter of kind (Http) Header for documentation purposes. +// It is initialized as not required with string as its DataType. +func HeaderParameter(name, description string) *Parameter { + p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}} + p.beHeader() + return p +} + +// FormParameter creates a new Parameter of kind Form (using application/x-www-form-urlencoded) for documentation purposes. +// It is initialized as required with string as its DataType. +func (w *WebService) FormParameter(name, description string) *Parameter { + return FormParameter(name, description) +} + +// FormParameter creates a new Parameter of kind Form (using application/x-www-form-urlencoded) for documentation purposes. +// It is initialized as required with string as its DataType. +func FormParameter(name, description string) *Parameter { + p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}} + p.beForm() + return p +} + +// Route creates a new Route using the RouteBuilder and add to the ordered list of Routes. +func (w *WebService) Route(builder *RouteBuilder) *WebService { + w.routesLock.Lock() + defer w.routesLock.Unlock() + builder.copyDefaults(w.produces, w.consumes) + w.routes = append(w.routes, builder.Build()) + return w +} + +// RemoveRoute removes the specified route, looks for something that matches 'path' and 'method' +func (w *WebService) RemoveRoute(path, method string) error { + if !w.dynamicRoutes { + return errors.New("dynamic routes are not enabled.") + } + w.routesLock.Lock() + defer w.routesLock.Unlock() + newRoutes := make([]Route, (len(w.routes) - 1)) + current := 0 + for ix := range w.routes { + if w.routes[ix].Method == method && w.routes[ix].Path == path { + continue + } + newRoutes[current] = w.routes[ix] + current = current + 1 + } + w.routes = newRoutes + return nil +} + +// Method creates a new RouteBuilder and initialize its http method +func (w *WebService) Method(httpMethod string) *RouteBuilder { + return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method(httpMethod) +} + +// Produces specifies that this WebService can produce one or more MIME types. +// Http requests must have one of these values set for the Accept header. +func (w *WebService) Produces(contentTypes ...string) *WebService { + w.produces = contentTypes + return w +} + +// Consumes specifies that this WebService can consume one or more MIME types. +// Http requests must have one of these values set for the Content-Type header. +func (w *WebService) Consumes(accepts ...string) *WebService { + w.consumes = accepts + return w +} + +// Routes returns the Routes associated with this WebService +func (w *WebService) Routes() []Route { + if !w.dynamicRoutes { + return w.routes + } + // Make a copy of the array to prevent concurrency problems + w.routesLock.RLock() + defer w.routesLock.RUnlock() + result := make([]Route, len(w.routes)) + for ix := range w.routes { + result[ix] = w.routes[ix] + } + return result +} + +// RootPath returns the RootPath associated with this WebService. Default "/" +func (w *WebService) RootPath() string { + return w.rootPath +} + +// PathParameters return the path parameter names for (shared amoung its Routes) +func (w *WebService) PathParameters() []*Parameter { + return w.pathParameters +} + +// Filter adds a filter function to the chain of filters applicable to all its Routes +func (w *WebService) Filter(filter FilterFunction) *WebService { + w.filters = append(w.filters, filter) + return w +} + +// Doc is used to set the documentation of this service. +func (w *WebService) Doc(plainText string) *WebService { + w.documentation = plainText + return w +} + +// Documentation returns it. +func (w *WebService) Documentation() string { + return w.documentation +} + +/* + Convenience methods +*/ + +// HEAD is a shortcut for .Method("HEAD").Path(subPath) +func (w *WebService) HEAD(subPath string) *RouteBuilder { + return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("HEAD").Path(subPath) +} + +// GET is a shortcut for .Method("GET").Path(subPath) +func (w *WebService) GET(subPath string) *RouteBuilder { + return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("GET").Path(subPath) +} + +// POST is a shortcut for .Method("POST").Path(subPath) +func (w *WebService) POST(subPath string) *RouteBuilder { + return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("POST").Path(subPath) +} + +// PUT is a shortcut for .Method("PUT").Path(subPath) +func (w *WebService) PUT(subPath string) *RouteBuilder { + return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PUT").Path(subPath) +} + +// PATCH is a shortcut for .Method("PATCH").Path(subPath) +func (w *WebService) PATCH(subPath string) *RouteBuilder { + return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PATCH").Path(subPath) +} + +// DELETE is a shortcut for .Method("DELETE").Path(subPath) +func (w *WebService) DELETE(subPath string) *RouteBuilder { + return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("DELETE").Path(subPath) +} diff --git a/vendor/github.com/emicklei/go-restful/web_service_container.go b/vendor/github.com/emicklei/go-restful/web_service_container.go new file mode 100644 index 000000000..c9d31b06c --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/web_service_container.go @@ -0,0 +1,39 @@ +package restful + +// Copyright 2013 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +import ( + "net/http" +) + +// DefaultContainer is a restful.Container that uses http.DefaultServeMux +var DefaultContainer *Container + +func init() { + DefaultContainer = NewContainer() + DefaultContainer.ServeMux = http.DefaultServeMux +} + +// If set the true then panics will not be caught to return HTTP 500. +// In that case, Route functions are responsible for handling any error situation. +// Default value is false = recover from panics. This has performance implications. +// OBSOLETE ; use restful.DefaultContainer.DoNotRecover(true) +var DoNotRecover = false + +// Add registers a new WebService add it to the DefaultContainer. +func Add(service *WebService) { + DefaultContainer.Add(service) +} + +// Filter appends a container FilterFunction from the DefaultContainer. +// These are called before dispatching a http.Request to a WebService. +func Filter(filter FilterFunction) { + DefaultContainer.Filter(filter) +} + +// RegisteredWebServices returns the collections of WebServices from the DefaultContainer +func RegisteredWebServices() []*WebService { + return DefaultContainer.RegisteredWebServices() +} diff --git a/vendor/github.com/fatih/color/.travis.yml b/vendor/github.com/fatih/color/.travis.yml new file mode 100644 index 000000000..95f8a1ff5 --- /dev/null +++ b/vendor/github.com/fatih/color/.travis.yml @@ -0,0 +1,5 @@ +language: go +go: + - 1.8.x + - tip + diff --git a/vendor/github.com/fatih/color/Gopkg.lock b/vendor/github.com/fatih/color/Gopkg.lock new file mode 100644 index 000000000..7d879e9ca --- /dev/null +++ b/vendor/github.com/fatih/color/Gopkg.lock @@ -0,0 +1,27 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/mattn/go-colorable" + packages = ["."] + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + +[[projects]] + name = "github.com/mattn/go-isatty" + packages = ["."] + revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" + version = "v0.0.3" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = ["unix"] + revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "e8a50671c3cb93ea935bf210b1cd20702876b9d9226129be581ef646d1565cdc" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/fatih/color/Gopkg.toml b/vendor/github.com/fatih/color/Gopkg.toml new file mode 100644 index 000000000..ff1617f71 --- /dev/null +++ b/vendor/github.com/fatih/color/Gopkg.toml @@ -0,0 +1,30 @@ + +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + + +[[constraint]] + name = "github.com/mattn/go-colorable" + version = "0.0.9" + +[[constraint]] + name = "github.com/mattn/go-isatty" + version = "0.0.3" diff --git a/vendor/github.com/fatih/color/LICENSE.md b/vendor/github.com/fatih/color/LICENSE.md new file mode 100644 index 000000000..25fdaf639 --- /dev/null +++ b/vendor/github.com/fatih/color/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Fatih Arslan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md new file mode 100644 index 000000000..3fc954460 --- /dev/null +++ b/vendor/github.com/fatih/color/README.md @@ -0,0 +1,179 @@ +# Color [![GoDoc](https://godoc.org/github.com/fatih/color?status.svg)](https://godoc.org/github.com/fatih/color) [![Build Status](https://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color) + + + +Color lets you use colorized outputs in terms of [ANSI Escape +Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It +has support for Windows too! The API can be used in several ways, pick one that +suits you. + + +![Color](https://i.imgur.com/c1JI0lA.png) + + +## Install + +```bash +go get github.com/fatih/color +``` + +Note that the `vendor` folder is here for stability. Remove the folder if you +already have the dependencies in your GOPATH. + +## Examples + +### Standard colors + +```go +// Print with default helper functions +color.Cyan("Prints text in cyan.") + +// A newline will be appended automatically +color.Blue("Prints %s in blue.", "text") + +// These are using the default foreground colors +color.Red("We have red") +color.Magenta("And many others ..") + +``` + +### Mix and reuse colors + +```go +// Create a new color object +c := color.New(color.FgCyan).Add(color.Underline) +c.Println("Prints cyan text with an underline.") + +// Or just add them to New() +d := color.New(color.FgCyan, color.Bold) +d.Printf("This prints bold cyan %s\n", "too!.") + +// Mix up foreground and background colors, create new mixes! +red := color.New(color.FgRed) + +boldRed := red.Add(color.Bold) +boldRed.Println("This will print text in bold red.") + +whiteBackground := red.Add(color.BgWhite) +whiteBackground.Println("Red text with white background.") +``` + +### Use your own output (io.Writer) + +```go +// Use your own io.Writer output +color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + +blue := color.New(color.FgBlue) +blue.Fprint(writer, "This will print text in blue.") +``` + +### Custom print functions (PrintFunc) + +```go +// Create a custom print function for convenience +red := color.New(color.FgRed).PrintfFunc() +red("Warning") +red("Error: %s", err) + +// Mix up multiple attributes +notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() +notice("Don't forget this...") +``` + +### Custom fprint functions (FprintFunc) + +```go +blue := color.New(FgBlue).FprintfFunc() +blue(myWriter, "important notice: %s", stars) + +// Mix up with multiple attributes +success := color.New(color.Bold, color.FgGreen).FprintlnFunc() +success(myWriter, "Don't forget this...") +``` + +### Insert into noncolor strings (SprintFunc) + +```go +// Create SprintXxx functions to mix strings with other non-colorized strings: +yellow := color.New(color.FgYellow).SprintFunc() +red := color.New(color.FgRed).SprintFunc() +fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error")) + +info := color.New(color.FgWhite, color.BgGreen).SprintFunc() +fmt.Printf("This %s rocks!\n", info("package")) + +// Use helper functions +fmt.Println("This", color.RedString("warning"), "should be not neglected.") +fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.") + +// Windows supported too! Just don't forget to change the output to color.Output +fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) +``` + +### Plug into existing code + +```go +// Use handy standard colors +color.Set(color.FgYellow) + +fmt.Println("Existing text will now be in yellow") +fmt.Printf("This one %s\n", "too") + +color.Unset() // Don't forget to unset + +// You can mix up parameters +color.Set(color.FgMagenta, color.Bold) +defer color.Unset() // Use it in your function + +fmt.Println("All text will now be bold magenta.") +``` + +### Disable/Enable color + +There might be a case where you want to explicitly disable/enable color output. the +`go-isatty` package will automatically disable color output for non-tty output streams +(for example if the output were piped directly to `less`) + +`Color` has support to disable/enable colors both globally and for single color +definitions. For example suppose you have a CLI app and a `--no-color` bool flag. You +can easily disable the color output with: + +```go + +var flagNoColor = flag.Bool("no-color", false, "Disable color output") + +if *flagNoColor { + color.NoColor = true // disables colorized output +} +``` + +It also has support for single color definitions (local). You can +disable/enable color output on the fly: + +```go +c := color.New(color.FgCyan) +c.Println("Prints cyan text") + +c.DisableColor() +c.Println("This is printed without any color") + +c.EnableColor() +c.Println("This prints again cyan...") +``` + +## Todo + +* Save/Return previous values +* Evaluate fmt.Formatter interface + + +## Credits + + * [Fatih Arslan](https://github.com/fatih) + * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) + +## License + +The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details + diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go new file mode 100644 index 000000000..b1f591d45 --- /dev/null +++ b/vendor/github.com/fatih/color/color.go @@ -0,0 +1,600 @@ +package color + +import ( + "fmt" + "io" + "os" + "strconv" + "strings" + "sync" + + "github.com/mattn/go-colorable" + "github.com/mattn/go-isatty" +) + +var ( + // NoColor defines if the output is colorized or not. It's dynamically set to + // false or true based on the stdout's file descriptor referring to a terminal + // or not. This is a global option and affects all colors. For more control + // over each color block use the methods DisableColor() individually. + NoColor = os.Getenv("TERM") == "dumb" || + (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) + + // Output defines the standard output of the print functions. By default + // os.Stdout is used. + Output = colorable.NewColorableStdout() + + // colorsCache is used to reduce the count of created Color objects and + // allows to reuse already created objects with required Attribute. + colorsCache = make(map[Attribute]*Color) + colorsCacheMu sync.Mutex // protects colorsCache +) + +// Color defines a custom color object which is defined by SGR parameters. +type Color struct { + params []Attribute + noColor *bool +} + +// Attribute defines a single SGR Code +type Attribute int + +const escape = "\x1b" + +// Base attributes +const ( + Reset Attribute = iota + Bold + Faint + Italic + Underline + BlinkSlow + BlinkRapid + ReverseVideo + Concealed + CrossedOut +) + +// Foreground text colors +const ( + FgBlack Attribute = iota + 30 + FgRed + FgGreen + FgYellow + FgBlue + FgMagenta + FgCyan + FgWhite +) + +// Foreground Hi-Intensity text colors +const ( + FgHiBlack Attribute = iota + 90 + FgHiRed + FgHiGreen + FgHiYellow + FgHiBlue + FgHiMagenta + FgHiCyan + FgHiWhite +) + +// Background text colors +const ( + BgBlack Attribute = iota + 40 + BgRed + BgGreen + BgYellow + BgBlue + BgMagenta + BgCyan + BgWhite +) + +// Background Hi-Intensity text colors +const ( + BgHiBlack Attribute = iota + 100 + BgHiRed + BgHiGreen + BgHiYellow + BgHiBlue + BgHiMagenta + BgHiCyan + BgHiWhite +) + +// New returns a newly created color object. +func New(value ...Attribute) *Color { + c := &Color{params: make([]Attribute, 0)} + c.Add(value...) + return c +} + +// Set sets the given parameters immediately. It will change the color of +// output with the given SGR parameters until color.Unset() is called. +func Set(p ...Attribute) *Color { + c := New(p...) + c.Set() + return c +} + +// Unset resets all escape attributes and clears the output. Usually should +// be called after Set(). +func Unset() { + if NoColor { + return + } + + fmt.Fprintf(Output, "%s[%dm", escape, Reset) +} + +// Set sets the SGR sequence. +func (c *Color) Set() *Color { + if c.isNoColorSet() { + return c + } + + fmt.Fprintf(Output, c.format()) + return c +} + +func (c *Color) unset() { + if c.isNoColorSet() { + return + } + + Unset() +} + +func (c *Color) setWriter(w io.Writer) *Color { + if c.isNoColorSet() { + return c + } + + fmt.Fprintf(w, c.format()) + return c +} + +func (c *Color) unsetWriter(w io.Writer) { + if c.isNoColorSet() { + return + } + + if NoColor { + return + } + + fmt.Fprintf(w, "%s[%dm", escape, Reset) +} + +// Add is used to chain SGR parameters. Use as many as parameters to combine +// and create custom color objects. Example: Add(color.FgRed, color.Underline). +func (c *Color) Add(value ...Attribute) *Color { + c.params = append(c.params, value...) + return c +} + +func (c *Color) prepend(value Attribute) { + c.params = append(c.params, 0) + copy(c.params[1:], c.params[0:]) + c.params[0] = value +} + +// Fprint formats using the default formats for its operands and writes to w. +// Spaces are added between operands when neither is a string. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprint(w, a...) +} + +// Print formats using the default formats for its operands and writes to +// standard output. Spaces are added between operands when neither is a +// string. It returns the number of bytes written and any write error +// encountered. This is the standard fmt.Print() method wrapped with the given +// color. +func (c *Color) Print(a ...interface{}) (n int, err error) { + c.Set() + defer c.unset() + + return fmt.Fprint(Output, a...) +} + +// Fprintf formats according to a format specifier and writes to w. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintf(w, format, a...) +} + +// Printf formats according to a format specifier and writes to standard output. +// It returns the number of bytes written and any write error encountered. +// This is the standard fmt.Printf() method wrapped with the given color. +func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { + c.Set() + defer c.unset() + + return fmt.Fprintf(Output, format, a...) +} + +// Fprintln formats using the default formats for its operands and writes to w. +// Spaces are always added between operands and a newline is appended. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintln(w, a...) +} + +// Println formats using the default formats for its operands and writes to +// standard output. Spaces are always added between operands and a newline is +// appended. It returns the number of bytes written and any write error +// encountered. This is the standard fmt.Print() method wrapped with the given +// color. +func (c *Color) Println(a ...interface{}) (n int, err error) { + c.Set() + defer c.unset() + + return fmt.Fprintln(Output, a...) +} + +// Sprint is just like Print, but returns a string instead of printing it. +func (c *Color) Sprint(a ...interface{}) string { + return c.wrap(fmt.Sprint(a...)) +} + +// Sprintln is just like Println, but returns a string instead of printing it. +func (c *Color) Sprintln(a ...interface{}) string { + return c.wrap(fmt.Sprintln(a...)) +} + +// Sprintf is just like Printf, but returns a string instead of printing it. +func (c *Color) Sprintf(format string, a ...interface{}) string { + return c.wrap(fmt.Sprintf(format, a...)) +} + +// FprintFunc returns a new function that prints the passed arguments as +// colorized with color.Fprint(). +func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprint(w, a...) + } +} + +// PrintFunc returns a new function that prints the passed arguments as +// colorized with color.Print(). +func (c *Color) PrintFunc() func(a ...interface{}) { + return func(a ...interface{}) { + c.Print(a...) + } +} + +// FprintfFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintf(). +func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) { + return func(w io.Writer, format string, a ...interface{}) { + c.Fprintf(w, format, a...) + } +} + +// PrintfFunc returns a new function that prints the passed arguments as +// colorized with color.Printf(). +func (c *Color) PrintfFunc() func(format string, a ...interface{}) { + return func(format string, a ...interface{}) { + c.Printf(format, a...) + } +} + +// FprintlnFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintln(). +func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprintln(w, a...) + } +} + +// PrintlnFunc returns a new function that prints the passed arguments as +// colorized with color.Println(). +func (c *Color) PrintlnFunc() func(a ...interface{}) { + return func(a ...interface{}) { + c.Println(a...) + } +} + +// SprintFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprint(). Useful to put into or mix into other +// string. Windows users should use this in conjunction with color.Output, example: +// +// put := New(FgYellow).SprintFunc() +// fmt.Fprintf(color.Output, "This is a %s", put("warning")) +func (c *Color) SprintFunc() func(a ...interface{}) string { + return func(a ...interface{}) string { + return c.wrap(fmt.Sprint(a...)) + } +} + +// SprintfFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprintf(). Useful to put into or mix into other +// string. Windows users should use this in conjunction with color.Output. +func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { + return func(format string, a ...interface{}) string { + return c.wrap(fmt.Sprintf(format, a...)) + } +} + +// SprintlnFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprintln(). Useful to put into or mix into other +// string. Windows users should use this in conjunction with color.Output. +func (c *Color) SprintlnFunc() func(a ...interface{}) string { + return func(a ...interface{}) string { + return c.wrap(fmt.Sprintln(a...)) + } +} + +// sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m" +// an example output might be: "1;36" -> bold cyan +func (c *Color) sequence() string { + format := make([]string, len(c.params)) + for i, v := range c.params { + format[i] = strconv.Itoa(int(v)) + } + + return strings.Join(format, ";") +} + +// wrap wraps the s string with the colors attributes. The string is ready to +// be printed. +func (c *Color) wrap(s string) string { + if c.isNoColorSet() { + return s + } + + return c.format() + s + c.unformat() +} + +func (c *Color) format() string { + return fmt.Sprintf("%s[%sm", escape, c.sequence()) +} + +func (c *Color) unformat() string { + return fmt.Sprintf("%s[%dm", escape, Reset) +} + +// DisableColor disables the color output. Useful to not change any existing +// code and still being able to output. Can be used for flags like +// "--no-color". To enable back use EnableColor() method. +func (c *Color) DisableColor() { + c.noColor = boolPtr(true) +} + +// EnableColor enables the color output. Use it in conjunction with +// DisableColor(). Otherwise this method has no side effects. +func (c *Color) EnableColor() { + c.noColor = boolPtr(false) +} + +func (c *Color) isNoColorSet() bool { + // check first if we have user setted action + if c.noColor != nil { + return *c.noColor + } + + // if not return the global option, which is disabled by default + return NoColor +} + +// Equals returns a boolean value indicating whether two colors are equal. +func (c *Color) Equals(c2 *Color) bool { + if len(c.params) != len(c2.params) { + return false + } + + for _, attr := range c.params { + if !c2.attrExists(attr) { + return false + } + } + + return true +} + +func (c *Color) attrExists(a Attribute) bool { + for _, attr := range c.params { + if attr == a { + return true + } + } + + return false +} + +func boolPtr(v bool) *bool { + return &v +} + +func getCachedColor(p Attribute) *Color { + colorsCacheMu.Lock() + defer colorsCacheMu.Unlock() + + c, ok := colorsCache[p] + if !ok { + c = New(p) + colorsCache[p] = c + } + + return c +} + +func colorPrint(format string, p Attribute, a ...interface{}) { + c := getCachedColor(p) + + if !strings.HasSuffix(format, "\n") { + format += "\n" + } + + if len(a) == 0 { + c.Print(format) + } else { + c.Printf(format, a...) + } +} + +func colorString(format string, p Attribute, a ...interface{}) string { + c := getCachedColor(p) + + if len(a) == 0 { + return c.SprintFunc()(format) + } + + return c.SprintfFunc()(format, a...) +} + +// Black is a convenient helper function to print with black foreground. A +// newline is appended to format by default. +func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) } + +// Red is a convenient helper function to print with red foreground. A +// newline is appended to format by default. +func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) } + +// Green is a convenient helper function to print with green foreground. A +// newline is appended to format by default. +func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) } + +// Yellow is a convenient helper function to print with yellow foreground. +// A newline is appended to format by default. +func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) } + +// Blue is a convenient helper function to print with blue foreground. A +// newline is appended to format by default. +func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) } + +// Magenta is a convenient helper function to print with magenta foreground. +// A newline is appended to format by default. +func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) } + +// Cyan is a convenient helper function to print with cyan foreground. A +// newline is appended to format by default. +func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) } + +// White is a convenient helper function to print with white foreground. A +// newline is appended to format by default. +func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) } + +// BlackString is a convenient helper function to return a string with black +// foreground. +func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) } + +// RedString is a convenient helper function to return a string with red +// foreground. +func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) } + +// GreenString is a convenient helper function to return a string with green +// foreground. +func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) } + +// YellowString is a convenient helper function to return a string with yellow +// foreground. +func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) } + +// BlueString is a convenient helper function to return a string with blue +// foreground. +func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) } + +// MagentaString is a convenient helper function to return a string with magenta +// foreground. +func MagentaString(format string, a ...interface{}) string { + return colorString(format, FgMagenta, a...) +} + +// CyanString is a convenient helper function to return a string with cyan +// foreground. +func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) } + +// WhiteString is a convenient helper function to return a string with white +// foreground. +func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) } + +// HiBlack is a convenient helper function to print with hi-intensity black foreground. A +// newline is appended to format by default. +func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) } + +// HiRed is a convenient helper function to print with hi-intensity red foreground. A +// newline is appended to format by default. +func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) } + +// HiGreen is a convenient helper function to print with hi-intensity green foreground. A +// newline is appended to format by default. +func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) } + +// HiYellow is a convenient helper function to print with hi-intensity yellow foreground. +// A newline is appended to format by default. +func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) } + +// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A +// newline is appended to format by default. +func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) } + +// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground. +// A newline is appended to format by default. +func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) } + +// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A +// newline is appended to format by default. +func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) } + +// HiWhite is a convenient helper function to print with hi-intensity white foreground. A +// newline is appended to format by default. +func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) } + +// HiBlackString is a convenient helper function to return a string with hi-intensity black +// foreground. +func HiBlackString(format string, a ...interface{}) string { + return colorString(format, FgHiBlack, a...) +} + +// HiRedString is a convenient helper function to return a string with hi-intensity red +// foreground. +func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) } + +// HiGreenString is a convenient helper function to return a string with hi-intensity green +// foreground. +func HiGreenString(format string, a ...interface{}) string { + return colorString(format, FgHiGreen, a...) +} + +// HiYellowString is a convenient helper function to return a string with hi-intensity yellow +// foreground. +func HiYellowString(format string, a ...interface{}) string { + return colorString(format, FgHiYellow, a...) +} + +// HiBlueString is a convenient helper function to return a string with hi-intensity blue +// foreground. +func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) } + +// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta +// foreground. +func HiMagentaString(format string, a ...interface{}) string { + return colorString(format, FgHiMagenta, a...) +} + +// HiCyanString is a convenient helper function to return a string with hi-intensity cyan +// foreground. +func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) } + +// HiWhiteString is a convenient helper function to return a string with hi-intensity white +// foreground. +func HiWhiteString(format string, a ...interface{}) string { + return colorString(format, FgHiWhite, a...) +} diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go new file mode 100644 index 000000000..cf1e96500 --- /dev/null +++ b/vendor/github.com/fatih/color/doc.go @@ -0,0 +1,133 @@ +/* +Package color is an ANSI color package to output colorized or SGR defined +output to the standard output. The API can be used in several way, pick one +that suits you. + +Use simple and default helper functions with predefined foreground colors: + + color.Cyan("Prints text in cyan.") + + // a newline will be appended automatically + color.Blue("Prints %s in blue.", "text") + + // More default foreground colors.. + color.Red("We have red") + color.Yellow("Yellow color too!") + color.Magenta("And many others ..") + + // Hi-intensity colors + color.HiGreen("Bright green color.") + color.HiBlack("Bright black means gray..") + color.HiWhite("Shiny white color!") + +However there are times where custom color mixes are required. Below are some +examples to create custom color objects and use the print functions of each +separate color object. + + // Create a new color object + c := color.New(color.FgCyan).Add(color.Underline) + c.Println("Prints cyan text with an underline.") + + // Or just add them to New() + d := color.New(color.FgCyan, color.Bold) + d.Printf("This prints bold cyan %s\n", "too!.") + + + // Mix up foreground and background colors, create new mixes! + red := color.New(color.FgRed) + + boldRed := red.Add(color.Bold) + boldRed.Println("This will print text in bold red.") + + whiteBackground := red.Add(color.BgWhite) + whiteBackground.Println("Red text with White background.") + + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") + +You can create PrintXxx functions to simplify even more: + + // Create a custom print function for convenient + red := color.New(color.FgRed).PrintfFunc() + red("warning") + red("error: %s", err) + + // Mix up multiple attributes + notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() + notice("don't forget this...") + +You can also FprintXxx functions to pass your own io.Writer: + + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") + + +Or create SprintXxx functions to mix strings with other non-colorized strings: + + yellow := New(FgYellow).SprintFunc() + red := New(FgRed).SprintFunc() + + fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) + + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Printf("this %s rocks!\n", info("package")) + +Windows support is enabled by default. All Print functions work as intended. +However only for color.SprintXXX functions, user should use fmt.FprintXXX and +set the output to color.Output: + + fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) + + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) + +Using with existing code is possible. Just use the Set() method to set the +standard output to the given parameters. That way a rewrite of an existing +code is not required. + + // Use handy standard colors. + color.Set(color.FgYellow) + + fmt.Println("Existing text will be now in Yellow") + fmt.Printf("This one %s\n", "too") + + color.Unset() // don't forget to unset + + // You can mix up parameters + color.Set(color.FgMagenta, color.Bold) + defer color.Unset() // use it in your function + + fmt.Println("All text will be now bold magenta.") + +There might be a case where you want to disable color output (for example to +pipe the standard output of your app to somewhere else). `Color` has support to +disable colors both globally and for single color definition. For example +suppose you have a CLI app and a `--no-color` bool flag. You can easily disable +the color output with: + + var flagNoColor = flag.Bool("no-color", false, "Disable color output") + + if *flagNoColor { + color.NoColor = true // disables colorized output + } + +It also has support for single color definitions (local). You can +disable/enable color output on the fly: + + c := color.New(color.FgCyan) + c.Println("Prints cyan text") + + c.DisableColor() + c.Println("This is printed without any color") + + c.EnableColor() + c.Println("This prints again cyan...") +*/ +package color diff --git a/vendor/github.com/fsnotify/fsnotify/.editorconfig b/vendor/github.com/fsnotify/fsnotify/.editorconfig new file mode 100644 index 000000000..ba49e3c23 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*] +indent_style = tab +indent_size = 4 diff --git a/vendor/github.com/fsnotify/fsnotify/.gitignore b/vendor/github.com/fsnotify/fsnotify/.gitignore new file mode 100644 index 000000000..4cd0cbaf4 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.gitignore @@ -0,0 +1,6 @@ +# Setup a Global .gitignore for OS and editor generated files: +# https://help.github.com/articles/ignoring-files +# git config --global core.excludesfile ~/.gitignore_global + +.vagrant +*.sublime-project diff --git a/vendor/github.com/fsnotify/fsnotify/.travis.yml b/vendor/github.com/fsnotify/fsnotify/.travis.yml new file mode 100644 index 000000000..22e5fa43f --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.travis.yml @@ -0,0 +1,30 @@ +sudo: false +language: go + +go: + - 1.8 + - 1.7.x + - tip + +matrix: + allow_failures: + - go: tip + fast_finish: true + +before_script: + - go get -u github.com/golang/lint/golint + +script: + - go test -v --race ./... + +after_script: + - test -z "$(gofmt -s -l -w . | tee /dev/stderr)" + - test -z "$(golint ./... | tee /dev/stderr)" + - go vet ./... + +os: + - linux + - osx + +notifications: + email: false diff --git a/vendor/github.com/fsnotify/fsnotify/AUTHORS b/vendor/github.com/fsnotify/fsnotify/AUTHORS new file mode 100644 index 000000000..0a5bf8f61 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/AUTHORS @@ -0,0 +1,46 @@ +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# You can update this list using the following command: +# +# $ git shortlog -se | awk '{print $2 " " $3 " " $4}' + +# Please keep the list sorted. + +Adrien Bustany +Amit Krishnan +Bjørn Erik Pedersen +Bruno Bigras +Caleb Spare +Case Nelson +Chris Howey +Christoffer Buchholz +Daniel Wagner-Hall +Dave Cheney +Evan Phoenix +Francisco Souza +Hari haran +John C Barstow +Kelvin Fo +Ken-ichirou MATSUZAWA +Matt Layher +Nathan Youngman +Patrick +Paul Hammond +Pawel Knap +Pieter Droogendijk +Pursuit92 +Riku Voipio +Rob Figueiredo +Slawek Ligus +Soge Zhang +Tiffany Jernigan +Tilak Sharma +Travis Cline +Tudor Golubenco +Yukang +bronze1man +debrando +henrikedwards +铁哥 diff --git a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md new file mode 100644 index 000000000..8c732c1d8 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md @@ -0,0 +1,307 @@ +# Changelog + +## v1.4.2 / 2016-10-10 + +* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack) + +## v1.4.1 / 2016-10-04 + +* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack) + +## v1.4.0 / 2016-10-01 + +* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie) + +## v1.3.1 / 2016-06-28 + +* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc) + +## v1.3.0 / 2016-04-19 + +* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135) + +## v1.2.10 / 2016-03-02 + +* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj) + +## v1.2.9 / 2016-01-13 + +kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep) + +## v1.2.8 / 2015-12-17 + +* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test) +* inotify: fix race in test +* enable race detection for continuous integration (Linux, Mac, Windows) + +## v1.2.5 / 2015-10-17 + +* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki) +* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken) +* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie) +* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion) + +## v1.2.1 / 2015-10-14 + +* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx) + +## v1.2.0 / 2015-02-08 + +* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD) +* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD) +* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59) + +## v1.1.1 / 2015-02-05 + +* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD) + +## v1.1.0 / 2014-12-12 + +* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43) + * add low-level functions + * only need to store flags on directories + * less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13) + * done can be an unbuffered channel + * remove calls to os.NewSyscallError +* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher) +* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48) +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) + +## v1.0.4 / 2014-09-07 + +* kqueue: add dragonfly to the build tags. +* Rename source code files, rearrange code so exported APIs are at the top. +* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang) + +## v1.0.3 / 2014-08-19 + +* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36) + +## v1.0.2 / 2014-08-17 + +* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) +* [Fix] Make ./path and path equivalent. (thanks @zhsso) + +## v1.0.0 / 2014-08-15 + +* [API] Remove AddWatch on Windows, use Add. +* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30) +* Minor updates based on feedback from golint. + +## dev / 2014-07-09 + +* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify). +* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno) + +## dev / 2014-07-04 + +* kqueue: fix incorrect mutex used in Close() +* Update example to demonstrate usage of Op. + +## dev / 2014-06-28 + +* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4) +* Fix for String() method on Event (thanks Alex Brainman) +* Don't build on Plan 9 or Solaris (thanks @4ad) + +## dev / 2014-06-21 + +* Events channel of type Event rather than *Event. +* [internal] use syscall constants directly for inotify and kqueue. +* [internal] kqueue: rename events to kevents and fileEvent to event. + +## dev / 2014-06-19 + +* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally). +* [internal] remove cookie from Event struct (unused). +* [internal] Event struct has the same definition across every OS. +* [internal] remove internal watch and removeWatch methods. + +## dev / 2014-06-12 + +* [API] Renamed Watch() to Add() and RemoveWatch() to Remove(). +* [API] Pluralized channel names: Events and Errors. +* [API] Renamed FileEvent struct to Event. +* [API] Op constants replace methods like IsCreate(). + +## dev / 2014-06-12 + +* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) + +## dev / 2014-05-23 + +* [API] Remove current implementation of WatchFlags. + * current implementation doesn't take advantage of OS for efficiency + * provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes + * no tests for the current implementation + * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195) + +## v0.9.3 / 2014-12-31 + +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) + +## v0.9.2 / 2014-08-17 + +* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) + +## v0.9.1 / 2014-06-12 + +* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) + +## v0.9.0 / 2014-01-17 + +* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany) +* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare) +* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library. + +## v0.8.12 / 2013-11-13 + +* [API] Remove FD_SET and friends from Linux adapter + +## v0.8.11 / 2013-11-02 + +* [Doc] Add Changelog [#72][] (thanks @nathany) +* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond) + +## v0.8.10 / 2013-10-19 + +* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott) +* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer) +* [Doc] specify OS-specific limits in README (thanks @debrando) + +## v0.8.9 / 2013-09-08 + +* [Doc] Contributing (thanks @nathany) +* [Doc] update package path in example code [#63][] (thanks @paulhammond) +* [Doc] GoCI badge in README (Linux only) [#60][] +* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany) + +## v0.8.8 / 2013-06-17 + +* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie) + +## v0.8.7 / 2013-06-03 + +* [API] Make syscall flags internal +* [Fix] inotify: ignore event changes +* [Fix] race in symlink test [#45][] (reported by @srid) +* [Fix] tests on Windows +* lower case error messages + +## v0.8.6 / 2013-05-23 + +* kqueue: Use EVT_ONLY flag on Darwin +* [Doc] Update README with full example + +## v0.8.5 / 2013-05-09 + +* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg) + +## v0.8.4 / 2013-04-07 + +* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz) + +## v0.8.3 / 2013-03-13 + +* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin) +* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin) + +## v0.8.2 / 2013-02-07 + +* [Doc] add Authors +* [Fix] fix data races for map access [#29][] (thanks @fsouza) + +## v0.8.1 / 2013-01-09 + +* [Fix] Windows path separators +* [Doc] BSD License + +## v0.8.0 / 2012-11-09 + +* kqueue: directory watching improvements (thanks @vmirage) +* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto) +* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr) + +## v0.7.4 / 2012-10-09 + +* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji) +* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig) +* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig) +* [Fix] kqueue: modify after recreation of file + +## v0.7.3 / 2012-09-27 + +* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage) +* [Fix] kqueue: no longer get duplicate CREATE events + +## v0.7.2 / 2012-09-01 + +* kqueue: events for created directories + +## v0.7.1 / 2012-07-14 + +* [Fix] for renaming files + +## v0.7.0 / 2012-07-02 + +* [Feature] FSNotify flags +* [Fix] inotify: Added file name back to event path + +## v0.6.0 / 2012-06-06 + +* kqueue: watch files after directory created (thanks @tmc) + +## v0.5.1 / 2012-05-22 + +* [Fix] inotify: remove all watches before Close() + +## v0.5.0 / 2012-05-03 + +* [API] kqueue: return errors during watch instead of sending over channel +* kqueue: match symlink behavior on Linux +* inotify: add `DELETE_SELF` (requested by @taralx) +* [Fix] kqueue: handle EINTR (reported by @robfig) +* [Doc] Godoc example [#1][] (thanks @davecheney) + +## v0.4.0 / 2012-03-30 + +* Go 1 released: build with go tool +* [Feature] Windows support using winfsnotify +* Windows does not have attribute change notifications +* Roll attribute notifications into IsModify + +## v0.3.0 / 2012-02-19 + +* kqueue: add files when watch directory + +## v0.2.0 / 2011-12-30 + +* update to latest Go weekly code + +## v0.1.0 / 2011-10-19 + +* kqueue: add watch on file creation to match inotify +* kqueue: create file event +* inotify: ignore `IN_IGNORED` events +* event String() +* linux: common FileEvent functions +* initial commit + +[#79]: https://github.com/howeyc/fsnotify/pull/79 +[#77]: https://github.com/howeyc/fsnotify/pull/77 +[#72]: https://github.com/howeyc/fsnotify/issues/72 +[#71]: https://github.com/howeyc/fsnotify/issues/71 +[#70]: https://github.com/howeyc/fsnotify/issues/70 +[#63]: https://github.com/howeyc/fsnotify/issues/63 +[#62]: https://github.com/howeyc/fsnotify/issues/62 +[#60]: https://github.com/howeyc/fsnotify/issues/60 +[#59]: https://github.com/howeyc/fsnotify/issues/59 +[#49]: https://github.com/howeyc/fsnotify/issues/49 +[#45]: https://github.com/howeyc/fsnotify/issues/45 +[#40]: https://github.com/howeyc/fsnotify/issues/40 +[#36]: https://github.com/howeyc/fsnotify/issues/36 +[#33]: https://github.com/howeyc/fsnotify/issues/33 +[#29]: https://github.com/howeyc/fsnotify/issues/29 +[#25]: https://github.com/howeyc/fsnotify/issues/25 +[#24]: https://github.com/howeyc/fsnotify/issues/24 +[#21]: https://github.com/howeyc/fsnotify/issues/21 diff --git a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md new file mode 100644 index 000000000..828a60b24 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md @@ -0,0 +1,77 @@ +# Contributing + +## Issues + +* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues). +* Please indicate the platform you are using fsnotify on. +* A code example to reproduce the problem is appreciated. + +## Pull Requests + +### Contributor License Agreement + +fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual). + +Please indicate that you have signed the CLA in your pull request. + +### How fsnotify is Developed + +* Development is done on feature branches. +* Tests are run on BSD, Linux, macOS and Windows. +* Pull requests are reviewed and [applied to master][am] using [hub][]. + * Maintainers may modify or squash commits rather than asking contributors to. +* To issue a new release, the maintainers will: + * Update the CHANGELOG + * Tag a version, which will become available through gopkg.in. + +### How to Fork + +For smooth sailing, always use the original import path. Installing with `go get` makes this easy. + +1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`) +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Ensure everything works and the tests pass (see below) +4. Commit your changes (`git commit -am 'Add some feature'`) + +Contribute upstream: + +1. Fork fsnotify on GitHub +2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`) +3. Push to the branch (`git push fork my-new-feature`) +4. Create a new Pull Request on GitHub + +This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/). + +### Testing + +fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows. + +Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on. + +To aid in cross-platform testing there is a Vagrantfile for Linux and BSD. + +* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/) +* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder. +* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password) +* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`. +* When you're done, you will want to halt or destroy the Vagrant boxes. + +Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory. + +Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads). + +### Maintainers + +Help maintaining fsnotify is welcome. To be a maintainer: + +* Submit a pull request and sign the CLA as above. +* You must be able to run the test suite on Mac, Windows, Linux and BSD. + +To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][]. + +All code changes should be internal pull requests. + +Releases are tagged using [Semantic Versioning](http://semver.org/). + +[hub]: https://github.com/github/hub +[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs diff --git a/vendor/github.com/fsnotify/fsnotify/LICENSE b/vendor/github.com/fsnotify/fsnotify/LICENSE new file mode 100644 index 000000000..f21e54080 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2012 fsnotify Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md new file mode 100644 index 000000000..399320741 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/README.md @@ -0,0 +1,79 @@ +# File system notifications for Go + +[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) + +fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running: + +```console +go get -u golang.org/x/sys/... +``` + +Cross platform: Windows, Linux, BSD and macOS. + +|Adapter |OS |Status | +|----------|----------|----------| +|inotify |Linux 2.6.27 or later, Android\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| +|kqueue |BSD, macOS, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| +|ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)| +|FSEvents |macOS |[Planned](https://github.com/fsnotify/fsnotify/issues/11)| +|FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)| +|fanotify |Linux 2.6.37+ | | +|USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)| +|Polling |*All* |[Maybe](https://github.com/fsnotify/fsnotify/issues/9)| + +\* Android and iOS are untested. + +Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information. + +## API stability + +fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA). + +All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number. + +Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`. + +## Contributing + +Please refer to [CONTRIBUTING][] before opening an issue or pull request. + +## Example + +See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go). + +## FAQ + +**When a file is moved to another directory is it still being watched?** + +No (it shouldn't be, unless you are watching where it was moved to). + +**When I watch a directory, are all subdirectories watched as well?** + +No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]). + +**Do I have to watch the Error and Event channels in a separate goroutine?** + +As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7]) + +**Why am I receiving multiple events for the same file on OS X?** + +Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]). + +**How many files can be watched at once?** + +There are OS-specific limits as to how many watches can be created: +* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error. +* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. + +[#62]: https://github.com/howeyc/fsnotify/issues/62 +[#18]: https://github.com/fsnotify/fsnotify/issues/18 +[#11]: https://github.com/fsnotify/fsnotify/issues/11 +[#7]: https://github.com/howeyc/fsnotify/issues/7 + +[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md + +## Related Projects + +* [notify](https://github.com/rjeczalik/notify) +* [fsevents](https://github.com/fsnotify/fsevents) + diff --git a/vendor/github.com/fsnotify/fsnotify/fen.go b/vendor/github.com/fsnotify/fsnotify/fen.go new file mode 100644 index 000000000..ced39cb88 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/fen.go @@ -0,0 +1,37 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build solaris + +package fsnotify + +import ( + "errors" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct { + Events chan Event + Errors chan error +} + +// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. +func NewWatcher() (*Watcher, error) { + return nil, errors.New("FEN based watcher not yet supported for fsnotify\n") +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + return nil +} + +// Add starts watching the named file or directory (non-recursively). +func (w *Watcher) Add(name string) error { + return nil +} + +// Remove stops watching the the named file or directory (non-recursively). +func (w *Watcher) Remove(name string) error { + return nil +} diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go new file mode 100644 index 000000000..190bf0de5 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/fsnotify.go @@ -0,0 +1,66 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9 + +// Package fsnotify provides a platform-independent interface for file system notifications. +package fsnotify + +import ( + "bytes" + "errors" + "fmt" +) + +// Event represents a single file system notification. +type Event struct { + Name string // Relative path to the file or directory. + Op Op // File operation that triggered the event. +} + +// Op describes a set of file operations. +type Op uint32 + +// These are the generalized file operations that can trigger a notification. +const ( + Create Op = 1 << iota + Write + Remove + Rename + Chmod +) + +func (op Op) String() string { + // Use a buffer for efficient string concatenation + var buffer bytes.Buffer + + if op&Create == Create { + buffer.WriteString("|CREATE") + } + if op&Remove == Remove { + buffer.WriteString("|REMOVE") + } + if op&Write == Write { + buffer.WriteString("|WRITE") + } + if op&Rename == Rename { + buffer.WriteString("|RENAME") + } + if op&Chmod == Chmod { + buffer.WriteString("|CHMOD") + } + if buffer.Len() == 0 { + return "" + } + return buffer.String()[1:] // Strip leading pipe +} + +// String returns a string representation of the event in the form +// "file: REMOVE|WRITE|..." +func (e Event) String() string { + return fmt.Sprintf("%q: %s", e.Name, e.Op.String()) +} + +// Common errors that can be reported by a watcher +var ErrEventOverflow = errors.New("fsnotify queue overflow") diff --git a/vendor/github.com/fsnotify/fsnotify/inotify.go b/vendor/github.com/fsnotify/fsnotify/inotify.go new file mode 100644 index 000000000..d9fd1b88a --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/inotify.go @@ -0,0 +1,337 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux + +package fsnotify + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "unsafe" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct { + Events chan Event + Errors chan error + mu sync.Mutex // Map access + fd int + poller *fdPoller + watches map[string]*watch // Map of inotify watches (key: path) + paths map[int]string // Map of watched paths (key: watch descriptor) + done chan struct{} // Channel for sending a "quit message" to the reader goroutine + doneResp chan struct{} // Channel to respond to Close +} + +// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. +func NewWatcher() (*Watcher, error) { + // Create inotify fd + fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC) + if fd == -1 { + return nil, errno + } + // Create epoll + poller, err := newFdPoller(fd) + if err != nil { + unix.Close(fd) + return nil, err + } + w := &Watcher{ + fd: fd, + poller: poller, + watches: make(map[string]*watch), + paths: make(map[int]string), + Events: make(chan Event), + Errors: make(chan error), + done: make(chan struct{}), + doneResp: make(chan struct{}), + } + + go w.readEvents() + return w, nil +} + +func (w *Watcher) isClosed() bool { + select { + case <-w.done: + return true + default: + return false + } +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + if w.isClosed() { + return nil + } + + // Send 'close' signal to goroutine, and set the Watcher to closed. + close(w.done) + + // Wake up goroutine + w.poller.wake() + + // Wait for goroutine to close + <-w.doneResp + + return nil +} + +// Add starts watching the named file or directory (non-recursively). +func (w *Watcher) Add(name string) error { + name = filepath.Clean(name) + if w.isClosed() { + return errors.New("inotify instance already closed") + } + + const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM | + unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY | + unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF + + var flags uint32 = agnosticEvents + + w.mu.Lock() + defer w.mu.Unlock() + watchEntry := w.watches[name] + if watchEntry != nil { + flags |= watchEntry.flags | unix.IN_MASK_ADD + } + wd, errno := unix.InotifyAddWatch(w.fd, name, flags) + if wd == -1 { + return errno + } + + if watchEntry == nil { + w.watches[name] = &watch{wd: uint32(wd), flags: flags} + w.paths[wd] = name + } else { + watchEntry.wd = uint32(wd) + watchEntry.flags = flags + } + + return nil +} + +// Remove stops watching the named file or directory (non-recursively). +func (w *Watcher) Remove(name string) error { + name = filepath.Clean(name) + + // Fetch the watch. + w.mu.Lock() + defer w.mu.Unlock() + watch, ok := w.watches[name] + + // Remove it from inotify. + if !ok { + return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) + } + + // We successfully removed the watch if InotifyRmWatch doesn't return an + // error, we need to clean up our internal state to ensure it matches + // inotify's kernel state. + delete(w.paths, int(watch.wd)) + delete(w.watches, name) + + // inotify_rm_watch will return EINVAL if the file has been deleted; + // the inotify will already have been removed. + // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously + // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE + // so that EINVAL means that the wd is being rm_watch()ed or its file removed + // by another thread and we have not received IN_IGNORE event. + success, errno := unix.InotifyRmWatch(w.fd, watch.wd) + if success == -1 { + // TODO: Perhaps it's not helpful to return an error here in every case. + // the only two possible errors are: + // EBADF, which happens when w.fd is not a valid file descriptor of any kind. + // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor. + // Watch descriptors are invalidated when they are removed explicitly or implicitly; + // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted. + return errno + } + + return nil +} + +type watch struct { + wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) + flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) +} + +// readEvents reads from the inotify file descriptor, converts the +// received events into Event objects and sends them via the Events channel +func (w *Watcher) readEvents() { + var ( + buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events + n int // Number of bytes read with read() + errno error // Syscall errno + ok bool // For poller.wait + ) + + defer close(w.doneResp) + defer close(w.Errors) + defer close(w.Events) + defer unix.Close(w.fd) + defer w.poller.close() + + for { + // See if we have been closed. + if w.isClosed() { + return + } + + ok, errno = w.poller.wait() + if errno != nil { + select { + case w.Errors <- errno: + case <-w.done: + return + } + continue + } + + if !ok { + continue + } + + n, errno = unix.Read(w.fd, buf[:]) + // If a signal interrupted execution, see if we've been asked to close, and try again. + // http://man7.org/linux/man-pages/man7/signal.7.html : + // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable" + if errno == unix.EINTR { + continue + } + + // unix.Read might have been woken up by Close. If so, we're done. + if w.isClosed() { + return + } + + if n < unix.SizeofInotifyEvent { + var err error + if n == 0 { + // If EOF is received. This should really never happen. + err = io.EOF + } else if n < 0 { + // If an error occurred while reading. + err = errno + } else { + // Read was too short. + err = errors.New("notify: short read in readEvents()") + } + select { + case w.Errors <- err: + case <-w.done: + return + } + continue + } + + var offset uint32 + // We don't know how many events we just read into the buffer + // While the offset points to at least one whole event... + for offset <= uint32(n-unix.SizeofInotifyEvent) { + // Point "raw" to the event in the buffer + raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) + + mask := uint32(raw.Mask) + nameLen := uint32(raw.Len) + + if mask&unix.IN_Q_OVERFLOW != 0 { + select { + case w.Errors <- ErrEventOverflow: + case <-w.done: + return + } + } + + // If the event happened to the watched directory or the watched file, the kernel + // doesn't append the filename to the event, but we would like to always fill the + // the "Name" field with a valid filename. We retrieve the path of the watch from + // the "paths" map. + w.mu.Lock() + name, ok := w.paths[int(raw.Wd)] + // IN_DELETE_SELF occurs when the file/directory being watched is removed. + // This is a sign to clean up the maps, otherwise we are no longer in sync + // with the inotify kernel state which has already deleted the watch + // automatically. + if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { + delete(w.paths, int(raw.Wd)) + delete(w.watches, name) + } + w.mu.Unlock() + + if nameLen > 0 { + // Point "bytes" at the first byte of the filename + bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent])) + // The filename is padded with NULL bytes. TrimRight() gets rid of those. + name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") + } + + event := newEvent(name, mask) + + // Send the events that are not ignored on the events channel + if !event.ignoreLinux(mask) { + select { + case w.Events <- event: + case <-w.done: + return + } + } + + // Move to the next event in the buffer + offset += unix.SizeofInotifyEvent + nameLen + } + } +} + +// Certain types of events can be "ignored" and not sent over the Events +// channel. Such as events marked ignore by the kernel, or MODIFY events +// against files that do not exist. +func (e *Event) ignoreLinux(mask uint32) bool { + // Ignore anything the inotify API says to ignore + if mask&unix.IN_IGNORED == unix.IN_IGNORED { + return true + } + + // If the event is not a DELETE or RENAME, the file must exist. + // Otherwise the event is ignored. + // *Note*: this was put in place because it was seen that a MODIFY + // event was sent after the DELETE. This ignores that MODIFY and + // assumes a DELETE will come or has come if the file doesn't exist. + if !(e.Op&Remove == Remove || e.Op&Rename == Rename) { + _, statErr := os.Lstat(e.Name) + return os.IsNotExist(statErr) + } + return false +} + +// newEvent returns an platform-independent Event based on an inotify mask. +func newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { + e.Op |= Create + } + if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE { + e.Op |= Remove + } + if mask&unix.IN_MODIFY == unix.IN_MODIFY { + e.Op |= Write + } + if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { + e.Op |= Rename + } + if mask&unix.IN_ATTRIB == unix.IN_ATTRIB { + e.Op |= Chmod + } + return e +} diff --git a/vendor/github.com/fsnotify/fsnotify/inotify_poller.go b/vendor/github.com/fsnotify/fsnotify/inotify_poller.go new file mode 100644 index 000000000..cc7db4b22 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/inotify_poller.go @@ -0,0 +1,187 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux + +package fsnotify + +import ( + "errors" + + "golang.org/x/sys/unix" +) + +type fdPoller struct { + fd int // File descriptor (as returned by the inotify_init() syscall) + epfd int // Epoll file descriptor + pipe [2]int // Pipe for waking up +} + +func emptyPoller(fd int) *fdPoller { + poller := new(fdPoller) + poller.fd = fd + poller.epfd = -1 + poller.pipe[0] = -1 + poller.pipe[1] = -1 + return poller +} + +// Create a new inotify poller. +// This creates an inotify handler, and an epoll handler. +func newFdPoller(fd int) (*fdPoller, error) { + var errno error + poller := emptyPoller(fd) + defer func() { + if errno != nil { + poller.close() + } + }() + poller.fd = fd + + // Create epoll fd + poller.epfd, errno = unix.EpollCreate1(0) + if poller.epfd == -1 { + return nil, errno + } + // Create pipe; pipe[0] is the read end, pipe[1] the write end. + errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK) + if errno != nil { + return nil, errno + } + + // Register inotify fd with epoll + event := unix.EpollEvent{ + Fd: int32(poller.fd), + Events: unix.EPOLLIN, + } + errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event) + if errno != nil { + return nil, errno + } + + // Register pipe fd with epoll + event = unix.EpollEvent{ + Fd: int32(poller.pipe[0]), + Events: unix.EPOLLIN, + } + errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event) + if errno != nil { + return nil, errno + } + + return poller, nil +} + +// Wait using epoll. +// Returns true if something is ready to be read, +// false if there is not. +func (poller *fdPoller) wait() (bool, error) { + // 3 possible events per fd, and 2 fds, makes a maximum of 6 events. + // I don't know whether epoll_wait returns the number of events returned, + // or the total number of events ready. + // I decided to catch both by making the buffer one larger than the maximum. + events := make([]unix.EpollEvent, 7) + for { + n, errno := unix.EpollWait(poller.epfd, events, -1) + if n == -1 { + if errno == unix.EINTR { + continue + } + return false, errno + } + if n == 0 { + // If there are no events, try again. + continue + } + if n > 6 { + // This should never happen. More events were returned than should be possible. + return false, errors.New("epoll_wait returned more events than I know what to do with") + } + ready := events[:n] + epollhup := false + epollerr := false + epollin := false + for _, event := range ready { + if event.Fd == int32(poller.fd) { + if event.Events&unix.EPOLLHUP != 0 { + // This should not happen, but if it does, treat it as a wakeup. + epollhup = true + } + if event.Events&unix.EPOLLERR != 0 { + // If an error is waiting on the file descriptor, we should pretend + // something is ready to read, and let unix.Read pick up the error. + epollerr = true + } + if event.Events&unix.EPOLLIN != 0 { + // There is data to read. + epollin = true + } + } + if event.Fd == int32(poller.pipe[0]) { + if event.Events&unix.EPOLLHUP != 0 { + // Write pipe descriptor was closed, by us. This means we're closing down the + // watcher, and we should wake up. + } + if event.Events&unix.EPOLLERR != 0 { + // If an error is waiting on the pipe file descriptor. + // This is an absolute mystery, and should never ever happen. + return false, errors.New("Error on the pipe descriptor.") + } + if event.Events&unix.EPOLLIN != 0 { + // This is a regular wakeup, so we have to clear the buffer. + err := poller.clearWake() + if err != nil { + return false, err + } + } + } + } + + if epollhup || epollerr || epollin { + return true, nil + } + return false, nil + } +} + +// Close the write end of the poller. +func (poller *fdPoller) wake() error { + buf := make([]byte, 1) + n, errno := unix.Write(poller.pipe[1], buf) + if n == -1 { + if errno == unix.EAGAIN { + // Buffer is full, poller will wake. + return nil + } + return errno + } + return nil +} + +func (poller *fdPoller) clearWake() error { + // You have to be woken up a LOT in order to get to 100! + buf := make([]byte, 100) + n, errno := unix.Read(poller.pipe[0], buf) + if n == -1 { + if errno == unix.EAGAIN { + // Buffer is empty, someone else cleared our wake. + return nil + } + return errno + } + return nil +} + +// Close all poller file descriptors, but not the one passed to it. +func (poller *fdPoller) close() { + if poller.pipe[1] != -1 { + unix.Close(poller.pipe[1]) + } + if poller.pipe[0] != -1 { + unix.Close(poller.pipe[0]) + } + if poller.epfd != -1 { + unix.Close(poller.epfd) + } +} diff --git a/vendor/github.com/fsnotify/fsnotify/kqueue.go b/vendor/github.com/fsnotify/fsnotify/kqueue.go new file mode 100644 index 000000000..c2b4acb18 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/kqueue.go @@ -0,0 +1,503 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build freebsd openbsd netbsd dragonfly darwin + +package fsnotify + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sync" + "time" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct { + Events chan Event + Errors chan error + done chan bool // Channel for sending a "quit message" to the reader goroutine + + kq int // File descriptor (as returned by the kqueue() syscall). + + mu sync.Mutex // Protects access to watcher data + watches map[string]int // Map of watched file descriptors (key: path). + externalWatches map[string]bool // Map of watches added by user of the library. + dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue. + paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events. + fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events). + isClosed bool // Set to true when Close() is first called +} + +type pathInfo struct { + name string + isDir bool +} + +// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. +func NewWatcher() (*Watcher, error) { + kq, err := kqueue() + if err != nil { + return nil, err + } + + w := &Watcher{ + kq: kq, + watches: make(map[string]int), + dirFlags: make(map[string]uint32), + paths: make(map[int]pathInfo), + fileExists: make(map[string]bool), + externalWatches: make(map[string]bool), + Events: make(chan Event), + Errors: make(chan error), + done: make(chan bool), + } + + go w.readEvents() + return w, nil +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return nil + } + w.isClosed = true + w.mu.Unlock() + + // copy paths to remove while locked + w.mu.Lock() + var pathsToRemove = make([]string, 0, len(w.watches)) + for name := range w.watches { + pathsToRemove = append(pathsToRemove, name) + } + w.mu.Unlock() + // unlock before calling Remove, which also locks + + var err error + for _, name := range pathsToRemove { + if e := w.Remove(name); e != nil && err == nil { + err = e + } + } + + // Send "quit" message to the reader goroutine: + w.done <- true + + return nil +} + +// Add starts watching the named file or directory (non-recursively). +func (w *Watcher) Add(name string) error { + w.mu.Lock() + w.externalWatches[name] = true + w.mu.Unlock() + _, err := w.addWatch(name, noteAllEvents) + return err +} + +// Remove stops watching the the named file or directory (non-recursively). +func (w *Watcher) Remove(name string) error { + name = filepath.Clean(name) + w.mu.Lock() + watchfd, ok := w.watches[name] + w.mu.Unlock() + if !ok { + return fmt.Errorf("can't remove non-existent kevent watch for: %s", name) + } + + const registerRemove = unix.EV_DELETE + if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil { + return err + } + + unix.Close(watchfd) + + w.mu.Lock() + isDir := w.paths[watchfd].isDir + delete(w.watches, name) + delete(w.paths, watchfd) + delete(w.dirFlags, name) + w.mu.Unlock() + + // Find all watched paths that are in this directory that are not external. + if isDir { + var pathsToRemove []string + w.mu.Lock() + for _, path := range w.paths { + wdir, _ := filepath.Split(path.name) + if filepath.Clean(wdir) == name { + if !w.externalWatches[path.name] { + pathsToRemove = append(pathsToRemove, path.name) + } + } + } + w.mu.Unlock() + for _, name := range pathsToRemove { + // Since these are internal, not much sense in propagating error + // to the user, as that will just confuse them with an error about + // a path they did not explicitly watch themselves. + w.Remove(name) + } + } + + return nil +} + +// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE) +const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME + +// keventWaitTime to block on each read from kevent +var keventWaitTime = durationToTimespec(100 * time.Millisecond) + +// addWatch adds name to the watched file set. +// The flags are interpreted as described in kevent(2). +// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks. +func (w *Watcher) addWatch(name string, flags uint32) (string, error) { + var isDir bool + // Make ./name and name equivalent + name = filepath.Clean(name) + + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return "", errors.New("kevent instance already closed") + } + watchfd, alreadyWatching := w.watches[name] + // We already have a watch, but we can still override flags. + if alreadyWatching { + isDir = w.paths[watchfd].isDir + } + w.mu.Unlock() + + if !alreadyWatching { + fi, err := os.Lstat(name) + if err != nil { + return "", err + } + + // Don't watch sockets. + if fi.Mode()&os.ModeSocket == os.ModeSocket { + return "", nil + } + + // Don't watch named pipes. + if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { + return "", nil + } + + // Follow Symlinks + // Unfortunately, Linux can add bogus symlinks to watch list without + // issue, and Windows can't do symlinks period (AFAIK). To maintain + // consistency, we will act like everything is fine. There will simply + // be no file events for broken symlinks. + // Hence the returns of nil on errors. + if fi.Mode()&os.ModeSymlink == os.ModeSymlink { + name, err = filepath.EvalSymlinks(name) + if err != nil { + return "", nil + } + + w.mu.Lock() + _, alreadyWatching = w.watches[name] + w.mu.Unlock() + + if alreadyWatching { + return name, nil + } + + fi, err = os.Lstat(name) + if err != nil { + return "", nil + } + } + + watchfd, err = unix.Open(name, openMode, 0700) + if watchfd == -1 { + return "", err + } + + isDir = fi.IsDir() + } + + const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE + if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil { + unix.Close(watchfd) + return "", err + } + + if !alreadyWatching { + w.mu.Lock() + w.watches[name] = watchfd + w.paths[watchfd] = pathInfo{name: name, isDir: isDir} + w.mu.Unlock() + } + + if isDir { + // Watch the directory if it has not been watched before, + // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) + w.mu.Lock() + + watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && + (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE) + // Store flags so this watch can be updated later + w.dirFlags[name] = flags + w.mu.Unlock() + + if watchDir { + if err := w.watchDirectoryFiles(name); err != nil { + return "", err + } + } + } + return name, nil +} + +// readEvents reads from kqueue and converts the received kevents into +// Event values that it sends down the Events channel. +func (w *Watcher) readEvents() { + eventBuffer := make([]unix.Kevent_t, 10) + + for { + // See if there is a message on the "done" channel + select { + case <-w.done: + err := unix.Close(w.kq) + if err != nil { + w.Errors <- err + } + close(w.Events) + close(w.Errors) + return + default: + } + + // Get new events + kevents, err := read(w.kq, eventBuffer, &keventWaitTime) + // EINTR is okay, the syscall was interrupted before timeout expired. + if err != nil && err != unix.EINTR { + w.Errors <- err + continue + } + + // Flush the events we received to the Events channel + for len(kevents) > 0 { + kevent := &kevents[0] + watchfd := int(kevent.Ident) + mask := uint32(kevent.Fflags) + w.mu.Lock() + path := w.paths[watchfd] + w.mu.Unlock() + event := newEvent(path.name, mask) + + if path.isDir && !(event.Op&Remove == Remove) { + // Double check to make sure the directory exists. This can happen when + // we do a rm -fr on a recursively watched folders and we receive a + // modification event first but the folder has been deleted and later + // receive the delete event + if _, err := os.Lstat(event.Name); os.IsNotExist(err) { + // mark is as delete event + event.Op |= Remove + } + } + + if event.Op&Rename == Rename || event.Op&Remove == Remove { + w.Remove(event.Name) + w.mu.Lock() + delete(w.fileExists, event.Name) + w.mu.Unlock() + } + + if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) { + w.sendDirectoryChangeEvents(event.Name) + } else { + // Send the event on the Events channel + w.Events <- event + } + + if event.Op&Remove == Remove { + // Look for a file that may have overwritten this. + // For example, mv f1 f2 will delete f2, then create f2. + if path.isDir { + fileDir := filepath.Clean(event.Name) + w.mu.Lock() + _, found := w.watches[fileDir] + w.mu.Unlock() + if found { + // make sure the directory exists before we watch for changes. When we + // do a recursive watch and perform rm -fr, the parent directory might + // have gone missing, ignore the missing directory and let the + // upcoming delete event remove the watch from the parent directory. + if _, err := os.Lstat(fileDir); err == nil { + w.sendDirectoryChangeEvents(fileDir) + } + } + } else { + filePath := filepath.Clean(event.Name) + if fileInfo, err := os.Lstat(filePath); err == nil { + w.sendFileCreatedEventIfNew(filePath, fileInfo) + } + } + } + + // Move to next event + kevents = kevents[1:] + } + } +} + +// newEvent returns an platform-independent Event based on kqueue Fflags. +func newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.NOTE_DELETE == unix.NOTE_DELETE { + e.Op |= Remove + } + if mask&unix.NOTE_WRITE == unix.NOTE_WRITE { + e.Op |= Write + } + if mask&unix.NOTE_RENAME == unix.NOTE_RENAME { + e.Op |= Rename + } + if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB { + e.Op |= Chmod + } + return e +} + +func newCreateEvent(name string) Event { + return Event{Name: name, Op: Create} +} + +// watchDirectoryFiles to mimic inotify when adding a watch on a directory +func (w *Watcher) watchDirectoryFiles(dirPath string) error { + // Get all files + files, err := ioutil.ReadDir(dirPath) + if err != nil { + return err + } + + for _, fileInfo := range files { + filePath := filepath.Join(dirPath, fileInfo.Name()) + filePath, err = w.internalWatch(filePath, fileInfo) + if err != nil { + return err + } + + w.mu.Lock() + w.fileExists[filePath] = true + w.mu.Unlock() + } + + return nil +} + +// sendDirectoryEvents searches the directory for newly created files +// and sends them over the event channel. This functionality is to have +// the BSD version of fsnotify match Linux inotify which provides a +// create event for files created in a watched directory. +func (w *Watcher) sendDirectoryChangeEvents(dirPath string) { + // Get all files + files, err := ioutil.ReadDir(dirPath) + if err != nil { + w.Errors <- err + } + + // Search for new files + for _, fileInfo := range files { + filePath := filepath.Join(dirPath, fileInfo.Name()) + err := w.sendFileCreatedEventIfNew(filePath, fileInfo) + + if err != nil { + return + } + } +} + +// sendFileCreatedEvent sends a create event if the file isn't already being tracked. +func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) { + w.mu.Lock() + _, doesExist := w.fileExists[filePath] + w.mu.Unlock() + if !doesExist { + // Send create event + w.Events <- newCreateEvent(filePath) + } + + // like watchDirectoryFiles (but without doing another ReadDir) + filePath, err = w.internalWatch(filePath, fileInfo) + if err != nil { + return err + } + + w.mu.Lock() + w.fileExists[filePath] = true + w.mu.Unlock() + + return nil +} + +func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) { + if fileInfo.IsDir() { + // mimic Linux providing delete events for subdirectories + // but preserve the flags used if currently watching subdirectory + w.mu.Lock() + flags := w.dirFlags[name] + w.mu.Unlock() + + flags |= unix.NOTE_DELETE | unix.NOTE_RENAME + return w.addWatch(name, flags) + } + + // watch file to mimic Linux inotify + return w.addWatch(name, noteAllEvents) +} + +// kqueue creates a new kernel event queue and returns a descriptor. +func kqueue() (kq int, err error) { + kq, err = unix.Kqueue() + if kq == -1 { + return kq, err + } + return kq, nil +} + +// register events with the queue +func register(kq int, fds []int, flags int, fflags uint32) error { + changes := make([]unix.Kevent_t, len(fds)) + + for i, fd := range fds { + // SetKevent converts int to the platform-specific types: + unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags) + changes[i].Fflags = fflags + } + + // register the events + success, err := unix.Kevent(kq, changes, nil, nil) + if success == -1 { + return err + } + return nil +} + +// read retrieves pending events, or waits until an event occurs. +// A timeout of nil blocks indefinitely, while 0 polls the queue. +func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) { + n, err := unix.Kevent(kq, nil, events, timeout) + if err != nil { + return nil, err + } + return events[0:n], nil +} + +// durationToTimespec prepares a timeout value +func durationToTimespec(d time.Duration) unix.Timespec { + return unix.NsecToTimespec(d.Nanoseconds()) +} diff --git a/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go b/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go new file mode 100644 index 000000000..7d8de1451 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go @@ -0,0 +1,11 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build freebsd openbsd netbsd dragonfly + +package fsnotify + +import "golang.org/x/sys/unix" + +const openMode = unix.O_NONBLOCK | unix.O_RDONLY diff --git a/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go b/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go new file mode 100644 index 000000000..9139e1716 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go @@ -0,0 +1,12 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package fsnotify + +import "golang.org/x/sys/unix" + +// note: this constant is not defined on BSD +const openMode = unix.O_EVTONLY diff --git a/vendor/github.com/fsnotify/fsnotify/windows.go b/vendor/github.com/fsnotify/fsnotify/windows.go new file mode 100644 index 000000000..09436f31d --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/windows.go @@ -0,0 +1,561 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package fsnotify + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "sync" + "syscall" + "unsafe" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct { + Events chan Event + Errors chan error + isClosed bool // Set to true when Close() is first called + mu sync.Mutex // Map access + port syscall.Handle // Handle to completion port + watches watchMap // Map of watches (key: i-number) + input chan *input // Inputs to the reader are sent on this channel + quit chan chan<- error +} + +// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. +func NewWatcher() (*Watcher, error) { + port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0) + if e != nil { + return nil, os.NewSyscallError("CreateIoCompletionPort", e) + } + w := &Watcher{ + port: port, + watches: make(watchMap), + input: make(chan *input, 1), + Events: make(chan Event, 50), + Errors: make(chan error), + quit: make(chan chan<- error, 1), + } + go w.readEvents() + return w, nil +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + if w.isClosed { + return nil + } + w.isClosed = true + + // Send "quit" message to the reader goroutine + ch := make(chan error) + w.quit <- ch + if err := w.wakeupReader(); err != nil { + return err + } + return <-ch +} + +// Add starts watching the named file or directory (non-recursively). +func (w *Watcher) Add(name string) error { + if w.isClosed { + return errors.New("watcher already closed") + } + in := &input{ + op: opAddWatch, + path: filepath.Clean(name), + flags: sysFSALLEVENTS, + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// Remove stops watching the the named file or directory (non-recursively). +func (w *Watcher) Remove(name string) error { + in := &input{ + op: opRemoveWatch, + path: filepath.Clean(name), + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +const ( + // Options for AddWatch + sysFSONESHOT = 0x80000000 + sysFSONLYDIR = 0x1000000 + + // Events + sysFSACCESS = 0x1 + sysFSALLEVENTS = 0xfff + sysFSATTRIB = 0x4 + sysFSCLOSE = 0x18 + sysFSCREATE = 0x100 + sysFSDELETE = 0x200 + sysFSDELETESELF = 0x400 + sysFSMODIFY = 0x2 + sysFSMOVE = 0xc0 + sysFSMOVEDFROM = 0x40 + sysFSMOVEDTO = 0x80 + sysFSMOVESELF = 0x800 + + // Special events + sysFSIGNORED = 0x8000 + sysFSQOVERFLOW = 0x4000 +) + +func newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO { + e.Op |= Create + } + if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF { + e.Op |= Remove + } + if mask&sysFSMODIFY == sysFSMODIFY { + e.Op |= Write + } + if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM { + e.Op |= Rename + } + if mask&sysFSATTRIB == sysFSATTRIB { + e.Op |= Chmod + } + return e +} + +const ( + opAddWatch = iota + opRemoveWatch +) + +const ( + provisional uint64 = 1 << (32 + iota) +) + +type input struct { + op int + path string + flags uint32 + reply chan error +} + +type inode struct { + handle syscall.Handle + volume uint32 + index uint64 +} + +type watch struct { + ov syscall.Overlapped + ino *inode // i-number + path string // Directory path + mask uint64 // Directory itself is being watched with these notify flags + names map[string]uint64 // Map of names being watched and their notify flags + rename string // Remembers the old name while renaming a file + buf [4096]byte +} + +type indexMap map[uint64]*watch +type watchMap map[uint32]indexMap + +func (w *Watcher) wakeupReader() error { + e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil) + if e != nil { + return os.NewSyscallError("PostQueuedCompletionStatus", e) + } + return nil +} + +func getDir(pathname string) (dir string, err error) { + attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname)) + if e != nil { + return "", os.NewSyscallError("GetFileAttributes", e) + } + if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { + dir = pathname + } else { + dir, _ = filepath.Split(pathname) + dir = filepath.Clean(dir) + } + return +} + +func getIno(path string) (ino *inode, err error) { + h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path), + syscall.FILE_LIST_DIRECTORY, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + nil, syscall.OPEN_EXISTING, + syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0) + if e != nil { + return nil, os.NewSyscallError("CreateFile", e) + } + var fi syscall.ByHandleFileInformation + if e = syscall.GetFileInformationByHandle(h, &fi); e != nil { + syscall.CloseHandle(h) + return nil, os.NewSyscallError("GetFileInformationByHandle", e) + } + ino = &inode{ + handle: h, + volume: fi.VolumeSerialNumber, + index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), + } + return ino, nil +} + +// Must run within the I/O thread. +func (m watchMap) get(ino *inode) *watch { + if i := m[ino.volume]; i != nil { + return i[ino.index] + } + return nil +} + +// Must run within the I/O thread. +func (m watchMap) set(ino *inode, watch *watch) { + i := m[ino.volume] + if i == nil { + i = make(indexMap) + m[ino.volume] = i + } + i[ino.index] = watch +} + +// Must run within the I/O thread. +func (w *Watcher) addWatch(pathname string, flags uint64) error { + dir, err := getDir(pathname) + if err != nil { + return err + } + if flags&sysFSONLYDIR != 0 && pathname != dir { + return nil + } + ino, err := getIno(dir) + if err != nil { + return err + } + w.mu.Lock() + watchEntry := w.watches.get(ino) + w.mu.Unlock() + if watchEntry == nil { + if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil { + syscall.CloseHandle(ino.handle) + return os.NewSyscallError("CreateIoCompletionPort", e) + } + watchEntry = &watch{ + ino: ino, + path: dir, + names: make(map[string]uint64), + } + w.mu.Lock() + w.watches.set(ino, watchEntry) + w.mu.Unlock() + flags |= provisional + } else { + syscall.CloseHandle(ino.handle) + } + if pathname == dir { + watchEntry.mask |= flags + } else { + watchEntry.names[filepath.Base(pathname)] |= flags + } + if err = w.startRead(watchEntry); err != nil { + return err + } + if pathname == dir { + watchEntry.mask &= ^provisional + } else { + watchEntry.names[filepath.Base(pathname)] &= ^provisional + } + return nil +} + +// Must run within the I/O thread. +func (w *Watcher) remWatch(pathname string) error { + dir, err := getDir(pathname) + if err != nil { + return err + } + ino, err := getIno(dir) + if err != nil { + return err + } + w.mu.Lock() + watch := w.watches.get(ino) + w.mu.Unlock() + if watch == nil { + return fmt.Errorf("can't remove non-existent watch for: %s", pathname) + } + if pathname == dir { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + watch.mask = 0 + } else { + name := filepath.Base(pathname) + w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + return w.startRead(watch) +} + +// Must run within the I/O thread. +func (w *Watcher) deleteWatch(watch *watch) { + for name, mask := range watch.names { + if mask&provisional == 0 { + w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED) + } + delete(watch.names, name) + } + if watch.mask != 0 { + if watch.mask&provisional == 0 { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + } + watch.mask = 0 + } +} + +// Must run within the I/O thread. +func (w *Watcher) startRead(watch *watch) error { + if e := syscall.CancelIo(watch.ino.handle); e != nil { + w.Errors <- os.NewSyscallError("CancelIo", e) + w.deleteWatch(watch) + } + mask := toWindowsFlags(watch.mask) + for _, m := range watch.names { + mask |= toWindowsFlags(m) + } + if mask == 0 { + if e := syscall.CloseHandle(watch.ino.handle); e != nil { + w.Errors <- os.NewSyscallError("CloseHandle", e) + } + w.mu.Lock() + delete(w.watches[watch.ino.volume], watch.ino.index) + w.mu.Unlock() + return nil + } + e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], + uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) + if e != nil { + err := os.NewSyscallError("ReadDirectoryChanges", e) + if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { + // Watched directory was probably removed + if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) { + if watch.mask&sysFSONESHOT != 0 { + watch.mask = 0 + } + } + err = nil + } + w.deleteWatch(watch) + w.startRead(watch) + return err + } + return nil +} + +// readEvents reads from the I/O completion port, converts the +// received events into Event objects and sends them via the Events channel. +// Entry point to the I/O thread. +func (w *Watcher) readEvents() { + var ( + n, key uint32 + ov *syscall.Overlapped + ) + runtime.LockOSThread() + + for { + e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE) + watch := (*watch)(unsafe.Pointer(ov)) + + if watch == nil { + select { + case ch := <-w.quit: + w.mu.Lock() + var indexes []indexMap + for _, index := range w.watches { + indexes = append(indexes, index) + } + w.mu.Unlock() + for _, index := range indexes { + for _, watch := range index { + w.deleteWatch(watch) + w.startRead(watch) + } + } + var err error + if e := syscall.CloseHandle(w.port); e != nil { + err = os.NewSyscallError("CloseHandle", e) + } + close(w.Events) + close(w.Errors) + ch <- err + return + case in := <-w.input: + switch in.op { + case opAddWatch: + in.reply <- w.addWatch(in.path, uint64(in.flags)) + case opRemoveWatch: + in.reply <- w.remWatch(in.path) + } + default: + } + continue + } + + switch e { + case syscall.ERROR_MORE_DATA: + if watch == nil { + w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer") + } else { + // The i/o succeeded but the buffer is full. + // In theory we should be building up a full packet. + // In practice we can get away with just carrying on. + n = uint32(unsafe.Sizeof(watch.buf)) + } + case syscall.ERROR_ACCESS_DENIED: + // Watched directory was probably removed + w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) + w.deleteWatch(watch) + w.startRead(watch) + continue + case syscall.ERROR_OPERATION_ABORTED: + // CancelIo was called on this handle + continue + default: + w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e) + continue + case nil: + } + + var offset uint32 + for { + if n == 0 { + w.Events <- newEvent("", sysFSQOVERFLOW) + w.Errors <- errors.New("short read in readEvents()") + break + } + + // Point "raw" to the event in the buffer + raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) + buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName)) + name := syscall.UTF16ToString(buf[:raw.FileNameLength/2]) + fullname := filepath.Join(watch.path, name) + + var mask uint64 + switch raw.Action { + case syscall.FILE_ACTION_REMOVED: + mask = sysFSDELETESELF + case syscall.FILE_ACTION_MODIFIED: + mask = sysFSMODIFY + case syscall.FILE_ACTION_RENAMED_OLD_NAME: + watch.rename = name + case syscall.FILE_ACTION_RENAMED_NEW_NAME: + if watch.names[watch.rename] != 0 { + watch.names[name] |= watch.names[watch.rename] + delete(watch.names, watch.rename) + mask = sysFSMOVESELF + } + } + + sendNameEvent := func() { + if w.sendEvent(fullname, watch.names[name]&mask) { + if watch.names[name]&sysFSONESHOT != 0 { + delete(watch.names, name) + } + } + } + if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME { + sendNameEvent() + } + if raw.Action == syscall.FILE_ACTION_REMOVED { + w.sendEvent(fullname, watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) { + if watch.mask&sysFSONESHOT != 0 { + watch.mask = 0 + } + } + if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME { + fullname = filepath.Join(watch.path, watch.rename) + sendNameEvent() + } + + // Move to the next event in the buffer + if raw.NextEntryOffset == 0 { + break + } + offset += raw.NextEntryOffset + + // Error! + if offset >= n { + w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.") + break + } + } + + if err := w.startRead(watch); err != nil { + w.Errors <- err + } + } +} + +func (w *Watcher) sendEvent(name string, mask uint64) bool { + if mask == 0 { + return false + } + event := newEvent(name, uint32(mask)) + select { + case ch := <-w.quit: + w.quit <- ch + case w.Events <- event: + } + return true +} + +func toWindowsFlags(mask uint64) uint32 { + var m uint32 + if mask&sysFSACCESS != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS + } + if mask&sysFSMODIFY != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE + } + if mask&sysFSATTRIB != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES + } + if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME + } + return m +} + +func toFSnotifyFlags(action uint32) uint64 { + switch action { + case syscall.FILE_ACTION_ADDED: + return sysFSCREATE + case syscall.FILE_ACTION_REMOVED: + return sysFSDELETE + case syscall.FILE_ACTION_MODIFIED: + return sysFSMODIFY + case syscall.FILE_ACTION_RENAMED_OLD_NAME: + return sysFSMOVEDFROM + case syscall.FILE_ACTION_RENAMED_NEW_NAME: + return sysFSMOVEDTO + } + return 0 +} diff --git a/vendor/github.com/fsouza/go-dockerclient/.gitignore b/vendor/github.com/fsouza/go-dockerclient/.gitignore new file mode 100644 index 000000000..ef22245ea --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/.gitignore @@ -0,0 +1,4 @@ +# temporary symlink for testing +testing/data/symlink +Gopkg.lock +vendor/ diff --git a/vendor/github.com/fsouza/go-dockerclient/.travis.yml b/vendor/github.com/fsouza/go-dockerclient/.travis.yml new file mode 100644 index 000000000..7da0371a0 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/.travis.yml @@ -0,0 +1,30 @@ +language: go +sudo: required +go: + - 1.9.x + - 1.10.x +os: + - linux + - osx +env: + matrix: + - GOARCH=amd64 DOCKER_PKG_VERSION=18.03.0~ce-0~ubuntu + - GOARCH=386 DOCKER_PKG_VERSION=18.03.0~ce-0~ubuntu + - GOARCH=amd64 DOCKER_PKG_VERSION=18.02.0~ce-0~ubuntu + - GOARCH=386 DOCKER_PKG_VERSION=18.02.0~ce-0~ubuntu + global: + - DOCKER_HOST=tcp://127.0.0.1:2375 +install: + - make testdeps + - travis_retry travis-scripts/install-docker.bash +script: + - travis-scripts/run-tests.bash +services: + - docker +matrix: + fast_finish: true + exclude: + - os: osx + env: GOARCH=amd64 DOCKER_PKG_VERSION=18.02.0~ce-0~ubuntu + - os: osx + env: GOARCH=386 DOCKER_PKG_VERSION=18.02.0~ce-0~ubuntu diff --git a/vendor/github.com/fsouza/go-dockerclient/AUTHORS b/vendor/github.com/fsouza/go-dockerclient/AUTHORS new file mode 100644 index 000000000..f944f3950 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/AUTHORS @@ -0,0 +1,194 @@ +# This is the official list of go-dockerclient authors for copyright purposes. + +Abhishek Chanda +Adam Bell-Hanssen +Adnan Khan +Adrien Kohlbecker +Aithal +Aldrin Leal +Alex Dadgar +Alfonso Acosta +André Carvalho +Andreas Jaekle +Andrew Snodgrass +Andrews Medina +Andrey Sibiryov +Andy Goldstein +Anirudh Aithal +Antonio Murdaca +Artem Sidorenko +Arthur Rodrigues +Ben Marini +Ben McCann +Ben Parees +Benno van den Berg +Bradley Cicenas +Brendan Fosberry +Brian Lalor +Brian P. Hamachek +Brian Palmer +Bryan Boreham +Burke Libbey +Carlos Diaz-Padron +Carson A +Cássio Botaro +Cesar Wong +Cezar Sa Espinola +Changping Chen +Cheah Chu Yeow +cheneydeng +Chris Bednarski +Chris Stavropoulos +Christian Stewart +Christophe Mourette +Clayton Coleman +Clint Armstrong +CMGS +Colin Hebert +Craig Jellick +Damien Lespiau +Damon Wang +Dan Williams +Daniel, Dao Quang Minh +Daniel Garcia +Daniel Hiltgen +Daniel Nephin +Daniel Tsui +Darren Shepherd +Dave Choi +David Huie +Dawn Chen +Denis Makogon +Derek Petersen +Dinesh Subhraveti +Drew Wells +Ed +Elias G. Schneevoigt +Erez Horev +Eric Anderson +Eric J. Holmes +Eric Mountain +Erwin van Eyk +Ethan Mosbaugh +Ewout Prangsma +Fabio Rehm +Fatih Arslan +Faye Salwin +Felipe Oliveira +Flavia Missi +Florent Aide +Francisco Souza +Frank Groeneveld +George Moura +Grégoire Delattre +Guilherme Rezende +Guillermo Álvarez Fernández +Harry Zhang +He Simei +Isaac Schnitzer +Ivan Mikushin +James Bardin +James Nugent +Jamie Snell +Januar Wayong +Jari Kolehmainen +Jason Wilder +Jawher Moussa +Jean-Baptiste Dalido +Jeff Mitchell +Jeffrey Hulten +Jen Andre +Jérôme Laurens +Jim Minter +Johan Euphrosine +Johannes Scheuermann +John Hughes +Jorge Marey +Julian Einwag +Kamil Domanski +Karan Misra +Ken Herner +Kevin Lin +Kevin Xu +Kim, Hirokuni +Kostas Lekkas +Kyle Allan +Yunhee Lee +Liron Levin +Lior Yankovich +Liu Peng +Lorenz Leutgeb +Lucas Clemente +Lucas Weiblen +Lyon Hill +Mantas Matelis +Manuel Vogel +Marguerite des Trois Maisons +Mariusz Borsa +Martin Sweeney +Máximo Cuadros Ortiz +Michael Schmatz +Michal Fojtik +Mike Dillon +Mrunal Patel +Nate Jones +Nguyen Sy Thanh Son +Nicholas Van Wiggeren +Nick Ethier +niko83 +Omeid Matten +Orivej Desh +Paul Bellamy +Paul Morie +Paul Weil +Peter Edge +Peter Jihoon Kim +Peter Teich +Phil Lu +Philippe Lafoucrière +Radek Simko +Rafe Colton +Raphaël Pinson +Reed Allman +RJ Catalano +Rob Miller +Robbert Klarenbeek +Robert Williamson +Roman Khlystik +Russell Haering +Salvador Gironès +Sam Rijs +Sami Wagiaalla +Samuel Archambault +Samuel Karp +Sebastian Borza +Seth Jennings +Shane Xie +Silas Sewell +Simon Eskildsen +Simon Menke +Skolos +Soulou +Sridhar Ratnakumar +Steven Jack +Summer Mousa +Sunjin Lee +Sunny +Swaroop Ramachandra +Tarsis Azevedo +Tim Schindler +Timothy St. Clair +Tobi Knaup +Tom Wilkie +Tonic +ttyh061 +upccup +Victor Marmol +Vincenzo Prignano +Vlad Alexandru Ionescu +Weitao Zhou +Wiliam Souza +Ye Yin +Yosuke Otosu +Yu, Zou +Yuriy Bogdanov diff --git a/vendor/github.com/fsouza/go-dockerclient/DOCKER-LICENSE b/vendor/github.com/fsouza/go-dockerclient/DOCKER-LICENSE new file mode 100644 index 000000000..706634474 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/DOCKER-LICENSE @@ -0,0 +1,6 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +You can find the Docker license at the following link: +https://raw.githubusercontent.com/docker/docker/master/LICENSE diff --git a/vendor/github.com/fsouza/go-dockerclient/Gopkg.toml b/vendor/github.com/fsouza/go-dockerclient/Gopkg.toml new file mode 100644 index 000000000..47971edae --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/Gopkg.toml @@ -0,0 +1,28 @@ +[[constraint]] + name = "github.com/Microsoft/go-winio" + version = "v0.4.5" + +[[constraint]] + name = "github.com/docker/docker" + revision = "3dfb26ab3cbf961298f8ce3f94659b5fe4146ceb" + +[[constraint]] + name = "github.com/docker/go-units" + version = "v0.3.2" + +[[constraint]] + name = "github.com/google/go-cmp" + version = "v0.2.0" + +[[constraint]] + name = "github.com/gorilla/mux" + version = "v1.5.0" + +[[override]] + name = "github.com/Nvveen/Gotty" + source = "https://github.com/ijc25/Gotty.git" + revision = "a8b993ba6abdb0e0c12b0125c603323a71c7790c" + +[[override]] + name = "github.com/docker/libnetwork" + revision = "19279f0492417475b6bfbd0aa529f73e8f178fb5" diff --git a/vendor/github.com/fsouza/go-dockerclient/LICENSE b/vendor/github.com/fsouza/go-dockerclient/LICENSE new file mode 100644 index 000000000..fc7e73f8f --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2013-2018, go-dockerclient authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/fsouza/go-dockerclient/Makefile b/vendor/github.com/fsouza/go-dockerclient/Makefile new file mode 100644 index 000000000..479b07b0c --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/Makefile @@ -0,0 +1,34 @@ +.PHONY: \ + all \ + lint \ + vet \ + fmtcheck \ + pretest \ + test \ + integration + +all: test + +lint: + @ go get -v golang.org/x/lint/golint + [ -z "$$(golint . | grep -v 'type name will be used as docker.DockerInfo' | grep -v 'context.Context should be the first' | tee /dev/stderr)" ] + +vet: + go vet ./... + +fmtcheck: + [ -z "$$(gofmt -s -d *.go ./testing | tee /dev/stderr)" ] + +testdeps: + go get -u github.com/golang/dep/cmd/dep + dep ensure -v + +pretest: testdeps lint vet fmtcheck + +gotest: + go test -race ./... + +test: pretest gotest + +integration: + go test -tags docker_integration -run TestIntegration -v diff --git a/vendor/github.com/fsouza/go-dockerclient/README.markdown b/vendor/github.com/fsouza/go-dockerclient/README.markdown new file mode 100644 index 000000000..86824d6c5 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/README.markdown @@ -0,0 +1,133 @@ +# go-dockerclient + +[![Travis Build Status](https://travis-ci.org/fsouza/go-dockerclient.svg?branch=master)](https://travis-ci.org/fsouza/go-dockerclient) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/4m374pti06ubg2l7?svg=true)](https://ci.appveyor.com/project/fsouza/go-dockerclient) +[![GoDoc](https://img.shields.io/badge/api-Godoc-blue.svg?style=flat-square)](https://godoc.org/github.com/fsouza/go-dockerclient) + +This package presents a client for the Docker remote API. It also provides +support for the extensions in the [Swarm API](https://docs.docker.com/swarm/swarm-api/). + +This package also provides support for docker's network API, which is a simple +passthrough to the libnetwork remote API. Note that docker's network API is +only available in docker 1.8 and above, and only enabled in docker if +DOCKER_EXPERIMENTAL is defined during the docker build process. + +For more details, check the [remote API +documentation](http://docs.docker.com/engine/reference/api/docker_remote_api/). + +## Example + +```go +package main + +import ( + "fmt" + + "github.com/fsouza/go-dockerclient" +) + +func main() { + endpoint := "unix:///var/run/docker.sock" + client, err := docker.NewClient(endpoint) + if err != nil { + panic(err) + } + imgs, err := client.ListImages(docker.ListImagesOptions{All: false}) + if err != nil { + panic(err) + } + for _, img := range imgs { + fmt.Println("ID: ", img.ID) + fmt.Println("RepoTags: ", img.RepoTags) + fmt.Println("Created: ", img.Created) + fmt.Println("Size: ", img.Size) + fmt.Println("VirtualSize: ", img.VirtualSize) + fmt.Println("ParentId: ", img.ParentID) + } +} +``` + +## Using with TLS + +In order to instantiate the client for a TLS-enabled daemon, you should use +NewTLSClient, passing the endpoint and path for key and certificates as +parameters. + +```go +package main + +import ( + "fmt" + + "github.com/fsouza/go-dockerclient" +) + +func main() { + endpoint := "tcp://[ip]:[port]" + path := os.Getenv("DOCKER_CERT_PATH") + ca := fmt.Sprintf("%s/ca.pem", path) + cert := fmt.Sprintf("%s/cert.pem", path) + key := fmt.Sprintf("%s/key.pem", path) + client, _ := docker.NewTLSClient(endpoint, cert, key, ca) + // use client +} +``` + +If using [docker-machine](https://docs.docker.com/machine/), or another +application that exports environment variables `DOCKER_HOST`, +`DOCKER_TLS_VERIFY`, `DOCKER_CERT_PATH`, you can use NewClientFromEnv. + + +```go +package main + +import ( + "fmt" + + "github.com/fsouza/go-dockerclient" +) + +func main() { + client, _ := docker.NewClientFromEnv() + // use client +} +``` + +See the documentation for more details. + +## Developing + +All development commands can be seen in the [Makefile](Makefile). + +Commited code must pass: + +* [golint](https://github.com/golang/lint) (with some exceptions, see the Makefile). +* [go vet](https://golang.org/cmd/vet/) +* [gofmt](https://golang.org/cmd/gofmt) +* [go test](https://golang.org/cmd/go/#hdr-Test_packages) + +Running `make test` will check all of these. If your editor does not +automatically call ``gofmt -s``, `make fmt` will format all go files in this +repository. + +## Vendoring + +go-dockerclient uses [dep](https://github.com/golang/dep/) for vendoring. If +you're using dep, you should be able to pick go-dockerclient releases and get +the proper dependencies. + +With other vendoring tools, users might need to specify go-dockerclient's +dependencies manually. + +## Using with Docker 1.9 and Go 1.4 + +There's a tag for using go-dockerclient with Docker 1.9 (which requires +compiling go-dockerclient with Go 1.4), the tag name is ``docker-1.9/go-1.4``. + +The instructions below can be used to get a version of go-dockerclient that compiles with Go 1.4: + +``` +% git clone -b docker-1.9/go-1.4 https://github.com/fsouza/go-dockerclient.git $GOPATH/src/github.com/fsouza/go-dockerclient +% git clone -b v1.9.1 https://github.com/docker/docker.git $GOPATH/src/github.com/docker/docker +% go get github.com/fsouza/go-dockerclient +``` diff --git a/vendor/github.com/fsouza/go-dockerclient/appveyor.yml b/vendor/github.com/fsouza/go-dockerclient/appveyor.yml new file mode 100644 index 000000000..ee1297ad0 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/appveyor.yml @@ -0,0 +1,21 @@ +version: '{build}' +platform: x64 +clone_depth: 2 +clone_folder: c:\gopath\src\github.com\fsouza\go-dockerclient +environment: + GOPATH: c:\gopath + matrix: + - GOVERSION: 1.9.7 + - GOVERSION: 1.10.3 +install: + - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% + - rmdir c:\go /s /q + - appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.zip + - 7z x go%GOVERSION%.windows-amd64.zip -y -oC:\ > NUL +build_script: + - go get -u github.com/golang/dep/cmd/dep + - dep ensure -v +test_script: + - for /f "" %%G in ('go list ./... ^| find /i /v "/vendor/"') do ( go test %%G & IF ERRORLEVEL == 1 EXIT 1) +matrix: + fast_finish: true diff --git a/vendor/github.com/fsouza/go-dockerclient/auth.go b/vendor/github.com/fsouza/go-dockerclient/auth.go new file mode 100644 index 000000000..c58de8671 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/auth.go @@ -0,0 +1,185 @@ +// Copyright 2015 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "path" + "strings" +) + +// ErrCannotParseDockercfg is the error returned by NewAuthConfigurations when the dockercfg cannot be parsed. +var ErrCannotParseDockercfg = errors.New("Failed to read authentication from dockercfg") + +// AuthConfiguration represents authentication options to use in the PushImage +// method. It represents the authentication in the Docker index server. +type AuthConfiguration struct { + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Email string `json:"email,omitempty"` + ServerAddress string `json:"serveraddress,omitempty"` +} + +// AuthConfigurations represents authentication options to use for the +// PushImage method accommodating the new X-Registry-Config header +type AuthConfigurations struct { + Configs map[string]AuthConfiguration `json:"configs"` +} + +// AuthConfigurations119 is used to serialize a set of AuthConfigurations +// for Docker API >= 1.19. +type AuthConfigurations119 map[string]AuthConfiguration + +// dockerConfig represents a registry authentation configuration from the +// .dockercfg file. +type dockerConfig struct { + Auth string `json:"auth"` + Email string `json:"email"` +} + +// NewAuthConfigurationsFromFile returns AuthConfigurations from a path containing JSON +// in the same format as the .dockercfg file. +func NewAuthConfigurationsFromFile(path string) (*AuthConfigurations, error) { + r, err := os.Open(path) + if err != nil { + return nil, err + } + return NewAuthConfigurations(r) +} + +func cfgPaths(dockerConfigEnv string, homeEnv string) []string { + var paths []string + if dockerConfigEnv != "" { + paths = append(paths, path.Join(dockerConfigEnv, "config.json")) + } + if homeEnv != "" { + paths = append(paths, path.Join(homeEnv, ".docker", "config.json")) + paths = append(paths, path.Join(homeEnv, ".dockercfg")) + } + return paths +} + +// NewAuthConfigurationsFromDockerCfg returns AuthConfigurations from +// system config files. The following files are checked in the order listed: +// - $DOCKER_CONFIG/config.json if DOCKER_CONFIG set in the environment, +// - $HOME/.docker/config.json +// - $HOME/.dockercfg +func NewAuthConfigurationsFromDockerCfg() (*AuthConfigurations, error) { + err := fmt.Errorf("No docker configuration found") + var auths *AuthConfigurations + + pathsToTry := cfgPaths(os.Getenv("DOCKER_CONFIG"), os.Getenv("HOME")) + for _, path := range pathsToTry { + auths, err = NewAuthConfigurationsFromFile(path) + if err == nil { + return auths, nil + } + } + return auths, err +} + +// NewAuthConfigurations returns AuthConfigurations from a JSON encoded string in the +// same format as the .dockercfg file. +func NewAuthConfigurations(r io.Reader) (*AuthConfigurations, error) { + var auth *AuthConfigurations + confs, err := parseDockerConfig(r) + if err != nil { + return nil, err + } + auth, err = authConfigs(confs) + if err != nil { + return nil, err + } + return auth, nil +} + +func parseDockerConfig(r io.Reader) (map[string]dockerConfig, error) { + buf := new(bytes.Buffer) + buf.ReadFrom(r) + byteData := buf.Bytes() + + confsWrapper := struct { + Auths map[string]dockerConfig `json:"auths"` + }{} + if err := json.Unmarshal(byteData, &confsWrapper); err == nil { + if len(confsWrapper.Auths) > 0 { + return confsWrapper.Auths, nil + } + } + + var confs map[string]dockerConfig + if err := json.Unmarshal(byteData, &confs); err != nil { + return nil, err + } + return confs, nil +} + +// authConfigs converts a dockerConfigs map to a AuthConfigurations object. +func authConfigs(confs map[string]dockerConfig) (*AuthConfigurations, error) { + c := &AuthConfigurations{ + Configs: make(map[string]AuthConfiguration), + } + for reg, conf := range confs { + if conf.Auth == "" { + continue + } + data, err := base64.StdEncoding.DecodeString(conf.Auth) + if err != nil { + return nil, err + } + userpass := strings.SplitN(string(data), ":", 2) + if len(userpass) != 2 { + return nil, ErrCannotParseDockercfg + } + c.Configs[reg] = AuthConfiguration{ + Email: conf.Email, + Username: userpass[0], + Password: userpass[1], + ServerAddress: reg, + } + } + return c, nil +} + +// AuthStatus returns the authentication status for Docker API versions >= 1.23. +type AuthStatus struct { + Status string `json:"Status,omitempty" yaml:"Status,omitempty" toml:"Status,omitempty"` + IdentityToken string `json:"IdentityToken,omitempty" yaml:"IdentityToken,omitempty" toml:"IdentityToken,omitempty"` +} + +// AuthCheck validates the given credentials. It returns nil if successful. +// +// For Docker API versions >= 1.23, the AuthStatus struct will be populated, otherwise it will be empty.` +// +// See https://goo.gl/6nsZkH for more details. +func (c *Client) AuthCheck(conf *AuthConfiguration) (AuthStatus, error) { + var authStatus AuthStatus + if conf == nil { + return authStatus, errors.New("conf is nil") + } + resp, err := c.do("POST", "/auth", doOptions{data: conf}) + if err != nil { + return authStatus, err + } + defer resp.Body.Close() + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return authStatus, err + } + if len(data) == 0 { + return authStatus, nil + } + if err := json.Unmarshal(data, &authStatus); err != nil { + return authStatus, err + } + return authStatus, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/change.go b/vendor/github.com/fsouza/go-dockerclient/change.go new file mode 100644 index 000000000..3f936b223 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/change.go @@ -0,0 +1,43 @@ +// Copyright 2014 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import "fmt" + +// ChangeType is a type for constants indicating the type of change +// in a container +type ChangeType int + +const ( + // ChangeModify is the ChangeType for container modifications + ChangeModify ChangeType = iota + + // ChangeAdd is the ChangeType for additions to a container + ChangeAdd + + // ChangeDelete is the ChangeType for deletions from a container + ChangeDelete +) + +// Change represents a change in a container. +// +// See https://goo.gl/Wo0JJp for more details. +type Change struct { + Path string + Kind ChangeType +} + +func (change *Change) String() string { + var kind string + switch change.Kind { + case ChangeModify: + kind = "C" + case ChangeAdd: + kind = "A" + case ChangeDelete: + kind = "D" + } + return fmt.Sprintf("%s %s", kind, change.Path) +} diff --git a/vendor/github.com/fsouza/go-dockerclient/client.go b/vendor/github.com/fsouza/go-dockerclient/client.go new file mode 100644 index 000000000..581e31417 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/client.go @@ -0,0 +1,1093 @@ +// Copyright 2013 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package docker provides a client for the Docker remote API. +// +// See https://goo.gl/o2v3rk for more details on the remote API. +package docker + +import ( + "bufio" + "bytes" + "context" + "crypto/tls" + "crypto/x509" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "net/http" + "net/http/httputil" + "net/url" + "os" + "path/filepath" + "reflect" + "runtime" + "strconv" + "strings" + "sync/atomic" + "time" + + "github.com/docker/docker/opts" + "github.com/docker/docker/pkg/homedir" + "github.com/docker/docker/pkg/stdcopy" + "github.com/fsouza/go-dockerclient/internal/jsonmessage" +) + +const ( + userAgent = "go-dockerclient" + + unixProtocol = "unix" + namedPipeProtocol = "npipe" +) + +var ( + // ErrInvalidEndpoint is returned when the endpoint is not a valid HTTP URL. + ErrInvalidEndpoint = errors.New("invalid endpoint") + + // ErrConnectionRefused is returned when the client cannot connect to the given endpoint. + ErrConnectionRefused = errors.New("cannot connect to Docker endpoint") + + // ErrInactivityTimeout is returned when a streamable call has been inactive for some time. + ErrInactivityTimeout = errors.New("inactivity time exceeded timeout") + + apiVersion112, _ = NewAPIVersion("1.12") + apiVersion119, _ = NewAPIVersion("1.19") + apiVersion124, _ = NewAPIVersion("1.24") + apiVersion125, _ = NewAPIVersion("1.25") + apiVersion135, _ = NewAPIVersion("1.35") +) + +// APIVersion is an internal representation of a version of the Remote API. +type APIVersion []int + +// NewAPIVersion returns an instance of APIVersion for the given string. +// +// The given string must be in the form .., where , +// and are integer numbers. +func NewAPIVersion(input string) (APIVersion, error) { + if !strings.Contains(input, ".") { + return nil, fmt.Errorf("Unable to parse version %q", input) + } + raw := strings.Split(input, "-") + arr := strings.Split(raw[0], ".") + ret := make(APIVersion, len(arr)) + var err error + for i, val := range arr { + ret[i], err = strconv.Atoi(val) + if err != nil { + return nil, fmt.Errorf("Unable to parse version %q: %q is not an integer", input, val) + } + } + return ret, nil +} + +func (version APIVersion) String() string { + var str string + for i, val := range version { + str += strconv.Itoa(val) + if i < len(version)-1 { + str += "." + } + } + return str +} + +// LessThan is a function for comparing APIVersion structs +func (version APIVersion) LessThan(other APIVersion) bool { + return version.compare(other) < 0 +} + +// LessThanOrEqualTo is a function for comparing APIVersion structs +func (version APIVersion) LessThanOrEqualTo(other APIVersion) bool { + return version.compare(other) <= 0 +} + +// GreaterThan is a function for comparing APIVersion structs +func (version APIVersion) GreaterThan(other APIVersion) bool { + return version.compare(other) > 0 +} + +// GreaterThanOrEqualTo is a function for comparing APIVersion structs +func (version APIVersion) GreaterThanOrEqualTo(other APIVersion) bool { + return version.compare(other) >= 0 +} + +func (version APIVersion) compare(other APIVersion) int { + for i, v := range version { + if i <= len(other)-1 { + otherVersion := other[i] + + if v < otherVersion { + return -1 + } else if v > otherVersion { + return 1 + } + } + } + if len(version) > len(other) { + return 1 + } + if len(version) < len(other) { + return -1 + } + return 0 +} + +// Client is the basic type of this package. It provides methods for +// interaction with the API. +type Client struct { + SkipServerVersionCheck bool + HTTPClient *http.Client + TLSConfig *tls.Config + Dialer Dialer + + endpoint string + endpointURL *url.URL + eventMonitor *eventMonitoringState + requestedAPIVersion APIVersion + serverAPIVersion APIVersion + expectedAPIVersion APIVersion +} + +// Dialer is an interface that allows network connections to be dialed +// (net.Dialer fulfills this interface) and named pipes (a shim using +// winio.DialPipe) +type Dialer interface { + Dial(network, address string) (net.Conn, error) +} + +// NewClient returns a Client instance ready for communication with the given +// server endpoint. It will use the latest remote API version available in the +// server. +func NewClient(endpoint string) (*Client, error) { + client, err := NewVersionedClient(endpoint, "") + if err != nil { + return nil, err + } + client.SkipServerVersionCheck = true + return client, nil +} + +// NewTLSClient returns a Client instance ready for TLS communications with the givens +// server endpoint, key and certificates . It will use the latest remote API version +// available in the server. +func NewTLSClient(endpoint string, cert, key, ca string) (*Client, error) { + client, err := NewVersionedTLSClient(endpoint, cert, key, ca, "") + if err != nil { + return nil, err + } + client.SkipServerVersionCheck = true + return client, nil +} + +// NewTLSClientFromBytes returns a Client instance ready for TLS communications with the givens +// server endpoint, key and certificates (passed inline to the function as opposed to being +// read from a local file). It will use the latest remote API version available in the server. +func NewTLSClientFromBytes(endpoint string, certPEMBlock, keyPEMBlock, caPEMCert []byte) (*Client, error) { + client, err := NewVersionedTLSClientFromBytes(endpoint, certPEMBlock, keyPEMBlock, caPEMCert, "") + if err != nil { + return nil, err + } + client.SkipServerVersionCheck = true + return client, nil +} + +// NewVersionedClient returns a Client instance ready for communication with +// the given server endpoint, using a specific remote API version. +func NewVersionedClient(endpoint string, apiVersionString string) (*Client, error) { + u, err := parseEndpoint(endpoint, false) + if err != nil { + return nil, err + } + var requestedAPIVersion APIVersion + if strings.Contains(apiVersionString, ".") { + requestedAPIVersion, err = NewAPIVersion(apiVersionString) + if err != nil { + return nil, err + } + } + c := &Client{ + HTTPClient: defaultClient(), + Dialer: &net.Dialer{}, + endpoint: endpoint, + endpointURL: u, + eventMonitor: new(eventMonitoringState), + requestedAPIVersion: requestedAPIVersion, + } + c.initializeNativeClient(defaultTransport) + return c, nil +} + +// WithTransport replaces underlying HTTP client of Docker Client by accepting +// a function that returns pointer to a transport object. +func (c *Client) WithTransport(trFunc func() *http.Transport) { + c.initializeNativeClient(trFunc) +} + +// NewVersionnedTLSClient is like NewVersionedClient, but with ann extra n. +// +// Deprecated: Use NewVersionedTLSClient instead. +func NewVersionnedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) { + return NewVersionedTLSClient(endpoint, cert, key, ca, apiVersionString) +} + +// NewVersionedTLSClient returns a Client instance ready for TLS communications with the givens +// server endpoint, key and certificates, using a specific remote API version. +func NewVersionedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) { + var certPEMBlock []byte + var keyPEMBlock []byte + var caPEMCert []byte + if _, err := os.Stat(cert); !os.IsNotExist(err) { + certPEMBlock, err = ioutil.ReadFile(cert) + if err != nil { + return nil, err + } + } + if _, err := os.Stat(key); !os.IsNotExist(err) { + keyPEMBlock, err = ioutil.ReadFile(key) + if err != nil { + return nil, err + } + } + if _, err := os.Stat(ca); !os.IsNotExist(err) { + caPEMCert, err = ioutil.ReadFile(ca) + if err != nil { + return nil, err + } + } + return NewVersionedTLSClientFromBytes(endpoint, certPEMBlock, keyPEMBlock, caPEMCert, apiVersionString) +} + +// NewClientFromEnv returns a Client instance ready for communication created from +// Docker's default logic for the environment variables DOCKER_HOST, DOCKER_TLS_VERIFY, and DOCKER_CERT_PATH. +// +// See https://github.com/docker/docker/blob/1f963af697e8df3a78217f6fdbf67b8123a7db94/docker/docker.go#L68. +// See https://github.com/docker/compose/blob/81707ef1ad94403789166d2fe042c8a718a4c748/compose/cli/docker_client.py#L7. +func NewClientFromEnv() (*Client, error) { + client, err := NewVersionedClientFromEnv("") + if err != nil { + return nil, err + } + client.SkipServerVersionCheck = true + return client, nil +} + +// NewVersionedClientFromEnv returns a Client instance ready for TLS communications created from +// Docker's default logic for the environment variables DOCKER_HOST, DOCKER_TLS_VERIFY, and DOCKER_CERT_PATH, +// and using a specific remote API version. +// +// See https://github.com/docker/docker/blob/1f963af697e8df3a78217f6fdbf67b8123a7db94/docker/docker.go#L68. +// See https://github.com/docker/compose/blob/81707ef1ad94403789166d2fe042c8a718a4c748/compose/cli/docker_client.py#L7. +func NewVersionedClientFromEnv(apiVersionString string) (*Client, error) { + dockerEnv, err := getDockerEnv() + if err != nil { + return nil, err + } + dockerHost := dockerEnv.dockerHost + if dockerEnv.dockerTLSVerify { + parts := strings.SplitN(dockerEnv.dockerHost, "://", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("could not split %s into two parts by ://", dockerHost) + } + cert := filepath.Join(dockerEnv.dockerCertPath, "cert.pem") + key := filepath.Join(dockerEnv.dockerCertPath, "key.pem") + ca := filepath.Join(dockerEnv.dockerCertPath, "ca.pem") + return NewVersionedTLSClient(dockerEnv.dockerHost, cert, key, ca, apiVersionString) + } + return NewVersionedClient(dockerEnv.dockerHost, apiVersionString) +} + +// NewVersionedTLSClientFromBytes returns a Client instance ready for TLS communications with the givens +// server endpoint, key and certificates (passed inline to the function as opposed to being +// read from a local file), using a specific remote API version. +func NewVersionedTLSClientFromBytes(endpoint string, certPEMBlock, keyPEMBlock, caPEMCert []byte, apiVersionString string) (*Client, error) { + u, err := parseEndpoint(endpoint, true) + if err != nil { + return nil, err + } + var requestedAPIVersion APIVersion + if strings.Contains(apiVersionString, ".") { + requestedAPIVersion, err = NewAPIVersion(apiVersionString) + if err != nil { + return nil, err + } + } + tlsConfig := &tls.Config{} + if certPEMBlock != nil && keyPEMBlock != nil { + tlsCert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) + if err != nil { + return nil, err + } + tlsConfig.Certificates = []tls.Certificate{tlsCert} + } + if caPEMCert == nil { + tlsConfig.InsecureSkipVerify = true + } else { + caPool := x509.NewCertPool() + if !caPool.AppendCertsFromPEM(caPEMCert) { + return nil, errors.New("Could not add RootCA pem") + } + tlsConfig.RootCAs = caPool + } + tr := defaultTransport() + tr.TLSClientConfig = tlsConfig + if err != nil { + return nil, err + } + c := &Client{ + HTTPClient: &http.Client{Transport: tr}, + TLSConfig: tlsConfig, + Dialer: &net.Dialer{}, + endpoint: endpoint, + endpointURL: u, + eventMonitor: new(eventMonitoringState), + requestedAPIVersion: requestedAPIVersion, + } + c.initializeNativeClient(defaultTransport) + return c, nil +} + +// SetTimeout takes a timeout and applies it to the HTTPClient. It should not +// be called concurrently with any other Client methods. +func (c *Client) SetTimeout(t time.Duration) { + if c.HTTPClient != nil { + c.HTTPClient.Timeout = t + } +} + +func (c *Client) checkAPIVersion() error { + serverAPIVersionString, err := c.getServerAPIVersionString() + if err != nil { + return err + } + c.serverAPIVersion, err = NewAPIVersion(serverAPIVersionString) + if err != nil { + return err + } + if c.requestedAPIVersion == nil { + c.expectedAPIVersion = c.serverAPIVersion + } else { + c.expectedAPIVersion = c.requestedAPIVersion + } + return nil +} + +// Endpoint returns the current endpoint. It's useful for getting the endpoint +// when using functions that get this data from the environment (like +// NewClientFromEnv. +func (c *Client) Endpoint() string { + return c.endpoint +} + +// Ping pings the docker server +// +// See https://goo.gl/wYfgY1 for more details. +func (c *Client) Ping() error { + return c.PingWithContext(nil) +} + +// PingWithContext pings the docker server +// The context object can be used to cancel the ping request. +// +// See https://goo.gl/wYfgY1 for more details. +func (c *Client) PingWithContext(ctx context.Context) error { + path := "/_ping" + resp, err := c.do("GET", path, doOptions{context: ctx}) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK { + return newError(resp) + } + resp.Body.Close() + return nil +} + +func (c *Client) getServerAPIVersionString() (version string, err error) { + resp, err := c.do("GET", "/version", doOptions{}) + if err != nil { + return "", err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("Received unexpected status %d while trying to retrieve the server version", resp.StatusCode) + } + var versionResponse map[string]interface{} + if err := json.NewDecoder(resp.Body).Decode(&versionResponse); err != nil { + return "", err + } + if version, ok := (versionResponse["ApiVersion"]).(string); ok { + return version, nil + } + return "", nil +} + +type doOptions struct { + data interface{} + forceJSON bool + headers map[string]string + context context.Context +} + +func (c *Client) do(method, path string, doOptions doOptions) (*http.Response, error) { + var params io.Reader + if doOptions.data != nil || doOptions.forceJSON { + buf, err := json.Marshal(doOptions.data) + if err != nil { + return nil, err + } + params = bytes.NewBuffer(buf) + } + if path != "/version" && !c.SkipServerVersionCheck && c.expectedAPIVersion == nil { + err := c.checkAPIVersion() + if err != nil { + return nil, err + } + } + protocol := c.endpointURL.Scheme + var u string + switch protocol { + case unixProtocol, namedPipeProtocol: + u = c.getFakeNativeURL(path) + default: + u = c.getURL(path) + } + + req, err := http.NewRequest(method, u, params) + if err != nil { + return nil, err + } + req.Header.Set("User-Agent", userAgent) + if doOptions.data != nil { + req.Header.Set("Content-Type", "application/json") + } else if method == "POST" { + req.Header.Set("Content-Type", "plain/text") + } + + for k, v := range doOptions.headers { + req.Header.Set(k, v) + } + + ctx := doOptions.context + if ctx == nil { + ctx = context.Background() + } + + resp, err := c.HTTPClient.Do(req.WithContext(ctx)) + if err != nil { + if strings.Contains(err.Error(), "connection refused") { + return nil, ErrConnectionRefused + } + + return nil, chooseError(ctx, err) + } + if resp.StatusCode < 200 || resp.StatusCode >= 400 { + return nil, newError(resp) + } + return resp, nil +} + +type streamOptions struct { + setRawTerminal bool + rawJSONStream bool + useJSONDecoder bool + headers map[string]string + in io.Reader + stdout io.Writer + stderr io.Writer + reqSent chan struct{} + // timeout is the initial connection timeout + timeout time.Duration + // Timeout with no data is received, it's reset every time new data + // arrives + inactivityTimeout time.Duration + context context.Context +} + +// if error in context, return that instead of generic http error +func chooseError(ctx context.Context, err error) error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + return err + } +} + +func (c *Client) stream(method, path string, streamOptions streamOptions) error { + if (method == "POST" || method == "PUT") && streamOptions.in == nil { + streamOptions.in = bytes.NewReader(nil) + } + if path != "/version" && !c.SkipServerVersionCheck && c.expectedAPIVersion == nil { + err := c.checkAPIVersion() + if err != nil { + return err + } + } + req, err := http.NewRequest(method, c.getURL(path), streamOptions.in) + if err != nil { + return err + } + req.Header.Set("User-Agent", userAgent) + if method == "POST" { + req.Header.Set("Content-Type", "plain/text") + } + for key, val := range streamOptions.headers { + req.Header.Set(key, val) + } + var resp *http.Response + protocol := c.endpointURL.Scheme + address := c.endpointURL.Path + if streamOptions.stdout == nil { + streamOptions.stdout = ioutil.Discard + } + if streamOptions.stderr == nil { + streamOptions.stderr = ioutil.Discard + } + + // make a sub-context so that our active cancellation does not affect parent + ctx := streamOptions.context + if ctx == nil { + ctx = context.Background() + } + subCtx, cancelRequest := context.WithCancel(ctx) + defer cancelRequest() + + if protocol == unixProtocol || protocol == namedPipeProtocol { + var dial net.Conn + dial, err = c.Dialer.Dial(protocol, address) + if err != nil { + return err + } + go func() { + <-subCtx.Done() + dial.Close() + }() + breader := bufio.NewReader(dial) + err = req.Write(dial) + if err != nil { + return chooseError(subCtx, err) + } + + // ReadResponse may hang if server does not replay + if streamOptions.timeout > 0 { + dial.SetDeadline(time.Now().Add(streamOptions.timeout)) + } + + if streamOptions.reqSent != nil { + close(streamOptions.reqSent) + } + if resp, err = http.ReadResponse(breader, req); err != nil { + // Cancel timeout for future I/O operations + if streamOptions.timeout > 0 { + dial.SetDeadline(time.Time{}) + } + if strings.Contains(err.Error(), "connection refused") { + return ErrConnectionRefused + } + + return chooseError(subCtx, err) + } + } else { + if resp, err = c.HTTPClient.Do(req.WithContext(subCtx)); err != nil { + if strings.Contains(err.Error(), "connection refused") { + return ErrConnectionRefused + } + return chooseError(subCtx, err) + } + if streamOptions.reqSent != nil { + close(streamOptions.reqSent) + } + } + defer resp.Body.Close() + if resp.StatusCode < 200 || resp.StatusCode >= 400 { + return newError(resp) + } + var canceled uint32 + if streamOptions.inactivityTimeout > 0 { + var ch chan<- struct{} + resp.Body, ch = handleInactivityTimeout(resp.Body, streamOptions.inactivityTimeout, cancelRequest, &canceled) + defer close(ch) + } + err = handleStreamResponse(resp, &streamOptions) + if err != nil { + if atomic.LoadUint32(&canceled) != 0 { + return ErrInactivityTimeout + } + return chooseError(subCtx, err) + } + return nil +} + +func handleStreamResponse(resp *http.Response, streamOptions *streamOptions) error { + var err error + if !streamOptions.useJSONDecoder && resp.Header.Get("Content-Type") != "application/json" { + if streamOptions.setRawTerminal { + _, err = io.Copy(streamOptions.stdout, resp.Body) + } else { + _, err = stdcopy.StdCopy(streamOptions.stdout, streamOptions.stderr, resp.Body) + } + return err + } + // if we want to get raw json stream, just copy it back to output + // without decoding it + if streamOptions.rawJSONStream { + _, err = io.Copy(streamOptions.stdout, resp.Body) + return err + } + if st, ok := streamOptions.stdout.(interface { + io.Writer + FD() uintptr + IsTerminal() bool + }); ok { + err = jsonmessage.DisplayJSONMessagesToStream(resp.Body, st, nil) + } else { + err = jsonmessage.DisplayJSONMessagesStream(resp.Body, streamOptions.stdout, 0, false, nil) + } + return err +} + +type proxyReader struct { + io.ReadCloser + calls uint64 +} + +func (p *proxyReader) callCount() uint64 { + return atomic.LoadUint64(&p.calls) +} + +func (p *proxyReader) Read(data []byte) (int, error) { + atomic.AddUint64(&p.calls, 1) + return p.ReadCloser.Read(data) +} + +func handleInactivityTimeout(reader io.ReadCloser, timeout time.Duration, cancelRequest func(), canceled *uint32) (io.ReadCloser, chan<- struct{}) { + done := make(chan struct{}) + proxyReader := &proxyReader{ReadCloser: reader} + go func() { + var lastCallCount uint64 + for { + select { + case <-time.After(timeout): + case <-done: + return + } + curCallCount := proxyReader.callCount() + if curCallCount == lastCallCount { + atomic.AddUint32(canceled, 1) + cancelRequest() + return + } + lastCallCount = curCallCount + } + }() + return proxyReader, done +} + +type hijackOptions struct { + success chan struct{} + setRawTerminal bool + in io.Reader + stdout io.Writer + stderr io.Writer + data interface{} +} + +// CloseWaiter is an interface with methods for closing the underlying resource +// and then waiting for it to finish processing. +type CloseWaiter interface { + io.Closer + Wait() error +} + +type waiterFunc func() error + +func (w waiterFunc) Wait() error { return w() } + +type closerFunc func() error + +func (c closerFunc) Close() error { return c() } + +func (c *Client) hijack(method, path string, hijackOptions hijackOptions) (CloseWaiter, error) { + if path != "/version" && !c.SkipServerVersionCheck && c.expectedAPIVersion == nil { + err := c.checkAPIVersion() + if err != nil { + return nil, err + } + } + var params io.Reader + if hijackOptions.data != nil { + buf, err := json.Marshal(hijackOptions.data) + if err != nil { + return nil, err + } + params = bytes.NewBuffer(buf) + } + req, err := http.NewRequest(method, c.getURL(path), params) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Connection", "Upgrade") + req.Header.Set("Upgrade", "tcp") + protocol := c.endpointURL.Scheme + address := c.endpointURL.Path + if protocol != unixProtocol && protocol != namedPipeProtocol { + protocol = "tcp" + address = c.endpointURL.Host + } + var dial net.Conn + if c.TLSConfig != nil && protocol != unixProtocol && protocol != namedPipeProtocol { + netDialer, ok := c.Dialer.(*net.Dialer) + if !ok { + return nil, ErrTLSNotSupported + } + dial, err = tlsDialWithDialer(netDialer, protocol, address, c.TLSConfig) + if err != nil { + return nil, err + } + } else { + dial, err = c.Dialer.Dial(protocol, address) + if err != nil { + return nil, err + } + } + + errs := make(chan error, 1) + quit := make(chan struct{}) + go func() { + clientconn := httputil.NewClientConn(dial, nil) + defer clientconn.Close() + clientconn.Do(req) + if hijackOptions.success != nil { + hijackOptions.success <- struct{}{} + <-hijackOptions.success + } + rwc, br := clientconn.Hijack() + defer rwc.Close() + + errChanOut := make(chan error, 1) + errChanIn := make(chan error, 2) + if hijackOptions.stdout == nil && hijackOptions.stderr == nil { + close(errChanOut) + } else { + // Only copy if hijackOptions.stdout and/or hijackOptions.stderr is actually set. + // Otherwise, if the only stream you care about is stdin, your attach session + // will "hang" until the container terminates, even though you're not reading + // stdout/stderr + if hijackOptions.stdout == nil { + hijackOptions.stdout = ioutil.Discard + } + if hijackOptions.stderr == nil { + hijackOptions.stderr = ioutil.Discard + } + + go func() { + defer func() { + if hijackOptions.in != nil { + if closer, ok := hijackOptions.in.(io.Closer); ok { + closer.Close() + } + errChanIn <- nil + } + }() + + var err error + if hijackOptions.setRawTerminal { + _, err = io.Copy(hijackOptions.stdout, br) + } else { + _, err = stdcopy.StdCopy(hijackOptions.stdout, hijackOptions.stderr, br) + } + errChanOut <- err + }() + } + + go func() { + var err error + if hijackOptions.in != nil { + _, err = io.Copy(rwc, hijackOptions.in) + } + errChanIn <- err + rwc.(interface { + CloseWrite() error + }).CloseWrite() + }() + + var errIn error + select { + case errIn = <-errChanIn: + case <-quit: + } + + var errOut error + select { + case errOut = <-errChanOut: + case <-quit: + } + + if errIn != nil { + errs <- errIn + } else { + errs <- errOut + } + }() + + return struct { + closerFunc + waiterFunc + }{ + closerFunc(func() error { close(quit); return nil }), + waiterFunc(func() error { return <-errs }), + }, nil +} + +func (c *Client) getURL(path string) string { + urlStr := strings.TrimRight(c.endpointURL.String(), "/") + if c.endpointURL.Scheme == unixProtocol || c.endpointURL.Scheme == namedPipeProtocol { + urlStr = "" + } + if c.requestedAPIVersion != nil { + return fmt.Sprintf("%s/v%s%s", urlStr, c.requestedAPIVersion, path) + } + return fmt.Sprintf("%s%s", urlStr, path) +} + +// getFakeNativeURL returns the URL needed to make an HTTP request over a UNIX +// domain socket to the given path. +func (c *Client) getFakeNativeURL(path string) string { + u := *c.endpointURL // Copy. + + // Override URL so that net/http will not complain. + u.Scheme = "http" + u.Host = "unix.sock" // Doesn't matter what this is - it's not used. + u.Path = "" + urlStr := strings.TrimRight(u.String(), "/") + if c.requestedAPIVersion != nil { + return fmt.Sprintf("%s/v%s%s", urlStr, c.requestedAPIVersion, path) + } + return fmt.Sprintf("%s%s", urlStr, path) +} + +type jsonMessage struct { + Status string `json:"status,omitempty"` + Progress string `json:"progress,omitempty"` + Error string `json:"error,omitempty"` + Stream string `json:"stream,omitempty"` +} + +func queryString(opts interface{}) string { + if opts == nil { + return "" + } + value := reflect.ValueOf(opts) + if value.Kind() == reflect.Ptr { + value = value.Elem() + } + if value.Kind() != reflect.Struct { + return "" + } + items := url.Values(map[string][]string{}) + for i := 0; i < value.NumField(); i++ { + field := value.Type().Field(i) + if field.PkgPath != "" { + continue + } + key := field.Tag.Get("qs") + if key == "" { + key = strings.ToLower(field.Name) + } else if key == "-" { + continue + } + addQueryStringValue(items, key, value.Field(i)) + } + return items.Encode() +} + +func addQueryStringValue(items url.Values, key string, v reflect.Value) { + switch v.Kind() { + case reflect.Bool: + if v.Bool() { + items.Add(key, "1") + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if v.Int() > 0 { + items.Add(key, strconv.FormatInt(v.Int(), 10)) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + if v.Uint() > 0 { + items.Add(key, strconv.FormatUint(v.Uint(), 10)) + } + case reflect.Float32, reflect.Float64: + if v.Float() > 0 { + items.Add(key, strconv.FormatFloat(v.Float(), 'f', -1, 64)) + } + case reflect.String: + if v.String() != "" { + items.Add(key, v.String()) + } + case reflect.Ptr: + if !v.IsNil() { + if b, err := json.Marshal(v.Interface()); err == nil { + items.Add(key, string(b)) + } + } + case reflect.Map: + if len(v.MapKeys()) > 0 { + if b, err := json.Marshal(v.Interface()); err == nil { + items.Add(key, string(b)) + } + } + case reflect.Array, reflect.Slice: + vLen := v.Len() + if vLen > 0 { + for i := 0; i < vLen; i++ { + addQueryStringValue(items, key, v.Index(i)) + } + } + } +} + +// Error represents failures in the API. It represents a failure from the API. +type Error struct { + Status int + Message string +} + +func newError(resp *http.Response) *Error { + type ErrMsg struct { + Message string `json:"message"` + } + defer resp.Body.Close() + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return &Error{Status: resp.StatusCode, Message: fmt.Sprintf("cannot read body, err: %v", err)} + } + var emsg ErrMsg + err = json.Unmarshal(data, &emsg) + if err != nil { + return &Error{Status: resp.StatusCode, Message: string(data)} + } + return &Error{Status: resp.StatusCode, Message: emsg.Message} +} + +func (e *Error) Error() string { + return fmt.Sprintf("API error (%d): %s", e.Status, e.Message) +} + +func parseEndpoint(endpoint string, tls bool) (*url.URL, error) { + if endpoint != "" && !strings.Contains(endpoint, "://") { + endpoint = "tcp://" + endpoint + } + u, err := url.Parse(endpoint) + if err != nil { + return nil, ErrInvalidEndpoint + } + if tls && u.Scheme != "unix" { + u.Scheme = "https" + } + switch u.Scheme { + case unixProtocol, namedPipeProtocol: + return u, nil + case "http", "https", "tcp": + _, port, err := net.SplitHostPort(u.Host) + if err != nil { + if e, ok := err.(*net.AddrError); ok { + if e.Err == "missing port in address" { + return u, nil + } + } + return nil, ErrInvalidEndpoint + } + number, err := strconv.ParseInt(port, 10, 64) + if err == nil && number > 0 && number < 65536 { + if u.Scheme == "tcp" { + if tls { + u.Scheme = "https" + } else { + u.Scheme = "http" + } + } + return u, nil + } + return nil, ErrInvalidEndpoint + default: + return nil, ErrInvalidEndpoint + } +} + +type dockerEnv struct { + dockerHost string + dockerTLSVerify bool + dockerCertPath string +} + +func getDockerEnv() (*dockerEnv, error) { + dockerHost := os.Getenv("DOCKER_HOST") + var err error + if dockerHost == "" { + dockerHost = opts.DefaultHost + } + dockerTLSVerify := os.Getenv("DOCKER_TLS_VERIFY") != "" + var dockerCertPath string + if dockerTLSVerify { + dockerCertPath = os.Getenv("DOCKER_CERT_PATH") + if dockerCertPath == "" { + home := homedir.Get() + if home == "" { + return nil, errors.New("environment variable HOME must be set if DOCKER_CERT_PATH is not set") + } + dockerCertPath = filepath.Join(home, ".docker") + dockerCertPath, err = filepath.Abs(dockerCertPath) + if err != nil { + return nil, err + } + } + } + return &dockerEnv{ + dockerHost: dockerHost, + dockerTLSVerify: dockerTLSVerify, + dockerCertPath: dockerCertPath, + }, nil +} + +// defaultTransport returns a new http.Transport with similar default values to +// http.DefaultTransport, but with idle connections and keepalives disabled. +func defaultTransport() *http.Transport { + transport := defaultPooledTransport() + transport.DisableKeepAlives = true + transport.MaxIdleConnsPerHost = -1 + return transport +} + +// defaultPooledTransport returns a new http.Transport with similar default +// values to http.DefaultTransport. Do not use this for transient transports as +// it can leak file descriptors over time. Only use this for transports that +// will be re-used for the same host(s). +func defaultPooledTransport() *http.Transport { + transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).DialContext, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1, + } + return transport +} + +// defaultClient returns a new http.Client with similar default values to +// http.Client, but with a non-shared Transport, idle connections disabled, and +// keepalives disabled. +func defaultClient() *http.Client { + return &http.Client{ + Transport: defaultTransport(), + } +} diff --git a/vendor/github.com/fsouza/go-dockerclient/client_unix.go b/vendor/github.com/fsouza/go-dockerclient/client_unix.go new file mode 100644 index 000000000..57d7904ea --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/client_unix.go @@ -0,0 +1,32 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !windows + +package docker + +import ( + "context" + "net" + "net/http" +) + +// initializeNativeClient initializes the native Unix domain socket client on +// Unix-style operating systems +func (c *Client) initializeNativeClient(trFunc func() *http.Transport) { + if c.endpointURL.Scheme != unixProtocol { + return + } + sockPath := c.endpointURL.Path + + tr := trFunc() + + tr.Dial = func(network, addr string) (net.Conn, error) { + return c.Dialer.Dial(unixProtocol, sockPath) + } + tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + return c.Dialer.Dial(unixProtocol, sockPath) + } + c.HTTPClient.Transport = tr +} diff --git a/vendor/github.com/fsouza/go-dockerclient/client_windows.go b/vendor/github.com/fsouza/go-dockerclient/client_windows.go new file mode 100644 index 000000000..8e7b457d7 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/client_windows.go @@ -0,0 +1,45 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package docker + +import ( + "context" + "net" + "net/http" + "time" + + "github.com/Microsoft/go-winio" +) + +const namedPipeConnectTimeout = 2 * time.Second + +type pipeDialer struct { + dialFunc func(network, addr string) (net.Conn, error) +} + +func (p pipeDialer) Dial(network, address string) (net.Conn, error) { + return p.dialFunc(network, address) +} + +// initializeNativeClient initializes the native Named Pipe client for Windows +func (c *Client) initializeNativeClient(trFunc func() *http.Transport) { + if c.endpointURL.Scheme != namedPipeProtocol { + return + } + namedPipePath := c.endpointURL.Path + dialFunc := func(network, addr string) (net.Conn, error) { + timeout := namedPipeConnectTimeout + return winio.DialPipe(namedPipePath, &timeout) + } + tr := trFunc() + tr.Dial = dialFunc + tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + return dialFunc(network, addr) + } + c.Dialer = &pipeDialer{dialFunc} + c.HTTPClient.Transport = tr +} diff --git a/vendor/github.com/fsouza/go-dockerclient/container.go b/vendor/github.com/fsouza/go-dockerclient/container.go new file mode 100644 index 000000000..e24c9fb2e --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/container.go @@ -0,0 +1,1623 @@ +// Copyright 2013 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/docker/go-units" +) + +// ErrContainerAlreadyExists is the error returned by CreateContainer when the +// container already exists. +var ErrContainerAlreadyExists = errors.New("container already exists") + +// ListContainersOptions specify parameters to the ListContainers function. +// +// See https://goo.gl/kaOHGw for more details. +type ListContainersOptions struct { + All bool + Size bool + Limit int + Since string + Before string + Filters map[string][]string + Context context.Context +} + +// APIPort is a type that represents a port mapping returned by the Docker API +type APIPort struct { + PrivatePort int64 `json:"PrivatePort,omitempty" yaml:"PrivatePort,omitempty" toml:"PrivatePort,omitempty"` + PublicPort int64 `json:"PublicPort,omitempty" yaml:"PublicPort,omitempty" toml:"PublicPort,omitempty"` + Type string `json:"Type,omitempty" yaml:"Type,omitempty" toml:"Type,omitempty"` + IP string `json:"IP,omitempty" yaml:"IP,omitempty" toml:"IP,omitempty"` +} + +// APIMount represents a mount point for a container. +type APIMount struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Source string `json:"Source,omitempty" yaml:"Source,omitempty" toml:"Source,omitempty"` + Destination string `json:"Destination,omitempty" yaml:"Destination,omitempty" toml:"Destination,omitempty"` + Driver string `json:"Driver,omitempty" yaml:"Driver,omitempty" toml:"Driver,omitempty"` + Mode string `json:"Mode,omitempty" yaml:"Mode,omitempty" toml:"Mode,omitempty"` + RW bool `json:"RW,omitempty" yaml:"RW,omitempty" toml:"RW,omitempty"` + Propogation string `json:"Propogation,omitempty" yaml:"Propogation,omitempty" toml:"Propogation,omitempty"` +} + +// APIContainers represents each container in the list returned by +// ListContainers. +type APIContainers struct { + ID string `json:"Id" yaml:"Id" toml:"Id"` + Image string `json:"Image,omitempty" yaml:"Image,omitempty" toml:"Image,omitempty"` + Command string `json:"Command,omitempty" yaml:"Command,omitempty" toml:"Command,omitempty"` + Created int64 `json:"Created,omitempty" yaml:"Created,omitempty" toml:"Created,omitempty"` + State string `json:"State,omitempty" yaml:"State,omitempty" toml:"State,omitempty"` + Status string `json:"Status,omitempty" yaml:"Status,omitempty" toml:"Status,omitempty"` + Ports []APIPort `json:"Ports,omitempty" yaml:"Ports,omitempty" toml:"Ports,omitempty"` + SizeRw int64 `json:"SizeRw,omitempty" yaml:"SizeRw,omitempty" toml:"SizeRw,omitempty"` + SizeRootFs int64 `json:"SizeRootFs,omitempty" yaml:"SizeRootFs,omitempty" toml:"SizeRootFs,omitempty"` + Names []string `json:"Names,omitempty" yaml:"Names,omitempty" toml:"Names,omitempty"` + Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"` + Networks NetworkList `json:"NetworkSettings,omitempty" yaml:"NetworkSettings,omitempty" toml:"NetworkSettings,omitempty"` + Mounts []APIMount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"` +} + +// NetworkList encapsulates a map of networks, as returned by the Docker API in +// ListContainers. +type NetworkList struct { + Networks map[string]ContainerNetwork `json:"Networks" yaml:"Networks,omitempty" toml:"Networks,omitempty"` +} + +// ListContainers returns a slice of containers matching the given criteria. +// +// See https://goo.gl/kaOHGw for more details. +func (c *Client) ListContainers(opts ListContainersOptions) ([]APIContainers, error) { + path := "/containers/json?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var containers []APIContainers + if err := json.NewDecoder(resp.Body).Decode(&containers); err != nil { + return nil, err + } + return containers, nil +} + +// Port represents the port number and the protocol, in the form +// /. For example: 80/tcp. +type Port string + +// Port returns the number of the port. +func (p Port) Port() string { + return strings.Split(string(p), "/")[0] +} + +// Proto returns the name of the protocol. +func (p Port) Proto() string { + parts := strings.Split(string(p), "/") + if len(parts) == 1 { + return "tcp" + } + return parts[1] +} + +// HealthCheck represents one check of health. +type HealthCheck struct { + Start time.Time `json:"Start,omitempty" yaml:"Start,omitempty" toml:"Start,omitempty"` + End time.Time `json:"End,omitempty" yaml:"End,omitempty" toml:"End,omitempty"` + ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty" toml:"ExitCode,omitempty"` + Output string `json:"Output,omitempty" yaml:"Output,omitempty" toml:"Output,omitempty"` +} + +// Health represents the health of a container. +type Health struct { + Status string `json:"Status,omitempty" yaml:"Status,omitempty" toml:"Status,omitempty"` + FailingStreak int `json:"FailingStreak,omitempty" yaml:"FailingStreak,omitempty" toml:"FailingStreak,omitempty"` + Log []HealthCheck `json:"Log,omitempty" yaml:"Log,omitempty" toml:"Log,omitempty"` +} + +// State represents the state of a container. +type State struct { + Status string `json:"Status,omitempty" yaml:"Status,omitempty" toml:"Status,omitempty"` + Running bool `json:"Running,omitempty" yaml:"Running,omitempty" toml:"Running,omitempty"` + Paused bool `json:"Paused,omitempty" yaml:"Paused,omitempty" toml:"Paused,omitempty"` + Restarting bool `json:"Restarting,omitempty" yaml:"Restarting,omitempty" toml:"Restarting,omitempty"` + OOMKilled bool `json:"OOMKilled,omitempty" yaml:"OOMKilled,omitempty" toml:"OOMKilled,omitempty"` + RemovalInProgress bool `json:"RemovalInProgress,omitempty" yaml:"RemovalInProgress,omitempty" toml:"RemovalInProgress,omitempty"` + Dead bool `json:"Dead,omitempty" yaml:"Dead,omitempty" toml:"Dead,omitempty"` + Pid int `json:"Pid,omitempty" yaml:"Pid,omitempty" toml:"Pid,omitempty"` + ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty" toml:"ExitCode,omitempty"` + Error string `json:"Error,omitempty" yaml:"Error,omitempty" toml:"Error,omitempty"` + StartedAt time.Time `json:"StartedAt,omitempty" yaml:"StartedAt,omitempty" toml:"StartedAt,omitempty"` + FinishedAt time.Time `json:"FinishedAt,omitempty" yaml:"FinishedAt,omitempty" toml:"FinishedAt,omitempty"` + Health Health `json:"Health,omitempty" yaml:"Health,omitempty" toml:"Health,omitempty"` +} + +// String returns a human-readable description of the state +func (s *State) String() string { + if s.Running { + if s.Paused { + return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) + } + if s.Restarting { + return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) + } + + return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) + } + + if s.RemovalInProgress { + return "Removal In Progress" + } + + if s.Dead { + return "Dead" + } + + if s.StartedAt.IsZero() { + return "Created" + } + + if s.FinishedAt.IsZero() { + return "" + } + + return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) +} + +// StateString returns a single string to describe state +func (s *State) StateString() string { + if s.Running { + if s.Paused { + return "paused" + } + if s.Restarting { + return "restarting" + } + return "running" + } + + if s.Dead { + return "dead" + } + + if s.StartedAt.IsZero() { + return "created" + } + + return "exited" +} + +// PortBinding represents the host/container port mapping as returned in the +// `docker inspect` json +type PortBinding struct { + HostIP string `json:"HostIp,omitempty" yaml:"HostIp,omitempty" toml:"HostIp,omitempty"` + HostPort string `json:"HostPort,omitempty" yaml:"HostPort,omitempty" toml:"HostPort,omitempty"` +} + +// PortMapping represents a deprecated field in the `docker inspect` output, +// and its value as found in NetworkSettings should always be nil +type PortMapping map[string]string + +// ContainerNetwork represents the networking settings of a container per network. +type ContainerNetwork struct { + Aliases []string `json:"Aliases,omitempty" yaml:"Aliases,omitempty" toml:"Aliases,omitempty"` + MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty" toml:"MacAddress,omitempty"` + GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen,omitempty" yaml:"GlobalIPv6PrefixLen,omitempty" toml:"GlobalIPv6PrefixLen,omitempty"` + GlobalIPv6Address string `json:"GlobalIPv6Address,omitempty" yaml:"GlobalIPv6Address,omitempty" toml:"GlobalIPv6Address,omitempty"` + IPv6Gateway string `json:"IPv6Gateway,omitempty" yaml:"IPv6Gateway,omitempty" toml:"IPv6Gateway,omitempty"` + IPPrefixLen int `json:"IPPrefixLen,omitempty" yaml:"IPPrefixLen,omitempty" toml:"IPPrefixLen,omitempty"` + IPAddress string `json:"IPAddress,omitempty" yaml:"IPAddress,omitempty" toml:"IPAddress,omitempty"` + Gateway string `json:"Gateway,omitempty" yaml:"Gateway,omitempty" toml:"Gateway,omitempty"` + EndpointID string `json:"EndpointID,omitempty" yaml:"EndpointID,omitempty" toml:"EndpointID,omitempty"` + NetworkID string `json:"NetworkID,omitempty" yaml:"NetworkID,omitempty" toml:"NetworkID,omitempty"` +} + +// NetworkSettings contains network-related information about a container +type NetworkSettings struct { + Networks map[string]ContainerNetwork `json:"Networks,omitempty" yaml:"Networks,omitempty" toml:"Networks,omitempty"` + IPAddress string `json:"IPAddress,omitempty" yaml:"IPAddress,omitempty" toml:"IPAddress,omitempty"` + IPPrefixLen int `json:"IPPrefixLen,omitempty" yaml:"IPPrefixLen,omitempty" toml:"IPPrefixLen,omitempty"` + MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty" toml:"MacAddress,omitempty"` + Gateway string `json:"Gateway,omitempty" yaml:"Gateway,omitempty" toml:"Gateway,omitempty"` + Bridge string `json:"Bridge,omitempty" yaml:"Bridge,omitempty" toml:"Bridge,omitempty"` + PortMapping map[string]PortMapping `json:"PortMapping,omitempty" yaml:"PortMapping,omitempty" toml:"PortMapping,omitempty"` + Ports map[Port][]PortBinding `json:"Ports,omitempty" yaml:"Ports,omitempty" toml:"Ports,omitempty"` + NetworkID string `json:"NetworkID,omitempty" yaml:"NetworkID,omitempty" toml:"NetworkID,omitempty"` + EndpointID string `json:"EndpointID,omitempty" yaml:"EndpointID,omitempty" toml:"EndpointID,omitempty"` + SandboxKey string `json:"SandboxKey,omitempty" yaml:"SandboxKey,omitempty" toml:"SandboxKey,omitempty"` + GlobalIPv6Address string `json:"GlobalIPv6Address,omitempty" yaml:"GlobalIPv6Address,omitempty" toml:"GlobalIPv6Address,omitempty"` + GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen,omitempty" yaml:"GlobalIPv6PrefixLen,omitempty" toml:"GlobalIPv6PrefixLen,omitempty"` + IPv6Gateway string `json:"IPv6Gateway,omitempty" yaml:"IPv6Gateway,omitempty" toml:"IPv6Gateway,omitempty"` + LinkLocalIPv6Address string `json:"LinkLocalIPv6Address,omitempty" yaml:"LinkLocalIPv6Address,omitempty" toml:"LinkLocalIPv6Address,omitempty"` + LinkLocalIPv6PrefixLen int `json:"LinkLocalIPv6PrefixLen,omitempty" yaml:"LinkLocalIPv6PrefixLen,omitempty" toml:"LinkLocalIPv6PrefixLen,omitempty"` + SecondaryIPAddresses []string `json:"SecondaryIPAddresses,omitempty" yaml:"SecondaryIPAddresses,omitempty" toml:"SecondaryIPAddresses,omitempty"` + SecondaryIPv6Addresses []string `json:"SecondaryIPv6Addresses,omitempty" yaml:"SecondaryIPv6Addresses,omitempty" toml:"SecondaryIPv6Addresses,omitempty"` +} + +// PortMappingAPI translates the port mappings as contained in NetworkSettings +// into the format in which they would appear when returned by the API +func (settings *NetworkSettings) PortMappingAPI() []APIPort { + var mapping []APIPort + for port, bindings := range settings.Ports { + p, _ := parsePort(port.Port()) + if len(bindings) == 0 { + mapping = append(mapping, APIPort{ + PrivatePort: int64(p), + Type: port.Proto(), + }) + continue + } + for _, binding := range bindings { + p, _ := parsePort(port.Port()) + h, _ := parsePort(binding.HostPort) + mapping = append(mapping, APIPort{ + PrivatePort: int64(p), + PublicPort: int64(h), + Type: port.Proto(), + IP: binding.HostIP, + }) + } + } + return mapping +} + +func parsePort(rawPort string) (int, error) { + port, err := strconv.ParseUint(rawPort, 10, 16) + if err != nil { + return 0, err + } + return int(port), nil +} + +// Config is the list of configuration options used when creating a container. +// Config does not contain the options that are specific to starting a container on a +// given host. Those are contained in HostConfig +type Config struct { + Hostname string `json:"Hostname,omitempty" yaml:"Hostname,omitempty" toml:"Hostname,omitempty"` + Domainname string `json:"Domainname,omitempty" yaml:"Domainname,omitempty" toml:"Domainname,omitempty"` + User string `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"` + Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty" toml:"Memory,omitempty"` + MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty" toml:"MemorySwap,omitempty"` + MemoryReservation int64 `json:"MemoryReservation,omitempty" yaml:"MemoryReservation,omitempty" toml:"MemoryReservation,omitempty"` + KernelMemory int64 `json:"KernelMemory,omitempty" yaml:"KernelMemory,omitempty" toml:"KernelMemory,omitempty"` + CPUShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty" toml:"CpuShares,omitempty"` + CPUSet string `json:"Cpuset,omitempty" yaml:"Cpuset,omitempty" toml:"Cpuset,omitempty"` + PortSpecs []string `json:"PortSpecs,omitempty" yaml:"PortSpecs,omitempty" toml:"PortSpecs,omitempty"` + ExposedPorts map[Port]struct{} `json:"ExposedPorts,omitempty" yaml:"ExposedPorts,omitempty" toml:"ExposedPorts,omitempty"` + PublishService string `json:"PublishService,omitempty" yaml:"PublishService,omitempty" toml:"PublishService,omitempty"` + StopSignal string `json:"StopSignal,omitempty" yaml:"StopSignal,omitempty" toml:"StopSignal,omitempty"` + StopTimeout int `json:"StopTimeout,omitempty" yaml:"StopTimeout,omitempty" toml:"StopTimeout,omitempty"` + Env []string `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"` + Cmd []string `json:"Cmd" yaml:"Cmd" toml:"Cmd"` + Shell []string `json:"Shell,omitempty" yaml:"Shell,omitempty" toml:"Shell,omitempty"` + Healthcheck *HealthConfig `json:"Healthcheck,omitempty" yaml:"Healthcheck,omitempty" toml:"Healthcheck,omitempty"` + DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty" toml:"Dns,omitempty"` // For Docker API v1.9 and below only + Image string `json:"Image,omitempty" yaml:"Image,omitempty" toml:"Image,omitempty"` + Volumes map[string]struct{} `json:"Volumes,omitempty" yaml:"Volumes,omitempty" toml:"Volumes,omitempty"` + VolumeDriver string `json:"VolumeDriver,omitempty" yaml:"VolumeDriver,omitempty" toml:"VolumeDriver,omitempty"` + WorkingDir string `json:"WorkingDir,omitempty" yaml:"WorkingDir,omitempty" toml:"WorkingDir,omitempty"` + MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty" toml:"MacAddress,omitempty"` + Entrypoint []string `json:"Entrypoint" yaml:"Entrypoint" toml:"Entrypoint"` + SecurityOpts []string `json:"SecurityOpts,omitempty" yaml:"SecurityOpts,omitempty" toml:"SecurityOpts,omitempty"` + OnBuild []string `json:"OnBuild,omitempty" yaml:"OnBuild,omitempty" toml:"OnBuild,omitempty"` + Mounts []Mount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"` + Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"` + AttachStdin bool `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty" toml:"AttachStdin,omitempty"` + AttachStdout bool `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty" toml:"AttachStdout,omitempty"` + AttachStderr bool `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty" toml:"AttachStderr,omitempty"` + ArgsEscaped bool `json:"ArgsEscaped,omitempty" yaml:"ArgsEscaped,omitempty" toml:"ArgsEscaped,omitempty"` + Tty bool `json:"Tty,omitempty" yaml:"Tty,omitempty" toml:"Tty,omitempty"` + OpenStdin bool `json:"OpenStdin,omitempty" yaml:"OpenStdin,omitempty" toml:"OpenStdin,omitempty"` + StdinOnce bool `json:"StdinOnce,omitempty" yaml:"StdinOnce,omitempty" toml:"StdinOnce,omitempty"` + NetworkDisabled bool `json:"NetworkDisabled,omitempty" yaml:"NetworkDisabled,omitempty" toml:"NetworkDisabled,omitempty"` + + // This is no longer used and has been kept here for backward + // compatibility, please use HostConfig.VolumesFrom. + VolumesFrom string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty" toml:"VolumesFrom,omitempty"` +} + +// HostMount represents a mount point in the container in HostConfig. +// +// It has been added in the version 1.25 of the Docker API +type HostMount struct { + Target string `json:"Target,omitempty" yaml:"Target,omitempty" toml:"Target,omitempty"` + Source string `json:"Source,omitempty" yaml:"Source,omitempty" toml:"Source,omitempty"` + Type string `json:"Type,omitempty" yaml:"Type,omitempty" toml:"Type,omitempty"` + ReadOnly bool `json:"ReadOnly,omitempty" yaml:"ReadOnly,omitempty" toml:"ReadOnly,omitempty"` + BindOptions *BindOptions `json:"BindOptions,omitempty" yaml:"BindOptions,omitempty" toml:"BindOptions,omitempty"` + VolumeOptions *VolumeOptions `json:"VolumeOptions,omitempty" yaml:"VolumeOptions,omitempty" toml:"VolumeOptions,omitempty"` + TempfsOptions *TempfsOptions `json:"TempfsOptions,omitempty" yaml:"TempfsOptions,omitempty" toml:"TempfsOptions,omitempty"` +} + +// BindOptions contains optional configuration for the bind type +type BindOptions struct { + Propagation string `json:"Propagation,omitempty" yaml:"Propagation,omitempty" toml:"Propagation,omitempty"` +} + +// VolumeOptions contains optional configuration for the volume type +type VolumeOptions struct { + NoCopy bool `json:"NoCopy,omitempty" yaml:"NoCopy,omitempty" toml:"NoCopy,omitempty"` + Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"` + DriverConfig VolumeDriverConfig `json:"DriverConfig,omitempty" yaml:"DriverConfig,omitempty" toml:"DriverConfig,omitempty"` +} + +// TempfsOptions contains optional configuration for the tempfs type +type TempfsOptions struct { + SizeBytes int64 `json:"SizeBytes,omitempty" yaml:"SizeBytes,omitempty" toml:"SizeBytes,omitempty"` + Mode int `json:"Mode,omitempty" yaml:"Mode,omitempty" toml:"Mode,omitempty"` +} + +// VolumeDriverConfig holds a map of volume driver specific options +type VolumeDriverConfig struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Options map[string]string `json:"Options,omitempty" yaml:"Options,omitempty" toml:"Options,omitempty"` +} + +// Mount represents a mount point in the container. +// +// It has been added in the version 1.20 of the Docker API, available since +// Docker 1.8. +type Mount struct { + Name string + Source string + Destination string + Driver string + Mode string + RW bool +} + +// LogConfig defines the log driver type and the configuration for it. +type LogConfig struct { + Type string `json:"Type,omitempty" yaml:"Type,omitempty" toml:"Type,omitempty"` + Config map[string]string `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"` +} + +// ULimit defines system-wide resource limitations This can help a lot in +// system administration, e.g. when a user starts too many processes and +// therefore makes the system unresponsive for other users. +type ULimit struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Soft int64 `json:"Soft,omitempty" yaml:"Soft,omitempty" toml:"Soft,omitempty"` + Hard int64 `json:"Hard,omitempty" yaml:"Hard,omitempty" toml:"Hard,omitempty"` +} + +// SwarmNode containers information about which Swarm node the container is on. +type SwarmNode struct { + ID string `json:"ID,omitempty" yaml:"ID,omitempty" toml:"ID,omitempty"` + IP string `json:"IP,omitempty" yaml:"IP,omitempty" toml:"IP,omitempty"` + Addr string `json:"Addr,omitempty" yaml:"Addr,omitempty" toml:"Addr,omitempty"` + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + CPUs int64 `json:"CPUs,omitempty" yaml:"CPUs,omitempty" toml:"CPUs,omitempty"` + Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty" toml:"Memory,omitempty"` + Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"` +} + +// GraphDriver contains information about the GraphDriver used by the +// container. +type GraphDriver struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Data map[string]string `json:"Data,omitempty" yaml:"Data,omitempty" toml:"Data,omitempty"` +} + +// HealthConfig holds configuration settings for the HEALTHCHECK feature +// +// It has been added in the version 1.24 of the Docker API, available since +// Docker 1.12. +type HealthConfig struct { + // Test is the test to perform to check that the container is healthy. + // An empty slice means to inherit the default. + // The options are: + // {} : inherit healthcheck + // {"NONE"} : disable healthcheck + // {"CMD", args...} : exec arguments directly + // {"CMD-SHELL", command} : run command with system's default shell + Test []string `json:"Test,omitempty" yaml:"Test,omitempty" toml:"Test,omitempty"` + + // Zero means to inherit. Durations are expressed as integer nanoseconds. + Interval time.Duration `json:"Interval,omitempty" yaml:"Interval,omitempty" toml:"Interval,omitempty"` // Interval is the time to wait between checks. + Timeout time.Duration `json:"Timeout,omitempty" yaml:"Timeout,omitempty" toml:"Timeout,omitempty"` // Timeout is the time to wait before considering the check to have hung. + StartPeriod time.Duration `json:"StartPeriod,omitempty" yaml:"StartPeriod,omitempty" toml:"StartPeriod,omitempty"` // The start period for the container to initialize before the retries starts to count down. + + // Retries is the number of consecutive failures needed to consider a container as unhealthy. + // Zero means inherit. + Retries int `json:"Retries,omitempty" yaml:"Retries,omitempty" toml:"Retries,omitempty"` +} + +// Container is the type encompasing everything about a container - its config, +// hostconfig, etc. +type Container struct { + ID string `json:"Id" yaml:"Id" toml:"Id"` + + Created time.Time `json:"Created,omitempty" yaml:"Created,omitempty" toml:"Created,omitempty"` + + Path string `json:"Path,omitempty" yaml:"Path,omitempty" toml:"Path,omitempty"` + Args []string `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"` + + Config *Config `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"` + State State `json:"State,omitempty" yaml:"State,omitempty" toml:"State,omitempty"` + Image string `json:"Image,omitempty" yaml:"Image,omitempty" toml:"Image,omitempty"` + + Node *SwarmNode `json:"Node,omitempty" yaml:"Node,omitempty" toml:"Node,omitempty"` + + NetworkSettings *NetworkSettings `json:"NetworkSettings,omitempty" yaml:"NetworkSettings,omitempty" toml:"NetworkSettings,omitempty"` + + SysInitPath string `json:"SysInitPath,omitempty" yaml:"SysInitPath,omitempty" toml:"SysInitPath,omitempty"` + ResolvConfPath string `json:"ResolvConfPath,omitempty" yaml:"ResolvConfPath,omitempty" toml:"ResolvConfPath,omitempty"` + HostnamePath string `json:"HostnamePath,omitempty" yaml:"HostnamePath,omitempty" toml:"HostnamePath,omitempty"` + HostsPath string `json:"HostsPath,omitempty" yaml:"HostsPath,omitempty" toml:"HostsPath,omitempty"` + LogPath string `json:"LogPath,omitempty" yaml:"LogPath,omitempty" toml:"LogPath,omitempty"` + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Driver string `json:"Driver,omitempty" yaml:"Driver,omitempty" toml:"Driver,omitempty"` + Mounts []Mount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"` + + Volumes map[string]string `json:"Volumes,omitempty" yaml:"Volumes,omitempty" toml:"Volumes,omitempty"` + VolumesRW map[string]bool `json:"VolumesRW,omitempty" yaml:"VolumesRW,omitempty" toml:"VolumesRW,omitempty"` + HostConfig *HostConfig `json:"HostConfig,omitempty" yaml:"HostConfig,omitempty" toml:"HostConfig,omitempty"` + ExecIDs []string `json:"ExecIDs,omitempty" yaml:"ExecIDs,omitempty" toml:"ExecIDs,omitempty"` + GraphDriver *GraphDriver `json:"GraphDriver,omitempty" yaml:"GraphDriver,omitempty" toml:"GraphDriver,omitempty"` + + RestartCount int `json:"RestartCount,omitempty" yaml:"RestartCount,omitempty" toml:"RestartCount,omitempty"` + + AppArmorProfile string `json:"AppArmorProfile,omitempty" yaml:"AppArmorProfile,omitempty" toml:"AppArmorProfile,omitempty"` +} + +// UpdateContainerOptions specify parameters to the UpdateContainer function. +// +// See https://goo.gl/Y6fXUy for more details. +type UpdateContainerOptions struct { + BlkioWeight int `json:"BlkioWeight"` + CPUShares int `json:"CpuShares"` + CPUPeriod int `json:"CpuPeriod"` + CPURealtimePeriod int64 `json:"CpuRealtimePeriod"` + CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime"` + CPUQuota int `json:"CpuQuota"` + CpusetCpus string `json:"CpusetCpus"` + CpusetMems string `json:"CpusetMems"` + Memory int `json:"Memory"` + MemorySwap int `json:"MemorySwap"` + MemoryReservation int `json:"MemoryReservation"` + KernelMemory int `json:"KernelMemory"` + RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty"` + Context context.Context +} + +// UpdateContainer updates the container at ID with the options +// +// See https://goo.gl/Y6fXUy for more details. +func (c *Client) UpdateContainer(id string, opts UpdateContainerOptions) error { + resp, err := c.do("POST", fmt.Sprintf("/containers/"+id+"/update"), doOptions{ + data: opts, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + return err + } + defer resp.Body.Close() + return nil +} + +// RenameContainerOptions specify parameters to the RenameContainer function. +// +// See https://goo.gl/46inai for more details. +type RenameContainerOptions struct { + // ID of container to rename + ID string `qs:"-"` + + // New name + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Context context.Context +} + +// RenameContainer updates and existing containers name +// +// See https://goo.gl/46inai for more details. +func (c *Client) RenameContainer(opts RenameContainerOptions) error { + resp, err := c.do("POST", fmt.Sprintf("/containers/"+opts.ID+"/rename?%s", queryString(opts)), doOptions{ + context: opts.Context, + }) + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// InspectContainer returns information about a container by its ID. +// +// See https://goo.gl/FaI5JT for more details. +func (c *Client) InspectContainer(id string) (*Container, error) { + return c.inspectContainer(id, doOptions{}) +} + +// InspectContainerWithContext returns information about a container by its ID. +// The context object can be used to cancel the inspect request. +// +// See https://goo.gl/FaI5JT for more details. +func (c *Client) InspectContainerWithContext(id string, ctx context.Context) (*Container, error) { + return c.inspectContainer(id, doOptions{context: ctx}) +} + +func (c *Client) inspectContainer(id string, opts doOptions) (*Container, error) { + path := "/containers/" + id + "/json" + resp, err := c.do("GET", path, opts) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchContainer{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var container Container + if err := json.NewDecoder(resp.Body).Decode(&container); err != nil { + return nil, err + } + return &container, nil +} + +// ContainerChanges returns changes in the filesystem of the given container. +// +// See https://goo.gl/15KKzh for more details. +func (c *Client) ContainerChanges(id string) ([]Change, error) { + path := "/containers/" + id + "/changes" + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchContainer{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var changes []Change + if err := json.NewDecoder(resp.Body).Decode(&changes); err != nil { + return nil, err + } + return changes, nil +} + +// CreateContainerOptions specify parameters to the CreateContainer function. +// +// See https://goo.gl/tyzwVM for more details. +type CreateContainerOptions struct { + Name string + Config *Config `qs:"-"` + HostConfig *HostConfig `qs:"-"` + NetworkingConfig *NetworkingConfig `qs:"-"` + Context context.Context +} + +// CreateContainer creates a new container, returning the container instance, +// or an error in case of failure. +// +// The returned container instance contains only the container ID. To get more +// details about the container after creating it, use InspectContainer. +// +// See https://goo.gl/tyzwVM for more details. +func (c *Client) CreateContainer(opts CreateContainerOptions) (*Container, error) { + path := "/containers/create?" + queryString(opts) + resp, err := c.do( + "POST", + path, + doOptions{ + data: struct { + *Config + HostConfig *HostConfig `json:"HostConfig,omitempty" yaml:"HostConfig,omitempty" toml:"HostConfig,omitempty"` + NetworkingConfig *NetworkingConfig `json:"NetworkingConfig,omitempty" yaml:"NetworkingConfig,omitempty" toml:"NetworkingConfig,omitempty"` + }{ + opts.Config, + opts.HostConfig, + opts.NetworkingConfig, + }, + context: opts.Context, + }, + ) + + if e, ok := err.(*Error); ok { + if e.Status == http.StatusNotFound { + return nil, ErrNoSuchImage + } + if e.Status == http.StatusConflict { + return nil, ErrContainerAlreadyExists + } + // Workaround for 17.09 bug returning 400 instead of 409. + // See https://github.com/moby/moby/issues/35021 + if e.Status == http.StatusBadRequest && strings.Contains(e.Message, "Conflict.") { + return nil, ErrContainerAlreadyExists + } + } + + if err != nil { + return nil, err + } + defer resp.Body.Close() + var container Container + if err := json.NewDecoder(resp.Body).Decode(&container); err != nil { + return nil, err + } + + container.Name = opts.Name + + return &container, nil +} + +// KeyValuePair is a type for generic key/value pairs as used in the Lxc +// configuration +type KeyValuePair struct { + Key string `json:"Key,omitempty" yaml:"Key,omitempty" toml:"Key,omitempty"` + Value string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"` +} + +// RestartPolicy represents the policy for automatically restarting a container. +// +// Possible values are: +// +// - always: the docker daemon will always restart the container +// - on-failure: the docker daemon will restart the container on failures, at +// most MaximumRetryCount times +// - unless-stopped: the docker daemon will always restart the container except +// when user has manually stopped the container +// - no: the docker daemon will not restart the container automatically +type RestartPolicy struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + MaximumRetryCount int `json:"MaximumRetryCount,omitempty" yaml:"MaximumRetryCount,omitempty" toml:"MaximumRetryCount,omitempty"` +} + +// AlwaysRestart returns a restart policy that tells the Docker daemon to +// always restart the container. +func AlwaysRestart() RestartPolicy { + return RestartPolicy{Name: "always"} +} + +// RestartOnFailure returns a restart policy that tells the Docker daemon to +// restart the container on failures, trying at most maxRetry times. +func RestartOnFailure(maxRetry int) RestartPolicy { + return RestartPolicy{Name: "on-failure", MaximumRetryCount: maxRetry} +} + +// RestartUnlessStopped returns a restart policy that tells the Docker daemon to +// always restart the container except when user has manually stopped the container. +func RestartUnlessStopped() RestartPolicy { + return RestartPolicy{Name: "unless-stopped"} +} + +// NeverRestart returns a restart policy that tells the Docker daemon to never +// restart the container on failures. +func NeverRestart() RestartPolicy { + return RestartPolicy{Name: "no"} +} + +// Device represents a device mapping between the Docker host and the +// container. +type Device struct { + PathOnHost string `json:"PathOnHost,omitempty" yaml:"PathOnHost,omitempty" toml:"PathOnHost,omitempty"` + PathInContainer string `json:"PathInContainer,omitempty" yaml:"PathInContainer,omitempty" toml:"PathInContainer,omitempty"` + CgroupPermissions string `json:"CgroupPermissions,omitempty" yaml:"CgroupPermissions,omitempty" toml:"CgroupPermissions,omitempty"` +} + +// BlockWeight represents a relative device weight for an individual device inside +// of a container +type BlockWeight struct { + Path string `json:"Path,omitempty"` + Weight string `json:"Weight,omitempty"` +} + +// BlockLimit represents a read/write limit in IOPS or Bandwidth for a device +// inside of a container +type BlockLimit struct { + Path string `json:"Path,omitempty"` + Rate int64 `json:"Rate,omitempty"` +} + +// HostConfig contains the container options related to starting a container on +// a given host +type HostConfig struct { + Binds []string `json:"Binds,omitempty" yaml:"Binds,omitempty" toml:"Binds,omitempty"` + CapAdd []string `json:"CapAdd,omitempty" yaml:"CapAdd,omitempty" toml:"CapAdd,omitempty"` + CapDrop []string `json:"CapDrop,omitempty" yaml:"CapDrop,omitempty" toml:"CapDrop,omitempty"` + GroupAdd []string `json:"GroupAdd,omitempty" yaml:"GroupAdd,omitempty" toml:"GroupAdd,omitempty"` + ContainerIDFile string `json:"ContainerIDFile,omitempty" yaml:"ContainerIDFile,omitempty" toml:"ContainerIDFile,omitempty"` + LxcConf []KeyValuePair `json:"LxcConf,omitempty" yaml:"LxcConf,omitempty" toml:"LxcConf,omitempty"` + PortBindings map[Port][]PortBinding `json:"PortBindings,omitempty" yaml:"PortBindings,omitempty" toml:"PortBindings,omitempty"` + Links []string `json:"Links,omitempty" yaml:"Links,omitempty" toml:"Links,omitempty"` + DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty" toml:"Dns,omitempty"` // For Docker API v1.10 and above only + DNSOptions []string `json:"DnsOptions,omitempty" yaml:"DnsOptions,omitempty" toml:"DnsOptions,omitempty"` + DNSSearch []string `json:"DnsSearch,omitempty" yaml:"DnsSearch,omitempty" toml:"DnsSearch,omitempty"` + ExtraHosts []string `json:"ExtraHosts,omitempty" yaml:"ExtraHosts,omitempty" toml:"ExtraHosts,omitempty"` + VolumesFrom []string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty" toml:"VolumesFrom,omitempty"` + UsernsMode string `json:"UsernsMode,omitempty" yaml:"UsernsMode,omitempty" toml:"UsernsMode,omitempty"` + NetworkMode string `json:"NetworkMode,omitempty" yaml:"NetworkMode,omitempty" toml:"NetworkMode,omitempty"` + IpcMode string `json:"IpcMode,omitempty" yaml:"IpcMode,omitempty" toml:"IpcMode,omitempty"` + PidMode string `json:"PidMode,omitempty" yaml:"PidMode,omitempty" toml:"PidMode,omitempty"` + UTSMode string `json:"UTSMode,omitempty" yaml:"UTSMode,omitempty" toml:"UTSMode,omitempty"` + RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty" yaml:"RestartPolicy,omitempty" toml:"RestartPolicy,omitempty"` + Devices []Device `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"` + DeviceCgroupRules []string `json:"DeviceCgroupRules,omitempty" yaml:"DeviceCgroupRules,omitempty" toml:"DeviceCgroupRules,omitempty"` + LogConfig LogConfig `json:"LogConfig,omitempty" yaml:"LogConfig,omitempty" toml:"LogConfig,omitempty"` + SecurityOpt []string `json:"SecurityOpt,omitempty" yaml:"SecurityOpt,omitempty" toml:"SecurityOpt,omitempty"` + Cgroup string `json:"Cgroup,omitempty" yaml:"Cgroup,omitempty" toml:"Cgroup,omitempty"` + CgroupParent string `json:"CgroupParent,omitempty" yaml:"CgroupParent,omitempty" toml:"CgroupParent,omitempty"` + Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty" toml:"Memory,omitempty"` + MemoryReservation int64 `json:"MemoryReservation,omitempty" yaml:"MemoryReservation,omitempty" toml:"MemoryReservation,omitempty"` + KernelMemory int64 `json:"KernelMemory,omitempty" yaml:"KernelMemory,omitempty" toml:"KernelMemory,omitempty"` + MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty" toml:"MemorySwap,omitempty"` + MemorySwappiness int64 `json:"MemorySwappiness,omitempty" yaml:"MemorySwappiness,omitempty" toml:"MemorySwappiness,omitempty"` + CPUShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty" toml:"CpuShares,omitempty"` + CPUSet string `json:"Cpuset,omitempty" yaml:"Cpuset,omitempty" toml:"Cpuset,omitempty"` + CPUSetCPUs string `json:"CpusetCpus,omitempty" yaml:"CpusetCpus,omitempty" toml:"CpusetCpus,omitempty"` + CPUSetMEMs string `json:"CpusetMems,omitempty" yaml:"CpusetMems,omitempty" toml:"CpusetMems,omitempty"` + CPUQuota int64 `json:"CpuQuota,omitempty" yaml:"CpuQuota,omitempty" toml:"CpuQuota,omitempty"` + CPUPeriod int64 `json:"CpuPeriod,omitempty" yaml:"CpuPeriod,omitempty" toml:"CpuPeriod,omitempty"` + CPURealtimePeriod int64 `json:"CpuRealtimePeriod,omitempty" yaml:"CpuRealtimePeriod,omitempty" toml:"CpuRealtimePeriod,omitempty"` + CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime,omitempty" yaml:"CpuRealtimeRuntime,omitempty" toml:"CpuRealtimeRuntime,omitempty"` + BlkioWeight int64 `json:"BlkioWeight,omitempty" yaml:"BlkioWeight,omitempty" toml:"BlkioWeight,omitempty"` + BlkioWeightDevice []BlockWeight `json:"BlkioWeightDevice,omitempty" yaml:"BlkioWeightDevice,omitempty" toml:"BlkioWeightDevice,omitempty"` + BlkioDeviceReadBps []BlockLimit `json:"BlkioDeviceReadBps,omitempty" yaml:"BlkioDeviceReadBps,omitempty" toml:"BlkioDeviceReadBps,omitempty"` + BlkioDeviceReadIOps []BlockLimit `json:"BlkioDeviceReadIOps,omitempty" yaml:"BlkioDeviceReadIOps,omitempty" toml:"BlkioDeviceReadIOps,omitempty"` + BlkioDeviceWriteBps []BlockLimit `json:"BlkioDeviceWriteBps,omitempty" yaml:"BlkioDeviceWriteBps,omitempty" toml:"BlkioDeviceWriteBps,omitempty"` + BlkioDeviceWriteIOps []BlockLimit `json:"BlkioDeviceWriteIOps,omitempty" yaml:"BlkioDeviceWriteIOps,omitempty" toml:"BlkioDeviceWriteIOps,omitempty"` + Ulimits []ULimit `json:"Ulimits,omitempty" yaml:"Ulimits,omitempty" toml:"Ulimits,omitempty"` + VolumeDriver string `json:"VolumeDriver,omitempty" yaml:"VolumeDriver,omitempty" toml:"VolumeDriver,omitempty"` + OomScoreAdj int `json:"OomScoreAdj,omitempty" yaml:"OomScoreAdj,omitempty" toml:"OomScoreAdj,omitempty"` + PidsLimit int64 `json:"PidsLimit,omitempty" yaml:"PidsLimit,omitempty" toml:"PidsLimit,omitempty"` + ShmSize int64 `json:"ShmSize,omitempty" yaml:"ShmSize,omitempty" toml:"ShmSize,omitempty"` + Tmpfs map[string]string `json:"Tmpfs,omitempty" yaml:"Tmpfs,omitempty" toml:"Tmpfs,omitempty"` + Privileged bool `json:"Privileged,omitempty" yaml:"Privileged,omitempty" toml:"Privileged,omitempty"` + PublishAllPorts bool `json:"PublishAllPorts,omitempty" yaml:"PublishAllPorts,omitempty" toml:"PublishAllPorts,omitempty"` + ReadonlyRootfs bool `json:"ReadonlyRootfs,omitempty" yaml:"ReadonlyRootfs,omitempty" toml:"ReadonlyRootfs,omitempty"` + OOMKillDisable bool `json:"OomKillDisable,omitempty" yaml:"OomKillDisable,omitempty" toml:"OomKillDisable,omitempty"` + AutoRemove bool `json:"AutoRemove,omitempty" yaml:"AutoRemove,omitempty" toml:"AutoRemove,omitempty"` + StorageOpt map[string]string `json:"StorageOpt,omitempty" yaml:"StorageOpt,omitempty" toml:"StorageOpt,omitempty"` + Sysctls map[string]string `json:"Sysctls,omitempty" yaml:"Sysctls,omitempty" toml:"Sysctls,omitempty"` + CPUCount int64 `json:"CpuCount,omitempty" yaml:"CpuCount,omitempty"` + CPUPercent int64 `json:"CpuPercent,omitempty" yaml:"CpuPercent,omitempty"` + IOMaximumBandwidth int64 `json:"IOMaximumBandwidth,omitempty" yaml:"IOMaximumBandwidth,omitempty"` + IOMaximumIOps int64 `json:"IOMaximumIOps,omitempty" yaml:"IOMaximumIOps,omitempty"` + Mounts []HostMount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"` + Init bool `json:",omitempty" yaml:",omitempty"` +} + +// NetworkingConfig represents the container's networking configuration for each of its interfaces +// Carries the networking configs specified in the `docker run` and `docker network connect` commands +type NetworkingConfig struct { + EndpointsConfig map[string]*EndpointConfig `json:"EndpointsConfig" yaml:"EndpointsConfig" toml:"EndpointsConfig"` // Endpoint configs for each connecting network +} + +// StartContainer starts a container, returning an error in case of failure. +// +// Passing the HostConfig to this method has been deprecated in Docker API 1.22 +// (Docker Engine 1.10.x) and totally removed in Docker API 1.24 (Docker Engine +// 1.12.x). The client will ignore the parameter when communicating with Docker +// API 1.24 or greater. +// +// See https://goo.gl/fbOSZy for more details. +func (c *Client) StartContainer(id string, hostConfig *HostConfig) error { + return c.startContainer(id, hostConfig, doOptions{}) +} + +// StartContainerWithContext starts a container, returning an error in case of +// failure. The context can be used to cancel the outstanding start container +// request. +// +// Passing the HostConfig to this method has been deprecated in Docker API 1.22 +// (Docker Engine 1.10.x) and totally removed in Docker API 1.24 (Docker Engine +// 1.12.x). The client will ignore the parameter when communicating with Docker +// API 1.24 or greater. +// +// See https://goo.gl/fbOSZy for more details. +func (c *Client) StartContainerWithContext(id string, hostConfig *HostConfig, ctx context.Context) error { + return c.startContainer(id, hostConfig, doOptions{context: ctx}) +} + +func (c *Client) startContainer(id string, hostConfig *HostConfig, opts doOptions) error { + path := "/containers/" + id + "/start" + if c.serverAPIVersion == nil { + c.checkAPIVersion() + } + if c.serverAPIVersion != nil && c.serverAPIVersion.LessThan(apiVersion124) { + opts.data = hostConfig + opts.forceJSON = true + } + resp, err := c.do("POST", path, opts) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchContainer{ID: id, Err: err} + } + return err + } + defer resp.Body.Close() + if resp.StatusCode == http.StatusNotModified { + return &ContainerAlreadyRunning{ID: id} + } + return nil +} + +// StopContainer stops a container, killing it after the given timeout (in +// seconds). +// +// See https://goo.gl/R9dZcV for more details. +func (c *Client) StopContainer(id string, timeout uint) error { + return c.stopContainer(id, timeout, doOptions{}) +} + +// StopContainerWithContext stops a container, killing it after the given +// timeout (in seconds). The context can be used to cancel the stop +// container request. +// +// See https://goo.gl/R9dZcV for more details. +func (c *Client) StopContainerWithContext(id string, timeout uint, ctx context.Context) error { + return c.stopContainer(id, timeout, doOptions{context: ctx}) +} + +func (c *Client) stopContainer(id string, timeout uint, opts doOptions) error { + path := fmt.Sprintf("/containers/%s/stop?t=%d", id, timeout) + resp, err := c.do("POST", path, opts) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchContainer{ID: id} + } + return err + } + defer resp.Body.Close() + if resp.StatusCode == http.StatusNotModified { + return &ContainerNotRunning{ID: id} + } + return nil +} + +// RestartContainer stops a container, killing it after the given timeout (in +// seconds), during the stop process. +// +// See https://goo.gl/MrAKQ5 for more details. +func (c *Client) RestartContainer(id string, timeout uint) error { + path := fmt.Sprintf("/containers/%s/restart?t=%d", id, timeout) + resp, err := c.do("POST", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchContainer{ID: id} + } + return err + } + resp.Body.Close() + return nil +} + +// PauseContainer pauses the given container. +// +// See https://goo.gl/D1Yaii for more details. +func (c *Client) PauseContainer(id string) error { + path := fmt.Sprintf("/containers/%s/pause", id) + resp, err := c.do("POST", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchContainer{ID: id} + } + return err + } + resp.Body.Close() + return nil +} + +// UnpauseContainer unpauses the given container. +// +// See https://goo.gl/sZ2faO for more details. +func (c *Client) UnpauseContainer(id string) error { + path := fmt.Sprintf("/containers/%s/unpause", id) + resp, err := c.do("POST", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchContainer{ID: id} + } + return err + } + resp.Body.Close() + return nil +} + +// TopResult represents the list of processes running in a container, as +// returned by /containers//top. +// +// See https://goo.gl/FLwpPl for more details. +type TopResult struct { + Titles []string + Processes [][]string +} + +// TopContainer returns processes running inside a container +// +// See https://goo.gl/FLwpPl for more details. +func (c *Client) TopContainer(id string, psArgs string) (TopResult, error) { + var args string + var result TopResult + if psArgs != "" { + args = fmt.Sprintf("?ps_args=%s", psArgs) + } + path := fmt.Sprintf("/containers/%s/top%s", id, args) + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return result, &NoSuchContainer{ID: id} + } + return result, err + } + defer resp.Body.Close() + err = json.NewDecoder(resp.Body).Decode(&result) + return result, err +} + +// Stats represents container statistics, returned by /containers//stats. +// +// See https://goo.gl/Dk3Xio for more details. +type Stats struct { + Read time.Time `json:"read,omitempty" yaml:"read,omitempty" toml:"read,omitempty"` + PreRead time.Time `json:"preread,omitempty" yaml:"preread,omitempty" toml:"preread,omitempty"` + NumProcs uint32 `json:"num_procs" yaml:"num_procs" toml:"num_procs"` + PidsStats struct { + Current uint64 `json:"current,omitempty" yaml:"current,omitempty"` + } `json:"pids_stats,omitempty" yaml:"pids_stats,omitempty" toml:"pids_stats,omitempty"` + Network NetworkStats `json:"network,omitempty" yaml:"network,omitempty" toml:"network,omitempty"` + Networks map[string]NetworkStats `json:"networks,omitempty" yaml:"networks,omitempty" toml:"networks,omitempty"` + MemoryStats struct { + Stats struct { + TotalPgmafault uint64 `json:"total_pgmafault,omitempty" yaml:"total_pgmafault,omitempty" toml:"total_pgmafault,omitempty"` + Cache uint64 `json:"cache,omitempty" yaml:"cache,omitempty" toml:"cache,omitempty"` + MappedFile uint64 `json:"mapped_file,omitempty" yaml:"mapped_file,omitempty" toml:"mapped_file,omitempty"` + TotalInactiveFile uint64 `json:"total_inactive_file,omitempty" yaml:"total_inactive_file,omitempty" toml:"total_inactive_file,omitempty"` + Pgpgout uint64 `json:"pgpgout,omitempty" yaml:"pgpgout,omitempty" toml:"pgpgout,omitempty"` + Rss uint64 `json:"rss,omitempty" yaml:"rss,omitempty" toml:"rss,omitempty"` + TotalMappedFile uint64 `json:"total_mapped_file,omitempty" yaml:"total_mapped_file,omitempty" toml:"total_mapped_file,omitempty"` + Writeback uint64 `json:"writeback,omitempty" yaml:"writeback,omitempty" toml:"writeback,omitempty"` + Unevictable uint64 `json:"unevictable,omitempty" yaml:"unevictable,omitempty" toml:"unevictable,omitempty"` + Pgpgin uint64 `json:"pgpgin,omitempty" yaml:"pgpgin,omitempty" toml:"pgpgin,omitempty"` + TotalUnevictable uint64 `json:"total_unevictable,omitempty" yaml:"total_unevictable,omitempty" toml:"total_unevictable,omitempty"` + Pgmajfault uint64 `json:"pgmajfault,omitempty" yaml:"pgmajfault,omitempty" toml:"pgmajfault,omitempty"` + TotalRss uint64 `json:"total_rss,omitempty" yaml:"total_rss,omitempty" toml:"total_rss,omitempty"` + TotalRssHuge uint64 `json:"total_rss_huge,omitempty" yaml:"total_rss_huge,omitempty" toml:"total_rss_huge,omitempty"` + TotalWriteback uint64 `json:"total_writeback,omitempty" yaml:"total_writeback,omitempty" toml:"total_writeback,omitempty"` + TotalInactiveAnon uint64 `json:"total_inactive_anon,omitempty" yaml:"total_inactive_anon,omitempty" toml:"total_inactive_anon,omitempty"` + RssHuge uint64 `json:"rss_huge,omitempty" yaml:"rss_huge,omitempty" toml:"rss_huge,omitempty"` + HierarchicalMemoryLimit uint64 `json:"hierarchical_memory_limit,omitempty" yaml:"hierarchical_memory_limit,omitempty" toml:"hierarchical_memory_limit,omitempty"` + TotalPgfault uint64 `json:"total_pgfault,omitempty" yaml:"total_pgfault,omitempty" toml:"total_pgfault,omitempty"` + TotalActiveFile uint64 `json:"total_active_file,omitempty" yaml:"total_active_file,omitempty" toml:"total_active_file,omitempty"` + ActiveAnon uint64 `json:"active_anon,omitempty" yaml:"active_anon,omitempty" toml:"active_anon,omitempty"` + TotalActiveAnon uint64 `json:"total_active_anon,omitempty" yaml:"total_active_anon,omitempty" toml:"total_active_anon,omitempty"` + TotalPgpgout uint64 `json:"total_pgpgout,omitempty" yaml:"total_pgpgout,omitempty" toml:"total_pgpgout,omitempty"` + TotalCache uint64 `json:"total_cache,omitempty" yaml:"total_cache,omitempty" toml:"total_cache,omitempty"` + InactiveAnon uint64 `json:"inactive_anon,omitempty" yaml:"inactive_anon,omitempty" toml:"inactive_anon,omitempty"` + ActiveFile uint64 `json:"active_file,omitempty" yaml:"active_file,omitempty" toml:"active_file,omitempty"` + Pgfault uint64 `json:"pgfault,omitempty" yaml:"pgfault,omitempty" toml:"pgfault,omitempty"` + InactiveFile uint64 `json:"inactive_file,omitempty" yaml:"inactive_file,omitempty" toml:"inactive_file,omitempty"` + TotalPgpgin uint64 `json:"total_pgpgin,omitempty" yaml:"total_pgpgin,omitempty" toml:"total_pgpgin,omitempty"` + HierarchicalMemswLimit uint64 `json:"hierarchical_memsw_limit,omitempty" yaml:"hierarchical_memsw_limit,omitempty" toml:"hierarchical_memsw_limit,omitempty"` + Swap uint64 `json:"swap,omitempty" yaml:"swap,omitempty" toml:"swap,omitempty"` + } `json:"stats,omitempty" yaml:"stats,omitempty" toml:"stats,omitempty"` + MaxUsage uint64 `json:"max_usage,omitempty" yaml:"max_usage,omitempty" toml:"max_usage,omitempty"` + Usage uint64 `json:"usage,omitempty" yaml:"usage,omitempty" toml:"usage,omitempty"` + Failcnt uint64 `json:"failcnt,omitempty" yaml:"failcnt,omitempty" toml:"failcnt,omitempty"` + Limit uint64 `json:"limit,omitempty" yaml:"limit,omitempty" toml:"limit,omitempty"` + Commit uint64 `json:"commitbytes,omitempty" yaml:"commitbytes,omitempty" toml:"privateworkingset,omitempty"` + CommitPeak uint64 `json:"commitpeakbytes,omitempty" yaml:"commitpeakbytes,omitempty" toml:"commitpeakbytes,omitempty"` + PrivateWorkingSet uint64 `json:"privateworkingset,omitempty" yaml:"privateworkingset,omitempty" toml:"privateworkingset,omitempty"` + } `json:"memory_stats,omitempty" yaml:"memory_stats,omitempty" toml:"memory_stats,omitempty"` + BlkioStats struct { + IOServiceBytesRecursive []BlkioStatsEntry `json:"io_service_bytes_recursive,omitempty" yaml:"io_service_bytes_recursive,omitempty" toml:"io_service_bytes_recursive,omitempty"` + IOServicedRecursive []BlkioStatsEntry `json:"io_serviced_recursive,omitempty" yaml:"io_serviced_recursive,omitempty" toml:"io_serviced_recursive,omitempty"` + IOQueueRecursive []BlkioStatsEntry `json:"io_queue_recursive,omitempty" yaml:"io_queue_recursive,omitempty" toml:"io_queue_recursive,omitempty"` + IOServiceTimeRecursive []BlkioStatsEntry `json:"io_service_time_recursive,omitempty" yaml:"io_service_time_recursive,omitempty" toml:"io_service_time_recursive,omitempty"` + IOWaitTimeRecursive []BlkioStatsEntry `json:"io_wait_time_recursive,omitempty" yaml:"io_wait_time_recursive,omitempty" toml:"io_wait_time_recursive,omitempty"` + IOMergedRecursive []BlkioStatsEntry `json:"io_merged_recursive,omitempty" yaml:"io_merged_recursive,omitempty" toml:"io_merged_recursive,omitempty"` + IOTimeRecursive []BlkioStatsEntry `json:"io_time_recursive,omitempty" yaml:"io_time_recursive,omitempty" toml:"io_time_recursive,omitempty"` + SectorsRecursive []BlkioStatsEntry `json:"sectors_recursive,omitempty" yaml:"sectors_recursive,omitempty" toml:"sectors_recursive,omitempty"` + } `json:"blkio_stats,omitempty" yaml:"blkio_stats,omitempty" toml:"blkio_stats,omitempty"` + CPUStats CPUStats `json:"cpu_stats,omitempty" yaml:"cpu_stats,omitempty" toml:"cpu_stats,omitempty"` + PreCPUStats CPUStats `json:"precpu_stats,omitempty"` + StorageStats struct { + ReadCountNormalized uint64 `json:"read_count_normalized,omitempty" yaml:"read_count_normalized,omitempty" toml:"read_count_normalized,omitempty"` + ReadSizeBytes uint64 `json:"read_size_bytes,omitempty" yaml:"read_size_bytes,omitempty" toml:"read_size_bytes,omitempty"` + WriteCountNormalized uint64 `json:"write_count_normalized,omitempty" yaml:"write_count_normalized,omitempty" toml:"write_count_normalized,omitempty"` + WriteSizeBytes uint64 `json:"write_size_bytes,omitempty" yaml:"write_size_bytes,omitempty" toml:"write_size_bytes,omitempty"` + } `json:"storage_stats,omitempty" yaml:"storage_stats,omitempty" toml:"storage_stats,omitempty"` +} + +// NetworkStats is a stats entry for network stats +type NetworkStats struct { + RxDropped uint64 `json:"rx_dropped,omitempty" yaml:"rx_dropped,omitempty" toml:"rx_dropped,omitempty"` + RxBytes uint64 `json:"rx_bytes,omitempty" yaml:"rx_bytes,omitempty" toml:"rx_bytes,omitempty"` + RxErrors uint64 `json:"rx_errors,omitempty" yaml:"rx_errors,omitempty" toml:"rx_errors,omitempty"` + TxPackets uint64 `json:"tx_packets,omitempty" yaml:"tx_packets,omitempty" toml:"tx_packets,omitempty"` + TxDropped uint64 `json:"tx_dropped,omitempty" yaml:"tx_dropped,omitempty" toml:"tx_dropped,omitempty"` + RxPackets uint64 `json:"rx_packets,omitempty" yaml:"rx_packets,omitempty" toml:"rx_packets,omitempty"` + TxErrors uint64 `json:"tx_errors,omitempty" yaml:"tx_errors,omitempty" toml:"tx_errors,omitempty"` + TxBytes uint64 `json:"tx_bytes,omitempty" yaml:"tx_bytes,omitempty" toml:"tx_bytes,omitempty"` +} + +// CPUStats is a stats entry for cpu stats +type CPUStats struct { + CPUUsage struct { + PercpuUsage []uint64 `json:"percpu_usage,omitempty" yaml:"percpu_usage,omitempty" toml:"percpu_usage,omitempty"` + UsageInUsermode uint64 `json:"usage_in_usermode,omitempty" yaml:"usage_in_usermode,omitempty" toml:"usage_in_usermode,omitempty"` + TotalUsage uint64 `json:"total_usage,omitempty" yaml:"total_usage,omitempty" toml:"total_usage,omitempty"` + UsageInKernelmode uint64 `json:"usage_in_kernelmode,omitempty" yaml:"usage_in_kernelmode,omitempty" toml:"usage_in_kernelmode,omitempty"` + } `json:"cpu_usage,omitempty" yaml:"cpu_usage,omitempty" toml:"cpu_usage,omitempty"` + SystemCPUUsage uint64 `json:"system_cpu_usage,omitempty" yaml:"system_cpu_usage,omitempty" toml:"system_cpu_usage,omitempty"` + OnlineCPUs uint64 `json:"online_cpus,omitempty" yaml:"online_cpus,omitempty" toml:"online_cpus,omitempty"` + ThrottlingData struct { + Periods uint64 `json:"periods,omitempty"` + ThrottledPeriods uint64 `json:"throttled_periods,omitempty"` + ThrottledTime uint64 `json:"throttled_time,omitempty"` + } `json:"throttling_data,omitempty" yaml:"throttling_data,omitempty" toml:"throttling_data,omitempty"` +} + +// BlkioStatsEntry is a stats entry for blkio_stats +type BlkioStatsEntry struct { + Major uint64 `json:"major,omitempty" yaml:"major,omitempty" toml:"major,omitempty"` + Minor uint64 `json:"minor,omitempty" yaml:"minor,omitempty" toml:"minor,omitempty"` + Op string `json:"op,omitempty" yaml:"op,omitempty" toml:"op,omitempty"` + Value uint64 `json:"value,omitempty" yaml:"value,omitempty" toml:"value,omitempty"` +} + +// StatsOptions specify parameters to the Stats function. +// +// See https://goo.gl/Dk3Xio for more details. +type StatsOptions struct { + ID string + Stats chan<- *Stats + Stream bool + // A flag that enables stopping the stats operation + Done <-chan bool + // Initial connection timeout + Timeout time.Duration + // Timeout with no data is received, it's reset every time new data + // arrives + InactivityTimeout time.Duration `qs:"-"` + Context context.Context +} + +// Stats sends container statistics for the given container to the given channel. +// +// This function is blocking, similar to a streaming call for logs, and should be run +// on a separate goroutine from the caller. Note that this function will block until +// the given container is removed, not just exited. When finished, this function +// will close the given channel. Alternatively, function can be stopped by +// signaling on the Done channel. +// +// See https://goo.gl/Dk3Xio for more details. +func (c *Client) Stats(opts StatsOptions) (retErr error) { + errC := make(chan error, 1) + readCloser, writeCloser := io.Pipe() + + defer func() { + close(opts.Stats) + + select { + case err := <-errC: + if err != nil && retErr == nil { + retErr = err + } + default: + // No errors + } + + if err := readCloser.Close(); err != nil && retErr == nil { + retErr = err + } + }() + + reqSent := make(chan struct{}) + go func() { + err := c.stream("GET", fmt.Sprintf("/containers/%s/stats?stream=%v", opts.ID, opts.Stream), streamOptions{ + rawJSONStream: true, + useJSONDecoder: true, + stdout: writeCloser, + timeout: opts.Timeout, + inactivityTimeout: opts.InactivityTimeout, + context: opts.Context, + reqSent: reqSent, + }) + if err != nil { + dockerError, ok := err.(*Error) + if ok { + if dockerError.Status == http.StatusNotFound { + err = &NoSuchContainer{ID: opts.ID} + } + } + } + if closeErr := writeCloser.Close(); closeErr != nil && err == nil { + err = closeErr + } + errC <- err + close(errC) + }() + + quit := make(chan struct{}) + defer close(quit) + go func() { + // block here waiting for the signal to stop function + select { + case <-opts.Done: + readCloser.Close() + case <-quit: + return + } + }() + + decoder := json.NewDecoder(readCloser) + stats := new(Stats) + <-reqSent + for err := decoder.Decode(stats); err != io.EOF; err = decoder.Decode(stats) { + if err != nil { + return err + } + opts.Stats <- stats + stats = new(Stats) + } + return nil +} + +// KillContainerOptions represents the set of options that can be used in a +// call to KillContainer. +// +// See https://goo.gl/JnTxXZ for more details. +type KillContainerOptions struct { + // The ID of the container. + ID string `qs:"-"` + + // The signal to send to the container. When omitted, Docker server + // will assume SIGKILL. + Signal Signal + Context context.Context +} + +// KillContainer sends a signal to a container, returning an error in case of +// failure. +// +// See https://goo.gl/JnTxXZ for more details. +func (c *Client) KillContainer(opts KillContainerOptions) error { + path := "/containers/" + opts.ID + "/kill" + "?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + if err != nil { + e, ok := err.(*Error) + if !ok { + return err + } + switch e.Status { + case http.StatusNotFound: + return &NoSuchContainer{ID: opts.ID} + case http.StatusConflict: + return &ContainerNotRunning{ID: opts.ID} + default: + return err + } + } + resp.Body.Close() + return nil +} + +// RemoveContainerOptions encapsulates options to remove a container. +// +// See https://goo.gl/hL5IPC for more details. +type RemoveContainerOptions struct { + // The ID of the container. + ID string `qs:"-"` + + // A flag that indicates whether Docker should remove the volumes + // associated to the container. + RemoveVolumes bool `qs:"v"` + + // A flag that indicates whether Docker should remove the container + // even if it is currently running. + Force bool + Context context.Context +} + +// RemoveContainer removes a container, returning an error in case of failure. +// +// See https://goo.gl/hL5IPC for more details. +func (c *Client) RemoveContainer(opts RemoveContainerOptions) error { + path := "/containers/" + opts.ID + "?" + queryString(opts) + resp, err := c.do("DELETE", path, doOptions{context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchContainer{ID: opts.ID} + } + return err + } + resp.Body.Close() + return nil +} + +// UploadToContainerOptions is the set of options that can be used when +// uploading an archive into a container. +// +// See https://goo.gl/g25o7u for more details. +type UploadToContainerOptions struct { + InputStream io.Reader `json:"-" qs:"-"` + Path string `qs:"path"` + NoOverwriteDirNonDir bool `qs:"noOverwriteDirNonDir"` + Context context.Context +} + +// UploadToContainer uploads a tar archive to be extracted to a path in the +// filesystem of the container. +// +// See https://goo.gl/g25o7u for more details. +func (c *Client) UploadToContainer(id string, opts UploadToContainerOptions) error { + url := fmt.Sprintf("/containers/%s/archive?", id) + queryString(opts) + + return c.stream("PUT", url, streamOptions{ + in: opts.InputStream, + context: opts.Context, + }) +} + +// DownloadFromContainerOptions is the set of options that can be used when +// downloading resources from a container. +// +// See https://goo.gl/W49jxK for more details. +type DownloadFromContainerOptions struct { + OutputStream io.Writer `json:"-" qs:"-"` + Path string `qs:"path"` + InactivityTimeout time.Duration `qs:"-"` + Context context.Context +} + +// DownloadFromContainer downloads a tar archive of files or folders in a container. +// +// See https://goo.gl/W49jxK for more details. +func (c *Client) DownloadFromContainer(id string, opts DownloadFromContainerOptions) error { + url := fmt.Sprintf("/containers/%s/archive?", id) + queryString(opts) + + return c.stream("GET", url, streamOptions{ + setRawTerminal: true, + stdout: opts.OutputStream, + inactivityTimeout: opts.InactivityTimeout, + context: opts.Context, + }) +} + +// CopyFromContainerOptions contains the set of options used for copying +// files from a container. +// +// Deprecated: Use DownloadFromContainerOptions and DownloadFromContainer instead. +type CopyFromContainerOptions struct { + OutputStream io.Writer `json:"-"` + Container string `json:"-"` + Resource string + Context context.Context `json:"-"` +} + +// CopyFromContainer copies files from a container. +// +// Deprecated: Use DownloadFromContainer and DownloadFromContainer instead. +func (c *Client) CopyFromContainer(opts CopyFromContainerOptions) error { + if opts.Container == "" { + return &NoSuchContainer{ID: opts.Container} + } + if c.serverAPIVersion == nil { + c.checkAPIVersion() + } + if c.serverAPIVersion != nil && c.serverAPIVersion.GreaterThanOrEqualTo(apiVersion124) { + return errors.New("go-dockerclient: CopyFromContainer is no longer available in Docker >= 1.12, use DownloadFromContainer instead") + } + url := fmt.Sprintf("/containers/%s/copy", opts.Container) + resp, err := c.do("POST", url, doOptions{ + data: opts, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchContainer{ID: opts.Container} + } + return err + } + defer resp.Body.Close() + _, err = io.Copy(opts.OutputStream, resp.Body) + return err +} + +// WaitContainer blocks until the given container stops, return the exit code +// of the container status. +// +// See https://goo.gl/4AGweZ for more details. +func (c *Client) WaitContainer(id string) (int, error) { + return c.waitContainer(id, doOptions{}) +} + +// WaitContainerWithContext blocks until the given container stops, return the exit code +// of the container status. The context object can be used to cancel the +// inspect request. +// +// See https://goo.gl/4AGweZ for more details. +func (c *Client) WaitContainerWithContext(id string, ctx context.Context) (int, error) { + return c.waitContainer(id, doOptions{context: ctx}) +} + +func (c *Client) waitContainer(id string, opts doOptions) (int, error) { + resp, err := c.do("POST", "/containers/"+id+"/wait", opts) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return 0, &NoSuchContainer{ID: id} + } + return 0, err + } + defer resp.Body.Close() + var r struct{ StatusCode int } + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + return 0, err + } + return r.StatusCode, nil +} + +// CommitContainerOptions aggregates parameters to the CommitContainer method. +// +// See https://goo.gl/CzIguf for more details. +type CommitContainerOptions struct { + Container string + Repository string `qs:"repo"` + Tag string + Message string `qs:"comment"` + Author string + Changes []string `qs:"changes"` + Run *Config `qs:"-"` + Context context.Context +} + +// CommitContainer creates a new image from a container's changes. +// +// See https://goo.gl/CzIguf for more details. +func (c *Client) CommitContainer(opts CommitContainerOptions) (*Image, error) { + path := "/commit?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + data: opts.Run, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchContainer{ID: opts.Container} + } + return nil, err + } + defer resp.Body.Close() + var image Image + if err := json.NewDecoder(resp.Body).Decode(&image); err != nil { + return nil, err + } + return &image, nil +} + +// AttachToContainerOptions is the set of options that can be used when +// attaching to a container. +// +// See https://goo.gl/JF10Zk for more details. +type AttachToContainerOptions struct { + Container string `qs:"-"` + InputStream io.Reader `qs:"-"` + OutputStream io.Writer `qs:"-"` + ErrorStream io.Writer `qs:"-"` + + // If set, after a successful connect, a sentinel will be sent and then the + // client will block on receive before continuing. + // + // It must be an unbuffered channel. Using a buffered channel can lead + // to unexpected behavior. + Success chan struct{} + + // Use raw terminal? Usually true when the container contains a TTY. + RawTerminal bool `qs:"-"` + + // Get container logs, sending it to OutputStream. + Logs bool + + // Stream the response? + Stream bool + + // Attach to stdin, and use InputStream. + Stdin bool + + // Attach to stdout, and use OutputStream. + Stdout bool + + // Attach to stderr, and use ErrorStream. + Stderr bool +} + +// AttachToContainer attaches to a container, using the given options. +// +// See https://goo.gl/JF10Zk for more details. +func (c *Client) AttachToContainer(opts AttachToContainerOptions) error { + cw, err := c.AttachToContainerNonBlocking(opts) + if err != nil { + return err + } + return cw.Wait() +} + +// AttachToContainerNonBlocking attaches to a container, using the given options. +// This function does not block. +// +// See https://goo.gl/NKpkFk for more details. +func (c *Client) AttachToContainerNonBlocking(opts AttachToContainerOptions) (CloseWaiter, error) { + if opts.Container == "" { + return nil, &NoSuchContainer{ID: opts.Container} + } + path := "/containers/" + opts.Container + "/attach?" + queryString(opts) + return c.hijack("POST", path, hijackOptions{ + success: opts.Success, + setRawTerminal: opts.RawTerminal, + in: opts.InputStream, + stdout: opts.OutputStream, + stderr: opts.ErrorStream, + }) +} + +// LogsOptions represents the set of options used when getting logs from a +// container. +// +// See https://goo.gl/krK0ZH for more details. +type LogsOptions struct { + Context context.Context + Container string `qs:"-"` + OutputStream io.Writer `qs:"-"` + ErrorStream io.Writer `qs:"-"` + InactivityTimeout time.Duration `qs:"-"` + Tail string + + Since int64 + Follow bool + Stdout bool + Stderr bool + Timestamps bool + + // Use raw terminal? Usually true when the container contains a TTY. + RawTerminal bool `qs:"-"` +} + +// Logs gets stdout and stderr logs from the specified container. +// +// When LogsOptions.RawTerminal is set to false, go-dockerclient will multiplex +// the streams and send the containers stdout to LogsOptions.OutputStream, and +// stderr to LogsOptions.ErrorStream. +// +// When LogsOptions.RawTerminal is true, callers will get the raw stream on +// LogsOptions.OutputStream. The caller can use libraries such as dlog +// (github.com/ahmetalpbalkan/dlog). +// +// See https://goo.gl/krK0ZH for more details. +func (c *Client) Logs(opts LogsOptions) error { + if opts.Container == "" { + return &NoSuchContainer{ID: opts.Container} + } + if opts.Tail == "" { + opts.Tail = "all" + } + path := "/containers/" + opts.Container + "/logs?" + queryString(opts) + return c.stream("GET", path, streamOptions{ + setRawTerminal: opts.RawTerminal, + stdout: opts.OutputStream, + stderr: opts.ErrorStream, + inactivityTimeout: opts.InactivityTimeout, + context: opts.Context, + }) +} + +// ResizeContainerTTY resizes the terminal to the given height and width. +// +// See https://goo.gl/FImjeq for more details. +func (c *Client) ResizeContainerTTY(id string, height, width int) error { + params := make(url.Values) + params.Set("h", strconv.Itoa(height)) + params.Set("w", strconv.Itoa(width)) + resp, err := c.do("POST", "/containers/"+id+"/resize?"+params.Encode(), doOptions{}) + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// ExportContainerOptions is the set of parameters to the ExportContainer +// method. +// +// See https://goo.gl/yGJCIh for more details. +type ExportContainerOptions struct { + ID string + OutputStream io.Writer + InactivityTimeout time.Duration `qs:"-"` + Context context.Context +} + +// ExportContainer export the contents of container id as tar archive +// and prints the exported contents to stdout. +// +// See https://goo.gl/yGJCIh for more details. +func (c *Client) ExportContainer(opts ExportContainerOptions) error { + if opts.ID == "" { + return &NoSuchContainer{ID: opts.ID} + } + url := fmt.Sprintf("/containers/%s/export", opts.ID) + return c.stream("GET", url, streamOptions{ + setRawTerminal: true, + stdout: opts.OutputStream, + inactivityTimeout: opts.InactivityTimeout, + context: opts.Context, + }) +} + +// PruneContainersOptions specify parameters to the PruneContainers function. +// +// See https://goo.gl/wnkgDT for more details. +type PruneContainersOptions struct { + Filters map[string][]string + Context context.Context +} + +// PruneContainersResults specify results from the PruneContainers function. +// +// See https://goo.gl/wnkgDT for more details. +type PruneContainersResults struct { + ContainersDeleted []string + SpaceReclaimed int64 +} + +// PruneContainers deletes containers which are stopped. +// +// See https://goo.gl/wnkgDT for more details. +func (c *Client) PruneContainers(opts PruneContainersOptions) (*PruneContainersResults, error) { + path := "/containers/prune?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var results PruneContainersResults + if err := json.NewDecoder(resp.Body).Decode(&results); err != nil { + return nil, err + } + return &results, nil +} + +// NoSuchContainer is the error returned when a given container does not exist. +type NoSuchContainer struct { + ID string + Err error +} + +func (err *NoSuchContainer) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such container: " + err.ID +} + +// ContainerAlreadyRunning is the error returned when a given container is +// already running. +type ContainerAlreadyRunning struct { + ID string +} + +func (err *ContainerAlreadyRunning) Error() string { + return "Container already running: " + err.ID +} + +// ContainerNotRunning is the error returned when a given container is not +// running. +type ContainerNotRunning struct { + ID string +} + +func (err *ContainerNotRunning) Error() string { + return "Container not running: " + err.ID +} diff --git a/vendor/github.com/fsouza/go-dockerclient/distribution.go b/vendor/github.com/fsouza/go-dockerclient/distribution.go new file mode 100644 index 000000000..d0f8ce74c --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/distribution.go @@ -0,0 +1,26 @@ +// Copyright 2017 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "encoding/json" + + "github.com/docker/docker/api/types/registry" +) + +// InspectDistribution returns image digest and platform information by contacting the registry +func (c *Client) InspectDistribution(name string) (*registry.DistributionInspect, error) { + path := "/distribution/" + name + "/json" + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var distributionInspect registry.DistributionInspect + if err := json.NewDecoder(resp.Body).Decode(&distributionInspect); err != nil { + return nil, err + } + return &distributionInspect, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/env.go b/vendor/github.com/fsouza/go-dockerclient/env.go new file mode 100644 index 000000000..13fedfb17 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/env.go @@ -0,0 +1,172 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package docker + +import ( + "encoding/json" + "fmt" + "io" + "strconv" + "strings" +) + +// Env represents a list of key-pair represented in the form KEY=VALUE. +type Env []string + +// Get returns the string value of the given key. +func (env *Env) Get(key string) (value string) { + return env.Map()[key] +} + +// Exists checks whether the given key is defined in the internal Env +// representation. +func (env *Env) Exists(key string) bool { + _, exists := env.Map()[key] + return exists +} + +// GetBool returns a boolean representation of the given key. The key is false +// whenever its value if 0, no, false, none or an empty string. Any other value +// will be interpreted as true. +func (env *Env) GetBool(key string) (value bool) { + s := strings.ToLower(strings.Trim(env.Get(key), " \t")) + if s == "" || s == "0" || s == "no" || s == "false" || s == "none" { + return false + } + return true +} + +// SetBool defines a boolean value to the given key. +func (env *Env) SetBool(key string, value bool) { + if value { + env.Set(key, "1") + } else { + env.Set(key, "0") + } +} + +// GetInt returns the value of the provided key, converted to int. +// +// It the value cannot be represented as an integer, it returns -1. +func (env *Env) GetInt(key string) int { + return int(env.GetInt64(key)) +} + +// SetInt defines an integer value to the given key. +func (env *Env) SetInt(key string, value int) { + env.Set(key, strconv.Itoa(value)) +} + +// GetInt64 returns the value of the provided key, converted to int64. +// +// It the value cannot be represented as an integer, it returns -1. +func (env *Env) GetInt64(key string) int64 { + s := strings.Trim(env.Get(key), " \t") + val, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return -1 + } + return val +} + +// SetInt64 defines an integer (64-bit wide) value to the given key. +func (env *Env) SetInt64(key string, value int64) { + env.Set(key, strconv.FormatInt(value, 10)) +} + +// GetJSON unmarshals the value of the provided key in the provided iface. +// +// iface is a value that can be provided to the json.Unmarshal function. +func (env *Env) GetJSON(key string, iface interface{}) error { + sval := env.Get(key) + if sval == "" { + return nil + } + return json.Unmarshal([]byte(sval), iface) +} + +// SetJSON marshals the given value to JSON format and stores it using the +// provided key. +func (env *Env) SetJSON(key string, value interface{}) error { + sval, err := json.Marshal(value) + if err != nil { + return err + } + env.Set(key, string(sval)) + return nil +} + +// GetList returns a list of strings matching the provided key. It handles the +// list as a JSON representation of a list of strings. +// +// If the given key matches to a single string, it will return a list +// containing only the value that matches the key. +func (env *Env) GetList(key string) []string { + sval := env.Get(key) + if sval == "" { + return nil + } + var l []string + if err := json.Unmarshal([]byte(sval), &l); err != nil { + l = append(l, sval) + } + return l +} + +// SetList stores the given list in the provided key, after serializing it to +// JSON format. +func (env *Env) SetList(key string, value []string) error { + return env.SetJSON(key, value) +} + +// Set defines the value of a key to the given string. +func (env *Env) Set(key, value string) { + *env = append(*env, key+"="+value) +} + +// Decode decodes `src` as a json dictionary, and adds each decoded key-value +// pair to the environment. +// +// If `src` cannot be decoded as a json dictionary, an error is returned. +func (env *Env) Decode(src io.Reader) error { + m := make(map[string]interface{}) + if err := json.NewDecoder(src).Decode(&m); err != nil { + return err + } + for k, v := range m { + env.SetAuto(k, v) + } + return nil +} + +// SetAuto will try to define the Set* method to call based on the given value. +func (env *Env) SetAuto(key string, value interface{}) { + if fval, ok := value.(float64); ok { + env.SetInt64(key, int64(fval)) + } else if sval, ok := value.(string); ok { + env.Set(key, sval) + } else if val, err := json.Marshal(value); err == nil { + env.Set(key, string(val)) + } else { + env.Set(key, fmt.Sprintf("%v", value)) + } +} + +// Map returns the map representation of the env. +func (env *Env) Map() map[string]string { + if len(*env) == 0 { + return nil + } + m := make(map[string]string) + for _, kv := range *env { + parts := strings.SplitN(kv, "=", 2) + if len(parts) == 1 { + m[parts[0]] = "" + } else { + m[parts[0]] = parts[1] + } + } + return m +} diff --git a/vendor/github.com/fsouza/go-dockerclient/event.go b/vendor/github.com/fsouza/go-dockerclient/event.go new file mode 100644 index 000000000..18ae5d5a6 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/event.go @@ -0,0 +1,410 @@ +// Copyright 2014 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "math" + "net" + "net/http" + "net/http/httputil" + "sync" + "sync/atomic" + "time" +) + +// APIEvents represents events coming from the Docker API +// The fields in the Docker API changed in API version 1.22, and +// events for more than images and containers are now fired off. +// To maintain forward and backward compatibility, go-dockerclient +// replicates the event in both the new and old format as faithfully as possible. +// +// For events that only exist in 1.22 in later, `Status` is filled in as +// `"Type:Action"` instead of just `Action` to allow for older clients to +// differentiate and not break if they rely on the pre-1.22 Status types. +// +// The transformEvent method can be consulted for more information about how +// events are translated from new/old API formats +type APIEvents struct { + // New API Fields in 1.22 + Action string `json:"action,omitempty"` + Type string `json:"type,omitempty"` + Actor APIActor `json:"actor,omitempty"` + + // Old API fields for < 1.22 + Status string `json:"status,omitempty"` + ID string `json:"id,omitempty"` + From string `json:"from,omitempty"` + + // Fields in both + Time int64 `json:"time,omitempty"` + TimeNano int64 `json:"timeNano,omitempty"` +} + +// APIActor represents an actor that accomplishes something for an event +type APIActor struct { + ID string `json:"id,omitempty"` + Attributes map[string]string `json:"attributes,omitempty"` +} + +type eventMonitoringState struct { + // `sync/atomic` expects the first word in an allocated struct to be 64-bit + // aligned on both ARM and x86-32. See https://goo.gl/zW7dgq for more details. + lastSeen int64 + sync.RWMutex + sync.WaitGroup + enabled bool + C chan *APIEvents + errC chan error + listeners []chan<- *APIEvents +} + +const ( + maxMonitorConnRetries = 5 + retryInitialWaitTime = 10. +) + +var ( + // ErrNoListeners is the error returned when no listeners are available + // to receive an event. + ErrNoListeners = errors.New("no listeners present to receive event") + + // ErrListenerAlreadyExists is the error returned when the listerner already + // exists. + ErrListenerAlreadyExists = errors.New("listener already exists for docker events") + + // ErrTLSNotSupported is the error returned when the client does not support + // TLS (this applies to the Windows named pipe client). + ErrTLSNotSupported = errors.New("tls not supported by this client") + + // EOFEvent is sent when the event listener receives an EOF error. + EOFEvent = &APIEvents{ + Type: "EOF", + Status: "EOF", + } +) + +// AddEventListener adds a new listener to container events in the Docker API. +// +// The parameter is a channel through which events will be sent. +func (c *Client) AddEventListener(listener chan<- *APIEvents) error { + var err error + if !c.eventMonitor.isEnabled() { + err = c.eventMonitor.enableEventMonitoring(c) + if err != nil { + return err + } + } + return c.eventMonitor.addListener(listener) +} + +// RemoveEventListener removes a listener from the monitor. +func (c *Client) RemoveEventListener(listener chan *APIEvents) error { + err := c.eventMonitor.removeListener(listener) + if err != nil { + return err + } + if c.eventMonitor.listernersCount() == 0 { + c.eventMonitor.disableEventMonitoring() + } + return nil +} + +func (eventState *eventMonitoringState) addListener(listener chan<- *APIEvents) error { + eventState.Lock() + defer eventState.Unlock() + if listenerExists(listener, &eventState.listeners) { + return ErrListenerAlreadyExists + } + eventState.Add(1) + eventState.listeners = append(eventState.listeners, listener) + return nil +} + +func (eventState *eventMonitoringState) removeListener(listener chan<- *APIEvents) error { + eventState.Lock() + defer eventState.Unlock() + if listenerExists(listener, &eventState.listeners) { + var newListeners []chan<- *APIEvents + for _, l := range eventState.listeners { + if l != listener { + newListeners = append(newListeners, l) + } + } + eventState.listeners = newListeners + eventState.Add(-1) + } + return nil +} + +func (eventState *eventMonitoringState) closeListeners() { + for _, l := range eventState.listeners { + close(l) + eventState.Add(-1) + } + eventState.listeners = nil +} + +func (eventState *eventMonitoringState) listernersCount() int { + eventState.RLock() + defer eventState.RUnlock() + return len(eventState.listeners) +} + +func listenerExists(a chan<- *APIEvents, list *[]chan<- *APIEvents) bool { + for _, b := range *list { + if b == a { + return true + } + } + return false +} + +func (eventState *eventMonitoringState) enableEventMonitoring(c *Client) error { + eventState.Lock() + defer eventState.Unlock() + if !eventState.enabled { + eventState.enabled = true + atomic.StoreInt64(&eventState.lastSeen, 0) + eventState.C = make(chan *APIEvents, 100) + eventState.errC = make(chan error, 1) + go eventState.monitorEvents(c) + } + return nil +} + +func (eventState *eventMonitoringState) disableEventMonitoring() error { + eventState.Lock() + defer eventState.Unlock() + + eventState.closeListeners() + + eventState.Wait() + + if eventState.enabled { + eventState.enabled = false + close(eventState.C) + close(eventState.errC) + } + return nil +} + +func (eventState *eventMonitoringState) monitorEvents(c *Client) { + const ( + noListenersTimeout = 5 * time.Second + noListenersInterval = 10 * time.Millisecond + noListenersMaxTries = noListenersTimeout / noListenersInterval + ) + + var err error + for i := time.Duration(0); i < noListenersMaxTries && eventState.noListeners(); i++ { + time.Sleep(10 * time.Millisecond) + } + + if eventState.noListeners() { + // terminate if no listener is available after 5 seconds. + // Prevents goroutine leak when RemoveEventListener is called + // right after AddEventListener. + eventState.disableEventMonitoring() + return + } + + if err = eventState.connectWithRetry(c); err != nil { + // terminate if connect failed + eventState.disableEventMonitoring() + return + } + for eventState.isEnabled() { + timeout := time.After(100 * time.Millisecond) + select { + case ev, ok := <-eventState.C: + if !ok { + return + } + if ev == EOFEvent { + eventState.disableEventMonitoring() + return + } + eventState.updateLastSeen(ev) + eventState.sendEvent(ev) + case err = <-eventState.errC: + if err == ErrNoListeners { + eventState.disableEventMonitoring() + return + } else if err != nil { + defer func() { go eventState.monitorEvents(c) }() + return + } + case <-timeout: + continue + } + } +} + +func (eventState *eventMonitoringState) connectWithRetry(c *Client) error { + var retries int + eventState.RLock() + eventChan := eventState.C + errChan := eventState.errC + eventState.RUnlock() + err := c.eventHijack(atomic.LoadInt64(&eventState.lastSeen), eventChan, errChan) + for ; err != nil && retries < maxMonitorConnRetries; retries++ { + waitTime := int64(retryInitialWaitTime * math.Pow(2, float64(retries))) + time.Sleep(time.Duration(waitTime) * time.Millisecond) + eventState.RLock() + eventChan = eventState.C + errChan = eventState.errC + eventState.RUnlock() + err = c.eventHijack(atomic.LoadInt64(&eventState.lastSeen), eventChan, errChan) + } + return err +} + +func (eventState *eventMonitoringState) noListeners() bool { + eventState.RLock() + defer eventState.RUnlock() + return len(eventState.listeners) == 0 +} + +func (eventState *eventMonitoringState) isEnabled() bool { + eventState.RLock() + defer eventState.RUnlock() + return eventState.enabled +} + +func (eventState *eventMonitoringState) sendEvent(event *APIEvents) { + eventState.RLock() + defer eventState.RUnlock() + eventState.Add(1) + defer eventState.Done() + if eventState.enabled { + if len(eventState.listeners) == 0 { + eventState.errC <- ErrNoListeners + return + } + + for _, listener := range eventState.listeners { + select { + case listener <- event: + default: + } + } + } +} + +func (eventState *eventMonitoringState) updateLastSeen(e *APIEvents) { + eventState.Lock() + defer eventState.Unlock() + if atomic.LoadInt64(&eventState.lastSeen) < e.Time { + atomic.StoreInt64(&eventState.lastSeen, e.Time) + } +} + +func (c *Client) eventHijack(startTime int64, eventChan chan *APIEvents, errChan chan error) error { + uri := "/events" + if startTime != 0 { + uri += fmt.Sprintf("?since=%d", startTime) + } + protocol := c.endpointURL.Scheme + address := c.endpointURL.Path + if protocol != "unix" && protocol != "npipe" { + protocol = "tcp" + address = c.endpointURL.Host + } + var dial net.Conn + var err error + if c.TLSConfig == nil { + dial, err = c.Dialer.Dial(protocol, address) + } else { + netDialer, ok := c.Dialer.(*net.Dialer) + if !ok { + return ErrTLSNotSupported + } + dial, err = tlsDialWithDialer(netDialer, protocol, address, c.TLSConfig) + } + if err != nil { + return err + } + conn := httputil.NewClientConn(dial, nil) + req, err := http.NewRequest("GET", uri, nil) + if err != nil { + return err + } + res, err := conn.Do(req) + if err != nil { + return err + } + go func(res *http.Response, conn *httputil.ClientConn) { + defer conn.Close() + defer res.Body.Close() + decoder := json.NewDecoder(res.Body) + for { + var event APIEvents + if err = decoder.Decode(&event); err != nil { + if err == io.EOF || err == io.ErrUnexpectedEOF { + c.eventMonitor.RLock() + if c.eventMonitor.enabled && c.eventMonitor.C == eventChan { + // Signal that we're exiting. + eventChan <- EOFEvent + } + c.eventMonitor.RUnlock() + break + } + errChan <- err + } + if event.Time == 0 { + continue + } + transformEvent(&event) + c.eventMonitor.RLock() + if c.eventMonitor.enabled && c.eventMonitor.C == eventChan { + eventChan <- &event + } + c.eventMonitor.RUnlock() + } + }(res, conn) + return nil +} + +// transformEvent takes an event and determines what version it is from +// then populates both versions of the event +func transformEvent(event *APIEvents) { + // if event version is <= 1.21 there will be no Action and no Type + if event.Action == "" && event.Type == "" { + event.Action = event.Status + event.Actor.ID = event.ID + event.Actor.Attributes = map[string]string{} + switch event.Status { + case "delete", "import", "pull", "push", "tag", "untag": + event.Type = "image" + default: + event.Type = "container" + if event.From != "" { + event.Actor.Attributes["image"] = event.From + } + } + } else { + if event.Status == "" { + if event.Type == "image" || event.Type == "container" { + event.Status = event.Action + } else { + // Because just the Status has been overloaded with different Types + // if an event is not for an image or a container, we prepend the type + // to avoid problems for people relying on actions being only for + // images and containers + event.Status = event.Type + ":" + event.Action + } + } + if event.ID == "" { + event.ID = event.Actor.ID + } + if event.From == "" { + event.From = event.Actor.Attributes["image"] + } + } +} diff --git a/vendor/github.com/fsouza/go-dockerclient/exec.go b/vendor/github.com/fsouza/go-dockerclient/exec.go new file mode 100644 index 000000000..5e7ea87f6 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/exec.go @@ -0,0 +1,217 @@ +// Copyright 2014 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "strconv" +) + +// Exec is the type representing a `docker exec` instance and containing the +// instance ID +type Exec struct { + ID string `json:"Id,omitempty" yaml:"Id,omitempty"` +} + +// CreateExecOptions specify parameters to the CreateExecContainer function. +// +// See https://goo.gl/60TeBP for more details +type CreateExecOptions struct { + AttachStdin bool `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty" toml:"AttachStdin,omitempty"` + AttachStdout bool `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty" toml:"AttachStdout,omitempty"` + AttachStderr bool `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty" toml:"AttachStderr,omitempty"` + Tty bool `json:"Tty,omitempty" yaml:"Tty,omitempty" toml:"Tty,omitempty"` + Env []string `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"` + Cmd []string `json:"Cmd,omitempty" yaml:"Cmd,omitempty" toml:"Cmd,omitempty"` + Container string `json:"Container,omitempty" yaml:"Container,omitempty" toml:"Container,omitempty"` + User string `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"` + WorkingDir string `json:"WorkingDir,omitempty" yaml:"WorkingDir,omitempty" toml:"WorkingDir,omitempty"` + Context context.Context `json:"-"` + Privileged bool `json:"Privileged,omitempty" yaml:"Privileged,omitempty" toml:"Privileged,omitempty"` +} + +// CreateExec sets up an exec instance in a running container `id`, returning the exec +// instance, or an error in case of failure. +// +// See https://goo.gl/60TeBP for more details +func (c *Client) CreateExec(opts CreateExecOptions) (*Exec, error) { + if len(opts.Env) > 0 && c.serverAPIVersion.LessThan(apiVersion125) { + return nil, errors.New("exec configuration Env is only supported in API#1.25 and above") + } + if len(opts.WorkingDir) > 0 && c.serverAPIVersion.LessThan(apiVersion135) { + return nil, errors.New("exec configuration WorkingDir is only supported in API#1.35 and above") + } + path := fmt.Sprintf("/containers/%s/exec", opts.Container) + resp, err := c.do("POST", path, doOptions{data: opts, context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchContainer{ID: opts.Container} + } + return nil, err + } + defer resp.Body.Close() + var exec Exec + if err := json.NewDecoder(resp.Body).Decode(&exec); err != nil { + return nil, err + } + + return &exec, nil +} + +// StartExecOptions specify parameters to the StartExecContainer function. +// +// See https://goo.gl/1EeDWi for more details +type StartExecOptions struct { + InputStream io.Reader `qs:"-"` + OutputStream io.Writer `qs:"-"` + ErrorStream io.Writer `qs:"-"` + + Detach bool `json:"Detach,omitempty" yaml:"Detach,omitempty" toml:"Detach,omitempty"` + Tty bool `json:"Tty,omitempty" yaml:"Tty,omitempty" toml:"Tty,omitempty"` + + // Use raw terminal? Usually true when the container contains a TTY. + RawTerminal bool `qs:"-"` + + // If set, after a successful connect, a sentinel will be sent and then the + // client will block on receive before continuing. + // + // It must be an unbuffered channel. Using a buffered channel can lead + // to unexpected behavior. + Success chan struct{} `json:"-"` + + Context context.Context `json:"-"` +} + +// StartExec starts a previously set up exec instance id. If opts.Detach is +// true, it returns after starting the exec command. Otherwise, it sets up an +// interactive session with the exec command. +// +// See https://goo.gl/1EeDWi for more details +func (c *Client) StartExec(id string, opts StartExecOptions) error { + cw, err := c.StartExecNonBlocking(id, opts) + if err != nil { + return err + } + if cw != nil { + return cw.Wait() + } + return nil +} + +// StartExecNonBlocking starts a previously set up exec instance id. If opts.Detach is +// true, it returns after starting the exec command. Otherwise, it sets up an +// interactive session with the exec command. +// +// See https://goo.gl/1EeDWi for more details +func (c *Client) StartExecNonBlocking(id string, opts StartExecOptions) (CloseWaiter, error) { + if id == "" { + return nil, &NoSuchExec{ID: id} + } + + path := fmt.Sprintf("/exec/%s/start", id) + + if opts.Detach { + resp, err := c.do("POST", path, doOptions{data: opts, context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchExec{ID: id} + } + return nil, err + } + defer resp.Body.Close() + return nil, nil + } + + return c.hijack("POST", path, hijackOptions{ + success: opts.Success, + setRawTerminal: opts.RawTerminal, + in: opts.InputStream, + stdout: opts.OutputStream, + stderr: opts.ErrorStream, + data: opts, + }) +} + +// ResizeExecTTY resizes the tty session used by the exec command id. This API +// is valid only if Tty was specified as part of creating and starting the exec +// command. +// +// See https://goo.gl/Mo5bxx for more details +func (c *Client) ResizeExecTTY(id string, height, width int) error { + params := make(url.Values) + params.Set("h", strconv.Itoa(height)) + params.Set("w", strconv.Itoa(width)) + + path := fmt.Sprintf("/exec/%s/resize?%s", id, params.Encode()) + resp, err := c.do("POST", path, doOptions{}) + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// ExecProcessConfig is a type describing the command associated to a Exec +// instance. It's used in the ExecInspect type. +type ExecProcessConfig struct { + User string `json:"user,omitempty" yaml:"user,omitempty" toml:"user,omitempty"` + Privileged bool `json:"privileged,omitempty" yaml:"privileged,omitempty" toml:"privileged,omitempty"` + Tty bool `json:"tty,omitempty" yaml:"tty,omitempty" toml:"tty,omitempty"` + EntryPoint string `json:"entrypoint,omitempty" yaml:"entrypoint,omitempty" toml:"entrypoint,omitempty"` + Arguments []string `json:"arguments,omitempty" yaml:"arguments,omitempty" toml:"arguments,omitempty"` +} + +// ExecInspect is a type with details about a exec instance, including the +// exit code if the command has finished running. It's returned by a api +// call to /exec/(id)/json +// +// See https://goo.gl/ctMUiW for more details +type ExecInspect struct { + ID string `json:"ID,omitempty" yaml:"ID,omitempty" toml:"ID,omitempty"` + ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty" toml:"ExitCode,omitempty"` + Running bool `json:"Running,omitempty" yaml:"Running,omitempty" toml:"Running,omitempty"` + OpenStdin bool `json:"OpenStdin,omitempty" yaml:"OpenStdin,omitempty" toml:"OpenStdin,omitempty"` + OpenStderr bool `json:"OpenStderr,omitempty" yaml:"OpenStderr,omitempty" toml:"OpenStderr,omitempty"` + OpenStdout bool `json:"OpenStdout,omitempty" yaml:"OpenStdout,omitempty" toml:"OpenStdout,omitempty"` + ProcessConfig ExecProcessConfig `json:"ProcessConfig,omitempty" yaml:"ProcessConfig,omitempty" toml:"ProcessConfig,omitempty"` + ContainerID string `json:"ContainerID,omitempty" yaml:"ContainerID,omitempty" toml:"ContainerID,omitempty"` + DetachKeys string `json:"DetachKeys,omitempty" yaml:"DetachKeys,omitempty" toml:"DetachKeys,omitempty"` + CanRemove bool `json:"CanRemove,omitempty" yaml:"CanRemove,omitempty" toml:"CanRemove,omitempty"` +} + +// InspectExec returns low-level information about the exec command id. +// +// See https://goo.gl/ctMUiW for more details +func (c *Client) InspectExec(id string) (*ExecInspect, error) { + path := fmt.Sprintf("/exec/%s/json", id) + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchExec{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var exec ExecInspect + if err := json.NewDecoder(resp.Body).Decode(&exec); err != nil { + return nil, err + } + return &exec, nil +} + +// NoSuchExec is the error returned when a given exec instance does not exist. +type NoSuchExec struct { + ID string +} + +func (err *NoSuchExec) Error() string { + return "No such exec instance: " + err.ID +} diff --git a/vendor/github.com/fsouza/go-dockerclient/image.go b/vendor/github.com/fsouza/go-dockerclient/image.go new file mode 100644 index 000000000..124e78da3 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/image.go @@ -0,0 +1,720 @@ +// Copyright 2013 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "os" + "strings" + "time" +) + +// APIImages represent an image returned in the ListImages call. +type APIImages struct { + ID string `json:"Id" yaml:"Id" toml:"Id"` + RepoTags []string `json:"RepoTags,omitempty" yaml:"RepoTags,omitempty" toml:"RepoTags,omitempty"` + Created int64 `json:"Created,omitempty" yaml:"Created,omitempty" toml:"Created,omitempty"` + Size int64 `json:"Size,omitempty" yaml:"Size,omitempty" toml:"Size,omitempty"` + VirtualSize int64 `json:"VirtualSize,omitempty" yaml:"VirtualSize,omitempty" toml:"VirtualSize,omitempty"` + ParentID string `json:"ParentId,omitempty" yaml:"ParentId,omitempty" toml:"ParentId,omitempty"` + RepoDigests []string `json:"RepoDigests,omitempty" yaml:"RepoDigests,omitempty" toml:"RepoDigests,omitempty"` + Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"` +} + +// RootFS represents the underlying layers used by an image +type RootFS struct { + Type string `json:"Type,omitempty" yaml:"Type,omitempty" toml:"Type,omitempty"` + Layers []string `json:"Layers,omitempty" yaml:"Layers,omitempty" toml:"Layers,omitempty"` +} + +// Image is the type representing a docker image and its various properties +type Image struct { + ID string `json:"Id" yaml:"Id" toml:"Id"` + RepoTags []string `json:"RepoTags,omitempty" yaml:"RepoTags,omitempty" toml:"RepoTags,omitempty"` + Parent string `json:"Parent,omitempty" yaml:"Parent,omitempty" toml:"Parent,omitempty"` + Comment string `json:"Comment,omitempty" yaml:"Comment,omitempty" toml:"Comment,omitempty"` + Created time.Time `json:"Created,omitempty" yaml:"Created,omitempty" toml:"Created,omitempty"` + Container string `json:"Container,omitempty" yaml:"Container,omitempty" toml:"Container,omitempty"` + ContainerConfig Config `json:"ContainerConfig,omitempty" yaml:"ContainerConfig,omitempty" toml:"ContainerConfig,omitempty"` + DockerVersion string `json:"DockerVersion,omitempty" yaml:"DockerVersion,omitempty" toml:"DockerVersion,omitempty"` + Author string `json:"Author,omitempty" yaml:"Author,omitempty" toml:"Author,omitempty"` + Config *Config `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"` + Architecture string `json:"Architecture,omitempty" yaml:"Architecture,omitempty"` + Size int64 `json:"Size,omitempty" yaml:"Size,omitempty" toml:"Size,omitempty"` + VirtualSize int64 `json:"VirtualSize,omitempty" yaml:"VirtualSize,omitempty" toml:"VirtualSize,omitempty"` + RepoDigests []string `json:"RepoDigests,omitempty" yaml:"RepoDigests,omitempty" toml:"RepoDigests,omitempty"` + RootFS *RootFS `json:"RootFS,omitempty" yaml:"RootFS,omitempty" toml:"RootFS,omitempty"` + OS string `json:"Os,omitempty" yaml:"Os,omitempty" toml:"Os,omitempty"` +} + +// ImagePre012 serves the same purpose as the Image type except that it is for +// earlier versions of the Docker API (pre-012 to be specific) +type ImagePre012 struct { + ID string `json:"id"` + Parent string `json:"parent,omitempty"` + Comment string `json:"comment,omitempty"` + Created time.Time `json:"created"` + Container string `json:"container,omitempty"` + ContainerConfig Config `json:"container_config,omitempty"` + DockerVersion string `json:"docker_version,omitempty"` + Author string `json:"author,omitempty"` + Config *Config `json:"config,omitempty"` + Architecture string `json:"architecture,omitempty"` + Size int64 `json:"size,omitempty"` +} + +var ( + // ErrNoSuchImage is the error returned when the image does not exist. + ErrNoSuchImage = errors.New("no such image") + + // ErrMissingRepo is the error returned when the remote repository is + // missing. + ErrMissingRepo = errors.New("missing remote repository e.g. 'github.com/user/repo'") + + // ErrMissingOutputStream is the error returned when no output stream + // is provided to some calls, like BuildImage. + ErrMissingOutputStream = errors.New("missing output stream") + + // ErrMultipleContexts is the error returned when both a ContextDir and + // InputStream are provided in BuildImageOptions + ErrMultipleContexts = errors.New("image build may not be provided BOTH context dir and input stream") + + // ErrMustSpecifyNames is the error rreturned when the Names field on + // ExportImagesOptions is nil or empty + ErrMustSpecifyNames = errors.New("must specify at least one name to export") +) + +// ListImagesOptions specify parameters to the ListImages function. +// +// See https://goo.gl/BVzauZ for more details. +type ListImagesOptions struct { + Filters map[string][]string + All bool + Digests bool + Filter string + Context context.Context +} + +// ListImages returns the list of available images in the server. +// +// See https://goo.gl/BVzauZ for more details. +func (c *Client) ListImages(opts ListImagesOptions) ([]APIImages, error) { + path := "/images/json?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var images []APIImages + if err := json.NewDecoder(resp.Body).Decode(&images); err != nil { + return nil, err + } + return images, nil +} + +// ImageHistory represent a layer in an image's history returned by the +// ImageHistory call. +type ImageHistory struct { + ID string `json:"Id" yaml:"Id" toml:"Id"` + Tags []string `json:"Tags,omitempty" yaml:"Tags,omitempty" toml:"Tags,omitempty"` + Created int64 `json:"Created,omitempty" yaml:"Created,omitempty" toml:"Tags,omitempty"` + CreatedBy string `json:"CreatedBy,omitempty" yaml:"CreatedBy,omitempty" toml:"CreatedBy,omitempty"` + Size int64 `json:"Size,omitempty" yaml:"Size,omitempty" toml:"Size,omitempty"` +} + +// ImageHistory returns the history of the image by its name or ID. +// +// See https://goo.gl/fYtxQa for more details. +func (c *Client) ImageHistory(name string) ([]ImageHistory, error) { + resp, err := c.do("GET", "/images/"+name+"/history", doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, ErrNoSuchImage + } + return nil, err + } + defer resp.Body.Close() + var history []ImageHistory + if err := json.NewDecoder(resp.Body).Decode(&history); err != nil { + return nil, err + } + return history, nil +} + +// RemoveImage removes an image by its name or ID. +// +// See https://goo.gl/Vd2Pck for more details. +func (c *Client) RemoveImage(name string) error { + resp, err := c.do("DELETE", "/images/"+name, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return ErrNoSuchImage + } + return err + } + resp.Body.Close() + return nil +} + +// RemoveImageOptions present the set of options available for removing an image +// from a registry. +// +// See https://goo.gl/Vd2Pck for more details. +type RemoveImageOptions struct { + Force bool `qs:"force"` + NoPrune bool `qs:"noprune"` + Context context.Context +} + +// RemoveImageExtended removes an image by its name or ID. +// Extra params can be passed, see RemoveImageOptions +// +// See https://goo.gl/Vd2Pck for more details. +func (c *Client) RemoveImageExtended(name string, opts RemoveImageOptions) error { + uri := fmt.Sprintf("/images/%s?%s", name, queryString(&opts)) + resp, err := c.do("DELETE", uri, doOptions{context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return ErrNoSuchImage + } + return err + } + resp.Body.Close() + return nil +} + +// InspectImage returns an image by its name or ID. +// +// See https://goo.gl/ncLTG8 for more details. +func (c *Client) InspectImage(name string) (*Image, error) { + resp, err := c.do("GET", "/images/"+name+"/json", doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, ErrNoSuchImage + } + return nil, err + } + defer resp.Body.Close() + + var image Image + + // if the caller elected to skip checking the server's version, assume it's the latest + if c.SkipServerVersionCheck || c.expectedAPIVersion.GreaterThanOrEqualTo(apiVersion112) { + if err := json.NewDecoder(resp.Body).Decode(&image); err != nil { + return nil, err + } + } else { + var imagePre012 ImagePre012 + if err := json.NewDecoder(resp.Body).Decode(&imagePre012); err != nil { + return nil, err + } + + image.ID = imagePre012.ID + image.Parent = imagePre012.Parent + image.Comment = imagePre012.Comment + image.Created = imagePre012.Created + image.Container = imagePre012.Container + image.ContainerConfig = imagePre012.ContainerConfig + image.DockerVersion = imagePre012.DockerVersion + image.Author = imagePre012.Author + image.Config = imagePre012.Config + image.Architecture = imagePre012.Architecture + image.Size = imagePre012.Size + } + + return &image, nil +} + +// PushImageOptions represents options to use in the PushImage method. +// +// See https://goo.gl/BZemGg for more details. +type PushImageOptions struct { + // Name of the image + Name string + + // Tag of the image + Tag string + + // Registry server to push the image + Registry string + + OutputStream io.Writer `qs:"-"` + RawJSONStream bool `qs:"-"` + InactivityTimeout time.Duration `qs:"-"` + + Context context.Context +} + +// PushImage pushes an image to a remote registry, logging progress to w. +// +// An empty instance of AuthConfiguration may be used for unauthenticated +// pushes. +// +// See https://goo.gl/BZemGg for more details. +func (c *Client) PushImage(opts PushImageOptions, auth AuthConfiguration) error { + if opts.Name == "" { + return ErrNoSuchImage + } + headers, err := headersWithAuth(auth) + if err != nil { + return err + } + name := opts.Name + opts.Name = "" + path := "/images/" + name + "/push?" + queryString(&opts) + return c.stream("POST", path, streamOptions{ + setRawTerminal: true, + rawJSONStream: opts.RawJSONStream, + headers: headers, + stdout: opts.OutputStream, + inactivityTimeout: opts.InactivityTimeout, + context: opts.Context, + }) +} + +// PullImageOptions present the set of options available for pulling an image +// from a registry. +// +// See https://goo.gl/qkoSsn for more details. +type PullImageOptions struct { + Repository string `qs:"fromImage"` + Tag string + + // Only required for Docker Engine 1.9 or 1.10 w/ Remote API < 1.21 + // and Docker Engine < 1.9 + // This parameter was removed in Docker Engine 1.11 + Registry string + + OutputStream io.Writer `qs:"-"` + RawJSONStream bool `qs:"-"` + InactivityTimeout time.Duration `qs:"-"` + Context context.Context +} + +// PullImage pulls an image from a remote registry, logging progress to +// opts.OutputStream. +// +// See https://goo.gl/qkoSsn for more details. +func (c *Client) PullImage(opts PullImageOptions, auth AuthConfiguration) error { + if opts.Repository == "" { + return ErrNoSuchImage + } + + headers, err := headersWithAuth(auth) + if err != nil { + return err + } + if opts.Tag == "" && strings.Contains(opts.Repository, "@") { + parts := strings.SplitN(opts.Repository, "@", 2) + opts.Repository = parts[0] + opts.Tag = parts[1] + } + return c.createImage(queryString(&opts), headers, nil, opts.OutputStream, opts.RawJSONStream, opts.InactivityTimeout, opts.Context) +} + +func (c *Client) createImage(qs string, headers map[string]string, in io.Reader, w io.Writer, rawJSONStream bool, timeout time.Duration, context context.Context) error { + path := "/images/create?" + qs + return c.stream("POST", path, streamOptions{ + setRawTerminal: true, + headers: headers, + in: in, + stdout: w, + rawJSONStream: rawJSONStream, + inactivityTimeout: timeout, + context: context, + }) +} + +// LoadImageOptions represents the options for LoadImage Docker API Call +// +// See https://goo.gl/rEsBV3 for more details. +type LoadImageOptions struct { + InputStream io.Reader + OutputStream io.Writer + Context context.Context +} + +// LoadImage imports a tarball docker image +// +// See https://goo.gl/rEsBV3 for more details. +func (c *Client) LoadImage(opts LoadImageOptions) error { + return c.stream("POST", "/images/load", streamOptions{ + setRawTerminal: true, + in: opts.InputStream, + stdout: opts.OutputStream, + context: opts.Context, + }) +} + +// ExportImageOptions represent the options for ExportImage Docker API call. +// +// See https://goo.gl/AuySaA for more details. +type ExportImageOptions struct { + Name string + OutputStream io.Writer + InactivityTimeout time.Duration + Context context.Context +} + +// ExportImage exports an image (as a tar file) into the stream. +// +// See https://goo.gl/AuySaA for more details. +func (c *Client) ExportImage(opts ExportImageOptions) error { + return c.stream("GET", fmt.Sprintf("/images/%s/get", opts.Name), streamOptions{ + setRawTerminal: true, + stdout: opts.OutputStream, + inactivityTimeout: opts.InactivityTimeout, + context: opts.Context, + }) +} + +// ExportImagesOptions represent the options for ExportImages Docker API call +// +// See https://goo.gl/N9XlDn for more details. +type ExportImagesOptions struct { + Names []string + OutputStream io.Writer `qs:"-"` + InactivityTimeout time.Duration `qs:"-"` + Context context.Context +} + +// ExportImages exports one or more images (as a tar file) into the stream +// +// See https://goo.gl/N9XlDn for more details. +func (c *Client) ExportImages(opts ExportImagesOptions) error { + if opts.Names == nil || len(opts.Names) == 0 { + return ErrMustSpecifyNames + } + return c.stream("GET", "/images/get?"+queryString(&opts), streamOptions{ + setRawTerminal: true, + stdout: opts.OutputStream, + inactivityTimeout: opts.InactivityTimeout, + }) +} + +// ImportImageOptions present the set of informations available for importing +// an image from a source file or the stdin. +// +// See https://goo.gl/qkoSsn for more details. +type ImportImageOptions struct { + Repository string `qs:"repo"` + Source string `qs:"fromSrc"` + Tag string `qs:"tag"` + + InputStream io.Reader `qs:"-"` + OutputStream io.Writer `qs:"-"` + RawJSONStream bool `qs:"-"` + InactivityTimeout time.Duration `qs:"-"` + Context context.Context +} + +// ImportImage imports an image from a url, a file or stdin +// +// See https://goo.gl/qkoSsn for more details. +func (c *Client) ImportImage(opts ImportImageOptions) error { + if opts.Repository == "" { + return ErrNoSuchImage + } + if opts.Source != "-" { + opts.InputStream = nil + } + if opts.Source != "-" && !isURL(opts.Source) { + f, err := os.Open(opts.Source) + if err != nil { + return err + } + opts.InputStream = f + opts.Source = "-" + } + return c.createImage(queryString(&opts), nil, opts.InputStream, opts.OutputStream, opts.RawJSONStream, opts.InactivityTimeout, opts.Context) +} + +// BuildImageOptions present the set of informations available for building an +// image from a tarfile with a Dockerfile in it. +// +// For more details about the Docker building process, see +// https://goo.gl/4nYHwV. +type BuildImageOptions struct { + Name string `qs:"t"` + Dockerfile string `qs:"dockerfile"` + NoCache bool `qs:"nocache"` + CacheFrom []string `qs:"-"` + SuppressOutput bool `qs:"q"` + Pull bool `qs:"pull"` + RmTmpContainer bool `qs:"rm"` + ForceRmTmpContainer bool `qs:"forcerm"` + RawJSONStream bool `qs:"-"` + Memory int64 `qs:"memory"` + Memswap int64 `qs:"memswap"` + CPUShares int64 `qs:"cpushares"` + CPUQuota int64 `qs:"cpuquota"` + CPUPeriod int64 `qs:"cpuperiod"` + CPUSetCPUs string `qs:"cpusetcpus"` + Labels map[string]string `qs:"labels"` + InputStream io.Reader `qs:"-"` + OutputStream io.Writer `qs:"-"` + Remote string `qs:"remote"` + Auth AuthConfiguration `qs:"-"` // for older docker X-Registry-Auth header + AuthConfigs AuthConfigurations `qs:"-"` // for newer docker X-Registry-Config header + ContextDir string `qs:"-"` + Ulimits []ULimit `qs:"-"` + BuildArgs []BuildArg `qs:"-"` + NetworkMode string `qs:"networkmode"` + InactivityTimeout time.Duration `qs:"-"` + CgroupParent string `qs:"cgroupparent"` + SecurityOpt []string `qs:"securityopt"` + Target string `gs:"target"` + Context context.Context +} + +// BuildArg represents arguments that can be passed to the image when building +// it from a Dockerfile. +// +// For more details about the Docker building process, see +// https://goo.gl/4nYHwV. +type BuildArg struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Value string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"` +} + +// BuildImage builds an image from a tarball's url or a Dockerfile in the input +// stream. +// +// See https://goo.gl/4nYHwV for more details. +func (c *Client) BuildImage(opts BuildImageOptions) error { + if opts.OutputStream == nil { + return ErrMissingOutputStream + } + headers, err := headersWithAuth(opts.Auth, c.versionedAuthConfigs(opts.AuthConfigs)) + if err != nil { + return err + } + + if opts.Remote != "" && opts.Name == "" { + opts.Name = opts.Remote + } + if opts.InputStream != nil || opts.ContextDir != "" { + headers["Content-Type"] = "application/tar" + } else if opts.Remote == "" { + return ErrMissingRepo + } + if opts.ContextDir != "" { + if opts.InputStream != nil { + return ErrMultipleContexts + } + var err error + if opts.InputStream, err = createTarStream(opts.ContextDir, opts.Dockerfile); err != nil { + return err + } + } + qs := queryString(&opts) + + if c.serverAPIVersion.GreaterThanOrEqualTo(apiVersion125) && len(opts.CacheFrom) > 0 { + if b, err := json.Marshal(opts.CacheFrom); err == nil { + item := url.Values(map[string][]string{}) + item.Add("cachefrom", string(b)) + qs = fmt.Sprintf("%s&%s", qs, item.Encode()) + } + } + + if len(opts.Ulimits) > 0 { + if b, err := json.Marshal(opts.Ulimits); err == nil { + item := url.Values(map[string][]string{}) + item.Add("ulimits", string(b)) + qs = fmt.Sprintf("%s&%s", qs, item.Encode()) + } + } + + if len(opts.BuildArgs) > 0 { + v := make(map[string]string) + for _, arg := range opts.BuildArgs { + v[arg.Name] = arg.Value + } + if b, err := json.Marshal(v); err == nil { + item := url.Values(map[string][]string{}) + item.Add("buildargs", string(b)) + qs = fmt.Sprintf("%s&%s", qs, item.Encode()) + } + } + + return c.stream("POST", fmt.Sprintf("/build?%s", qs), streamOptions{ + setRawTerminal: true, + rawJSONStream: opts.RawJSONStream, + headers: headers, + in: opts.InputStream, + stdout: opts.OutputStream, + inactivityTimeout: opts.InactivityTimeout, + context: opts.Context, + }) +} + +func (c *Client) versionedAuthConfigs(authConfigs AuthConfigurations) interface{} { + if c.serverAPIVersion == nil { + c.checkAPIVersion() + } + if c.serverAPIVersion != nil && c.serverAPIVersion.GreaterThanOrEqualTo(apiVersion119) { + return AuthConfigurations119(authConfigs.Configs) + } + return authConfigs +} + +// TagImageOptions present the set of options to tag an image. +// +// See https://goo.gl/prHrvo for more details. +type TagImageOptions struct { + Repo string + Tag string + Force bool + Context context.Context +} + +// TagImage adds a tag to the image identified by the given name. +// +// See https://goo.gl/prHrvo for more details. +func (c *Client) TagImage(name string, opts TagImageOptions) error { + if name == "" { + return ErrNoSuchImage + } + resp, err := c.do("POST", "/images/"+name+"/tag?"+queryString(&opts), doOptions{ + context: opts.Context, + }) + + if err != nil { + return err + } + + defer resp.Body.Close() + + if resp.StatusCode == http.StatusNotFound { + return ErrNoSuchImage + } + + return err +} + +func isURL(u string) bool { + p, err := url.Parse(u) + if err != nil { + return false + } + return p.Scheme == "http" || p.Scheme == "https" +} + +func headersWithAuth(auths ...interface{}) (map[string]string, error) { + var headers = make(map[string]string) + + for _, auth := range auths { + switch auth.(type) { + case AuthConfiguration: + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(auth); err != nil { + return nil, err + } + headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes()) + case AuthConfigurations, AuthConfigurations119: + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(auth); err != nil { + return nil, err + } + headers["X-Registry-Config"] = base64.URLEncoding.EncodeToString(buf.Bytes()) + } + } + + return headers, nil +} + +// APIImageSearch reflect the result of a search on the Docker Hub. +// +// See https://goo.gl/KLO9IZ for more details. +type APIImageSearch struct { + Description string `json:"description,omitempty" yaml:"description,omitempty" toml:"description,omitempty"` + IsOfficial bool `json:"is_official,omitempty" yaml:"is_official,omitempty" toml:"is_official,omitempty"` + IsAutomated bool `json:"is_automated,omitempty" yaml:"is_automated,omitempty" toml:"is_automated,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty" toml:"name,omitempty"` + StarCount int `json:"star_count,omitempty" yaml:"star_count,omitempty" toml:"star_count,omitempty"` +} + +// SearchImages search the docker hub with a specific given term. +// +// See https://goo.gl/KLO9IZ for more details. +func (c *Client) SearchImages(term string) ([]APIImageSearch, error) { + resp, err := c.do("GET", "/images/search?term="+term, doOptions{}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var searchResult []APIImageSearch + if err := json.NewDecoder(resp.Body).Decode(&searchResult); err != nil { + return nil, err + } + return searchResult, nil +} + +// SearchImagesEx search the docker hub with a specific given term and authentication. +// +// See https://goo.gl/KLO9IZ for more details. +func (c *Client) SearchImagesEx(term string, auth AuthConfiguration) ([]APIImageSearch, error) { + headers, err := headersWithAuth(auth) + if err != nil { + return nil, err + } + + resp, err := c.do("GET", "/images/search?term="+term, doOptions{ + headers: headers, + }) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + var searchResult []APIImageSearch + if err := json.NewDecoder(resp.Body).Decode(&searchResult); err != nil { + return nil, err + } + + return searchResult, nil +} + +// PruneImagesOptions specify parameters to the PruneImages function. +// +// See https://goo.gl/qfZlbZ for more details. +type PruneImagesOptions struct { + Filters map[string][]string + Context context.Context +} + +// PruneImagesResults specify results from the PruneImages function. +// +// See https://goo.gl/qfZlbZ for more details. +type PruneImagesResults struct { + ImagesDeleted []struct{ Untagged, Deleted string } + SpaceReclaimed int64 +} + +// PruneImages deletes images which are unused. +// +// See https://goo.gl/qfZlbZ for more details. +func (c *Client) PruneImages(opts PruneImagesOptions) (*PruneImagesResults, error) { + path := "/images/prune?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var results PruneImagesResults + if err := json.NewDecoder(resp.Body).Decode(&results); err != nil { + return nil, err + } + return &results, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive.go new file mode 100644 index 000000000..a13ee7cca --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive.go @@ -0,0 +1,505 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import ( + "archive/tar" + "bufio" + "compress/gzip" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/docker/docker/pkg/fileutils" + "github.com/docker/docker/pkg/idtools" + "github.com/docker/docker/pkg/pools" + "github.com/docker/docker/pkg/system" + "github.com/sirupsen/logrus" +) + +const ( + // Uncompressed represents the uncompressed. + Uncompressed Compression = iota + // Bzip2 is bzip2 compression algorithm. + Bzip2 + // Gzip is gzip compression algorithm. + Gzip + // Xz is xz compression algorithm. + Xz +) + +const ( + modeISDIR = 040000 // Directory + modeISFIFO = 010000 // FIFO + modeISREG = 0100000 // Regular file + modeISLNK = 0120000 // Symbolic link + modeISBLK = 060000 // Block special file + modeISCHR = 020000 // Character special file + modeISSOCK = 0140000 // Socket +) + +// Compression is the state represents if compressed or not. +type Compression int + +// Extension returns the extension of a file that uses the specified compression algorithm. +func (compression *Compression) Extension() string { + switch *compression { + case Uncompressed: + return "tar" + case Bzip2: + return "tar.bz2" + case Gzip: + return "tar.gz" + case Xz: + return "tar.xz" + } + return "" +} + +// WhiteoutFormat is the format of whiteouts unpacked +type WhiteoutFormat int + +// TarOptions wraps the tar options. +type TarOptions struct { + IncludeFiles []string + ExcludePatterns []string + Compression Compression + NoLchown bool + UIDMaps []idtools.IDMap + GIDMaps []idtools.IDMap + ChownOpts *idtools.IDPair + IncludeSourceDir bool + // WhiteoutFormat is the expected on disk format for whiteout files. + // This format will be converted to the standard format on pack + // and from the standard format on unpack. + WhiteoutFormat WhiteoutFormat + // When unpacking, specifies whether overwriting a directory with a + // non-directory is allowed and vice versa. + NoOverwriteDirNonDir bool + // For each include when creating an archive, the included name will be + // replaced with the matching name from this map. + RebaseNames map[string]string + InUserNS bool +} + +// TarWithOptions creates an archive from the directory at `path`, only including files whose relative +// paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`. +func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) { + + // Fix the source path to work with long path names. This is a no-op + // on platforms other than Windows. + srcPath = fixVolumePathPrefix(srcPath) + + pm, err := fileutils.NewPatternMatcher(options.ExcludePatterns) + if err != nil { + return nil, err + } + + pipeReader, pipeWriter := io.Pipe() + + compressWriter, err := CompressStream(pipeWriter, options.Compression) + if err != nil { + return nil, err + } + + go func() { + ta := newTarAppender( + idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps), + compressWriter, + options.ChownOpts, + ) + ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat) + + defer func() { + // Make sure to check the error on Close. + if err := ta.TarWriter.Close(); err != nil { + logrus.Errorf("Can't close tar writer: %s", err) + } + if err := compressWriter.Close(); err != nil { + logrus.Errorf("Can't close compress writer: %s", err) + } + if err := pipeWriter.Close(); err != nil { + logrus.Errorf("Can't close pipe writer: %s", err) + } + }() + + // this buffer is needed for the duration of this piped stream + defer pools.BufioWriter32KPool.Put(ta.Buffer) + + // In general we log errors here but ignore them because + // during e.g. a diff operation the container can continue + // mutating the filesystem and we can see transient errors + // from this + + stat, err := os.Lstat(srcPath) + if err != nil { + return + } + + if !stat.IsDir() { + // We can't later join a non-dir with any includes because the + // 'walk' will error if "file/." is stat-ed and "file" is not a + // directory. So, we must split the source path and use the + // basename as the include. + if len(options.IncludeFiles) > 0 { + logrus.Warn("Tar: Can't archive a file with includes") + } + + dir, base := SplitPathDirEntry(srcPath) + srcPath = dir + options.IncludeFiles = []string{base} + } + + if len(options.IncludeFiles) == 0 { + options.IncludeFiles = []string{"."} + } + + seen := make(map[string]bool) + + for _, include := range options.IncludeFiles { + rebaseName := options.RebaseNames[include] + + walkRoot := getWalkRoot(srcPath, include) + filepath.Walk(walkRoot, func(filePath string, f os.FileInfo, err error) error { + if err != nil { + logrus.Errorf("Tar: Can't stat file %s to tar: %s", srcPath, err) + return nil + } + + relFilePath, err := filepath.Rel(srcPath, filePath) + if err != nil || (!options.IncludeSourceDir && relFilePath == "." && f.IsDir()) { + // Error getting relative path OR we are looking + // at the source directory path. Skip in both situations. + return nil + } + + if options.IncludeSourceDir && include == "." && relFilePath != "." { + relFilePath = strings.Join([]string{".", relFilePath}, string(filepath.Separator)) + } + + skip := false + + // If "include" is an exact match for the current file + // then even if there's an "excludePatterns" pattern that + // matches it, don't skip it. IOW, assume an explicit 'include' + // is asking for that file no matter what - which is true + // for some files, like .dockerignore and Dockerfile (sometimes) + if include != relFilePath { + skip, err = pm.Matches(relFilePath) + if err != nil { + logrus.Errorf("Error matching %s: %v", relFilePath, err) + return err + } + } + + if skip { + // If we want to skip this file and its a directory + // then we should first check to see if there's an + // excludes pattern (e.g. !dir/file) that starts with this + // dir. If so then we can't skip this dir. + + // Its not a dir then so we can just return/skip. + if !f.IsDir() { + return nil + } + + // No exceptions (!...) in patterns so just skip dir + if !pm.Exclusions() { + return filepath.SkipDir + } + + dirSlash := relFilePath + string(filepath.Separator) + + for _, pat := range pm.Patterns() { + if !pat.Exclusion() { + continue + } + if strings.HasPrefix(pat.String()+string(filepath.Separator), dirSlash) { + // found a match - so can't skip this dir + return nil + } + } + + // No matching exclusion dir so just skip dir + return filepath.SkipDir + } + + if seen[relFilePath] { + return nil + } + seen[relFilePath] = true + + // Rename the base resource. + if rebaseName != "" { + var replacement string + if rebaseName != string(filepath.Separator) { + // Special case the root directory to replace with an + // empty string instead so that we don't end up with + // double slashes in the paths. + replacement = rebaseName + } + + relFilePath = strings.Replace(relFilePath, include, replacement, 1) + } + + if err := ta.addTarFile(filePath, relFilePath); err != nil { + logrus.Errorf("Can't add file %s to tar: %s", filePath, err) + // if pipe is broken, stop writing tar stream to it + if err == io.ErrClosedPipe { + return err + } + } + return nil + }) + } + }() + + return pipeReader, nil +} + +// CompressStream compresses the dest with specified compression algorithm. +func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) { + p := pools.BufioWriter32KPool + buf := p.Get(dest) + switch compression { + case Uncompressed: + writeBufWrapper := p.NewWriteCloserWrapper(buf, buf) + return writeBufWrapper, nil + case Gzip: + gzWriter := gzip.NewWriter(dest) + writeBufWrapper := p.NewWriteCloserWrapper(buf, gzWriter) + return writeBufWrapper, nil + case Bzip2, Xz: + // archive/bzip2 does not support writing, and there is no xz support at all + // However, this is not a problem as docker only currently generates gzipped tars + return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension()) + default: + return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension()) + } +} + +type tarWhiteoutConverter interface { + ConvertWrite(*tar.Header, string, os.FileInfo) (*tar.Header, error) + ConvertRead(*tar.Header, string) (bool, error) +} + +type tarAppender struct { + TarWriter *tar.Writer + Buffer *bufio.Writer + + // for hardlink mapping + SeenFiles map[uint64]string + IDMappings *idtools.IDMappings + ChownOpts *idtools.IDPair + + // For packing and unpacking whiteout files in the + // non standard format. The whiteout files defined + // by the AUFS standard are used as the tar whiteout + // standard. + WhiteoutConverter tarWhiteoutConverter +} + +func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender { + return &tarAppender{ + SeenFiles: make(map[uint64]string), + TarWriter: tar.NewWriter(writer), + Buffer: pools.BufioWriter32KPool.Get(nil), + IDMappings: idMapping, + ChownOpts: chownOpts, + } +} + +// addTarFile adds to the tar archive a file from `path` as `name` +func (ta *tarAppender) addTarFile(path, name string) error { + fi, err := os.Lstat(path) + if err != nil { + return err + } + + var link string + if fi.Mode()&os.ModeSymlink != 0 { + var err error + link, err = os.Readlink(path) + if err != nil { + return err + } + } + + hdr, err := FileInfoHeader(name, fi, link) + if err != nil { + return err + } + if err := ReadSecurityXattrToTarHeader(path, hdr); err != nil { + return err + } + + // if it's not a directory and has more than 1 link, + // it's hard linked, so set the type flag accordingly + if !fi.IsDir() && hasHardlinks(fi) { + inode, err := getInodeFromStat(fi.Sys()) + if err != nil { + return err + } + // a link should have a name that it links too + // and that linked name should be first in the tar archive + if oldpath, ok := ta.SeenFiles[inode]; ok { + hdr.Typeflag = tar.TypeLink + hdr.Linkname = oldpath + hdr.Size = 0 // This Must be here for the writer math to add up! + } else { + ta.SeenFiles[inode] = name + } + } + + //check whether the file is overlayfs whiteout + //if yes, skip re-mapping container ID mappings. + isOverlayWhiteout := fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 + + //handle re-mapping container ID mappings back to host ID mappings before + //writing tar headers/files. We skip whiteout files because they were written + //by the kernel and already have proper ownership relative to the host + if !isOverlayWhiteout && + !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && + !ta.IDMappings.Empty() { + fileIDPair, err := getFileUIDGID(fi.Sys()) + if err != nil { + return err + } + hdr.Uid, hdr.Gid, err = ta.IDMappings.ToContainer(fileIDPair) + if err != nil { + return err + } + } + + // explicitly override with ChownOpts + if ta.ChownOpts != nil { + hdr.Uid = ta.ChownOpts.UID + hdr.Gid = ta.ChownOpts.GID + } + + if ta.WhiteoutConverter != nil { + wo, err := ta.WhiteoutConverter.ConvertWrite(hdr, path, fi) + if err != nil { + return err + } + + // If a new whiteout file exists, write original hdr, then + // replace hdr with wo to be written after. Whiteouts should + // always be written after the original. Note the original + // hdr may have been updated to be a whiteout with returning + // a whiteout header + if wo != nil { + if err := ta.TarWriter.WriteHeader(hdr); err != nil { + return err + } + if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 { + return fmt.Errorf("tar: cannot use whiteout for non-empty file") + } + hdr = wo + } + } + + if err := ta.TarWriter.WriteHeader(hdr); err != nil { + return err + } + + if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 { + // We use system.OpenSequential to ensure we use sequential file + // access on Windows to avoid depleting the standby list. + // On Linux, this equates to a regular os.Open. + file, err := system.OpenSequential(path) + if err != nil { + return err + } + + ta.Buffer.Reset(ta.TarWriter) + defer ta.Buffer.Reset(nil) + _, err = io.Copy(ta.Buffer, file) + file.Close() + if err != nil { + return err + } + err = ta.Buffer.Flush() + if err != nil { + return err + } + } + + return nil +} + +// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem +// to a tar header +func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error { + capability, _ := system.Lgetxattr(path, "security.capability") + if capability != nil { + hdr.Xattrs = make(map[string]string) + hdr.Xattrs["security.capability"] = string(capability) + } + return nil +} + +// FileInfoHeader creates a populated Header from fi. +// Compared to archive pkg this function fills in more information. +// Also, regardless of Go version, this function fills file type bits (e.g. hdr.Mode |= modeISDIR), +// which have been deleted since Go 1.9 archive/tar. +func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, error) { + hdr, err := tar.FileInfoHeader(fi, link) + if err != nil { + return nil, err + } + hdr.Mode = fillGo18FileTypeBits(int64(chmodTarEntry(os.FileMode(hdr.Mode))), fi) + name, err = canonicalTarName(name, fi.IsDir()) + if err != nil { + return nil, fmt.Errorf("tar: cannot canonicalize path: %v", err) + } + hdr.Name = name + if err := setHeaderForSpecialDevice(hdr, name, fi.Sys()); err != nil { + return nil, err + } + return hdr, nil +} + +// fillGo18FileTypeBits fills type bits which have been removed on Go 1.9 archive/tar +// https://github.com/golang/go/commit/66b5a2f +func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 { + fm := fi.Mode() + switch { + case fm.IsRegular(): + mode |= modeISREG + case fi.IsDir(): + mode |= modeISDIR + case fm&os.ModeSymlink != 0: + mode |= modeISLNK + case fm&os.ModeDevice != 0: + if fm&os.ModeCharDevice != 0 { + mode |= modeISCHR + } else { + mode |= modeISBLK + } + case fm&os.ModeNamedPipe != 0: + mode |= modeISFIFO + case fm&os.ModeSocket != 0: + mode |= modeISSOCK + } + return mode +} + +// canonicalTarName provides a platform-independent and consistent posix-style +//path for files and directories to be archived regardless of the platform. +func canonicalTarName(name string, isDir bool) (string, error) { + name, err := CanonicalTarNameForPath(name) + if err != nil { + return "", err + } + + // suffix with '/' for directories + if isDir && !strings.HasSuffix(name, "/") { + name += "/" + } + return name, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_linux.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_linux.go new file mode 100644 index 000000000..9e1f3f2f1 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_linux.go @@ -0,0 +1,104 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import ( + "archive/tar" + "os" + "path/filepath" + "strings" + + "github.com/docker/docker/pkg/system" + "golang.org/x/sys/unix" +) + +const ( + // AUFSWhiteoutFormat is the default format for whiteouts + AUFSWhiteoutFormat WhiteoutFormat = iota + // OverlayWhiteoutFormat formats whiteout according to the overlay + // standard. + OverlayWhiteoutFormat +) + +func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter { + if format == OverlayWhiteoutFormat { + return overlayWhiteoutConverter{} + } + return nil +} + +type overlayWhiteoutConverter struct{} + +func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, err error) { + // convert whiteouts to AUFS format + if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 { + // we just rename the file and make it normal + dir, filename := filepath.Split(hdr.Name) + hdr.Name = filepath.Join(dir, WhiteoutPrefix+filename) + hdr.Mode = 0600 + hdr.Typeflag = tar.TypeReg + hdr.Size = 0 + } + + if fi.Mode()&os.ModeDir != 0 { + // convert opaque dirs to AUFS format by writing an empty file with the prefix + opaque, err := system.Lgetxattr(path, "trusted.overlay.opaque") + if err != nil { + return nil, err + } + if len(opaque) == 1 && opaque[0] == 'y' { + if hdr.Xattrs != nil { + delete(hdr.Xattrs, "trusted.overlay.opaque") + } + + // create a header for the whiteout file + // it should inherit some properties from the parent, but be a regular file + wo = &tar.Header{ + Typeflag: tar.TypeReg, + Mode: hdr.Mode & int64(os.ModePerm), + Name: filepath.Join(hdr.Name, WhiteoutOpaqueDir), + Size: 0, + Uid: hdr.Uid, + Uname: hdr.Uname, + Gid: hdr.Gid, + Gname: hdr.Gname, + AccessTime: hdr.AccessTime, + ChangeTime: hdr.ChangeTime, + } + } + } + + return +} + +func (overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) { + base := filepath.Base(path) + dir := filepath.Dir(path) + + // if a directory is marked as opaque by the AUFS special file, we need to translate that to overlay + if base == WhiteoutOpaqueDir { + err := unix.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0) + // don't write the file itself + return false, err + } + + // if a file was deleted and we are using overlay, we need to create a character device + if strings.HasPrefix(base, WhiteoutPrefix) { + originalBase := base[len(WhiteoutPrefix):] + originalPath := filepath.Join(dir, originalBase) + + if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil { + return false, err + } + if err := os.Chown(originalPath, hdr.Uid, hdr.Gid); err != nil { + return false, err + } + + // don't write the file itself + return false, nil + } + + return true, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_other.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_other.go new file mode 100644 index 000000000..72822c857 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_other.go @@ -0,0 +1,11 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +// +build !linux + +package archive + +func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter { + return nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_unix.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_unix.go new file mode 100644 index 000000000..2633f5020 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_unix.go @@ -0,0 +1,77 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +// +build !windows + +package archive + +import ( + "archive/tar" + "errors" + "os" + "path/filepath" + "syscall" + + "github.com/docker/docker/pkg/idtools" + "golang.org/x/sys/unix" +) + +// CanonicalTarNameForPath returns platform-specific filepath +// to canonical posix-style path for tar archival. p is relative +// path. +func CanonicalTarNameForPath(p string) (string, error) { + return p, nil // already unix-style +} + +// fixVolumePathPrefix does platform specific processing to ensure that if +// the path being passed in is not in a volume path format, convert it to one. +func fixVolumePathPrefix(srcPath string) string { + return srcPath +} + +// getWalkRoot calculates the root path when performing a TarWithOptions. +// We use a separate function as this is platform specific. On Linux, we +// can't use filepath.Join(srcPath,include) because this will clean away +// a trailing "." or "/" which may be important. +func getWalkRoot(srcPath string, include string) string { + return srcPath + string(filepath.Separator) + include +} + +func getInodeFromStat(stat interface{}) (inode uint64, err error) { + s, ok := stat.(*syscall.Stat_t) + + if ok { + inode = uint64(s.Ino) + } + + return +} + +func getFileUIDGID(stat interface{}) (idtools.IDPair, error) { + s, ok := stat.(*syscall.Stat_t) + + if !ok { + return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t") + } + return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil +} + +func chmodTarEntry(perm os.FileMode) os.FileMode { + return perm // noop for unix as golang APIs provide perm bits correctly +} + +func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (err error) { + s, ok := stat.(*syscall.Stat_t) + + if ok { + // Currently go does not fill in the major/minors + if s.Mode&unix.S_IFBLK != 0 || + s.Mode&unix.S_IFCHR != 0 { + hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) // nolint: unconvert + hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) // nolint: unconvert + } + } + + return +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_windows.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_windows.go new file mode 100644 index 000000000..c14875cd7 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_windows.go @@ -0,0 +1,71 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import ( + "archive/tar" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/docker/docker/pkg/idtools" + "github.com/docker/docker/pkg/longpath" +) + +// CanonicalTarNameForPath returns platform-specific filepath +// to canonical posix-style path for tar archival. p is relative +// path. +func CanonicalTarNameForPath(p string) (string, error) { + // windows: convert windows style relative path with backslashes + // into forward slashes. Since windows does not allow '/' or '\' + // in file names, it is mostly safe to replace however we must + // check just in case + if strings.Contains(p, "/") { + return "", fmt.Errorf("Windows path contains forward slash: %s", p) + } + return strings.Replace(p, string(os.PathSeparator), "/", -1), nil + +} + +// fixVolumePathPrefix does platform specific processing to ensure that if +// the path being passed in is not in a volume path format, convert it to one. +func fixVolumePathPrefix(srcPath string) string { + return longpath.AddPrefix(srcPath) +} + +// getWalkRoot calculates the root path when performing a TarWithOptions. +// We use a separate function as this is platform specific. +func getWalkRoot(srcPath string, include string) string { + return filepath.Join(srcPath, include) +} + +func getInodeFromStat(stat interface{}) (inode uint64, err error) { + // do nothing. no notion of Inode in stat on Windows + return +} + +func getFileUIDGID(stat interface{}) (idtools.IDPair, error) { + // no notion of file ownership mapping yet on Windows + return idtools.IDPair{0, 0}, nil +} + +// chmodTarEntry is used to adjust the file permissions used in tar header based +// on the platform the archival is done. +func chmodTarEntry(perm os.FileMode) os.FileMode { + //perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.) + permPart := perm & os.ModePerm + noPermPart := perm &^ os.ModePerm + // Add the x bit: make everything +x from windows + permPart |= 0111 + permPart &= 0755 + + return noPermPart | permPart +} + +func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (err error) { + // do nothing. no notion of Rdev, Nlink in stat on Windows + return +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_unix.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_unix.go new file mode 100644 index 000000000..39ea287bf --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_unix.go @@ -0,0 +1,16 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +// +build !windows + +package archive + +import ( + "os" + "syscall" +) + +func hasHardlinks(fi os.FileInfo) bool { + return fi.Sys().(*syscall.Stat_t).Nlink > 1 +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_windows.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_windows.go new file mode 100644 index 000000000..a93130474 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_windows.go @@ -0,0 +1,11 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import "os" + +func hasHardlinks(fi os.FileInfo) bool { + return false +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/copy.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/copy.go new file mode 100644 index 000000000..45d45f20e --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/copy.go @@ -0,0 +1,29 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import ( + "os" + "path/filepath" +) + +// SplitPathDirEntry splits the given path between its directory name and its +// basename by first cleaning the path but preserves a trailing "." if the +// original path specified the current directory. +func SplitPathDirEntry(path string) (dir, base string) { + cleanedPath := filepath.Clean(filepath.FromSlash(path)) + + if specifiesCurrentDir(path) { + cleanedPath += string(os.PathSeparator) + "." + } + + return filepath.Dir(cleanedPath), filepath.Base(cleanedPath) +} + +// specifiesCurrentDir returns whether the given path specifies +// a "current directory", i.e., the last path segment is `.`. +func specifiesCurrentDir(path string) bool { + return filepath.Base(path) == "." +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/whiteouts.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/whiteouts.go new file mode 100644 index 000000000..a61c22a08 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/whiteouts.go @@ -0,0 +1,27 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +// Whiteouts are files with a special meaning for the layered filesystem. +// Docker uses AUFS whiteout files inside exported archives. In other +// filesystems these files are generated/handled on tar creation/extraction. + +// WhiteoutPrefix prefix means file is a whiteout. If this is followed by a +// filename this means that file has been removed from the base layer. +const WhiteoutPrefix = ".wh." + +// WhiteoutMetaPrefix prefix means whiteout has a special meaning and is not +// for removing an actual file. Normally these files are excluded from exported +// archives. +const WhiteoutMetaPrefix = WhiteoutPrefix + WhiteoutPrefix + +// WhiteoutLinkDir is a directory AUFS uses for storing hardlink links to other +// layers. Normally these should not go into exported archives and all changed +// hardlinks should be copied to the top layer. +const WhiteoutLinkDir = WhiteoutMetaPrefix + "plnk" + +// WhiteoutOpaqueDir file means directory has been made opaque - meaning +// readdir calls to this directory do not follow to lower layers. +const WhiteoutOpaqueDir = WhiteoutMetaPrefix + ".opq" diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/jsonmessage/jsonmessage.go b/vendor/github.com/fsouza/go-dockerclient/internal/jsonmessage/jsonmessage.go new file mode 100644 index 000000000..71b3395ce --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/jsonmessage/jsonmessage.go @@ -0,0 +1,339 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package jsonmessage + +import ( + "encoding/json" + "fmt" + "io" + "os" + "strings" + "time" + + "github.com/Nvveen/Gotty" + "github.com/docker/go-units" + "github.com/fsouza/go-dockerclient/internal/term" +) + +// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to +// ensure the formatted time isalways the same number of characters. +const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00" + +// JSONError wraps a concrete Code and Message, `Code` is +// is an integer error code, `Message` is the error message. +type JSONError struct { + Code int `json:"code,omitempty"` + Message string `json:"message,omitempty"` +} + +func (e *JSONError) Error() string { + return e.Message +} + +// JSONProgress describes a Progress. terminalFd is the fd of the current terminal, +// Start is the initial value for the operation. Current is the current status and +// value of the progress made towards Total. Total is the end value describing when +// we made 100% progress for an operation. +type JSONProgress struct { + terminalFd uintptr + Current int64 `json:"current,omitempty"` + Total int64 `json:"total,omitempty"` + Start int64 `json:"start,omitempty"` + // If true, don't show xB/yB + HideCounts bool `json:"hidecounts,omitempty"` + Units string `json:"units,omitempty"` + nowFunc func() time.Time + winSize int +} + +func (p *JSONProgress) String() string { + var ( + width = p.width() + pbBox string + numbersBox string + timeLeftBox string + ) + if p.Current <= 0 && p.Total <= 0 { + return "" + } + if p.Total <= 0 { + switch p.Units { + case "": + current := units.HumanSize(float64(p.Current)) + return fmt.Sprintf("%8v", current) + default: + return fmt.Sprintf("%d %s", p.Current, p.Units) + } + } + + percentage := int(float64(p.Current)/float64(p.Total)*100) / 2 + if percentage > 50 { + percentage = 50 + } + if width > 110 { + // this number can't be negative gh#7136 + numSpaces := 0 + if 50-percentage > 0 { + numSpaces = 50 - percentage + } + pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces)) + } + + switch { + case p.HideCounts: + case p.Units == "": // no units, use bytes + current := units.HumanSize(float64(p.Current)) + total := units.HumanSize(float64(p.Total)) + + numbersBox = fmt.Sprintf("%8v/%v", current, total) + + if p.Current > p.Total { + // remove total display if the reported current is wonky. + numbersBox = fmt.Sprintf("%8v", current) + } + default: + numbersBox = fmt.Sprintf("%d/%d %s", p.Current, p.Total, p.Units) + + if p.Current > p.Total { + // remove total display if the reported current is wonky. + numbersBox = fmt.Sprintf("%d %s", p.Current, p.Units) + } + } + + if p.Current > 0 && p.Start > 0 && percentage < 50 { + fromStart := p.now().Sub(time.Unix(p.Start, 0)) + perEntry := fromStart / time.Duration(p.Current) + left := time.Duration(p.Total-p.Current) * perEntry + left = (left / time.Second) * time.Second + + if width > 50 { + timeLeftBox = " " + left.String() + } + } + return pbBox + numbersBox + timeLeftBox +} + +// shim for testing +func (p *JSONProgress) now() time.Time { + if p.nowFunc == nil { + p.nowFunc = func() time.Time { + return time.Now().UTC() + } + } + return p.nowFunc() +} + +// shim for testing +func (p *JSONProgress) width() int { + if p.winSize != 0 { + return p.winSize + } + ws, err := term.GetWinsize(p.terminalFd) + if err == nil { + return int(ws.Width) + } + return 200 +} + +// JSONMessage defines a message struct. It describes +// the created time, where it from, status, ID of the +// message. It's used for docker events. +type JSONMessage struct { + Stream string `json:"stream,omitempty"` + Status string `json:"status,omitempty"` + Progress *JSONProgress `json:"progressDetail,omitempty"` + ProgressMessage string `json:"progress,omitempty"` //deprecated + ID string `json:"id,omitempty"` + From string `json:"from,omitempty"` + Time int64 `json:"time,omitempty"` + TimeNano int64 `json:"timeNano,omitempty"` + Error *JSONError `json:"errorDetail,omitempty"` + ErrorMessage string `json:"error,omitempty"` //deprecated + // Aux contains out-of-band data, such as digests for push signing and image id after building. + Aux *json.RawMessage `json:"aux,omitempty"` +} + +/* Satisfied by gotty.TermInfo as well as noTermInfo from below */ +type termInfo interface { + Parse(attr string, params ...interface{}) (string, error) +} + +type noTermInfo struct{} // canary used when no terminfo. + +func (ti *noTermInfo) Parse(attr string, params ...interface{}) (string, error) { + return "", fmt.Errorf("noTermInfo") +} + +func clearLine(out io.Writer, ti termInfo) { + // el2 (clear whole line) is not exposed by terminfo. + + // First clear line from beginning to cursor + if attr, err := ti.Parse("el1"); err == nil { + fmt.Fprintf(out, "%s", attr) + } else { + fmt.Fprintf(out, "\x1b[1K") + } + // Then clear line from cursor to end + if attr, err := ti.Parse("el"); err == nil { + fmt.Fprintf(out, "%s", attr) + } else { + fmt.Fprintf(out, "\x1b[K") + } +} + +func cursorUp(out io.Writer, ti termInfo, l int) { + if l == 0 { // Should never be the case, but be tolerant + return + } + if attr, err := ti.Parse("cuu", l); err == nil { + fmt.Fprintf(out, "%s", attr) + } else { + fmt.Fprintf(out, "\x1b[%dA", l) + } +} + +func cursorDown(out io.Writer, ti termInfo, l int) { + if l == 0 { // Should never be the case, but be tolerant + return + } + if attr, err := ti.Parse("cud", l); err == nil { + fmt.Fprintf(out, "%s", attr) + } else { + fmt.Fprintf(out, "\x1b[%dB", l) + } +} + +// Display displays the JSONMessage to `out`. `termInfo` is non-nil if `out` +// is a terminal. If this is the case, it will erase the entire current line +// when displaying the progressbar. +func (jm *JSONMessage) Display(out io.Writer, termInfo termInfo) error { + if jm.Error != nil { + if jm.Error.Code == 401 { + return fmt.Errorf("authentication is required") + } + return jm.Error + } + var endl string + if termInfo != nil && jm.Stream == "" && jm.Progress != nil { + clearLine(out, termInfo) + endl = "\r" + fmt.Fprintf(out, endl) + } else if jm.Progress != nil && jm.Progress.String() != "" { //disable progressbar in non-terminal + return nil + } + if jm.TimeNano != 0 { + fmt.Fprintf(out, "%s ", time.Unix(0, jm.TimeNano).Format(RFC3339NanoFixed)) + } else if jm.Time != 0 { + fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(RFC3339NanoFixed)) + } + if jm.ID != "" { + fmt.Fprintf(out, "%s: ", jm.ID) + } + if jm.From != "" { + fmt.Fprintf(out, "(from %s) ", jm.From) + } + if jm.Progress != nil && termInfo != nil { + fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl) + } else if jm.ProgressMessage != "" { //deprecated + fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl) + } else if jm.Stream != "" { + fmt.Fprintf(out, "%s%s", jm.Stream, endl) + } else { + fmt.Fprintf(out, "%s%s\n", jm.Status, endl) + } + return nil +} + +// DisplayJSONMessagesStream displays a json message stream from `in` to `out`, `isTerminal` +// describes if `out` is a terminal. If this is the case, it will print `\n` at the end of +// each line and move the cursor while displaying. +func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(JSONMessage)) error { + var ( + dec = json.NewDecoder(in) + ids = make(map[string]int) + ) + + var termInfo termInfo + + if isTerminal { + term := os.Getenv("TERM") + if term == "" { + term = "vt102" + } + + var err error + if termInfo, err = gotty.OpenTermInfo(term); err != nil { + termInfo = &noTermInfo{} + } + } + + for { + diff := 0 + var jm JSONMessage + if err := dec.Decode(&jm); err != nil { + if err == io.EOF { + break + } + return err + } + + if jm.Aux != nil { + if auxCallback != nil { + auxCallback(jm) + } + continue + } + + if jm.Progress != nil { + jm.Progress.terminalFd = terminalFd + } + if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") { + line, ok := ids[jm.ID] + if !ok { + // NOTE: This approach of using len(id) to + // figure out the number of lines of history + // only works as long as we clear the history + // when we output something that's not + // accounted for in the map, such as a line + // with no ID. + line = len(ids) + ids[jm.ID] = line + if termInfo != nil { + fmt.Fprintf(out, "\n") + } + } + diff = len(ids) - line + if termInfo != nil { + cursorUp(out, termInfo, diff) + } + } else { + // When outputting something that isn't progress + // output, clear the history of previous lines. We + // don't want progress entries from some previous + // operation to be updated (for example, pull -a + // with multiple tags). + ids = make(map[string]int) + } + err := jm.Display(out, termInfo) + if jm.ID != "" && termInfo != nil { + cursorDown(out, termInfo, diff) + } + if err != nil { + return err + } + } + return nil +} + +type stream interface { + io.Writer + FD() uintptr + IsTerminal() bool +} + +// DisplayJSONMessagesToStream prints json messages to the output stream +func DisplayJSONMessagesToStream(in io.Reader, stream stream, auxCallback func(JSONMessage)) error { + return DisplayJSONMessagesStream(in, stream, stream.FD(), stream.IsTerminal(), auxCallback) +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/term/term.go b/vendor/github.com/fsouza/go-dockerclient/internal/term/term.go new file mode 100644 index 000000000..af06911d8 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/term/term.go @@ -0,0 +1,13 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package term + +// Winsize represents the size of the terminal window. +type Winsize struct { + Height uint16 + Width uint16 + x uint16 + y uint16 +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize.go b/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize.go new file mode 100644 index 000000000..2a9964a0d --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize.go @@ -0,0 +1,16 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +// +build !windows + +package term + +import "golang.org/x/sys/unix" + +// GetWinsize returns the window size based on the specified file descriptor. +func GetWinsize(fd uintptr) (*Winsize, error) { + uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) + ws := &Winsize{Height: uws.Row, Width: uws.Col, x: uws.Xpixel, y: uws.Ypixel} + return ws, err +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize_windows.go b/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize_windows.go new file mode 100644 index 000000000..4a07a5d19 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize_windows.go @@ -0,0 +1,22 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package term + +import "github.com/Azure/go-ansiterm/winterm" + +// GetWinsize returns the window size based on the specified file descriptor. +func GetWinsize(fd uintptr) (*Winsize, error) { + info, err := winterm.GetConsoleScreenBufferInfo(fd) + if err != nil { + return nil, err + } + + winsize := &Winsize{ + Width: uint16(info.Window.Right - info.Window.Left + 1), + Height: uint16(info.Window.Bottom - info.Window.Top + 1), + } + + return winsize, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/misc.go b/vendor/github.com/fsouza/go-dockerclient/misc.go new file mode 100644 index 000000000..1fc37b14e --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/misc.go @@ -0,0 +1,188 @@ +// Copyright 2013 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "net" + "strings" + + "github.com/docker/docker/api/types/swarm" +) + +// Version returns version information about the docker server. +// +// See https://goo.gl/mU7yje for more details. +func (c *Client) Version() (*Env, error) { + return c.VersionWithContext(nil) +} + +// VersionWithContext returns version information about the docker server. +func (c *Client) VersionWithContext(ctx context.Context) (*Env, error) { + resp, err := c.do("GET", "/version", doOptions{context: ctx}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var env Env + if err := env.Decode(resp.Body); err != nil { + return nil, err + } + return &env, nil +} + +// DockerInfo contains information about the Docker server +// +// See https://goo.gl/bHUoz9 for more details. +type DockerInfo struct { + ID string + Containers int + ContainersRunning int + ContainersPaused int + ContainersStopped int + Images int + Driver string + DriverStatus [][2]string + SystemStatus [][2]string + Plugins PluginsInfo + MemoryLimit bool + SwapLimit bool + KernelMemory bool + CPUCfsPeriod bool `json:"CpuCfsPeriod"` + CPUCfsQuota bool `json:"CpuCfsQuota"` + CPUShares bool + CPUSet bool + IPv4Forwarding bool + BridgeNfIptables bool + BridgeNfIP6tables bool `json:"BridgeNfIp6tables"` + Debug bool + OomKillDisable bool + ExperimentalBuild bool + NFd int + NGoroutines int + SystemTime string + ExecutionDriver string + LoggingDriver string + CgroupDriver string + NEventsListener int + KernelVersion string + OperatingSystem string + OSType string + Architecture string + IndexServerAddress string + RegistryConfig *ServiceConfig + SecurityOptions []string + NCPU int + MemTotal int64 + DockerRootDir string + HTTPProxy string `json:"HttpProxy"` + HTTPSProxy string `json:"HttpsProxy"` + NoProxy string + Name string + Labels []string + ServerVersion string + ClusterStore string + ClusterAdvertise string + Isolation string + InitBinary string + DefaultRuntime string + LiveRestoreEnabled bool + Swarm swarm.Info +} + +// PluginsInfo is a struct with the plugins registered with the docker daemon +// +// for more information, see: https://goo.gl/bHUoz9 +type PluginsInfo struct { + // List of Volume plugins registered + Volume []string + // List of Network plugins registered + Network []string + // List of Authorization plugins registered + Authorization []string +} + +// ServiceConfig stores daemon registry services configuration. +// +// for more information, see: https://goo.gl/7iFFDz +type ServiceConfig struct { + InsecureRegistryCIDRs []*NetIPNet + IndexConfigs map[string]*IndexInfo + Mirrors []string +} + +// NetIPNet is the net.IPNet type, which can be marshalled and +// unmarshalled to JSON. +// +// for more information, see: https://goo.gl/7iFFDz +type NetIPNet net.IPNet + +// MarshalJSON returns the JSON representation of the IPNet. +// +func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) { + return json.Marshal((*net.IPNet)(ipnet).String()) +} + +// UnmarshalJSON sets the IPNet from a byte array of JSON. +// +func (ipnet *NetIPNet) UnmarshalJSON(b []byte) (err error) { + var ipnetStr string + if err = json.Unmarshal(b, &ipnetStr); err == nil { + var cidr *net.IPNet + if _, cidr, err = net.ParseCIDR(ipnetStr); err == nil { + *ipnet = NetIPNet(*cidr) + } + } + return +} + +// IndexInfo contains information about a registry. +// +// for more information, see: https://goo.gl/7iFFDz +type IndexInfo struct { + Name string + Mirrors []string + Secure bool + Official bool +} + +// Info returns system-wide information about the Docker server. +// +// See https://goo.gl/ElTHi2 for more details. +func (c *Client) Info() (*DockerInfo, error) { + resp, err := c.do("GET", "/info", doOptions{}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var info DockerInfo + if err := json.NewDecoder(resp.Body).Decode(&info); err != nil { + return nil, err + } + return &info, nil +} + +// ParseRepositoryTag gets the name of the repository and returns it splitted +// in two parts: the repository and the tag. It ignores the digest when it is +// present. +// +// Some examples: +// +// localhost.localdomain:5000/samalba/hipache:latest -> localhost.localdomain:5000/samalba/hipache, latest +// localhost.localdomain:5000/samalba/hipache -> localhost.localdomain:5000/samalba/hipache, "" +// busybox:latest@sha256:4a731fb46adc5cefe3ae374a8b6020fc1b6ad667a279647766e9a3cd89f6fa92 -> busybox, latest +func ParseRepositoryTag(repoTag string) (repository string, tag string) { + parts := strings.SplitN(repoTag, "@", 2) + repoTag = parts[0] + n := strings.LastIndex(repoTag, ":") + if n < 0 { + return repoTag, "" + } + if tag := repoTag[n+1:]; !strings.Contains(tag, "/") { + return repoTag[:n], tag + } + return repoTag, "" +} diff --git a/vendor/github.com/fsouza/go-dockerclient/network.go b/vendor/github.com/fsouza/go-dockerclient/network.go new file mode 100644 index 000000000..c6ddb22c6 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/network.go @@ -0,0 +1,321 @@ +// Copyright 2015 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/http" +) + +// ErrNetworkAlreadyExists is the error returned by CreateNetwork when the +// network already exists. +var ErrNetworkAlreadyExists = errors.New("network already exists") + +// Network represents a network. +// +// See https://goo.gl/6GugX3 for more details. +type Network struct { + Name string + ID string `json:"Id"` + Scope string + Driver string + IPAM IPAMOptions + Containers map[string]Endpoint + Options map[string]string + Internal bool + EnableIPv6 bool `json:"EnableIPv6"` + Labels map[string]string +} + +// Endpoint contains network resources allocated and used for a container in a network +// +// See https://goo.gl/6GugX3 for more details. +type Endpoint struct { + Name string + ID string `json:"EndpointID"` + MacAddress string + IPv4Address string + IPv6Address string +} + +// ListNetworks returns all networks. +// +// See https://goo.gl/6GugX3 for more details. +func (c *Client) ListNetworks() ([]Network, error) { + resp, err := c.do("GET", "/networks", doOptions{}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var networks []Network + if err := json.NewDecoder(resp.Body).Decode(&networks); err != nil { + return nil, err + } + return networks, nil +} + +// NetworkFilterOpts is an aggregation of key=value that Docker +// uses to filter networks +type NetworkFilterOpts map[string]map[string]bool + +// FilteredListNetworks returns all networks with the filters applied +// +// See goo.gl/zd2mx4 for more details. +func (c *Client) FilteredListNetworks(opts NetworkFilterOpts) ([]Network, error) { + params, err := json.Marshal(opts) + if err != nil { + return nil, err + } + path := "/networks?filters=" + string(params) + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var networks []Network + if err := json.NewDecoder(resp.Body).Decode(&networks); err != nil { + return nil, err + } + return networks, nil +} + +// NetworkInfo returns information about a network by its ID. +// +// See https://goo.gl/6GugX3 for more details. +func (c *Client) NetworkInfo(id string) (*Network, error) { + path := "/networks/" + id + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchNetwork{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var network Network + if err := json.NewDecoder(resp.Body).Decode(&network); err != nil { + return nil, err + } + return &network, nil +} + +// CreateNetworkOptions specify parameters to the CreateNetwork function and +// (for now) is the expected body of the "create network" http request message +// +// See https://goo.gl/6GugX3 for more details. +type CreateNetworkOptions struct { + Name string `json:"Name" yaml:"Name" toml:"Name"` + Driver string `json:"Driver" yaml:"Driver" toml:"Driver"` + IPAM *IPAMOptions `json:"IPAM,omitempty" yaml:"IPAM" toml:"IPAM"` + Options map[string]interface{} `json:"Options" yaml:"Options" toml:"Options"` + Labels map[string]string `json:"Labels" yaml:"Labels" toml:"Labels"` + CheckDuplicate bool `json:"CheckDuplicate" yaml:"CheckDuplicate" toml:"CheckDuplicate"` + Internal bool `json:"Internal" yaml:"Internal" toml:"Internal"` + EnableIPv6 bool `json:"EnableIPv6" yaml:"EnableIPv6" toml:"EnableIPv6"` + Context context.Context `json:"-"` +} + +// IPAMOptions controls IP Address Management when creating a network +// +// See https://goo.gl/T8kRVH for more details. +type IPAMOptions struct { + Driver string `json:"Driver" yaml:"Driver" toml:"Driver"` + Config []IPAMConfig `json:"Config" yaml:"Config" toml:"Config"` + Options map[string]string `json:"Options" yaml:"Options" toml:"Options"` +} + +// IPAMConfig represents IPAM configurations +// +// See https://goo.gl/T8kRVH for more details. +type IPAMConfig struct { + Subnet string `json:",omitempty"` + IPRange string `json:",omitempty"` + Gateway string `json:",omitempty"` + AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"` +} + +// CreateNetwork creates a new network, returning the network instance, +// or an error in case of failure. +// +// See https://goo.gl/6GugX3 for more details. +func (c *Client) CreateNetwork(opts CreateNetworkOptions) (*Network, error) { + resp, err := c.do( + "POST", + "/networks/create", + doOptions{ + data: opts, + context: opts.Context, + }, + ) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + type createNetworkResponse struct { + ID string + } + var ( + network Network + cnr createNetworkResponse + ) + if err := json.NewDecoder(resp.Body).Decode(&cnr); err != nil { + return nil, err + } + + network.Name = opts.Name + network.ID = cnr.ID + network.Driver = opts.Driver + + return &network, nil +} + +// RemoveNetwork removes a network or returns an error in case of failure. +// +// See https://goo.gl/6GugX3 for more details. +func (c *Client) RemoveNetwork(id string) error { + resp, err := c.do("DELETE", "/networks/"+id, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchNetwork{ID: id} + } + return err + } + resp.Body.Close() + return nil +} + +// NetworkConnectionOptions specify parameters to the ConnectNetwork and +// DisconnectNetwork function. +// +// See https://goo.gl/RV7BJU for more details. +type NetworkConnectionOptions struct { + Container string + + // EndpointConfig is only applicable to the ConnectNetwork call + EndpointConfig *EndpointConfig `json:"EndpointConfig,omitempty"` + + // Force is only applicable to the DisconnectNetwork call + Force bool + + Context context.Context `json:"-"` +} + +// EndpointConfig stores network endpoint details +// +// See https://goo.gl/RV7BJU for more details. +type EndpointConfig struct { + IPAMConfig *EndpointIPAMConfig `json:"IPAMConfig,omitempty" yaml:"IPAMConfig,omitempty" toml:"IPAMConfig,omitempty"` + Links []string `json:"Links,omitempty" yaml:"Links,omitempty" toml:"Links,omitempty"` + Aliases []string `json:"Aliases,omitempty" yaml:"Aliases,omitempty" toml:"Aliases,omitempty"` + NetworkID string `json:"NetworkID,omitempty" yaml:"NetworkID,omitempty" toml:"NetworkID,omitempty"` + EndpointID string `json:"EndpointID,omitempty" yaml:"EndpointID,omitempty" toml:"EndpointID,omitempty"` + Gateway string `json:"Gateway,omitempty" yaml:"Gateway,omitempty" toml:"Gateway,omitempty"` + IPAddress string `json:"IPAddress,omitempty" yaml:"IPAddress,omitempty" toml:"IPAddress,omitempty"` + IPPrefixLen int `json:"IPPrefixLen,omitempty" yaml:"IPPrefixLen,omitempty" toml:"IPPrefixLen,omitempty"` + IPv6Gateway string `json:"IPv6Gateway,omitempty" yaml:"IPv6Gateway,omitempty" toml:"IPv6Gateway,omitempty"` + GlobalIPv6Address string `json:"GlobalIPv6Address,omitempty" yaml:"GlobalIPv6Address,omitempty" toml:"GlobalIPv6Address,omitempty"` + GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen,omitempty" yaml:"GlobalIPv6PrefixLen,omitempty" toml:"GlobalIPv6PrefixLen,omitempty"` + MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty" toml:"MacAddress,omitempty"` +} + +// EndpointIPAMConfig represents IPAM configurations for an +// endpoint +// +// See https://goo.gl/RV7BJU for more details. +type EndpointIPAMConfig struct { + IPv4Address string `json:",omitempty"` + IPv6Address string `json:",omitempty"` +} + +// ConnectNetwork adds a container to a network or returns an error in case of +// failure. +// +// See https://goo.gl/6GugX3 for more details. +func (c *Client) ConnectNetwork(id string, opts NetworkConnectionOptions) error { + resp, err := c.do("POST", "/networks/"+id+"/connect", doOptions{ + data: opts, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container} + } + return err + } + resp.Body.Close() + return nil +} + +// DisconnectNetwork removes a container from a network or returns an error in +// case of failure. +// +// See https://goo.gl/6GugX3 for more details. +func (c *Client) DisconnectNetwork(id string, opts NetworkConnectionOptions) error { + resp, err := c.do("POST", "/networks/"+id+"/disconnect", doOptions{data: opts}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container} + } + return err + } + resp.Body.Close() + return nil +} + +// PruneNetworksOptions specify parameters to the PruneNetworks function. +// +// See https://goo.gl/kX0S9h for more details. +type PruneNetworksOptions struct { + Filters map[string][]string + Context context.Context +} + +// PruneNetworksResults specify results from the PruneNetworks function. +// +// See https://goo.gl/kX0S9h for more details. +type PruneNetworksResults struct { + NetworksDeleted []string +} + +// PruneNetworks deletes networks which are unused. +// +// See https://goo.gl/kX0S9h for more details. +func (c *Client) PruneNetworks(opts PruneNetworksOptions) (*PruneNetworksResults, error) { + path := "/networks/prune?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var results PruneNetworksResults + if err := json.NewDecoder(resp.Body).Decode(&results); err != nil { + return nil, err + } + return &results, nil +} + +// NoSuchNetwork is the error returned when a given network does not exist. +type NoSuchNetwork struct { + ID string +} + +func (err *NoSuchNetwork) Error() string { + return fmt.Sprintf("No such network: %s", err.ID) +} + +// NoSuchNetworkOrContainer is the error returned when a given network or +// container does not exist. +type NoSuchNetworkOrContainer struct { + NetworkID string + ContainerID string +} + +func (err *NoSuchNetworkOrContainer) Error() string { + return fmt.Sprintf("No such network (%s) or container (%s)", err.NetworkID, err.ContainerID) +} diff --git a/vendor/github.com/fsouza/go-dockerclient/plugin.go b/vendor/github.com/fsouza/go-dockerclient/plugin.go new file mode 100644 index 000000000..a28ff3d1e --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/plugin.go @@ -0,0 +1,418 @@ +// Copyright 2018 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "io/ioutil" + "net/http" +) + +// PluginPrivilege represents a privilege for a plugin. +type PluginPrivilege struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"` + Value []string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"` +} + +// InstallPluginOptions specify parameters to the InstallPlugins function. +// +// See https://goo.gl/C4t7Tz for more details. +type InstallPluginOptions struct { + Remote string + Name string + Plugins []PluginPrivilege `qs:"-"` + + Auth AuthConfiguration + + Context context.Context +} + +// InstallPlugins installs a plugin or returns an error in case of failure. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) InstallPlugins(opts InstallPluginOptions) error { + path := "/plugins/pull?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + data: opts.Plugins, + context: opts.Context, + }) + defer resp.Body.Close() + if err != nil { + return err + } + return nil +} + +// PluginSettings stores plugin settings. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginSettings struct { + Env []string `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"` + Args []string `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"` + Devices []string `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"` +} + +// PluginInterface stores plugin interface. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginInterface struct { + Types []string `json:"Types,omitempty" yaml:"Types,omitempty" toml:"Types,omitempty"` + Socket string `json:"Socket,omitempty" yaml:"Socket,omitempty" toml:"Socket,omitempty"` +} + +// PluginNetwork stores plugin network type. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginNetwork struct { + Type string `json:"Type,omitempty" yaml:"Type,omitempty" toml:"Type,omitempty"` +} + +// PluginLinux stores plugin linux setting. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginLinux struct { + Capabilities []string `json:"Capabilities,omitempty" yaml:"Capabilities,omitempty" toml:"Capabilities,omitempty"` + AllowAllDevices bool `json:"AllowAllDevices,omitempty" yaml:"AllowAllDevices,omitempty" toml:"AllowAllDevices,omitempty"` + Devices []PluginLinuxDevices `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"` +} + +// PluginLinuxDevices stores plugin linux device setting. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginLinuxDevices struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Description string `json:"Documentation,omitempty" yaml:"Documentation,omitempty" toml:"Documentation,omitempty"` + Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"` + Path string `json:"Path,omitempty" yaml:"Path,omitempty" toml:"Path,omitempty"` +} + +// PluginEnv stores plugin environment. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginEnv struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"` + Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"` + Value string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"` +} + +// PluginArgs stores plugin arguments. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginArgs struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"` + Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"` + Value []string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"` +} + +// PluginUser stores plugin user. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginUser struct { + UID int32 `json:"UID,omitempty" yaml:"UID,omitempty" toml:"UID,omitempty"` + GID int32 `json:"GID,omitempty" yaml:"GID,omitempty" toml:"GID,omitempty"` +} + +// PluginConfig stores plugin config. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginConfig struct { + Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"` + Documentation string + Interface PluginInterface `json:"Interface,omitempty" yaml:"Interface,omitempty" toml:"Interface,omitempty"` + Entrypoint []string `json:"Entrypoint,omitempty" yaml:"Entrypoint,omitempty" toml:"Entrypoint,omitempty"` + WorkDir string `json:"WorkDir,omitempty" yaml:"WorkDir,omitempty" toml:"WorkDir,omitempty"` + User PluginUser `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"` + Network PluginNetwork `json:"Network,omitempty" yaml:"Network,omitempty" toml:"Network,omitempty"` + Linux PluginLinux `json:"Linux,omitempty" yaml:"Linux,omitempty" toml:"Linux,omitempty"` + PropagatedMount string `json:"PropagatedMount,omitempty" yaml:"PropagatedMount,omitempty" toml:"PropagatedMount,omitempty"` + Mounts []Mount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"` + Env []PluginEnv `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"` + Args PluginArgs `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"` +} + +// PluginDetail specify results from the ListPlugins function. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginDetail struct { + ID string `json:"Id,omitempty" yaml:"Id,omitempty" toml:"Id,omitempty"` + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Tag string `json:"Tag,omitempty" yaml:"Tag,omitempty" toml:"Tag,omitempty"` + Active bool `json:"Active,omitempty" yaml:"Active,omitempty" toml:"Active,omitempty"` + Settings PluginSettings `json:"Settings,omitempty" yaml:"Settings,omitempty" toml:"Settings,omitempty"` + Config PluginConfig `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"` +} + +// ListPlugins returns pluginDetails or an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) ListPlugins(ctx context.Context) ([]PluginDetail, error) { + resp, err := c.do("GET", "/plugins", doOptions{ + context: ctx, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + pluginDetails := make([]PluginDetail, 0) + if err := json.NewDecoder(resp.Body).Decode(&pluginDetails); err != nil { + return nil, err + } + return pluginDetails, nil +} + +// ListFilteredPluginsOptions specify parameters to the ListFilteredPlugins function. +// +// See https://goo.gl/C4t7Tz for more details. +type ListFilteredPluginsOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListFilteredPlugins returns pluginDetails or an error. +// +// See https://goo.gl/rmdmWg for more details. +func (c *Client) ListFilteredPlugins(opts ListFilteredPluginsOptions) ([]PluginDetail, error) { + path := "/plugins/json?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{ + context: opts.Context, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + pluginDetails := make([]PluginDetail, 0) + if err := json.NewDecoder(resp.Body).Decode(&pluginDetails); err != nil { + return nil, err + } + return pluginDetails, nil +} + +// GetPluginPrivileges returns pulginPrivileges or an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) GetPluginPrivileges(name string, ctx context.Context) ([]PluginPrivilege, error) { + resp, err := c.do("GET", "/plugins/privileges?remote="+name, doOptions{ + context: ctx, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var pluginPrivileges []PluginPrivilege + if err := json.NewDecoder(resp.Body).Decode(&pluginPrivileges); err != nil { + return nil, err + } + return pluginPrivileges, nil +} + +// InspectPlugins returns a pluginDetail or an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) InspectPlugins(name string, ctx context.Context) (*PluginDetail, error) { + resp, err := c.do("GET", "/plugins/"+name+"/json", doOptions{ + context: ctx, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchPlugin{ID: name} + } + return nil, err + } + resp.Body.Close() + var pluginDetail PluginDetail + if err := json.NewDecoder(resp.Body).Decode(&pluginDetail); err != nil { + return nil, err + } + return &pluginDetail, nil +} + +// RemovePluginOptions specify parameters to the RemovePlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type RemovePluginOptions struct { + // The Name of the plugin. + Name string `qs:"-"` + + Force bool `qs:"force"` + Context context.Context +} + +// RemovePlugin returns a PluginDetail or an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) RemovePlugin(opts RemovePluginOptions) (*PluginDetail, error) { + path := "/plugins/" + opts.Name + "?" + queryString(opts) + resp, err := c.do("DELETE", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchPlugin{ID: opts.Name} + } + return nil, err + } + resp.Body.Close() + var pluginDetail PluginDetail + if err := json.NewDecoder(resp.Body).Decode(&pluginDetail); err != nil { + return nil, err + } + return &pluginDetail, nil +} + +// EnablePluginOptions specify parameters to the EnablePlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type EnablePluginOptions struct { + // The Name of the plugin. + Name string `qs:"-"` + Timeout int64 `qs:"timeout"` + + Context context.Context +} + +// EnablePlugin enables plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) EnablePlugin(opts EnablePluginOptions) error { + path := "/plugins/" + opts.Name + "/enable?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + defer resp.Body.Close() + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// DisablePluginOptions specify parameters to the DisablePlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type DisablePluginOptions struct { + // The Name of the plugin. + Name string `qs:"-"` + + Context context.Context +} + +// DisablePlugin disables plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) DisablePlugin(opts DisablePluginOptions) error { + path := "/plugins/" + opts.Name + "/disable" + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + defer resp.Body.Close() + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// CreatePluginOptions specify parameters to the CreatePlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type CreatePluginOptions struct { + // The Name of the plugin. + Name string `qs:"name"` + // Path to tar containing plugin + Path string `qs:"-"` + + Context context.Context +} + +// CreatePlugin creates plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) CreatePlugin(opts CreatePluginOptions) (string, error) { + path := "/plugins/create?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + data: opts.Path, + context: opts.Context}) + defer resp.Body.Close() + if err != nil { + return "", err + } + containerNameBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(containerNameBytes), nil +} + +// PushPluginOptions specify parameters to PushPlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type PushPluginOptions struct { + // The Name of the plugin. + Name string + + Context context.Context +} + +// PushPlugin pushes plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) PushPlugin(opts PushPluginOptions) error { + path := "/plugins/" + opts.Name + "/push" + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + defer resp.Body.Close() + if err != nil { + return err + } + return nil +} + +// ConfigurePluginOptions specify parameters to the ConfigurePlugin +// +// See https://goo.gl/C4t7Tz for more details. +type ConfigurePluginOptions struct { + // The Name of the plugin. + Name string `qs:"name"` + Envs []string + + Context context.Context +} + +// ConfigurePlugin configures plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) ConfigurePlugin(opts ConfigurePluginOptions) error { + path := "/plugins/" + opts.Name + "/set" + resp, err := c.do("POST", path, doOptions{ + data: opts.Envs, + context: opts.Context, + }) + defer resp.Body.Close() + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchPlugin{ID: opts.Name} + } + return err + } + return nil +} + +// NoSuchPlugin is the error returned when a given plugin does not exist. +type NoSuchPlugin struct { + ID string + Err error +} + +func (err *NoSuchPlugin) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such plugin: " + err.ID +} diff --git a/vendor/github.com/fsouza/go-dockerclient/signal.go b/vendor/github.com/fsouza/go-dockerclient/signal.go new file mode 100644 index 000000000..16aa00388 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/signal.go @@ -0,0 +1,49 @@ +// Copyright 2014 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +// Signal represents a signal that can be send to the container on +// KillContainer call. +type Signal int + +// These values represent all signals available on Linux, where containers will +// be running. +const ( + SIGABRT = Signal(0x6) + SIGALRM = Signal(0xe) + SIGBUS = Signal(0x7) + SIGCHLD = Signal(0x11) + SIGCLD = Signal(0x11) + SIGCONT = Signal(0x12) + SIGFPE = Signal(0x8) + SIGHUP = Signal(0x1) + SIGILL = Signal(0x4) + SIGINT = Signal(0x2) + SIGIO = Signal(0x1d) + SIGIOT = Signal(0x6) + SIGKILL = Signal(0x9) + SIGPIPE = Signal(0xd) + SIGPOLL = Signal(0x1d) + SIGPROF = Signal(0x1b) + SIGPWR = Signal(0x1e) + SIGQUIT = Signal(0x3) + SIGSEGV = Signal(0xb) + SIGSTKFLT = Signal(0x10) + SIGSTOP = Signal(0x13) + SIGSYS = Signal(0x1f) + SIGTERM = Signal(0xf) + SIGTRAP = Signal(0x5) + SIGTSTP = Signal(0x14) + SIGTTIN = Signal(0x15) + SIGTTOU = Signal(0x16) + SIGUNUSED = Signal(0x1f) + SIGURG = Signal(0x17) + SIGUSR1 = Signal(0xa) + SIGUSR2 = Signal(0xc) + SIGVTALRM = Signal(0x1a) + SIGWINCH = Signal(0x1c) + SIGXCPU = Signal(0x18) + SIGXFSZ = Signal(0x19) +) diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm.go b/vendor/github.com/fsouza/go-dockerclient/swarm.go new file mode 100644 index 000000000..a257758fc --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/swarm.go @@ -0,0 +1,156 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "net/url" + "strconv" + + "github.com/docker/docker/api/types/swarm" +) + +var ( + // ErrNodeAlreadyInSwarm is the error returned by InitSwarm and JoinSwarm + // when the node is already part of a Swarm. + ErrNodeAlreadyInSwarm = errors.New("node already in a Swarm") + + // ErrNodeNotInSwarm is the error returned by LeaveSwarm and UpdateSwarm + // when the node is not part of a Swarm. + ErrNodeNotInSwarm = errors.New("node is not in a Swarm") +) + +// InitSwarmOptions specify parameters to the InitSwarm function. +// See https://goo.gl/hzkgWu for more details. +type InitSwarmOptions struct { + swarm.InitRequest + Context context.Context +} + +// InitSwarm initializes a new Swarm and returns the node ID. +// See https://goo.gl/ZWyG1M for more details. +func (c *Client) InitSwarm(opts InitSwarmOptions) (string, error) { + path := "/swarm/init" + resp, err := c.do("POST", path, doOptions{ + data: opts.InitRequest, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { + return "", ErrNodeAlreadyInSwarm + } + return "", err + } + defer resp.Body.Close() + var response string + if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { + return "", err + } + return response, nil +} + +// JoinSwarmOptions specify parameters to the JoinSwarm function. +// See https://goo.gl/TdhJWU for more details. +type JoinSwarmOptions struct { + swarm.JoinRequest + Context context.Context +} + +// JoinSwarm joins an existing Swarm. +// See https://goo.gl/N59IP1 for more details. +func (c *Client) JoinSwarm(opts JoinSwarmOptions) error { + path := "/swarm/join" + resp, err := c.do("POST", path, doOptions{ + data: opts.JoinRequest, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { + return ErrNodeAlreadyInSwarm + } + } + resp.Body.Close() + return err +} + +// LeaveSwarmOptions specify parameters to the LeaveSwarm function. +// See https://goo.gl/UWDlLg for more details. +type LeaveSwarmOptions struct { + Force bool + Context context.Context +} + +// LeaveSwarm leaves a Swarm. +// See https://goo.gl/FTX1aD for more details. +func (c *Client) LeaveSwarm(opts LeaveSwarmOptions) error { + params := make(url.Values) + params.Set("force", strconv.FormatBool(opts.Force)) + path := "/swarm/leave?" + params.Encode() + resp, err := c.do("POST", path, doOptions{ + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { + return ErrNodeNotInSwarm + } + } + resp.Body.Close() + return err +} + +// UpdateSwarmOptions specify parameters to the UpdateSwarm function. +// See https://goo.gl/vFbq36 for more details. +type UpdateSwarmOptions struct { + Version int + RotateWorkerToken bool + RotateManagerToken bool + Swarm swarm.Spec + Context context.Context +} + +// UpdateSwarm updates a Swarm. +// See https://goo.gl/iJFnsw for more details. +func (c *Client) UpdateSwarm(opts UpdateSwarmOptions) error { + params := make(url.Values) + params.Set("version", strconv.Itoa(opts.Version)) + params.Set("rotateWorkerToken", strconv.FormatBool(opts.RotateWorkerToken)) + params.Set("rotateManagerToken", strconv.FormatBool(opts.RotateManagerToken)) + path := "/swarm/update?" + params.Encode() + resp, err := c.do("POST", path, doOptions{ + data: opts.Swarm, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { + return ErrNodeNotInSwarm + } + } + resp.Body.Close() + return err +} + +// InspectSwarm inspects a Swarm. +// See https://goo.gl/MFwgX9 for more details. +func (c *Client) InspectSwarm(ctx context.Context) (swarm.Swarm, error) { + response := swarm.Swarm{} + resp, err := c.do("GET", "/swarm", doOptions{ + context: ctx, + }) + if err != nil { + if e, ok := err.(*Error); ok && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { + return response, ErrNodeNotInSwarm + } + return response, err + } + defer resp.Body.Close() + err = json.NewDecoder(resp.Body).Decode(&response) + return response, err +} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go b/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go new file mode 100644 index 000000000..fb73ab2ef --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go @@ -0,0 +1,171 @@ +// Copyright 2017 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "net/http" + "net/url" + "strconv" + + "github.com/docker/docker/api/types/swarm" +) + +// NoSuchConfig is the error returned when a given config does not exist. +type NoSuchConfig struct { + ID string + Err error +} + +func (err *NoSuchConfig) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such config: " + err.ID +} + +// CreateConfigOptions specify parameters to the CreateConfig function. +// +// See https://goo.gl/KrVjHz for more details. +type CreateConfigOptions struct { + Auth AuthConfiguration `qs:"-"` + swarm.ConfigSpec + Context context.Context +} + +// CreateConfig creates a new config, returning the config instance +// or an error in case of failure. +// +// See https://goo.gl/KrVjHz for more details. +func (c *Client) CreateConfig(opts CreateConfigOptions) (*swarm.Config, error) { + headers, err := headersWithAuth(opts.Auth) + if err != nil { + return nil, err + } + path := "/configs/create?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + headers: headers, + data: opts.ConfigSpec, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var config swarm.Config + if err := json.NewDecoder(resp.Body).Decode(&config); err != nil { + return nil, err + } + return &config, nil +} + +// RemoveConfigOptions encapsulates options to remove a config. +// +// See https://goo.gl/Tqrtya for more details. +type RemoveConfigOptions struct { + ID string `qs:"-"` + Context context.Context +} + +// RemoveConfig removes a config, returning an error in case of failure. +// +// See https://goo.gl/Tqrtya for more details. +func (c *Client) RemoveConfig(opts RemoveConfigOptions) error { + path := "/configs/" + opts.ID + resp, err := c.do("DELETE", path, doOptions{context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchConfig{ID: opts.ID} + } + return err + } + resp.Body.Close() + return nil +} + +// UpdateConfigOptions specify parameters to the UpdateConfig function. +// +// See https://goo.gl/wu3MmS for more details. +type UpdateConfigOptions struct { + Auth AuthConfiguration `qs:"-"` + swarm.ConfigSpec + Context context.Context + Version uint64 +} + +// UpdateConfig updates the config at ID with the options +// +// Only label can be updated +// https://docs.docker.com/engine/api/v1.33/#operation/ConfigUpdate +// See https://goo.gl/wu3MmS for more details. +func (c *Client) UpdateConfig(id string, opts UpdateConfigOptions) error { + headers, err := headersWithAuth(opts.Auth) + if err != nil { + return err + } + params := make(url.Values) + params.Set("version", strconv.FormatUint(opts.Version, 10)) + resp, err := c.do("POST", "/configs/"+id+"/update?"+params.Encode(), doOptions{ + headers: headers, + data: opts.ConfigSpec, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchConfig{ID: id} + } + return err + } + defer resp.Body.Close() + return nil +} + +// InspectConfig returns information about a config by its ID. +// +// See https://goo.gl/dHmr75 for more details. +func (c *Client) InspectConfig(id string) (*swarm.Config, error) { + path := "/configs/" + id + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchConfig{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var config swarm.Config + if err := json.NewDecoder(resp.Body).Decode(&config); err != nil { + return nil, err + } + return &config, nil +} + +// ListConfigsOptions specify parameters to the ListConfigs function. +// +// See https://goo.gl/DwvNMd for more details. +type ListConfigsOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListConfigs returns a slice of configs matching the given criteria. +// +// See https://goo.gl/DwvNMd for more details. +func (c *Client) ListConfigs(opts ListConfigsOptions) ([]swarm.Config, error) { + path := "/configs?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var configs []swarm.Config + if err := json.NewDecoder(resp.Body).Decode(&configs); err != nil { + return nil, err + } + return configs, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_node.go b/vendor/github.com/fsouza/go-dockerclient/swarm_node.go new file mode 100644 index 000000000..095653cd9 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_node.go @@ -0,0 +1,130 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "net/http" + "net/url" + "strconv" + + "github.com/docker/docker/api/types/swarm" +) + +// NoSuchNode is the error returned when a given node does not exist. +type NoSuchNode struct { + ID string + Err error +} + +func (err *NoSuchNode) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such node: " + err.ID +} + +// ListNodesOptions specify parameters to the ListNodes function. +// +// See http://goo.gl/3K4GwU for more details. +type ListNodesOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListNodes returns a slice of nodes matching the given criteria. +// +// See http://goo.gl/3K4GwU for more details. +func (c *Client) ListNodes(opts ListNodesOptions) ([]swarm.Node, error) { + path := "/nodes?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var nodes []swarm.Node + if err := json.NewDecoder(resp.Body).Decode(&nodes); err != nil { + return nil, err + } + return nodes, nil +} + +// InspectNode returns information about a node by its ID. +// +// See http://goo.gl/WjkTOk for more details. +func (c *Client) InspectNode(id string) (*swarm.Node, error) { + resp, err := c.do("GET", "/nodes/"+id, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchNode{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var node swarm.Node + if err := json.NewDecoder(resp.Body).Decode(&node); err != nil { + return nil, err + } + return &node, nil +} + +// UpdateNodeOptions specify parameters to the NodeUpdate function. +// +// See http://goo.gl/VPBFgA for more details. +type UpdateNodeOptions struct { + swarm.NodeSpec + Version uint64 + Context context.Context +} + +// UpdateNode updates a node. +// +// See http://goo.gl/VPBFgA for more details. +func (c *Client) UpdateNode(id string, opts UpdateNodeOptions) error { + params := make(url.Values) + params.Set("version", strconv.FormatUint(opts.Version, 10)) + path := "/nodes/" + id + "/update?" + params.Encode() + resp, err := c.do("POST", path, doOptions{ + context: opts.Context, + forceJSON: true, + data: opts.NodeSpec, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchNode{ID: id} + } + return err + } + resp.Body.Close() + return nil +} + +// RemoveNodeOptions specify parameters to the RemoveNode function. +// +// See http://goo.gl/0SNvYg for more details. +type RemoveNodeOptions struct { + ID string + Force bool + Context context.Context +} + +// RemoveNode removes a node. +// +// See http://goo.gl/0SNvYg for more details. +func (c *Client) RemoveNode(opts RemoveNodeOptions) error { + params := make(url.Values) + params.Set("force", strconv.FormatBool(opts.Force)) + path := "/nodes/" + opts.ID + "?" + params.Encode() + resp, err := c.do("DELETE", path, doOptions{context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchNode{ID: opts.ID} + } + return err + } + resp.Body.Close() + return nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go b/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go new file mode 100644 index 000000000..5a3b82ca5 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go @@ -0,0 +1,171 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "net/http" + "net/url" + "strconv" + + "github.com/docker/docker/api/types/swarm" +) + +// NoSuchSecret is the error returned when a given secret does not exist. +type NoSuchSecret struct { + ID string + Err error +} + +func (err *NoSuchSecret) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such secret: " + err.ID +} + +// CreateSecretOptions specify parameters to the CreateSecret function. +// +// See https://goo.gl/KrVjHz for more details. +type CreateSecretOptions struct { + Auth AuthConfiguration `qs:"-"` + swarm.SecretSpec + Context context.Context +} + +// CreateSecret creates a new secret, returning the secret instance +// or an error in case of failure. +// +// See https://goo.gl/KrVjHz for more details. +func (c *Client) CreateSecret(opts CreateSecretOptions) (*swarm.Secret, error) { + headers, err := headersWithAuth(opts.Auth) + if err != nil { + return nil, err + } + path := "/secrets/create?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + headers: headers, + data: opts.SecretSpec, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var secret swarm.Secret + if err := json.NewDecoder(resp.Body).Decode(&secret); err != nil { + return nil, err + } + return &secret, nil +} + +// RemoveSecretOptions encapsulates options to remove a secret. +// +// See https://goo.gl/Tqrtya for more details. +type RemoveSecretOptions struct { + ID string `qs:"-"` + Context context.Context +} + +// RemoveSecret removes a secret, returning an error in case of failure. +// +// See https://goo.gl/Tqrtya for more details. +func (c *Client) RemoveSecret(opts RemoveSecretOptions) error { + path := "/secrets/" + opts.ID + resp, err := c.do("DELETE", path, doOptions{context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchSecret{ID: opts.ID} + } + return err + } + resp.Body.Close() + return nil +} + +// UpdateSecretOptions specify parameters to the UpdateSecret function. +// +// Only label can be updated +// See https://docs.docker.com/engine/api/v1.33/#operation/SecretUpdate +// See https://goo.gl/wu3MmS for more details. +type UpdateSecretOptions struct { + Auth AuthConfiguration `qs:"-"` + swarm.SecretSpec + Context context.Context + Version uint64 +} + +// UpdateSecret updates the secret at ID with the options +// +// See https://goo.gl/wu3MmS for more details. +func (c *Client) UpdateSecret(id string, opts UpdateSecretOptions) error { + headers, err := headersWithAuth(opts.Auth) + if err != nil { + return err + } + params := make(url.Values) + params.Set("version", strconv.FormatUint(opts.Version, 10)) + resp, err := c.do("POST", "/secrets/"+id+"/update?"+params.Encode(), doOptions{ + headers: headers, + data: opts.SecretSpec, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchSecret{ID: id} + } + return err + } + defer resp.Body.Close() + return nil +} + +// InspectSecret returns information about a secret by its ID. +// +// See https://goo.gl/dHmr75 for more details. +func (c *Client) InspectSecret(id string) (*swarm.Secret, error) { + path := "/secrets/" + id + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchSecret{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var secret swarm.Secret + if err := json.NewDecoder(resp.Body).Decode(&secret); err != nil { + return nil, err + } + return &secret, nil +} + +// ListSecretsOptions specify parameters to the ListSecrets function. +// +// See https://goo.gl/DwvNMd for more details. +type ListSecretsOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListSecrets returns a slice of secrets matching the given criteria. +// +// See https://goo.gl/DwvNMd for more details. +func (c *Client) ListSecrets(opts ListSecretsOptions) ([]swarm.Secret, error) { + path := "/secrets?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var secrets []swarm.Secret + if err := json.NewDecoder(resp.Body).Decode(&secrets); err != nil { + return nil, err + } + return secrets, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_service.go b/vendor/github.com/fsouza/go-dockerclient/swarm_service.go new file mode 100644 index 000000000..ca7e23725 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_service.go @@ -0,0 +1,213 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "io" + "net/http" + "time" + + "github.com/docker/docker/api/types/swarm" +) + +// NoSuchService is the error returned when a given service does not exist. +type NoSuchService struct { + ID string + Err error +} + +func (err *NoSuchService) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such service: " + err.ID +} + +// CreateServiceOptions specify parameters to the CreateService function. +// +// See https://goo.gl/KrVjHz for more details. +type CreateServiceOptions struct { + Auth AuthConfiguration `qs:"-"` + swarm.ServiceSpec + Context context.Context +} + +// CreateService creates a new service, returning the service instance +// or an error in case of failure. +// +// See https://goo.gl/KrVjHz for more details. +func (c *Client) CreateService(opts CreateServiceOptions) (*swarm.Service, error) { + headers, err := headersWithAuth(opts.Auth) + if err != nil { + return nil, err + } + path := "/services/create?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + headers: headers, + data: opts.ServiceSpec, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var service swarm.Service + if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { + return nil, err + } + return &service, nil +} + +// RemoveServiceOptions encapsulates options to remove a service. +// +// See https://goo.gl/Tqrtya for more details. +type RemoveServiceOptions struct { + ID string `qs:"-"` + Context context.Context +} + +// RemoveService removes a service, returning an error in case of failure. +// +// See https://goo.gl/Tqrtya for more details. +func (c *Client) RemoveService(opts RemoveServiceOptions) error { + path := "/services/" + opts.ID + resp, err := c.do("DELETE", path, doOptions{context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchService{ID: opts.ID} + } + return err + } + resp.Body.Close() + return nil +} + +// UpdateServiceOptions specify parameters to the UpdateService function. +// +// See https://goo.gl/wu3MmS for more details. +type UpdateServiceOptions struct { + Auth AuthConfiguration `qs:"-"` + swarm.ServiceSpec `qs:"-"` + Context context.Context + Version uint64 + Rollback string +} + +// UpdateService updates the service at ID with the options +// +// See https://goo.gl/wu3MmS for more details. +func (c *Client) UpdateService(id string, opts UpdateServiceOptions) error { + headers, err := headersWithAuth(opts.Auth) + if err != nil { + return err + } + resp, err := c.do("POST", "/services/"+id+"/update?"+queryString(opts), doOptions{ + headers: headers, + data: opts.ServiceSpec, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchService{ID: id} + } + return err + } + defer resp.Body.Close() + return nil +} + +// InspectService returns information about a service by its ID. +// +// See https://goo.gl/dHmr75 for more details. +func (c *Client) InspectService(id string) (*swarm.Service, error) { + path := "/services/" + id + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchService{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var service swarm.Service + if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { + return nil, err + } + return &service, nil +} + +// ListServicesOptions specify parameters to the ListServices function. +// +// See https://goo.gl/DwvNMd for more details. +type ListServicesOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListServices returns a slice of services matching the given criteria. +// +// See https://goo.gl/DwvNMd for more details. +func (c *Client) ListServices(opts ListServicesOptions) ([]swarm.Service, error) { + path := "/services?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var services []swarm.Service + if err := json.NewDecoder(resp.Body).Decode(&services); err != nil { + return nil, err + } + return services, nil +} + +// LogsServiceOptions represents the set of options used when getting logs from a +// service. +type LogsServiceOptions struct { + Context context.Context + Service string `qs:"-"` + OutputStream io.Writer `qs:"-"` + ErrorStream io.Writer `qs:"-"` + InactivityTimeout time.Duration `qs:"-"` + Tail string + + // Use raw terminal? Usually true when the container contains a TTY. + RawTerminal bool `qs:"-"` + Since int64 + Follow bool + Stdout bool + Stderr bool + Timestamps bool + Details bool +} + +// GetServiceLogs gets stdout and stderr logs from the specified service. +// +// When LogsServiceOptions.RawTerminal is set to false, go-dockerclient will multiplex +// the streams and send the containers stdout to LogsServiceOptions.OutputStream, and +// stderr to LogsServiceOptions.ErrorStream. +// +// When LogsServiceOptions.RawTerminal is true, callers will get the raw stream on +// LogsServiceOptions.OutputStream. +func (c *Client) GetServiceLogs(opts LogsServiceOptions) error { + if opts.Service == "" { + return &NoSuchService{ID: opts.Service} + } + if opts.Tail == "" { + opts.Tail = "all" + } + path := "/services/" + opts.Service + "/logs?" + queryString(opts) + return c.stream("GET", path, streamOptions{ + setRawTerminal: opts.RawTerminal, + stdout: opts.OutputStream, + stderr: opts.ErrorStream, + inactivityTimeout: opts.InactivityTimeout, + context: opts.Context, + }) +} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_task.go b/vendor/github.com/fsouza/go-dockerclient/swarm_task.go new file mode 100644 index 000000000..3b1161ab9 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_task.go @@ -0,0 +1,70 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "net/http" + + "github.com/docker/docker/api/types/swarm" +) + +// NoSuchTask is the error returned when a given task does not exist. +type NoSuchTask struct { + ID string + Err error +} + +func (err *NoSuchTask) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such task: " + err.ID +} + +// ListTasksOptions specify parameters to the ListTasks function. +// +// See http://goo.gl/rByLzw for more details. +type ListTasksOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListTasks returns a slice of tasks matching the given criteria. +// +// See http://goo.gl/rByLzw for more details. +func (c *Client) ListTasks(opts ListTasksOptions) ([]swarm.Task, error) { + path := "/tasks?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var tasks []swarm.Task + if err := json.NewDecoder(resp.Body).Decode(&tasks); err != nil { + return nil, err + } + return tasks, nil +} + +// InspectTask returns information about a task by its ID. +// +// See http://goo.gl/kyziuq for more details. +func (c *Client) InspectTask(id string) (*swarm.Task, error) { + resp, err := c.do("GET", "/tasks/"+id, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchTask{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var task swarm.Task + if err := json.NewDecoder(resp.Body).Decode(&task); err != nil { + return nil, err + } + return &task, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/tar.go b/vendor/github.com/fsouza/go-dockerclient/tar.go new file mode 100644 index 000000000..611da8c9e --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/tar.go @@ -0,0 +1,122 @@ +// Copyright 2014 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path" + "path/filepath" + "strings" + + "github.com/docker/docker/pkg/fileutils" + "github.com/fsouza/go-dockerclient/internal/archive" +) + +func createTarStream(srcPath, dockerfilePath string) (io.ReadCloser, error) { + srcPath, err := filepath.Abs(srcPath) + if err != nil { + return nil, err + } + + excludes, err := parseDockerignore(srcPath) + if err != nil { + return nil, err + } + + includes := []string{"."} + + // If .dockerignore mentions .dockerignore or the Dockerfile + // then make sure we send both files over to the daemon + // because Dockerfile is, obviously, needed no matter what, and + // .dockerignore is needed to know if either one needs to be + // removed. The deamon will remove them for us, if needed, after it + // parses the Dockerfile. + // + // https://github.com/docker/docker/issues/8330 + // + forceIncludeFiles := []string{".dockerignore", dockerfilePath} + + for _, includeFile := range forceIncludeFiles { + if includeFile == "" { + continue + } + keepThem, err := fileutils.Matches(includeFile, excludes) + if err != nil { + return nil, fmt.Errorf("cannot match .dockerfile: '%s', error: %s", includeFile, err) + } + if keepThem { + includes = append(includes, includeFile) + } + } + + if err := validateContextDirectory(srcPath, excludes); err != nil { + return nil, err + } + tarOpts := &archive.TarOptions{ + ExcludePatterns: excludes, + IncludeFiles: includes, + Compression: archive.Uncompressed, + NoLchown: true, + } + return archive.TarWithOptions(srcPath, tarOpts) +} + +// validateContextDirectory checks if all the contents of the directory +// can be read and returns an error if some files can't be read. +// Symlinks which point to non-existing files don't trigger an error +func validateContextDirectory(srcPath string, excludes []string) error { + return filepath.Walk(filepath.Join(srcPath, "."), func(filePath string, f os.FileInfo, err error) error { + // skip this directory/file if it's not in the path, it won't get added to the context + if relFilePath, relErr := filepath.Rel(srcPath, filePath); relErr != nil { + return relErr + } else if skip, matchErr := fileutils.Matches(relFilePath, excludes); matchErr != nil { + return matchErr + } else if skip { + if f.IsDir() { + return filepath.SkipDir + } + return nil + } + + if err != nil { + if os.IsPermission(err) { + return fmt.Errorf("can't stat '%s'", filePath) + } + if os.IsNotExist(err) { + return nil + } + return err + } + + // skip checking if symlinks point to non-existing files, such symlinks can be useful + // also skip named pipes, because they hanging on open + if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 { + return nil + } + + if !f.IsDir() { + currentFile, err := os.Open(filePath) + if err != nil && os.IsPermission(err) { + return fmt.Errorf("no permission to read from '%s'", filePath) + } + currentFile.Close() + } + return nil + }) +} + +func parseDockerignore(root string) ([]string, error) { + var excludes []string + ignore, err := ioutil.ReadFile(path.Join(root, ".dockerignore")) + if err != nil && !os.IsNotExist(err) { + return excludes, fmt.Errorf("error reading .dockerignore: '%s'", err) + } + excludes = strings.Split(string(ignore), "\n") + + return excludes, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/tls.go b/vendor/github.com/fsouza/go-dockerclient/tls.go new file mode 100644 index 000000000..bb5790b5f --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/tls.go @@ -0,0 +1,118 @@ +// Copyright 2014 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// The content is borrowed from Docker's own source code to provide a simple +// tls based dialer + +package docker + +import ( + "crypto/tls" + "errors" + "net" + "strings" + "time" +) + +type tlsClientCon struct { + *tls.Conn + rawConn net.Conn +} + +func (c *tlsClientCon) CloseWrite() error { + // Go standard tls.Conn doesn't provide the CloseWrite() method so we do it + // on its underlying connection. + if cwc, ok := c.rawConn.(interface { + CloseWrite() error + }); ok { + return cwc.CloseWrite() + } + return nil +} + +func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Config) (net.Conn, error) { + // We want the Timeout and Deadline values from dialer to cover the + // whole process: TCP connection and TLS handshake. This means that we + // also need to start our own timers now. + timeout := dialer.Timeout + + if !dialer.Deadline.IsZero() { + deadlineTimeout := dialer.Deadline.Sub(time.Now()) + if timeout == 0 || deadlineTimeout < timeout { + timeout = deadlineTimeout + } + } + + var errChannel chan error + + if timeout != 0 { + errChannel = make(chan error, 2) + time.AfterFunc(timeout, func() { + errChannel <- errors.New("") + }) + } + + rawConn, err := dialer.Dial(network, addr) + if err != nil { + return nil, err + } + + colonPos := strings.LastIndex(addr, ":") + if colonPos == -1 { + colonPos = len(addr) + } + hostname := addr[:colonPos] + + // If no ServerName is set, infer the ServerName + // from the hostname we're connecting to. + if config.ServerName == "" { + // Make a copy to avoid polluting argument or default. + config = copyTLSConfig(config) + config.ServerName = hostname + } + + conn := tls.Client(rawConn, config) + + if timeout == 0 { + err = conn.Handshake() + } else { + go func() { + errChannel <- conn.Handshake() + }() + + err = <-errChannel + } + + if err != nil { + rawConn.Close() + return nil, err + } + + // This is Docker difference with standard's crypto/tls package: returned a + // wrapper which holds both the TLS and raw connections. + return &tlsClientCon{conn, rawConn}, nil +} + +// this exists to silent an error message in go vet +func copyTLSConfig(cfg *tls.Config) *tls.Config { + return &tls.Config{ + Certificates: cfg.Certificates, + CipherSuites: cfg.CipherSuites, + ClientAuth: cfg.ClientAuth, + ClientCAs: cfg.ClientCAs, + ClientSessionCache: cfg.ClientSessionCache, + CurvePreferences: cfg.CurvePreferences, + InsecureSkipVerify: cfg.InsecureSkipVerify, + MaxVersion: cfg.MaxVersion, + MinVersion: cfg.MinVersion, + NameToCertificate: cfg.NameToCertificate, + NextProtos: cfg.NextProtos, + PreferServerCipherSuites: cfg.PreferServerCipherSuites, + Rand: cfg.Rand, + RootCAs: cfg.RootCAs, + ServerName: cfg.ServerName, + SessionTicketKey: cfg.SessionTicketKey, + SessionTicketsDisabled: cfg.SessionTicketsDisabled, + } +} diff --git a/vendor/github.com/fsouza/go-dockerclient/volume.go b/vendor/github.com/fsouza/go-dockerclient/volume.go new file mode 100644 index 000000000..021a262b7 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/volume.go @@ -0,0 +1,190 @@ +// Copyright 2015 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "errors" + "net/http" +) + +var ( + // ErrNoSuchVolume is the error returned when the volume does not exist. + ErrNoSuchVolume = errors.New("no such volume") + + // ErrVolumeInUse is the error returned when the volume requested to be removed is still in use. + ErrVolumeInUse = errors.New("volume in use and cannot be removed") +) + +// Volume represents a volume. +// +// See https://goo.gl/3wgTsd for more details. +type Volume struct { + Name string `json:"Name" yaml:"Name" toml:"Name"` + Driver string `json:"Driver,omitempty" yaml:"Driver,omitempty" toml:"Driver,omitempty"` + Mountpoint string `json:"Mountpoint,omitempty" yaml:"Mountpoint,omitempty" toml:"Mountpoint,omitempty"` + Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"` + Options map[string]string `json:"Options,omitempty" yaml:"Options,omitempty" toml:"Options,omitempty"` +} + +// ListVolumesOptions specify parameters to the ListVolumes function. +// +// See https://goo.gl/3wgTsd for more details. +type ListVolumesOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListVolumes returns a list of available volumes in the server. +// +// See https://goo.gl/3wgTsd for more details. +func (c *Client) ListVolumes(opts ListVolumesOptions) ([]Volume, error) { + resp, err := c.do("GET", "/volumes?"+queryString(opts), doOptions{ + context: opts.Context, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + m := make(map[string]interface{}) + if err = json.NewDecoder(resp.Body).Decode(&m); err != nil { + return nil, err + } + var volumes []Volume + volumesJSON, ok := m["Volumes"] + if !ok { + return volumes, nil + } + data, err := json.Marshal(volumesJSON) + if err != nil { + return nil, err + } + if err := json.Unmarshal(data, &volumes); err != nil { + return nil, err + } + return volumes, nil +} + +// CreateVolumeOptions specify parameters to the CreateVolume function. +// +// See https://goo.gl/qEhmEC for more details. +type CreateVolumeOptions struct { + Name string + Driver string + DriverOpts map[string]string + Context context.Context `json:"-"` + Labels map[string]string +} + +// CreateVolume creates a volume on the server. +// +// See https://goo.gl/qEhmEC for more details. +func (c *Client) CreateVolume(opts CreateVolumeOptions) (*Volume, error) { + resp, err := c.do("POST", "/volumes/create", doOptions{ + data: opts, + context: opts.Context, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var volume Volume + if err := json.NewDecoder(resp.Body).Decode(&volume); err != nil { + return nil, err + } + return &volume, nil +} + +// InspectVolume returns a volume by its name. +// +// See https://goo.gl/GMjsMc for more details. +func (c *Client) InspectVolume(name string) (*Volume, error) { + resp, err := c.do("GET", "/volumes/"+name, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, ErrNoSuchVolume + } + return nil, err + } + defer resp.Body.Close() + var volume Volume + if err := json.NewDecoder(resp.Body).Decode(&volume); err != nil { + return nil, err + } + return &volume, nil +} + +// RemoveVolume removes a volume by its name. +// +// Deprecated: Use RemoveVolumeWithOptions instead. +func (c *Client) RemoveVolume(name string) error { + return c.RemoveVolumeWithOptions(RemoveVolumeOptions{Name: name}) +} + +// RemoveVolumeOptions specify parameters to the RemoveVolumeWithOptions +// function. +// +// See https://goo.gl/nvd6qj for more details. +type RemoveVolumeOptions struct { + Context context.Context + Name string `qs:"-"` + Force bool +} + +// RemoveVolumeWithOptions removes a volume by its name and takes extra +// parameters. +// +// See https://goo.gl/nvd6qj for more details. +func (c *Client) RemoveVolumeWithOptions(opts RemoveVolumeOptions) error { + path := "/volumes/" + opts.Name + resp, err := c.do("DELETE", path+"?"+queryString(opts), doOptions{context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok { + if e.Status == http.StatusNotFound { + return ErrNoSuchVolume + } + if e.Status == http.StatusConflict { + return ErrVolumeInUse + } + } + return err + } + defer resp.Body.Close() + return nil +} + +// PruneVolumesOptions specify parameters to the PruneVolumes function. +// +// See https://goo.gl/f9XDem for more details. +type PruneVolumesOptions struct { + Filters map[string][]string + Context context.Context +} + +// PruneVolumesResults specify results from the PruneVolumes function. +// +// See https://goo.gl/f9XDem for more details. +type PruneVolumesResults struct { + VolumesDeleted []string + SpaceReclaimed int64 +} + +// PruneVolumes deletes volumes which are unused. +// +// See https://goo.gl/f9XDem for more details. +func (c *Client) PruneVolumes(opts PruneVolumesOptions) (*PruneVolumesResults, error) { + path := "/volumes/prune?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var results PruneVolumesResults + if err := json.NewDecoder(resp.Body).Decode(&results); err != nil { + return nil, err + } + return &results, nil +} diff --git a/vendor/github.com/ghodss/yaml/.gitignore b/vendor/github.com/ghodss/yaml/.gitignore new file mode 100644 index 000000000..e256a31e0 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/.gitignore @@ -0,0 +1,20 @@ +# OSX leaves these everywhere on SMB shares +._* + +# Eclipse files +.classpath +.project +.settings/** + +# Emacs save files +*~ + +# Vim-related files +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist + +# Go test binaries +*.test diff --git a/vendor/github.com/ghodss/yaml/.travis.yml b/vendor/github.com/ghodss/yaml/.travis.yml new file mode 100644 index 000000000..0e9d6edc0 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/.travis.yml @@ -0,0 +1,7 @@ +language: go +go: + - 1.3 + - 1.4 +script: + - go test + - go build diff --git a/vendor/github.com/ghodss/yaml/LICENSE b/vendor/github.com/ghodss/yaml/LICENSE new file mode 100644 index 000000000..7805d36de --- /dev/null +++ b/vendor/github.com/ghodss/yaml/LICENSE @@ -0,0 +1,50 @@ +The MIT License (MIT) + +Copyright (c) 2014 Sam Ghods + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/ghodss/yaml/README.md b/vendor/github.com/ghodss/yaml/README.md new file mode 100644 index 000000000..f8f7e3695 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/README.md @@ -0,0 +1,116 @@ +# YAML marshaling and unmarshaling support for Go + +[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml) + +## Introduction + +A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs. + +In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). + +## Compatibility + +This package uses [go-yaml v2](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility). + +## Caveats + +**Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example: + +``` +BAD: + exampleKey: !!binary gIGC + +GOOD: + exampleKey: gIGC +... and decode the base64 data in your code. +``` + +**Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys. + +## Installation and usage + +To install, run: + +``` +$ go get github.com/ghodss/yaml +``` + +And import using: + +``` +import "github.com/ghodss/yaml" +``` + +Usage is very similar to the JSON library: + +```go +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +type Person struct { + Name string `json:"name"` // Affects YAML field names too. + Age int `json:"name"` +} + +func main() { + // Marshal a Person struct to YAML. + p := Person{"John", 30} + y, err := yaml.Marshal(p) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + name: John + age: 30 + */ + + // Unmarshal the YAML back into a Person struct. + var p2 Person + err := yaml.Unmarshal(y, &p2) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(p2) + /* Output: + {John 30} + */ +} +``` + +`yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available: + +```go +import ( + "fmt" + + "github.com/ghodss/yaml" +) +func main() { + j := []byte(`{"name": "John", "age": 30}`) + y, err := yaml.JSONToYAML(j) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + name: John + age: 30 + */ + j2, err := yaml.YAMLToJSON(y) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(j2)) + /* Output: + {"age":30,"name":"John"} + */ +} +``` diff --git a/vendor/github.com/ghodss/yaml/fields.go b/vendor/github.com/ghodss/yaml/fields.go new file mode 100644 index 000000000..0bd3c2b46 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/fields.go @@ -0,0 +1,497 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package yaml + +import ( + "bytes" + "encoding" + "encoding/json" + "reflect" + "sort" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// if it encounters an Unmarshaler, indirect stops and returns that. +// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. +func indirect(v reflect.Value, decodingNull bool) (json.Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { + v = e + continue + } + } + + if v.Kind() != reflect.Ptr { + break + } + + if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 { + if u, ok := v.Interface().(json.Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + v = v.Elem() + } + return nil, nil, v +} + +// A field represents a single field found in a struct. +type field struct { + name string + nameBytes []byte // []byte(name) + equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent + + tag bool + index []int + typ reflect.Type + omitEmpty bool + quoted bool +} + +func fillField(f field) field { + f.nameBytes = []byte(f.name) + f.equalFold = foldFunc(f.nameBytes) + return f +} + +// byName sorts field by name, breaking ties with depth, +// then breaking ties with "name came from json tag", then +// breaking ties with index sequence. +type byName []field + +func (x byName) Len() int { return len(x) } + +func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byName) Less(i, j int) bool { + if x[i].name != x[j].name { + return x[i].name < x[j].name + } + if len(x[i].index) != len(x[j].index) { + return len(x[i].index) < len(x[j].index) + } + if x[i].tag != x[j].tag { + return x[i].tag + } + return byIndex(x).Less(i, j) +} + +// byIndex sorts field by index sequence. +type byIndex []field + +func (x byIndex) Len() int { return len(x) } + +func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byIndex) Less(i, j int) bool { + for k, xik := range x[i].index { + if k >= len(x[j].index) { + return false + } + if xik != x[j].index[k] { + return xik < x[j].index[k] + } + } + return len(x[i].index) < len(x[j].index) +} + +// typeFields returns a list of fields that JSON should recognize for the given type. +// The algorithm is breadth-first search over the set of structs to include - the top struct +// and then any reachable anonymous structs. +func typeFields(t reflect.Type) []field { + // Anonymous fields to explore at the current level and the next. + current := []field{} + next := []field{{typ: t}} + + // Count of queued names for current level and the next. + count := map[reflect.Type]int{} + nextCount := map[reflect.Type]int{} + + // Types already visited at an earlier level. + visited := map[reflect.Type]bool{} + + // Fields found. + var fields []field + + for len(next) > 0 { + current, next = next, current[:0] + count, nextCount = nextCount, map[reflect.Type]int{} + + for _, f := range current { + if visited[f.typ] { + continue + } + visited[f.typ] = true + + // Scan f.typ for fields to include. + for i := 0; i < f.typ.NumField(); i++ { + sf := f.typ.Field(i) + if sf.PkgPath != "" { // unexported + continue + } + tag := sf.Tag.Get("json") + if tag == "-" { + continue + } + name, opts := parseTag(tag) + if !isValidTag(name) { + name = "" + } + index := make([]int, len(f.index)+1) + copy(index, f.index) + index[len(f.index)] = i + + ft := sf.Type + if ft.Name() == "" && ft.Kind() == reflect.Ptr { + // Follow pointer. + ft = ft.Elem() + } + + // Record found field and index sequence. + if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { + tagged := name != "" + if name == "" { + name = sf.Name + } + fields = append(fields, fillField(field{ + name: name, + tag: tagged, + index: index, + typ: ft, + omitEmpty: opts.Contains("omitempty"), + quoted: opts.Contains("string"), + })) + if count[f.typ] > 1 { + // If there were multiple instances, add a second, + // so that the annihilation code will see a duplicate. + // It only cares about the distinction between 1 or 2, + // so don't bother generating any more copies. + fields = append(fields, fields[len(fields)-1]) + } + continue + } + + // Record new anonymous struct to explore in next round. + nextCount[ft]++ + if nextCount[ft] == 1 { + next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft})) + } + } + } + } + + sort.Sort(byName(fields)) + + // Delete all fields that are hidden by the Go rules for embedded fields, + // except that fields with JSON tags are promoted. + + // The fields are sorted in primary order of name, secondary order + // of field index length. Loop over names; for each name, delete + // hidden fields by choosing the one dominant field that survives. + out := fields[:0] + for advance, i := 0, 0; i < len(fields); i += advance { + // One iteration per name. + // Find the sequence of fields with the name of this first field. + fi := fields[i] + name := fi.name + for advance = 1; i+advance < len(fields); advance++ { + fj := fields[i+advance] + if fj.name != name { + break + } + } + if advance == 1 { // Only one field with this name + out = append(out, fi) + continue + } + dominant, ok := dominantField(fields[i : i+advance]) + if ok { + out = append(out, dominant) + } + } + + fields = out + sort.Sort(byIndex(fields)) + + return fields +} + +// dominantField looks through the fields, all of which are known to +// have the same name, to find the single field that dominates the +// others using Go's embedding rules, modified by the presence of +// JSON tags. If there are multiple top-level fields, the boolean +// will be false: This condition is an error in Go and we skip all +// the fields. +func dominantField(fields []field) (field, bool) { + // The fields are sorted in increasing index-length order. The winner + // must therefore be one with the shortest index length. Drop all + // longer entries, which is easy: just truncate the slice. + length := len(fields[0].index) + tagged := -1 // Index of first tagged field. + for i, f := range fields { + if len(f.index) > length { + fields = fields[:i] + break + } + if f.tag { + if tagged >= 0 { + // Multiple tagged fields at the same level: conflict. + // Return no field. + return field{}, false + } + tagged = i + } + } + if tagged >= 0 { + return fields[tagged], true + } + // All remaining fields have the same length. If there's more than one, + // we have a conflict (two fields named "X" at the same level) and we + // return no field. + if len(fields) > 1 { + return field{}, false + } + return fields[0], true +} + +var fieldCache struct { + sync.RWMutex + m map[reflect.Type][]field +} + +// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. +func cachedTypeFields(t reflect.Type) []field { + fieldCache.RLock() + f := fieldCache.m[t] + fieldCache.RUnlock() + if f != nil { + return f + } + + // Compute fields without lock. + // Might duplicate effort but won't hold other computations back. + f = typeFields(t) + if f == nil { + f = []field{} + } + + fieldCache.Lock() + if fieldCache.m == nil { + fieldCache.m = map[reflect.Type][]field{} + } + fieldCache.m[t] = f + fieldCache.Unlock() + return f +} + +func isValidTag(s string) bool { + if s == "" { + return false + } + for _, c := range s { + switch { + case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): + // Backslash and quote chars are reserved, but + // otherwise any punctuation chars are allowed + // in a tag name. + default: + if !unicode.IsLetter(c) && !unicode.IsDigit(c) { + return false + } + } + } + return true +} + +const ( + caseMask = ^byte(0x20) // Mask to ignore case in ASCII. + kelvin = '\u212a' + smallLongEss = '\u017f' +) + +// foldFunc returns one of four different case folding equivalence +// functions, from most general (and slow) to fastest: +// +// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 +// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') +// 3) asciiEqualFold, no special, but includes non-letters (including _) +// 4) simpleLetterEqualFold, no specials, no non-letters. +// +// The letters S and K are special because they map to 3 runes, not just 2: +// * S maps to s and to U+017F 'ſ' Latin small letter long s +// * k maps to K and to U+212A 'K' Kelvin sign +// See http://play.golang.org/p/tTxjOc0OGo +// +// The returned function is specialized for matching against s and +// should only be given s. It's not curried for performance reasons. +func foldFunc(s []byte) func(s, t []byte) bool { + nonLetter := false + special := false // special letter + for _, b := range s { + if b >= utf8.RuneSelf { + return bytes.EqualFold + } + upper := b & caseMask + if upper < 'A' || upper > 'Z' { + nonLetter = true + } else if upper == 'K' || upper == 'S' { + // See above for why these letters are special. + special = true + } + } + if special { + return equalFoldRight + } + if nonLetter { + return asciiEqualFold + } + return simpleLetterEqualFold +} + +// equalFoldRight is a specialization of bytes.EqualFold when s is +// known to be all ASCII (including punctuation), but contains an 's', +// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. +// See comments on foldFunc. +func equalFoldRight(s, t []byte) bool { + for _, sb := range s { + if len(t) == 0 { + return false + } + tb := t[0] + if tb < utf8.RuneSelf { + if sb != tb { + sbUpper := sb & caseMask + if 'A' <= sbUpper && sbUpper <= 'Z' { + if sbUpper != tb&caseMask { + return false + } + } else { + return false + } + } + t = t[1:] + continue + } + // sb is ASCII and t is not. t must be either kelvin + // sign or long s; sb must be s, S, k, or K. + tr, size := utf8.DecodeRune(t) + switch sb { + case 's', 'S': + if tr != smallLongEss { + return false + } + case 'k', 'K': + if tr != kelvin { + return false + } + default: + return false + } + t = t[size:] + + } + if len(t) > 0 { + return false + } + return true +} + +// asciiEqualFold is a specialization of bytes.EqualFold for use when +// s is all ASCII (but may contain non-letters) and contains no +// special-folding letters. +// See comments on foldFunc. +func asciiEqualFold(s, t []byte) bool { + if len(s) != len(t) { + return false + } + for i, sb := range s { + tb := t[i] + if sb == tb { + continue + } + if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { + if sb&caseMask != tb&caseMask { + return false + } + } else { + return false + } + } + return true +} + +// simpleLetterEqualFold is a specialization of bytes.EqualFold for +// use when s is all ASCII letters (no underscores, etc) and also +// doesn't contain 'k', 'K', 's', or 'S'. +// See comments on foldFunc. +func simpleLetterEqualFold(s, t []byte) bool { + if len(s) != len(t) { + return false + } + for i, b := range s { + if b&caseMask != t[i]&caseMask { + return false + } + } + return true +} + +// tagOptions is the string following a comma in a struct field's "json" +// tag, or the empty string. It does not include the leading comma. +type tagOptions string + +// parseTag splits a struct field's json tag into its name and +// comma-separated options. +func parseTag(tag string) (string, tagOptions) { + if idx := strings.Index(tag, ","); idx != -1 { + return tag[:idx], tagOptions(tag[idx+1:]) + } + return tag, tagOptions("") +} + +// Contains reports whether a comma-separated list of options +// contains a particular substr flag. substr must be surrounded by a +// string boundary or commas. +func (o tagOptions) Contains(optionName string) bool { + if len(o) == 0 { + return false + } + s := string(o) + for s != "" { + var next string + i := strings.Index(s, ",") + if i >= 0 { + s, next = s[:i], s[i+1:] + } + if s == optionName { + return true + } + s = next + } + return false +} diff --git a/vendor/github.com/ghodss/yaml/yaml.go b/vendor/github.com/ghodss/yaml/yaml.go new file mode 100644 index 000000000..c02beacb9 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/yaml.go @@ -0,0 +1,277 @@ +package yaml + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "strconv" + + "gopkg.in/yaml.v2" +) + +// Marshals the object into JSON then converts JSON to YAML and returns the +// YAML. +func Marshal(o interface{}) ([]byte, error) { + j, err := json.Marshal(o) + if err != nil { + return nil, fmt.Errorf("error marshaling into JSON: ", err) + } + + y, err := JSONToYAML(j) + if err != nil { + return nil, fmt.Errorf("error converting JSON to YAML: ", err) + } + + return y, nil +} + +// Converts YAML to JSON then uses JSON to unmarshal into an object. +func Unmarshal(y []byte, o interface{}) error { + vo := reflect.ValueOf(o) + j, err := yamlToJSON(y, &vo) + if err != nil { + return fmt.Errorf("error converting YAML to JSON: %v", err) + } + + err = json.Unmarshal(j, o) + if err != nil { + return fmt.Errorf("error unmarshaling JSON: %v", err) + } + + return nil +} + +// Convert JSON to YAML. +func JSONToYAML(j []byte) ([]byte, error) { + // Convert the JSON to an object. + var jsonObj interface{} + // We are using yaml.Unmarshal here (instead of json.Unmarshal) because the + // Go JSON library doesn't try to pick the right number type (int, float, + // etc.) when unmarshling to interface{}, it just picks float64 + // universally. go-yaml does go through the effort of picking the right + // number type, so we can preserve number type throughout this process. + err := yaml.Unmarshal(j, &jsonObj) + if err != nil { + return nil, err + } + + // Marshal this object into YAML. + return yaml.Marshal(jsonObj) +} + +// Convert YAML to JSON. Since JSON is a subset of YAML, passing JSON through +// this method should be a no-op. +// +// Things YAML can do that are not supported by JSON: +// * In YAML you can have binary and null keys in your maps. These are invalid +// in JSON. (int and float keys are converted to strings.) +// * Binary data in YAML with the !!binary tag is not supported. If you want to +// use binary data with this library, encode the data as base64 as usual but do +// not use the !!binary tag in your YAML. This will ensure the original base64 +// encoded data makes it all the way through to the JSON. +func YAMLToJSON(y []byte) ([]byte, error) { + return yamlToJSON(y, nil) +} + +func yamlToJSON(y []byte, jsonTarget *reflect.Value) ([]byte, error) { + // Convert the YAML to an object. + var yamlObj interface{} + err := yaml.Unmarshal(y, &yamlObj) + if err != nil { + return nil, err + } + + // YAML objects are not completely compatible with JSON objects (e.g. you + // can have non-string keys in YAML). So, convert the YAML-compatible object + // to a JSON-compatible object, failing with an error if irrecoverable + // incompatibilties happen along the way. + jsonObj, err := convertToJSONableObject(yamlObj, jsonTarget) + if err != nil { + return nil, err + } + + // Convert this object to JSON and return the data. + return json.Marshal(jsonObj) +} + +func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (interface{}, error) { + var err error + + // Resolve jsonTarget to a concrete value (i.e. not a pointer or an + // interface). We pass decodingNull as false because we're not actually + // decoding into the value, we're just checking if the ultimate target is a + // string. + if jsonTarget != nil { + ju, tu, pv := indirect(*jsonTarget, false) + // We have a JSON or Text Umarshaler at this level, so we can't be trying + // to decode into a string. + if ju != nil || tu != nil { + jsonTarget = nil + } else { + jsonTarget = &pv + } + } + + // If yamlObj is a number or a boolean, check if jsonTarget is a string - + // if so, coerce. Else return normal. + // If yamlObj is a map or array, find the field that each key is + // unmarshaling to, and when you recurse pass the reflect.Value for that + // field back into this function. + switch typedYAMLObj := yamlObj.(type) { + case map[interface{}]interface{}: + // JSON does not support arbitrary keys in a map, so we must convert + // these keys to strings. + // + // From my reading of go-yaml v2 (specifically the resolve function), + // keys can only have the types string, int, int64, float64, binary + // (unsupported), or null (unsupported). + strMap := make(map[string]interface{}) + for k, v := range typedYAMLObj { + // Resolve the key to a string first. + var keyString string + switch typedKey := k.(type) { + case string: + keyString = typedKey + case int: + keyString = strconv.Itoa(typedKey) + case int64: + // go-yaml will only return an int64 as a key if the system + // architecture is 32-bit and the key's value is between 32-bit + // and 64-bit. Otherwise the key type will simply be int. + keyString = strconv.FormatInt(typedKey, 10) + case float64: + // Stolen from go-yaml to use the same conversion to string as + // the go-yaml library uses to convert float to string when + // Marshaling. + s := strconv.FormatFloat(typedKey, 'g', -1, 32) + switch s { + case "+Inf": + s = ".inf" + case "-Inf": + s = "-.inf" + case "NaN": + s = ".nan" + } + keyString = s + case bool: + if typedKey { + keyString = "true" + } else { + keyString = "false" + } + default: + return nil, fmt.Errorf("Unsupported map key of type: %s, key: %+#v, value: %+#v", + reflect.TypeOf(k), k, v) + } + + // jsonTarget should be a struct or a map. If it's a struct, find + // the field it's going to map to and pass its reflect.Value. If + // it's a map, find the element type of the map and pass the + // reflect.Value created from that type. If it's neither, just pass + // nil - JSON conversion will error for us if it's a real issue. + if jsonTarget != nil { + t := *jsonTarget + if t.Kind() == reflect.Struct { + keyBytes := []byte(keyString) + // Find the field that the JSON library would use. + var f *field + fields := cachedTypeFields(t.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, keyBytes) { + f = ff + break + } + // Do case-insensitive comparison. + if f == nil && ff.equalFold(ff.nameBytes, keyBytes) { + f = ff + } + } + if f != nil { + // Find the reflect.Value of the most preferential + // struct field. + jtf := t.Field(f.index[0]) + strMap[keyString], err = convertToJSONableObject(v, &jtf) + if err != nil { + return nil, err + } + continue + } + } else if t.Kind() == reflect.Map { + // Create a zero value of the map's element type to use as + // the JSON target. + jtv := reflect.Zero(t.Type().Elem()) + strMap[keyString], err = convertToJSONableObject(v, &jtv) + if err != nil { + return nil, err + } + continue + } + } + strMap[keyString], err = convertToJSONableObject(v, nil) + if err != nil { + return nil, err + } + } + return strMap, nil + case []interface{}: + // We need to recurse into arrays in case there are any + // map[interface{}]interface{}'s inside and to convert any + // numbers to strings. + + // If jsonTarget is a slice (which it really should be), find the + // thing it's going to map to. If it's not a slice, just pass nil + // - JSON conversion will error for us if it's a real issue. + var jsonSliceElemValue *reflect.Value + if jsonTarget != nil { + t := *jsonTarget + if t.Kind() == reflect.Slice { + // By default slices point to nil, but we need a reflect.Value + // pointing to a value of the slice type, so we create one here. + ev := reflect.Indirect(reflect.New(t.Type().Elem())) + jsonSliceElemValue = &ev + } + } + + // Make and use a new array. + arr := make([]interface{}, len(typedYAMLObj)) + for i, v := range typedYAMLObj { + arr[i], err = convertToJSONableObject(v, jsonSliceElemValue) + if err != nil { + return nil, err + } + } + return arr, nil + default: + // If the target type is a string and the YAML type is a number, + // convert the YAML type to a string. + if jsonTarget != nil && (*jsonTarget).Kind() == reflect.String { + // Based on my reading of go-yaml, it may return int, int64, + // float64, or uint64. + var s string + switch typedVal := typedYAMLObj.(type) { + case int: + s = strconv.FormatInt(int64(typedVal), 10) + case int64: + s = strconv.FormatInt(typedVal, 10) + case float64: + s = strconv.FormatFloat(typedVal, 'g', -1, 32) + case uint64: + s = strconv.FormatUint(typedVal, 10) + case bool: + if typedVal { + s = "true" + } else { + s = "false" + } + } + if len(s) > 0 { + yamlObj = interface{}(s) + } + } + return yamlObj, nil + } + + return nil, nil +} diff --git a/vendor/github.com/go-openapi/jsonpointer/.drone.sec b/vendor/github.com/go-openapi/jsonpointer/.drone.sec new file mode 100644 index 000000000..a1d7bbe07 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/.drone.sec @@ -0,0 +1 @@ +eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.pDqezepze0YqRx4u6M8GFaWtnVR-utTWZic-GX-RvMATAoYpG4H2sc9tlnGNCxa44dbRY0vY10qfBU7Sno8vkp21fsK42ofGLfen_suum_0ilm0sFS0X-kAwk7TIq5L5lPPKiChPMUiGp5oJW-g5MqMFX1jNiI-4fP-vSM3B3-eyZtJD_O517TgfIRLnblCzqwIkyRmAfPNopi-Fe8Y31TmO2Vd0nFc1Aqro_VaJSACzEVxOHTNpjETcMjlYzwgMXLeiAfLV-5hM0f6DXgHMlLSuMkB_Ndnw25dkB7hreGk4x0tHQ3X9mUfTgLq1hIDoyeeKDIM83Tqw4LBRph20BQ.qd_pNuyi23B0PlWz.JtpO7kqOm0SWOGzWDalkWheHuNd-eDpVbqI9WPAEFDOIBvz7TbsYMBlIYVWEGWbat4mkx_ejxnMn1L1l996NJnyP7eY-QE82cfPJbjx94d0Ob70KZ4DCm_UxcY2t-OKFiPJqxW7MA5jKyDuGD16bdxpjLEoe_cMSEr8FNu-MVG6wcchPcyYyRkqTQSl4mb09KikkAzHjwjo-DcO0f8ps4Uzsoc0aqAAWdE-ocG0YqierLoemjusYMiLH-eLF6MvaLRvHSte-cLzPuYCeZURnBDgxu3i3UApgddnX7g1c7tdGGBGvgCl-tEEDW58Vxgdjksim2S7y3lfoJ8FFzSWeRH2y7Kq04hgew3b2J_RiDB9ejzIopzG8ZGjJa3EO1-i9ORTl12nXK1RdlLGqu604ENaeVOPCIHL-0C8e6_wHdUGHydLZImSxKYSrNvy8resP1D_9t4B-3q2mkS9mhnMONrXbPDVw5QY5mvXlWs0Db99ARwzsl-Qlu0A_tsZwMjWT2I1QMvWPyTRScmMm0FJSv9zStjzxWa_q2GL7Naz1fI4Dd6ZgNJWYYq-mHN5chEeBdIcwb_zMPHczMQXXNL5nmfRGM1aPffkToFWCDpIlI8IXec83ZC6_POxZegS6n9Drrvc.6Nz8EXxs1lWX3ASaCeNElA \ No newline at end of file diff --git a/vendor/github.com/go-openapi/jsonpointer/.drone.yml b/vendor/github.com/go-openapi/jsonpointer/.drone.yml new file mode 100644 index 000000000..cb8c7b50a --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/.drone.yml @@ -0,0 +1,32 @@ +clone: + path: github.com/go-openapi/jsonpointer + +matrix: + GO_VERSION: + - "1.6" + +build: + integration: + image: golang:$$GO_VERSION + pull: true + commands: + - go get -u github.com/stretchr/testify/assert + - go get -u github.com/go-openapi/swag + - go test -race + - go test -v -cover -coverprofile=coverage.out -covermode=count ./... + +notify: + slack: + channel: bots + webhook_url: $$SLACK_URL + username: drone + +publish: + coverage: + server: https://coverage.vmware.run + token: $$GITHUB_TOKEN + # threshold: 70 + # must_increase: true + when: + matrix: + GO_VERSION: "1.6" diff --git a/vendor/github.com/go-openapi/jsonpointer/.gitignore b/vendor/github.com/go-openapi/jsonpointer/.gitignore new file mode 100644 index 000000000..769c24400 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/.gitignore @@ -0,0 +1 @@ +secrets.yml diff --git a/vendor/github.com/go-openapi/jsonpointer/.pullapprove.yml b/vendor/github.com/go-openapi/jsonpointer/.pullapprove.yml new file mode 100644 index 000000000..5ec183e22 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/.pullapprove.yml @@ -0,0 +1,13 @@ +approve_by_comment: true +approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)' +reject_regex: ^[Rr]ejected +reset_on_push: false +reviewers: + members: + - casualjim + - chancez + - frapposelli + - vburenin + - pytlesk4 + name: pullapprove + required: 1 diff --git a/vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/jsonpointer/LICENSE b/vendor/github.com/go-openapi/jsonpointer/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/go-openapi/jsonpointer/README.md b/vendor/github.com/go-openapi/jsonpointer/README.md new file mode 100644 index 000000000..9c9b1fd48 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/README.md @@ -0,0 +1,15 @@ +# gojsonpointer [![Build Status](https://ci.vmware.run/api/badges/go-openapi/jsonpointer/status.svg)](https://ci.vmware.run/go-openapi/jsonpointer) [![Coverage](https://coverage.vmware.run/badges/go-openapi/jsonpointer/coverage.svg)](https://coverage.vmware.run/go-openapi/jsonpointer) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonpointer?status.svg)](http://godoc.org/github.com/go-openapi/jsonpointer) +An implementation of JSON Pointer - Go language + +## Status +Completed YES + +Tested YES + +## References +http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 + +### Note +The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array, the reference token MUST contain either...' is not implemented. diff --git a/vendor/github.com/go-openapi/jsonpointer/pointer.go b/vendor/github.com/go-openapi/jsonpointer/pointer.go new file mode 100644 index 000000000..39dd012c2 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/pointer.go @@ -0,0 +1,238 @@ +// Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author sigu-399 +// author-github https://github.com/sigu-399 +// author-mail sigu.399@gmail.com +// +// repository-name jsonpointer +// repository-desc An implementation of JSON Pointer - Go language +// +// description Main and unique file. +// +// created 25-02-2013 + +package jsonpointer + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "strings" + + "github.com/go-openapi/swag" +) + +const ( + emptyPointer = `` + pointerSeparator = `/` + + invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator +) + +var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem() + +// JSONPointable is an interface for structs to implement when they need to customize the +// json pointer process +type JSONPointable interface { + JSONLookup(string) (interface{}, error) +} + +type implStruct struct { + mode string // "SET" or "GET" + + inDocument interface{} + + setInValue interface{} + + getOutNode interface{} + getOutKind reflect.Kind + outError error +} + +// New creates a new json pointer for the given string +func New(jsonPointerString string) (Pointer, error) { + + var p Pointer + err := p.parse(jsonPointerString) + return p, err + +} + +// Pointer the json pointer reprsentation +type Pointer struct { + referenceTokens []string +} + +// "Constructor", parses the given string JSON pointer +func (p *Pointer) parse(jsonPointerString string) error { + + var err error + + if jsonPointerString != emptyPointer { + if !strings.HasPrefix(jsonPointerString, pointerSeparator) { + err = errors.New(invalidStart) + } else { + referenceTokens := strings.Split(jsonPointerString, pointerSeparator) + for _, referenceToken := range referenceTokens[1:] { + p.referenceTokens = append(p.referenceTokens, referenceToken) + } + } + } + + return err +} + +// Get uses the pointer to retrieve a value from a JSON document +func (p *Pointer) Get(document interface{}) (interface{}, reflect.Kind, error) { + return p.get(document, swag.DefaultJSONNameProvider) +} + +// GetForToken gets a value for a json pointer token 1 level deep +func GetForToken(document interface{}, decodedToken string) (interface{}, reflect.Kind, error) { + return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider) +} + +func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) { + kind := reflect.Invalid + rValue := reflect.Indirect(reflect.ValueOf(node)) + kind = rValue.Kind() + switch kind { + + case reflect.Struct: + if rValue.Type().Implements(jsonPointableType) { + r, err := node.(JSONPointable).JSONLookup(decodedToken) + if err != nil { + return nil, kind, err + } + return r, kind, nil + } + nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) + if !ok { + return nil, kind, fmt.Errorf("object has no field %q", decodedToken) + } + fld := rValue.FieldByName(nm) + return fld.Interface(), kind, nil + + case reflect.Map: + kv := reflect.ValueOf(decodedToken) + mv := rValue.MapIndex(kv) + if mv.IsValid() && !swag.IsZero(mv) { + return mv.Interface(), kind, nil + } + return nil, kind, fmt.Errorf("object has no key %q", decodedToken) + + case reflect.Slice: + tokenIndex, err := strconv.Atoi(decodedToken) + if err != nil { + return nil, kind, err + } + sLength := rValue.Len() + if tokenIndex < 0 || tokenIndex >= sLength { + return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex) + } + + elem := rValue.Index(tokenIndex) + return elem.Interface(), kind, nil + + default: + return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken) + } + +} + +func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) { + + if nameProvider == nil { + nameProvider = swag.DefaultJSONNameProvider + } + + kind := reflect.Invalid + + // Full document when empty + if len(p.referenceTokens) == 0 { + return node, kind, nil + } + + for _, token := range p.referenceTokens { + + decodedToken := Unescape(token) + + r, knd, err := getSingleImpl(node, decodedToken, nameProvider) + if err != nil { + return nil, knd, err + } + node, kind = r, knd + + } + + rValue := reflect.ValueOf(node) + kind = rValue.Kind() + + return node, kind, nil +} + +// DecodedTokens returns the decoded tokens +func (p *Pointer) DecodedTokens() []string { + result := make([]string, 0, len(p.referenceTokens)) + for _, t := range p.referenceTokens { + result = append(result, Unescape(t)) + } + return result +} + +// IsEmpty returns true if this is an empty json pointer +// this indicates that it points to the root document +func (p *Pointer) IsEmpty() bool { + return len(p.referenceTokens) == 0 +} + +// Pointer to string representation function +func (p *Pointer) String() string { + + if len(p.referenceTokens) == 0 { + return emptyPointer + } + + pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator) + + return pointerString +} + +// Specific JSON pointer encoding here +// ~0 => ~ +// ~1 => / +// ... and vice versa + +const ( + encRefTok0 = `~0` + encRefTok1 = `~1` + decRefTok0 = `~` + decRefTok1 = `/` +) + +// Unescape unescapes a json pointer reference token string to the original representation +func Unescape(token string) string { + step1 := strings.Replace(token, encRefTok1, decRefTok1, -1) + step2 := strings.Replace(step1, encRefTok0, decRefTok0, -1) + return step2 +} + +// Escape escapes a pointer reference token string +func Escape(token string) string { + step1 := strings.Replace(token, decRefTok0, encRefTok0, -1) + step2 := strings.Replace(step1, decRefTok1, encRefTok1, -1) + return step2 +} diff --git a/vendor/github.com/go-openapi/jsonreference/.drone.sec b/vendor/github.com/go-openapi/jsonreference/.drone.sec new file mode 100644 index 000000000..5ff54fb9c --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/.drone.sec @@ -0,0 +1 @@ +eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.Xe40Wx6g5Y-iN0JVMhKyFfubtOId3zAVE564szw_yYGzFNhc_cGZO9F3BtAcJ55CfHG9C_ozn9dpnUDl_zYZoy_6cPCq13Ekb95z8NAC3ekDtbAATsc9HZwRNwI7UfkhstdwxljEouGB01qoLcUn6lFutrou-Ho21COHeDb2caemnPSA-rEAnXkOiBFu0RQ1MIwMygzvHXIHHYNpNwAtXqmiggM10miSjqBM3JmRPxCi7VK6_Rxij5p6LlhmK1BDi8Y6oBh-9BX3--5GAJeWZ6Vof5TnP-Enioia18j8c8KFtfY4q0y6Ednjb-AarLZ12gj695ppkBNJUdTJQmwGwA.fVcz_RiLrUB5fgMS.rjWllDYC6m_NB-ket_LizNEy9mlJ27odBTZQcMKaUqqXZBtWUCmPrOoMXGq-_cc-c7chg7D-WMh9SPQ23pV0P-DY-jsDpbOqHG2STOMEfW9ZREoaOLJXQaWcuBldLjRyWFcq0HGj97LgE6szD1Zlou3bmdHS_Q-U9Up9YQ_8_YnDcESD_cj1w5FZom7HjchKJFeGjQjfDQpoCKCQNMJaavUqy9jHQEeQ_uVocSrETg3GpewDcUF2tuv8uGq7ZZWu7Vl8zmnY1MFTynaGBWzTCSRmCkAXjcsaUheDP_NT5D7k-xUS6LwtqEUiXAXV07SNFraorFj5lnBQZRDlZMYcA3NWR6zHiOxekR9LBYPofst6w1rIqUchj_5m1tDpVTBMPir1eAaFcnJtPgo4ch17OF-kmcmQGLhJI3U7n8wv4sTrmP1dewtRRKrvlJe5r3_6eDiK4xZ8K0rnK1D4g6zuQqU1gA8KaU7pmZkKpFx3Bew4v-6DH32YwQBvAI7Lbb8afou9WsCNB_iswz5XGimP4bifiJRwpWBEz9VGhZFdiw-hZpYWgbxzVb5gtqfTDLIvpbLDmFz1vge16uUQHHVFpo1pSozyr7A60X8qsh9pmmO3RcJ-ZGZBWqiRC-Kl5ejz7WQ.LFoK4Ibi11B2lWQ5WcPSag \ No newline at end of file diff --git a/vendor/github.com/go-openapi/jsonreference/.drone.yml b/vendor/github.com/go-openapi/jsonreference/.drone.yml new file mode 100644 index 000000000..157ffe579 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/.drone.yml @@ -0,0 +1,33 @@ +clone: + path: github.com/go-openapi/jsonreference + +matrix: + GO_VERSION: + - "1.6" + +build: + integration: + image: golang:$$GO_VERSION + pull: true + commands: + - go get -u github.com/stretchr/testify/assert + - go get -u github.com/PuerkitoBio/purell + - go get -u github.com/go-openapi/jsonpointer + - go test -race + - go test -v -cover -coverprofile=coverage.out -covermode=count ./... + +notify: + slack: + channel: bots + webhook_url: $$SLACK_URL + username: drone + +publish: + coverage: + server: https://coverage.vmware.run + token: $$GITHUB_TOKEN + # threshold: 70 + # must_increase: true + when: + matrix: + GO_VERSION: "1.6" diff --git a/vendor/github.com/go-openapi/jsonreference/.gitignore b/vendor/github.com/go-openapi/jsonreference/.gitignore new file mode 100644 index 000000000..769c24400 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/.gitignore @@ -0,0 +1 @@ +secrets.yml diff --git a/vendor/github.com/go-openapi/jsonreference/.pullapprove.yml b/vendor/github.com/go-openapi/jsonreference/.pullapprove.yml new file mode 100644 index 000000000..5ec183e22 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/.pullapprove.yml @@ -0,0 +1,13 @@ +approve_by_comment: true +approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)' +reject_regex: ^[Rr]ejected +reset_on_push: false +reviewers: + members: + - casualjim + - chancez + - frapposelli + - vburenin + - pytlesk4 + name: pullapprove + required: 1 diff --git a/vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/jsonreference/LICENSE b/vendor/github.com/go-openapi/jsonreference/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/go-openapi/jsonreference/README.md b/vendor/github.com/go-openapi/jsonreference/README.md new file mode 100644 index 000000000..5f7881274 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/README.md @@ -0,0 +1,15 @@ +# gojsonreference [![Build Status](https://ci.vmware.run/api/badges/go-openapi/jsonreference/status.svg)](https://ci.vmware.run/go-openapi/jsonreference) [![Coverage](https://coverage.vmware.run/badges/go-openapi/jsonreference/coverage.svg)](https://coverage.vmware.run/go-openapi/jsonreference) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonreference/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonreference?status.svg)](http://godoc.org/github.com/go-openapi/jsonreference) +An implementation of JSON Reference - Go language + +## Status +Work in progress ( 90% done ) + +## Dependencies +https://github.com/xeipuuv/gojsonpointer + +## References +http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 + +http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03 diff --git a/vendor/github.com/go-openapi/jsonreference/reference.go b/vendor/github.com/go-openapi/jsonreference/reference.go new file mode 100644 index 000000000..3bc0a6e26 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/reference.go @@ -0,0 +1,156 @@ +// Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author sigu-399 +// author-github https://github.com/sigu-399 +// author-mail sigu.399@gmail.com +// +// repository-name jsonreference +// repository-desc An implementation of JSON Reference - Go language +// +// description Main and unique file. +// +// created 26-02-2013 + +package jsonreference + +import ( + "errors" + "net/url" + "strings" + + "github.com/PuerkitoBio/purell" + "github.com/go-openapi/jsonpointer" +) + +const ( + fragmentRune = `#` +) + +// New creates a new reference for the given string +func New(jsonReferenceString string) (Ref, error) { + + var r Ref + err := r.parse(jsonReferenceString) + return r, err + +} + +// MustCreateRef parses the ref string and panics when it's invalid. +// Use the New method for a version that returns an error +func MustCreateRef(ref string) Ref { + r, err := New(ref) + if err != nil { + panic(err) + } + return r +} + +// Ref represents a json reference object +type Ref struct { + referenceURL *url.URL + referencePointer jsonpointer.Pointer + + HasFullURL bool + HasURLPathOnly bool + HasFragmentOnly bool + HasFileScheme bool + HasFullFilePath bool +} + +// GetURL gets the URL for this reference +func (r *Ref) GetURL() *url.URL { + return r.referenceURL +} + +// GetPointer gets the json pointer for this reference +func (r *Ref) GetPointer() *jsonpointer.Pointer { + return &r.referencePointer +} + +// String returns the best version of the url for this reference +func (r *Ref) String() string { + + if r.referenceURL != nil { + return r.referenceURL.String() + } + + if r.HasFragmentOnly { + return fragmentRune + r.referencePointer.String() + } + + return r.referencePointer.String() +} + +// IsRoot returns true if this reference is a root document +func (r *Ref) IsRoot() bool { + return r.referenceURL != nil && + !r.IsCanonical() && + !r.HasURLPathOnly && + r.referenceURL.Fragment == "" +} + +// IsCanonical returns true when this pointer starts with http(s):// or file:// +func (r *Ref) IsCanonical() bool { + return (r.HasFileScheme && r.HasFullFilePath) || (!r.HasFileScheme && r.HasFullURL) +} + +// "Constructor", parses the given string JSON reference +func (r *Ref) parse(jsonReferenceString string) error { + + parsed, err := url.Parse(jsonReferenceString) + if err != nil { + return err + } + + r.referenceURL, _ = url.Parse(purell.NormalizeURL(parsed, purell.FlagsSafe|purell.FlagRemoveDuplicateSlashes)) + refURL := r.referenceURL + + if refURL.Scheme != "" && refURL.Host != "" { + r.HasFullURL = true + } else { + if refURL.Path != "" { + r.HasURLPathOnly = true + } else if refURL.RawQuery == "" && refURL.Fragment != "" { + r.HasFragmentOnly = true + } + } + + r.HasFileScheme = refURL.Scheme == "file" + r.HasFullFilePath = strings.HasPrefix(refURL.Path, "/") + + // invalid json-pointer error means url has no json-pointer fragment. simply ignore error + r.referencePointer, _ = jsonpointer.New(refURL.Fragment) + + return nil +} + +// Inherits creates a new reference from a parent and a child +// If the child cannot inherit from the parent, an error is returned +func (r *Ref) Inherits(child Ref) (*Ref, error) { + childURL := child.GetURL() + parentURL := r.GetURL() + if childURL == nil { + return nil, errors.New("child url is nil") + } + if parentURL == nil { + return &child, nil + } + + ref, err := New(parentURL.ResolveReference(childURL).String()) + if err != nil { + return nil, err + } + return &ref, nil +} diff --git a/vendor/github.com/go-openapi/spec/.editorconfig b/vendor/github.com/go-openapi/spec/.editorconfig new file mode 100644 index 000000000..3152da69a --- /dev/null +++ b/vendor/github.com/go-openapi/spec/.editorconfig @@ -0,0 +1,26 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +# Set default charset +[*.{js,py,go,scala,rb,java,html,css,less,sass,md}] +charset = utf-8 + +# Tab indentation (no size specified) +[*.go] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/vendor/github.com/go-openapi/spec/.gitignore b/vendor/github.com/go-openapi/spec/.gitignore new file mode 100644 index 000000000..dd91ed6a0 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/.gitignore @@ -0,0 +1,2 @@ +secrets.yml +coverage.out diff --git a/vendor/github.com/go-openapi/spec/.travis.yml b/vendor/github.com/go-openapi/spec/.travis.yml new file mode 100644 index 000000000..ea80ef2a7 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/.travis.yml @@ -0,0 +1,16 @@ +language: go +go: +- 1.7 +install: +- go get -u github.com/stretchr/testify +- go get -u github.com/go-openapi/swag +- go get -u gopkg.in/yaml.v2 +- go get -u github.com/go-openapi/jsonpointer +- go get -u github.com/go-openapi/jsonreference +script: +- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./... +after_success: +- bash <(curl -s https://codecov.io/bash) +notifications: + slack: + secure: QUWvCkBBK09GF7YtEvHHVt70JOkdlNBG0nIKu/5qc4/nW5HP8I2w0SEf/XR2je0eED1Qe3L/AfMCWwrEj+IUZc3l4v+ju8X8R3Lomhme0Eb0jd1MTMCuPcBT47YCj0M7RON7vXtbFfm1hFJ/jLe5+9FXz0hpXsR24PJc5ZIi/ogNwkaPqG4BmndzecpSh0vc2FJPZUD9LT0I09REY/vXR0oQAalLkW0asGD5taHZTUZq/kBpsNxaAFrLM23i4mUcf33M5fjLpvx5LRICrX/57XpBrDh2TooBU6Qj3CgoY0uPRYUmSNxbVx1czNzl2JtEpb5yjoxfVPQeg0BvQM00G8LJINISR+ohrjhkZmAqchDupAX+yFrxTtORa78CtnIL6z/aTNlgwwVD8kvL/1pFA/JWYmKDmz93mV/+6wubGzNSQCstzjkFA4/iZEKewKUoRIAi/fxyscP6L/rCpmY/4llZZvrnyTqVbt6URWpopUpH4rwYqreXAtJxJsfBJIeSmUIiDIOMGkCTvyTEW3fWGmGoqWtSHLoaWDyAIGb7azb+KvfpWtEcoPFWfSWU+LGee0A/YsUhBl7ADB9A0CJEuR8q4BPpKpfLwPKSiKSAXL7zDkyjExyhtgqbSl2jS+rKIHOZNL8JkCcTP2MKMVd563C5rC5FMKqu3S9m2b6380E= diff --git a/vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/spec/LICENSE b/vendor/github.com/go-openapi/spec/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/go-openapi/spec/README.md b/vendor/github.com/go-openapi/spec/README.md new file mode 100644 index 000000000..1d1622082 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/README.md @@ -0,0 +1,5 @@ +# OAI object model [![Build Status](https://travis-ci.org/go-openapi/spec.svg?branch=master)](https://travis-ci.org/go-openapi/spec) [![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/spec?status.svg)](http://godoc.org/github.com/go-openapi/spec) + +The object model for OpenAPI specification documents diff --git a/vendor/github.com/go-openapi/spec/bindata.go b/vendor/github.com/go-openapi/spec/bindata.go new file mode 100644 index 000000000..9afb5df19 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/bindata.go @@ -0,0 +1,260 @@ +// Code generated by go-bindata. +// sources: +// schemas/jsonschema-draft-04.json +// schemas/v2/schema.json +// DO NOT EDIT! + +package spec + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _jsonschemaDraft04JSON = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\x57\x3b\x6f\xdb\x3e\x10\xdf\xf3\x29\x08\x26\x63\xf2\x97\xff\x40\x27\x6f\x45\xbb\x18\x68\xd1\x0c\xdd\x0c\x0f\xb4\x75\xb2\x19\x50\xa4\x42\x51\x81\x0d\x43\xdf\xbd\xa0\xa8\x07\x29\x91\x92\x2d\xbb\x8d\x97\x28\xbc\xd7\xef\x8e\xf7\xe2\xf9\x01\x21\x84\x30\x8d\xf1\x12\xe1\x83\x52\xd9\x32\x8a\xde\x72\xc1\x5f\xf2\xdd\x01\x52\xf2\x9f\x90\xfb\x28\x96\x24\x51\x2f\x8b\x2f\x91\x39\x7b\xc4\xcf\x46\xe8\xc9\xfc\x3f\x43\x32\x86\x7c\x27\x69\xa6\xa8\xe0\x5a\xfa\x9b\x90\x80\x0c\x0b\x4a\x41\x91\x5a\x45\xc7\x9d\x50\x4e\x35\x73\x8e\x97\xc8\x20\xae\x08\x86\xed\xab\x94\xe4\xe4\x10\x2a\xa2\x3a\x65\xa0\x95\x93\x8a\xfc\xec\x12\x53\xca\x57\x0a\x52\xad\xef\xff\x1e\x89\xd6\xe7\x67\x84\x9f\x24\x24\x5a\xc5\x23\x46\x65\xcb\x54\x76\xfc\x38\x13\x39\x55\xf4\x03\x56\x5c\xc1\x1e\x64\x18\x04\xad\x19\x86\x30\x68\x5a\xa4\x78\x89\x16\x97\xe8\xff\x0e\x09\x29\x98\x5a\x0c\xed\x10\xc6\x7e\x69\xa8\x6b\x07\x76\x64\x45\x2e\xea\x63\x45\xe5\xb3\x66\x8e\x8d\x4e\x0d\x01\x95\x68\xe3\x85\x91\xd3\x34\x63\xf0\xfb\x94\x41\x3e\x34\x0d\xbc\x72\x60\xdd\x46\x1a\xe1\xad\x10\x0c\x08\xd7\x9f\xad\xe3\x08\xf3\x82\x31\xf3\x37\xdd\x9a\x13\xb1\x7d\x83\x9d\xd2\x5f\xb9\x92\x94\xef\x71\xc8\x7e\x45\x9d\x73\xcf\xd6\x65\x36\x7c\x8d\xa9\xf2\xf2\x94\x28\x38\x7d\x2f\xa0\xa1\x2a\x59\x40\x07\xf3\xc1\x02\xdb\xda\x68\x1c\x33\xa7\x99\x14\x19\x48\x45\x7b\xd1\x33\x45\x17\xf0\xa6\x46\xd9\x03\x92\x08\x99\x12\x7d\x57\xb8\x90\x14\x7b\x63\xd5\x15\xe5\xbd\x35\x2b\xaa\x18\x4c\xea\xf5\x8a\xba\xf5\x3e\x4b\x41\x93\xa5\x67\xfb\x38\x2d\x98\xa2\x19\x83\x2a\xf7\x03\x6a\x9b\x74\x0b\x56\x5e\x8f\x02\xc7\x1d\x2b\x72\xfa\x01\x3f\x5b\x16\xf7\xc6\x6d\xfb\xe4\x58\xb3\x8c\x1b\xf7\x0a\x77\x86\xa6\xb4\xb4\xf5\xe4\x92\xbb\xa0\x24\x84\xe5\x01\x84\xad\x13\x37\x21\x9c\xd2\x72\x0b\x42\x72\xfc\x01\x7c\xaf\x0e\xbd\x9e\x3b\xd5\xbc\x1c\x1f\xaf\xd6\xd0\xb6\x52\xb7\xdf\x12\xa5\x40\x4e\xe7\x68\xb0\x78\x24\xec\xe1\xe8\x0f\x26\x89\xe3\x0a\x0a\x61\x4d\x23\xe9\xf7\x70\x7e\x32\x3d\xdc\x39\xd6\xbf\xf3\x30\xd0\xfd\xf6\x55\xb3\x79\x27\x96\xfe\x6d\x82\x37\x73\xf6\x8f\x36\x3a\x03\xa4\x6d\x7d\x1c\x9e\x73\x35\xf6\x18\xbf\x15\x76\x4a\x8e\x2b\xcf\x00\xbf\x2a\x99\xae\x55\xe0\xcf\x25\x77\x68\xfc\x95\xba\x79\x75\x06\xcb\x5c\x77\x67\x69\xf1\xfb\x2c\xe1\xbd\xa0\x12\xe2\x31\x45\xf6\x30\x0f\x14\xc8\xab\x7f\x60\x4e\x27\xe0\x3f\xaf\x92\xd0\x6a\x8a\x82\xdb\xc0\xa4\xbb\x63\x65\x34\x0d\x28\xb0\x6b\x7c\x1e\x1e\xd3\x51\xc7\x6e\xf4\x33\x60\xc5\x90\x01\x8f\x81\xef\xee\x88\x68\x90\x69\x23\xb9\x8a\x2e\x69\x98\x7d\xa6\x91\x32\x1a\xc8\x6e\x9c\x13\x7f\x10\xea\xcd\xfd\x4e\xef\xa6\xb1\x25\xd9\xde\x22\x8d\xfa\x59\x63\xc5\x0d\x80\xf5\x28\xf1\xd6\xb9\x37\x9e\xa3\xee\xb5\x4c\xbe\x37\xe0\x55\xc6\x27\x82\x75\x49\xd0\xda\xe0\xb9\x1d\xca\xbf\x5b\xd4\xcf\xbf\x0b\x47\xac\x2d\x59\x07\xfe\x7a\x49\xc1\x61\xa6\x24\x17\x2a\xf0\xbe\x2e\xdb\x17\x7f\xa0\x3c\x7d\x4b\xf3\xba\xdb\xc3\xed\x06\xee\xdb\x5e\xd7\xdd\x42\x5c\x47\xb2\xb3\x68\x75\x8c\xf2\xe1\x4f\x00\x00\x00\xff\xff\x4e\x9b\x8d\xdf\x17\x11\x00\x00") + +func jsonschemaDraft04JSONBytes() ([]byte, error) { + return bindataRead( + _jsonschemaDraft04JSON, + "jsonschema-draft-04.json", + ) +} + +func jsonschemaDraft04JSON() (*asset, error) { + bytes, err := jsonschemaDraft04JSONBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "jsonschema-draft-04.json", size: 4375, mode: os.FileMode(420), modTime: time.Unix(1482389892, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _v2SchemaJSON = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xec\x5d\x4f\x93\xdb\x36\xb2\xbf\xfb\x53\xa0\x14\x57\xd9\xae\xd8\x92\xe3\xf7\x2e\xcf\x97\xd4\xbc\xd8\x49\x66\x37\x5e\x4f\x79\x26\xbb\x87\x78\x5c\x05\x91\x2d\x09\x09\x09\x30\x00\x38\x33\x5a\xef\x7c\xf7\x2d\xf0\x9f\x08\x02\x20\x41\x8a\xd2\xc8\x0e\x0f\xa9\x78\x28\xa0\xd1\xdd\x68\x34\x7e\xdd\xf8\xf7\xf9\x11\x42\x33\x49\x64\x04\xb3\xd7\x68\x76\x86\xfe\x76\xf9\xfe\x1f\xe8\x32\xd8\x40\x8c\xd1\x8a\x71\x74\x79\x8b\xd7\x6b\xe0\xe8\xd5\xfc\x25\x3a\xbb\x38\x9f\xcf\x9e\xab\x0a\x24\x54\xa5\x37\x52\x26\xaf\x17\x0b\x91\x17\x99\x13\xb6\xb8\x79\xb5\x10\x59\xdd\xf9\xef\x82\xd1\x6f\xf2\xc2\x8f\xf3\x4f\xb5\x1a\xea\xc7\x17\x45\x41\xc6\xd7\x8b\x90\xe3\x95\x7c\xf1\xf2\x7f\x8b\xca\x45\x3d\xb9\x4d\x32\xa6\xd8\xf2\x77\x08\x64\xfe\x8d\xc3\x9f\x29\xe1\xa0\x9a\xff\xed\x11\x42\x08\xcd\x8a\xd6\xb3\x9f\x15\x67\x74\xc5\xca\x7f\x27\x58\x6e\xc4\xec\x11\x42\xd7\x59\x5d\x1c\x86\x44\x12\x46\x71\x74\xc1\x59\x02\x5c\x12\x10\xb3\xd7\x68\x85\x23\x01\x59\x81\x04\x4b\x09\x9c\x6a\xbf\x7e\xce\x49\x7d\xba\x7b\x51\xfd\xa1\x44\xe2\xb0\x52\xac\x7d\xb3\x08\x61\x45\x68\x46\x56\x2c\x6e\x80\x86\x8c\xbf\xbd\x93\x40\x05\x61\x74\x96\x95\xbe\x7f\x84\xd0\x7d\x4e\xde\x42\xb7\xe4\xbe\x46\xbb\x14\x5b\x48\x4e\xe8\xba\x90\x05\xa1\x19\xd0\x34\xae\xc4\xce\xbe\xbc\x9a\xbf\x9c\x15\x7f\x5d\x57\xc5\x42\x10\x01\x27\x89\xe2\x48\x51\xb9\xda\x40\xd5\x87\x37\xc0\x15\x5f\x88\xad\x90\xdc\x10\x81\x42\x16\xa4\x31\x50\x39\x2f\x38\xad\xab\xb0\x53\xd8\xac\x94\x56\x6f\xc3\x84\xf4\x11\xa4\x50\xb3\xfa\xe9\xd3\x6f\x9f\x3e\xdf\x2f\xd0\xeb\x8f\x1f\x3f\x7e\xbc\xfe\xf6\xe9\xf7\xaf\x5f\x7f\xfc\x18\x7e\xfb\xec\xfb\xc7\xb3\x36\x79\x54\x43\xe8\x29\xc5\x31\x20\xc6\x11\x49\x9e\xe5\x12\x41\x66\xa0\xe8\xed\x1d\x8e\x93\x08\x5e\xa3\x27\x3b\xc3\x7c\xa2\x73\xba\xc4\x02\x2e\xb0\xdc\xf4\xe5\x76\xd1\xca\x96\xa2\x8a\x94\xcd\x21\xc9\x6c\xec\x2c\x70\x42\x9e\x34\x74\x9d\x19\x7c\xcd\x20\x9c\xea\x2e\x0a\xfe\x42\x84\xd4\x29\x04\x8c\x8a\xb4\x41\xa2\xc1\xdc\x19\x8a\x88\x90\x4a\x49\xef\xce\xdf\xbd\x45\x4a\x52\x81\x70\x10\x40\x22\x21\x44\xcb\x6d\xc5\xec\x4e\x3c\x1c\x45\xef\x57\x9a\xb5\x7d\xae\xfe\xe5\xe4\x31\x86\x90\xe0\xab\x6d\x02\x3b\x2e\xcb\x11\x90\xd9\xa8\xc6\x77\xc2\x59\x98\x06\xfd\xf9\x2e\x78\x45\x01\xa6\xa8\xa0\x71\x5c\xbe\x33\xa7\xd2\xd9\x5f\x95\xef\xd9\xd5\xac\xfd\xdc\x5d\xbf\x5e\xb8\xd1\x3e\xc7\x31\x48\xe0\x5e\x4c\x14\x65\xdf\xb8\xa8\x71\x10\x09\xa3\xc2\xc7\x02\xcb\xa2\x4e\x5a\x02\x82\x94\x13\xb9\xf5\x30\xe6\xb2\xa4\xb5\xfe\x9b\x3e\x7a\xb2\x55\xd2\xa8\x4a\xbc\x16\xb6\x71\x8e\x39\xc7\xdb\x9d\xe1\x10\x09\x71\xbd\x9c\xb3\x41\x89\xd7\xa5\x89\xdc\x57\xb5\x53\x4a\xfe\x4c\xe1\xbc\xa0\x21\x79\x0a\x1a\x0f\x70\xa7\x5c\x08\x8e\xde\xb0\xc0\x43\x24\xad\x74\x63\x0e\xb1\xd9\x90\xe1\xb0\x2d\x13\xa7\x6d\x78\xfd\x04\x14\x38\x8e\x90\xaa\xce\x63\xac\x3e\x23\xbc\x64\xa9\xb4\xf8\x03\x63\xde\xcd\xbe\x16\x13\x4a\x55\xac\x82\x12\xc6\xac\xd4\x35\xf7\x22\xd4\x3a\xff\x22\x73\x0e\x6e\x51\xa0\x75\x1e\xae\x8f\xe8\x5d\xc7\x59\xe6\xe4\x9a\x18\x8d\xd6\x1c\x53\x84\x4d\xb7\x67\x28\x37\x09\x84\x69\x88\x12\x0e\x01\x11\x80\x32\xa2\xf5\xb9\xaa\xc6\xd9\x73\x53\xab\xfb\xb4\x2e\x20\xc6\x54\x92\xa0\x9a\xf3\x69\x1a\x2f\x81\x77\x37\xae\x53\x1a\xce\x40\xc4\xa8\x82\x1c\xb5\xef\xda\x24\x7d\xb9\x61\x69\x14\xa2\x25\xa0\x90\xac\x56\xc0\x81\x4a\xb4\xe2\x2c\xce\x4a\x64\x7a\x9a\x23\xf4\x13\x91\x3f\xa7\x4b\xf4\x63\x84\x6f\x18\x87\x10\xbd\xc3\xfc\x8f\x90\xdd\x52\x44\x04\xc2\x51\xc4\x6e\x21\x74\x48\x21\x81\xc7\xe2\xfd\xea\x12\xf8\x0d\x09\xf6\xe9\x47\x35\xaf\x67\xc4\x14\xf7\x22\x27\x97\xe1\xe2\x76\x2d\x06\x8c\x4a\x1c\x48\x3f\x73\x2d\x0b\x5b\x29\x45\x24\x00\x2a\x0c\x11\xec\x94\xca\xc2\xa6\xc1\x37\x21\x43\x83\x3b\x5f\x97\xf1\x43\x5e\x53\x73\x19\xa5\x36\xd8\x2d\x05\x2e\x34\x0b\xeb\x39\xfc\x1d\x63\x51\x01\xbd\x3d\xbb\x90\x84\x40\x25\x59\x6d\x09\x5d\xa3\x1c\x37\xe6\x5c\x16\x9a\x40\x09\x70\xc1\xe8\x82\xf1\x35\xa6\xe4\xdf\x99\x5c\x8e\x9e\x4d\x79\xb4\x27\x2f\xbf\x7e\xf8\x05\x25\x8c\x50\xa9\x98\x29\x90\x62\x60\xea\x75\xae\x13\xca\xbf\x2b\x1a\x29\x27\x76\xd6\x20\xc6\x64\x5f\xe6\x32\x1a\x08\x87\x21\x07\x21\xbc\xb4\xe4\xe0\x32\x67\xa6\xcd\xf3\x1e\xcd\xd9\x6b\xb6\x6f\x8e\x27\xa7\xed\xdb\xe7\xbc\xcc\x1a\x07\xce\x6f\x87\x33\xf0\xba\x51\x17\x22\x66\x78\x79\x8e\xce\xe5\x13\x81\x80\x06\x2c\xe5\x78\x0d\xa1\xb2\xb8\x54\xa8\x79\x09\xbd\xbf\x3c\x47\x01\x8b\x13\x2c\xc9\x32\xaa\xaa\x1d\xd5\xee\xab\x36\xbd\x6c\xfd\x54\x6c\xc8\x08\x01\x3c\xbd\xe7\x07\x88\xb0\x24\x37\x79\x90\x28\x4a\x1d\x10\x1a\x92\x1b\x12\xa6\x38\x42\x40\xc3\x4c\x43\x62\x8e\xae\x36\xb0\x45\x71\x2a\xa4\x9a\x23\x79\x59\xb1\xa8\xf2\xa4\x0c\x60\x9f\xcc\x8d\x40\xf5\x80\xca\xa8\x99\xc3\xa7\x85\x1f\x31\x25\xa9\x82\xc5\x6d\xbd\xd8\x36\x76\x7c\x02\x28\x97\xf6\x1d\x74\x3b\x11\x7e\x91\xae\x32\xf8\x6c\xf4\xe6\x7b\x9a\xa5\x1f\x62\xc6\x21\xcf\x9a\xe5\xed\x8b\x02\xf3\x2c\x33\x33\xdf\x00\xca\xc9\x09\xb4\x04\xf5\xa5\x08\xd7\xc3\x02\x18\x66\xf1\xab\x1e\x83\x37\x4c\xcd\x12\xc1\x1d\x50\xf6\xaa\xbd\xfe\xe2\x73\x48\x38\x08\xa0\x32\x9b\x18\x44\x86\x0b\x6a\xc1\xaa\x26\x96\x2d\x96\x3c\xa0\x54\x65\x73\x87\x15\xca\x15\xe5\xf5\x94\x46\x9f\x33\x1a\x0c\x9a\xb1\x5a\xd9\x6a\x95\xcd\xcb\x7e\xec\x9a\xc5\x94\x3b\x37\x26\x31\xd7\xfc\xe4\x1f\x13\x8c\x31\x75\x9c\xba\xf7\x87\x3c\xa1\xb7\x4f\x17\x1b\x09\x82\x98\xc4\x70\x95\xd3\xe8\x4c\x48\x5a\xa6\xd6\x2a\x3d\x56\x42\x80\x9f\xaf\xae\x2e\x50\x0c\x42\xe0\x35\x34\x3c\x8a\x62\x03\x37\xba\xb2\x27\x04\xda\x25\x8d\x06\xe2\xa0\x13\x8a\xf3\xf5\xec\x10\x72\x67\x88\x90\x3d\x4b\x64\xeb\xaa\xda\x8f\xf7\x5a\x75\x47\x9a\xa8\x51\x70\x26\xd2\x38\xc6\x7c\xbb\x57\xfc\xbd\xe4\x04\x56\xa8\xa0\x54\x9a\x45\xd5\xf7\x0f\x16\xfc\x57\x1c\x3c\xdf\x23\xba\x77\x38\xda\x16\x4b\x31\x53\x6a\x4d\x9a\x15\x63\xe7\xe1\x18\x69\x9f\x22\xe0\x24\xbb\x94\x4b\x97\xee\x2d\xf9\x70\x87\x72\x7b\xe6\xc4\x33\x2a\x66\x5e\x1c\x35\x72\xe3\x2d\xda\x73\xe4\xc7\x51\x6d\xa4\xa1\x2a\x4f\xde\x94\xcb\xb2\x3e\x31\x48\xae\x82\xce\xc9\xc8\x65\xcd\xc3\xb7\x34\xb6\x2b\xdf\x58\x65\x78\x6e\x73\xac\x5e\x24\x0d\x3f\xdc\x70\x23\xc6\xda\x52\x0b\x2d\x63\x7d\xa9\x49\x2d\x54\x48\x28\xc0\x12\x9c\xe3\x63\xc9\x58\x04\x98\x36\x07\xc8\x0a\xa7\x91\xd4\xf0\xbc\xc1\xa8\xb9\x70\xd0\xc6\xa9\xb6\x78\x80\x5a\xa3\xb4\x2c\xf4\x18\x0b\x8a\x9d\xd0\xb4\x55\x10\xee\x0d\xc5\xd6\xe0\x99\x93\xdc\xa1\x04\xbb\xf1\xa7\x23\xd1\xd1\x97\x8c\x87\x13\x0a\x21\x02\xe9\x99\x25\xed\x20\xc5\x92\x66\x3c\x32\x9c\xd6\x06\xb0\x31\x5c\x86\x29\x0a\xcb\x60\x33\x12\xa5\x91\xfc\x96\x75\xd0\x59\xd7\x13\xbd\xd3\x23\x79\xdd\x2a\x90\xa6\x38\x06\x91\x39\x7f\x20\x72\x03\x1c\x2d\x01\x61\xba\x45\x37\x38\x22\x61\x8e\x71\x85\xc4\x32\x15\x28\x60\x61\x16\xb8\x3d\x29\xdc\x4d\x3d\x2f\x12\x13\x7d\xc8\x7e\x37\xee\xa8\x7f\xfa\xdb\xcb\x17\xff\x77\xfd\xf9\x7f\xee\x9f\x3d\xfe\xcf\xa7\xa7\x45\xfb\xcf\x1e\xf7\xf3\xe0\xff\xc4\x51\x0a\x8e\x4c\xcb\x01\xdc\x0a\x65\xb2\x01\x83\xed\x3d\xe4\xa9\xa3\x4e\x2d\x59\xc5\xe8\x2f\x48\x7d\x5a\x6e\x37\xbf\x5c\x9f\x35\x13\x64\x14\xfa\xef\x0b\x68\xa6\x0d\xb4\x8e\xf1\xa8\xff\xbb\x60\xf4\x03\x64\xab\x5b\x81\x65\x51\xe6\xda\xca\xfa\xf0\xb0\xac\x3e\x9c\xca\x26\x0e\x1d\xdb\x57\x5b\xbb\xb4\x9a\xa6\xb6\x9b\x1a\x6b\xd1\x9a\x9e\x7e\x33\x9a\xec\x41\x69\x45\x22\xb8\xb4\x51\xeb\x04\x77\xca\x6f\x7b\x7b\xc8\xb2\xb0\x95\x92\x25\x5b\xd0\x42\xaa\x2a\xdd\x32\x78\x4f\x0c\xab\x68\x46\x6c\xea\x6d\xf4\x5c\x5e\xde\xc4\xac\xa5\xf9\xd1\x00\x9f\x7d\x98\x65\x24\xbd\xc7\x97\xd4\xb3\x3a\xa8\x2b\xa0\x34\x76\xf9\x65\x5f\x2d\x25\x95\x1b\xcf\xd6\xf4\x9b\x5f\x09\x95\xb0\x36\x3f\xdb\xd0\x39\x2a\x93\x1c\x9d\x03\xa2\x4a\xca\xf5\xf6\x10\xb6\x94\x89\x0b\x6a\x70\x12\x13\x49\x6e\x40\xe4\x29\x12\x2b\xbd\x80\x45\x11\x04\xaa\xc2\x8f\x56\x9e\x5c\x6b\xec\x8d\x5a\x0e\x14\x59\x06\x2b\x1e\x24\xcb\xc2\x56\x4a\x31\xbe\x23\x71\x1a\xfb\x51\x2a\x0b\x3b\x1c\x48\x10\xa5\x82\xdc\xc0\xbb\x3e\x24\x8d\x5a\x76\x2e\x09\xed\xc1\x65\x51\xb8\x83\xcb\x3e\x24\x8d\x5a\x2e\x5d\xfe\x02\x74\x2d\x3d\xf1\xef\xae\xb8\x4b\xe6\x5e\xd4\xaa\xe2\x2e\x5c\x5e\xec\x0e\xf5\x5b\x0c\xcb\x0a\xbb\xa4\x3c\xf7\x1f\x2a\x55\x69\x97\x8c\x7d\x68\x95\xa5\xad\xb4\xf4\x9c\xa5\x07\xb9\x7a\x05\xbb\xad\x50\x6f\xfb\xa0\x4e\x9b\x48\x23\x49\x92\x28\x87\x19\x3e\x32\xee\xca\x3b\x46\x7e\x7f\x18\x64\xcc\xcc\x0f\x34\xe9\x36\x8b\xb7\x6c\xa8\xa5\x5b\x54\x4c\x54\x5b\x15\x3a\xf1\x6c\x2d\xfe\x96\xc8\x0d\xba\x7b\x81\x88\xc8\x23\xab\xee\x7d\x3b\x92\xa7\x60\x29\xe3\xdc\xff\xb8\x64\xe1\xf6\xa2\x5a\x59\xdc\x6f\xeb\x45\x7d\x6a\xd1\x76\x1e\xea\xb8\xf1\xfa\x14\xd3\x36\x63\xe5\xd7\xf3\xe4\xbe\x25\xbd\x5e\x05\xeb\x73\x74\xb5\x21\x2a\x2e\x4e\xa3\x30\xdf\xbf\x43\x28\x2a\xd1\xa5\x2a\x9d\x8a\xfd\x76\xd8\x8d\xbc\x67\x65\xc7\xb8\x03\x45\xec\xa3\xb0\x37\x8a\x70\x4c\x68\x91\x51\x8e\x58\x80\xed\x4a\xf3\x81\x62\xca\x96\xbb\xf1\x52\xcd\x80\xfb\xe4\x4a\x5d\x6c\xdf\x6e\x20\x4b\x80\x30\x8e\x28\x93\xf9\xe9\x8d\x8a\x6d\xd5\x59\x65\x7b\xaa\x44\x9e\xc0\xc2\xd1\x7c\x40\x26\xd6\x1a\xce\xf9\xc5\x69\x7b\x6c\xec\xc8\x71\x7b\xe5\x21\x2e\xd3\xe5\x65\x93\x91\x53\x0b\x7b\x3a\xc7\xfa\x17\x6a\x01\xa7\x33\xd0\xf4\x40\x0f\x39\x87\xda\xe4\x54\x87\x3a\xd5\xe3\xc7\xa6\x8e\x20\xd4\x11\xb2\x4e\xb1\xe9\x14\x9b\x4e\xb1\xe9\x14\x9b\xfe\x15\x63\xd3\x47\xf5\xff\x97\x38\xe9\xcf\x14\xf8\x76\x82\x49\x13\x4c\xaa\x7d\xcd\x6c\x62\x42\x49\x87\x43\x49\x19\x33\x6f\xe3\x44\x6e\x9b\xab\x8a\x3e\x86\xaa\x99\x52\x1b\x5b\x59\x33\x02\x09\xa0\x21\xa1\x6b\x84\x6b\x66\xbb\xdc\x16\x0c\xd3\x68\xab\xec\x36\x4b\xd8\x60\x8a\x40\x31\x85\x6e\x14\x57\x13\xc2\xfb\x92\x10\xde\xbf\x88\xdc\xbc\x53\x5e\x7f\x82\x7a\x13\xd4\x9b\xa0\xde\x04\xf5\x90\x01\xf5\x94\xcb\x7b\x83\x25\x9e\xd0\xde\x84\xf6\x6a\x5f\x4b\xb3\x98\x00\xdf\x04\xf8\x6c\xbc\x7f\x19\x80\xaf\xf1\x71\x45\x22\x98\x40\xe0\x04\x02\x27\x10\xd8\x29\xf5\x04\x02\xff\x4a\x20\x30\xc1\x72\xf3\x65\x02\x40\xd7\xc1\xd1\xe2\x6b\xf1\xa9\x7b\xfb\xe4\x20\xc0\x68\x9d\xd4\xb4\xd3\x96\xb5\xa6\xd1\x41\x20\xe6\x89\xc3\x48\x65\x58\x13\x84\x9c\x56\x56\x3b\x0c\xe0\x6b\x83\x5c\x13\xd2\x9a\x90\xd6\x84\xb4\x26\xa4\x85\x0c\xa4\x45\x19\xfd\xff\x63\x6c\x52\xb5\x1f\x1e\x19\x74\x3a\xcd\xb9\x69\xce\xa6\x3a\x0f\x7a\x2d\x19\xc7\x81\x14\x5d\xcb\xd5\x03\xc9\x39\xd0\xb0\xd1\xb3\xcd\xfb\x7a\x2d\x5d\x3a\x48\xe1\xfa\x2e\xe6\x81\x42\x18\x86\xd6\xc1\xbe\xb1\x23\xd3\xf7\x34\xed\x19\x0a\x0b\xc4\x48\x44\xfd\x22\x50\xb6\x42\x58\xbb\xe5\x3d\xa7\x73\xd4\x8b\xc4\x8c\x70\x61\xec\x73\xee\xc3\x81\x8b\xf5\xe2\xd7\x52\x3e\xcf\xeb\xeb\x17\x3b\x71\x16\xda\x7d\xb8\xde\xf0\x7a\x8f\x06\x2d\xa7\x40\x7b\xc1\x9d\x41\x4d\xb6\x61\xa2\x4e\x9f\x3d\xa0\xc5\xae\xe3\x1c\x1d\x40\x6c\x48\x8b\x63\xa0\xb5\x01\xed\x8e\x02\xe9\x86\xc8\x3b\x06\xee\xdb\x4b\xde\xbd\xc0\xa1\x6f\xcb\xda\xfc\xc2\x44\x16\x87\x9c\x17\x31\xd3\x30\x20\x39\x42\xcb\x6f\xf2\xf1\xf4\x72\x10\xf8\x1c\xa0\xf3\xbd\x10\xea\x21\x35\x7d\xe8\x86\xdb\x15\xed\x81\x81\x07\x28\xbb\x13\x28\xc7\xf8\xce\x7d\x8d\xc2\x31\xb4\x7e\x94\xd6\xdb\x55\xef\x4a\xfb\xed\xc3\x40\x3e\xeb\x9f\xe9\x99\x0f\xdf\x08\x65\x88\x27\x73\x86\x31\x9d\x47\xdf\x55\x19\xba\x3d\xee\x15\x0a\xcd\x8c\xaa\x5e\xb9\xf6\x57\x33\x73\x5a\xa1\x89\x7b\x3b\xa0\xb2\xa4\xc2\xf6\xc1\x53\xb5\x00\xca\x23\xe5\xf4\x60\x6a\xb4\x2d\x74\xea\x4e\xed\x3b\xe3\x47\xfb\xed\x82\x3d\x19\xd4\x3b\x6b\xaf\xae\x2b\x2f\x57\xb3\x82\x68\xcb\xed\x88\x2e\xe1\x5c\xd7\x26\xfa\x0a\x65\xe7\xce\x11\x33\xb4\xdd\x66\xe3\x37\xf6\xfa\x70\xd6\x4f\xa1\x21\x51\xd8\x3c\x26\x14\x4b\xc6\x87\x44\x27\x1c\x70\xf8\x9e\x46\xce\xab\x21\x07\x5f\xc1\x76\x17\x1b\x77\xb4\xda\x75\xa0\x0a\x3a\x30\xe1\xf8\x97\x32\x16\x2b\x00\x75\x85\xee\x62\x46\xef\xd3\x85\xb5\x6b\x60\xbe\xf2\x30\x7a\x8c\x0b\x4b\xa6\xd0\xf9\x64\x42\xe7\x07\x41\x41\xe3\x2c\x5d\xf9\x6d\xe9\x39\x98\x3b\x3b\x5d\x67\xd4\x5c\xed\xf2\xf0\x48\x7b\xbd\x2d\x31\xdd\x3f\x34\xad\x44\x76\x51\x9a\x56\x22\xa7\x95\xc8\x69\x25\xf2\xe1\x56\x22\x1f\x00\x32\x6a\x73\x92\xed\xe1\xc6\x7d\x9f\x49\x2c\x69\x7e\xc8\x31\x4c\x0c\xb4\xf2\x54\x3b\x79\x3b\x9e\x4d\xb4\xd1\x18\x3e\x5f\x9a\x93\xa2\x11\xc3\xda\x27\x0b\xaf\x37\x2e\x5c\x37\xfb\xeb\x9a\xd6\xc3\xac\xc3\xcc\xf8\x1e\x5b\x9d\xac\x22\x64\xb7\xed\x26\xb8\xf3\xb9\x3c\xbb\x1f\xe2\xb0\x22\x77\x43\x6a\x62\x29\x39\x59\xa6\xe6\xe5\xcd\x7b\x83\xc0\x5b\x8e\x93\x64\xac\xeb\xca\x4f\x65\xac\x4a\xbc\x1e\xcd\x82\xfa\x3c\x70\x36\xb6\xb5\xed\x79\xef\xec\x68\x00\xff\x54\xfa\xb5\xe3\xf1\xdb\xe1\xbe\xce\x76\x17\xaf\x57\xb6\x6b\x89\x05\x09\xce\x52\xb9\x01\x2a\x49\xbe\xd9\xf4\xd2\xb8\x7a\xbf\x91\x02\xf3\x22\x8c\x13\xf2\x77\xd8\x8e\x43\x8b\xe1\x54\x6e\x5e\x9d\xc7\x49\x44\x02\x22\xc7\xa4\x79\x81\x85\xb8\x65\x3c\x1c\x93\xe6\x59\xa2\xf8\x1c\x51\x95\x05\xd9\x20\x00\x21\x7e\x60\x21\x58\xa9\x56\xff\xbe\xb6\x5a\x5e\x5b\x3f\x1f\xd6\xd3\x3c\xc4\x4d\xba\x99\xb4\x63\x6e\x7d\x3e\x3d\x57\xd2\x18\x5f\x47\xe8\xc3\x06\x8a\x68\x6c\x7f\x3b\x72\x0f\xe7\xe2\x77\x77\xf1\xd0\x99\xab\xdf\x2e\xfe\xd6\xbb\xcd\x1a\xb9\x90\xd1\xaf\xf2\x38\x3d\xdb\x74\xf8\xeb\xe3\xda\xe8\x2a\x62\xb7\xda\x1b\x07\xa9\xdc\x30\x5e\xbc\x68\xfb\x6b\x9f\x97\xf1\xc6\xb1\xd8\x5c\x29\x1e\x49\x30\xc5\xf7\xde\xad\x91\x42\xf9\xdd\xed\x89\x80\x25\xbe\x37\xd7\xe7\x32\x5c\xe6\x35\xac\xd4\x0c\x2d\xf7\x90\xc4\xe3\xf5\xe3\x2f\x7f\x54\x18\x88\xe3\x61\x47\x85\x64\x7f\xc0\xd7\x3f\x1a\x92\x42\xe9\xc7\x1e\x0d\x95\x76\xa7\x51\xa0\x8f\x02\x1b\x46\x9e\x06\x42\xd1\xf2\x01\x07\x02\xde\xe9\x7d\x1a\x0b\xa7\x32\x16\xcc\xc0\xee\xc4\x90\xd2\x5f\x6f\x98\x54\x5d\xf2\x95\xe1\xa7\x69\x10\x3a\x06\xe1\x65\xb3\x17\x47\x58\x78\xd0\x45\xd6\x5b\xd5\x5f\x25\x1d\x71\x49\xa6\x7a\x64\xda\xd0\x6f\xc7\x3a\x4c\xe3\x09\xc0\x6e\x96\x2c\xa7\xa7\x77\x34\x10\x05\x08\x21\x44\x92\x65\x77\xdf\x20\x5c\xbc\xe7\x97\x3f\xf4\x1a\x45\xd6\xe7\x27\x4a\xde\x74\x27\x66\x11\x7d\x70\xba\xd3\x78\xf9\x1e\x0d\xca\xc8\x39\xde\x7c\xb3\xa6\xe1\xbc\xd7\xc1\x6a\x6f\xb3\x0e\x52\xbe\xe4\x98\x8a\x15\x70\x94\x70\x26\x59\xc0\xa2\xf2\x1c\xfb\xd9\xc5\xf9\xbc\xd5\x92\x9c\xa3\xdf\xe6\x1e\xb3\x0d\x49\xba\x87\x50\x5f\x84\xfe\xe9\xd6\xf8\xbb\xe6\xf0\x7a\xeb\xa6\x65\x3b\x86\x8b\x79\x93\xf5\x59\x20\x6e\xb4\xa7\x44\xf4\x3f\xa5\xfe\x67\x42\x12\xdb\xd3\xe7\xbb\xa5\xa3\x8c\x5c\x2b\x97\xbb\xbb\x7f\x8e\xc5\x6e\xed\x43\x5c\xbf\x74\xc8\x8f\xff\xe6\xd6\xbe\x91\xb6\xf5\x95\xe4\xed\x93\xc4\xa8\x5b\xf9\x76\x4d\x35\xb7\xd8\x8c\xb6\x7d\xaf\x72\xe0\xb6\xbd\x01\x63\x9e\x76\xab\x1a\x32\x76\xe4\x8c\x76\xc2\xad\x6c\xa2\x65\xf7\xcf\xf8\xa7\xda\x2a\xb9\x8c\x3d\x3c\xa3\x9d\x64\x33\xe5\x1a\xb5\x2d\xfb\x86\xa2\x5a\x7f\x19\x5b\x7f\xc6\x3f\xd1\x53\xd3\xe2\x41\x5b\xd3\x4f\xf0\xec\xb0\x42\x73\x43\xd2\x68\x27\xd3\x6a\x6a\x34\xf6\x4e\x1e\x52\x8b\x87\x6c\xcc\xae\x44\xfb\x9e\xa7\x51\x4f\x9d\x55\x03\x81\x8e\x67\xfc\xb4\x69\xf0\x3a\x18\xf2\x40\xd0\xf6\xa8\x34\xe3\xc9\x98\xaf\xf6\xda\x24\xd3\xeb\x60\xb9\x0e\xd3\x1f\xa9\xff\xee\x1f\xfd\x37\x00\x00\xff\xff\x69\x5d\x0a\x6a\x39\x9d\x00\x00") + +func v2SchemaJSONBytes() ([]byte, error) { + return bindataRead( + _v2SchemaJSON, + "v2/schema.json", + ) +} + +func v2SchemaJSON() (*asset, error) { + bytes, err := v2SchemaJSONBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "v2/schema.json", size: 40249, mode: os.FileMode(420), modTime: time.Unix(1482389892, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "jsonschema-draft-04.json": jsonschemaDraft04JSON, + "v2/schema.json": v2SchemaJSON, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} +var _bintree = &bintree{nil, map[string]*bintree{ + "jsonschema-draft-04.json": &bintree{jsonschemaDraft04JSON, map[string]*bintree{}}, + "v2": &bintree{nil, map[string]*bintree{ + "schema.json": &bintree{v2SchemaJSON, map[string]*bintree{}}, + }}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} + diff --git a/vendor/github.com/go-openapi/spec/contact_info.go b/vendor/github.com/go-openapi/spec/contact_info.go new file mode 100644 index 000000000..f285970aa --- /dev/null +++ b/vendor/github.com/go-openapi/spec/contact_info.go @@ -0,0 +1,24 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +// ContactInfo contact information for the exposed API. +// +// For more information: http://goo.gl/8us55a#contactObject +type ContactInfo struct { + Name string `json:"name,omitempty"` + URL string `json:"url,omitempty"` + Email string `json:"email,omitempty"` +} diff --git a/vendor/github.com/go-openapi/spec/expander.go b/vendor/github.com/go-openapi/spec/expander.go new file mode 100644 index 000000000..b4429a21c --- /dev/null +++ b/vendor/github.com/go-openapi/spec/expander.go @@ -0,0 +1,900 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "fmt" + "log" + "net/url" + "os" + "path/filepath" + "reflect" + "strings" + "sync" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +var ( + // Debug enables logging when SWAGGER_DEBUG env var is not empty + Debug = os.Getenv("SWAGGER_DEBUG") != "" +) + +// ExpandOptions provides options for expand. +type ExpandOptions struct { + RelativeBase string + SkipSchemas bool + ContinueOnError bool +} + +// ResolutionCache a cache for resolving urls +type ResolutionCache interface { + Get(string) (interface{}, bool) + Set(string, interface{}) +} + +type simpleCache struct { + lock sync.Mutex + store map[string]interface{} +} + +var resCache ResolutionCache + +func init() { + resCache = initResolutionCache() +} + +func initResolutionCache() ResolutionCache { + return &simpleCache{store: map[string]interface{}{ + "http://swagger.io/v2/schema.json": MustLoadSwagger20Schema(), + "http://json-schema.org/draft-04/schema": MustLoadJSONSchemaDraft04(), + }} +} + +func (s *simpleCache) Get(uri string) (interface{}, bool) { + debugLog("getting %q from resolution cache", uri) + s.lock.Lock() + v, ok := s.store[uri] + debugLog("got %q from resolution cache: %t", uri, ok) + + s.lock.Unlock() + return v, ok +} + +func (s *simpleCache) Set(uri string, data interface{}) { + s.lock.Lock() + s.store[uri] = data + s.lock.Unlock() +} + +// ResolveRefWithBase resolves a reference against a context root with preservation of base path +func ResolveRefWithBase(root interface{}, ref *Ref, opts *ExpandOptions) (*Schema, error) { + resolver, err := defaultSchemaLoader(root, nil, opts, nil) + if err != nil { + return nil, err + } + + result := new(Schema) + if err := resolver.Resolve(ref, result); err != nil { + return nil, err + } + return result, nil +} + +// ResolveRef resolves a reference against a context root +func ResolveRef(root interface{}, ref *Ref) (*Schema, error) { + return ResolveRefWithBase(root, ref, nil) +} + +// ResolveParameter resolves a paramter reference against a context root +func ResolveParameter(root interface{}, ref Ref) (*Parameter, error) { + return ResolveParameterWithBase(root, ref, nil) +} + +// ResolveParameterWithBase resolves a paramter reference against a context root and base path +func ResolveParameterWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Parameter, error) { + resolver, err := defaultSchemaLoader(root, nil, opts, nil) + if err != nil { + return nil, err + } + + result := new(Parameter) + if err := resolver.Resolve(&ref, result); err != nil { + return nil, err + } + return result, nil +} + +// ResolveResponse resolves response a reference against a context root +func ResolveResponse(root interface{}, ref Ref) (*Response, error) { + return ResolveResponseWithBase(root, ref, nil) +} + +// ResolveResponseWithBase resolves response a reference against a context root and base path +func ResolveResponseWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Response, error) { + resolver, err := defaultSchemaLoader(root, nil, opts, nil) + if err != nil { + return nil, err + } + + result := new(Response) + if err := resolver.Resolve(&ref, result); err != nil { + return nil, err + } + return result, nil +} + +// ResolveItems resolves header and parameter items reference against a context root and base path +func ResolveItems(root interface{}, ref Ref, opts *ExpandOptions) (*Items, error) { + resolver, err := defaultSchemaLoader(root, nil, opts, nil) + if err != nil { + return nil, err + } + + result := new(Items) + if err := resolver.Resolve(&ref, result); err != nil { + return nil, err + } + return result, nil +} + +// ResolvePathItem resolves response a path item against a context root and base path +func ResolvePathItem(root interface{}, ref Ref, opts *ExpandOptions) (*PathItem, error) { + resolver, err := defaultSchemaLoader(root, nil, opts, nil) + if err != nil { + return nil, err + } + + result := new(PathItem) + if err := resolver.Resolve(&ref, result); err != nil { + return nil, err + } + return result, nil +} + +type schemaLoader struct { + loadingRef *Ref + startingRef *Ref + currentRef *Ref + root interface{} + options *ExpandOptions + cache ResolutionCache + loadDoc func(string) (json.RawMessage, error) +} + +var idPtr, _ = jsonpointer.New("/id") +var refPtr, _ = jsonpointer.New("/$ref") + +// PathLoader function to use when loading remote refs +var PathLoader func(string) (json.RawMessage, error) + +func init() { + PathLoader = func(path string) (json.RawMessage, error) { + data, err := swag.LoadFromFileOrHTTP(path) + if err != nil { + return nil, err + } + return json.RawMessage(data), nil + } +} + +func defaultSchemaLoader( + root interface{}, + ref *Ref, + expandOptions *ExpandOptions, + cache ResolutionCache) (*schemaLoader, error) { + + if cache == nil { + cache = resCache + } + if expandOptions == nil { + expandOptions = &ExpandOptions{} + } + + var ptr *jsonpointer.Pointer + if ref != nil { + ptr = ref.GetPointer() + } + + currentRef := nextRef(root, ref, ptr) + + return &schemaLoader{ + loadingRef: ref, + startingRef: ref, + currentRef: currentRef, + root: root, + options: expandOptions, + cache: cache, + loadDoc: func(path string) (json.RawMessage, error) { + debugLog("fetching document at %q", path) + return PathLoader(path) + }, + }, nil +} + +func idFromNode(node interface{}) (*Ref, error) { + if idValue, _, err := idPtr.Get(node); err == nil { + if refStr, ok := idValue.(string); ok && refStr != "" { + idRef, err := NewRef(refStr) + if err != nil { + return nil, err + } + return &idRef, nil + } + } + return nil, nil +} + +func nextRef(startingNode interface{}, startingRef *Ref, ptr *jsonpointer.Pointer) *Ref { + if startingRef == nil { + return nil + } + + if ptr == nil { + return startingRef + } + + ret := startingRef + var idRef *Ref + node := startingNode + + for _, tok := range ptr.DecodedTokens() { + node, _, _ = jsonpointer.GetForToken(node, tok) + if node == nil { + break + } + + idRef, _ = idFromNode(node) + if idRef != nil { + nw, err := ret.Inherits(*idRef) + if err != nil { + break + } + ret = nw + } + + refRef, _, _ := refPtr.Get(node) + if refRef != nil { + var rf Ref + switch value := refRef.(type) { + case string: + rf, _ = NewRef(value) + } + nw, err := ret.Inherits(rf) + if err != nil { + break + } + nwURL := nw.GetURL() + if nwURL.Scheme == "file" || (nwURL.Scheme == "" && nwURL.Host == "") { + nwpt := filepath.ToSlash(nwURL.Path) + if filepath.IsAbs(nwpt) { + _, err := os.Stat(nwpt) + if err != nil { + nwURL.Path = filepath.Join(".", nwpt) + } + } + } + + ret = nw + } + + } + + return ret +} + +func debugLog(msg string, args ...interface{}) { + if Debug { + log.Printf(msg, args...) + } +} + +func normalizeFileRef(ref *Ref, relativeBase string) *Ref { + refURL := ref.GetURL() + debugLog("normalizing %s against %s (%s)", ref.String(), relativeBase, refURL.String()) + if strings.HasPrefix(refURL.String(), "#") { + return ref + } + + if refURL.Scheme == "file" || (refURL.Scheme == "" && refURL.Host == "") { + filePath := refURL.Path + debugLog("normalizing file path: %s", filePath) + + if !filepath.IsAbs(filepath.FromSlash(filePath)) && len(relativeBase) != 0 { + debugLog("joining %s with %s", relativeBase, filePath) + if fi, err := os.Stat(filepath.FromSlash(relativeBase)); err == nil { + if !fi.IsDir() { + relativeBase = filepath.Dir(filepath.FromSlash(relativeBase)) + } + } + filePath = filepath.Join(filepath.FromSlash(relativeBase), filepath.FromSlash(filePath)) + } + if !filepath.IsAbs(filepath.FromSlash(filePath)) { + pwd, err := os.Getwd() + if err == nil { + debugLog("joining cwd %s with %s", pwd, filePath) + filePath = filepath.Join(pwd, filepath.FromSlash(filePath)) + } + } + + debugLog("cleaning %s", filePath) + filePath = filepath.Clean(filepath.FromSlash(filePath)) + _, err := os.Stat(filepath.FromSlash(filePath)) + if err == nil { + debugLog("rewriting url %s to scheme \"\" path %s", refURL.String(), filePath) + slp := filepath.FromSlash(filePath) + if filepath.IsAbs(slp) && filepath.Separator == '\\' && len(slp) > 1 && slp[1] == ':' && ('a' <= slp[0] && slp[0] <= 'z' || 'A' <= slp[0] && slp[0] <= 'Z') { + slp = slp[2:] + } + refURL.Scheme = "" + refURL.Path = filepath.ToSlash(slp) + debugLog("new url with joined filepath: %s", refURL.String()) + *ref = MustCreateRef(refURL.String()) + } + } + + debugLog("refurl: %s", ref.GetURL().String()) + return ref +} + +func (r *schemaLoader) resolveRef(currentRef, ref *Ref, node, target interface{}) error { + + tgt := reflect.ValueOf(target) + if tgt.Kind() != reflect.Ptr { + return fmt.Errorf("resolve ref: target needs to be a pointer") + } + + oldRef := currentRef + + if currentRef != nil { + debugLog("resolve ref current %s new %s", currentRef.String(), ref.String()) + nextRef := nextRef(node, ref, currentRef.GetPointer()) + if nextRef == nil || nextRef.GetURL() == nil { + return nil + } + var err error + currentRef, err = currentRef.Inherits(*nextRef) + debugLog("resolved ref current %s", currentRef.String()) + if err != nil { + return err + } + } + + if currentRef == nil { + currentRef = ref + } + + refURL := currentRef.GetURL() + if refURL == nil { + return nil + } + if currentRef.IsRoot() { + nv := reflect.ValueOf(node) + reflect.Indirect(tgt).Set(reflect.Indirect(nv)) + return nil + } + + if strings.HasPrefix(refURL.String(), "#") { + res, _, err := ref.GetPointer().Get(node) + if err != nil { + res, _, err = ref.GetPointer().Get(r.root) + if err != nil { + return err + } + } + rv := reflect.Indirect(reflect.ValueOf(res)) + tgtType := reflect.Indirect(tgt).Type() + if rv.Type().AssignableTo(tgtType) { + reflect.Indirect(tgt).Set(reflect.Indirect(reflect.ValueOf(res))) + } else { + if err := swag.DynamicJSONToStruct(rv.Interface(), target); err != nil { + return err + } + } + + return nil + } + + relativeBase := "" + if r.options != nil && r.options.RelativeBase != "" { + relativeBase = r.options.RelativeBase + } + normalizeFileRef(currentRef, relativeBase) + debugLog("current ref normalized file: %s", currentRef.String()) + normalizeFileRef(ref, relativeBase) + debugLog("ref normalized file: %s", currentRef.String()) + + data, _, _, err := r.load(currentRef.GetURL()) + if err != nil { + return err + } + + if ((oldRef == nil && currentRef != nil) || + (oldRef != nil && currentRef == nil) || + oldRef.String() != currentRef.String()) && + ((oldRef == nil && ref != nil) || + (oldRef != nil && ref == nil) || + (oldRef.String() != ref.String())) { + + return r.resolveRef(currentRef, ref, data, target) + } + + var res interface{} + if currentRef.String() != "" { + res, _, err = currentRef.GetPointer().Get(data) + if err != nil { + if strings.HasPrefix(ref.String(), "#") { + if r.loadingRef != nil { + rr, er := r.loadingRef.Inherits(*ref) + if er != nil { + return er + } + refURL = rr.GetURL() + + data, _, _, err = r.load(refURL) + if err != nil { + return err + } + } else { + data = r.root + } + } + + res, _, err = ref.GetPointer().Get(data) + if err != nil { + return err + } + } + } else { + res = data + } + + if err := swag.DynamicJSONToStruct(res, target); err != nil { + return err + } + + r.currentRef = currentRef + + return nil +} + +func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error) { + debugLog("loading schema from url: %s", refURL) + toFetch := *refURL + toFetch.Fragment = "" + + data, fromCache := r.cache.Get(toFetch.String()) + if !fromCache { + b, err := r.loadDoc(toFetch.String()) + if err != nil { + return nil, url.URL{}, false, err + } + + if err := json.Unmarshal(b, &data); err != nil { + return nil, url.URL{}, false, err + } + r.cache.Set(toFetch.String(), data) + } + + return data, toFetch, fromCache, nil +} + +func (r *schemaLoader) Resolve(ref *Ref, target interface{}) error { + return r.resolveRef(r.currentRef, ref, r.root, target) +} + +func (r *schemaLoader) reset() { + ref := r.startingRef + + var ptr *jsonpointer.Pointer + if ref != nil { + ptr = ref.GetPointer() + } + + r.currentRef = nextRef(r.root, ref, ptr) +} + +// ExpandSpec expands the references in a swagger spec +func ExpandSpec(spec *Swagger, options *ExpandOptions) error { + resolver, err := defaultSchemaLoader(spec, nil, options, nil) + // Just in case this ever returns an error. + if shouldStopOnError(err, resolver.options) { + return err + } + + if options == nil || !options.SkipSchemas { + for key, definition := range spec.Definitions { + var def *Schema + var err error + if def, err = expandSchema(definition, []string{"#/definitions/" + key}, resolver); shouldStopOnError(err, resolver.options) { + return err + } + resolver.reset() + spec.Definitions[key] = *def + } + } + + for key, parameter := range spec.Parameters { + if err := expandParameter(¶meter, resolver); shouldStopOnError(err, resolver.options) { + return err + } + spec.Parameters[key] = parameter + } + + for key, response := range spec.Responses { + if err := expandResponse(&response, resolver); shouldStopOnError(err, resolver.options) { + return err + } + spec.Responses[key] = response + } + + if spec.Paths != nil { + for key, path := range spec.Paths.Paths { + if err := expandPathItem(&path, resolver); shouldStopOnError(err, resolver.options) { + return err + } + spec.Paths.Paths[key] = path + } + } + + return nil +} + +func shouldStopOnError(err error, opts *ExpandOptions) bool { + if err != nil && !opts.ContinueOnError { + return true + } + + if err != nil { + log.Println(err) + } + + return false +} + +// ExpandSchema expands the refs in the schema object +func ExpandSchema(schema *Schema, root interface{}, cache ResolutionCache) error { + return ExpandSchemaWithBasePath(schema, root, cache, nil) +} + +// ExpandSchemaWithBasePath expands the refs in the schema object, base path configured through expand options +func ExpandSchemaWithBasePath(schema *Schema, root interface{}, cache ResolutionCache, opts *ExpandOptions) error { + if schema == nil { + return nil + } + if root == nil { + root = schema + } + + nrr, _ := NewRef(schema.ID) + var rrr *Ref + if nrr.String() != "" { + switch rt := root.(type) { + case *Schema: + rid, _ := NewRef(rt.ID) + rrr, _ = rid.Inherits(nrr) + case *Swagger: + rid, _ := NewRef(rt.ID) + rrr, _ = rid.Inherits(nrr) + } + } + + resolver, err := defaultSchemaLoader(root, rrr, opts, cache) + if err != nil { + return err + } + + refs := []string{""} + if rrr != nil { + refs[0] = rrr.String() + } + var s *Schema + if s, err = expandSchema(*schema, refs, resolver); err != nil { + return err + } + *schema = *s + return nil +} + +func expandItems(target Schema, parentRefs []string, resolver *schemaLoader) (*Schema, error) { + if target.Items != nil { + if target.Items.Schema != nil { + t, err := expandSchema(*target.Items.Schema, parentRefs, resolver) + if err != nil { + if target.Items.Schema.ID == "" { + target.Items.Schema.ID = target.ID + if err != nil { + t, err = expandSchema(*target.Items.Schema, parentRefs, resolver) + if err != nil { + return nil, err + } + } + } + } + *target.Items.Schema = *t + } + for i := range target.Items.Schemas { + t, err := expandSchema(target.Items.Schemas[i], parentRefs, resolver) + if err != nil { + return nil, err + } + target.Items.Schemas[i] = *t + } + } + return &target, nil +} + +func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader) (*Schema, error) { + if target.Ref.String() == "" && target.Ref.IsRoot() { + debugLog("skipping expand schema for no ref and root: %v", resolver.root) + + return resolver.root.(*Schema), nil + } + + // t is the new expanded schema + var t *Schema + + for target.Ref.String() != "" { + if swag.ContainsStringsCI(parentRefs, target.Ref.String()) { + return &target, nil + } + + if err := resolver.Resolve(&target.Ref, &t); shouldStopOnError(err, resolver.options) { + return &target, err + } + + if swag.ContainsStringsCI(parentRefs, target.Ref.String()) { + debugLog("ref already exists in parent") + return &target, nil + } + parentRefs = append(parentRefs, target.Ref.String()) + if t != nil { + target = *t + } + } + + t, err := expandItems(target, parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + target = *t + } + + for i := range target.AllOf { + t, err := expandSchema(target.AllOf[i], parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + target.AllOf[i] = *t + } + } + for i := range target.AnyOf { + t, err := expandSchema(target.AnyOf[i], parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + target.AnyOf[i] = *t + } + for i := range target.OneOf { + t, err := expandSchema(target.OneOf[i], parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + target.OneOf[i] = *t + } + } + if target.Not != nil { + t, err := expandSchema(*target.Not, parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + *target.Not = *t + } + } + for k := range target.Properties { + t, err := expandSchema(target.Properties[k], parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + target.Properties[k] = *t + } + } + if target.AdditionalProperties != nil && target.AdditionalProperties.Schema != nil { + t, err := expandSchema(*target.AdditionalProperties.Schema, parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + *target.AdditionalProperties.Schema = *t + } + } + for k := range target.PatternProperties { + t, err := expandSchema(target.PatternProperties[k], parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + target.PatternProperties[k] = *t + } + } + for k := range target.Dependencies { + if target.Dependencies[k].Schema != nil { + t, err := expandSchema(*target.Dependencies[k].Schema, parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + *target.Dependencies[k].Schema = *t + } + } + } + if target.AdditionalItems != nil && target.AdditionalItems.Schema != nil { + t, err := expandSchema(*target.AdditionalItems.Schema, parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + *target.AdditionalItems.Schema = *t + } + } + for k := range target.Definitions { + t, err := expandSchema(target.Definitions[k], parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return &target, err + } + if t != nil { + target.Definitions[k] = *t + } + } + return &target, nil +} + +func expandPathItem(pathItem *PathItem, resolver *schemaLoader) error { + if pathItem == nil { + return nil + } + + if pathItem.Ref.String() != "" { + if err := resolver.Resolve(&pathItem.Ref, &pathItem); err != nil { + return err + } + resolver.reset() + pathItem.Ref = Ref{} + } + + for idx := range pathItem.Parameters { + if err := expandParameter(&(pathItem.Parameters[idx]), resolver); shouldStopOnError(err, resolver.options) { + return err + } + } + if err := expandOperation(pathItem.Get, resolver); shouldStopOnError(err, resolver.options) { + return err + } + if err := expandOperation(pathItem.Head, resolver); shouldStopOnError(err, resolver.options) { + return err + } + if err := expandOperation(pathItem.Options, resolver); shouldStopOnError(err, resolver.options) { + return err + } + if err := expandOperation(pathItem.Put, resolver); shouldStopOnError(err, resolver.options) { + return err + } + if err := expandOperation(pathItem.Post, resolver); shouldStopOnError(err, resolver.options) { + return err + } + if err := expandOperation(pathItem.Patch, resolver); shouldStopOnError(err, resolver.options) { + return err + } + if err := expandOperation(pathItem.Delete, resolver); shouldStopOnError(err, resolver.options) { + return err + } + return nil +} + +func expandOperation(op *Operation, resolver *schemaLoader) error { + if op == nil { + return nil + } + + for i, param := range op.Parameters { + if err := expandParameter(¶m, resolver); shouldStopOnError(err, resolver.options) { + return err + } + op.Parameters[i] = param + } + + if op.Responses != nil { + responses := op.Responses + if err := expandResponse(responses.Default, resolver); shouldStopOnError(err, resolver.options) { + return err + } + for code, response := range responses.StatusCodeResponses { + if err := expandResponse(&response, resolver); shouldStopOnError(err, resolver.options) { + return err + } + responses.StatusCodeResponses[code] = response + } + } + return nil +} + +func expandResponse(response *Response, resolver *schemaLoader) error { + if response == nil { + return nil + } + + var parentRefs []string + + if response.Ref.String() != "" { + parentRefs = append(parentRefs, response.Ref.String()) + if err := resolver.Resolve(&response.Ref, response); shouldStopOnError(err, resolver.options) { + return err + } + resolver.reset() + response.Ref = Ref{} + } + + if !resolver.options.SkipSchemas && response.Schema != nil { + parentRefs = append(parentRefs, response.Schema.Ref.String()) + debugLog("response ref: %s", response.Schema.Ref) + if err := resolver.Resolve(&response.Schema.Ref, &response.Schema); shouldStopOnError(err, resolver.options) { + return err + } + s, err := expandSchema(*response.Schema, parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return err + } + resolver.reset() + *response.Schema = *s + } + return nil +} + +func expandParameter(parameter *Parameter, resolver *schemaLoader) error { + if parameter == nil { + return nil + } + + var parentRefs []string + + if parameter.Ref.String() != "" { + parentRefs = append(parentRefs, parameter.Ref.String()) + if err := resolver.Resolve(¶meter.Ref, parameter); shouldStopOnError(err, resolver.options) { + return err + } + resolver.reset() + parameter.Ref = Ref{} + } + if !resolver.options.SkipSchemas && parameter.Schema != nil { + parentRefs = append(parentRefs, parameter.Schema.Ref.String()) + if err := resolver.Resolve(¶meter.Schema.Ref, ¶meter.Schema); shouldStopOnError(err, resolver.options) { + return err + } + s, err := expandSchema(*parameter.Schema, parentRefs, resolver) + if shouldStopOnError(err, resolver.options) { + return err + } + resolver.reset() + *parameter.Schema = *s + } + return nil +} diff --git a/vendor/github.com/go-openapi/spec/external_docs.go b/vendor/github.com/go-openapi/spec/external_docs.go new file mode 100644 index 000000000..88add91b2 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/external_docs.go @@ -0,0 +1,24 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +// ExternalDocumentation allows referencing an external resource for +// extended documentation. +// +// For more information: http://goo.gl/8us55a#externalDocumentationObject +type ExternalDocumentation struct { + Description string `json:"description,omitempty"` + URL string `json:"url,omitempty"` +} diff --git a/vendor/github.com/go-openapi/spec/header.go b/vendor/github.com/go-openapi/spec/header.go new file mode 100644 index 000000000..85c4d454c --- /dev/null +++ b/vendor/github.com/go-openapi/spec/header.go @@ -0,0 +1,195 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "strings" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +type HeaderProps struct { + Description string `json:"description,omitempty"` +} + +// Header describes a header for a response of the API +// +// For more information: http://goo.gl/8us55a#headerObject +type Header struct { + CommonValidations + SimpleSchema + VendorExtensible + HeaderProps +} + +// ResponseHeader creates a new header instance for use in a response +func ResponseHeader() *Header { + return new(Header) +} + +// WithDescription sets the description on this response, allows for chaining +func (h *Header) WithDescription(description string) *Header { + h.Description = description + return h +} + +// Typed a fluent builder method for the type of parameter +func (h *Header) Typed(tpe, format string) *Header { + h.Type = tpe + h.Format = format + return h +} + +// CollectionOf a fluent builder method for an array item +func (h *Header) CollectionOf(items *Items, format string) *Header { + h.Type = "array" + h.Items = items + h.CollectionFormat = format + return h +} + +// WithDefault sets the default value on this item +func (h *Header) WithDefault(defaultValue interface{}) *Header { + h.Default = defaultValue + return h +} + +// WithMaxLength sets a max length value +func (h *Header) WithMaxLength(max int64) *Header { + h.MaxLength = &max + return h +} + +// WithMinLength sets a min length value +func (h *Header) WithMinLength(min int64) *Header { + h.MinLength = &min + return h +} + +// WithPattern sets a pattern value +func (h *Header) WithPattern(pattern string) *Header { + h.Pattern = pattern + return h +} + +// WithMultipleOf sets a multiple of value +func (h *Header) WithMultipleOf(number float64) *Header { + h.MultipleOf = &number + return h +} + +// WithMaximum sets a maximum number value +func (h *Header) WithMaximum(max float64, exclusive bool) *Header { + h.Maximum = &max + h.ExclusiveMaximum = exclusive + return h +} + +// WithMinimum sets a minimum number value +func (h *Header) WithMinimum(min float64, exclusive bool) *Header { + h.Minimum = &min + h.ExclusiveMinimum = exclusive + return h +} + +// WithEnum sets a the enum values (replace) +func (h *Header) WithEnum(values ...interface{}) *Header { + h.Enum = append([]interface{}{}, values...) + return h +} + +// WithMaxItems sets the max items +func (h *Header) WithMaxItems(size int64) *Header { + h.MaxItems = &size + return h +} + +// WithMinItems sets the min items +func (h *Header) WithMinItems(size int64) *Header { + h.MinItems = &size + return h +} + +// UniqueValues dictates that this array can only have unique items +func (h *Header) UniqueValues() *Header { + h.UniqueItems = true + return h +} + +// AllowDuplicates this array can have duplicates +func (h *Header) AllowDuplicates() *Header { + h.UniqueItems = false + return h +} + +// MarshalJSON marshal this to JSON +func (h Header) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(h.CommonValidations) + if err != nil { + return nil, err + } + b2, err := json.Marshal(h.SimpleSchema) + if err != nil { + return nil, err + } + b3, err := json.Marshal(h.HeaderProps) + if err != nil { + return nil, err + } + return swag.ConcatJSON(b1, b2, b3), nil +} + +// UnmarshalJSON marshal this from JSON +func (h *Header) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &h.CommonValidations); err != nil { + return err + } + if err := json.Unmarshal(data, &h.SimpleSchema); err != nil { + return err + } + if err := json.Unmarshal(data, &h.VendorExtensible); err != nil { + return err + } + if err := json.Unmarshal(data, &h.HeaderProps); err != nil { + return err + } + return nil +} + +// JSONLookup look up a value by the json property name +func (p Header) JSONLookup(token string) (interface{}, error) { + if ex, ok := p.Extensions[token]; ok { + return &ex, nil + } + + r, _, err := jsonpointer.GetForToken(p.CommonValidations, token) + if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { + return nil, err + } + if r != nil { + return r, nil + } + r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token) + if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { + return nil, err + } + if r != nil { + return r, nil + } + r, _, err = jsonpointer.GetForToken(p.HeaderProps, token) + return r, err +} diff --git a/vendor/github.com/go-openapi/spec/info.go b/vendor/github.com/go-openapi/spec/info.go new file mode 100644 index 000000000..fb8b7c4ac --- /dev/null +++ b/vendor/github.com/go-openapi/spec/info.go @@ -0,0 +1,168 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "strings" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +// Extensions vendor specific extensions +type Extensions map[string]interface{} + +// Add adds a value to these extensions +func (e Extensions) Add(key string, value interface{}) { + realKey := strings.ToLower(key) + e[realKey] = value +} + +// GetString gets a string value from the extensions +func (e Extensions) GetString(key string) (string, bool) { + if v, ok := e[strings.ToLower(key)]; ok { + str, ok := v.(string) + return str, ok + } + return "", false +} + +// GetBool gets a string value from the extensions +func (e Extensions) GetBool(key string) (bool, bool) { + if v, ok := e[strings.ToLower(key)]; ok { + str, ok := v.(bool) + return str, ok + } + return false, false +} + +// GetStringSlice gets a string value from the extensions +func (e Extensions) GetStringSlice(key string) ([]string, bool) { + if v, ok := e[strings.ToLower(key)]; ok { + arr, ok := v.([]interface{}) + if !ok { + return nil, false + } + var strs []string + for _, iface := range arr { + str, ok := iface.(string) + if !ok { + return nil, false + } + strs = append(strs, str) + } + return strs, ok + } + return nil, false +} + +// VendorExtensible composition block. +type VendorExtensible struct { + Extensions Extensions +} + +// AddExtension adds an extension to this extensible object +func (v *VendorExtensible) AddExtension(key string, value interface{}) { + if value == nil { + return + } + if v.Extensions == nil { + v.Extensions = make(map[string]interface{}) + } + v.Extensions.Add(key, value) +} + +// MarshalJSON marshals the extensions to json +func (v VendorExtensible) MarshalJSON() ([]byte, error) { + toser := make(map[string]interface{}) + for k, v := range v.Extensions { + lk := strings.ToLower(k) + if strings.HasPrefix(lk, "x-") { + toser[k] = v + } + } + return json.Marshal(toser) +} + +// UnmarshalJSON for this extensible object +func (v *VendorExtensible) UnmarshalJSON(data []byte) error { + var d map[string]interface{} + if err := json.Unmarshal(data, &d); err != nil { + return err + } + for k, vv := range d { + lk := strings.ToLower(k) + if strings.HasPrefix(lk, "x-") { + if v.Extensions == nil { + v.Extensions = map[string]interface{}{} + } + v.Extensions[k] = vv + } + } + return nil +} + +// InfoProps the properties for an info definition +type InfoProps struct { + Description string `json:"description,omitempty"` + Title string `json:"title,omitempty"` + TermsOfService string `json:"termsOfService,omitempty"` + Contact *ContactInfo `json:"contact,omitempty"` + License *License `json:"license,omitempty"` + Version string `json:"version,omitempty"` +} + +// Info object provides metadata about the API. +// The metadata can be used by the clients if needed, and can be presented in the Swagger-UI for convenience. +// +// For more information: http://goo.gl/8us55a#infoObject +type Info struct { + VendorExtensible + InfoProps +} + +// JSONLookup look up a value by the json property name +func (i Info) JSONLookup(token string) (interface{}, error) { + if ex, ok := i.Extensions[token]; ok { + return &ex, nil + } + r, _, err := jsonpointer.GetForToken(i.InfoProps, token) + return r, err +} + +// MarshalJSON marshal this to JSON +func (i Info) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(i.InfoProps) + if err != nil { + return nil, err + } + b2, err := json.Marshal(i.VendorExtensible) + if err != nil { + return nil, err + } + return swag.ConcatJSON(b1, b2), nil +} + +// UnmarshalJSON marshal this from JSON +func (i *Info) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &i.InfoProps); err != nil { + return err + } + if err := json.Unmarshal(data, &i.VendorExtensible); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/go-openapi/spec/items.go b/vendor/github.com/go-openapi/spec/items.go new file mode 100644 index 000000000..46944fb69 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/items.go @@ -0,0 +1,219 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "strings" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +type SimpleSchema struct { + Type string `json:"type,omitempty"` + Format string `json:"format,omitempty"` + Items *Items `json:"items,omitempty"` + CollectionFormat string `json:"collectionFormat,omitempty"` + Default interface{} `json:"default,omitempty"` +} + +func (s *SimpleSchema) TypeName() string { + if s.Format != "" { + return s.Format + } + return s.Type +} + +func (s *SimpleSchema) ItemsTypeName() string { + if s.Items == nil { + return "" + } + return s.Items.TypeName() +} + +type CommonValidations struct { + Maximum *float64 `json:"maximum,omitempty"` + ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` + Minimum *float64 `json:"minimum,omitempty"` + ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` + MaxLength *int64 `json:"maxLength,omitempty"` + MinLength *int64 `json:"minLength,omitempty"` + Pattern string `json:"pattern,omitempty"` + MaxItems *int64 `json:"maxItems,omitempty"` + MinItems *int64 `json:"minItems,omitempty"` + UniqueItems bool `json:"uniqueItems,omitempty"` + MultipleOf *float64 `json:"multipleOf,omitempty"` + Enum []interface{} `json:"enum,omitempty"` +} + +// Items a limited subset of JSON-Schema's items object. +// It is used by parameter definitions that are not located in "body". +// +// For more information: http://goo.gl/8us55a#items-object +type Items struct { + Refable + CommonValidations + SimpleSchema + VendorExtensible +} + +// NewItems creates a new instance of items +func NewItems() *Items { + return &Items{} +} + +// Typed a fluent builder method for the type of item +func (i *Items) Typed(tpe, format string) *Items { + i.Type = tpe + i.Format = format + return i +} + +// CollectionOf a fluent builder method for an array item +func (i *Items) CollectionOf(items *Items, format string) *Items { + i.Type = "array" + i.Items = items + i.CollectionFormat = format + return i +} + +// WithDefault sets the default value on this item +func (i *Items) WithDefault(defaultValue interface{}) *Items { + i.Default = defaultValue + return i +} + +// WithMaxLength sets a max length value +func (i *Items) WithMaxLength(max int64) *Items { + i.MaxLength = &max + return i +} + +// WithMinLength sets a min length value +func (i *Items) WithMinLength(min int64) *Items { + i.MinLength = &min + return i +} + +// WithPattern sets a pattern value +func (i *Items) WithPattern(pattern string) *Items { + i.Pattern = pattern + return i +} + +// WithMultipleOf sets a multiple of value +func (i *Items) WithMultipleOf(number float64) *Items { + i.MultipleOf = &number + return i +} + +// WithMaximum sets a maximum number value +func (i *Items) WithMaximum(max float64, exclusive bool) *Items { + i.Maximum = &max + i.ExclusiveMaximum = exclusive + return i +} + +// WithMinimum sets a minimum number value +func (i *Items) WithMinimum(min float64, exclusive bool) *Items { + i.Minimum = &min + i.ExclusiveMinimum = exclusive + return i +} + +// WithEnum sets a the enum values (replace) +func (i *Items) WithEnum(values ...interface{}) *Items { + i.Enum = append([]interface{}{}, values...) + return i +} + +// WithMaxItems sets the max items +func (i *Items) WithMaxItems(size int64) *Items { + i.MaxItems = &size + return i +} + +// WithMinItems sets the min items +func (i *Items) WithMinItems(size int64) *Items { + i.MinItems = &size + return i +} + +// UniqueValues dictates that this array can only have unique items +func (i *Items) UniqueValues() *Items { + i.UniqueItems = true + return i +} + +// AllowDuplicates this array can have duplicates +func (i *Items) AllowDuplicates() *Items { + i.UniqueItems = false + return i +} + +// UnmarshalJSON hydrates this items instance with the data from JSON +func (i *Items) UnmarshalJSON(data []byte) error { + var validations CommonValidations + if err := json.Unmarshal(data, &validations); err != nil { + return err + } + var ref Refable + if err := json.Unmarshal(data, &ref); err != nil { + return err + } + var simpleSchema SimpleSchema + if err := json.Unmarshal(data, &simpleSchema); err != nil { + return err + } + i.Refable = ref + i.CommonValidations = validations + i.SimpleSchema = simpleSchema + return nil +} + +// MarshalJSON converts this items object to JSON +func (i Items) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(i.CommonValidations) + if err != nil { + return nil, err + } + b2, err := json.Marshal(i.SimpleSchema) + if err != nil { + return nil, err + } + b3, err := json.Marshal(i.Refable) + if err != nil { + return nil, err + } + return swag.ConcatJSON(b3, b1, b2), nil +} + +// JSONLookup look up a value by the json property name +func (p Items) JSONLookup(token string) (interface{}, error) { + if token == "$ref" { + return &p.Ref, nil + } + + r, _, err := jsonpointer.GetForToken(p.CommonValidations, token) + if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { + return nil, err + } + if r != nil { + return r, nil + } + r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token) + return r, err +} diff --git a/vendor/github.com/go-openapi/spec/license.go b/vendor/github.com/go-openapi/spec/license.go new file mode 100644 index 000000000..f20961b4f --- /dev/null +++ b/vendor/github.com/go-openapi/spec/license.go @@ -0,0 +1,23 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +// License information for the exposed API. +// +// For more information: http://goo.gl/8us55a#licenseObject +type License struct { + Name string `json:"name,omitempty"` + URL string `json:"url,omitempty"` +} diff --git a/vendor/github.com/go-openapi/spec/operation.go b/vendor/github.com/go-openapi/spec/operation.go new file mode 100644 index 000000000..de1db6f02 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/operation.go @@ -0,0 +1,233 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +type OperationProps struct { + Description string `json:"description,omitempty"` + Consumes []string `json:"consumes,omitempty"` + Produces []string `json:"produces,omitempty"` + Schemes []string `json:"schemes,omitempty"` // the scheme, when present must be from [http, https, ws, wss] + Tags []string `json:"tags,omitempty"` + Summary string `json:"summary,omitempty"` + ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` + ID string `json:"operationId,omitempty"` + Deprecated bool `json:"deprecated,omitempty"` + Security []map[string][]string `json:"security,omitempty"` + Parameters []Parameter `json:"parameters,omitempty"` + Responses *Responses `json:"responses,omitempty"` +} + +// Operation describes a single API operation on a path. +// +// For more information: http://goo.gl/8us55a#operationObject +type Operation struct { + VendorExtensible + OperationProps +} + +// SuccessResponse gets a success response model +func (o *Operation) SuccessResponse() (*Response, int, bool) { + if o.Responses == nil { + return nil, 0, false + } + + for k, v := range o.Responses.StatusCodeResponses { + if k/100 == 2 { + return &v, k, true + } + } + + return o.Responses.Default, 0, false +} + +// JSONLookup look up a value by the json property name +func (o Operation) JSONLookup(token string) (interface{}, error) { + if ex, ok := o.Extensions[token]; ok { + return &ex, nil + } + r, _, err := jsonpointer.GetForToken(o.OperationProps, token) + return r, err +} + +// UnmarshalJSON hydrates this items instance with the data from JSON +func (o *Operation) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &o.OperationProps); err != nil { + return err + } + if err := json.Unmarshal(data, &o.VendorExtensible); err != nil { + return err + } + return nil +} + +// MarshalJSON converts this items object to JSON +func (o Operation) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(o.OperationProps) + if err != nil { + return nil, err + } + b2, err := json.Marshal(o.VendorExtensible) + if err != nil { + return nil, err + } + concated := swag.ConcatJSON(b1, b2) + return concated, nil +} + +// NewOperation creates a new operation instance. +// It expects an ID as parameter but not passing an ID is also valid. +func NewOperation(id string) *Operation { + op := new(Operation) + op.ID = id + return op +} + +// WithID sets the ID property on this operation, allows for chaining. +func (o *Operation) WithID(id string) *Operation { + o.ID = id + return o +} + +// WithDescription sets the description on this operation, allows for chaining +func (o *Operation) WithDescription(description string) *Operation { + o.Description = description + return o +} + +// WithSummary sets the summary on this operation, allows for chaining +func (o *Operation) WithSummary(summary string) *Operation { + o.Summary = summary + return o +} + +// WithExternalDocs sets/removes the external docs for/from this operation. +// When you pass empty strings as params the external documents will be removed. +// When you pass non-empty string as one value then those values will be used on the external docs object. +// So when you pass a non-empty description, you should also pass the url and vice versa. +func (o *Operation) WithExternalDocs(description, url string) *Operation { + if description == "" && url == "" { + o.ExternalDocs = nil + return o + } + + if o.ExternalDocs == nil { + o.ExternalDocs = &ExternalDocumentation{} + } + o.ExternalDocs.Description = description + o.ExternalDocs.URL = url + return o +} + +// Deprecate marks the operation as deprecated +func (o *Operation) Deprecate() *Operation { + o.Deprecated = true + return o +} + +// Undeprecate marks the operation as not deprected +func (o *Operation) Undeprecate() *Operation { + o.Deprecated = false + return o +} + +// WithConsumes adds media types for incoming body values +func (o *Operation) WithConsumes(mediaTypes ...string) *Operation { + o.Consumes = append(o.Consumes, mediaTypes...) + return o +} + +// WithProduces adds media types for outgoing body values +func (o *Operation) WithProduces(mediaTypes ...string) *Operation { + o.Produces = append(o.Produces, mediaTypes...) + return o +} + +// WithTags adds tags for this operation +func (o *Operation) WithTags(tags ...string) *Operation { + o.Tags = append(o.Tags, tags...) + return o +} + +// AddParam adds a parameter to this operation, when a parameter for that location +// and with that name already exists it will be replaced +func (o *Operation) AddParam(param *Parameter) *Operation { + if param == nil { + return o + } + + for i, p := range o.Parameters { + if p.Name == param.Name && p.In == param.In { + params := append(o.Parameters[:i], *param) + params = append(params, o.Parameters[i+1:]...) + o.Parameters = params + return o + } + } + + o.Parameters = append(o.Parameters, *param) + return o +} + +// RemoveParam removes a parameter from the operation +func (o *Operation) RemoveParam(name, in string) *Operation { + for i, p := range o.Parameters { + if p.Name == name && p.In == name { + o.Parameters = append(o.Parameters[:i], o.Parameters[i+1:]...) + return o + } + } + return o +} + +// SecuredWith adds a security scope to this operation. +func (o *Operation) SecuredWith(name string, scopes ...string) *Operation { + o.Security = append(o.Security, map[string][]string{name: scopes}) + return o +} + +// WithDefaultResponse adds a default response to the operation. +// Passing a nil value will remove the response +func (o *Operation) WithDefaultResponse(response *Response) *Operation { + return o.RespondsWith(0, response) +} + +// RespondsWith adds a status code response to the operation. +// When the code is 0 the value of the response will be used as default response value. +// When the value of the response is nil it will be removed from the operation +func (o *Operation) RespondsWith(code int, response *Response) *Operation { + if o.Responses == nil { + o.Responses = new(Responses) + } + if code == 0 { + o.Responses.Default = response + return o + } + if response == nil { + delete(o.Responses.StatusCodeResponses, code) + return o + } + if o.Responses.StatusCodeResponses == nil { + o.Responses.StatusCodeResponses = make(map[int]Response) + } + o.Responses.StatusCodeResponses[code] = *response + return o +} diff --git a/vendor/github.com/go-openapi/spec/parameter.go b/vendor/github.com/go-openapi/spec/parameter.go new file mode 100644 index 000000000..71aee1e80 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/parameter.go @@ -0,0 +1,301 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "strings" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +// QueryParam creates a query parameter +func QueryParam(name string) *Parameter { + return &Parameter{ParamProps: ParamProps{Name: name, In: "query"}} +} + +// HeaderParam creates a header parameter, this is always required by default +func HeaderParam(name string) *Parameter { + return &Parameter{ParamProps: ParamProps{Name: name, In: "header", Required: true}} +} + +// PathParam creates a path parameter, this is always required +func PathParam(name string) *Parameter { + return &Parameter{ParamProps: ParamProps{Name: name, In: "path", Required: true}} +} + +// BodyParam creates a body parameter +func BodyParam(name string, schema *Schema) *Parameter { + return &Parameter{ParamProps: ParamProps{Name: name, In: "body", Schema: schema}, SimpleSchema: SimpleSchema{Type: "object"}} +} + +// FormDataParam creates a body parameter +func FormDataParam(name string) *Parameter { + return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}} +} + +// FileParam creates a body parameter +func FileParam(name string) *Parameter { + return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}, SimpleSchema: SimpleSchema{Type: "file"}} +} + +// SimpleArrayParam creates a param for a simple array (string, int, date etc) +func SimpleArrayParam(name, tpe, fmt string) *Parameter { + return &Parameter{ParamProps: ParamProps{Name: name}, SimpleSchema: SimpleSchema{Type: "array", CollectionFormat: "csv", Items: &Items{SimpleSchema: SimpleSchema{Type: "string", Format: fmt}}}} +} + +// ParamRef creates a parameter that's a json reference +func ParamRef(uri string) *Parameter { + p := new(Parameter) + p.Ref = MustCreateRef(uri) + return p +} + +type ParamProps struct { + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + In string `json:"in,omitempty"` + Required bool `json:"required,omitempty"` + Schema *Schema `json:"schema,omitempty"` // when in == "body" + AllowEmptyValue bool `json:"allowEmptyValue,omitempty"` // when in == "query" || "formData" +} + +// Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn). +// +// There are five possible parameter types. +// * Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`, the path parameter is `itemId`. +// * Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`. +// * Header - Custom headers that are expected as part of the request. +// * Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be *one* body parameter. The name of the body parameter has no effect on the parameter itself and is used for documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist together for the same operation. +// * Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or `multipart/form-data` are used as the content type of the request (in Swagger's definition, the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be declared together with a body parameter for the same operation. Form parameters have a different format based on the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4): +// * `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload. For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple parameters that are being transferred. +// * `multipart/form-data` - each parameter takes a section in the payload with an internal header. For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is `submit-name`. This type of form parameters is more commonly used for file transfers. +// +// For more information: http://goo.gl/8us55a#parameterObject +type Parameter struct { + Refable + CommonValidations + SimpleSchema + VendorExtensible + ParamProps +} + +// JSONLookup look up a value by the json property name +func (p Parameter) JSONLookup(token string) (interface{}, error) { + if ex, ok := p.Extensions[token]; ok { + return &ex, nil + } + if token == "$ref" { + return &p.Ref, nil + } + + r, _, err := jsonpointer.GetForToken(p.CommonValidations, token) + if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { + return nil, err + } + if r != nil { + return r, nil + } + r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token) + if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { + return nil, err + } + if r != nil { + return r, nil + } + r, _, err = jsonpointer.GetForToken(p.ParamProps, token) + return r, err +} + +// WithDescription a fluent builder method for the description of the parameter +func (p *Parameter) WithDescription(description string) *Parameter { + p.Description = description + return p +} + +// Named a fluent builder method to override the name of the parameter +func (p *Parameter) Named(name string) *Parameter { + p.Name = name + return p +} + +// WithLocation a fluent builder method to override the location of the parameter +func (p *Parameter) WithLocation(in string) *Parameter { + p.In = in + return p +} + +// Typed a fluent builder method for the type of the parameter value +func (p *Parameter) Typed(tpe, format string) *Parameter { + p.Type = tpe + p.Format = format + return p +} + +// CollectionOf a fluent builder method for an array parameter +func (p *Parameter) CollectionOf(items *Items, format string) *Parameter { + p.Type = "array" + p.Items = items + p.CollectionFormat = format + return p +} + +// WithDefault sets the default value on this parameter +func (p *Parameter) WithDefault(defaultValue interface{}) *Parameter { + p.AsOptional() // with default implies optional + p.Default = defaultValue + return p +} + +// AllowsEmptyValues flags this parameter as being ok with empty values +func (p *Parameter) AllowsEmptyValues() *Parameter { + p.AllowEmptyValue = true + return p +} + +// NoEmptyValues flags this parameter as not liking empty values +func (p *Parameter) NoEmptyValues() *Parameter { + p.AllowEmptyValue = false + return p +} + +// AsOptional flags this parameter as optional +func (p *Parameter) AsOptional() *Parameter { + p.Required = false + return p +} + +// AsRequired flags this parameter as required +func (p *Parameter) AsRequired() *Parameter { + if p.Default != nil { // with a default required makes no sense + return p + } + p.Required = true + return p +} + +// WithMaxLength sets a max length value +func (p *Parameter) WithMaxLength(max int64) *Parameter { + p.MaxLength = &max + return p +} + +// WithMinLength sets a min length value +func (p *Parameter) WithMinLength(min int64) *Parameter { + p.MinLength = &min + return p +} + +// WithPattern sets a pattern value +func (p *Parameter) WithPattern(pattern string) *Parameter { + p.Pattern = pattern + return p +} + +// WithMultipleOf sets a multiple of value +func (p *Parameter) WithMultipleOf(number float64) *Parameter { + p.MultipleOf = &number + return p +} + +// WithMaximum sets a maximum number value +func (p *Parameter) WithMaximum(max float64, exclusive bool) *Parameter { + p.Maximum = &max + p.ExclusiveMaximum = exclusive + return p +} + +// WithMinimum sets a minimum number value +func (p *Parameter) WithMinimum(min float64, exclusive bool) *Parameter { + p.Minimum = &min + p.ExclusiveMinimum = exclusive + return p +} + +// WithEnum sets a the enum values (replace) +func (p *Parameter) WithEnum(values ...interface{}) *Parameter { + p.Enum = append([]interface{}{}, values...) + return p +} + +// WithMaxItems sets the max items +func (p *Parameter) WithMaxItems(size int64) *Parameter { + p.MaxItems = &size + return p +} + +// WithMinItems sets the min items +func (p *Parameter) WithMinItems(size int64) *Parameter { + p.MinItems = &size + return p +} + +// UniqueValues dictates that this array can only have unique items +func (p *Parameter) UniqueValues() *Parameter { + p.UniqueItems = true + return p +} + +// AllowDuplicates this array can have duplicates +func (p *Parameter) AllowDuplicates() *Parameter { + p.UniqueItems = false + return p +} + +// UnmarshalJSON hydrates this items instance with the data from JSON +func (p *Parameter) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &p.CommonValidations); err != nil { + return err + } + if err := json.Unmarshal(data, &p.Refable); err != nil { + return err + } + if err := json.Unmarshal(data, &p.SimpleSchema); err != nil { + return err + } + if err := json.Unmarshal(data, &p.VendorExtensible); err != nil { + return err + } + if err := json.Unmarshal(data, &p.ParamProps); err != nil { + return err + } + return nil +} + +// MarshalJSON converts this items object to JSON +func (p Parameter) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(p.CommonValidations) + if err != nil { + return nil, err + } + b2, err := json.Marshal(p.SimpleSchema) + if err != nil { + return nil, err + } + b3, err := json.Marshal(p.Refable) + if err != nil { + return nil, err + } + b4, err := json.Marshal(p.VendorExtensible) + if err != nil { + return nil, err + } + b5, err := json.Marshal(p.ParamProps) + if err != nil { + return nil, err + } + return swag.ConcatJSON(b3, b1, b2, b4, b5), nil +} diff --git a/vendor/github.com/go-openapi/spec/path_item.go b/vendor/github.com/go-openapi/spec/path_item.go new file mode 100644 index 000000000..9ab3ec538 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/path_item.go @@ -0,0 +1,90 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +// pathItemProps the path item specific properties +type PathItemProps struct { + Get *Operation `json:"get,omitempty"` + Put *Operation `json:"put,omitempty"` + Post *Operation `json:"post,omitempty"` + Delete *Operation `json:"delete,omitempty"` + Options *Operation `json:"options,omitempty"` + Head *Operation `json:"head,omitempty"` + Patch *Operation `json:"patch,omitempty"` + Parameters []Parameter `json:"parameters,omitempty"` +} + +// PathItem describes the operations available on a single path. +// A Path Item may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering). +// The path itself is still exposed to the documentation viewer but they will +// not know which operations and parameters are available. +// +// For more information: http://goo.gl/8us55a#pathItemObject +type PathItem struct { + Refable + VendorExtensible + PathItemProps +} + +// JSONLookup look up a value by the json property name +func (p PathItem) JSONLookup(token string) (interface{}, error) { + if ex, ok := p.Extensions[token]; ok { + return &ex, nil + } + if token == "$ref" { + return &p.Ref, nil + } + r, _, err := jsonpointer.GetForToken(p.PathItemProps, token) + return r, err +} + +// UnmarshalJSON hydrates this items instance with the data from JSON +func (p *PathItem) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &p.Refable); err != nil { + return err + } + if err := json.Unmarshal(data, &p.VendorExtensible); err != nil { + return err + } + if err := json.Unmarshal(data, &p.PathItemProps); err != nil { + return err + } + return nil +} + +// MarshalJSON converts this items object to JSON +func (p PathItem) MarshalJSON() ([]byte, error) { + b3, err := json.Marshal(p.Refable) + if err != nil { + return nil, err + } + b4, err := json.Marshal(p.VendorExtensible) + if err != nil { + return nil, err + } + b5, err := json.Marshal(p.PathItemProps) + if err != nil { + return nil, err + } + concated := swag.ConcatJSON(b3, b4, b5) + return concated, nil +} diff --git a/vendor/github.com/go-openapi/spec/paths.go b/vendor/github.com/go-openapi/spec/paths.go new file mode 100644 index 000000000..9dc82a290 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/paths.go @@ -0,0 +1,97 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/go-openapi/swag" +) + +// Paths holds the relative paths to the individual endpoints. +// The path is appended to the [`basePath`](http://goo.gl/8us55a#swaggerBasePath) in order +// to construct the full URL. +// The Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering). +// +// For more information: http://goo.gl/8us55a#pathsObject +type Paths struct { + VendorExtensible + Paths map[string]PathItem `json:"-"` // custom serializer to flatten this, each entry must start with "/" +} + +// JSONLookup look up a value by the json property name +func (p Paths) JSONLookup(token string) (interface{}, error) { + if pi, ok := p.Paths[token]; ok { + return &pi, nil + } + if ex, ok := p.Extensions[token]; ok { + return &ex, nil + } + return nil, fmt.Errorf("object has no field %q", token) +} + +// UnmarshalJSON hydrates this items instance with the data from JSON +func (p *Paths) UnmarshalJSON(data []byte) error { + var res map[string]json.RawMessage + if err := json.Unmarshal(data, &res); err != nil { + return err + } + for k, v := range res { + if strings.HasPrefix(strings.ToLower(k), "x-") { + if p.Extensions == nil { + p.Extensions = make(map[string]interface{}) + } + var d interface{} + if err := json.Unmarshal(v, &d); err != nil { + return err + } + p.Extensions[k] = d + } + if strings.HasPrefix(k, "/") { + if p.Paths == nil { + p.Paths = make(map[string]PathItem) + } + var pi PathItem + if err := json.Unmarshal(v, &pi); err != nil { + return err + } + p.Paths[k] = pi + } + } + return nil +} + +// MarshalJSON converts this items object to JSON +func (p Paths) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(p.VendorExtensible) + if err != nil { + return nil, err + } + + pths := make(map[string]PathItem) + for k, v := range p.Paths { + if strings.HasPrefix(k, "/") { + pths[k] = v + } + } + b2, err := json.Marshal(pths) + if err != nil { + return nil, err + } + concated := swag.ConcatJSON(b1, b2) + return concated, nil +} diff --git a/vendor/github.com/go-openapi/spec/ref.go b/vendor/github.com/go-openapi/spec/ref.go new file mode 100644 index 000000000..4833b87e2 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/ref.go @@ -0,0 +1,164 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "net/http" + "os" + "path/filepath" + + "github.com/go-openapi/jsonreference" +) + +// Refable is a struct for things that accept a $ref property +type Refable struct { + Ref Ref +} + +// MarshalJSON marshals the ref to json +func (r Refable) MarshalJSON() ([]byte, error) { + return r.Ref.MarshalJSON() +} + +// UnmarshalJSON unmarshalss the ref from json +func (r *Refable) UnmarshalJSON(d []byte) error { + return json.Unmarshal(d, &r.Ref) +} + +// Ref represents a json reference that is potentially resolved +type Ref struct { + jsonreference.Ref +} + +// RemoteURI gets the remote uri part of the ref +func (r *Ref) RemoteURI() string { + if r.String() == "" { + return r.String() + } + + u := *r.GetURL() + u.Fragment = "" + return u.String() +} + +// IsValidURI returns true when the url the ref points to can be found +func (r *Ref) IsValidURI(basepaths ...string) bool { + if r.String() == "" { + return true + } + + v := r.RemoteURI() + if v == "" { + return true + } + + if r.HasFullURL { + rr, err := http.Get(v) + if err != nil { + return false + } + + return rr.StatusCode/100 == 2 + } + + if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) { + return false + } + + // check for local file + pth := v + if r.HasURLPathOnly { + base := "." + if len(basepaths) > 0 { + base = filepath.Dir(filepath.Join(basepaths...)) + } + p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth))) + if e != nil { + return false + } + pth = p + } + + fi, err := os.Stat(filepath.ToSlash(pth)) + if err != nil { + return false + } + + return !fi.IsDir() +} + +// Inherits creates a new reference from a parent and a child +// If the child cannot inherit from the parent, an error is returned +func (r *Ref) Inherits(child Ref) (*Ref, error) { + ref, err := r.Ref.Inherits(child.Ref) + if err != nil { + return nil, err + } + return &Ref{Ref: *ref}, nil +} + +// NewRef creates a new instance of a ref object +// returns an error when the reference uri is an invalid uri +func NewRef(refURI string) (Ref, error) { + ref, err := jsonreference.New(refURI) + if err != nil { + return Ref{}, err + } + return Ref{Ref: ref}, nil +} + +// MustCreateRef creates a ref object but panics when refURI is invalid. +// Use the NewRef method for a version that returns an error. +func MustCreateRef(refURI string) Ref { + return Ref{Ref: jsonreference.MustCreateRef(refURI)} +} + +// MarshalJSON marshals this ref into a JSON object +func (r Ref) MarshalJSON() ([]byte, error) { + str := r.String() + if str == "" { + if r.IsRoot() { + return []byte(`{"$ref":""}`), nil + } + return []byte("{}"), nil + } + v := map[string]interface{}{"$ref": str} + return json.Marshal(v) +} + +// UnmarshalJSON unmarshals this ref from a JSON object +func (r *Ref) UnmarshalJSON(d []byte) error { + var v map[string]interface{} + if err := json.Unmarshal(d, &v); err != nil { + return err + } + + if v == nil { + return nil + } + + if vv, ok := v["$ref"]; ok { + if str, ok := vv.(string); ok { + ref, err := jsonreference.New(str) + if err != nil { + return err + } + *r = Ref{Ref: ref} + } + } + + return nil +} diff --git a/vendor/github.com/go-openapi/spec/response.go b/vendor/github.com/go-openapi/spec/response.go new file mode 100644 index 000000000..a32b039ea --- /dev/null +++ b/vendor/github.com/go-openapi/spec/response.go @@ -0,0 +1,134 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +// ResponseProps properties specific to a response +type ResponseProps struct { + Description string `json:"description,omitempty"` + Schema *Schema `json:"schema,omitempty"` + Headers map[string]Header `json:"headers,omitempty"` + Examples map[string]interface{} `json:"examples,omitempty"` +} + +// Response describes a single response from an API Operation. +// +// For more information: http://goo.gl/8us55a#responseObject +type Response struct { + Refable + ResponseProps + VendorExtensible +} + +// JSONLookup look up a value by the json property name +func (p Response) JSONLookup(token string) (interface{}, error) { + if ex, ok := p.Extensions[token]; ok { + return &ex, nil + } + if token == "$ref" { + return &p.Ref, nil + } + r, _, err := jsonpointer.GetForToken(p.ResponseProps, token) + return r, err +} + +// UnmarshalJSON hydrates this items instance with the data from JSON +func (r *Response) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &r.ResponseProps); err != nil { + return err + } + if err := json.Unmarshal(data, &r.Refable); err != nil { + return err + } + if err := json.Unmarshal(data, &r.VendorExtensible); err != nil { + return err + } + return nil +} + +// MarshalJSON converts this items object to JSON +func (r Response) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(r.ResponseProps) + if err != nil { + return nil, err + } + b2, err := json.Marshal(r.Refable) + if err != nil { + return nil, err + } + b3, err := json.Marshal(r.VendorExtensible) + if err != nil { + return nil, err + } + return swag.ConcatJSON(b1, b2, b3), nil +} + +// NewResponse creates a new response instance +func NewResponse() *Response { + return new(Response) +} + +// ResponseRef creates a response as a json reference +func ResponseRef(url string) *Response { + resp := NewResponse() + resp.Ref = MustCreateRef(url) + return resp +} + +// WithDescription sets the description on this response, allows for chaining +func (r *Response) WithDescription(description string) *Response { + r.Description = description + return r +} + +// WithSchema sets the schema on this response, allows for chaining. +// Passing a nil argument removes the schema from this response +func (r *Response) WithSchema(schema *Schema) *Response { + r.Schema = schema + return r +} + +// AddHeader adds a header to this response +func (r *Response) AddHeader(name string, header *Header) *Response { + if header == nil { + return r.RemoveHeader(name) + } + if r.Headers == nil { + r.Headers = make(map[string]Header) + } + r.Headers[name] = *header + return r +} + +// RemoveHeader removes a header from this response +func (r *Response) RemoveHeader(name string) *Response { + delete(r.Headers, name) + return r +} + +// AddExample adds an example to this response +func (r *Response) AddExample(mediaType string, example interface{}) *Response { + if r.Examples == nil { + r.Examples = make(map[string]interface{}) + } + r.Examples[mediaType] = example + return r +} diff --git a/vendor/github.com/go-openapi/spec/responses.go b/vendor/github.com/go-openapi/spec/responses.go new file mode 100644 index 000000000..3ab06697f --- /dev/null +++ b/vendor/github.com/go-openapi/spec/responses.go @@ -0,0 +1,122 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "fmt" + "reflect" + "strconv" + + "github.com/go-openapi/swag" +) + +// Responses is a container for the expected responses of an operation. +// The container maps a HTTP response code to the expected response. +// It is not expected from the documentation to necessarily cover all possible HTTP response codes, +// since they may not be known in advance. However, it is expected from the documentation to cover +// a successful operation response and any known errors. +// +// The `default` can be used a default response object for all HTTP codes that are not covered +// individually by the specification. +// +// The `Responses Object` MUST contain at least one response code, and it SHOULD be the response +// for a successful operation call. +// +// For more information: http://goo.gl/8us55a#responsesObject +type Responses struct { + VendorExtensible + ResponsesProps +} + +// JSONLookup implements an interface to customize json pointer lookup +func (r Responses) JSONLookup(token string) (interface{}, error) { + if token == "default" { + return r.Default, nil + } + if ex, ok := r.Extensions[token]; ok { + return &ex, nil + } + if i, err := strconv.Atoi(token); err == nil { + if scr, ok := r.StatusCodeResponses[i]; ok { + return scr, nil + } + } + return nil, fmt.Errorf("object has no field %q", token) +} + +// UnmarshalJSON hydrates this items instance with the data from JSON +func (r *Responses) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &r.ResponsesProps); err != nil { + return err + } + if err := json.Unmarshal(data, &r.VendorExtensible); err != nil { + return err + } + if reflect.DeepEqual(ResponsesProps{}, r.ResponsesProps) { + r.ResponsesProps = ResponsesProps{} + } + return nil +} + +// MarshalJSON converts this items object to JSON +func (r Responses) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(r.ResponsesProps) + if err != nil { + return nil, err + } + b2, err := json.Marshal(r.VendorExtensible) + if err != nil { + return nil, err + } + concated := swag.ConcatJSON(b1, b2) + return concated, nil +} + +type ResponsesProps struct { + Default *Response + StatusCodeResponses map[int]Response +} + +func (r ResponsesProps) MarshalJSON() ([]byte, error) { + toser := map[string]Response{} + if r.Default != nil { + toser["default"] = *r.Default + } + for k, v := range r.StatusCodeResponses { + toser[strconv.Itoa(k)] = v + } + return json.Marshal(toser) +} + +func (r *ResponsesProps) UnmarshalJSON(data []byte) error { + var res map[string]Response + if err := json.Unmarshal(data, &res); err != nil { + return nil + } + if v, ok := res["default"]; ok { + r.Default = &v + delete(res, "default") + } + for k, v := range res { + if nk, err := strconv.Atoi(k); err == nil { + if r.StatusCodeResponses == nil { + r.StatusCodeResponses = map[int]Response{} + } + r.StatusCodeResponses[nk] = v + } + } + return nil +} diff --git a/vendor/github.com/go-openapi/spec/schema.go b/vendor/github.com/go-openapi/spec/schema.go new file mode 100644 index 000000000..1cdcc163f --- /dev/null +++ b/vendor/github.com/go-openapi/spec/schema.go @@ -0,0 +1,628 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "fmt" + "net/url" + "strings" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +// BooleanProperty creates a boolean property +func BooleanProperty() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}} +} + +// BoolProperty creates a boolean property +func BoolProperty() *Schema { return BooleanProperty() } + +// StringProperty creates a string property +func StringProperty() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} +} + +// CharProperty creates a string property +func CharProperty() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} +} + +// Float64Property creates a float64/double property +func Float64Property() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}} +} + +// Float32Property creates a float32/float property +func Float32Property() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}} +} + +// Int8Property creates an int8 property +func Int8Property() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}} +} + +// Int16Property creates an int16 property +func Int16Property() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}} +} + +// Int32Property creates an int32 property +func Int32Property() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}} +} + +// Int64Property creates an int64 property +func Int64Property() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}} +} + +// StrFmtProperty creates a property for the named string format +func StrFmtProperty(format string) *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}} +} + +// DateProperty creates a date property +func DateProperty() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}} +} + +// DateTimeProperty creates a date time property +func DateTimeProperty() *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}} +} + +// MapProperty creates a map property +func MapProperty(property *Schema) *Schema { + return &Schema{SchemaProps: SchemaProps{Type: []string{"object"}, AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}} +} + +// RefProperty creates a ref property +func RefProperty(name string) *Schema { + return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} +} + +// RefSchema creates a ref property +func RefSchema(name string) *Schema { + return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} +} + +// ArrayProperty creates an array property +func ArrayProperty(items *Schema) *Schema { + if items == nil { + return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}} + } + return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}} +} + +// ComposedSchema creates a schema with allOf +func ComposedSchema(schemas ...Schema) *Schema { + s := new(Schema) + s.AllOf = schemas + return s +} + +// SchemaURL represents a schema url +type SchemaURL string + +// MarshalJSON marshal this to JSON +func (r SchemaURL) MarshalJSON() ([]byte, error) { + if r == "" { + return []byte("{}"), nil + } + v := map[string]interface{}{"$schema": string(r)} + return json.Marshal(v) +} + +// UnmarshalJSON unmarshal this from JSON +func (r *SchemaURL) UnmarshalJSON(data []byte) error { + var v map[string]interface{} + if err := json.Unmarshal(data, &v); err != nil { + return err + } + if v == nil { + return nil + } + if vv, ok := v["$schema"]; ok { + if str, ok := vv.(string); ok { + u, err := url.Parse(str) + if err != nil { + return err + } + + *r = SchemaURL(u.String()) + } + } + return nil +} + +// type ExtraSchemaProps map[string]interface{} + +// // JSONSchema represents a structure that is a json schema draft 04 +// type JSONSchema struct { +// SchemaProps +// ExtraSchemaProps +// } + +// // MarshalJSON marshal this to JSON +// func (s JSONSchema) MarshalJSON() ([]byte, error) { +// b1, err := json.Marshal(s.SchemaProps) +// if err != nil { +// return nil, err +// } +// b2, err := s.Ref.MarshalJSON() +// if err != nil { +// return nil, err +// } +// b3, err := s.Schema.MarshalJSON() +// if err != nil { +// return nil, err +// } +// b4, err := json.Marshal(s.ExtraSchemaProps) +// if err != nil { +// return nil, err +// } +// return swag.ConcatJSON(b1, b2, b3, b4), nil +// } + +// // UnmarshalJSON marshal this from JSON +// func (s *JSONSchema) UnmarshalJSON(data []byte) error { +// var sch JSONSchema +// if err := json.Unmarshal(data, &sch.SchemaProps); err != nil { +// return err +// } +// if err := json.Unmarshal(data, &sch.Ref); err != nil { +// return err +// } +// if err := json.Unmarshal(data, &sch.Schema); err != nil { +// return err +// } +// if err := json.Unmarshal(data, &sch.ExtraSchemaProps); err != nil { +// return err +// } +// *s = sch +// return nil +// } + +type SchemaProps struct { + ID string `json:"id,omitempty"` + Ref Ref `json:"-"` + Schema SchemaURL `json:"-"` + Description string `json:"description,omitempty"` + Type StringOrArray `json:"type,omitempty"` + Format string `json:"format,omitempty"` + Title string `json:"title,omitempty"` + Default interface{} `json:"default,omitempty"` + Maximum *float64 `json:"maximum,omitempty"` + ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` + Minimum *float64 `json:"minimum,omitempty"` + ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` + MaxLength *int64 `json:"maxLength,omitempty"` + MinLength *int64 `json:"minLength,omitempty"` + Pattern string `json:"pattern,omitempty"` + MaxItems *int64 `json:"maxItems,omitempty"` + MinItems *int64 `json:"minItems,omitempty"` + UniqueItems bool `json:"uniqueItems,omitempty"` + MultipleOf *float64 `json:"multipleOf,omitempty"` + Enum []interface{} `json:"enum,omitempty"` + MaxProperties *int64 `json:"maxProperties,omitempty"` + MinProperties *int64 `json:"minProperties,omitempty"` + Required []string `json:"required,omitempty"` + Items *SchemaOrArray `json:"items,omitempty"` + AllOf []Schema `json:"allOf,omitempty"` + OneOf []Schema `json:"oneOf,omitempty"` + AnyOf []Schema `json:"anyOf,omitempty"` + Not *Schema `json:"not,omitempty"` + Properties map[string]Schema `json:"properties,omitempty"` + AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitempty"` + PatternProperties map[string]Schema `json:"patternProperties,omitempty"` + Dependencies Dependencies `json:"dependencies,omitempty"` + AdditionalItems *SchemaOrBool `json:"additionalItems,omitempty"` + Definitions Definitions `json:"definitions,omitempty"` +} + +type SwaggerSchemaProps struct { + Discriminator string `json:"discriminator,omitempty"` + ReadOnly bool `json:"readOnly,omitempty"` + XML *XMLObject `json:"xml,omitempty"` + ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` + Example interface{} `json:"example,omitempty"` +} + +// Schema the schema object allows the definition of input and output data types. +// These types can be objects, but also primitives and arrays. +// This object is based on the [JSON Schema Specification Draft 4](http://json-schema.org/) +// and uses a predefined subset of it. +// On top of this subset, there are extensions provided by this specification to allow for more complete documentation. +// +// For more information: http://goo.gl/8us55a#schemaObject +type Schema struct { + VendorExtensible + SchemaProps + SwaggerSchemaProps + ExtraProps map[string]interface{} `json:"-"` +} + +// JSONLookup implements an interface to customize json pointer lookup +func (s Schema) JSONLookup(token string) (interface{}, error) { + if ex, ok := s.Extensions[token]; ok { + return &ex, nil + } + + if ex, ok := s.ExtraProps[token]; ok { + return &ex, nil + } + + r, _, err := jsonpointer.GetForToken(s.SchemaProps, token) + if r != nil || (err != nil && !strings.HasPrefix(err.Error(), "object has no field")) { + return r, err + } + r, _, err = jsonpointer.GetForToken(s.SwaggerSchemaProps, token) + return r, err +} + +// WithID sets the id for this schema, allows for chaining +func (s *Schema) WithID(id string) *Schema { + s.ID = id + return s +} + +// WithTitle sets the title for this schema, allows for chaining +func (s *Schema) WithTitle(title string) *Schema { + s.Title = title + return s +} + +// WithDescription sets the description for this schema, allows for chaining +func (s *Schema) WithDescription(description string) *Schema { + s.Description = description + return s +} + +// WithProperties sets the properties for this schema +func (s *Schema) WithProperties(schemas map[string]Schema) *Schema { + s.Properties = schemas + return s +} + +// SetProperty sets a property on this schema +func (s *Schema) SetProperty(name string, schema Schema) *Schema { + if s.Properties == nil { + s.Properties = make(map[string]Schema) + } + s.Properties[name] = schema + return s +} + +// WithAllOf sets the all of property +func (s *Schema) WithAllOf(schemas ...Schema) *Schema { + s.AllOf = schemas + return s +} + +// WithMaxProperties sets the max number of properties an object can have +func (s *Schema) WithMaxProperties(max int64) *Schema { + s.MaxProperties = &max + return s +} + +// WithMinProperties sets the min number of properties an object must have +func (s *Schema) WithMinProperties(min int64) *Schema { + s.MinProperties = &min + return s +} + +// Typed sets the type of this schema for a single value item +func (s *Schema) Typed(tpe, format string) *Schema { + s.Type = []string{tpe} + s.Format = format + return s +} + +// AddType adds a type with potential format to the types for this schema +func (s *Schema) AddType(tpe, format string) *Schema { + s.Type = append(s.Type, tpe) + if format != "" { + s.Format = format + } + return s +} + +// CollectionOf a fluent builder method for an array parameter +func (s *Schema) CollectionOf(items Schema) *Schema { + s.Type = []string{"array"} + s.Items = &SchemaOrArray{Schema: &items} + return s +} + +// WithDefault sets the default value on this parameter +func (s *Schema) WithDefault(defaultValue interface{}) *Schema { + s.Default = defaultValue + return s +} + +// WithRequired flags this parameter as required +func (s *Schema) WithRequired(items ...string) *Schema { + s.Required = items + return s +} + +// AddRequired adds field names to the required properties array +func (s *Schema) AddRequired(items ...string) *Schema { + s.Required = append(s.Required, items...) + return s +} + +// WithMaxLength sets a max length value +func (s *Schema) WithMaxLength(max int64) *Schema { + s.MaxLength = &max + return s +} + +// WithMinLength sets a min length value +func (s *Schema) WithMinLength(min int64) *Schema { + s.MinLength = &min + return s +} + +// WithPattern sets a pattern value +func (s *Schema) WithPattern(pattern string) *Schema { + s.Pattern = pattern + return s +} + +// WithMultipleOf sets a multiple of value +func (s *Schema) WithMultipleOf(number float64) *Schema { + s.MultipleOf = &number + return s +} + +// WithMaximum sets a maximum number value +func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema { + s.Maximum = &max + s.ExclusiveMaximum = exclusive + return s +} + +// WithMinimum sets a minimum number value +func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema { + s.Minimum = &min + s.ExclusiveMinimum = exclusive + return s +} + +// WithEnum sets a the enum values (replace) +func (s *Schema) WithEnum(values ...interface{}) *Schema { + s.Enum = append([]interface{}{}, values...) + return s +} + +// WithMaxItems sets the max items +func (s *Schema) WithMaxItems(size int64) *Schema { + s.MaxItems = &size + return s +} + +// WithMinItems sets the min items +func (s *Schema) WithMinItems(size int64) *Schema { + s.MinItems = &size + return s +} + +// UniqueValues dictates that this array can only have unique items +func (s *Schema) UniqueValues() *Schema { + s.UniqueItems = true + return s +} + +// AllowDuplicates this array can have duplicates +func (s *Schema) AllowDuplicates() *Schema { + s.UniqueItems = false + return s +} + +// AddToAllOf adds a schema to the allOf property +func (s *Schema) AddToAllOf(schemas ...Schema) *Schema { + s.AllOf = append(s.AllOf, schemas...) + return s +} + +// WithDiscriminator sets the name of the discriminator field +func (s *Schema) WithDiscriminator(discriminator string) *Schema { + s.Discriminator = discriminator + return s +} + +// AsReadOnly flags this schema as readonly +func (s *Schema) AsReadOnly() *Schema { + s.ReadOnly = true + return s +} + +// AsWritable flags this schema as writeable (not read-only) +func (s *Schema) AsWritable() *Schema { + s.ReadOnly = false + return s +} + +// WithExample sets the example for this schema +func (s *Schema) WithExample(example interface{}) *Schema { + s.Example = example + return s +} + +// WithExternalDocs sets/removes the external docs for/from this schema. +// When you pass empty strings as params the external documents will be removed. +// When you pass non-empty string as one value then those values will be used on the external docs object. +// So when you pass a non-empty description, you should also pass the url and vice versa. +func (s *Schema) WithExternalDocs(description, url string) *Schema { + if description == "" && url == "" { + s.ExternalDocs = nil + return s + } + + if s.ExternalDocs == nil { + s.ExternalDocs = &ExternalDocumentation{} + } + s.ExternalDocs.Description = description + s.ExternalDocs.URL = url + return s +} + +// WithXMLName sets the xml name for the object +func (s *Schema) WithXMLName(name string) *Schema { + if s.XML == nil { + s.XML = new(XMLObject) + } + s.XML.Name = name + return s +} + +// WithXMLNamespace sets the xml namespace for the object +func (s *Schema) WithXMLNamespace(namespace string) *Schema { + if s.XML == nil { + s.XML = new(XMLObject) + } + s.XML.Namespace = namespace + return s +} + +// WithXMLPrefix sets the xml prefix for the object +func (s *Schema) WithXMLPrefix(prefix string) *Schema { + if s.XML == nil { + s.XML = new(XMLObject) + } + s.XML.Prefix = prefix + return s +} + +// AsXMLAttribute flags this object as xml attribute +func (s *Schema) AsXMLAttribute() *Schema { + if s.XML == nil { + s.XML = new(XMLObject) + } + s.XML.Attribute = true + return s +} + +// AsXMLElement flags this object as an xml node +func (s *Schema) AsXMLElement() *Schema { + if s.XML == nil { + s.XML = new(XMLObject) + } + s.XML.Attribute = false + return s +} + +// AsWrappedXML flags this object as wrapped, this is mostly useful for array types +func (s *Schema) AsWrappedXML() *Schema { + if s.XML == nil { + s.XML = new(XMLObject) + } + s.XML.Wrapped = true + return s +} + +// AsUnwrappedXML flags this object as an xml node +func (s *Schema) AsUnwrappedXML() *Schema { + if s.XML == nil { + s.XML = new(XMLObject) + } + s.XML.Wrapped = false + return s +} + +// MarshalJSON marshal this to JSON +func (s Schema) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(s.SchemaProps) + if err != nil { + return nil, fmt.Errorf("schema props %v", err) + } + b2, err := json.Marshal(s.VendorExtensible) + if err != nil { + return nil, fmt.Errorf("vendor props %v", err) + } + b3, err := s.Ref.MarshalJSON() + if err != nil { + return nil, fmt.Errorf("ref prop %v", err) + } + b4, err := s.Schema.MarshalJSON() + if err != nil { + return nil, fmt.Errorf("schema prop %v", err) + } + b5, err := json.Marshal(s.SwaggerSchemaProps) + if err != nil { + return nil, fmt.Errorf("common validations %v", err) + } + var b6 []byte + if s.ExtraProps != nil { + jj, err := json.Marshal(s.ExtraProps) + if err != nil { + return nil, fmt.Errorf("extra props %v", err) + } + b6 = jj + } + return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil +} + +// UnmarshalJSON marshal this from JSON +func (s *Schema) UnmarshalJSON(data []byte) error { + var sch Schema + if err := json.Unmarshal(data, &sch.SchemaProps); err != nil { + return err + } + if err := json.Unmarshal(data, &sch.Ref); err != nil { + return err + } + if err := json.Unmarshal(data, &sch.Schema); err != nil { + return err + } + if err := json.Unmarshal(data, &sch.SwaggerSchemaProps); err != nil { + return err + } + + var d map[string]interface{} + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + delete(d, "$ref") + delete(d, "$schema") + for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) { + delete(d, pn) + } + + for k, vv := range d { + lk := strings.ToLower(k) + if strings.HasPrefix(lk, "x-") { + if sch.Extensions == nil { + sch.Extensions = map[string]interface{}{} + } + sch.Extensions[k] = vv + continue + } + if sch.ExtraProps == nil { + sch.ExtraProps = map[string]interface{}{} + } + sch.ExtraProps[k] = vv + } + + *s = sch + + return nil +} diff --git a/vendor/github.com/go-openapi/spec/security_scheme.go b/vendor/github.com/go-openapi/spec/security_scheme.go new file mode 100644 index 000000000..22d4f10af --- /dev/null +++ b/vendor/github.com/go-openapi/spec/security_scheme.go @@ -0,0 +1,142 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +const ( + basic = "basic" + apiKey = "apiKey" + oauth2 = "oauth2" + implicit = "implicit" + password = "password" + application = "application" + accessCode = "accessCode" +) + +// BasicAuth creates a basic auth security scheme +func BasicAuth() *SecurityScheme { + return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: basic}} +} + +// APIKeyAuth creates an api key auth security scheme +func APIKeyAuth(fieldName, valueSource string) *SecurityScheme { + return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: apiKey, Name: fieldName, In: valueSource}} +} + +// OAuth2Implicit creates an implicit flow oauth2 security scheme +func OAuth2Implicit(authorizationURL string) *SecurityScheme { + return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ + Type: oauth2, + Flow: implicit, + AuthorizationURL: authorizationURL, + }} +} + +// OAuth2Password creates a password flow oauth2 security scheme +func OAuth2Password(tokenURL string) *SecurityScheme { + return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ + Type: oauth2, + Flow: password, + TokenURL: tokenURL, + }} +} + +// OAuth2Application creates an application flow oauth2 security scheme +func OAuth2Application(tokenURL string) *SecurityScheme { + return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ + Type: oauth2, + Flow: application, + TokenURL: tokenURL, + }} +} + +// OAuth2AccessToken creates an access token flow oauth2 security scheme +func OAuth2AccessToken(authorizationURL, tokenURL string) *SecurityScheme { + return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ + Type: oauth2, + Flow: accessCode, + AuthorizationURL: authorizationURL, + TokenURL: tokenURL, + }} +} + +type SecuritySchemeProps struct { + Description string `json:"description,omitempty"` + Type string `json:"type"` + Name string `json:"name,omitempty"` // api key + In string `json:"in,omitempty"` // api key + Flow string `json:"flow,omitempty"` // oauth2 + AuthorizationURL string `json:"authorizationUrl,omitempty"` // oauth2 + TokenURL string `json:"tokenUrl,omitempty"` // oauth2 + Scopes map[string]string `json:"scopes,omitempty"` // oauth2 +} + +// AddScope adds a scope to this security scheme +func (s *SecuritySchemeProps) AddScope(scope, description string) { + if s.Scopes == nil { + s.Scopes = make(map[string]string) + } + s.Scopes[scope] = description +} + +// SecurityScheme allows the definition of a security scheme that can be used by the operations. +// Supported schemes are basic authentication, an API key (either as a header or as a query parameter) +// and OAuth2's common flows (implicit, password, application and access code). +// +// For more information: http://goo.gl/8us55a#securitySchemeObject +type SecurityScheme struct { + VendorExtensible + SecuritySchemeProps +} + +// JSONLookup implements an interface to customize json pointer lookup +func (s SecurityScheme) JSONLookup(token string) (interface{}, error) { + if ex, ok := s.Extensions[token]; ok { + return &ex, nil + } + + r, _, err := jsonpointer.GetForToken(s.SecuritySchemeProps, token) + return r, err +} + +// MarshalJSON marshal this to JSON +func (s SecurityScheme) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(s.SecuritySchemeProps) + if err != nil { + return nil, err + } + b2, err := json.Marshal(s.VendorExtensible) + if err != nil { + return nil, err + } + return swag.ConcatJSON(b1, b2), nil +} + +// UnmarshalJSON marshal this from JSON +func (s *SecurityScheme) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil { + return err + } + if err := json.Unmarshal(data, &s.VendorExtensible); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/go-openapi/spec/spec.go b/vendor/github.com/go-openapi/spec/spec.go new file mode 100644 index 000000000..0bb045bc0 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/spec.go @@ -0,0 +1,86 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import "encoding/json" + +//go:generate curl -L --progress -o ./schemas/v2/schema.json http://swagger.io/v2/schema.json +//go:generate curl -L --progress -o ./schemas/jsonschema-draft-04.json http://json-schema.org/draft-04/schema +//go:generate go-bindata -pkg=spec -prefix=./schemas -ignore=.*\.md ./schemas/... +//go:generate perl -pi -e s,Json,JSON,g bindata.go + +const ( + // SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs + SwaggerSchemaURL = "http://swagger.io/v2/schema.json#" + // JSONSchemaURL the url for the json schema schema + JSONSchemaURL = "http://json-schema.org/draft-04/schema#" +) + +var ( + jsonSchema *Schema + swaggerSchema *Schema +) + +func init() { + jsonSchema = MustLoadJSONSchemaDraft04() + swaggerSchema = MustLoadSwagger20Schema() +} + +// MustLoadJSONSchemaDraft04 panics when Swagger20Schema returns an error +func MustLoadJSONSchemaDraft04() *Schema { + d, e := JSONSchemaDraft04() + if e != nil { + panic(e) + } + return d +} + +// JSONSchemaDraft04 loads the json schema document for json shema draft04 +func JSONSchemaDraft04() (*Schema, error) { + b, err := Asset("jsonschema-draft-04.json") + if err != nil { + return nil, err + } + + schema := new(Schema) + if err := json.Unmarshal(b, schema); err != nil { + return nil, err + } + return schema, nil +} + +// MustLoadSwagger20Schema panics when Swagger20Schema returns an error +func MustLoadSwagger20Schema() *Schema { + d, e := Swagger20Schema() + if e != nil { + panic(e) + } + return d +} + +// Swagger20Schema loads the swagger 2.0 schema from the embedded assets +func Swagger20Schema() (*Schema, error) { + + b, err := Asset("v2/schema.json") + if err != nil { + return nil, err + } + + schema := new(Schema) + if err := json.Unmarshal(b, schema); err != nil { + return nil, err + } + return schema, nil +} diff --git a/vendor/github.com/go-openapi/spec/swagger.go b/vendor/github.com/go-openapi/spec/swagger.go new file mode 100644 index 000000000..23780c78a --- /dev/null +++ b/vendor/github.com/go-openapi/spec/swagger.go @@ -0,0 +1,317 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "fmt" + "strconv" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +// Swagger this is the root document object for the API specification. +// It combines what previously was the Resource Listing and API Declaration (version 1.2 and earlier) together into one document. +// +// For more information: http://goo.gl/8us55a#swagger-object- +type Swagger struct { + VendorExtensible + SwaggerProps +} + +// JSONLookup look up a value by the json property name +func (s Swagger) JSONLookup(token string) (interface{}, error) { + if ex, ok := s.Extensions[token]; ok { + return &ex, nil + } + r, _, err := jsonpointer.GetForToken(s.SwaggerProps, token) + return r, err +} + +// MarshalJSON marshals this swagger structure to json +func (s Swagger) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(s.SwaggerProps) + if err != nil { + return nil, err + } + b2, err := json.Marshal(s.VendorExtensible) + if err != nil { + return nil, err + } + return swag.ConcatJSON(b1, b2), nil +} + +// UnmarshalJSON unmarshals a swagger spec from json +func (s *Swagger) UnmarshalJSON(data []byte) error { + var sw Swagger + if err := json.Unmarshal(data, &sw.SwaggerProps); err != nil { + return err + } + if err := json.Unmarshal(data, &sw.VendorExtensible); err != nil { + return err + } + *s = sw + return nil +} + +type SwaggerProps struct { + ID string `json:"id,omitempty"` + Consumes []string `json:"consumes,omitempty"` + Produces []string `json:"produces,omitempty"` + Schemes []string `json:"schemes,omitempty"` // the scheme, when present must be from [http, https, ws, wss] + Swagger string `json:"swagger,omitempty"` + Info *Info `json:"info,omitempty"` + Host string `json:"host,omitempty"` + BasePath string `json:"basePath,omitempty"` // must start with a leading "/" + Paths *Paths `json:"paths"` // required + Definitions Definitions `json:"definitions,omitempty"` + Parameters map[string]Parameter `json:"parameters,omitempty"` + Responses map[string]Response `json:"responses,omitempty"` + SecurityDefinitions SecurityDefinitions `json:"securityDefinitions,omitempty"` + Security []map[string][]string `json:"security,omitempty"` + Tags []Tag `json:"tags,omitempty"` + ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` +} + +// Dependencies represent a dependencies property +type Dependencies map[string]SchemaOrStringArray + +// SchemaOrBool represents a schema or boolean value, is biased towards true for the boolean property +type SchemaOrBool struct { + Allows bool + Schema *Schema +} + +// JSONLookup implements an interface to customize json pointer lookup +func (s SchemaOrBool) JSONLookup(token string) (interface{}, error) { + if token == "allows" { + return s.Allows, nil + } + r, _, err := jsonpointer.GetForToken(s.Schema, token) + return r, err +} + +var jsTrue = []byte("true") +var jsFalse = []byte("false") + +// MarshalJSON convert this object to JSON +func (s SchemaOrBool) MarshalJSON() ([]byte, error) { + if s.Schema != nil { + return json.Marshal(s.Schema) + } + + if s.Schema == nil && !s.Allows { + return jsFalse, nil + } + return jsTrue, nil +} + +// UnmarshalJSON converts this bool or schema object from a JSON structure +func (s *SchemaOrBool) UnmarshalJSON(data []byte) error { + var nw SchemaOrBool + if len(data) >= 4 { + if data[0] == '{' { + var sch Schema + if err := json.Unmarshal(data, &sch); err != nil { + return err + } + nw.Schema = &sch + } + nw.Allows = !(data[0] == 'f' && data[1] == 'a' && data[2] == 'l' && data[3] == 's' && data[4] == 'e') + } + *s = nw + return nil +} + +// SchemaOrStringArray represents a schema or a string array +type SchemaOrStringArray struct { + Schema *Schema + Property []string +} + +// JSONLookup implements an interface to customize json pointer lookup +func (s SchemaOrStringArray) JSONLookup(token string) (interface{}, error) { + r, _, err := jsonpointer.GetForToken(s.Schema, token) + return r, err +} + +// MarshalJSON converts this schema object or array into JSON structure +func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) { + if len(s.Property) > 0 { + return json.Marshal(s.Property) + } + if s.Schema != nil { + return json.Marshal(s.Schema) + } + return []byte("null"), nil +} + +// UnmarshalJSON converts this schema object or array from a JSON structure +func (s *SchemaOrStringArray) UnmarshalJSON(data []byte) error { + var first byte + if len(data) > 1 { + first = data[0] + } + var nw SchemaOrStringArray + if first == '{' { + var sch Schema + if err := json.Unmarshal(data, &sch); err != nil { + return err + } + nw.Schema = &sch + } + if first == '[' { + if err := json.Unmarshal(data, &nw.Property); err != nil { + return err + } + } + *s = nw + return nil +} + +// Definitions contains the models explicitly defined in this spec +// An object to hold data types that can be consumed and produced by operations. +// These data types can be primitives, arrays or models. +// +// For more information: http://goo.gl/8us55a#definitionsObject +type Definitions map[string]Schema + +// SecurityDefinitions a declaration of the security schemes available to be used in the specification. +// This does not enforce the security schemes on the operations and only serves to provide +// the relevant details for each scheme. +// +// For more information: http://goo.gl/8us55a#securityDefinitionsObject +type SecurityDefinitions map[string]*SecurityScheme + +// StringOrArray represents a value that can either be a string +// or an array of strings. Mainly here for serialization purposes +type StringOrArray []string + +// Contains returns true when the value is contained in the slice +func (s StringOrArray) Contains(value string) bool { + for _, str := range s { + if str == value { + return true + } + } + return false +} + +// JSONLookup implements an interface to customize json pointer lookup +func (s SchemaOrArray) JSONLookup(token string) (interface{}, error) { + if _, err := strconv.Atoi(token); err == nil { + r, _, err := jsonpointer.GetForToken(s.Schemas, token) + return r, err + } + r, _, err := jsonpointer.GetForToken(s.Schema, token) + return r, err +} + +// UnmarshalJSON unmarshals this string or array object from a JSON array or JSON string +func (s *StringOrArray) UnmarshalJSON(data []byte) error { + var first byte + if len(data) > 1 { + first = data[0] + } + + if first == '[' { + var parsed []string + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *s = StringOrArray(parsed) + return nil + } + + var single interface{} + if err := json.Unmarshal(data, &single); err != nil { + return err + } + if single == nil { + return nil + } + switch single.(type) { + case string: + *s = StringOrArray([]string{single.(string)}) + return nil + default: + return fmt.Errorf("only string or array is allowed, not %T", single) + } +} + +// MarshalJSON converts this string or array to a JSON array or JSON string +func (s StringOrArray) MarshalJSON() ([]byte, error) { + if len(s) == 1 { + return json.Marshal([]string(s)[0]) + } + return json.Marshal([]string(s)) +} + +// SchemaOrArray represents a value that can either be a Schema +// or an array of Schema. Mainly here for serialization purposes +type SchemaOrArray struct { + Schema *Schema + Schemas []Schema +} + +// Len returns the number of schemas in this property +func (s SchemaOrArray) Len() int { + if s.Schema != nil { + return 1 + } + return len(s.Schemas) +} + +// ContainsType returns true when one of the schemas is of the specified type +func (s *SchemaOrArray) ContainsType(name string) bool { + if s.Schema != nil { + return s.Schema.Type != nil && s.Schema.Type.Contains(name) + } + return false +} + +// MarshalJSON converts this schema object or array into JSON structure +func (s SchemaOrArray) MarshalJSON() ([]byte, error) { + if len(s.Schemas) > 0 { + return json.Marshal(s.Schemas) + } + return json.Marshal(s.Schema) +} + +// UnmarshalJSON converts this schema object or array from a JSON structure +func (s *SchemaOrArray) UnmarshalJSON(data []byte) error { + var nw SchemaOrArray + var first byte + if len(data) > 1 { + first = data[0] + } + if first == '{' { + var sch Schema + if err := json.Unmarshal(data, &sch); err != nil { + return err + } + nw.Schema = &sch + } + if first == '[' { + if err := json.Unmarshal(data, &nw.Schemas); err != nil { + return err + } + } + *s = nw + return nil +} + +// vim:set ft=go noet sts=2 sw=2 ts=2: diff --git a/vendor/github.com/go-openapi/spec/tag.go b/vendor/github.com/go-openapi/spec/tag.go new file mode 100644 index 000000000..97f555840 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/tag.go @@ -0,0 +1,73 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" +) + +type TagProps struct { + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` +} + +// NewTag creates a new tag +func NewTag(name, description string, externalDocs *ExternalDocumentation) Tag { + return Tag{TagProps: TagProps{description, name, externalDocs}} +} + +// Tag allows adding meta data to a single tag that is used by the [Operation Object](http://goo.gl/8us55a#operationObject). +// It is not mandatory to have a Tag Object per tag used there. +// +// For more information: http://goo.gl/8us55a#tagObject +type Tag struct { + VendorExtensible + TagProps +} + +// JSONLookup implements an interface to customize json pointer lookup +func (t Tag) JSONLookup(token string) (interface{}, error) { + if ex, ok := t.Extensions[token]; ok { + return &ex, nil + } + + r, _, err := jsonpointer.GetForToken(t.TagProps, token) + return r, err +} + +// MarshalJSON marshal this to JSON +func (t Tag) MarshalJSON() ([]byte, error) { + b1, err := json.Marshal(t.TagProps) + if err != nil { + return nil, err + } + b2, err := json.Marshal(t.VendorExtensible) + if err != nil { + return nil, err + } + return swag.ConcatJSON(b1, b2), nil +} + +// UnmarshalJSON marshal this from JSON +func (t *Tag) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &t.TagProps); err != nil { + return err + } + return json.Unmarshal(data, &t.VendorExtensible) +} diff --git a/vendor/github.com/go-openapi/spec/xml_object.go b/vendor/github.com/go-openapi/spec/xml_object.go new file mode 100644 index 000000000..945a46703 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/xml_object.go @@ -0,0 +1,68 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +// XMLObject a metadata object that allows for more fine-tuned XML model definitions. +// +// For more information: http://goo.gl/8us55a#xmlObject +type XMLObject struct { + Name string `json:"name,omitempty"` + Namespace string `json:"namespace,omitempty"` + Prefix string `json:"prefix,omitempty"` + Attribute bool `json:"attribute,omitempty"` + Wrapped bool `json:"wrapped,omitempty"` +} + +// WithName sets the xml name for the object +func (x *XMLObject) WithName(name string) *XMLObject { + x.Name = name + return x +} + +// WithNamespace sets the xml namespace for the object +func (x *XMLObject) WithNamespace(namespace string) *XMLObject { + x.Namespace = namespace + return x +} + +// WithPrefix sets the xml prefix for the object +func (x *XMLObject) WithPrefix(prefix string) *XMLObject { + x.Prefix = prefix + return x +} + +// AsAttribute flags this object as xml attribute +func (x *XMLObject) AsAttribute() *XMLObject { + x.Attribute = true + return x +} + +// AsElement flags this object as an xml node +func (x *XMLObject) AsElement() *XMLObject { + x.Attribute = false + return x +} + +// AsWrapped flags this object as wrapped, this is mostly useful for array types +func (x *XMLObject) AsWrapped() *XMLObject { + x.Wrapped = true + return x +} + +// AsUnwrapped flags this object as an xml node +func (x *XMLObject) AsUnwrapped() *XMLObject { + x.Wrapped = false + return x +} diff --git a/vendor/github.com/go-openapi/swag/.editorconfig b/vendor/github.com/go-openapi/swag/.editorconfig new file mode 100644 index 000000000..3152da69a --- /dev/null +++ b/vendor/github.com/go-openapi/swag/.editorconfig @@ -0,0 +1,26 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +# Set default charset +[*.{js,py,go,scala,rb,java,html,css,less,sass,md}] +charset = utf-8 + +# Tab indentation (no size specified) +[*.go] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/vendor/github.com/go-openapi/swag/.gitignore b/vendor/github.com/go-openapi/swag/.gitignore new file mode 100644 index 000000000..769c24400 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/.gitignore @@ -0,0 +1 @@ +secrets.yml diff --git a/vendor/github.com/go-openapi/swag/.travis.yml b/vendor/github.com/go-openapi/swag/.travis.yml new file mode 100644 index 000000000..24c69bdf3 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/.travis.yml @@ -0,0 +1,14 @@ +language: go +go: +- 1.8 +install: +- go get -u github.com/stretchr/testify +- go get -u github.com/mailru/easyjson +- go get -u gopkg.in/yaml.v2 +script: +- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./... +after_success: +- bash <(curl -s https://codecov.io/bash) +notifications: + slack: + secure: QUWvCkBBK09GF7YtEvHHVt70JOkdlNBG0nIKu/5qc4/nW5HP8I2w0SEf/XR2je0eED1Qe3L/AfMCWwrEj+IUZc3l4v+ju8X8R3Lomhme0Eb0jd1MTMCuPcBT47YCj0M7RON7vXtbFfm1hFJ/jLe5+9FXz0hpXsR24PJc5ZIi/ogNwkaPqG4BmndzecpSh0vc2FJPZUD9LT0I09REY/vXR0oQAalLkW0asGD5taHZTUZq/kBpsNxaAFrLM23i4mUcf33M5fjLpvx5LRICrX/57XpBrDh2TooBU6Qj3CgoY0uPRYUmSNxbVx1czNzl2JtEpb5yjoxfVPQeg0BvQM00G8LJINISR+ohrjhkZmAqchDupAX+yFrxTtORa78CtnIL6z/aTNlgwwVD8kvL/1pFA/JWYmKDmz93mV/+6wubGzNSQCstzjkFA4/iZEKewKUoRIAi/fxyscP6L/rCpmY/4llZZvrnyTqVbt6URWpopUpH4rwYqreXAtJxJsfBJIeSmUIiDIOMGkCTvyTEW3fWGmGoqWtSHLoaWDyAIGb7azb+KvfpWtEcoPFWfSWU+LGee0A/YsUhBl7ADB9A0CJEuR8q4BPpKpfLwPKSiKSAXL7zDkyjExyhtgqbSl2jS+rKIHOZNL8JkCcTP2MKMVd563C5rC5FMKqu3S9m2b6380E= diff --git a/vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/swag/LICENSE b/vendor/github.com/go-openapi/swag/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/go-openapi/swag/README.md b/vendor/github.com/go-openapi/swag/README.md new file mode 100644 index 000000000..5d43728e8 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/README.md @@ -0,0 +1,12 @@ +# Swag [![Build Status](https://travis-ci.org/go-openapi/swag.svg?branch=master)](https://travis-ci.org/go-openapi/swag) [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/swag?status.svg)](http://godoc.org/github.com/go-openapi/swag) + +Contains a bunch of helper functions: + +* convert between value and pointers for builtins +* convert from string to builtin +* fast json concatenation +* search in path +* load from file or http +* name manglin \ No newline at end of file diff --git a/vendor/github.com/go-openapi/swag/convert.go b/vendor/github.com/go-openapi/swag/convert.go new file mode 100644 index 000000000..2bf5ecbba --- /dev/null +++ b/vendor/github.com/go-openapi/swag/convert.go @@ -0,0 +1,188 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "math" + "strconv" + "strings" +) + +// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER +const ( + maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1 + minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1 +) + +// IsFloat64AJSONInteger allow for integers [-2^53, 2^53-1] inclusive +func IsFloat64AJSONInteger(f float64) bool { + if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat { + return false + } + + return f == float64(int64(f)) || f == float64(uint64(f)) +} + +var evaluatesAsTrue = map[string]struct{}{ + "true": struct{}{}, + "1": struct{}{}, + "yes": struct{}{}, + "ok": struct{}{}, + "y": struct{}{}, + "on": struct{}{}, + "selected": struct{}{}, + "checked": struct{}{}, + "t": struct{}{}, + "enabled": struct{}{}, +} + +// ConvertBool turn a string into a boolean +func ConvertBool(str string) (bool, error) { + _, ok := evaluatesAsTrue[strings.ToLower(str)] + return ok, nil +} + +// ConvertFloat32 turn a string into a float32 +func ConvertFloat32(str string) (float32, error) { + f, err := strconv.ParseFloat(str, 32) + if err != nil { + return 0, err + } + return float32(f), nil +} + +// ConvertFloat64 turn a string into a float64 +func ConvertFloat64(str string) (float64, error) { + return strconv.ParseFloat(str, 64) +} + +// ConvertInt8 turn a string into int8 boolean +func ConvertInt8(str string) (int8, error) { + i, err := strconv.ParseInt(str, 10, 8) + if err != nil { + return 0, err + } + return int8(i), nil +} + +// ConvertInt16 turn a string into a int16 +func ConvertInt16(str string) (int16, error) { + i, err := strconv.ParseInt(str, 10, 16) + if err != nil { + return 0, err + } + return int16(i), nil +} + +// ConvertInt32 turn a string into a int32 +func ConvertInt32(str string) (int32, error) { + i, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return 0, err + } + return int32(i), nil +} + +// ConvertInt64 turn a string into a int64 +func ConvertInt64(str string) (int64, error) { + return strconv.ParseInt(str, 10, 64) +} + +// ConvertUint8 turn a string into a uint8 +func ConvertUint8(str string) (uint8, error) { + i, err := strconv.ParseUint(str, 10, 8) + if err != nil { + return 0, err + } + return uint8(i), nil +} + +// ConvertUint16 turn a string into a uint16 +func ConvertUint16(str string) (uint16, error) { + i, err := strconv.ParseUint(str, 10, 16) + if err != nil { + return 0, err + } + return uint16(i), nil +} + +// ConvertUint32 turn a string into a uint32 +func ConvertUint32(str string) (uint32, error) { + i, err := strconv.ParseUint(str, 10, 32) + if err != nil { + return 0, err + } + return uint32(i), nil +} + +// ConvertUint64 turn a string into a uint64 +func ConvertUint64(str string) (uint64, error) { + return strconv.ParseUint(str, 10, 64) +} + +// FormatBool turns a boolean into a string +func FormatBool(value bool) string { + return strconv.FormatBool(value) +} + +// FormatFloat32 turns a float32 into a string +func FormatFloat32(value float32) string { + return strconv.FormatFloat(float64(value), 'f', -1, 32) +} + +// FormatFloat64 turns a float64 into a string +func FormatFloat64(value float64) string { + return strconv.FormatFloat(value, 'f', -1, 64) +} + +// FormatInt8 turns an int8 into a string +func FormatInt8(value int8) string { + return strconv.FormatInt(int64(value), 10) +} + +// FormatInt16 turns an int16 into a string +func FormatInt16(value int16) string { + return strconv.FormatInt(int64(value), 10) +} + +// FormatInt32 turns an int32 into a string +func FormatInt32(value int32) string { + return strconv.Itoa(int(value)) +} + +// FormatInt64 turns an int64 into a string +func FormatInt64(value int64) string { + return strconv.FormatInt(value, 10) +} + +// FormatUint8 turns an uint8 into a string +func FormatUint8(value uint8) string { + return strconv.FormatUint(uint64(value), 10) +} + +// FormatUint16 turns an uint16 into a string +func FormatUint16(value uint16) string { + return strconv.FormatUint(uint64(value), 10) +} + +// FormatUint32 turns an uint32 into a string +func FormatUint32(value uint32) string { + return strconv.FormatUint(uint64(value), 10) +} + +// FormatUint64 turns an uint64 into a string +func FormatUint64(value uint64) string { + return strconv.FormatUint(value, 10) +} diff --git a/vendor/github.com/go-openapi/swag/convert_types.go b/vendor/github.com/go-openapi/swag/convert_types.go new file mode 100644 index 000000000..c95e4e78b --- /dev/null +++ b/vendor/github.com/go-openapi/swag/convert_types.go @@ -0,0 +1,595 @@ +package swag + +import "time" + +// This file was taken from the aws go sdk + +// String returns a pointer to of the string value passed in. +func String(v string) *string { + return &v +} + +// StringValue returns the value of the string pointer passed in or +// "" if the pointer is nil. +func StringValue(v *string) string { + if v != nil { + return *v + } + return "" +} + +// StringSlice converts a slice of string values into a slice of +// string pointers +func StringSlice(src []string) []*string { + dst := make([]*string, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// StringValueSlice converts a slice of string pointers into a slice of +// string values +func StringValueSlice(src []*string) []string { + dst := make([]string, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// StringMap converts a string map of string values into a string +// map of string pointers +func StringMap(src map[string]string) map[string]*string { + dst := make(map[string]*string) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// StringValueMap converts a string map of string pointers into a string +// map of string values +func StringValueMap(src map[string]*string) map[string]string { + dst := make(map[string]string) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} + +// Bool returns a pointer to of the bool value passed in. +func Bool(v bool) *bool { + return &v +} + +// BoolValue returns the value of the bool pointer passed in or +// false if the pointer is nil. +func BoolValue(v *bool) bool { + if v != nil { + return *v + } + return false +} + +// BoolSlice converts a slice of bool values into a slice of +// bool pointers +func BoolSlice(src []bool) []*bool { + dst := make([]*bool, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// BoolValueSlice converts a slice of bool pointers into a slice of +// bool values +func BoolValueSlice(src []*bool) []bool { + dst := make([]bool, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// BoolMap converts a string map of bool values into a string +// map of bool pointers +func BoolMap(src map[string]bool) map[string]*bool { + dst := make(map[string]*bool) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// BoolValueMap converts a string map of bool pointers into a string +// map of bool values +func BoolValueMap(src map[string]*bool) map[string]bool { + dst := make(map[string]bool) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} + +// Int returns a pointer to of the int value passed in. +func Int(v int) *int { + return &v +} + +// IntValue returns the value of the int pointer passed in or +// 0 if the pointer is nil. +func IntValue(v *int) int { + if v != nil { + return *v + } + return 0 +} + +// IntSlice converts a slice of int values into a slice of +// int pointers +func IntSlice(src []int) []*int { + dst := make([]*int, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// IntValueSlice converts a slice of int pointers into a slice of +// int values +func IntValueSlice(src []*int) []int { + dst := make([]int, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// IntMap converts a string map of int values into a string +// map of int pointers +func IntMap(src map[string]int) map[string]*int { + dst := make(map[string]*int) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// IntValueMap converts a string map of int pointers into a string +// map of int values +func IntValueMap(src map[string]*int) map[string]int { + dst := make(map[string]int) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} + +// Int32 returns a pointer to of the int64 value passed in. +func Int32(v int32) *int32 { + return &v +} + +// Int32Value returns the value of the int64 pointer passed in or +// 0 if the pointer is nil. +func Int32Value(v *int32) int32 { + if v != nil { + return *v + } + return 0 +} + +// Int32Slice converts a slice of int64 values into a slice of +// int32 pointers +func Int32Slice(src []int32) []*int32 { + dst := make([]*int32, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// Int32ValueSlice converts a slice of int32 pointers into a slice of +// int32 values +func Int32ValueSlice(src []*int32) []int32 { + dst := make([]int32, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// Int32Map converts a string map of int32 values into a string +// map of int32 pointers +func Int32Map(src map[string]int32) map[string]*int32 { + dst := make(map[string]*int32) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// Int32ValueMap converts a string map of int32 pointers into a string +// map of int32 values +func Int32ValueMap(src map[string]*int32) map[string]int32 { + dst := make(map[string]int32) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} + +// Int64 returns a pointer to of the int64 value passed in. +func Int64(v int64) *int64 { + return &v +} + +// Int64Value returns the value of the int64 pointer passed in or +// 0 if the pointer is nil. +func Int64Value(v *int64) int64 { + if v != nil { + return *v + } + return 0 +} + +// Int64Slice converts a slice of int64 values into a slice of +// int64 pointers +func Int64Slice(src []int64) []*int64 { + dst := make([]*int64, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// Int64ValueSlice converts a slice of int64 pointers into a slice of +// int64 values +func Int64ValueSlice(src []*int64) []int64 { + dst := make([]int64, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// Int64Map converts a string map of int64 values into a string +// map of int64 pointers +func Int64Map(src map[string]int64) map[string]*int64 { + dst := make(map[string]*int64) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// Int64ValueMap converts a string map of int64 pointers into a string +// map of int64 values +func Int64ValueMap(src map[string]*int64) map[string]int64 { + dst := make(map[string]int64) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} + +// Uint returns a pouinter to of the uint value passed in. +func Uint(v uint) *uint { + return &v +} + +// UintValue returns the value of the uint pouinter passed in or +// 0 if the pouinter is nil. +func UintValue(v *uint) uint { + if v != nil { + return *v + } + return 0 +} + +// UintSlice converts a slice of uint values uinto a slice of +// uint pouinters +func UintSlice(src []uint) []*uint { + dst := make([]*uint, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// UintValueSlice converts a slice of uint pouinters uinto a slice of +// uint values +func UintValueSlice(src []*uint) []uint { + dst := make([]uint, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// UintMap converts a string map of uint values uinto a string +// map of uint pouinters +func UintMap(src map[string]uint) map[string]*uint { + dst := make(map[string]*uint) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// UintValueMap converts a string map of uint pouinters uinto a string +// map of uint values +func UintValueMap(src map[string]*uint) map[string]uint { + dst := make(map[string]uint) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} + +// Uint32 returns a pouinter to of the uint64 value passed in. +func Uint32(v uint32) *uint32 { + return &v +} + +// Uint32Value returns the value of the uint64 pouinter passed in or +// 0 if the pouinter is nil. +func Uint32Value(v *uint32) uint32 { + if v != nil { + return *v + } + return 0 +} + +// Uint32Slice converts a slice of uint64 values uinto a slice of +// uint32 pouinters +func Uint32Slice(src []uint32) []*uint32 { + dst := make([]*uint32, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// Uint32ValueSlice converts a slice of uint32 pouinters uinto a slice of +// uint32 values +func Uint32ValueSlice(src []*uint32) []uint32 { + dst := make([]uint32, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// Uint32Map converts a string map of uint32 values uinto a string +// map of uint32 pouinters +func Uint32Map(src map[string]uint32) map[string]*uint32 { + dst := make(map[string]*uint32) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// Uint32ValueMap converts a string map of uint32 pouinters uinto a string +// map of uint32 values +func Uint32ValueMap(src map[string]*uint32) map[string]uint32 { + dst := make(map[string]uint32) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} + +// Uint64 returns a pouinter to of the uint64 value passed in. +func Uint64(v uint64) *uint64 { + return &v +} + +// Uint64Value returns the value of the uint64 pouinter passed in or +// 0 if the pouinter is nil. +func Uint64Value(v *uint64) uint64 { + if v != nil { + return *v + } + return 0 +} + +// Uint64Slice converts a slice of uint64 values uinto a slice of +// uint64 pouinters +func Uint64Slice(src []uint64) []*uint64 { + dst := make([]*uint64, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// Uint64ValueSlice converts a slice of uint64 pouinters uinto a slice of +// uint64 values +func Uint64ValueSlice(src []*uint64) []uint64 { + dst := make([]uint64, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// Uint64Map converts a string map of uint64 values uinto a string +// map of uint64 pouinters +func Uint64Map(src map[string]uint64) map[string]*uint64 { + dst := make(map[string]*uint64) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// Uint64ValueMap converts a string map of uint64 pouinters uinto a string +// map of uint64 values +func Uint64ValueMap(src map[string]*uint64) map[string]uint64 { + dst := make(map[string]uint64) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} + +// Float64 returns a pointer to of the float64 value passed in. +func Float64(v float64) *float64 { + return &v +} + +// Float64Value returns the value of the float64 pointer passed in or +// 0 if the pointer is nil. +func Float64Value(v *float64) float64 { + if v != nil { + return *v + } + return 0 +} + +// Float64Slice converts a slice of float64 values into a slice of +// float64 pointers +func Float64Slice(src []float64) []*float64 { + dst := make([]*float64, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// Float64ValueSlice converts a slice of float64 pointers into a slice of +// float64 values +func Float64ValueSlice(src []*float64) []float64 { + dst := make([]float64, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// Float64Map converts a string map of float64 values into a string +// map of float64 pointers +func Float64Map(src map[string]float64) map[string]*float64 { + dst := make(map[string]*float64) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// Float64ValueMap converts a string map of float64 pointers into a string +// map of float64 values +func Float64ValueMap(src map[string]*float64) map[string]float64 { + dst := make(map[string]float64) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} + +// Time returns a pointer to of the time.Time value passed in. +func Time(v time.Time) *time.Time { + return &v +} + +// TimeValue returns the value of the time.Time pointer passed in or +// time.Time{} if the pointer is nil. +func TimeValue(v *time.Time) time.Time { + if v != nil { + return *v + } + return time.Time{} +} + +// TimeSlice converts a slice of time.Time values into a slice of +// time.Time pointers +func TimeSlice(src []time.Time) []*time.Time { + dst := make([]*time.Time, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// TimeValueSlice converts a slice of time.Time pointers into a slice of +// time.Time values +func TimeValueSlice(src []*time.Time) []time.Time { + dst := make([]time.Time, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// TimeMap converts a string map of time.Time values into a string +// map of time.Time pointers +func TimeMap(src map[string]time.Time) map[string]*time.Time { + dst := make(map[string]*time.Time) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// TimeValueMap converts a string map of time.Time pointers into a string +// map of time.Time values +func TimeValueMap(src map[string]*time.Time) map[string]time.Time { + dst := make(map[string]time.Time) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} diff --git a/vendor/github.com/go-openapi/swag/json.go b/vendor/github.com/go-openapi/swag/json.go new file mode 100644 index 000000000..cb20a6a0f --- /dev/null +++ b/vendor/github.com/go-openapi/swag/json.go @@ -0,0 +1,295 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "bytes" + "encoding/json" + "log" + "reflect" + "strings" + "sync" + + "github.com/mailru/easyjson/jlexer" + "github.com/mailru/easyjson/jwriter" +) + +// DefaultJSONNameProvider the default cache for types +var DefaultJSONNameProvider = NewNameProvider() + +const comma = byte(',') + +var closers = map[byte]byte{ + '{': '}', + '[': ']', +} + +type ejMarshaler interface { + MarshalEasyJSON(w *jwriter.Writer) +} + +type ejUnmarshaler interface { + UnmarshalEasyJSON(w *jlexer.Lexer) +} + +// WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaller +// so it takes the fastest option available. +func WriteJSON(data interface{}) ([]byte, error) { + if d, ok := data.(ejMarshaler); ok { + jw := new(jwriter.Writer) + d.MarshalEasyJSON(jw) + return jw.BuildBytes() + } + if d, ok := data.(json.Marshaler); ok { + return d.MarshalJSON() + } + return json.Marshal(data) +} + +// ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaller +// so it takes the fastes option available +func ReadJSON(data []byte, value interface{}) error { + if d, ok := value.(ejUnmarshaler); ok { + jl := &jlexer.Lexer{Data: data} + d.UnmarshalEasyJSON(jl) + return jl.Error() + } + if d, ok := value.(json.Unmarshaler); ok { + return d.UnmarshalJSON(data) + } + return json.Unmarshal(data, value) +} + +// DynamicJSONToStruct converts an untyped json structure into a struct +func DynamicJSONToStruct(data interface{}, target interface{}) error { + // TODO: convert straight to a json typed map (mergo + iterate?) + b, err := WriteJSON(data) + if err != nil { + return err + } + if err := ReadJSON(b, target); err != nil { + return err + } + return nil +} + +// ConcatJSON concatenates multiple json objects efficiently +func ConcatJSON(blobs ...[]byte) []byte { + if len(blobs) == 0 { + return nil + } + if len(blobs) == 1 { + return blobs[0] + } + + last := len(blobs) - 1 + var opening, closing byte + a := 0 + idx := 0 + buf := bytes.NewBuffer(nil) + + for i, b := range blobs { + if len(b) > 0 && opening == 0 { // is this an array or an object? + opening, closing = b[0], closers[b[0]] + } + + if opening != '{' && opening != '[' { + continue // don't know how to concatenate non container objects + } + + if len(b) < 3 { // yep empty but also the last one, so closing this thing + if i == last && a > 0 { + if err := buf.WriteByte(closing); err != nil { + log.Println(err) + } + } + continue + } + + idx = 0 + if a > 0 { // we need to join with a comma for everything beyond the first non-empty item + if err := buf.WriteByte(comma); err != nil { + log.Println(err) + } + idx = 1 // this is not the first or the last so we want to drop the leading bracket + } + + if i != last { // not the last one, strip brackets + if _, err := buf.Write(b[idx : len(b)-1]); err != nil { + log.Println(err) + } + } else { // last one, strip only the leading bracket + if _, err := buf.Write(b[idx:]); err != nil { + log.Println(err) + } + } + a++ + } + // somehow it ended up being empty, so provide a default value + if buf.Len() == 0 { + if err := buf.WriteByte(opening); err != nil { + log.Println(err) + } + if err := buf.WriteByte(closing); err != nil { + log.Println(err) + } + } + return buf.Bytes() +} + +// ToDynamicJSON turns an object into a properly JSON typed structure +func ToDynamicJSON(data interface{}) interface{} { + // TODO: convert straight to a json typed map (mergo + iterate?) + b, err := json.Marshal(data) + if err != nil { + log.Println(err) + } + var res interface{} + if err := json.Unmarshal(b, &res); err != nil { + log.Println(err) + } + return res +} + +// FromDynamicJSON turns an object into a properly JSON typed structure +func FromDynamicJSON(data, target interface{}) error { + b, err := json.Marshal(data) + if err != nil { + log.Println(err) + } + return json.Unmarshal(b, target) +} + +// NameProvider represents an object capabale of translating from go property names +// to json property names +// This type is thread-safe. +type NameProvider struct { + lock *sync.Mutex + index map[reflect.Type]nameIndex +} + +type nameIndex struct { + jsonNames map[string]string + goNames map[string]string +} + +// NewNameProvider creates a new name provider +func NewNameProvider() *NameProvider { + return &NameProvider{ + lock: &sync.Mutex{}, + index: make(map[reflect.Type]nameIndex), + } +} + +func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) { + for i := 0; i < tpe.NumField(); i++ { + targetDes := tpe.Field(i) + + if targetDes.PkgPath != "" { // unexported + continue + } + + if targetDes.Anonymous { // walk embedded structures tree down first + buildnameIndex(targetDes.Type, idx, reverseIdx) + continue + } + + if tag := targetDes.Tag.Get("json"); tag != "" { + + parts := strings.Split(tag, ",") + if len(parts) == 0 { + continue + } + + nm := parts[0] + if nm == "-" { + continue + } + if nm == "" { // empty string means we want to use the Go name + nm = targetDes.Name + } + + idx[nm] = targetDes.Name + reverseIdx[targetDes.Name] = nm + } + } +} + +func newNameIndex(tpe reflect.Type) nameIndex { + var idx = make(map[string]string, tpe.NumField()) + var reverseIdx = make(map[string]string, tpe.NumField()) + + buildnameIndex(tpe, idx, reverseIdx) + return nameIndex{jsonNames: idx, goNames: reverseIdx} +} + +// GetJSONNames gets all the json property names for a type +func (n *NameProvider) GetJSONNames(subject interface{}) []string { + n.lock.Lock() + defer n.lock.Unlock() + tpe := reflect.Indirect(reflect.ValueOf(subject)).Type() + names, ok := n.index[tpe] + if !ok { + names = n.makeNameIndex(tpe) + } + + var res []string + for k := range names.jsonNames { + res = append(res, k) + } + return res +} + +// GetJSONName gets the json name for a go property name +func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) { + tpe := reflect.Indirect(reflect.ValueOf(subject)).Type() + return n.GetJSONNameForType(tpe, name) +} + +// GetJSONNameForType gets the json name for a go property name on a given type +func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) { + n.lock.Lock() + defer n.lock.Unlock() + names, ok := n.index[tpe] + if !ok { + names = n.makeNameIndex(tpe) + } + nme, ok := names.goNames[name] + return nme, ok +} + +func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex { + names := newNameIndex(tpe) + n.index[tpe] = names + return names +} + +// GetGoName gets the go name for a json property name +func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) { + tpe := reflect.Indirect(reflect.ValueOf(subject)).Type() + return n.GetGoNameForType(tpe, name) +} + +// GetGoNameForType gets the go name for a given type for a json property name +func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) { + n.lock.Lock() + defer n.lock.Unlock() + names, ok := n.index[tpe] + if !ok { + names = n.makeNameIndex(tpe) + } + nme, ok := names.jsonNames[name] + return nme, ok +} diff --git a/vendor/github.com/go-openapi/swag/loading.go b/vendor/github.com/go-openapi/swag/loading.go new file mode 100644 index 000000000..62ed1e80a --- /dev/null +++ b/vendor/github.com/go-openapi/swag/loading.go @@ -0,0 +1,74 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "path/filepath" + "strings" + "time" +) + +// LoadHTTPTimeout the default timeout for load requests +var LoadHTTPTimeout = 30 * time.Second + +// LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in +func LoadFromFileOrHTTP(path string) ([]byte, error) { + return LoadStrategy(path, ioutil.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(path) +} + +// LoadFromFileOrHTTPWithTimeout loads the bytes from a file or a remote http server based on the path passed in +// timeout arg allows for per request overriding of the request timeout +func LoadFromFileOrHTTPWithTimeout(path string, timeout time.Duration) ([]byte, error) { + return LoadStrategy(path, ioutil.ReadFile, loadHTTPBytes(timeout))(path) +} + +// LoadStrategy returns a loader function for a given path or uri +func LoadStrategy(path string, local, remote func(string) ([]byte, error)) func(string) ([]byte, error) { + if strings.HasPrefix(path, "http") { + return remote + } + return func(pth string) ([]byte, error) { return local(filepath.FromSlash(pth)) } +} + +func loadHTTPBytes(timeout time.Duration) func(path string) ([]byte, error) { + return func(path string) ([]byte, error) { + client := &http.Client{Timeout: timeout} + req, err := http.NewRequest("GET", path, nil) + if err != nil { + return nil, err + } + resp, err := client.Do(req) + defer func() { + if resp != nil { + if e := resp.Body.Close(); e != nil { + log.Println(e) + } + } + }() + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("could not access document at %q [%s] ", path, resp.Status) + } + + return ioutil.ReadAll(resp.Body) + } +} diff --git a/vendor/github.com/go-openapi/swag/net.go b/vendor/github.com/go-openapi/swag/net.go new file mode 100644 index 000000000..8323fa37b --- /dev/null +++ b/vendor/github.com/go-openapi/swag/net.go @@ -0,0 +1,24 @@ +package swag + +import ( + "net" + "strconv" +) + +// SplitHostPort splits a network address into a host and a port. +// The port is -1 when there is no port to be found +func SplitHostPort(addr string) (host string, port int, err error) { + h, p, err := net.SplitHostPort(addr) + if err != nil { + return "", -1, err + } + if p == "" { + return "", -1, &net.AddrError{Err: "missing port in address", Addr: addr} + } + + pi, err := strconv.Atoi(p) + if err != nil { + return "", -1, err + } + return h, pi, nil +} diff --git a/vendor/github.com/go-openapi/swag/path.go b/vendor/github.com/go-openapi/swag/path.go new file mode 100644 index 000000000..941bd0176 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/path.go @@ -0,0 +1,59 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "os" + "path/filepath" + "runtime" + "strings" +) + +const ( + // GOPATHKey represents the env key for gopath + GOPATHKey = "GOPATH" +) + +// FindInSearchPath finds a package in a provided lists of paths +func FindInSearchPath(searchPath, pkg string) string { + pathsList := filepath.SplitList(searchPath) + for _, path := range pathsList { + if evaluatedPath, err := filepath.EvalSymlinks(filepath.Join(path, "src", pkg)); err == nil { + if _, err := os.Stat(evaluatedPath); err == nil { + return evaluatedPath + } + } + } + return "" +} + +// FindInGoSearchPath finds a package in the $GOPATH:$GOROOT +func FindInGoSearchPath(pkg string) string { + return FindInSearchPath(FullGoSearchPath(), pkg) +} + +// FullGoSearchPath gets the search paths for finding packages +func FullGoSearchPath() string { + allPaths := os.Getenv(GOPATHKey) + if allPaths == "" { + allPaths = filepath.Join(os.Getenv("HOME"), "go") + } + if allPaths != "" { + allPaths = strings.Join([]string{allPaths, runtime.GOROOT()}, ":") + } else { + allPaths = runtime.GOROOT() + } + return allPaths +} diff --git a/vendor/github.com/go-openapi/swag/util.go b/vendor/github.com/go-openapi/swag/util.go new file mode 100644 index 000000000..40751aab4 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/util.go @@ -0,0 +1,336 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "math" + "reflect" + "regexp" + "sort" + "strings" + "unicode" +) + +// Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769 +var commonInitialisms = map[string]bool{ + "ACL": true, + "API": true, + "ASCII": true, + "CPU": true, + "CSS": true, + "DNS": true, + "EOF": true, + "GUID": true, + "HTML": true, + "HTTPS": true, + "HTTP": true, + "ID": true, + "IP": true, + "JSON": true, + "LHS": true, + "QPS": true, + "RAM": true, + "RHS": true, + "RPC": true, + "SLA": true, + "SMTP": true, + "SQL": true, + "SSH": true, + "TCP": true, + "TLS": true, + "TTL": true, + "UDP": true, + "UI": true, + "UID": true, + "UUID": true, + "URI": true, + "URL": true, + "UTF8": true, + "VM": true, + "XML": true, + "XMPP": true, + "XSRF": true, + "XSS": true, +} +var initialisms []string + +func init() { + for k := range commonInitialisms { + initialisms = append(initialisms, k) + } + sort.Sort(sort.Reverse(byLength(initialisms))) +} + +// JoinByFormat joins a string array by a known format: +// ssv: space separated value +// tsv: tab separated value +// pipes: pipe (|) separated value +// csv: comma separated value (default) +func JoinByFormat(data []string, format string) []string { + if len(data) == 0 { + return data + } + var sep string + switch format { + case "ssv": + sep = " " + case "tsv": + sep = "\t" + case "pipes": + sep = "|" + case "multi": + return data + default: + sep = "," + } + return []string{strings.Join(data, sep)} +} + +// SplitByFormat splits a string by a known format: +// ssv: space separated value +// tsv: tab separated value +// pipes: pipe (|) separated value +// csv: comma separated value (default) +func SplitByFormat(data, format string) []string { + if data == "" { + return nil + } + var sep string + switch format { + case "ssv": + sep = " " + case "tsv": + sep = "\t" + case "pipes": + sep = "|" + case "multi": + return nil + default: + sep = "," + } + var result []string + for _, s := range strings.Split(data, sep) { + if ts := strings.TrimSpace(s); ts != "" { + result = append(result, ts) + } + } + return result +} + +type byLength []string + +func (s byLength) Len() int { + return len(s) +} +func (s byLength) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} +func (s byLength) Less(i, j int) bool { + return len(s[i]) < len(s[j]) +} + +// Prepares strings by splitting by caps, spaces, dashes, and underscore +func split(str string) (words []string) { + repl := strings.NewReplacer( + "@", "At ", + "&", "And ", + "|", "Pipe ", + "$", "Dollar ", + "!", "Bang ", + "-", " ", + "_", " ", + ) + + rex1 := regexp.MustCompile(`(\p{Lu})`) + rex2 := regexp.MustCompile(`(\pL|\pM|\pN|\p{Pc})+`) + + str = trim(str) + + // Convert dash and underscore to spaces + str = repl.Replace(str) + + // Split when uppercase is found (needed for Snake) + str = rex1.ReplaceAllString(str, " $1") + // check if consecutive single char things make up an initialism + + for _, k := range initialisms { + str = strings.Replace(str, rex1.ReplaceAllString(k, " $1"), " "+k, -1) + } + // Get the final list of words + words = rex2.FindAllString(str, -1) + + return +} + +// Removes leading whitespaces +func trim(str string) string { + return strings.Trim(str, " ") +} + +// Shortcut to strings.ToUpper() +func upper(str string) string { + return strings.ToUpper(trim(str)) +} + +// Shortcut to strings.ToLower() +func lower(str string) string { + return strings.ToLower(trim(str)) +} + +// ToFileName lowercases and underscores a go type name +func ToFileName(name string) string { + var out []string + for _, w := range split(name) { + out = append(out, lower(w)) + } + return strings.Join(out, "_") +} + +// ToCommandName lowercases and underscores a go type name +func ToCommandName(name string) string { + var out []string + for _, w := range split(name) { + out = append(out, lower(w)) + } + return strings.Join(out, "-") +} + +// ToHumanNameLower represents a code name as a human series of words +func ToHumanNameLower(name string) string { + var out []string + for _, w := range split(name) { + if !commonInitialisms[upper(w)] { + out = append(out, lower(w)) + } else { + out = append(out, w) + } + } + return strings.Join(out, " ") +} + +// ToHumanNameTitle represents a code name as a human series of words with the first letters titleized +func ToHumanNameTitle(name string) string { + var out []string + for _, w := range split(name) { + uw := upper(w) + if !commonInitialisms[uw] { + out = append(out, upper(w[:1])+lower(w[1:])) + } else { + out = append(out, w) + } + } + return strings.Join(out, " ") +} + +// ToJSONName camelcases a name which can be underscored or pascal cased +func ToJSONName(name string) string { + var out []string + for i, w := range split(name) { + if i == 0 { + out = append(out, lower(w)) + continue + } + out = append(out, upper(w[:1])+lower(w[1:])) + } + return strings.Join(out, "") +} + +// ToVarName camelcases a name which can be underscored or pascal cased +func ToVarName(name string) string { + res := ToGoName(name) + if _, ok := commonInitialisms[res]; ok { + return lower(res) + } + if len(res) <= 1 { + return lower(res) + } + return lower(res[:1]) + res[1:] +} + +// ToGoName translates a swagger name which can be underscored or camel cased to a name that golint likes +func ToGoName(name string) string { + var out []string + for _, w := range split(name) { + uw := upper(w) + mod := int(math.Min(float64(len(uw)), 2)) + if !commonInitialisms[uw] && !commonInitialisms[uw[:len(uw)-mod]] { + uw = upper(w[:1]) + lower(w[1:]) + } + out = append(out, uw) + } + + result := strings.Join(out, "") + if len(result) > 0 { + ud := upper(result[:1]) + ru := []rune(ud) + if unicode.IsUpper(ru[0]) { + result = ud + result[1:] + } else { + result = "X" + ud + result[1:] + } + } + return result +} + +// ContainsStringsCI searches a slice of strings for a case-insensitive match +func ContainsStringsCI(coll []string, item string) bool { + for _, a := range coll { + if strings.EqualFold(a, item) { + return true + } + } + return false +} + +type zeroable interface { + IsZero() bool +} + +// IsZero returns true when the value passed into the function is a zero value. +// This allows for safer checking of interface values. +func IsZero(data interface{}) bool { + // check for things that have an IsZero method instead + if vv, ok := data.(zeroable); ok { + return vv.IsZero() + } + // continue with slightly more complex reflection + v := reflect.ValueOf(data) + switch v.Kind() { + case reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + case reflect.Struct, reflect.Array: + return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface()) + case reflect.Invalid: + return true + } + return false +} + +// CommandLineOptionsGroup represents a group of user-defined command line options +type CommandLineOptionsGroup struct { + ShortDescription string + LongDescription string + Options interface{} +} diff --git a/vendor/github.com/go-openapi/swag/yaml.go b/vendor/github.com/go-openapi/swag/yaml.go new file mode 100644 index 000000000..26502f21d --- /dev/null +++ b/vendor/github.com/go-openapi/swag/yaml.go @@ -0,0 +1,215 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "encoding/json" + "fmt" + "path/filepath" + "strconv" + + "github.com/mailru/easyjson/jlexer" + "github.com/mailru/easyjson/jwriter" + + yaml "gopkg.in/yaml.v2" +) + +// YAMLMatcher matches yaml +func YAMLMatcher(path string) bool { + ext := filepath.Ext(path) + return ext == ".yaml" || ext == ".yml" +} + +// YAMLToJSON converts YAML unmarshaled data into json compatible data +func YAMLToJSON(data interface{}) (json.RawMessage, error) { + jm, err := transformData(data) + if err != nil { + return nil, err + } + b, err := WriteJSON(jm) + return json.RawMessage(b), err +} + +func BytesToYAMLDoc(data []byte) (interface{}, error) { + var canary map[interface{}]interface{} // validate this is an object and not a different type + if err := yaml.Unmarshal(data, &canary); err != nil { + return nil, err + } + + var document yaml.MapSlice // preserve order that is present in the document + if err := yaml.Unmarshal(data, &document); err != nil { + return nil, err + } + return document, nil +} + +type JSONMapSlice []JSONMapItem + +func (s JSONMapSlice) MarshalJSON() ([]byte, error) { + w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty} + s.MarshalEasyJSON(w) + return w.BuildBytes() +} + +func (s JSONMapSlice) MarshalEasyJSON(w *jwriter.Writer) { + w.RawByte('{') + + ln := len(s) + last := ln - 1 + for i := 0; i < ln; i++ { + s[i].MarshalEasyJSON(w) + if i != last { // last item + w.RawByte(',') + } + } + + w.RawByte('}') +} + +func (s *JSONMapSlice) UnmarshalJSON(data []byte) error { + l := jlexer.Lexer{Data: data} + s.UnmarshalEasyJSON(&l) + return l.Error() +} +func (s *JSONMapSlice) UnmarshalEasyJSON(in *jlexer.Lexer) { + if in.IsNull() { + in.Skip() + return + } + + var result JSONMapSlice + in.Delim('{') + for !in.IsDelim('}') { + var mi JSONMapItem + mi.UnmarshalEasyJSON(in) + result = append(result, mi) + } + *s = result +} + +type JSONMapItem struct { + Key string + Value interface{} +} + +func (s JSONMapItem) MarshalJSON() ([]byte, error) { + w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty} + s.MarshalEasyJSON(w) + return w.BuildBytes() +} + +func (s JSONMapItem) MarshalEasyJSON(w *jwriter.Writer) { + w.String(s.Key) + w.RawByte(':') + w.Raw(WriteJSON(s.Value)) +} + +func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) { + key := in.UnsafeString() + in.WantColon() + value := in.Interface() + in.WantComma() + s.Key = key + s.Value = value +} +func (s *JSONMapItem) UnmarshalJSON(data []byte) error { + l := jlexer.Lexer{Data: data} + s.UnmarshalEasyJSON(&l) + return l.Error() +} + +func transformData(input interface{}) (out interface{}, err error) { + switch in := input.(type) { + case yaml.MapSlice: + + o := make(JSONMapSlice, len(in)) + for i, mi := range in { + var nmi JSONMapItem + switch k := mi.Key.(type) { + case string: + nmi.Key = k + case int: + nmi.Key = strconv.Itoa(k) + default: + return nil, fmt.Errorf("types don't match expect map key string or int got: %T", mi.Key) + } + + v, err := transformData(mi.Value) + if err != nil { + return nil, err + } + nmi.Value = v + o[i] = nmi + } + return o, nil + case map[interface{}]interface{}: + o := make(JSONMapSlice, 0, len(in)) + for ke, va := range in { + var nmi JSONMapItem + switch k := ke.(type) { + case string: + nmi.Key = k + case int: + nmi.Key = strconv.Itoa(k) + default: + return nil, fmt.Errorf("types don't match expect map key string or int got: %T", ke) + } + + v, err := transformData(va) + if err != nil { + return nil, err + } + nmi.Value = v + o = append(o, nmi) + } + return o, nil + case []interface{}: + len1 := len(in) + o := make([]interface{}, len1) + for i := 0; i < len1; i++ { + o[i], err = transformData(in[i]) + if err != nil { + return nil, err + } + } + return o, nil + } + return input, nil +} + +// YAMLDoc loads a yaml document from either http or a file and converts it to json +func YAMLDoc(path string) (json.RawMessage, error) { + yamlDoc, err := YAMLData(path) + if err != nil { + return nil, err + } + + data, err := YAMLToJSON(yamlDoc) + if err != nil { + return nil, err + } + + return json.RawMessage(data), nil +} + +// YAMLData loads a yaml document from either http or a file +func YAMLData(path string) (interface{}, error) { + data, err := LoadFromFileOrHTTP(path) + if err != nil { + return nil, err + } + + return BytesToYAMLDoc(data) +} diff --git a/vendor/github.com/gogo/protobuf/AUTHORS b/vendor/github.com/gogo/protobuf/AUTHORS new file mode 100644 index 000000000..2eaf4d53a --- /dev/null +++ b/vendor/github.com/gogo/protobuf/AUTHORS @@ -0,0 +1,14 @@ +# This is the official list of GoGo authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS file, which +# lists people. For example, employees are listed in CONTRIBUTORS, +# but not in AUTHORS, because the employer holds the copyright. + +# Names should be added to this file as one of +# Organization's name +# Individual's name +# Individual's name + +# Please keep the list sorted. + +Vastech SA (PTY) LTD +Walter Schulze diff --git a/vendor/github.com/gogo/protobuf/CONTRIBUTORS b/vendor/github.com/gogo/protobuf/CONTRIBUTORS new file mode 100644 index 000000000..84a85b1e8 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/CONTRIBUTORS @@ -0,0 +1,18 @@ +Anton Povarov +Clayton Coleman +Denis Smirnov +DongYun Kang +Dwayne Schultz +Georg Apitz +Gustav Paul +Johan Brandhorst +John Shahid +John Tuley +Laurent +Patrick Lee +Sergio Arbeo +Stephen J Day +Tamir Duberstein +Todd Eisenberger +Tormod Erevik Lea +Walter Schulze diff --git a/vendor/github.com/gogo/protobuf/GOLANG_CONTRIBUTORS b/vendor/github.com/gogo/protobuf/GOLANG_CONTRIBUTORS new file mode 100644 index 000000000..b368efb7f --- /dev/null +++ b/vendor/github.com/gogo/protobuf/GOLANG_CONTRIBUTORS @@ -0,0 +1,5 @@ +The contributors to the Go protobuf repository: + +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. \ No newline at end of file diff --git a/vendor/github.com/gogo/protobuf/LICENSE b/vendor/github.com/gogo/protobuf/LICENSE new file mode 100644 index 000000000..7be0cc7b6 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/LICENSE @@ -0,0 +1,36 @@ +Protocol Buffers for Go with Gadgets + +Copyright (c) 2013, The GoGo Authors. All rights reserved. +http://github.com/gogo/protobuf + +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/vendor/github.com/gogo/protobuf/proto/Makefile b/vendor/github.com/gogo/protobuf/proto/Makefile new file mode 100644 index 000000000..41c717573 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/Makefile @@ -0,0 +1,43 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +install: + go install + +test: install generate-test-pbs + go test + + +generate-test-pbs: + make install + make -C testdata + protoc-min-version --version="3.0.0" --proto_path=.:../../../../:../protobuf --gogo_out=Mtestdata/test.proto=github.com/gogo/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types:. proto3_proto/proto3.proto + make diff --git a/vendor/github.com/gogo/protobuf/proto/clone.go b/vendor/github.com/gogo/protobuf/proto/clone.go new file mode 100644 index 000000000..5d4cba4b5 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/clone.go @@ -0,0 +1,234 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer deep copy and merge. +// TODO: RawMessage. + +package proto + +import ( + "log" + "reflect" + "strings" +) + +// Clone returns a deep copy of a protocol buffer. +func Clone(pb Message) Message { + in := reflect.ValueOf(pb) + if in.IsNil() { + return pb + } + + out := reflect.New(in.Type().Elem()) + // out is empty so a merge is a deep copy. + mergeStruct(out.Elem(), in.Elem()) + return out.Interface().(Message) +} + +// Merge merges src into dst. +// Required and optional fields that are set in src will be set to that value in dst. +// Elements of repeated fields will be appended. +// Merge panics if src and dst are not the same type, or if dst is nil. +func Merge(dst, src Message) { + in := reflect.ValueOf(src) + out := reflect.ValueOf(dst) + if out.IsNil() { + panic("proto: nil destination") + } + if in.Type() != out.Type() { + // Explicit test prior to mergeStruct so that mistyped nils will fail + panic("proto: type mismatch") + } + if in.IsNil() { + // Merging nil into non-nil is a quiet no-op + return + } + mergeStruct(out.Elem(), in.Elem()) +} + +func mergeStruct(out, in reflect.Value) { + sprop := GetProperties(in.Type()) + for i := 0; i < in.NumField(); i++ { + f := in.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) + } + + if emIn, ok := in.Addr().Interface().(extensionsBytes); ok { + emOut := out.Addr().Interface().(extensionsBytes) + bIn := emIn.GetExtensions() + bOut := emOut.GetExtensions() + *bOut = append(*bOut, *bIn...) + } else if emIn, ok := extendable(in.Addr().Interface()); ok { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + uf := in.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return + } + uin := uf.Bytes() + if len(uin) > 0 { + out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) + } +} + +// mergeAny performs a merge between two values of the same type. +// viaPtr indicates whether the values were indirected through a pointer (implying proto2). +// prop is set if this is a struct field (it may be nil). +func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { + if in.Type() == protoMessageType { + if !in.IsNil() { + if out.IsNil() { + out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) + } else { + Merge(out.Interface().(Message), in.Interface().(Message)) + } + } + return + } + switch in.Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + if !viaPtr && isProto3Zero(in) { + return + } + out.Set(in) + case reflect.Interface: + // Probably a oneof field; copy non-nil values. + if in.IsNil() { + return + } + // Allocate destination if it is not set, or set to a different type. + // Otherwise we will merge as normal. + if out.IsNil() || out.Elem().Type() != in.Elem().Type() { + out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) + } + mergeAny(out.Elem(), in.Elem(), false, nil) + case reflect.Map: + if in.Len() == 0 { + return + } + if out.IsNil() { + out.Set(reflect.MakeMap(in.Type())) + } + // For maps with value types of *T or []byte we need to deep copy each value. + elemKind := in.Type().Elem().Kind() + for _, key := range in.MapKeys() { + var val reflect.Value + switch elemKind { + case reflect.Ptr: + val = reflect.New(in.Type().Elem().Elem()) + mergeAny(val, in.MapIndex(key), false, nil) + case reflect.Slice: + val = in.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + default: + val = in.MapIndex(key) + } + out.SetMapIndex(key, val) + } + case reflect.Ptr: + if in.IsNil() { + return + } + if out.IsNil() { + out.Set(reflect.New(in.Elem().Type())) + } + mergeAny(out.Elem(), in.Elem(), true, nil) + case reflect.Slice: + if in.IsNil() { + return + } + if in.Type().Elem().Kind() == reflect.Uint8 { + // []byte is a scalar bytes field, not a repeated field. + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value, and should not + // be merged. + if prop != nil && prop.proto3 && in.Len() == 0 { + return + } + + // Make a deep copy. + // Append to []byte{} instead of []byte(nil) so that we never end up + // with a nil result. + out.SetBytes(append([]byte{}, in.Bytes()...)) + return + } + n := in.Len() + if out.IsNil() { + out.Set(reflect.MakeSlice(in.Type(), 0, n)) + } + switch in.Type().Elem().Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + out.Set(reflect.AppendSlice(out, in)) + default: + for i := 0; i < n; i++ { + x := reflect.Indirect(reflect.New(in.Type().Elem())) + mergeAny(x, in.Index(i), false, nil) + out.Set(reflect.Append(out, x)) + } + } + case reflect.Struct: + mergeStruct(out, in) + default: + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to copy %v", in) + } +} + +func mergeExtension(out, in map[int32]Extension) { + for extNum, eIn := range in { + eOut := Extension{desc: eIn.desc} + if eIn.value != nil { + v := reflect.New(reflect.TypeOf(eIn.value)).Elem() + mergeAny(v, reflect.ValueOf(eIn.value), false, nil) + eOut.value = v.Interface() + } + if eIn.enc != nil { + eOut.enc = make([]byte, len(eIn.enc)) + copy(eOut.enc, eIn.enc) + } + + out[extNum] = eOut + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/decode.go b/vendor/github.com/gogo/protobuf/proto/decode.go new file mode 100644 index 000000000..737f2731d --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/decode.go @@ -0,0 +1,978 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for decoding protocol buffer data to construct in-memory representations. + */ + +import ( + "errors" + "fmt" + "io" + "os" + "reflect" +) + +// errOverflow is returned when an integer is too large to be represented. +var errOverflow = errors.New("proto: integer overflow") + +// ErrInternalBadWireType is returned by generated code when an incorrect +// wire type is encountered. It does not get returned to user code. +var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") + +// The fundamental decoders that interpret bytes on the wire. +// Those that take integer types all return uint64 and are +// therefore of type valueDecoder. + +// DecodeVarint reads a varint-encoded integer from the slice. +// It returns the integer and the number of bytes consumed, or +// zero if there is not enough. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func DecodeVarint(buf []byte) (x uint64, n int) { + for shift := uint(0); shift < 64; shift += 7 { + if n >= len(buf) { + return 0, 0 + } + b := uint64(buf[n]) + n++ + x |= (b & 0x7F) << shift + if (b & 0x80) == 0 { + return x, n + } + } + + // The number is too large to represent in a 64-bit value. + return 0, 0 +} + +func (p *Buffer) decodeVarintSlow() (x uint64, err error) { + i := p.index + l := len(p.buf) + + for shift := uint(0); shift < 64; shift += 7 { + if i >= l { + err = io.ErrUnexpectedEOF + return + } + b := p.buf[i] + i++ + x |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + p.index = i + return + } + } + + // The number is too large to represent in a 64-bit value. + err = errOverflow + return +} + +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) DecodeVarint() (x uint64, err error) { + i := p.index + buf := p.buf + + if i >= len(buf) { + return 0, io.ErrUnexpectedEOF + } else if buf[i] < 0x80 { + p.index++ + return uint64(buf[i]), nil + } else if len(buf)-i < 10 { + return p.decodeVarintSlow() + } + + var b uint64 + // we already checked the first byte + x = uint64(buf[i]) - 0x80 + i++ + + b = uint64(buf[i]) + i++ + x += b << 7 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 7 + + b = uint64(buf[i]) + i++ + x += b << 14 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 14 + + b = uint64(buf[i]) + i++ + x += b << 21 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 21 + + b = uint64(buf[i]) + i++ + x += b << 28 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 28 + + b = uint64(buf[i]) + i++ + x += b << 35 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 35 + + b = uint64(buf[i]) + i++ + x += b << 42 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 42 + + b = uint64(buf[i]) + i++ + x += b << 49 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 49 + + b = uint64(buf[i]) + i++ + x += b << 56 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 56 + + b = uint64(buf[i]) + i++ + x += b << 63 + if b&0x80 == 0 { + goto done + } + // x -= 0x80 << 63 // Always zero. + + return 0, errOverflow + +done: + p.index = i + return x, nil +} + +// DecodeFixed64 reads a 64-bit integer from the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) DecodeFixed64() (x uint64, err error) { + // x, err already 0 + i := p.index + 8 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-8]) + x |= uint64(p.buf[i-7]) << 8 + x |= uint64(p.buf[i-6]) << 16 + x |= uint64(p.buf[i-5]) << 24 + x |= uint64(p.buf[i-4]) << 32 + x |= uint64(p.buf[i-3]) << 40 + x |= uint64(p.buf[i-2]) << 48 + x |= uint64(p.buf[i-1]) << 56 + return +} + +// DecodeFixed32 reads a 32-bit integer from the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) DecodeFixed32() (x uint64, err error) { + // x, err already 0 + i := p.index + 4 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-4]) + x |= uint64(p.buf[i-3]) << 8 + x |= uint64(p.buf[i-2]) << 16 + x |= uint64(p.buf[i-1]) << 24 + return +} + +// DecodeZigzag64 reads a zigzag-encoded 64-bit integer +// from the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) DecodeZigzag64() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) + return +} + +// DecodeZigzag32 reads a zigzag-encoded 32-bit integer +// from the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) DecodeZigzag32() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) + return +} + +// These are not ValueDecoders: they produce an array of bytes or a string. +// bytes, embedded messages + +// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { + n, err := p.DecodeVarint() + if err != nil { + return nil, err + } + + nb := int(n) + if nb < 0 { + return nil, fmt.Errorf("proto: bad byte length %d", nb) + } + end := p.index + nb + if end < p.index || end > len(p.buf) { + return nil, io.ErrUnexpectedEOF + } + + if !alloc { + // todo: check if can get more uses of alloc=false + buf = p.buf[p.index:end] + p.index += nb + return + } + + buf = make([]byte, nb) + copy(buf, p.buf[p.index:]) + p.index += nb + return +} + +// DecodeStringBytes reads an encoded string from the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) DecodeStringBytes() (s string, err error) { + buf, err := p.DecodeRawBytes(false) + if err != nil { + return + } + return string(buf), nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +// If the protocol buffer has extensions, and the field matches, add it as an extension. +// Otherwise, if the XXX_unrecognized field exists, append the skipped data there. +func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { + oi := o.index + + err := o.skip(t, tag, wire) + if err != nil { + return err + } + + if !unrecField.IsValid() { + return nil + } + + ptr := structPointer_Bytes(base, unrecField) + + // Add the skipped field to struct field + obuf := o.buf + + o.buf = *ptr + o.EncodeVarint(uint64(tag<<3 | wire)) + *ptr = append(o.buf, obuf[oi:o.index]...) + + o.buf = obuf + + return nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +func (o *Buffer) skip(t reflect.Type, tag, wire int) error { + + var u uint64 + var err error + + switch wire { + case WireVarint: + _, err = o.DecodeVarint() + case WireFixed64: + _, err = o.DecodeFixed64() + case WireBytes: + _, err = o.DecodeRawBytes(false) + case WireFixed32: + _, err = o.DecodeFixed32() + case WireStartGroup: + for { + u, err = o.DecodeVarint() + if err != nil { + break + } + fwire := int(u & 0x7) + if fwire == WireEndGroup { + break + } + ftag := int(u >> 3) + err = o.skip(t, ftag, fwire) + if err != nil { + break + } + } + default: + err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) + } + return err +} + +// Unmarshaler is the interface representing objects that can +// unmarshal themselves. The method should reset the receiver before +// decoding starts. The argument points to data that may be +// overwritten, so implementations should not keep references to the +// buffer. +type Unmarshaler interface { + Unmarshal([]byte) error +} + +// Unmarshal parses the protocol buffer representation in buf and places the +// decoded result in pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// Unmarshal resets pb before starting to unmarshal, so any +// existing data in pb is always removed. Use UnmarshalMerge +// to preserve and append to existing data. +func Unmarshal(buf []byte, pb Message) error { + pb.Reset() + return UnmarshalMerge(buf, pb) +} + +// UnmarshalMerge parses the protocol buffer representation in buf and +// writes the decoded result to pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// UnmarshalMerge merges into existing data in pb. +// Most code should use Unmarshal instead. +func UnmarshalMerge(buf []byte, pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) +} + +// DecodeMessage reads a count-delimited message from the Buffer. +func (p *Buffer) DecodeMessage(pb Message) error { + enc, err := p.DecodeRawBytes(false) + if err != nil { + return err + } + return NewBuffer(enc).Unmarshal(pb) +} + +// DecodeGroup reads a tag-delimited group from the Buffer. +func (p *Buffer) DecodeGroup(pb Message) error { + typ, base, err := getbase(pb) + if err != nil { + return err + } + return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) +} + +// Unmarshal parses the protocol buffer representation in the +// Buffer and places the decoded result in pb. If the struct +// underlying pb does not match the data in the buffer, the results can be +// unpredictable. +// +// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. +func (p *Buffer) Unmarshal(pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + err := u.Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } + + typ, base, err := getbase(pb) + if err != nil { + return err + } + + err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) + + if collectStats { + stats.Decode++ + } + + return err +} + +// unmarshalType does the work of unmarshaling a structure. +func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { + var state errorState + required, reqFields := prop.reqCount, uint64(0) + + var err error + for err == nil && o.index < len(o.buf) { + oi := o.index + var u uint64 + u, err = o.DecodeVarint() + if err != nil { + break + } + wire := int(u & 0x7) + if wire == WireEndGroup { + if is_group { + if required > 0 { + // Not enough information to determine the exact field. + // (See below.) + return &RequiredNotSetError{"{Unknown}"} + } + return nil // input is satisfied + } + return fmt.Errorf("proto: %s: wiretype end group for non-group", st) + } + tag := int(u >> 3) + if tag <= 0 { + return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) + } + fieldnum, ok := prop.decoderTags.get(tag) + if !ok { + // Maybe it's an extension? + if prop.extendable { + if e, eok := structPointer_Interface(base, st).(extensionsBytes); eok { + if isExtensionField(e, int32(tag)) { + if err = o.skip(st, tag, wire); err == nil { + ext := e.GetExtensions() + *ext = append(*ext, o.buf[oi:o.index]...) + } + continue + } + } else if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { + if err = o.skip(st, tag, wire); err == nil { + extmap := e.extensionsWrite() + ext := extmap[int32(tag)] // may be missing + ext.enc = append(ext.enc, o.buf[oi:o.index]...) + extmap[int32(tag)] = ext + } + continue + } + } + // Maybe it's a oneof? + if prop.oneofUnmarshaler != nil { + m := structPointer_Interface(base, st).(Message) + // First return value indicates whether tag is a oneof field. + ok, err = prop.oneofUnmarshaler(m, tag, wire, o) + if err == ErrInternalBadWireType { + // Map the error to something more descriptive. + // Do the formatting here to save generated code space. + err = fmt.Errorf("bad wiretype for oneof field in %T", m) + } + if ok { + continue + } + } + err = o.skipAndSave(st, tag, wire, base, prop.unrecField) + continue + } + p := prop.Prop[fieldnum] + + if p.dec == nil { + fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) + continue + } + dec := p.dec + if wire != WireStartGroup && wire != p.WireType { + if wire == WireBytes && p.packedDec != nil { + // a packable field + dec = p.packedDec + } else { + err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) + continue + } + } + decErr := dec(o, p, base) + if decErr != nil && !state.shouldContinue(decErr, p) { + err = decErr + } + if err == nil && p.Required { + // Successfully decoded a required field. + if tag <= 64 { + // use bitmap for fields 1-64 to catch field reuse. + var mask uint64 = 1 << uint64(tag-1) + if reqFields&mask == 0 { + // new required field + reqFields |= mask + required-- + } + } else { + // This is imprecise. It can be fooled by a required field + // with a tag > 64 that is encoded twice; that's very rare. + // A fully correct implementation would require allocating + // a data structure, which we would like to avoid. + required-- + } + } + } + if err == nil { + if is_group { + return io.ErrUnexpectedEOF + } + if state.err != nil { + return state.err + } + if required > 0 { + // Not enough information to determine the exact field. If we use extra + // CPU, we could determine the field only if the missing required field + // has a tag <= 64 and we check reqFields. + return &RequiredNotSetError{"{Unknown}"} + } + } + return err +} + +// Individual type decoders +// For each, +// u is the decoded value, +// v is a pointer to the field (pointer) in the struct + +// Sizes of the pools to allocate inside the Buffer. +// The goal is modest amortization and allocation +// on at least 16-byte boundaries. +const ( + boolPoolSize = 16 + uint32PoolSize = 8 + uint64PoolSize = 4 +) + +// Decode a bool. +func (o *Buffer) dec_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + if len(o.bools) == 0 { + o.bools = make([]bool, boolPoolSize) + } + o.bools[0] = u != 0 + *structPointer_Bool(base, p.field) = &o.bools[0] + o.bools = o.bools[1:] + return nil +} + +func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + *structPointer_BoolVal(base, p.field) = u != 0 + return nil +} + +// Decode an int32. +func (o *Buffer) dec_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) + return nil +} + +func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) + return nil +} + +// Decode an int64. +func (o *Buffer) dec_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64_Set(structPointer_Word64(base, p.field), o, u) + return nil +} + +func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64Val_Set(structPointer_Word64Val(base, p.field), o, u) + return nil +} + +// Decode a string. +func (o *Buffer) dec_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_String(base, p.field) = &s + return nil +} + +func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_StringVal(base, p.field) = s + return nil +} + +// Decode a slice of bytes ([]byte). +func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + *structPointer_Bytes(base, p.field) = b + return nil +} + +// Decode a slice of bools ([]bool). +func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + v := structPointer_BoolSlice(base, p.field) + *v = append(*v, u != 0) + return nil +} + +// Decode a slice of bools ([]bool) in packed format. +func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { + v := structPointer_BoolSlice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded bools + fin := o.index + nb + if fin < o.index { + return errOverflow + } + + y := *v + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + y = append(y, u != 0) + } + + *v = y + return nil +} + +// Decode a slice of int32s ([]int32). +func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + structPointer_Word32Slice(base, p.field).Append(uint32(u)) + return nil +} + +// Decode a slice of int32s ([]int32) in packed format. +func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int32s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(uint32(u)) + } + return nil +} + +// Decode a slice of int64s ([]int64). +func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + + structPointer_Word64Slice(base, p.field).Append(u) + return nil +} + +// Decode a slice of int64s ([]int64) in packed format. +func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int64s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(u) + } + return nil +} + +// Decode a slice of strings ([]string). +func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + v := structPointer_StringSlice(base, p.field) + *v = append(*v, s) + return nil +} + +// Decode a slice of slice of bytes ([][]byte). +func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + v := structPointer_BytesSlice(base, p.field) + *v = append(*v, b) + return nil +} + +// Decode a map field. +func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + oi := o.index // index at the end of this map entry + o.index -= len(raw) // move buffer back to start of map entry + + mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V + if mptr.Elem().IsNil() { + mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) + } + v := mptr.Elem() // map[K]V + + // Prepare addressable doubly-indirect placeholders for the key and value types. + // See enc_new_map for why. + keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K + keybase := toStructPointer(keyptr.Addr()) // **K + + var valbase structPointer + var valptr reflect.Value + switch p.mtype.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valptr = reflect.ValueOf(&dummy) // *[]byte + valbase = toStructPointer(valptr) // *[]byte + case reflect.Ptr: + // message; valptr is **Msg; need to allocate the intermediate pointer + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valptr.Set(reflect.New(valptr.Type().Elem())) + valbase = toStructPointer(valptr) + default: + // everything else + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valbase = toStructPointer(valptr.Addr()) // **V + } + + // Decode. + // This parses a restricted wire format, namely the encoding of a message + // with two fields. See enc_new_map for the format. + for o.index < oi { + // tagcode for key and value properties are always a single byte + // because they have tags 1 and 2. + tagcode := o.buf[o.index] + o.index++ + switch tagcode { + case p.mkeyprop.tagcode[0]: + if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { + return err + } + case p.mvalprop.tagcode[0]: + if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { + return err + } + default: + // TODO: Should we silently skip this instead? + return fmt.Errorf("proto: bad map data tag %d", raw[0]) + } + } + keyelem, valelem := keyptr.Elem(), valptr.Elem() + if !keyelem.IsValid() { + keyelem = reflect.Zero(p.mtype.Key()) + } + if !valelem.IsValid() { + valelem = reflect.Zero(p.mtype.Elem()) + } + + v.SetMapIndex(keyelem, valelem) + return nil +} + +// Decode a group. +func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + return o.unmarshalType(p.stype, p.sprop, true, bas) +} + +// Decode an embedded message. +func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { + raw, e := o.DecodeRawBytes(false) + if e != nil { + return e + } + + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := structPointer_Interface(bas, p.stype) + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, false, bas) + o.buf = obuf + o.index = oi + + return err +} + +// Decode a slice of embedded messages. +func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, false, base) +} + +// Decode a slice of embedded groups. +func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, true, base) +} + +// Decode a slice of structs ([]*struct). +func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { + v := reflect.New(p.stype) + bas := toStructPointer(v) + structPointer_StructPointerSlice(base, p.field).Append(bas) + + if is_group { + err := o.unmarshalType(p.stype, p.sprop, is_group, bas) + return err + } + + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := v.Interface() + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, is_group, bas) + + o.buf = obuf + o.index = oi + + return err +} diff --git a/vendor/github.com/gogo/protobuf/proto/decode_gogo.go b/vendor/github.com/gogo/protobuf/proto/decode_gogo.go new file mode 100644 index 000000000..6fb74de4c --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/decode_gogo.go @@ -0,0 +1,172 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "reflect" +) + +// Decode a reference to a struct pointer. +func (o *Buffer) dec_ref_struct_message(p *Properties, base structPointer) (err error) { + raw, e := o.DecodeRawBytes(false) + if e != nil { + return e + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + panic("not supported, since this is a pointer receiver") + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + bas := structPointer_FieldPointer(base, p.field) + + err = o.unmarshalType(p.stype, p.sprop, false, bas) + o.buf = obuf + o.index = oi + + return err +} + +// Decode a slice of references to struct pointers ([]struct). +func (o *Buffer) dec_slice_ref_struct(p *Properties, is_group bool, base structPointer) error { + newBas := appendStructPointer(base, p.field, p.sstype) + + if is_group { + panic("not supported, maybe in future, if requested.") + } + + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + panic("not supported, since this is not a pointer receiver.") + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, is_group, newBas) + + o.buf = obuf + o.index = oi + + return err +} + +// Decode a slice of references to struct pointers. +func (o *Buffer) dec_slice_ref_struct_message(p *Properties, base structPointer) error { + return o.dec_slice_ref_struct(p, false, base) +} + +func setPtrCustomType(base structPointer, f field, v interface{}) { + if v == nil { + return + } + structPointer_SetStructPointer(base, f, toStructPointer(reflect.ValueOf(v))) +} + +func setCustomType(base structPointer, f field, value interface{}) { + if value == nil { + return + } + v := reflect.ValueOf(value).Elem() + t := reflect.TypeOf(value).Elem() + kind := t.Kind() + switch kind { + case reflect.Slice: + slice := reflect.MakeSlice(t, v.Len(), v.Cap()) + reflect.Copy(slice, v) + oldHeader := structPointer_GetSliceHeader(base, f) + oldHeader.Data = slice.Pointer() + oldHeader.Len = v.Len() + oldHeader.Cap = v.Cap() + default: + size := reflect.TypeOf(value).Elem().Size() + structPointer_Copy(toStructPointer(reflect.ValueOf(value)), structPointer_Add(base, f), int(size)) + } +} + +func (o *Buffer) dec_custom_bytes(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + i := reflect.New(p.ctype.Elem()).Interface() + custom := (i).(Unmarshaler) + if err := custom.Unmarshal(b); err != nil { + return err + } + setPtrCustomType(base, p.field, custom) + return nil +} + +func (o *Buffer) dec_custom_ref_bytes(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + i := reflect.New(p.ctype).Interface() + custom := (i).(Unmarshaler) + if err := custom.Unmarshal(b); err != nil { + return err + } + if custom != nil { + setCustomType(base, p.field, custom) + } + return nil +} + +// Decode a slice of bytes ([]byte) into a slice of custom types. +func (o *Buffer) dec_custom_slice_bytes(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + i := reflect.New(p.ctype.Elem()).Interface() + custom := (i).(Unmarshaler) + if err := custom.Unmarshal(b); err != nil { + return err + } + newBas := appendStructPointer(base, p.field, p.ctype) + + var zero field + setCustomType(newBas, zero, custom) + + return nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/duration.go b/vendor/github.com/gogo/protobuf/proto/duration.go new file mode 100644 index 000000000..93464c91c --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/duration.go @@ -0,0 +1,100 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// This file implements conversions between google.protobuf.Duration +// and time.Duration. + +import ( + "errors" + "fmt" + "time" +) + +const ( + // Range of a Duration in seconds, as specified in + // google/protobuf/duration.proto. This is about 10,000 years in seconds. + maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) + minSeconds = -maxSeconds +) + +// validateDuration determines whether the Duration is valid according to the +// definition in google/protobuf/duration.proto. A valid Duration +// may still be too large to fit into a time.Duration (the range of Duration +// is about 10,000 years, and the range of time.Duration is about 290). +func validateDuration(d *duration) error { + if d == nil { + return errors.New("duration: nil Duration") + } + if d.Seconds < minSeconds || d.Seconds > maxSeconds { + return fmt.Errorf("duration: %#v: seconds out of range", d) + } + if d.Nanos <= -1e9 || d.Nanos >= 1e9 { + return fmt.Errorf("duration: %#v: nanos out of range", d) + } + // Seconds and Nanos must have the same sign, unless d.Nanos is zero. + if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) { + return fmt.Errorf("duration: %#v: seconds and nanos have different signs", d) + } + return nil +} + +// DurationFromProto converts a Duration to a time.Duration. DurationFromProto +// returns an error if the Duration is invalid or is too large to be +// represented in a time.Duration. +func durationFromProto(p *duration) (time.Duration, error) { + if err := validateDuration(p); err != nil { + return 0, err + } + d := time.Duration(p.Seconds) * time.Second + if int64(d/time.Second) != p.Seconds { + return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p) + } + if p.Nanos != 0 { + d += time.Duration(p.Nanos) + if (d < 0) != (p.Nanos < 0) { + return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p) + } + } + return d, nil +} + +// DurationProto converts a time.Duration to a Duration. +func durationProto(d time.Duration) *duration { + nanos := d.Nanoseconds() + secs := nanos / 1e9 + nanos -= secs * 1e9 + return &duration{ + Seconds: secs, + Nanos: int32(nanos), + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/duration_gogo.go b/vendor/github.com/gogo/protobuf/proto/duration_gogo.go new file mode 100644 index 000000000..18e2a5f77 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/duration_gogo.go @@ -0,0 +1,203 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2016, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "reflect" + "time" +) + +var durationType = reflect.TypeOf((*time.Duration)(nil)).Elem() + +type duration struct { + Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` + Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` +} + +func (m *duration) Reset() { *m = duration{} } +func (*duration) ProtoMessage() {} +func (*duration) String() string { return "duration" } + +func init() { + RegisterType((*duration)(nil), "gogo.protobuf.proto.duration") +} + +func (o *Buffer) decDuration() (time.Duration, error) { + b, err := o.DecodeRawBytes(true) + if err != nil { + return 0, err + } + dproto := &duration{} + if err := Unmarshal(b, dproto); err != nil { + return 0, err + } + return durationFromProto(dproto) +} + +func (o *Buffer) dec_duration(p *Properties, base structPointer) error { + d, err := o.decDuration() + if err != nil { + return err + } + word64_Set(structPointer_Word64(base, p.field), o, uint64(d)) + return nil +} + +func (o *Buffer) dec_ref_duration(p *Properties, base structPointer) error { + d, err := o.decDuration() + if err != nil { + return err + } + word64Val_Set(structPointer_Word64Val(base, p.field), o, uint64(d)) + return nil +} + +func (o *Buffer) dec_slice_duration(p *Properties, base structPointer) error { + d, err := o.decDuration() + if err != nil { + return err + } + newBas := appendStructPointer(base, p.field, reflect.SliceOf(reflect.PtrTo(durationType))) + var zero field + setPtrCustomType(newBas, zero, &d) + return nil +} + +func (o *Buffer) dec_slice_ref_duration(p *Properties, base structPointer) error { + d, err := o.decDuration() + if err != nil { + return err + } + structPointer_Word64Slice(base, p.field).Append(uint64(d)) + return nil +} + +func size_duration(p *Properties, base structPointer) (n int) { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + dur := structPointer_Interface(structp, durationType).(*time.Duration) + d := durationProto(*dur) + size := Size(d) + return size + sizeVarint(uint64(size)) + len(p.tagcode) +} + +func (o *Buffer) enc_duration(p *Properties, base structPointer) error { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + dur := structPointer_Interface(structp, durationType).(*time.Duration) + d := durationProto(*dur) + data, err := Marshal(d) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_ref_duration(p *Properties, base structPointer) (n int) { + dur := structPointer_InterfaceAt(base, p.field, durationType).(*time.Duration) + d := durationProto(*dur) + size := Size(d) + return size + sizeVarint(uint64(size)) + len(p.tagcode) +} + +func (o *Buffer) enc_ref_duration(p *Properties, base structPointer) error { + dur := structPointer_InterfaceAt(base, p.field, durationType).(*time.Duration) + d := durationProto(*dur) + data, err := Marshal(d) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_slice_duration(p *Properties, base structPointer) (n int) { + pdurs := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(reflect.PtrTo(durationType))).(*[]*time.Duration) + durs := *pdurs + for i := 0; i < len(durs); i++ { + if durs[i] == nil { + return 0 + } + dproto := durationProto(*durs[i]) + size := Size(dproto) + n += len(p.tagcode) + size + sizeVarint(uint64(size)) + } + return n +} + +func (o *Buffer) enc_slice_duration(p *Properties, base structPointer) error { + pdurs := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(reflect.PtrTo(durationType))).(*[]*time.Duration) + durs := *pdurs + for i := 0; i < len(durs); i++ { + if durs[i] == nil { + return errRepeatedHasNil + } + dproto := durationProto(*durs[i]) + data, err := Marshal(dproto) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} + +func size_slice_ref_duration(p *Properties, base structPointer) (n int) { + pdurs := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(durationType)).(*[]time.Duration) + durs := *pdurs + for i := 0; i < len(durs); i++ { + dproto := durationProto(durs[i]) + size := Size(dproto) + n += len(p.tagcode) + size + sizeVarint(uint64(size)) + } + return n +} + +func (o *Buffer) enc_slice_ref_duration(p *Properties, base structPointer) error { + pdurs := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(durationType)).(*[]time.Duration) + durs := *pdurs + for i := 0; i < len(durs); i++ { + dproto := durationProto(durs[i]) + data, err := Marshal(dproto) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/encode.go b/vendor/github.com/gogo/protobuf/proto/encode.go new file mode 100644 index 000000000..2b30f8462 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/encode.go @@ -0,0 +1,1362 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "errors" + "fmt" + "reflect" + "sort" +) + +// RequiredNotSetError is the error returned if Marshal is called with +// a protocol buffer struct whose required fields have not +// all been initialized. It is also the error returned if Unmarshal is +// called with an encoded protocol buffer that does not include all the +// required fields. +// +// When printed, RequiredNotSetError reports the first unset required field in a +// message. If the field cannot be precisely determined, it is reported as +// "{Unknown}". +type RequiredNotSetError struct { + field string +} + +func (e *RequiredNotSetError) Error() string { + return fmt.Sprintf("proto: required field %q not set", e.field) +} + +var ( + // errRepeatedHasNil is the error returned if Marshal is called with + // a struct with a repeated field containing a nil element. + errRepeatedHasNil = errors.New("proto: repeated field has nil element") + + // errOneofHasNil is the error returned if Marshal is called with + // a struct with a oneof field containing a nil element. + errOneofHasNil = errors.New("proto: oneof field has nil value") + + // ErrNil is the error returned if Marshal is called with nil. + ErrNil = errors.New("proto: Marshal called with nil") + + // ErrTooLarge is the error returned if Marshal is called with a + // message that encodes to >2GB. + ErrTooLarge = errors.New("proto: message encodes to over 2 GB") +) + +// The fundamental encoders that put bytes on the wire. +// Those that take integer types all accept uint64 and are +// therefore of type valueEncoder. + +const maxVarintBytes = 10 // maximum length of a varint + +// maxMarshalSize is the largest allowed size of an encoded protobuf, +// since C++ and Java use signed int32s for the size. +const maxMarshalSize = 1<<31 - 1 + +// EncodeVarint returns the varint encoding of x. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +// Not used by the package itself, but helpful to clients +// wishing to use the same encoding. +func EncodeVarint(x uint64) []byte { + var buf [maxVarintBytes]byte + var n int + for n = 0; x > 127; n++ { + buf[n] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + buf[n] = uint8(x) + n++ + return buf[0:n] +} + +// EncodeVarint writes a varint-encoded integer to the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) EncodeVarint(x uint64) error { + for x >= 1<<7 { + p.buf = append(p.buf, uint8(x&0x7f|0x80)) + x >>= 7 + } + p.buf = append(p.buf, uint8(x)) + return nil +} + +// SizeVarint returns the varint encoding size of an integer. +func SizeVarint(x uint64) int { + return sizeVarint(x) +} + +func sizeVarint(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} + +// EncodeFixed64 writes a 64-bit integer to the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) EncodeFixed64(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24), + uint8(x>>32), + uint8(x>>40), + uint8(x>>48), + uint8(x>>56)) + return nil +} + +func sizeFixed64(x uint64) int { + return 8 +} + +// EncodeFixed32 writes a 32-bit integer to the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) EncodeFixed32(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24)) + return nil +} + +func sizeFixed32(x uint64) int { + return 4 +} + +// EncodeZigzag64 writes a zigzag-encoded 64-bit integer +// to the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) EncodeZigzag64(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} + +func sizeZigzag64(x uint64) int { + return sizeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} + +// EncodeZigzag32 writes a zigzag-encoded 32-bit integer +// to the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) EncodeZigzag32(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +func sizeZigzag32(x uint64) int { + return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) EncodeRawBytes(b []byte) error { + p.EncodeVarint(uint64(len(b))) + p.buf = append(p.buf, b...) + return nil +} + +func sizeRawBytes(b []byte) int { + return sizeVarint(uint64(len(b))) + + len(b) +} + +// EncodeStringBytes writes an encoded string to the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) EncodeStringBytes(s string) error { + p.EncodeVarint(uint64(len(s))) + p.buf = append(p.buf, s...) + return nil +} + +func sizeStringBytes(s string) int { + return sizeVarint(uint64(len(s))) + + len(s) +} + +// Marshaler is the interface representing objects that can marshal themselves. +type Marshaler interface { + Marshal() ([]byte, error) +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, returning the data. +func Marshal(pb Message) ([]byte, error) { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + return m.Marshal() + } + p := NewBuffer(nil) + err := p.Marshal(pb) + if p.buf == nil && err == nil { + // Return a non-nil slice on success. + return []byte{}, nil + } + return p.buf, err +} + +// EncodeMessage writes the protocol buffer to the Buffer, +// prefixed by a varint-encoded length. +func (p *Buffer) EncodeMessage(pb Message) error { + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + var state errorState + err = p.enc_len_struct(GetProperties(t.Elem()), base, &state) + } + return err +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, writing the result to the +// Buffer. +func (p *Buffer) Marshal(pb Message) error { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + data, err := m.Marshal() + p.buf = append(p.buf, data...) + return err + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + err = p.enc_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + (stats).Encode++ // Parens are to work around a goimports bug. + } + + if len(p.buf) > maxMarshalSize { + return ErrTooLarge + } + return err +} + +// Size returns the encoded size of a protocol buffer. +func Size(pb Message) (n int) { + // Can the object marshal itself? If so, Size is slow. + // TODO: add Size to Marshaler, or add a Sizer interface. + if m, ok := pb.(Marshaler); ok { + b, _ := m.Marshal() + return len(b) + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return 0 + } + if err == nil { + n = size_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + (stats).Size++ // Parens are to work around a goimports bug. + } + + return +} + +// Individual type encoders. + +// Encode a bool. +func (o *Buffer) enc_bool(p *Properties, base structPointer) error { + v := *structPointer_Bool(base, p.field) + if v == nil { + return ErrNil + } + x := 0 + if *v { + x = 1 + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { + v := *structPointer_BoolVal(base, p.field) + if !v { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, 1) + return nil +} + +func size_bool(p *Properties, base structPointer) int { + v := *structPointer_Bool(base, p.field) + if v == nil { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +func size_proto3_bool(p *Properties, base structPointer) int { + v := *structPointer_BoolVal(base, p.field) + if !v && !p.oneof { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +// Encode an int32. +func (o *Buffer) enc_int32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode a uint32. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := word32_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := word32_Get(v) + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode an int64. +func (o *Buffer) enc_int64(p *Properties, base structPointer) error { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return ErrNil + } + x := word64_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func size_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return 0 + } + x := word64_Get(v) + n += len(p.tagcode) + n += p.valSize(x) + return +} + +func size_proto3_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(x) + return +} + +// Encode a string. +func (o *Buffer) enc_string(p *Properties, base structPointer) error { + v := *structPointer_String(base, p.field) + if v == nil { + return ErrNil + } + x := *v + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(x) + return nil +} + +func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { + v := *structPointer_StringVal(base, p.field) + if v == "" { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(v) + return nil +} + +func size_string(p *Properties, base structPointer) (n int) { + v := *structPointer_String(base, p.field) + if v == nil { + return 0 + } + x := *v + n += len(p.tagcode) + n += sizeStringBytes(x) + return +} + +func size_proto3_string(p *Properties, base structPointer) (n int) { + v := *structPointer_StringVal(base, p.field) + if v == "" && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeStringBytes(v) + return +} + +// All protocol buffer fields are nillable, but be careful. +func isNil(v reflect.Value) bool { + switch v.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + } + return false +} + +// Encode a message struct. +func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { + var state errorState + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return state.err + } + + o.buf = append(o.buf, p.tagcode...) + return o.enc_len_struct(p.sprop, structp, &state) +} + +func size_struct_message(p *Properties, base structPointer) int { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n0 := len(p.tagcode) + n1 := sizeRawBytes(data) + return n0 + n1 + } + + n0 := len(p.tagcode) + n1 := size_struct(p.sprop, structp) + n2 := sizeVarint(uint64(n1)) // size of encoded length + return n0 + n1 + n2 +} + +// Encode a group struct. +func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { + var state errorState + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return ErrNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + err := o.enc_struct(p.sprop, b) + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return state.err +} + +func size_struct_group(p *Properties, base structPointer) (n int) { + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return 0 + } + + n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) + n += size_struct(p.sprop, b) + n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return +} + +// Encode a slice of bools ([]bool). +func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + for _, x := range s { + o.buf = append(o.buf, p.tagcode...) + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_bool(p *Properties, base structPointer) int { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + return l * (len(p.tagcode) + 1) // each bool takes exactly one byte +} + +// Encode a slice of bools ([]bool) in packed format. +func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(l)) // each bool takes exactly one byte + for _, x := range s { + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_packed_bool(p *Properties, base structPointer) (n int) { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + n += len(p.tagcode) + n += sizeVarint(uint64(l)) + n += l // each bool takes exactly one byte + return +} + +// Encode a slice of bytes ([]byte). +func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func size_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if s == nil && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +// Encode a slice of int32s ([]int32). +func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of int32s ([]int32) in packed format. +func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(buf, uint64(x)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + bufSize += p.valSize(uint64(x)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of uint32s ([]uint32). +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := s.Index(i) + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := s.Index(i) + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of uint32s ([]uint32) in packed format. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, uint64(s.Index(i))) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(uint64(s.Index(i))) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of int64s ([]int64). +func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, s.Index(i)) + } + return nil +} + +func size_slice_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + n += p.valSize(s.Index(i)) + } + return +} + +// Encode a slice of int64s ([]int64) in packed format. +func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, s.Index(i)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(s.Index(i)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of slice of bytes ([][]byte). +func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(ss[i]) + } + return nil +} + +func size_slice_slice_byte(p *Properties, base structPointer) (n int) { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return 0 + } + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeRawBytes(ss[i]) + } + return +} + +// Encode a slice of strings ([]string). +func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(ss[i]) + } + return nil +} + +func size_slice_string(p *Properties, base structPointer) (n int) { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeStringBytes(ss[i]) + } + return +} + +// Encode a slice of message structs ([]*struct). +func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return errRepeatedHasNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + continue + } + + o.buf = append(o.buf, p.tagcode...) + err := o.enc_len_struct(p.sprop, structp, &state) + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + } + return state.err +} + +func size_slice_struct_message(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return // return the size up to this point + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n += sizeRawBytes(data) + continue + } + + n0 := size_struct(p.sprop, structp) + n1 := sizeVarint(uint64(n0)) // size of encoded length + n += n0 + n1 + } + return +} + +// Encode a slice of group structs ([]*struct). +func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return errRepeatedHasNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + + err := o.enc_struct(p.sprop, b) + + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + } + return state.err +} + +func size_slice_struct_group(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) + n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return // return size up to this point + } + + n += size_struct(p.sprop, b) + } + return +} + +// Encode an extension map. +func (o *Buffer) enc_map(p *Properties, base structPointer) error { + exts := structPointer_ExtMap(base, p.field) + if err := encodeExtensionsMap(*exts); err != nil { + return err + } + + return o.enc_map_body(*exts) +} + +func (o *Buffer) enc_exts(p *Properties, base structPointer) error { + exts := structPointer_Extensions(base, p.field) + + v, mu := exts.extensionsRead() + if v == nil { + return nil + } + + mu.Lock() + defer mu.Unlock() + if err := encodeExtensionsMap(v); err != nil { + return err + } + + return o.enc_map_body(v) +} + +func (o *Buffer) enc_map_body(v map[int32]Extension) error { + // Fast-path for common cases: zero or one extensions. + if len(v) <= 1 { + for _, e := range v { + o.buf = append(o.buf, e.enc...) + } + return nil + } + + // Sort keys to provide a deterministic encoding. + keys := make([]int, 0, len(v)) + for k := range v { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, k := range keys { + o.buf = append(o.buf, v[int32(k)].enc...) + } + return nil +} + +func size_map(p *Properties, base structPointer) int { + v := structPointer_ExtMap(base, p.field) + return extensionsMapSize(*v) +} + +func size_exts(p *Properties, base structPointer) int { + v := structPointer_Extensions(base, p.field) + return extensionsSize(v) +} + +// Encode a map field. +func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { + var state errorState // XXX: or do we need to plumb this through? + + /* + A map defined as + map map_field = N; + is encoded in the same way as + message MapFieldEntry { + key_type key = 1; + value_type value = 2; + } + repeated MapFieldEntry map_field = N; + */ + + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V + if v.Len() == 0 { + return nil + } + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + enc := func() error { + if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { + return err + } + if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { + return err + } + return nil + } + + // Don't sort map keys. It is not required by the spec, and C++ doesn't do it. + for _, key := range v.MapKeys() { + val := v.MapIndex(key) + + keycopy.Set(key) + valcopy.Set(val) + + o.buf = append(o.buf, p.tagcode...) + if err := o.enc_len_thing(enc, &state); err != nil { + return err + } + } + return nil +} + +func size_new_map(p *Properties, base structPointer) int { + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + n := 0 + for _, key := range v.MapKeys() { + val := v.MapIndex(key) + keycopy.Set(key) + valcopy.Set(val) + + // Tag codes for key and val are the responsibility of the sub-sizer. + keysize := p.mkeyprop.size(p.mkeyprop, keybase) + valsize := p.mvalprop.size(p.mvalprop, valbase) + entry := keysize + valsize + // Add on tag code and length of map entry itself. + n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry + } + return n +} + +// mapEncodeScratch returns a new reflect.Value matching the map's value type, +// and a structPointer suitable for passing to an encoder or sizer. +func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { + // Prepare addressable doubly-indirect placeholders for the key and value types. + // This is needed because the element-type encoders expect **T, but the map iteration produces T. + + keycopy = reflect.New(mapType.Key()).Elem() // addressable K + keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K + keyptr.Set(keycopy.Addr()) // + keybase = toStructPointer(keyptr.Addr()) // **K + + // Value types are more varied and require special handling. + switch mapType.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte + valbase = toStructPointer(valcopy.Addr()) + case reflect.Ptr: + // message; the generated field type is map[K]*Msg (so V is *Msg), + // so we only need one level of indirection. + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valbase = toStructPointer(valcopy.Addr()) + default: + // everything else + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V + valptr.Set(valcopy.Addr()) // + valbase = toStructPointer(valptr.Addr()) // **V + } + return +} + +// Encode a struct. +func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { + var state errorState + // Encode fields in tag order so that decoders may use optimizations + // that depend on the ordering. + // https://developers.google.com/protocol-buffers/docs/encoding#order + for _, i := range prop.order { + p := prop.Prop[i] + if p.enc != nil { + err := p.enc(o, p, base) + if err != nil { + if err == ErrNil { + if p.Required && state.err == nil { + state.err = &RequiredNotSetError{p.Name} + } + } else if err == errRepeatedHasNil { + // Give more context to nil values in repeated fields. + return errors.New("repeated field " + p.OrigName + " has nil element") + } else if !state.shouldContinue(err, p) { + return err + } + } + if len(o.buf) > maxMarshalSize { + return ErrTooLarge + } + } + } + + // Do oneof fields. + if prop.oneofMarshaler != nil { + m := structPointer_Interface(base, prop.stype).(Message) + if err := prop.oneofMarshaler(m, o); err == ErrNil { + return errOneofHasNil + } else if err != nil { + return err + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + if len(o.buf)+len(v) > maxMarshalSize { + return ErrTooLarge + } + if len(v) > 0 { + o.buf = append(o.buf, v...) + } + } + + return state.err +} + +func size_struct(prop *StructProperties, base structPointer) (n int) { + for _, i := range prop.order { + p := prop.Prop[i] + if p.size != nil { + n += p.size(p, base) + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + n += len(v) + } + + // Factor in any oneof fields. + if prop.oneofSizer != nil { + m := structPointer_Interface(base, prop.stype).(Message) + n += prop.oneofSizer(m) + } + + return +} + +var zeroes [20]byte // longer than any conceivable sizeVarint + +// Encode a struct, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { + return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) +} + +// Encode something, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { + iLen := len(o.buf) + o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length + iMsg := len(o.buf) + err := enc() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + lMsg := len(o.buf) - iMsg + lLen := sizeVarint(uint64(lMsg)) + switch x := lLen - (iMsg - iLen); { + case x > 0: // actual length is x bytes larger than the space we reserved + // Move msg x bytes right. + o.buf = append(o.buf, zeroes[:x]...) + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + case x < 0: // actual length is x bytes smaller than the space we reserved + // Move msg x bytes left. + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + o.buf = o.buf[:len(o.buf)+x] // x is negative + } + // Encode the length in the reserved space. + o.buf = o.buf[:iLen] + o.EncodeVarint(uint64(lMsg)) + o.buf = o.buf[:len(o.buf)+lMsg] + return state.err +} + +// errorState maintains the first error that occurs and updates that error +// with additional context. +type errorState struct { + err error +} + +// shouldContinue reports whether encoding should continue upon encountering the +// given error. If the error is RequiredNotSetError, shouldContinue returns true +// and, if this is the first appearance of that error, remembers it for future +// reporting. +// +// If prop is not nil, it may update any error with additional context about the +// field with the error. +func (s *errorState) shouldContinue(err error, prop *Properties) bool { + // Ignore unset required fields. + reqNotSet, ok := err.(*RequiredNotSetError) + if !ok { + return false + } + if s.err == nil { + if prop != nil { + err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} + } + s.err = err + } + return true +} diff --git a/vendor/github.com/gogo/protobuf/proto/encode_gogo.go b/vendor/github.com/gogo/protobuf/proto/encode_gogo.go new file mode 100644 index 000000000..32111b7f4 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/encode_gogo.go @@ -0,0 +1,350 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// http://github.com/golang/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "reflect" +) + +func NewRequiredNotSetError(field string) *RequiredNotSetError { + return &RequiredNotSetError{field} +} + +type Sizer interface { + Size() int +} + +func (o *Buffer) enc_ext_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return ErrNil + } + o.buf = append(o.buf, s...) + return nil +} + +func size_ext_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return 0 + } + n += len(s) + return +} + +// Encode a reference to bool pointer. +func (o *Buffer) enc_ref_bool(p *Properties, base structPointer) error { + v := *structPointer_BoolVal(base, p.field) + x := 0 + if v { + x = 1 + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_ref_bool(p *Properties, base structPointer) int { + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +// Encode a reference to int32 pointer. +func (o *Buffer) enc_ref_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_ref_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func (o *Buffer) enc_ref_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_ref_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode a reference to an int64 pointer. +func (o *Buffer) enc_ref_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func size_ref_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + n += len(p.tagcode) + n += p.valSize(x) + return +} + +// Encode a reference to a string pointer. +func (o *Buffer) enc_ref_string(p *Properties, base structPointer) error { + v := *structPointer_StringVal(base, p.field) + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(v) + return nil +} + +func size_ref_string(p *Properties, base structPointer) (n int) { + v := *structPointer_StringVal(base, p.field) + n += len(p.tagcode) + n += sizeStringBytes(v) + return +} + +// Encode a reference to a message struct. +func (o *Buffer) enc_ref_struct_message(p *Properties, base structPointer) error { + var state errorState + structp := structPointer_GetRefStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil + } + + o.buf = append(o.buf, p.tagcode...) + return o.enc_len_struct(p.sprop, structp, &state) +} + +//TODO this is only copied, please fix this +func size_ref_struct_message(p *Properties, base structPointer) int { + structp := structPointer_GetRefStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n0 := len(p.tagcode) + n1 := sizeRawBytes(data) + return n0 + n1 + } + + n0 := len(p.tagcode) + n1 := size_struct(p.sprop, structp) + n2 := sizeVarint(uint64(n1)) // size of encoded length + return n0 + n1 + n2 +} + +// Encode a slice of references to message struct pointers ([]struct). +func (o *Buffer) enc_slice_ref_struct_message(p *Properties, base structPointer) error { + var state errorState + ss := structPointer_StructRefSlice(base, p.field, p.stype.Size()) + l := ss.Len() + for i := 0; i < l; i++ { + structp := ss.Index(i) + if structPointer_IsNil(structp) { + return errRepeatedHasNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + continue + } + + o.buf = append(o.buf, p.tagcode...) + err := o.enc_len_struct(p.sprop, structp, &state) + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + + } + return state.err +} + +//TODO this is only copied, please fix this +func size_slice_ref_struct_message(p *Properties, base structPointer) (n int) { + ss := structPointer_StructRefSlice(base, p.field, p.stype.Size()) + l := ss.Len() + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + structp := ss.Index(i) + if structPointer_IsNil(structp) { + return // return the size up to this point + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n += len(p.tagcode) + n += sizeRawBytes(data) + continue + } + + n0 := size_struct(p.sprop, structp) + n1 := sizeVarint(uint64(n0)) // size of encoded length + n += n0 + n1 + } + return +} + +func (o *Buffer) enc_custom_bytes(p *Properties, base structPointer) error { + i := structPointer_InterfaceRef(base, p.field, p.ctype) + if i == nil { + return ErrNil + } + custom := i.(Marshaler) + data, err := custom.Marshal() + if err != nil { + return err + } + if data == nil { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_custom_bytes(p *Properties, base structPointer) (n int) { + n += len(p.tagcode) + i := structPointer_InterfaceRef(base, p.field, p.ctype) + if i == nil { + return 0 + } + custom := i.(Marshaler) + data, _ := custom.Marshal() + n += sizeRawBytes(data) + return +} + +func (o *Buffer) enc_custom_ref_bytes(p *Properties, base structPointer) error { + custom := structPointer_InterfaceAt(base, p.field, p.ctype).(Marshaler) + data, err := custom.Marshal() + if err != nil { + return err + } + if data == nil { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_custom_ref_bytes(p *Properties, base structPointer) (n int) { + n += len(p.tagcode) + i := structPointer_InterfaceAt(base, p.field, p.ctype) + if i == nil { + return 0 + } + custom := i.(Marshaler) + data, _ := custom.Marshal() + n += sizeRawBytes(data) + return +} + +func (o *Buffer) enc_custom_slice_bytes(p *Properties, base structPointer) error { + inter := structPointer_InterfaceRef(base, p.field, p.ctype) + if inter == nil { + return ErrNil + } + slice := reflect.ValueOf(inter) + l := slice.Len() + for i := 0; i < l; i++ { + v := slice.Index(i) + custom := v.Interface().(Marshaler) + data, err := custom.Marshal() + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} + +func size_custom_slice_bytes(p *Properties, base structPointer) (n int) { + inter := structPointer_InterfaceRef(base, p.field, p.ctype) + if inter == nil { + return 0 + } + slice := reflect.ValueOf(inter) + l := slice.Len() + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + v := slice.Index(i) + custom := v.Interface().(Marshaler) + data, _ := custom.Marshal() + n += sizeRawBytes(data) + } + return +} diff --git a/vendor/github.com/gogo/protobuf/proto/equal.go b/vendor/github.com/gogo/protobuf/proto/equal.go new file mode 100644 index 000000000..2ed1cf596 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/equal.go @@ -0,0 +1,300 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer comparison. + +package proto + +import ( + "bytes" + "log" + "reflect" + "strings" +) + +/* +Equal returns true iff protocol buffers a and b are equal. +The arguments must both be pointers to protocol buffer structs. + +Equality is defined in this way: + - Two messages are equal iff they are the same type, + corresponding fields are equal, unknown field sets + are equal, and extensions sets are equal. + - Two set scalar fields are equal iff their values are equal. + If the fields are of a floating-point type, remember that + NaN != x for all x, including NaN. If the message is defined + in a proto3 .proto file, fields are not "set"; specifically, + zero length proto3 "bytes" fields are equal (nil == {}). + - Two repeated fields are equal iff their lengths are the same, + and their corresponding elements are equal. Note a "bytes" field, + although represented by []byte, is not a repeated field and the + rule for the scalar fields described above applies. + - Two unset fields are equal. + - Two unknown field sets are equal if their current + encoded state is equal. + - Two extension sets are equal iff they have corresponding + elements that are pairwise equal. + - Two map fields are equal iff their lengths are the same, + and they contain the same set of elements. Zero-length map + fields are equal. + - Every other combination of things are not equal. + +The return value is undefined if a and b are not protocol buffers. +*/ +func Equal(a, b Message) bool { + if a == nil || b == nil { + return a == b + } + v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) + if v1.Type() != v2.Type() { + return false + } + if v1.Kind() == reflect.Ptr { + if v1.IsNil() { + return v2.IsNil() + } + if v2.IsNil() { + return false + } + v1, v2 = v1.Elem(), v2.Elem() + } + if v1.Kind() != reflect.Struct { + return false + } + return equalStruct(v1, v2) +} + +// v1 and v2 are known to have the same type. +func equalStruct(v1, v2 reflect.Value) bool { + sprop := GetProperties(v1.Type()) + for i := 0; i < v1.NumField(); i++ { + f := v1.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + f1, f2 := v1.Field(i), v2.Field(i) + if f.Type.Kind() == reflect.Ptr { + if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { + // both unset + continue + } else if n1 != n2 { + // set/unset mismatch + return false + } + b1, ok := f1.Interface().(raw) + if ok { + b2 := f2.Interface().(raw) + // RawMessage + if !bytes.Equal(b1.Bytes(), b2.Bytes()) { + return false + } + continue + } + f1, f2 = f1.Elem(), f2.Elem() + } + if !equalAny(f1, f2, sprop.Prop[i]) { + return false + } + } + + if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_InternalExtensions") + if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { + return false + } + } + + if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_extensions") + if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { + return false + } + } + + uf := v1.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return true + } + + u1 := uf.Bytes() + u2 := v2.FieldByName("XXX_unrecognized").Bytes() + if !bytes.Equal(u1, u2) { + return false + } + + return true +} + +// v1 and v2 are known to have the same type. +// prop may be nil. +func equalAny(v1, v2 reflect.Value, prop *Properties) bool { + if v1.Type() == protoMessageType { + m1, _ := v1.Interface().(Message) + m2, _ := v2.Interface().(Message) + return Equal(m1, m2) + } + switch v1.Kind() { + case reflect.Bool: + return v1.Bool() == v2.Bool() + case reflect.Float32, reflect.Float64: + return v1.Float() == v2.Float() + case reflect.Int32, reflect.Int64: + return v1.Int() == v2.Int() + case reflect.Interface: + // Probably a oneof field; compare the inner values. + n1, n2 := v1.IsNil(), v2.IsNil() + if n1 || n2 { + return n1 == n2 + } + e1, e2 := v1.Elem(), v2.Elem() + if e1.Type() != e2.Type() { + return false + } + return equalAny(e1, e2, nil) + case reflect.Map: + if v1.Len() != v2.Len() { + return false + } + for _, key := range v1.MapKeys() { + val2 := v2.MapIndex(key) + if !val2.IsValid() { + // This key was not found in the second map. + return false + } + if !equalAny(v1.MapIndex(key), val2, nil) { + return false + } + } + return true + case reflect.Ptr: + // Maps may have nil values in them, so check for nil. + if v1.IsNil() && v2.IsNil() { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return equalAny(v1.Elem(), v2.Elem(), prop) + case reflect.Slice: + if v1.Type().Elem().Kind() == reflect.Uint8 { + // short circuit: []byte + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value. + if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) + } + + if v1.Len() != v2.Len() { + return false + } + for i := 0; i < v1.Len(); i++ { + if !equalAny(v1.Index(i), v2.Index(i), prop) { + return false + } + } + return true + case reflect.String: + return v1.Interface().(string) == v2.Interface().(string) + case reflect.Struct: + return equalStruct(v1, v2) + case reflect.Uint32, reflect.Uint64: + return v1.Uint() == v2.Uint() + } + + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to compare %v", v1) + return false +} + +// base is the struct type that the extensions are based on. +// x1 and x2 are InternalExtensions. +func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { + em1, _ := x1.extensionsRead() + em2, _ := x2.extensionsRead() + return equalExtMap(base, em1, em2) +} + +func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { + if len(em1) != len(em2) { + return false + } + + for extNum, e1 := range em1 { + e2, ok := em2[extNum] + if !ok { + return false + } + + m1, m2 := e1.value, e2.value + + if m1 != nil && m2 != nil { + // Both are unencoded. + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + continue + } + + // At least one is encoded. To do a semantically correct comparison + // we need to unmarshal them first. + var desc *ExtensionDesc + if m := extensionMaps[base]; m != nil { + desc = m[extNum] + } + if desc == nil { + log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) + continue + } + var err error + if m1 == nil { + m1, err = decodeExtension(e1.enc, desc) + } + if m2 == nil && err == nil { + m2, err = decodeExtension(e2.enc, desc) + } + if err != nil { + // The encoded form is invalid. + log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) + return false + } + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + } + + return true +} diff --git a/vendor/github.com/gogo/protobuf/proto/extensions.go b/vendor/github.com/gogo/protobuf/proto/extensions.go new file mode 100644 index 000000000..0dfcb538e --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/extensions.go @@ -0,0 +1,693 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Types and routines for supporting protocol buffer extensions. + */ + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "sync" +) + +// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. +var ErrMissingExtension = errors.New("proto: missing extension") + +// ExtensionRange represents a range of message extensions for a protocol buffer. +// Used in code generated by the protocol compiler. +type ExtensionRange struct { + Start, End int32 // both inclusive +} + +// extendableProto is an interface implemented by any protocol buffer generated by the current +// proto compiler that may be extended. +type extendableProto interface { + Message + ExtensionRangeArray() []ExtensionRange + extensionsWrite() map[int32]Extension + extensionsRead() (map[int32]Extension, sync.Locker) +} + +// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous +// version of the proto compiler that may be extended. +type extendableProtoV1 interface { + Message + ExtensionRangeArray() []ExtensionRange + ExtensionMap() map[int32]Extension +} + +type extensionsBytes interface { + Message + ExtensionRangeArray() []ExtensionRange + GetExtensions() *[]byte +} + +// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. +type extensionAdapter struct { + extendableProtoV1 +} + +func (e extensionAdapter) extensionsWrite() map[int32]Extension { + return e.ExtensionMap() +} + +func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { + return e.ExtensionMap(), notLocker{} +} + +// notLocker is a sync.Locker whose Lock and Unlock methods are nops. +type notLocker struct{} + +func (n notLocker) Lock() {} +func (n notLocker) Unlock() {} + +// extendable returns the extendableProto interface for the given generated proto message. +// If the proto message has the old extension format, it returns a wrapper that implements +// the extendableProto interface. +func extendable(p interface{}) (extendableProto, bool) { + if ep, ok := p.(extendableProto); ok { + return ep, ok + } + if ep, ok := p.(extendableProtoV1); ok { + return extensionAdapter{ep}, ok + } + return nil, false +} + +// XXX_InternalExtensions is an internal representation of proto extensions. +// +// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, +// thus gaining the unexported 'extensions' method, which can be called only from the proto package. +// +// The methods of XXX_InternalExtensions are not concurrency safe in general, +// but calls to logically read-only methods such as has and get may be executed concurrently. +type XXX_InternalExtensions struct { + // The struct must be indirect so that if a user inadvertently copies a + // generated message and its embedded XXX_InternalExtensions, they + // avoid the mayhem of a copied mutex. + // + // The mutex serializes all logically read-only operations to p.extensionMap. + // It is up to the client to ensure that write operations to p.extensionMap are + // mutually exclusive with other accesses. + p *struct { + mu sync.Mutex + extensionMap map[int32]Extension + } +} + +// extensionsWrite returns the extension map, creating it on first use. +func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { + if e.p == nil { + e.p = new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }) + e.p.extensionMap = make(map[int32]Extension) + } + return e.p.extensionMap +} + +// extensionsRead returns the extensions map for read-only use. It may be nil. +// The caller must hold the returned mutex's lock when accessing Elements within the map. +func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { + if e.p == nil { + return nil, nil + } + return e.p.extensionMap, &e.p.mu +} + +type extensionRange interface { + Message + ExtensionRangeArray() []ExtensionRange +} + +var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() +var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() +var extendableBytesType = reflect.TypeOf((*extensionsBytes)(nil)).Elem() +var extensionRangeType = reflect.TypeOf((*extensionRange)(nil)).Elem() + +// ExtensionDesc represents an extension specification. +// Used in generated code from the protocol compiler. +type ExtensionDesc struct { + ExtendedType Message // nil pointer to the type that is being extended + ExtensionType interface{} // nil pointer to the extension type + Field int32 // field number + Name string // fully-qualified name of extension, for text formatting + Tag string // protobuf tag style + Filename string // name of the file in which the extension is defined +} + +func (ed *ExtensionDesc) repeated() bool { + t := reflect.TypeOf(ed.ExtensionType) + return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 +} + +// Extension represents an extension in a message. +type Extension struct { + // When an extension is stored in a message using SetExtension + // only desc and value are set. When the message is marshaled + // enc will be set to the encoded form of the message. + // + // When a message is unmarshaled and contains extensions, each + // extension will have only enc set. When such an extension is + // accessed using GetExtension (or GetExtensions) desc and value + // will be set. + desc *ExtensionDesc + value interface{} + enc []byte +} + +// SetRawExtension is for testing only. +func SetRawExtension(base Message, id int32, b []byte) { + if ebase, ok := base.(extensionsBytes); ok { + clearExtension(base, id) + ext := ebase.GetExtensions() + *ext = append(*ext, b...) + return + } + epb, ok := extendable(base) + if !ok { + return + } + extmap := epb.extensionsWrite() + extmap[id] = Extension{enc: b} +} + +// isExtensionField returns true iff the given field number is in an extension range. +func isExtensionField(pb extensionRange, field int32) bool { + for _, er := range pb.ExtensionRangeArray() { + if er.Start <= field && field <= er.End { + return true + } + } + return false +} + +// checkExtensionTypes checks that the given extension is valid for pb. +func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { + var pbi interface{} = pb + // Check the extended type. + if ea, ok := pbi.(extensionAdapter); ok { + pbi = ea.extendableProtoV1 + } + if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { + return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) + } + // Check the range. + if !isExtensionField(pb, extension.Field) { + return errors.New("proto: bad extension number; not in declared ranges") + } + return nil +} + +// extPropKey is sufficient to uniquely identify an extension. +type extPropKey struct { + base reflect.Type + field int32 +} + +var extProp = struct { + sync.RWMutex + m map[extPropKey]*Properties +}{ + m: make(map[extPropKey]*Properties), +} + +func extensionProperties(ed *ExtensionDesc) *Properties { + key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} + + extProp.RLock() + if prop, ok := extProp.m[key]; ok { + extProp.RUnlock() + return prop + } + extProp.RUnlock() + + extProp.Lock() + defer extProp.Unlock() + // Check again. + if prop, ok := extProp.m[key]; ok { + return prop + } + + prop := new(Properties) + prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) + extProp.m[key] = prop + return prop +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensions(e *XXX_InternalExtensions) error { + m, mu := e.extensionsRead() + if m == nil { + return nil // fast path + } + mu.Lock() + defer mu.Unlock() + return encodeExtensionsMap(m) +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensionsMap(m map[int32]Extension) error { + for k, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + p := NewBuffer(nil) + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + e.enc = p.buf + m[k] = e + } + return nil +} + +func extensionsSize(e *XXX_InternalExtensions) (n int) { + m, mu := e.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + defer mu.Unlock() + return extensionsMapSize(m) +} + +func extensionsMapSize(m map[int32]Extension) (n int) { + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + n += props.size(props, toStructPointer(x)) + } + return +} + +// HasExtension returns whether the given extension is present in pb. +func HasExtension(pb Message, extension *ExtensionDesc) bool { + if epb, doki := pb.(extensionsBytes); doki { + ext := epb.GetExtensions() + buf := *ext + o := 0 + for o < len(buf) { + tag, n := DecodeVarint(buf[o:]) + fieldNum := int32(tag >> 3) + if int32(fieldNum) == extension.Field { + return true + } + wireType := int(tag & 0x7) + o += n + l, err := size(buf[o:], wireType) + if err != nil { + return false + } + o += l + } + return false + } + // TODO: Check types, field numbers, etc.? + epb, ok := extendable(pb) + if !ok { + return false + } + extmap, mu := epb.extensionsRead() + if extmap == nil { + return false + } + mu.Lock() + _, ok = extmap[extension.Field] + mu.Unlock() + return ok +} + +func deleteExtension(pb extensionsBytes, theFieldNum int32, offset int) int { + ext := pb.GetExtensions() + for offset < len(*ext) { + tag, n1 := DecodeVarint((*ext)[offset:]) + fieldNum := int32(tag >> 3) + wireType := int(tag & 0x7) + n2, err := size((*ext)[offset+n1:], wireType) + if err != nil { + panic(err) + } + newOffset := offset + n1 + n2 + if fieldNum == theFieldNum { + *ext = append((*ext)[:offset], (*ext)[newOffset:]...) + return offset + } + offset = newOffset + } + return -1 +} + +// ClearExtension removes the given extension from pb. +func ClearExtension(pb Message, extension *ExtensionDesc) { + clearExtension(pb, extension.Field) +} + +func clearExtension(pb Message, fieldNum int32) { + if epb, doki := pb.(extensionsBytes); doki { + offset := 0 + for offset != -1 { + offset = deleteExtension(epb, fieldNum, offset) + } + return + } + epb, ok := extendable(pb) + if !ok { + return + } + // TODO: Check types, field numbers, etc.? + extmap := epb.extensionsWrite() + delete(extmap, fieldNum) +} + +// GetExtension parses and returns the given extension of pb. +// If the extension is not present and has no default value it returns ErrMissingExtension. +func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { + if epb, doki := pb.(extensionsBytes); doki { + ext := epb.GetExtensions() + o := 0 + for o < len(*ext) { + tag, n := DecodeVarint((*ext)[o:]) + fieldNum := int32(tag >> 3) + wireType := int(tag & 0x7) + l, err := size((*ext)[o+n:], wireType) + if err != nil { + return nil, err + } + if int32(fieldNum) == extension.Field { + v, err := decodeExtension((*ext)[o:o+n+l], extension) + if err != nil { + return nil, err + } + return v, nil + } + o += n + l + } + return defaultExtensionValue(extension) + } + epb, ok := extendable(pb) + if !ok { + return nil, errors.New("proto: not an extendable proto") + } + if err := checkExtensionTypes(epb, extension); err != nil { + return nil, err + } + + emap, mu := epb.extensionsRead() + if emap == nil { + return defaultExtensionValue(extension) + } + mu.Lock() + defer mu.Unlock() + e, ok := emap[extension.Field] + if !ok { + // defaultExtensionValue returns the default value or + // ErrMissingExtension if there is no default. + return defaultExtensionValue(extension) + } + + if e.value != nil { + // Already decoded. Check the descriptor, though. + if e.desc != extension { + // This shouldn't happen. If it does, it means that + // GetExtension was called twice with two different + // descriptors with the same field number. + return nil, errors.New("proto: descriptor conflict") + } + return e.value, nil + } + + v, err := decodeExtension(e.enc, extension) + if err != nil { + return nil, err + } + + // Remember the decoded version and drop the encoded version. + // That way it is safe to mutate what we return. + e.value = v + e.desc = extension + e.enc = nil + emap[extension.Field] = e + return e.value, nil +} + +// defaultExtensionValue returns the default value for extension. +// If no default for an extension is defined ErrMissingExtension is returned. +func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { + t := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + + sf, _, err := fieldDefault(t, props) + if err != nil { + return nil, err + } + + if sf == nil || sf.value == nil { + // There is no default value. + return nil, ErrMissingExtension + } + + if t.Kind() != reflect.Ptr { + // We do not need to return a Ptr, we can directly return sf.value. + return sf.value, nil + } + + // We need to return an interface{} that is a pointer to sf.value. + value := reflect.New(t).Elem() + value.Set(reflect.New(value.Type().Elem())) + if sf.kind == reflect.Int32 { + // We may have an int32 or an enum, but the underlying data is int32. + // Since we can't set an int32 into a non int32 reflect.value directly + // set it as a int32. + value.Elem().SetInt(int64(sf.value.(int32))) + } else { + value.Elem().Set(reflect.ValueOf(sf.value)) + } + return value.Interface(), nil +} + +// decodeExtension decodes an extension encoded in b. +func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { + o := NewBuffer(b) + + t := reflect.TypeOf(extension.ExtensionType) + + props := extensionProperties(extension) + + // t is a pointer to a struct, pointer to basic type or a slice. + // Allocate a "field" to store the pointer/slice itself; the + // pointer/slice will be stored here. We pass + // the address of this field to props.dec. + // This passes a zero field and a *t and lets props.dec + // interpret it as a *struct{ x t }. + value := reflect.New(t).Elem() + + for { + // Discard wire type and field number varint. It isn't needed. + if _, err := o.DecodeVarint(); err != nil { + return nil, err + } + + if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { + return nil, err + } + + if o.index >= len(o.buf) { + break + } + } + return value.Interface(), nil +} + +// GetExtensions returns a slice of the extensions present in pb that are also listed in es. +// The returned slice has the same length as es; missing extensions will appear as nil elements. +func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { + extensions = make([]interface{}, len(es)) + for i, e := range es { + extensions[i], err = GetExtension(pb, e) + if err == ErrMissingExtension { + err = nil + } + if err != nil { + return + } + } + return +} + +// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. +// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing +// just the Field field, which defines the extension's field number. +func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { + epb, ok := extendable(pb) + if !ok { + return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) + } + registeredExtensions := RegisteredExtensions(pb) + + emap, mu := epb.extensionsRead() + if emap == nil { + return nil, nil + } + mu.Lock() + defer mu.Unlock() + extensions := make([]*ExtensionDesc, 0, len(emap)) + for extid, e := range emap { + desc := e.desc + if desc == nil { + desc = registeredExtensions[extid] + if desc == nil { + desc = &ExtensionDesc{Field: extid} + } + } + + extensions = append(extensions, desc) + } + return extensions, nil +} + +// SetExtension sets the specified extension of pb to the specified value. +func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { + if epb, doki := pb.(extensionsBytes); doki { + ClearExtension(pb, extension) + ext := epb.GetExtensions() + et := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + p := NewBuffer(nil) + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + *ext = append(*ext, p.buf...) + return nil + } + epb, ok := extendable(pb) + if !ok { + return errors.New("proto: not an extendable proto") + } + if err := checkExtensionTypes(epb, extension); err != nil { + return err + } + typ := reflect.TypeOf(extension.ExtensionType) + if typ != reflect.TypeOf(value) { + return errors.New("proto: bad extension value type") + } + // nil extension values need to be caught early, because the + // encoder can't distinguish an ErrNil due to a nil extension + // from an ErrNil due to a missing field. Extensions are + // always optional, so the encoder would just swallow the error + // and drop all the extensions from the encoded message. + if reflect.ValueOf(value).IsNil() { + return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) + } + + extmap := epb.extensionsWrite() + extmap[extension.Field] = Extension{desc: extension, value: value} + return nil +} + +// ClearAllExtensions clears all extensions from pb. +func ClearAllExtensions(pb Message) { + if epb, doki := pb.(extensionsBytes); doki { + ext := epb.GetExtensions() + *ext = []byte{} + return + } + epb, ok := extendable(pb) + if !ok { + return + } + m := epb.extensionsWrite() + for k := range m { + delete(m, k) + } +} + +// A global registry of extensions. +// The generated code will register the generated descriptors by calling RegisterExtension. + +var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) + +// RegisterExtension is called from the generated code. +func RegisterExtension(desc *ExtensionDesc) { + st := reflect.TypeOf(desc.ExtendedType).Elem() + m := extensionMaps[st] + if m == nil { + m = make(map[int32]*ExtensionDesc) + extensionMaps[st] = m + } + if _, ok := m[desc.Field]; ok { + panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) + } + m[desc.Field] = desc +} + +// RegisteredExtensions returns a map of the registered extensions of a +// protocol buffer struct, indexed by the extension number. +// The argument pb should be a nil pointer to the struct type. +func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { + return extensionMaps[reflect.TypeOf(pb).Elem()] +} diff --git a/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go b/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go new file mode 100644 index 000000000..ea6478f00 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go @@ -0,0 +1,294 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "sort" + "strings" + "sync" +) + +func GetBoolExtension(pb Message, extension *ExtensionDesc, ifnotset bool) bool { + if reflect.ValueOf(pb).IsNil() { + return ifnotset + } + value, err := GetExtension(pb, extension) + if err != nil { + return ifnotset + } + if value == nil { + return ifnotset + } + if value.(*bool) == nil { + return ifnotset + } + return *(value.(*bool)) +} + +func (this *Extension) Equal(that *Extension) bool { + return bytes.Equal(this.enc, that.enc) +} + +func (this *Extension) Compare(that *Extension) int { + return bytes.Compare(this.enc, that.enc) +} + +func SizeOfInternalExtension(m extendableProto) (n int) { + return SizeOfExtensionMap(m.extensionsWrite()) +} + +func SizeOfExtensionMap(m map[int32]Extension) (n int) { + return extensionsMapSize(m) +} + +type sortableMapElem struct { + field int32 + ext Extension +} + +func newSortableExtensionsFromMap(m map[int32]Extension) sortableExtensions { + s := make(sortableExtensions, 0, len(m)) + for k, v := range m { + s = append(s, &sortableMapElem{field: k, ext: v}) + } + return s +} + +type sortableExtensions []*sortableMapElem + +func (this sortableExtensions) Len() int { return len(this) } + +func (this sortableExtensions) Swap(i, j int) { this[i], this[j] = this[j], this[i] } + +func (this sortableExtensions) Less(i, j int) bool { return this[i].field < this[j].field } + +func (this sortableExtensions) String() string { + sort.Sort(this) + ss := make([]string, len(this)) + for i := range this { + ss[i] = fmt.Sprintf("%d: %v", this[i].field, this[i].ext) + } + return "map[" + strings.Join(ss, ",") + "]" +} + +func StringFromInternalExtension(m extendableProto) string { + return StringFromExtensionsMap(m.extensionsWrite()) +} + +func StringFromExtensionsMap(m map[int32]Extension) string { + return newSortableExtensionsFromMap(m).String() +} + +func StringFromExtensionsBytes(ext []byte) string { + m, err := BytesToExtensionsMap(ext) + if err != nil { + panic(err) + } + return StringFromExtensionsMap(m) +} + +func EncodeInternalExtension(m extendableProto, data []byte) (n int, err error) { + return EncodeExtensionMap(m.extensionsWrite(), data) +} + +func EncodeExtensionMap(m map[int32]Extension, data []byte) (n int, err error) { + if err := encodeExtensionsMap(m); err != nil { + return 0, err + } + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + for _, k := range keys { + n += copy(data[n:], m[int32(k)].enc) + } + return n, nil +} + +func GetRawExtension(m map[int32]Extension, id int32) ([]byte, error) { + if m[id].value == nil || m[id].desc == nil { + return m[id].enc, nil + } + if err := encodeExtensionsMap(m); err != nil { + return nil, err + } + return m[id].enc, nil +} + +func size(buf []byte, wire int) (int, error) { + switch wire { + case WireVarint: + _, n := DecodeVarint(buf) + return n, nil + case WireFixed64: + return 8, nil + case WireBytes: + v, n := DecodeVarint(buf) + return int(v) + n, nil + case WireFixed32: + return 4, nil + case WireStartGroup: + offset := 0 + for { + u, n := DecodeVarint(buf[offset:]) + fwire := int(u & 0x7) + offset += n + if fwire == WireEndGroup { + return offset, nil + } + s, err := size(buf[offset:], wire) + if err != nil { + return 0, err + } + offset += s + } + } + return 0, fmt.Errorf("proto: can't get size for unknown wire type %d", wire) +} + +func BytesToExtensionsMap(buf []byte) (map[int32]Extension, error) { + m := make(map[int32]Extension) + i := 0 + for i < len(buf) { + tag, n := DecodeVarint(buf[i:]) + if n <= 0 { + return nil, fmt.Errorf("unable to decode varint") + } + fieldNum := int32(tag >> 3) + wireType := int(tag & 0x7) + l, err := size(buf[i+n:], wireType) + if err != nil { + return nil, err + } + end := i + int(l) + n + m[int32(fieldNum)] = Extension{enc: buf[i:end]} + i = end + } + return m, nil +} + +func NewExtension(e []byte) Extension { + ee := Extension{enc: make([]byte, len(e))} + copy(ee.enc, e) + return ee +} + +func AppendExtension(e Message, tag int32, buf []byte) { + if ee, eok := e.(extensionsBytes); eok { + ext := ee.GetExtensions() + *ext = append(*ext, buf...) + return + } + if ee, eok := e.(extendableProto); eok { + m := ee.extensionsWrite() + ext := m[int32(tag)] // may be missing + ext.enc = append(ext.enc, buf...) + m[int32(tag)] = ext + } +} + +func encodeExtension(e *Extension) error { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + return nil + } + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + p := NewBuffer(nil) + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + e.enc = p.buf + return nil +} + +func (this Extension) GoString() string { + if this.enc == nil { + if err := encodeExtension(&this); err != nil { + panic(err) + } + } + return fmt.Sprintf("proto.NewExtension(%#v)", this.enc) +} + +func SetUnsafeExtension(pb Message, fieldNum int32, value interface{}) error { + typ := reflect.TypeOf(pb).Elem() + ext, ok := extensionMaps[typ] + if !ok { + return fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String()) + } + desc, ok := ext[fieldNum] + if !ok { + return errors.New("proto: bad extension number; not in declared ranges") + } + return SetExtension(pb, desc, value) +} + +func GetUnsafeExtension(pb Message, fieldNum int32) (interface{}, error) { + typ := reflect.TypeOf(pb).Elem() + ext, ok := extensionMaps[typ] + if !ok { + return nil, fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String()) + } + desc, ok := ext[fieldNum] + if !ok { + return nil, fmt.Errorf("unregistered field number %d", fieldNum) + } + return GetExtension(pb, desc) +} + +func NewUnsafeXXX_InternalExtensions(m map[int32]Extension) XXX_InternalExtensions { + x := &XXX_InternalExtensions{ + p: new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }), + } + x.p.extensionMap = m + return *x +} + +func GetUnsafeExtensionsMap(extendable Message) map[int32]Extension { + pb := extendable.(extendableProto) + return pb.extensionsWrite() +} diff --git a/vendor/github.com/gogo/protobuf/proto/lib.go b/vendor/github.com/gogo/protobuf/proto/lib.go new file mode 100644 index 000000000..7580bb45c --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/lib.go @@ -0,0 +1,898 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* +Package proto converts data structures to and from the wire format of +protocol buffers. It works in concert with the Go source code generated +for .proto files by the protocol compiler. + +A summary of the properties of the protocol buffer interface +for a protocol buffer variable v: + + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. + - Nested messages, groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Oneof field sets are given a single field in their message, + with distinguished wrapper types for each possible field value. + - Marshal and Unmarshal are functions to encode and decode the wire format. + +When the .proto file specifies `syntax="proto3"`, there are some differences: + + - Non-repeated fields of non-message type are values instead of pointers. + - Getters are only generated for message and oneof fields. + - Enum types do not get an Enum method. + +The simplest way to describe this is to see an example. +Given file test.proto, containing + + package example; + + enum FOO { X = 17; } + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + oneof union { + int32 number = 6; + string name = 7; + } + } + +The resulting file, test.pb.go, is: + + package example + + import proto "github.com/gogo/protobuf/proto" + import math "math" + + type FOO int32 + const ( + FOO_X FOO = 17 + ) + var FOO_name = map[int32]string{ + 17: "X", + } + var FOO_value = map[string]int32{ + "X": 17, + } + + func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p + } + func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) + } + func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data) + if err != nil { + return err + } + *x = FOO(value) + return nil + } + + type Test struct { + Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` + Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` + Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` + Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` + // Types that are valid to be assigned to Union: + // *Test_Number + // *Test_Name + Union isTest_Union `protobuf_oneof:"union"` + XXX_unrecognized []byte `json:"-"` + } + func (m *Test) Reset() { *m = Test{} } + func (m *Test) String() string { return proto.CompactTextString(m) } + func (*Test) ProtoMessage() {} + + type isTest_Union interface { + isTest_Union() + } + + type Test_Number struct { + Number int32 `protobuf:"varint,6,opt,name=number"` + } + type Test_Name struct { + Name string `protobuf:"bytes,7,opt,name=name"` + } + + func (*Test_Number) isTest_Union() {} + func (*Test_Name) isTest_Union() {} + + func (m *Test) GetUnion() isTest_Union { + if m != nil { + return m.Union + } + return nil + } + const Default_Test_Type int32 = 77 + + func (m *Test) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" + } + + func (m *Test) GetType() int32 { + if m != nil && m.Type != nil { + return *m.Type + } + return Default_Test_Type + } + + func (m *Test) GetOptionalgroup() *Test_OptionalGroup { + if m != nil { + return m.Optionalgroup + } + return nil + } + + type Test_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` + } + func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } + func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } + + func (m *Test_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" + } + + func (m *Test) GetNumber() int32 { + if x, ok := m.GetUnion().(*Test_Number); ok { + return x.Number + } + return 0 + } + + func (m *Test) GetName() string { + if x, ok := m.GetUnion().(*Test_Name); ok { + return x.Name + } + return "" + } + + func init() { + proto.RegisterEnum("example.FOO", FOO_name, FOO_value) + } + +To create and play with a Test object: + + package main + + import ( + "log" + + "github.com/gogo/protobuf/proto" + pb "./example.pb" + ) + + func main() { + test := &pb.Test{ + Label: proto.String("hello"), + Type: proto.Int32(17), + Reps: []int64{1, 2, 3}, + Optionalgroup: &pb.Test_OptionalGroup{ + RequiredField: proto.String("good bye"), + }, + Union: &pb.Test_Name{"fred"}, + } + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) + } + newTest := &pb.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) + } + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) + } + // Use a type switch to determine which oneof was set. + switch u := test.Union.(type) { + case *pb.Test_Number: // u.Number contains the number. + case *pb.Test_Name: // u.Name contains the string. + } + // etc. + } +*/ +package proto + +import ( + "encoding/json" + "fmt" + "log" + "reflect" + "sort" + "strconv" + "sync" +) + +// Message is implemented by generated protocol buffer messages. +type Message interface { + Reset() + String() string + ProtoMessage() +} + +// Stats records allocation details about the protocol buffer encoders +// and decoders. Useful for tuning the library itself. +type Stats struct { + Emalloc uint64 // mallocs in encode + Dmalloc uint64 // mallocs in decode + Encode uint64 // number of encodes + Decode uint64 // number of decodes + Chit uint64 // number of cache hits + Cmiss uint64 // number of cache misses + Size uint64 // number of sizes +} + +// Set to true to enable stats collection. +const collectStats = false + +var stats Stats + +// GetStats returns a copy of the global Stats structure. +func GetStats() Stats { return stats } + +// A Buffer is a buffer manager for marshaling and unmarshaling +// protocol buffers. It may be reused between invocations to +// reduce memory usage. It is not necessary to use a Buffer; +// the global functions Marshal and Unmarshal create a +// temporary Buffer and are fine for most applications. +type Buffer struct { + buf []byte // encode/decode byte stream + index int // read point + + // pools of basic types to amortize allocation. + bools []bool + uint32s []uint32 + uint64s []uint64 + + // extra pools, only used with pointer_reflect.go + int32s []int32 + int64s []int64 + float32s []float32 + float64s []float64 +} + +// NewBuffer allocates a new Buffer and initializes its internal data to +// the contents of the argument slice. +func NewBuffer(e []byte) *Buffer { + return &Buffer{buf: e} +} + +// Reset resets the Buffer, ready for marshaling a new protocol buffer. +func (p *Buffer) Reset() { + p.buf = p.buf[0:0] // for reading/writing + p.index = 0 // for reading +} + +// SetBuf replaces the internal buffer with the slice, +// ready for unmarshaling the contents of the slice. +func (p *Buffer) SetBuf(s []byte) { + p.buf = s + p.index = 0 +} + +// Bytes returns the contents of the Buffer. +func (p *Buffer) Bytes() []byte { return p.buf } + +/* + * Helper routines for simplifying the creation of optional fields of basic type. + */ + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { + return &v +} + +// Int32 is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it. +func Int32(v int32) *int32 { + return &v +} + +// Int is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it, but unlike Int32 +// its argument value is an int. +func Int(v int) *int32 { + p := new(int32) + *p = int32(v) + return p +} + +// Int64 is a helper routine that allocates a new int64 value +// to store v and returns a pointer to it. +func Int64(v int64) *int64 { + return &v +} + +// Float32 is a helper routine that allocates a new float32 value +// to store v and returns a pointer to it. +func Float32(v float32) *float32 { + return &v +} + +// Float64 is a helper routine that allocates a new float64 value +// to store v and returns a pointer to it. +func Float64(v float64) *float64 { + return &v +} + +// Uint32 is a helper routine that allocates a new uint32 value +// to store v and returns a pointer to it. +func Uint32(v uint32) *uint32 { + return &v +} + +// Uint64 is a helper routine that allocates a new uint64 value +// to store v and returns a pointer to it. +func Uint64(v uint64) *uint64 { + return &v +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { + return &v +} + +// EnumName is a helper function to simplify printing protocol buffer enums +// by name. Given an enum map and a value, it returns a useful string. +func EnumName(m map[int32]string, v int32) string { + s, ok := m[v] + if ok { + return s + } + return strconv.Itoa(int(v)) +} + +// UnmarshalJSONEnum is a helper function to simplify recovering enum int values +// from their JSON-encoded representation. Given a map from the enum's symbolic +// names to its int values, and a byte buffer containing the JSON-encoded +// value, it returns an int32 that can be cast to the enum type by the caller. +// +// The function can deal with both JSON representations, numeric and symbolic. +func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { + if data[0] == '"' { + // New style: enums are strings. + var repr string + if err := json.Unmarshal(data, &repr); err != nil { + return -1, err + } + val, ok := m[repr] + if !ok { + return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) + } + return val, nil + } + // Old style: enums are ints. + var val int32 + if err := json.Unmarshal(data, &val); err != nil { + return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) + } + return val, nil +} + +// DebugPrint dumps the encoded data in b in a debugging format with a header +// including the string s. Used in testing but made available for general debugging. +func (p *Buffer) DebugPrint(s string, b []byte) { + var u uint64 + + obuf := p.buf + sindex := p.index + p.buf = b + p.index = 0 + depth := 0 + + fmt.Printf("\n--- %s ---\n", s) + +out: + for { + for i := 0; i < depth; i++ { + fmt.Print(" ") + } + + index := p.index + if index == len(p.buf) { + break + } + + op, err := p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: fetching op err %v\n", index, err) + break out + } + tag := op >> 3 + wire := op & 7 + + switch wire { + default: + fmt.Printf("%3d: t=%3d unknown wire=%d\n", + index, tag, wire) + break out + + case WireBytes: + var r []byte + + r, err = p.DecodeRawBytes(false) + if err != nil { + break out + } + fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) + if len(r) <= 6 { + for i := 0; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } else { + for i := 0; i < 3; i++ { + fmt.Printf(" %.2x", r[i]) + } + fmt.Printf(" ..") + for i := len(r) - 3; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } + fmt.Printf("\n") + + case WireFixed32: + u, err = p.DecodeFixed32() + if err != nil { + fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) + + case WireFixed64: + u, err = p.DecodeFixed64() + if err != nil { + fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) + + case WireVarint: + u, err = p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) + + case WireStartGroup: + fmt.Printf("%3d: t=%3d start\n", index, tag) + depth++ + + case WireEndGroup: + depth-- + fmt.Printf("%3d: t=%3d end\n", index, tag) + } + } + + if depth != 0 { + fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) + } + fmt.Printf("\n") + + p.buf = obuf + p.index = sindex +} + +// SetDefaults sets unset protocol buffer fields to their default values. +// It only modifies fields that are both unset and have defined defaults. +// It recursively sets default values in any non-nil sub-messages. +func SetDefaults(pb Message) { + setDefaults(reflect.ValueOf(pb), true, false) +} + +// v is a pointer to a struct. +func setDefaults(v reflect.Value, recur, zeros bool) { + v = v.Elem() + + defaultMu.RLock() + dm, ok := defaults[v.Type()] + defaultMu.RUnlock() + if !ok { + dm = buildDefaultMessage(v.Type()) + defaultMu.Lock() + defaults[v.Type()] = dm + defaultMu.Unlock() + } + + for _, sf := range dm.scalars { + f := v.Field(sf.index) + if !f.IsNil() { + // field already set + continue + } + dv := sf.value + if dv == nil && !zeros { + // no explicit default, and don't want to set zeros + continue + } + fptr := f.Addr().Interface() // **T + // TODO: Consider batching the allocations we do here. + switch sf.kind { + case reflect.Bool: + b := new(bool) + if dv != nil { + *b = dv.(bool) + } + *(fptr.(**bool)) = b + case reflect.Float32: + f := new(float32) + if dv != nil { + *f = dv.(float32) + } + *(fptr.(**float32)) = f + case reflect.Float64: + f := new(float64) + if dv != nil { + *f = dv.(float64) + } + *(fptr.(**float64)) = f + case reflect.Int32: + // might be an enum + if ft := f.Type(); ft != int32PtrType { + // enum + f.Set(reflect.New(ft.Elem())) + if dv != nil { + f.Elem().SetInt(int64(dv.(int32))) + } + } else { + // int32 field + i := new(int32) + if dv != nil { + *i = dv.(int32) + } + *(fptr.(**int32)) = i + } + case reflect.Int64: + i := new(int64) + if dv != nil { + *i = dv.(int64) + } + *(fptr.(**int64)) = i + case reflect.String: + s := new(string) + if dv != nil { + *s = dv.(string) + } + *(fptr.(**string)) = s + case reflect.Uint8: + // exceptional case: []byte + var b []byte + if dv != nil { + db := dv.([]byte) + b = make([]byte, len(db)) + copy(b, db) + } else { + b = []byte{} + } + *(fptr.(*[]byte)) = b + case reflect.Uint32: + u := new(uint32) + if dv != nil { + *u = dv.(uint32) + } + *(fptr.(**uint32)) = u + case reflect.Uint64: + u := new(uint64) + if dv != nil { + *u = dv.(uint64) + } + *(fptr.(**uint64)) = u + default: + log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) + } + } + + for _, ni := range dm.nested { + f := v.Field(ni) + // f is *T or []*T or map[T]*T + switch f.Kind() { + case reflect.Ptr: + if f.IsNil() { + continue + } + setDefaults(f, recur, zeros) + + case reflect.Slice: + for i := 0; i < f.Len(); i++ { + e := f.Index(i) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + + case reflect.Map: + for _, k := range f.MapKeys() { + e := f.MapIndex(k) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + } + } +} + +var ( + // defaults maps a protocol buffer struct type to a slice of the fields, + // with its scalar fields set to their proto-declared non-zero default values. + defaultMu sync.RWMutex + defaults = make(map[reflect.Type]defaultMessage) + + int32PtrType = reflect.TypeOf((*int32)(nil)) +) + +// defaultMessage represents information about the default values of a message. +type defaultMessage struct { + scalars []scalarField + nested []int // struct field index of nested messages +} + +type scalarField struct { + index int // struct field index + kind reflect.Kind // element type (the T in *T or []T) + value interface{} // the proto-declared default value, or nil +} + +// t is a struct type. +func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { + sprop := GetProperties(t) + for _, prop := range sprop.Prop { + fi, ok := sprop.decoderTags.get(prop.Tag) + if !ok { + // XXX_unrecognized + continue + } + ft := t.Field(fi).Type + + sf, nested, err := fieldDefault(ft, prop) + switch { + case err != nil: + log.Print(err) + case nested: + dm.nested = append(dm.nested, fi) + case sf != nil: + sf.index = fi + dm.scalars = append(dm.scalars, *sf) + } + } + + return dm +} + +// fieldDefault returns the scalarField for field type ft. +// sf will be nil if the field can not have a default. +// nestedMessage will be true if this is a nested message. +// Note that sf.index is not set on return. +func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { + var canHaveDefault bool + switch ft.Kind() { + case reflect.Ptr: + if ft.Elem().Kind() == reflect.Struct { + nestedMessage = true + } else { + canHaveDefault = true // proto2 scalar field + } + + case reflect.Slice: + switch ft.Elem().Kind() { + case reflect.Ptr: + nestedMessage = true // repeated message + case reflect.Uint8: + canHaveDefault = true // bytes field + } + + case reflect.Map: + if ft.Elem().Kind() == reflect.Ptr { + nestedMessage = true // map with message values + } + } + + if !canHaveDefault { + if nestedMessage { + return nil, true, nil + } + return nil, false, nil + } + + // We now know that ft is a pointer or slice. + sf = &scalarField{kind: ft.Elem().Kind()} + + // scalar fields without defaults + if !prop.HasDefault { + return sf, false, nil + } + + // a scalar field: either *T or []byte + switch ft.Elem().Kind() { + case reflect.Bool: + x, err := strconv.ParseBool(prop.Default) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Float32: + x, err := strconv.ParseFloat(prop.Default, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) + } + sf.value = float32(x) + case reflect.Float64: + x, err := strconv.ParseFloat(prop.Default, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Int32: + x, err := strconv.ParseInt(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) + } + sf.value = int32(x) + case reflect.Int64: + x, err := strconv.ParseInt(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.String: + sf.value = prop.Default + case reflect.Uint8: + // []byte (not *uint8) + sf.value = []byte(prop.Default) + case reflect.Uint32: + x, err := strconv.ParseUint(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) + } + sf.value = uint32(x) + case reflect.Uint64: + x, err := strconv.ParseUint(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) + } + sf.value = x + default: + return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) + } + + return sf, false, nil +} + +// Map fields may have key types of non-float scalars, strings and enums. +// The easiest way to sort them in some deterministic order is to use fmt. +// If this turns out to be inefficient we can always consider other options, +// such as doing a Schwartzian transform. + +func mapKeys(vs []reflect.Value) sort.Interface { + s := mapKeySorter{ + vs: vs, + // default Less function: textual comparison + less: func(a, b reflect.Value) bool { + return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) + }, + } + + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; + // numeric keys are sorted numerically. + if len(vs) == 0 { + return s + } + switch vs[0].Kind() { + case reflect.Int32, reflect.Int64: + s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } + case reflect.Uint32, reflect.Uint64: + s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } + } + + return s +} + +type mapKeySorter struct { + vs []reflect.Value + less func(a, b reflect.Value) bool +} + +func (s mapKeySorter) Len() int { return len(s.vs) } +func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } +func (s mapKeySorter) Less(i, j int) bool { + return s.less(s.vs[i], s.vs[j]) +} + +// isProto3Zero reports whether v is a zero proto3 value. +func isProto3Zero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint32, reflect.Uint64: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.String: + return v.String() == "" + } + return false +} + +// ProtoPackageIsVersion2 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const GoGoProtoPackageIsVersion2 = true + +// ProtoPackageIsVersion1 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const GoGoProtoPackageIsVersion1 = true diff --git a/vendor/github.com/gogo/protobuf/proto/lib_gogo.go b/vendor/github.com/gogo/protobuf/proto/lib_gogo.go new file mode 100644 index 000000000..4b4f7c909 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/lib_gogo.go @@ -0,0 +1,42 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "encoding/json" + "strconv" +) + +func MarshalJSONEnum(m map[int32]string, value int32) ([]byte, error) { + s, ok := m[value] + if !ok { + s = strconv.Itoa(int(value)) + } + return json.Marshal(s) +} diff --git a/vendor/github.com/gogo/protobuf/proto/message_set.go b/vendor/github.com/gogo/protobuf/proto/message_set.go new file mode 100644 index 000000000..fd982decd --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/message_set.go @@ -0,0 +1,311 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Support for message sets. + */ + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" +) + +// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. +// A message type ID is required for storing a protocol buffer in a message set. +var errNoMessageTypeID = errors.New("proto does not have a message type ID") + +// The first two types (_MessageSet_Item and messageSet) +// model what the protocol compiler produces for the following protocol message: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } +// That is the MessageSet wire format. We can't use a proto to generate these +// because that would introduce a circular dependency between it and this package. + +type _MessageSet_Item struct { + TypeId *int32 `protobuf:"varint,2,req,name=type_id"` + Message []byte `protobuf:"bytes,3,req,name=message"` +} + +type messageSet struct { + Item []*_MessageSet_Item `protobuf:"group,1,rep"` + XXX_unrecognized []byte + // TODO: caching? +} + +// Make sure messageSet is a Message. +var _ Message = (*messageSet)(nil) + +// messageTypeIder is an interface satisfied by a protocol buffer type +// that may be stored in a MessageSet. +type messageTypeIder interface { + MessageTypeId() int32 +} + +func (ms *messageSet) find(pb Message) *_MessageSet_Item { + mti, ok := pb.(messageTypeIder) + if !ok { + return nil + } + id := mti.MessageTypeId() + for _, item := range ms.Item { + if *item.TypeId == id { + return item + } + } + return nil +} + +func (ms *messageSet) Has(pb Message) bool { + if ms.find(pb) != nil { + return true + } + return false +} + +func (ms *messageSet) Unmarshal(pb Message) error { + if item := ms.find(pb); item != nil { + return Unmarshal(item.Message, pb) + } + if _, ok := pb.(messageTypeIder); !ok { + return errNoMessageTypeID + } + return nil // TODO: return error instead? +} + +func (ms *messageSet) Marshal(pb Message) error { + msg, err := Marshal(pb) + if err != nil { + return err + } + if item := ms.find(pb); item != nil { + // reuse existing item + item.Message = msg + return nil + } + + mti, ok := pb.(messageTypeIder) + if !ok { + return errNoMessageTypeID + } + + mtid := mti.MessageTypeId() + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: &mtid, + Message: msg, + }) + return nil +} + +func (ms *messageSet) Reset() { *ms = messageSet{} } +func (ms *messageSet) String() string { return CompactTextString(ms) } +func (*messageSet) ProtoMessage() {} + +// Support for the message_set_wire_format message option. + +func skipVarint(buf []byte) []byte { + i := 0 + for ; buf[i]&0x80 != 0; i++ { + } + return buf[i+1:] +} + +// MarshalMessageSet encodes the extension map represented by m in the message set wire format. +// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSet(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + if err := encodeExtensions(exts); err != nil { + return nil, err + } + m, _ = exts.extensionsRead() + case map[int32]Extension: + if err := encodeExtensionsMap(exts); err != nil { + return nil, err + } + m = exts + default: + return nil, errors.New("proto: not an extension map") + } + + // Sort extension IDs to provide a deterministic encoding. + // See also enc_map in encode.go. + ids := make([]int, 0, len(m)) + for id := range m { + ids = append(ids, int(id)) + } + sort.Ints(ids) + + ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} + for _, id := range ids { + e := m[int32(id)] + // Remove the wire type and field number varint, as well as the length varint. + msg := skipVarint(skipVarint(e.enc)) + + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: Int32(int32(id)), + Message: msg, + }) + } + return Marshal(ms) +} + +// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSet(buf []byte, exts interface{}) error { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m = exts.extensionsWrite() + case map[int32]Extension: + m = exts + default: + return errors.New("proto: not an extension map") + } + + ms := new(messageSet) + if err := Unmarshal(buf, ms); err != nil { + return err + } + for _, item := range ms.Item { + id := *item.TypeId + msg := item.Message + + // Restore wire type and field number varint, plus length varint. + // Be careful to preserve duplicate items. + b := EncodeVarint(uint64(id)<<3 | WireBytes) + if ext, ok := m[id]; ok { + // Existing data; rip off the tag and length varint + // so we join the new data correctly. + // We can assume that ext.enc is set because we are unmarshaling. + o := ext.enc[len(b):] // skip wire type and field number + _, n := DecodeVarint(o) // calculate length of length varint + o = o[n:] // skip length varint + msg = append(o, msg...) // join old data and new data + } + b = append(b, EncodeVarint(uint64(len(msg)))...) + b = append(b, msg...) + + m[id] = Extension{enc: b} + } + return nil +} + +// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. +// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m, _ = exts.extensionsRead() + case map[int32]Extension: + m = exts + default: + return nil, errors.New("proto: not an extension map") + } + var b bytes.Buffer + b.WriteByte('{') + + // Process the map in key order for deterministic output. + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) // int32Slice defined in text.go + + for i, id := range ids { + ext := m[id] + if i > 0 { + b.WriteByte(',') + } + + msd, ok := messageSetMap[id] + if !ok { + // Unknown type; we can't render it, so skip it. + continue + } + fmt.Fprintf(&b, `"[%s]":`, msd.name) + + x := ext.value + if x == nil { + x = reflect.New(msd.t.Elem()).Interface() + if err := Unmarshal(ext.enc, x.(Message)); err != nil { + return nil, err + } + } + d, err := json.Marshal(x) + if err != nil { + return nil, err + } + b.Write(d) + } + b.WriteByte('}') + return b.Bytes(), nil +} + +// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. +// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { + // Common-case fast path. + if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { + return nil + } + + // This is fairly tricky, and it's not clear that it is needed. + return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") +} + +// A global registry of types that can be used in a MessageSet. + +var messageSetMap = make(map[int32]messageSetDesc) + +type messageSetDesc struct { + t reflect.Type // pointer to struct + name string +} + +// RegisterMessageSetType is called from the generated code. +func RegisterMessageSetType(m Message, fieldNum int32, name string) { + messageSetMap[fieldNum] = messageSetDesc{ + t: reflect.TypeOf(m), + name: name, + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go new file mode 100644 index 000000000..fb512e2e1 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go @@ -0,0 +1,484 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build appengine js + +// This file contains an implementation of proto field accesses using package reflect. +// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can +// be used on App Engine. + +package proto + +import ( + "math" + "reflect" +) + +// A structPointer is a pointer to a struct. +type structPointer struct { + v reflect.Value +} + +// toStructPointer returns a structPointer equivalent to the given reflect value. +// The reflect value must itself be a pointer to a struct. +func toStructPointer(v reflect.Value) structPointer { + return structPointer{v} +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p.v.IsNil() +} + +// Interface returns the struct pointer as an interface value. +func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { + return p.v.Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by the sequence of field indices +// passed to reflect's FieldByIndex. +type field []int + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return f.Index +} + +// invalidField is an invalid field identifier. +var invalidField = field(nil) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { return f != nil } + +// field returns the given field in the struct as a reflect value. +func structPointer_field(p structPointer, f field) reflect.Value { + // Special case: an extension map entry with a value of type T + // passes a *T to the struct-handling code with a zero field, + // expecting that it will be treated as equivalent to *struct{ X T }, + // which has the same memory layout. We have to handle that case + // specially, because reflect will panic if we call FieldByIndex on a + // non-struct. + if f == nil { + return p.v.Elem() + } + + return p.v.Elem().FieldByIndex(f) +} + +// ifield returns the given field in the struct as an interface value. +func structPointer_ifield(p structPointer, f field) interface{} { + return structPointer_field(p, f).Addr().Interface() +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return structPointer_ifield(p, f).(*[]byte) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return structPointer_ifield(p, f).(*[][]byte) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return structPointer_ifield(p, f).(**bool) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return structPointer_ifield(p, f).(*bool) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return structPointer_ifield(p, f).(*[]bool) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return structPointer_ifield(p, f).(**string) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return structPointer_ifield(p, f).(*string) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return structPointer_ifield(p, f).(*[]string) +} + +// Extensions returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return structPointer_ifield(p, f).(*XXX_InternalExtensions) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return structPointer_ifield(p, f).(*map[int32]Extension) +} + +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { + return structPointer_field(p, f).Addr() +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + structPointer_field(p, f).Set(q.v) +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return structPointer{structPointer_field(p, f)} +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { + return structPointerSlice{structPointer_field(p, f)} +} + +// A structPointerSlice represents the address of a slice of pointers to structs +// (themselves messages or groups). That is, v.Type() is *[]*struct{...}. +type structPointerSlice struct { + v reflect.Value +} + +func (p structPointerSlice) Len() int { return p.v.Len() } +func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } +func (p structPointerSlice) Append(q structPointer) { + p.v.Set(reflect.Append(p.v, q.v)) +} + +var ( + int32Type = reflect.TypeOf(int32(0)) + uint32Type = reflect.TypeOf(uint32(0)) + float32Type = reflect.TypeOf(float32(0)) + int64Type = reflect.TypeOf(int64(0)) + uint64Type = reflect.TypeOf(uint64(0)) + float64Type = reflect.TypeOf(float64(0)) +) + +// A word32 represents a field of type *int32, *uint32, *float32, or *enum. +// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. +type word32 struct { + v reflect.Value +} + +// IsNil reports whether p is nil. +func word32_IsNil(p word32) bool { + return p.v.IsNil() +} + +// Set sets p to point at a newly allocated word with bits set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + t := p.v.Type().Elem() + switch t { + case int32Type: + if len(o.int32s) == 0 { + o.int32s = make([]int32, uint32PoolSize) + } + o.int32s[0] = int32(x) + p.v.Set(reflect.ValueOf(&o.int32s[0])) + o.int32s = o.int32s[1:] + return + case uint32Type: + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + p.v.Set(reflect.ValueOf(&o.uint32s[0])) + o.uint32s = o.uint32s[1:] + return + case float32Type: + if len(o.float32s) == 0 { + o.float32s = make([]float32, uint32PoolSize) + } + o.float32s[0] = math.Float32frombits(x) + p.v.Set(reflect.ValueOf(&o.float32s[0])) + o.float32s = o.float32s[1:] + return + } + + // must be enum + p.v.Set(reflect.New(t)) + p.v.Elem().SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32_Get(p word32) uint32 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32{structPointer_field(p, f)} +} + +// A word32Val represents a field of type int32, uint32, float32, or enum. +// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. +type word32Val struct { + v reflect.Value +} + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + switch p.v.Type() { + case int32Type: + p.v.SetInt(int64(x)) + return + case uint32Type: + p.v.SetUint(uint64(x)) + return + case float32Type: + p.v.SetFloat(float64(math.Float32frombits(x))) + return + } + + // must be enum + p.v.SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32Val_Get(p word32Val) uint32 { + elem := p.v + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val{structPointer_field(p, f)} +} + +// A word32Slice is a slice of 32-bit values. +// That is, v.Type() is []int32, []uint32, []float32, or []enum. +type word32Slice struct { + v reflect.Value +} + +func (p word32Slice) Append(x uint32) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int32: + elem.SetInt(int64(int32(x))) + case reflect.Uint32: + elem.SetUint(uint64(x)) + case reflect.Float32: + elem.SetFloat(float64(math.Float32frombits(x))) + } +} + +func (p word32Slice) Len() int { + return p.v.Len() +} + +func (p word32Slice) Index(i int) uint32 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) word32Slice { + return word32Slice{structPointer_field(p, f)} +} + +// word64 is like word32 but for 64-bit values. +type word64 struct { + v reflect.Value +} + +func word64_Set(p word64, o *Buffer, x uint64) { + t := p.v.Type().Elem() + switch t { + case int64Type: + if len(o.int64s) == 0 { + o.int64s = make([]int64, uint64PoolSize) + } + o.int64s[0] = int64(x) + p.v.Set(reflect.ValueOf(&o.int64s[0])) + o.int64s = o.int64s[1:] + return + case uint64Type: + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + p.v.Set(reflect.ValueOf(&o.uint64s[0])) + o.uint64s = o.uint64s[1:] + return + case float64Type: + if len(o.float64s) == 0 { + o.float64s = make([]float64, uint64PoolSize) + } + o.float64s[0] = math.Float64frombits(x) + p.v.Set(reflect.ValueOf(&o.float64s[0])) + o.float64s = o.float64s[1:] + return + } + panic("unreachable") +} + +func word64_IsNil(p word64) bool { + return p.v.IsNil() +} + +func word64_Get(p word64) uint64 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64{structPointer_field(p, f)} +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val struct { + v reflect.Value +} + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + switch p.v.Type() { + case int64Type: + p.v.SetInt(int64(x)) + return + case uint64Type: + p.v.SetUint(x) + return + case float64Type: + p.v.SetFloat(math.Float64frombits(x)) + return + } + panic("unreachable") +} + +func word64Val_Get(p word64Val) uint64 { + elem := p.v + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val{structPointer_field(p, f)} +} + +type word64Slice struct { + v reflect.Value +} + +func (p word64Slice) Append(x uint64) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int64: + elem.SetInt(int64(int64(x))) + case reflect.Uint64: + elem.SetUint(uint64(x)) + case reflect.Float64: + elem.SetFloat(float64(math.Float64frombits(x))) + } +} + +func (p word64Slice) Len() int { + return p.v.Len() +} + +func (p word64Slice) Index(i int) uint64 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return uint64(elem.Uint()) + case reflect.Float64: + return math.Float64bits(float64(elem.Float())) + } + panic("unreachable") +} + +func structPointer_Word64Slice(p structPointer, f field) word64Slice { + return word64Slice{structPointer_field(p, f)} +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go new file mode 100644 index 000000000..1763a5f22 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go @@ -0,0 +1,85 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2016, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build appengine js + +package proto + +import ( + "reflect" +) + +func structPointer_FieldPointer(p structPointer, f field) structPointer { + panic("not implemented") +} + +func appendStructPointer(base structPointer, f field, typ reflect.Type) structPointer { + panic("not implemented") +} + +func structPointer_InterfaceAt(p structPointer, f field, t reflect.Type) interface{} { + panic("not implemented") +} + +func structPointer_InterfaceRef(p structPointer, f field, t reflect.Type) interface{} { + panic("not implemented") +} + +func structPointer_GetRefStructPointer(p structPointer, f field) structPointer { + panic("not implemented") +} + +func structPointer_Add(p structPointer, size field) structPointer { + panic("not implemented") +} + +func structPointer_Len(p structPointer, f field) int { + panic("not implemented") +} + +func structPointer_GetSliceHeader(p structPointer, f field) *reflect.SliceHeader { + panic("not implemented") +} + +func structPointer_Copy(oldptr structPointer, newptr structPointer, size int) { + panic("not implemented") +} + +func structPointer_StructRefSlice(p structPointer, f field, size uintptr) *structRefSlice { + panic("not implemented") +} + +type structRefSlice struct{} + +func (v *structRefSlice) Len() int { + panic("not implemented") +} + +func (v *structRefSlice) Index(i int) structPointer { + panic("not implemented") +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go new file mode 100644 index 000000000..6b5567d47 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go @@ -0,0 +1,270 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build !appengine,!js + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "unsafe" +) + +// NOTE: These type_Foo functions would more idiomatically be methods, +// but Go does not allow methods on pointer types, and we must preserve +// some pointer type for the garbage collector. We use these +// funcs with clunky names as our poor approximation to methods. +// +// An alternative would be +// type structPointer struct { p unsafe.Pointer } +// but that does not registerize as well. + +// A structPointer is a pointer to a struct. +type structPointer unsafe.Pointer + +// toStructPointer returns a structPointer equivalent to the given reflect value. +func toStructPointer(v reflect.Value) structPointer { + return structPointer(unsafe.Pointer(v.Pointer())) +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p == nil +} + +// Interface returns the struct pointer, assumed to have element type t, +// as an interface value. +func structPointer_Interface(p structPointer, t reflect.Type) interface{} { + return reflect.NewAt(t, unsafe.Pointer(p)).Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by its byte offset from the start of the struct. +type field uintptr + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return field(f.Offset) +} + +// invalidField is an invalid field identifier. +const invalidField = ^field(0) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { + return f != ^field(0) +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { + return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { + return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). +type structPointerSlice []structPointer + +func (v *structPointerSlice) Len() int { return len(*v) } +func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } +func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } + +// A word32 is the address of a "pointer to 32-bit value" field. +type word32 **uint32 + +// IsNil reports whether *v is nil. +func word32_IsNil(p word32) bool { + return *p == nil +} + +// Set sets *v to point at a newly allocated word set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + *p = &o.uint32s[0] + o.uint32s = o.uint32s[1:] +} + +// Get gets the value pointed at by *v. +func word32_Get(p word32) uint32 { + return **p +} + +// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Val is the address of a 32-bit value field. +type word32Val *uint32 + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + *p = x +} + +// Get gets the value pointed at by p. +func word32Val_Get(p word32Val) uint32 { + return *p +} + +// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Slice is a slice of 32-bit values. +type word32Slice []uint32 + +func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } +func (v *word32Slice) Len() int { return len(*v) } +func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } + +// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) *word32Slice { + return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// word64 is like word32 but for 64-bit values. +type word64 **uint64 + +func word64_Set(p word64, o *Buffer, x uint64) { + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + *p = &o.uint64s[0] + o.uint64s = o.uint64s[1:] +} + +func word64_IsNil(p word64) bool { + return *p == nil +} + +func word64_Get(p word64) uint64 { + return **p +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val *uint64 + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + *p = x +} + +func word64Val_Get(p word64Val) uint64 { + return *p +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Slice is like word32Slice but for 64-bit values. +type word64Slice []uint64 + +func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } +func (v *word64Slice) Len() int { return len(*v) } +func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } + +func structPointer_Word64Slice(p structPointer, f field) *word64Slice { + return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go new file mode 100644 index 000000000..f156a29f0 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go @@ -0,0 +1,128 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build !appengine,!js + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "unsafe" +) + +func structPointer_InterfaceAt(p structPointer, f field, t reflect.Type) interface{} { + point := unsafe.Pointer(uintptr(p) + uintptr(f)) + r := reflect.NewAt(t, point) + return r.Interface() +} + +func structPointer_InterfaceRef(p structPointer, f field, t reflect.Type) interface{} { + point := unsafe.Pointer(uintptr(p) + uintptr(f)) + r := reflect.NewAt(t, point) + if r.Elem().IsNil() { + return nil + } + return r.Elem().Interface() +} + +func copyUintPtr(oldptr, newptr uintptr, size int) { + oldbytes := make([]byte, 0) + oldslice := (*reflect.SliceHeader)(unsafe.Pointer(&oldbytes)) + oldslice.Data = oldptr + oldslice.Len = size + oldslice.Cap = size + newbytes := make([]byte, 0) + newslice := (*reflect.SliceHeader)(unsafe.Pointer(&newbytes)) + newslice.Data = newptr + newslice.Len = size + newslice.Cap = size + copy(newbytes, oldbytes) +} + +func structPointer_Copy(oldptr structPointer, newptr structPointer, size int) { + copyUintPtr(uintptr(oldptr), uintptr(newptr), size) +} + +func appendStructPointer(base structPointer, f field, typ reflect.Type) structPointer { + size := typ.Elem().Size() + + oldHeader := structPointer_GetSliceHeader(base, f) + oldSlice := reflect.NewAt(typ, unsafe.Pointer(oldHeader)).Elem() + newLen := oldHeader.Len + 1 + newSlice := reflect.MakeSlice(typ, newLen, newLen) + reflect.Copy(newSlice, oldSlice) + bas := toStructPointer(newSlice) + oldHeader.Data = uintptr(bas) + oldHeader.Len = newLen + oldHeader.Cap = newLen + + return structPointer(unsafe.Pointer(uintptr(unsafe.Pointer(bas)) + uintptr(uintptr(newLen-1)*size))) +} + +func structPointer_FieldPointer(p structPointer, f field) structPointer { + return structPointer(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +func structPointer_GetRefStructPointer(p structPointer, f field) structPointer { + return structPointer((*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +func structPointer_GetSliceHeader(p structPointer, f field) *reflect.SliceHeader { + return (*reflect.SliceHeader)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +func structPointer_Add(p structPointer, size field) structPointer { + return structPointer(unsafe.Pointer(uintptr(p) + uintptr(size))) +} + +func structPointer_Len(p structPointer, f field) int { + return len(*(*[]interface{})(unsafe.Pointer(structPointer_GetRefStructPointer(p, f)))) +} + +func structPointer_StructRefSlice(p structPointer, f field, size uintptr) *structRefSlice { + return &structRefSlice{p: p, f: f, size: size} +} + +// A structRefSlice represents a slice of structs (themselves submessages or groups). +type structRefSlice struct { + p structPointer + f field + size uintptr +} + +func (v *structRefSlice) Len() int { + return structPointer_Len(v.p, v.f) +} + +func (v *structRefSlice) Index(i int) structPointer { + ss := structPointer_GetStructPointer(v.p, v.f) + ss1 := structPointer_GetRefStructPointer(ss, 0) + return structPointer_Add(ss1, field(uintptr(i)*v.size)) +} diff --git a/vendor/github.com/gogo/protobuf/proto/properties.go b/vendor/github.com/gogo/protobuf/proto/properties.go new file mode 100644 index 000000000..44b332052 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/properties.go @@ -0,0 +1,968 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "fmt" + "log" + "os" + "reflect" + "sort" + "strconv" + "strings" + "sync" +) + +const debug bool = false + +// Constants that identify the encoding of a value on the wire. +const ( + WireVarint = 0 + WireFixed64 = 1 + WireBytes = 2 + WireStartGroup = 3 + WireEndGroup = 4 + WireFixed32 = 5 +) + +const startSize = 10 // initial slice/string sizes + +// Encoders are defined in encode.go +// An encoder outputs the full representation of a field, including its +// tag and encoder type. +type encoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueEncoder encodes a single integer in a particular encoding. +type valueEncoder func(o *Buffer, x uint64) error + +// Sizers are defined in encode.go +// A sizer returns the encoded size of a field, including its tag and encoder +// type. +type sizer func(prop *Properties, base structPointer) int + +// A valueSizer returns the encoded size of a single integer in a particular +// encoding. +type valueSizer func(x uint64) int + +// Decoders are defined in decode.go +// A decoder creates a value from its wire representation. +// Unrecognized subelements are saved in unrec. +type decoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueDecoder decodes a single integer in a particular encoding. +type valueDecoder func(o *Buffer) (x uint64, err error) + +// A oneofMarshaler does the marshaling for all oneof fields in a message. +type oneofMarshaler func(Message, *Buffer) error + +// A oneofUnmarshaler does the unmarshaling for a oneof field in a message. +type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) + +// A oneofSizer does the sizing for all oneof fields in a message. +type oneofSizer func(Message) int + +// tagMap is an optimization over map[int]int for typical protocol buffer +// use-cases. Encoded protocol buffers are often in tag order with small tag +// numbers. +type tagMap struct { + fastTags []int + slowTags map[int]int +} + +// tagMapFastLimit is the upper bound on the tag number that will be stored in +// the tagMap slice rather than its map. +const tagMapFastLimit = 1024 + +func (p *tagMap) get(t int) (int, bool) { + if t > 0 && t < tagMapFastLimit { + if t >= len(p.fastTags) { + return 0, false + } + fi := p.fastTags[t] + return fi, fi >= 0 + } + fi, ok := p.slowTags[t] + return fi, ok +} + +func (p *tagMap) put(t int, fi int) { + if t > 0 && t < tagMapFastLimit { + for len(p.fastTags) < t+1 { + p.fastTags = append(p.fastTags, -1) + } + p.fastTags[t] = fi + return + } + if p.slowTags == nil { + p.slowTags = make(map[int]int) + } + p.slowTags[t] = fi +} + +// StructProperties represents properties for all the fields of a struct. +// decoderTags and decoderOrigNames should only be used by the decoder. +type StructProperties struct { + Prop []*Properties // properties for each field + reqCount int // required count + decoderTags tagMap // map from proto tag to struct field number + decoderOrigNames map[string]int // map from original name to struct field number + order []int // list of struct field numbers in tag order + unrecField field // field id of the XXX_unrecognized []byte field + extendable bool // is this an extendable proto + + oneofMarshaler oneofMarshaler + oneofUnmarshaler oneofUnmarshaler + oneofSizer oneofSizer + stype reflect.Type + + // OneofTypes contains information about the oneof fields in this message. + // It is keyed by the original name of a field. + OneofTypes map[string]*OneofProperties +} + +// OneofProperties represents information about a specific field in a oneof. +type OneofProperties struct { + Type reflect.Type // pointer to generated struct type for this oneof field + Field int // struct field number of the containing oneof in the message + Prop *Properties +} + +// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. +// See encode.go, (*Buffer).enc_struct. + +func (sp *StructProperties) Len() int { return len(sp.order) } +func (sp *StructProperties) Less(i, j int) bool { + return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag +} +func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } + +// Properties represents the protocol-specific behavior of a single struct field. +type Properties struct { + Name string // name of the field, for error messages + OrigName string // original name before protocol compiler (always set) + JSONName string // name to use for JSON; determined by protoc + Wire string + WireType int + Tag int + Required bool + Optional bool + Repeated bool + Packed bool // relevant for repeated primitives only + Enum string // set for enum types only + proto3 bool // whether this is known to be a proto3 field; set for []byte only + oneof bool // whether this is a oneof field + + Default string // default value + HasDefault bool // whether an explicit default was provided + CustomType string + StdTime bool + StdDuration bool + + enc encoder + valEnc valueEncoder // set for bool and numeric types only + field field + tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) + tagbuf [8]byte + stype reflect.Type // set for struct types only + sstype reflect.Type // set for slices of structs types only + ctype reflect.Type // set for custom types only + sprop *StructProperties // set for struct types only + isMarshaler bool + isUnmarshaler bool + + mtype reflect.Type // set for map types only + mkeyprop *Properties // set for map types only + mvalprop *Properties // set for map types only + + size sizer + valSize valueSizer // set for bool and numeric types only + + dec decoder + valDec valueDecoder // set for bool and numeric types only + + // If this is a packable field, this will be the decoder for the packed version of the field. + packedDec decoder +} + +// String formats the properties in the protobuf struct field tag style. +func (p *Properties) String() string { + s := p.Wire + s = "," + s += strconv.Itoa(p.Tag) + if p.Required { + s += ",req" + } + if p.Optional { + s += ",opt" + } + if p.Repeated { + s += ",rep" + } + if p.Packed { + s += ",packed" + } + s += ",name=" + p.OrigName + if p.JSONName != p.OrigName { + s += ",json=" + p.JSONName + } + if p.proto3 { + s += ",proto3" + } + if p.oneof { + s += ",oneof" + } + if len(p.Enum) > 0 { + s += ",enum=" + p.Enum + } + if p.HasDefault { + s += ",def=" + p.Default + } + return s +} + +// Parse populates p by parsing a string in the protobuf struct field tag style. +func (p *Properties) Parse(s string) { + // "bytes,49,opt,name=foo,def=hello!" + fields := strings.Split(s, ",") // breaks def=, but handled below. + if len(fields) < 2 { + fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) + return + } + + p.Wire = fields[0] + switch p.Wire { + case "varint": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeVarint + p.valDec = (*Buffer).DecodeVarint + p.valSize = sizeVarint + case "fixed32": + p.WireType = WireFixed32 + p.valEnc = (*Buffer).EncodeFixed32 + p.valDec = (*Buffer).DecodeFixed32 + p.valSize = sizeFixed32 + case "fixed64": + p.WireType = WireFixed64 + p.valEnc = (*Buffer).EncodeFixed64 + p.valDec = (*Buffer).DecodeFixed64 + p.valSize = sizeFixed64 + case "zigzag32": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag32 + p.valDec = (*Buffer).DecodeZigzag32 + p.valSize = sizeZigzag32 + case "zigzag64": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag64 + p.valDec = (*Buffer).DecodeZigzag64 + p.valSize = sizeZigzag64 + case "bytes", "group": + p.WireType = WireBytes + // no numeric converter for non-numeric types + default: + fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) + return + } + + var err error + p.Tag, err = strconv.Atoi(fields[1]) + if err != nil { + return + } + + for i := 2; i < len(fields); i++ { + f := fields[i] + switch { + case f == "req": + p.Required = true + case f == "opt": + p.Optional = true + case f == "rep": + p.Repeated = true + case f == "packed": + p.Packed = true + case strings.HasPrefix(f, "name="): + p.OrigName = f[5:] + case strings.HasPrefix(f, "json="): + p.JSONName = f[5:] + case strings.HasPrefix(f, "enum="): + p.Enum = f[5:] + case f == "proto3": + p.proto3 = true + case f == "oneof": + p.oneof = true + case strings.HasPrefix(f, "def="): + p.HasDefault = true + p.Default = f[4:] // rest of string + if i+1 < len(fields) { + // Commas aren't escaped, and def is always last. + p.Default += "," + strings.Join(fields[i+1:], ",") + break + } + case strings.HasPrefix(f, "embedded="): + p.OrigName = strings.Split(f, "=")[1] + case strings.HasPrefix(f, "customtype="): + p.CustomType = strings.Split(f, "=")[1] + case f == "stdtime": + p.StdTime = true + case f == "stdduration": + p.StdDuration = true + } + } +} + +func logNoSliceEnc(t1, t2 reflect.Type) { + fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) +} + +var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() + +// Initialize the fields for encoding and decoding. +func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { + p.enc = nil + p.dec = nil + p.size = nil + isMap := typ.Kind() == reflect.Map + if len(p.CustomType) > 0 && !isMap { + p.setCustomEncAndDec(typ) + p.setTag(lockGetProp) + return + } + if p.StdTime && !isMap { + p.setTimeEncAndDec(typ) + p.setTag(lockGetProp) + return + } + if p.StdDuration && !isMap { + p.setDurationEncAndDec(typ) + p.setTag(lockGetProp) + return + } + switch t1 := typ; t1.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) + + // proto3 scalar types + + case reflect.Bool: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_bool + p.dec = (*Buffer).dec_proto3_bool + p.size = size_proto3_bool + } else { + p.enc = (*Buffer).enc_ref_bool + p.dec = (*Buffer).dec_proto3_bool + p.size = size_ref_bool + } + case reflect.Int32: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_int32 + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_int32 + } else { + p.enc = (*Buffer).enc_ref_int32 + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_ref_int32 + } + case reflect.Uint32: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_uint32 + p.dec = (*Buffer).dec_proto3_int32 // can reuse + p.size = size_proto3_uint32 + } else { + p.enc = (*Buffer).enc_ref_uint32 + p.dec = (*Buffer).dec_proto3_int32 // can reuse + p.size = size_ref_uint32 + } + case reflect.Int64, reflect.Uint64: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_int64 + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + } else { + p.enc = (*Buffer).enc_ref_int64 + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_ref_int64 + } + case reflect.Float32: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_uint32 + } else { + p.enc = (*Buffer).enc_ref_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_ref_uint32 + } + case reflect.Float64: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + } else { + p.enc = (*Buffer).enc_ref_int64 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_ref_int64 + } + case reflect.String: + if p.proto3 { + p.enc = (*Buffer).enc_proto3_string + p.dec = (*Buffer).dec_proto3_string + p.size = size_proto3_string + } else { + p.enc = (*Buffer).enc_ref_string + p.dec = (*Buffer).dec_proto3_string + p.size = size_ref_string + } + case reflect.Struct: + p.stype = typ + p.isMarshaler = isMarshaler(typ) + p.isUnmarshaler = isUnmarshaler(typ) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_ref_struct_message + p.dec = (*Buffer).dec_ref_struct_message + p.size = size_ref_struct_message + } else { + fmt.Fprintf(os.Stderr, "proto: no coders for struct %T\n", typ) + } + + case reflect.Ptr: + switch t2 := t1.Elem(); t2.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) + break + case reflect.Bool: + p.enc = (*Buffer).enc_bool + p.dec = (*Buffer).dec_bool + p.size = size_bool + case reflect.Int32: + p.enc = (*Buffer).enc_int32 + p.dec = (*Buffer).dec_int32 + p.size = size_int32 + case reflect.Uint32: + p.enc = (*Buffer).enc_uint32 + p.dec = (*Buffer).dec_int32 // can reuse + p.size = size_uint32 + case reflect.Int64, reflect.Uint64: + p.enc = (*Buffer).enc_int64 + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.Float32: + p.enc = (*Buffer).enc_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_int32 + p.size = size_uint32 + case reflect.Float64: + p.enc = (*Buffer).enc_int64 // can just treat them as bits + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.String: + p.enc = (*Buffer).enc_string + p.dec = (*Buffer).dec_string + p.size = size_string + case reflect.Struct: + p.stype = t1.Elem() + p.isMarshaler = isMarshaler(t1) + p.isUnmarshaler = isUnmarshaler(t1) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_struct_message + p.dec = (*Buffer).dec_struct_message + p.size = size_struct_message + } else { + p.enc = (*Buffer).enc_struct_group + p.dec = (*Buffer).dec_struct_group + p.size = size_struct_group + } + } + + case reflect.Slice: + switch t2 := t1.Elem(); t2.Kind() { + default: + logNoSliceEnc(t1, t2) + break + case reflect.Bool: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_bool + p.size = size_slice_packed_bool + } else { + p.enc = (*Buffer).enc_slice_bool + p.size = size_slice_bool + } + p.dec = (*Buffer).dec_slice_bool + p.packedDec = (*Buffer).dec_slice_packed_bool + case reflect.Int32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int32 + p.size = size_slice_packed_int32 + } else { + p.enc = (*Buffer).enc_slice_int32 + p.size = size_slice_int32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Uint32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Int64, reflect.Uint64: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + case reflect.Uint8: + p.dec = (*Buffer).dec_slice_byte + if p.proto3 { + p.enc = (*Buffer).enc_proto3_slice_byte + p.size = size_proto3_slice_byte + } else { + p.enc = (*Buffer).enc_slice_byte + p.size = size_slice_byte + } + case reflect.Float32, reflect.Float64: + switch t2.Bits() { + case 32: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case 64: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + default: + logNoSliceEnc(t1, t2) + break + } + case reflect.String: + p.enc = (*Buffer).enc_slice_string + p.dec = (*Buffer).dec_slice_string + p.size = size_slice_string + case reflect.Ptr: + switch t3 := t2.Elem(); t3.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) + break + case reflect.Struct: + p.stype = t2.Elem() + p.isMarshaler = isMarshaler(t2) + p.isUnmarshaler = isUnmarshaler(t2) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_slice_struct_message + p.dec = (*Buffer).dec_slice_struct_message + p.size = size_slice_struct_message + } else { + p.enc = (*Buffer).enc_slice_struct_group + p.dec = (*Buffer).dec_slice_struct_group + p.size = size_slice_struct_group + } + } + case reflect.Slice: + switch t2.Elem().Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) + break + case reflect.Uint8: + p.enc = (*Buffer).enc_slice_slice_byte + p.dec = (*Buffer).dec_slice_slice_byte + p.size = size_slice_slice_byte + } + case reflect.Struct: + p.setSliceOfNonPointerStructs(t1) + } + + case reflect.Map: + p.enc = (*Buffer).enc_new_map + p.dec = (*Buffer).dec_new_map + p.size = size_new_map + + p.mtype = t1 + p.mkeyprop = &Properties{} + p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) + p.mvalprop = &Properties{} + vtype := p.mtype.Elem() + if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { + // The value type is not a message (*T) or bytes ([]byte), + // so we need encoders for the pointer to this type. + vtype = reflect.PtrTo(vtype) + } + + p.mvalprop.CustomType = p.CustomType + p.mvalprop.StdDuration = p.StdDuration + p.mvalprop.StdTime = p.StdTime + p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) + } + p.setTag(lockGetProp) +} + +func (p *Properties) setTag(lockGetProp bool) { + // precalculate tag code + wire := p.WireType + if p.Packed { + wire = WireBytes + } + x := uint32(p.Tag)<<3 | uint32(wire) + i := 0 + for i = 0; x > 127; i++ { + p.tagbuf[i] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + p.tagbuf[i] = uint8(x) + p.tagcode = p.tagbuf[0 : i+1] + + if p.stype != nil { + if lockGetProp { + p.sprop = GetProperties(p.stype) + } else { + p.sprop = getPropertiesLocked(p.stype) + } + } +} + +var ( + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() +) + +// isMarshaler reports whether type t implements Marshaler. +func isMarshaler(t reflect.Type) bool { + return t.Implements(marshalerType) +} + +// isUnmarshaler reports whether type t implements Unmarshaler. +func isUnmarshaler(t reflect.Type) bool { + return t.Implements(unmarshalerType) +} + +// Init populates the properties from a protocol buffer struct tag. +func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { + p.init(typ, name, tag, f, true) +} + +func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { + // "bytes,49,opt,def=hello!" + p.Name = name + p.OrigName = name + if f != nil { + p.field = toField(f) + } + if tag == "" { + return + } + p.Parse(tag) + p.setEncAndDec(typ, f, lockGetProp) +} + +var ( + propertiesMu sync.RWMutex + propertiesMap = make(map[reflect.Type]*StructProperties) +) + +// GetProperties returns the list of properties for the type represented by t. +// t must represent a generated struct type of a protocol message. +func GetProperties(t reflect.Type) *StructProperties { + if t.Kind() != reflect.Struct { + panic("proto: type must have kind struct") + } + + // Most calls to GetProperties in a long-running program will be + // retrieving details for types we have seen before. + propertiesMu.RLock() + sprop, ok := propertiesMap[t] + propertiesMu.RUnlock() + if ok { + if collectStats { + stats.Chit++ + } + return sprop + } + + propertiesMu.Lock() + sprop = getPropertiesLocked(t) + propertiesMu.Unlock() + return sprop +} + +// getPropertiesLocked requires that propertiesMu is held. +func getPropertiesLocked(t reflect.Type) *StructProperties { + if prop, ok := propertiesMap[t]; ok { + if collectStats { + stats.Chit++ + } + return prop + } + if collectStats { + stats.Cmiss++ + } + + prop := new(StructProperties) + // in case of recursive protos, fill this in now. + propertiesMap[t] = prop + + // build properties + prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || + reflect.PtrTo(t).Implements(extendableProtoV1Type) || + reflect.PtrTo(t).Implements(extendableBytesType) + prop.unrecField = invalidField + prop.Prop = make([]*Properties, t.NumField()) + prop.order = make([]int, t.NumField()) + + isOneofMessage := false + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + p := new(Properties) + name := f.Name + p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) + + if f.Name == "XXX_InternalExtensions" { // special case + p.enc = (*Buffer).enc_exts + p.dec = nil // not needed + p.size = size_exts + } else if f.Name == "XXX_extensions" { // special case + if len(f.Tag.Get("protobuf")) > 0 { + p.enc = (*Buffer).enc_ext_slice_byte + p.dec = nil // not needed + p.size = size_ext_slice_byte + } else { + p.enc = (*Buffer).enc_map + p.dec = nil // not needed + p.size = size_map + } + } else if f.Name == "XXX_unrecognized" { // special case + prop.unrecField = toField(&f) + } + oneof := f.Tag.Get("protobuf_oneof") // special case + if oneof != "" { + isOneofMessage = true + // Oneof fields don't use the traditional protobuf tag. + p.OrigName = oneof + } + prop.Prop[i] = p + prop.order[i] = i + if debug { + print(i, " ", f.Name, " ", t.String(), " ") + if p.Tag > 0 { + print(p.String()) + } + print("\n") + } + if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { + fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") + } + } + + // Re-order prop.order. + sort.Sort(prop) + + type oneofMessage interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + } + if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); isOneofMessage && ok { + var oots []interface{} + prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() + prop.stype = t + + // Interpret oneof metadata. + prop.OneofTypes = make(map[string]*OneofProperties) + for _, oot := range oots { + oop := &OneofProperties{ + Type: reflect.ValueOf(oot).Type(), // *T + Prop: new(Properties), + } + sft := oop.Type.Elem().Field(0) + oop.Prop.Name = sft.Name + oop.Prop.Parse(sft.Tag.Get("protobuf")) + // There will be exactly one interface field that + // this new value is assignable to. + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Type.Kind() != reflect.Interface { + continue + } + if !oop.Type.AssignableTo(f.Type) { + continue + } + oop.Field = i + break + } + prop.OneofTypes[oop.Prop.OrigName] = oop + } + } + + // build required counts + // build tags + reqCount := 0 + prop.decoderOrigNames = make(map[string]int) + for i, p := range prop.Prop { + if strings.HasPrefix(p.Name, "XXX_") { + // Internal fields should not appear in tags/origNames maps. + // They are handled specially when encoding and decoding. + continue + } + if p.Required { + reqCount++ + } + prop.decoderTags.put(p.Tag, i) + prop.decoderOrigNames[p.OrigName] = i + } + prop.reqCount = reqCount + + return prop +} + +// Return the Properties object for the x[0]'th field of the structure. +func propByIndex(t reflect.Type, x []int) *Properties { + if len(x) != 1 { + fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) + return nil + } + prop := GetProperties(t) + return prop.Prop[x[0]] +} + +// Get the address and type of a pointer to a struct from an interface. +func getbase(pb Message) (t reflect.Type, b structPointer, err error) { + if pb == nil { + err = ErrNil + return + } + // get the reflect type of the pointer to the struct. + t = reflect.TypeOf(pb) + // get the address of the struct. + value := reflect.ValueOf(pb) + b = toStructPointer(value) + return +} + +// A global registry of enum types. +// The generated code will register the generated maps by calling RegisterEnum. + +var enumValueMaps = make(map[string]map[string]int32) +var enumStringMaps = make(map[string]map[int32]string) + +// RegisterEnum is called from the generated code to install the enum descriptor +// maps into the global table to aid parsing text format protocol buffers. +func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { + if _, ok := enumValueMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumValueMaps[typeName] = valueMap + if _, ok := enumStringMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumStringMaps[typeName] = unusedNameMap +} + +// EnumValueMap returns the mapping from names to integers of the +// enum type enumType, or a nil if not found. +func EnumValueMap(enumType string) map[string]int32 { + return enumValueMaps[enumType] +} + +// A registry of all linked message types. +// The string is a fully-qualified proto name ("pkg.Message"). +var ( + protoTypes = make(map[string]reflect.Type) + revProtoTypes = make(map[reflect.Type]string) +) + +// RegisterType is called from generated code and maps from the fully qualified +// proto name to the type (pointer to struct) of the protocol buffer. +func RegisterType(x Message, name string) { + if _, ok := protoTypes[name]; ok { + // TODO: Some day, make this a panic. + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + protoTypes[name] = t + revProtoTypes[t] = name +} + +// MessageName returns the fully-qualified proto name for the given message type. +func MessageName(x Message) string { + type xname interface { + XXX_MessageName() string + } + if m, ok := x.(xname); ok { + return m.XXX_MessageName() + } + return revProtoTypes[reflect.TypeOf(x)] +} + +// MessageType returns the message type (pointer to struct) for a named message. +func MessageType(name string) reflect.Type { return protoTypes[name] } + +// A registry of all linked proto files. +var ( + protoFiles = make(map[string][]byte) // file name => fileDescriptor +) + +// RegisterFile is called from generated code and maps from the +// full file name of a .proto file to its compressed FileDescriptorProto. +func RegisterFile(filename string, fileDescriptor []byte) { + protoFiles[filename] = fileDescriptor +} + +// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. +func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/gogo/protobuf/proto/properties_gogo.go b/vendor/github.com/gogo/protobuf/proto/properties_gogo.go new file mode 100644 index 000000000..b6b7176c5 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/properties_gogo.go @@ -0,0 +1,111 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "os" + "reflect" +) + +func (p *Properties) setCustomEncAndDec(typ reflect.Type) { + p.ctype = typ + if p.Repeated { + p.enc = (*Buffer).enc_custom_slice_bytes + p.dec = (*Buffer).dec_custom_slice_bytes + p.size = size_custom_slice_bytes + } else if typ.Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_custom_bytes + p.dec = (*Buffer).dec_custom_bytes + p.size = size_custom_bytes + } else { + p.enc = (*Buffer).enc_custom_ref_bytes + p.dec = (*Buffer).dec_custom_ref_bytes + p.size = size_custom_ref_bytes + } +} + +func (p *Properties) setDurationEncAndDec(typ reflect.Type) { + if p.Repeated { + if typ.Elem().Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_slice_duration + p.dec = (*Buffer).dec_slice_duration + p.size = size_slice_duration + } else { + p.enc = (*Buffer).enc_slice_ref_duration + p.dec = (*Buffer).dec_slice_ref_duration + p.size = size_slice_ref_duration + } + } else if typ.Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_duration + p.dec = (*Buffer).dec_duration + p.size = size_duration + } else { + p.enc = (*Buffer).enc_ref_duration + p.dec = (*Buffer).dec_ref_duration + p.size = size_ref_duration + } +} + +func (p *Properties) setTimeEncAndDec(typ reflect.Type) { + if p.Repeated { + if typ.Elem().Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_slice_time + p.dec = (*Buffer).dec_slice_time + p.size = size_slice_time + } else { + p.enc = (*Buffer).enc_slice_ref_time + p.dec = (*Buffer).dec_slice_ref_time + p.size = size_slice_ref_time + } + } else if typ.Kind() == reflect.Ptr { + p.enc = (*Buffer).enc_time + p.dec = (*Buffer).dec_time + p.size = size_time + } else { + p.enc = (*Buffer).enc_ref_time + p.dec = (*Buffer).dec_ref_time + p.size = size_ref_time + } + +} + +func (p *Properties) setSliceOfNonPointerStructs(typ reflect.Type) { + t2 := typ.Elem() + p.sstype = typ + p.stype = t2 + p.isMarshaler = isMarshaler(t2) + p.isUnmarshaler = isUnmarshaler(t2) + p.enc = (*Buffer).enc_slice_ref_struct_message + p.dec = (*Buffer).dec_slice_ref_struct_message + p.size = size_slice_ref_struct_message + if p.Wire != "bytes" { + fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T \n", typ, t2) + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/skip_gogo.go b/vendor/github.com/gogo/protobuf/proto/skip_gogo.go new file mode 100644 index 000000000..5a5fd93f7 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/skip_gogo.go @@ -0,0 +1,119 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "io" +) + +func Skip(data []byte) (n int, err error) { + l := len(data) + index := 0 + for index < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[index] + index++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + index++ + if data[index-1] < 0x80 { + break + } + } + return index, nil + case 1: + index += 8 + return index, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[index] + index++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + index += length + return index, nil + case 3: + for { + var innerWire uint64 + var start int = index + for shift := uint(0); ; shift += 7 { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[index] + index++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := Skip(data[start:]) + if err != nil { + return 0, err + } + index = start + next + } + return index, nil + case 4: + return index, nil + case 5: + index += 4 + return index, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} diff --git a/vendor/github.com/gogo/protobuf/proto/text.go b/vendor/github.com/gogo/protobuf/proto/text.go new file mode 100644 index 000000000..d63732fcb --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text.go @@ -0,0 +1,928 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for writing the text protocol buffer format. + +import ( + "bufio" + "bytes" + "encoding" + "errors" + "fmt" + "io" + "log" + "math" + "reflect" + "sort" + "strings" + "sync" + "time" +) + +var ( + newline = []byte("\n") + spaces = []byte(" ") + gtNewline = []byte(">\n") + endBraceNewline = []byte("}\n") + backslashN = []byte{'\\', 'n'} + backslashR = []byte{'\\', 'r'} + backslashT = []byte{'\\', 't'} + backslashDQ = []byte{'\\', '"'} + backslashBS = []byte{'\\', '\\'} + posInf = []byte("inf") + negInf = []byte("-inf") + nan = []byte("nan") +) + +type writer interface { + io.Writer + WriteByte(byte) error +} + +// textWriter is an io.Writer that tracks its indentation level. +type textWriter struct { + ind int + complete bool // if the current position is a complete line + compact bool // whether to write out as a one-liner + w writer +} + +func (w *textWriter) WriteString(s string) (n int, err error) { + if !strings.Contains(s, "\n") { + if !w.compact && w.complete { + w.writeIndent() + } + w.complete = false + return io.WriteString(w.w, s) + } + // WriteString is typically called without newlines, so this + // codepath and its copy are rare. We copy to avoid + // duplicating all of Write's logic here. + return w.Write([]byte(s)) +} + +func (w *textWriter) Write(p []byte) (n int, err error) { + newlines := bytes.Count(p, newline) + if newlines == 0 { + if !w.compact && w.complete { + w.writeIndent() + } + n, err = w.w.Write(p) + w.complete = false + return n, err + } + + frags := bytes.SplitN(p, newline, newlines+1) + if w.compact { + for i, frag := range frags { + if i > 0 { + if err := w.w.WriteByte(' '); err != nil { + return n, err + } + n++ + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + } + return n, nil + } + + for i, frag := range frags { + if w.complete { + w.writeIndent() + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + if i+1 < len(frags) { + if err := w.w.WriteByte('\n'); err != nil { + return n, err + } + n++ + } + } + w.complete = len(frags[len(frags)-1]) == 0 + return n, nil +} + +func (w *textWriter) WriteByte(c byte) error { + if w.compact && c == '\n' { + c = ' ' + } + if !w.compact && w.complete { + w.writeIndent() + } + err := w.w.WriteByte(c) + w.complete = c == '\n' + return err +} + +func (w *textWriter) indent() { w.ind++ } + +func (w *textWriter) unindent() { + if w.ind == 0 { + log.Print("proto: textWriter unindented too far") + return + } + w.ind-- +} + +func writeName(w *textWriter, props *Properties) error { + if _, err := w.WriteString(props.OrigName); err != nil { + return err + } + if props.Wire != "group" { + return w.WriteByte(':') + } + return nil +} + +// raw is the interface satisfied by RawMessage. +type raw interface { + Bytes() []byte +} + +func requiresQuotes(u string) bool { + // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. + for _, ch := range u { + switch { + case ch == '.' || ch == '/' || ch == '_': + continue + case '0' <= ch && ch <= '9': + continue + case 'A' <= ch && ch <= 'Z': + continue + case 'a' <= ch && ch <= 'z': + continue + default: + return true + } + } + return false +} + +// isAny reports whether sv is a google.protobuf.Any message +func isAny(sv reflect.Value) bool { + type wkt interface { + XXX_WellKnownType() string + } + t, ok := sv.Addr().Interface().(wkt) + return ok && t.XXX_WellKnownType() == "Any" +} + +// writeProto3Any writes an expanded google.protobuf.Any message. +// +// It returns (false, nil) if sv value can't be unmarshaled (e.g. because +// required messages are not linked in). +// +// It returns (true, error) when sv was written in expanded format or an error +// was encountered. +func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { + turl := sv.FieldByName("TypeUrl") + val := sv.FieldByName("Value") + if !turl.IsValid() || !val.IsValid() { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + b, ok := val.Interface().([]byte) + if !ok { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + parts := strings.Split(turl.String(), "/") + mt := MessageType(parts[len(parts)-1]) + if mt == nil { + return false, nil + } + m := reflect.New(mt.Elem()) + if err := Unmarshal(b, m.Interface().(Message)); err != nil { + return false, nil + } + w.Write([]byte("[")) + u := turl.String() + if requiresQuotes(u) { + writeString(w, u) + } else { + w.Write([]byte(u)) + } + if w.compact { + w.Write([]byte("]:<")) + } else { + w.Write([]byte("]: <\n")) + w.ind++ + } + if err := tm.writeStruct(w, m.Elem()); err != nil { + return true, err + } + if w.compact { + w.Write([]byte("> ")) + } else { + w.ind-- + w.Write([]byte(">\n")) + } + return true, nil +} + +func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { + if tm.ExpandAny && isAny(sv) { + if canExpand, err := tm.writeProto3Any(w, sv); canExpand { + return err + } + } + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < sv.NumField(); i++ { + fv := sv.Field(i) + props := sprops.Prop[i] + name := st.Field(i).Name + + if strings.HasPrefix(name, "XXX_") { + // There are two XXX_ fields: + // XXX_unrecognized []byte + // XXX_extensions map[int32]proto.Extension + // The first is handled here; + // the second is handled at the bottom of this function. + if name == "XXX_unrecognized" && !fv.IsNil() { + if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Field not filled in. This could be an optional field or + // a required field that wasn't filled in. Either way, there + // isn't anything we can show for it. + continue + } + if fv.Kind() == reflect.Slice && fv.IsNil() { + // Repeated field that is empty, or a bytes field that is unused. + continue + } + + if props.Repeated && fv.Kind() == reflect.Slice { + // Repeated field. + for j := 0; j < fv.Len(); j++ { + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + v := fv.Index(j) + if v.Kind() == reflect.Ptr && v.IsNil() { + // A nil message in a repeated field is not valid, + // but we can handle that more gracefully than panicking. + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + continue + } + if len(props.Enum) > 0 { + if err := tm.writeEnum(w, v, props); err != nil { + return err + } + } else if err := tm.writeAny(w, v, props); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Map { + // Map fields are rendered as a repeated struct with key/value fields. + keys := fv.MapKeys() + sort.Sort(mapKeys(keys)) + for _, key := range keys { + val := fv.MapIndex(key) + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + // open struct + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + // key + if _, err := w.WriteString("key:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, key, props.mkeyprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // nil values aren't legal, but we can avoid panicking because of them. + if val.Kind() != reflect.Ptr || !val.IsNil() { + // value + if _, err := w.WriteString("value:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, val, props.mvalprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + // close struct + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { + // empty bytes field + continue + } + if props.proto3 && fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { + // proto3 non-repeated scalar field; skip if zero value + if isProto3Zero(fv) { + continue + } + } + + if fv.Kind() == reflect.Interface { + // Check if it is a oneof. + if st.Field(i).Tag.Get("protobuf_oneof") != "" { + // fv is nil, or holds a pointer to generated struct. + // That generated struct has exactly one field, + // which has a protobuf struct tag. + if fv.IsNil() { + continue + } + inner := fv.Elem().Elem() // interface -> *T -> T + tag := inner.Type().Field(0).Tag.Get("protobuf") + props = new(Properties) // Overwrite the outer props var, but not its pointee. + props.Parse(tag) + // Write the value in the oneof, not the oneof itself. + fv = inner.Field(0) + + // Special case to cope with malformed messages gracefully: + // If the value in the oneof is a nil pointer, don't panic + // in writeAny. + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Use errors.New so writeAny won't render quotes. + msg := errors.New("/* nil */") + fv = reflect.ValueOf(&msg).Elem() + } + } + } + + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if b, ok := fv.Interface().(raw); ok { + if err := writeRaw(w, b.Bytes()); err != nil { + return err + } + continue + } + + if len(props.Enum) > 0 { + if err := tm.writeEnum(w, fv, props); err != nil { + return err + } + } else if err := tm.writeAny(w, fv, props); err != nil { + return err + } + + if err := w.WriteByte('\n'); err != nil { + return err + } + } + + // Extensions (the XXX_extensions field). + pv := sv + if pv.CanAddr() { + pv = sv.Addr() + } else { + pv = reflect.New(sv.Type()) + pv.Elem().Set(sv) + } + if pv.Type().Implements(extensionRangeType) { + if err := tm.writeExtensions(w, pv); err != nil { + return err + } + } + + return nil +} + +// writeRaw writes an uninterpreted raw message. +func writeRaw(w *textWriter, b []byte) error { + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if err := writeUnknownStruct(w, b); err != nil { + return err + } + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + return nil +} + +// writeAny writes an arbitrary field. +func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { + v = reflect.Indirect(v) + + if props != nil { + if len(props.CustomType) > 0 { + custom, ok := v.Interface().(Marshaler) + if ok { + data, err := custom.Marshal() + if err != nil { + return err + } + if err := writeString(w, string(data)); err != nil { + return err + } + return nil + } + } else if props.StdTime { + t, ok := v.Interface().(time.Time) + if !ok { + return fmt.Errorf("stdtime is not time.Time, but %T", v.Interface()) + } + tproto, err := timestampProto(t) + if err != nil { + return err + } + props.StdTime = false + err = tm.writeAny(w, reflect.ValueOf(tproto), props) + props.StdTime = true + return err + } else if props.StdDuration { + d, ok := v.Interface().(time.Duration) + if !ok { + return fmt.Errorf("stdtime is not time.Duration, but %T", v.Interface()) + } + dproto := durationProto(d) + props.StdDuration = false + err := tm.writeAny(w, reflect.ValueOf(dproto), props) + props.StdDuration = true + return err + } + } + + // Floats have special cases. + if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { + x := v.Float() + var b []byte + switch { + case math.IsInf(x, 1): + b = posInf + case math.IsInf(x, -1): + b = negInf + case math.IsNaN(x): + b = nan + } + if b != nil { + _, err := w.Write(b) + return err + } + // Other values are handled below. + } + + // We don't attempt to serialise every possible value type; only those + // that can occur in protocol buffers. + switch v.Kind() { + case reflect.Slice: + // Should only be a []byte; repeated fields are handled in writeStruct. + if err := writeString(w, string(v.Bytes())); err != nil { + return err + } + case reflect.String: + if err := writeString(w, v.String()); err != nil { + return err + } + case reflect.Struct: + // Required/optional group/message. + var bra, ket byte = '<', '>' + if props != nil && props.Wire == "group" { + bra, ket = '{', '}' + } + if err := w.WriteByte(bra); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if etm, ok := v.Interface().(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = w.Write(text); err != nil { + return err + } + } else if err := tm.writeStruct(w, v); err != nil { + return err + } + w.unindent() + if err := w.WriteByte(ket); err != nil { + return err + } + default: + _, err := fmt.Fprint(w, v.Interface()) + return err + } + return nil +} + +// equivalent to C's isprint. +func isprint(c byte) bool { + return c >= 0x20 && c < 0x7f +} + +// writeString writes a string in the protocol buffer text format. +// It is similar to strconv.Quote except we don't use Go escape sequences, +// we treat the string as a byte sequence, and we use octal escapes. +// These differences are to maintain interoperability with the other +// languages' implementations of the text format. +func writeString(w *textWriter, s string) error { + // use WriteByte here to get any needed indent + if err := w.WriteByte('"'); err != nil { + return err + } + // Loop over the bytes, not the runes. + for i := 0; i < len(s); i++ { + var err error + // Divergence from C++: we don't escape apostrophes. + // There's no need to escape them, and the C++ parser + // copes with a naked apostrophe. + switch c := s[i]; c { + case '\n': + _, err = w.w.Write(backslashN) + case '\r': + _, err = w.w.Write(backslashR) + case '\t': + _, err = w.w.Write(backslashT) + case '"': + _, err = w.w.Write(backslashDQ) + case '\\': + _, err = w.w.Write(backslashBS) + default: + if isprint(c) { + err = w.w.WriteByte(c) + } else { + _, err = fmt.Fprintf(w.w, "\\%03o", c) + } + } + if err != nil { + return err + } + } + return w.WriteByte('"') +} + +func writeUnknownStruct(w *textWriter, data []byte) (err error) { + if !w.compact { + if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { + return err + } + } + b := NewBuffer(data) + for b.index < len(b.buf) { + x, err := b.DecodeVarint() + if err != nil { + _, ferr := fmt.Fprintf(w, "/* %v */\n", err) + return ferr + } + wire, tag := x&7, x>>3 + if wire == WireEndGroup { + w.unindent() + if _, werr := w.Write(endBraceNewline); werr != nil { + return werr + } + continue + } + if _, ferr := fmt.Fprint(w, tag); ferr != nil { + return ferr + } + if wire != WireStartGroup { + if err = w.WriteByte(':'); err != nil { + return err + } + } + if !w.compact || wire == WireStartGroup { + if err = w.WriteByte(' '); err != nil { + return err + } + } + switch wire { + case WireBytes: + buf, e := b.DecodeRawBytes(false) + if e == nil { + _, err = fmt.Fprintf(w, "%q", buf) + } else { + _, err = fmt.Fprintf(w, "/* %v */", e) + } + case WireFixed32: + x, err = b.DecodeFixed32() + err = writeUnknownInt(w, x, err) + case WireFixed64: + x, err = b.DecodeFixed64() + err = writeUnknownInt(w, x, err) + case WireStartGroup: + err = w.WriteByte('{') + w.indent() + case WireVarint: + x, err = b.DecodeVarint() + err = writeUnknownInt(w, x, err) + default: + _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) + } + if err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + return nil +} + +func writeUnknownInt(w *textWriter, x uint64, err error) error { + if err == nil { + _, err = fmt.Fprint(w, x) + } else { + _, err = fmt.Fprintf(w, "/* %v */", err) + } + return err +} + +type int32Slice []int32 + +func (s int32Slice) Len() int { return len(s) } +func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } +func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// writeExtensions writes all the extensions in pv. +// pv is assumed to be a pointer to a protocol message struct that is extendable. +func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { + emap := extensionMaps[pv.Type().Elem()] + e := pv.Interface().(Message) + + var m map[int32]Extension + var mu sync.Locker + if em, ok := e.(extensionsBytes); ok { + eb := em.GetExtensions() + var err error + m, err = BytesToExtensionsMap(*eb) + if err != nil { + return err + } + mu = notLocker{} + } else if _, ok := e.(extendableProto); ok { + ep, _ := extendable(e) + m, mu = ep.extensionsRead() + if m == nil { + return nil + } + } + + // Order the extensions by ID. + // This isn't strictly necessary, but it will give us + // canonical output, which will also make testing easier. + + mu.Lock() + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) + mu.Unlock() + + for _, extNum := range ids { + ext := m[extNum] + var desc *ExtensionDesc + if emap != nil { + desc = emap[extNum] + } + if desc == nil { + // Unknown extension. + if err := writeUnknownStruct(w, ext.enc); err != nil { + return err + } + continue + } + + pb, err := GetExtension(e, desc) + if err != nil { + return fmt.Errorf("failed getting extension: %v", err) + } + + // Repeated extensions will appear as a slice. + if !desc.repeated() { + if err := tm.writeExtension(w, desc.Name, pb); err != nil { + return err + } + } else { + v := reflect.ValueOf(pb) + for i := 0; i < v.Len(); i++ { + if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { + return err + } + } + } + } + return nil +} + +func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { + if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + return nil +} + +func (w *textWriter) writeIndent() { + if !w.complete { + return + } + remain := w.ind * 2 + for remain > 0 { + n := remain + if n > len(spaces) { + n = len(spaces) + } + w.w.Write(spaces[:n]) + remain -= n + } + w.complete = false +} + +// TextMarshaler is a configurable text format marshaler. +type TextMarshaler struct { + Compact bool // use compact text format (one line). + ExpandAny bool // expand google.protobuf.Any messages of known types +} + +// Marshal writes a given protocol buffer in text format. +// The only errors returned are from w. +func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { + val := reflect.ValueOf(pb) + if pb == nil || val.IsNil() { + w.Write([]byte("")) + return nil + } + var bw *bufio.Writer + ww, ok := w.(writer) + if !ok { + bw = bufio.NewWriter(w) + ww = bw + } + aw := &textWriter{ + w: ww, + complete: true, + compact: tm.Compact, + } + + if etm, ok := pb.(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = aw.Write(text); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil + } + // Dereference the received pointer so we don't have outer < and >. + v := reflect.Indirect(val) + if err := tm.writeStruct(aw, v); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil +} + +// Text is the same as Marshal, but returns the string directly. +func (tm *TextMarshaler) Text(pb Message) string { + var buf bytes.Buffer + tm.Marshal(&buf, pb) + return buf.String() +} + +var ( + defaultTextMarshaler = TextMarshaler{} + compactTextMarshaler = TextMarshaler{Compact: true} +) + +// TODO: consider removing some of the Marshal functions below. + +// MarshalText writes a given protocol buffer in text format. +// The only errors returned are from w. +func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } + +// MarshalTextString is the same as MarshalText, but returns the string directly. +func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } + +// CompactText writes a given protocol buffer in compact text format (one line). +func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } + +// CompactTextString is the same as CompactText, but returns the string directly. +func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/gogo/protobuf/proto/text_gogo.go b/vendor/github.com/gogo/protobuf/proto/text_gogo.go new file mode 100644 index 000000000..1d6c6aa0e --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text_gogo.go @@ -0,0 +1,57 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "reflect" +) + +func (tm *TextMarshaler) writeEnum(w *textWriter, v reflect.Value, props *Properties) error { + m, ok := enumStringMaps[props.Enum] + if !ok { + if err := tm.writeAny(w, v, props); err != nil { + return err + } + } + key := int32(0) + if v.Kind() == reflect.Ptr { + key = int32(v.Elem().Int()) + } else { + key = int32(v.Int()) + } + s, ok := m[key] + if !ok { + if err := tm.writeAny(w, v, props); err != nil { + return err + } + } + _, err := fmt.Fprint(w, s) + return err +} diff --git a/vendor/github.com/gogo/protobuf/proto/text_parser.go b/vendor/github.com/gogo/protobuf/proto/text_parser.go new file mode 100644 index 000000000..9db12e960 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text_parser.go @@ -0,0 +1,1013 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for parsing the Text protocol buffer format. +// TODO: message sets. + +import ( + "encoding" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +// Error string emitted when deserializing Any and fields are already set +const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" + +type ParseError struct { + Message string + Line int // 1-based line number + Offset int // 0-based byte offset from start of input +} + +func (p *ParseError) Error() string { + if p.Line == 1 { + // show offset only for first line + return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) + } + return fmt.Sprintf("line %d: %v", p.Line, p.Message) +} + +type token struct { + value string + err *ParseError + line int // line number + offset int // byte number from start of input, not start of line + unquoted string // the unquoted version of value, if it was a quoted string +} + +func (t *token) String() string { + if t.err == nil { + return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) + } + return fmt.Sprintf("parse error: %v", t.err) +} + +type textParser struct { + s string // remaining input + done bool // whether the parsing is finished (success or error) + backed bool // whether back() was called + offset, line int + cur token +} + +func newTextParser(s string) *textParser { + p := new(textParser) + p.s = s + p.line = 1 + p.cur.line = 1 + return p +} + +func (p *textParser) errorf(format string, a ...interface{}) *ParseError { + pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} + p.cur.err = pe + p.done = true + return pe +} + +// Numbers and identifiers are matched by [-+._A-Za-z0-9] +func isIdentOrNumberChar(c byte) bool { + switch { + case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': + return true + case '0' <= c && c <= '9': + return true + } + switch c { + case '-', '+', '.', '_': + return true + } + return false +} + +func isWhitespace(c byte) bool { + switch c { + case ' ', '\t', '\n', '\r': + return true + } + return false +} + +func isQuote(c byte) bool { + switch c { + case '"', '\'': + return true + } + return false +} + +func (p *textParser) skipWhitespace() { + i := 0 + for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { + if p.s[i] == '#' { + // comment; skip to end of line or input + for i < len(p.s) && p.s[i] != '\n' { + i++ + } + if i == len(p.s) { + break + } + } + if p.s[i] == '\n' { + p.line++ + } + i++ + } + p.offset += i + p.s = p.s[i:len(p.s)] + if len(p.s) == 0 { + p.done = true + } +} + +func (p *textParser) advance() { + // Skip whitespace + p.skipWhitespace() + if p.done { + return + } + + // Start of non-whitespace + p.cur.err = nil + p.cur.offset, p.cur.line = p.offset, p.line + p.cur.unquoted = "" + switch p.s[0] { + case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': + // Single symbol + p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] + case '"', '\'': + // Quoted string + i := 1 + for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { + if p.s[i] == '\\' && i+1 < len(p.s) { + // skip escaped char + i++ + } + i++ + } + if i >= len(p.s) || p.s[i] != p.s[0] { + p.errorf("unmatched quote") + return + } + unq, err := unquoteC(p.s[1:i], rune(p.s[0])) + if err != nil { + p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) + return + } + p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] + p.cur.unquoted = unq + default: + i := 0 + for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { + i++ + } + if i == 0 { + p.errorf("unexpected byte %#x", p.s[0]) + return + } + p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] + } + p.offset += len(p.cur.value) +} + +var ( + errBadUTF8 = errors.New("proto: bad UTF-8") + errBadHex = errors.New("proto: bad hexadecimal") +) + +func unquoteC(s string, quote rune) (string, error) { + // This is based on C++'s tokenizer.cc. + // Despite its name, this is *not* parsing C syntax. + // For instance, "\0" is an invalid quoted string. + + // Avoid allocation in trivial cases. + simple := true + for _, r := range s { + if r == '\\' || r == quote { + simple = false + break + } + } + if simple { + return s, nil + } + + buf := make([]byte, 0, 3*len(s)/2) + for len(s) > 0 { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", errBadUTF8 + } + s = s[n:] + if r != '\\' { + if r < utf8.RuneSelf { + buf = append(buf, byte(r)) + } else { + buf = append(buf, string(r)...) + } + continue + } + + ch, tail, err := unescape(s) + if err != nil { + return "", err + } + buf = append(buf, ch...) + s = tail + } + return string(buf), nil +} + +func unescape(s string) (ch string, tail string, err error) { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", "", errBadUTF8 + } + s = s[n:] + switch r { + case 'a': + return "\a", s, nil + case 'b': + return "\b", s, nil + case 'f': + return "\f", s, nil + case 'n': + return "\n", s, nil + case 'r': + return "\r", s, nil + case 't': + return "\t", s, nil + case 'v': + return "\v", s, nil + case '?': + return "?", s, nil // trigraph workaround + case '\'', '"', '\\': + return string(r), s, nil + case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': + if len(s) < 2 { + return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) + } + base := 8 + ss := s[:2] + s = s[2:] + if r == 'x' || r == 'X' { + base = 16 + } else { + ss = string(r) + ss + } + i, err := strconv.ParseUint(ss, base, 8) + if err != nil { + return "", "", err + } + return string([]byte{byte(i)}), s, nil + case 'u', 'U': + n := 4 + if r == 'U' { + n = 8 + } + if len(s) < n { + return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) + } + + bs := make([]byte, n/2) + for i := 0; i < n; i += 2 { + a, ok1 := unhex(s[i]) + b, ok2 := unhex(s[i+1]) + if !ok1 || !ok2 { + return "", "", errBadHex + } + bs[i/2] = a<<4 | b + } + s = s[n:] + return string(bs), s, nil + } + return "", "", fmt.Errorf(`unknown escape \%c`, r) +} + +// Adapted from src/pkg/strconv/quote.go. +func unhex(b byte) (v byte, ok bool) { + switch { + case '0' <= b && b <= '9': + return b - '0', true + case 'a' <= b && b <= 'f': + return b - 'a' + 10, true + case 'A' <= b && b <= 'F': + return b - 'A' + 10, true + } + return 0, false +} + +// Back off the parser by one token. Can only be done between calls to next(). +// It makes the next advance() a no-op. +func (p *textParser) back() { p.backed = true } + +// Advances the parser and returns the new current token. +func (p *textParser) next() *token { + if p.backed || p.done { + p.backed = false + return &p.cur + } + p.advance() + if p.done { + p.cur.value = "" + } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { + // Look for multiple quoted strings separated by whitespace, + // and concatenate them. + cat := p.cur + for { + p.skipWhitespace() + if p.done || !isQuote(p.s[0]) { + break + } + p.advance() + if p.cur.err != nil { + return &p.cur + } + cat.value += " " + p.cur.value + cat.unquoted += p.cur.unquoted + } + p.done = false // parser may have seen EOF, but we want to return cat + p.cur = cat + } + return &p.cur +} + +func (p *textParser) consumeToken(s string) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != s { + p.back() + return p.errorf("expected %q, found %q", s, tok.value) + } + return nil +} + +// Return a RequiredNotSetError indicating which required field was not set. +func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < st.NumField(); i++ { + if !isNil(sv.Field(i)) { + continue + } + + props := sprops.Prop[i] + if props.Required { + return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} + } + } + return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen +} + +// Returns the index in the struct for the named field, as well as the parsed tag properties. +func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { + i, ok := sprops.decoderOrigNames[name] + if ok { + return i, sprops.Prop[i], true + } + return -1, nil, false +} + +// Consume a ':' from the input stream (if the next token is a colon), +// returning an error if a colon is needed but not present. +func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ":" { + // Colon is optional when the field is a group or message. + needColon := true + switch props.Wire { + case "group": + needColon = false + case "bytes": + // A "bytes" field is either a message, a string, or a repeated field; + // those three become *T, *string and []T respectively, so we can check for + // this field being a pointer to a non-string. + if typ.Kind() == reflect.Ptr { + // *T or *string + if typ.Elem().Kind() == reflect.String { + break + } + } else if typ.Kind() == reflect.Slice { + // []T or []*T + if typ.Elem().Kind() != reflect.Ptr { + break + } + } else if typ.Kind() == reflect.String { + // The proto3 exception is for a string field, + // which requires a colon. + break + } + needColon = false + } + if needColon { + return p.errorf("expected ':', found %q", tok.value) + } + p.back() + } + return nil +} + +func (p *textParser) readStruct(sv reflect.Value, terminator string) error { + st := sv.Type() + sprops := GetProperties(st) + reqCount := sprops.reqCount + var reqFieldErr error + fieldSet := make(map[string]bool) + // A struct is a sequence of "name: value", terminated by one of + // '>' or '}', or the end of the input. A name may also be + // "[extension]" or "[type/url]". + // + // The whole struct can also be an expanded Any message, like: + // [type/url] < ... struct contents ... > + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + if tok.value == "[" { + // Looks like an extension or an Any. + // + // TODO: Check whether we need to handle + // namespace rooted names (e.g. ".something.Foo"). + extName, err := p.consumeExtName() + if err != nil { + return err + } + + if s := strings.LastIndex(extName, "/"); s >= 0 { + // If it contains a slash, it's an Any type URL. + messageName := extName[s+1:] + mt := MessageType(messageName) + if mt == nil { + return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) + } + tok = p.next() + if tok.err != nil { + return tok.err + } + // consume an optional colon + if tok.value == ":" { + tok = p.next() + if tok.err != nil { + return tok.err + } + } + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + v := reflect.New(mt.Elem()) + if pe := p.readStruct(v.Elem(), terminator); pe != nil { + return pe + } + b, err := Marshal(v.Interface().(Message)) + if err != nil { + return p.errorf("failed to marshal message of type %q: %v", messageName, err) + } + if fieldSet["type_url"] { + return p.errorf(anyRepeatedlyUnpacked, "type_url") + } + if fieldSet["value"] { + return p.errorf(anyRepeatedlyUnpacked, "value") + } + sv.FieldByName("TypeUrl").SetString(extName) + sv.FieldByName("Value").SetBytes(b) + fieldSet["type_url"] = true + fieldSet["value"] = true + continue + } + + var desc *ExtensionDesc + // This could be faster, but it's functional. + // TODO: Do something smarter than a linear scan. + for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { + if d.Name == extName { + desc = d + break + } + } + if desc == nil { + return p.errorf("unrecognized extension %q", extName) + } + + props := &Properties{} + props.Parse(desc.Tag) + + typ := reflect.TypeOf(desc.ExtensionType) + if err := p.checkForColon(props, typ); err != nil { + return err + } + + rep := desc.repeated() + + // Read the extension structure, and set it in + // the value we're constructing. + var ext reflect.Value + if !rep { + ext = reflect.New(typ).Elem() + } else { + ext = reflect.New(typ.Elem()).Elem() + } + if err := p.readAny(ext, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + ep := sv.Addr().Interface().(Message) + if !rep { + SetExtension(ep, desc, ext.Interface()) + } else { + old, err := GetExtension(ep, desc) + var sl reflect.Value + if err == nil { + sl = reflect.ValueOf(old) // existing slice + } else { + sl = reflect.MakeSlice(typ, 0, 1) + } + sl = reflect.Append(sl, ext) + SetExtension(ep, desc, sl.Interface()) + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + continue + } + + // This is a normal, non-extension field. + name := tok.value + var dst reflect.Value + fi, props, ok := structFieldByName(sprops, name) + if ok { + dst = sv.Field(fi) + } else if oop, ok := sprops.OneofTypes[name]; ok { + // It is a oneof. + props = oop.Prop + nv := reflect.New(oop.Type.Elem()) + dst = nv.Elem().Field(0) + field := sv.Field(oop.Field) + if !field.IsNil() { + return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) + } + field.Set(nv) + } + if !dst.IsValid() { + return p.errorf("unknown field name %q in %v", name, st) + } + + if dst.Kind() == reflect.Map { + // Consume any colon. + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Construct the map if it doesn't already exist. + if dst.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) + } + key := reflect.New(dst.Type().Key()).Elem() + val := reflect.New(dst.Type().Elem()).Elem() + + // The map entry should be this sequence of tokens: + // < key : KEY value : VALUE > + // However, implementations may omit key or value, and technically + // we should support them in any order. See b/28924776 for a time + // this went wrong. + + tok := p.next() + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + switch tok.value { + case "key": + if err := p.consumeToken(":"); err != nil { + return err + } + if err := p.readAny(key, props.mkeyprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + case "value": + if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + return err + } + if err := p.readAny(val, props.mvalprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + default: + p.back() + return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) + } + } + + dst.SetMapIndex(key, val) + continue + } + + // Check that it's not already set if it's not a repeated field. + if !props.Repeated && fieldSet[name] { + return p.errorf("non-repeated field %q was repeated", name) + } + + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Parse into the field. + fieldSet[name] = true + if err := p.readAny(dst, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + if props.Required { + reqCount-- + } + + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + + } + + if reqCount > 0 { + return p.missingRequiredFieldError(sv) + } + return reqFieldErr +} + +// consumeExtName consumes extension name or expanded Any type URL and the +// following ']'. It returns the name or URL consumed. +func (p *textParser) consumeExtName() (string, error) { + tok := p.next() + if tok.err != nil { + return "", tok.err + } + + // If extension name or type url is quoted, it's a single token. + if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { + name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) + if err != nil { + return "", err + } + return name, p.consumeToken("]") + } + + // Consume everything up to "]" + var parts []string + for tok.value != "]" { + parts = append(parts, tok.value) + tok = p.next() + if tok.err != nil { + return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) + } + } + return strings.Join(parts, ""), nil +} + +// consumeOptionalSeparator consumes an optional semicolon or comma. +// It is used in readStruct to provide backward compatibility. +func (p *textParser) consumeOptionalSeparator() error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ";" && tok.value != "," { + p.back() + } + return nil +} + +func (p *textParser) readAny(v reflect.Value, props *Properties) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "" { + return p.errorf("unexpected EOF") + } + if len(props.CustomType) > 0 { + if props.Repeated { + t := reflect.TypeOf(v.Interface()) + if t.Kind() == reflect.Slice { + tc := reflect.TypeOf(new(Marshaler)) + ok := t.Elem().Implements(tc.Elem()) + if ok { + fv := v + flen := fv.Len() + if flen == fv.Cap() { + nav := reflect.MakeSlice(v.Type(), flen, 2*flen+1) + reflect.Copy(nav, fv) + fv.Set(nav) + } + fv.SetLen(flen + 1) + + // Read one. + p.back() + return p.readAny(fv.Index(flen), props) + } + } + } + if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { + custom := reflect.New(props.ctype.Elem()).Interface().(Unmarshaler) + err := custom.Unmarshal([]byte(tok.unquoted)) + if err != nil { + return p.errorf("%v %v: %v", err, v.Type(), tok.value) + } + v.Set(reflect.ValueOf(custom)) + } else { + custom := reflect.New(reflect.TypeOf(v.Interface())).Interface().(Unmarshaler) + err := custom.Unmarshal([]byte(tok.unquoted)) + if err != nil { + return p.errorf("%v %v: %v", err, v.Type(), tok.value) + } + v.Set(reflect.Indirect(reflect.ValueOf(custom))) + } + return nil + } + if props.StdTime { + fv := v + p.back() + props.StdTime = false + tproto := ×tamp{} + err := p.readAny(reflect.ValueOf(tproto).Elem(), props) + props.StdTime = true + if err != nil { + return err + } + tim, err := timestampFromProto(tproto) + if err != nil { + return err + } + if props.Repeated { + t := reflect.TypeOf(v.Interface()) + if t.Kind() == reflect.Slice { + if t.Elem().Kind() == reflect.Ptr { + ts := fv.Interface().([]*time.Time) + ts = append(ts, &tim) + fv.Set(reflect.ValueOf(ts)) + return nil + } else { + ts := fv.Interface().([]time.Time) + ts = append(ts, tim) + fv.Set(reflect.ValueOf(ts)) + return nil + } + } + } + if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { + v.Set(reflect.ValueOf(&tim)) + } else { + v.Set(reflect.Indirect(reflect.ValueOf(&tim))) + } + return nil + } + if props.StdDuration { + fv := v + p.back() + props.StdDuration = false + dproto := &duration{} + err := p.readAny(reflect.ValueOf(dproto).Elem(), props) + props.StdDuration = true + if err != nil { + return err + } + dur, err := durationFromProto(dproto) + if err != nil { + return err + } + if props.Repeated { + t := reflect.TypeOf(v.Interface()) + if t.Kind() == reflect.Slice { + if t.Elem().Kind() == reflect.Ptr { + ds := fv.Interface().([]*time.Duration) + ds = append(ds, &dur) + fv.Set(reflect.ValueOf(ds)) + return nil + } else { + ds := fv.Interface().([]time.Duration) + ds = append(ds, dur) + fv.Set(reflect.ValueOf(ds)) + return nil + } + } + } + if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { + v.Set(reflect.ValueOf(&dur)) + } else { + v.Set(reflect.Indirect(reflect.ValueOf(&dur))) + } + return nil + } + switch fv := v; fv.Kind() { + case reflect.Slice: + at := v.Type() + if at.Elem().Kind() == reflect.Uint8 { + // Special case for []byte + if tok.value[0] != '"' && tok.value[0] != '\'' { + // Deliberately written out here, as the error after + // this switch statement would write "invalid []byte: ...", + // which is not as user-friendly. + return p.errorf("invalid string: %v", tok.value) + } + bytes := []byte(tok.unquoted) + fv.Set(reflect.ValueOf(bytes)) + return nil + } + // Repeated field. + if tok.value == "[" { + // Repeated field with list notation, like [1,2,3]. + for { + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + err := p.readAny(fv.Index(fv.Len()-1), props) + if err != nil { + return err + } + ntok := p.next() + if ntok.err != nil { + return ntok.err + } + if ntok.value == "]" { + break + } + if ntok.value != "," { + return p.errorf("Expected ']' or ',' found %q", ntok.value) + } + } + return nil + } + // One value of the repeated field. + p.back() + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + return p.readAny(fv.Index(fv.Len()-1), props) + case reflect.Bool: + // true/1/t/True or false/f/0/False. + switch tok.value { + case "true", "1", "t", "True": + fv.SetBool(true) + return nil + case "false", "0", "f", "False": + fv.SetBool(false) + return nil + } + case reflect.Float32, reflect.Float64: + v := tok.value + // Ignore 'f' for compatibility with output generated by C++, but don't + // remove 'f' when the value is "-inf" or "inf". + if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { + v = v[:len(v)-1] + } + if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { + fv.SetFloat(f) + return nil + } + case reflect.Int32: + if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { + fv.SetInt(x) + return nil + } + + if len(props.Enum) == 0 { + break + } + m, ok := enumValueMaps[props.Enum] + if !ok { + break + } + x, ok := m[tok.value] + if !ok { + break + } + fv.SetInt(int64(x)) + return nil + case reflect.Int64: + if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { + fv.SetInt(x) + return nil + } + + case reflect.Ptr: + // A basic field (indirected through pointer), or a repeated message/group + p.back() + fv.Set(reflect.New(fv.Type().Elem())) + return p.readAny(fv.Elem(), props) + case reflect.String: + if tok.value[0] == '"' || tok.value[0] == '\'' { + fv.SetString(tok.unquoted) + return nil + } + case reflect.Struct: + var terminator string + switch tok.value { + case "{": + terminator = "}" + case "<": + terminator = ">" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + // TODO: Handle nested messages which implement encoding.TextUnmarshaler. + return p.readStruct(fv, terminator) + case reflect.Uint32: + if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { + fv.SetUint(uint64(x)) + return nil + } + case reflect.Uint64: + if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { + fv.SetUint(x) + return nil + } + } + return p.errorf("invalid %v: %v", v.Type(), tok.value) +} + +// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb +// before starting to unmarshal, so any existing data in pb is always removed. +// If a required field is not set and no other error occurs, +// UnmarshalText returns *RequiredNotSetError. +func UnmarshalText(s string, pb Message) error { + if um, ok := pb.(encoding.TextUnmarshaler); ok { + err := um.UnmarshalText([]byte(s)) + return err + } + pb.Reset() + v := reflect.ValueOf(pb) + if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { + return pe + } + return nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/timestamp.go b/vendor/github.com/gogo/protobuf/proto/timestamp.go new file mode 100644 index 000000000..9324f6542 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/timestamp.go @@ -0,0 +1,113 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// This file implements operations on google.protobuf.Timestamp. + +import ( + "errors" + "fmt" + "time" +) + +const ( + // Seconds field of the earliest valid Timestamp. + // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + minValidSeconds = -62135596800 + // Seconds field just after the latest valid Timestamp. + // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + maxValidSeconds = 253402300800 +) + +// validateTimestamp determines whether a Timestamp is valid. +// A valid timestamp represents a time in the range +// [0001-01-01, 10000-01-01) and has a Nanos field +// in the range [0, 1e9). +// +// If the Timestamp is valid, validateTimestamp returns nil. +// Otherwise, it returns an error that describes +// the problem. +// +// Every valid Timestamp can be represented by a time.Time, but the converse is not true. +func validateTimestamp(ts *timestamp) error { + if ts == nil { + return errors.New("timestamp: nil Timestamp") + } + if ts.Seconds < minValidSeconds { + return fmt.Errorf("timestamp: %#v before 0001-01-01", ts) + } + if ts.Seconds >= maxValidSeconds { + return fmt.Errorf("timestamp: %#v after 10000-01-01", ts) + } + if ts.Nanos < 0 || ts.Nanos >= 1e9 { + return fmt.Errorf("timestamp: %#v: nanos not in range [0, 1e9)", ts) + } + return nil +} + +// TimestampFromProto converts a google.protobuf.Timestamp proto to a time.Time. +// It returns an error if the argument is invalid. +// +// Unlike most Go functions, if Timestamp returns an error, the first return value +// is not the zero time.Time. Instead, it is the value obtained from the +// time.Unix function when passed the contents of the Timestamp, in the UTC +// locale. This may or may not be a meaningful time; many invalid Timestamps +// do map to valid time.Times. +// +// A nil Timestamp returns an error. The first return value in that case is +// undefined. +func timestampFromProto(ts *timestamp) (time.Time, error) { + // Don't return the zero value on error, because corresponds to a valid + // timestamp. Instead return whatever time.Unix gives us. + var t time.Time + if ts == nil { + t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp + } else { + t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() + } + return t, validateTimestamp(ts) +} + +// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. +// It returns an error if the resulting Timestamp is invalid. +func timestampProto(t time.Time) (*timestamp, error) { + seconds := t.Unix() + nanos := int32(t.Sub(time.Unix(seconds, 0))) + ts := ×tamp{ + Seconds: seconds, + Nanos: nanos, + } + if err := validateTimestamp(ts); err != nil { + return nil, err + } + return ts, nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go b/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go new file mode 100644 index 000000000..d42764743 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go @@ -0,0 +1,229 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2016, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "reflect" + "time" +) + +var timeType = reflect.TypeOf((*time.Time)(nil)).Elem() + +type timestamp struct { + Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` + Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` +} + +func (m *timestamp) Reset() { *m = timestamp{} } +func (*timestamp) ProtoMessage() {} +func (*timestamp) String() string { return "timestamp" } + +func init() { + RegisterType((*timestamp)(nil), "gogo.protobuf.proto.timestamp") +} + +func (o *Buffer) decTimestamp() (time.Time, error) { + b, err := o.DecodeRawBytes(true) + if err != nil { + return time.Time{}, err + } + tproto := ×tamp{} + if err := Unmarshal(b, tproto); err != nil { + return time.Time{}, err + } + return timestampFromProto(tproto) +} + +func (o *Buffer) dec_time(p *Properties, base structPointer) error { + t, err := o.decTimestamp() + if err != nil { + return err + } + setPtrCustomType(base, p.field, &t) + return nil +} + +func (o *Buffer) dec_ref_time(p *Properties, base structPointer) error { + t, err := o.decTimestamp() + if err != nil { + return err + } + setCustomType(base, p.field, &t) + return nil +} + +func (o *Buffer) dec_slice_time(p *Properties, base structPointer) error { + t, err := o.decTimestamp() + if err != nil { + return err + } + newBas := appendStructPointer(base, p.field, reflect.SliceOf(reflect.PtrTo(timeType))) + var zero field + setPtrCustomType(newBas, zero, &t) + return nil +} + +func (o *Buffer) dec_slice_ref_time(p *Properties, base structPointer) error { + t, err := o.decTimestamp() + if err != nil { + return err + } + newBas := appendStructPointer(base, p.field, reflect.SliceOf(timeType)) + var zero field + setCustomType(newBas, zero, &t) + return nil +} + +func size_time(p *Properties, base structPointer) (n int) { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + tim := structPointer_Interface(structp, timeType).(*time.Time) + t, err := timestampProto(*tim) + if err != nil { + return 0 + } + size := Size(t) + return size + sizeVarint(uint64(size)) + len(p.tagcode) +} + +func (o *Buffer) enc_time(p *Properties, base structPointer) error { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + tim := structPointer_Interface(structp, timeType).(*time.Time) + t, err := timestampProto(*tim) + if err != nil { + return err + } + data, err := Marshal(t) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_ref_time(p *Properties, base structPointer) (n int) { + tim := structPointer_InterfaceAt(base, p.field, timeType).(*time.Time) + t, err := timestampProto(*tim) + if err != nil { + return 0 + } + size := Size(t) + return size + sizeVarint(uint64(size)) + len(p.tagcode) +} + +func (o *Buffer) enc_ref_time(p *Properties, base structPointer) error { + tim := structPointer_InterfaceAt(base, p.field, timeType).(*time.Time) + t, err := timestampProto(*tim) + if err != nil { + return err + } + data, err := Marshal(t) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil +} + +func size_slice_time(p *Properties, base structPointer) (n int) { + ptims := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(reflect.PtrTo(timeType))).(*[]*time.Time) + tims := *ptims + for i := 0; i < len(tims); i++ { + if tims[i] == nil { + return 0 + } + tproto, err := timestampProto(*tims[i]) + if err != nil { + return 0 + } + size := Size(tproto) + n += len(p.tagcode) + size + sizeVarint(uint64(size)) + } + return n +} + +func (o *Buffer) enc_slice_time(p *Properties, base structPointer) error { + ptims := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(reflect.PtrTo(timeType))).(*[]*time.Time) + tims := *ptims + for i := 0; i < len(tims); i++ { + if tims[i] == nil { + return errRepeatedHasNil + } + tproto, err := timestampProto(*tims[i]) + if err != nil { + return err + } + data, err := Marshal(tproto) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} + +func size_slice_ref_time(p *Properties, base structPointer) (n int) { + ptims := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(timeType)).(*[]time.Time) + tims := *ptims + for i := 0; i < len(tims); i++ { + tproto, err := timestampProto(tims[i]) + if err != nil { + return 0 + } + size := Size(tproto) + n += len(p.tagcode) + size + sizeVarint(uint64(size)) + } + return n +} + +func (o *Buffer) enc_slice_ref_time(p *Properties, base structPointer) error { + ptims := structPointer_InterfaceAt(base, p.field, reflect.SliceOf(timeType)).(*[]time.Time) + tims := *ptims + for i := 0; i < len(tims); i++ { + tproto, err := timestampProto(tims[i]) + if err != nil { + return err + } + data, err := Marshal(tproto) + if err != nil { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + } + return nil +} diff --git a/vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go b/vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go new file mode 100644 index 000000000..ceadde6a5 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go @@ -0,0 +1,101 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package sortkeys + +import ( + "sort" +) + +func Strings(l []string) { + sort.Strings(l) +} + +func Float64s(l []float64) { + sort.Float64s(l) +} + +func Float32s(l []float32) { + sort.Sort(Float32Slice(l)) +} + +func Int64s(l []int64) { + sort.Sort(Int64Slice(l)) +} + +func Int32s(l []int32) { + sort.Sort(Int32Slice(l)) +} + +func Uint64s(l []uint64) { + sort.Sort(Uint64Slice(l)) +} + +func Uint32s(l []uint32) { + sort.Sort(Uint32Slice(l)) +} + +func Bools(l []bool) { + sort.Sort(BoolSlice(l)) +} + +type BoolSlice []bool + +func (p BoolSlice) Len() int { return len(p) } +func (p BoolSlice) Less(i, j int) bool { return p[j] } +func (p BoolSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Int64Slice []int64 + +func (p Int64Slice) Len() int { return len(p) } +func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Int32Slice []int32 + +func (p Int32Slice) Len() int { return len(p) } +func (p Int32Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Int32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Uint64Slice []uint64 + +func (p Uint64Slice) Len() int { return len(p) } +func (p Uint64Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Uint64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Uint32Slice []uint32 + +func (p Uint32Slice) Len() int { return len(p) } +func (p Uint32Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Uint32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +type Float32Slice []float32 + +func (p Float32Slice) Len() int { return len(p) } +func (p Float32Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p Float32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } diff --git a/vendor/github.com/golang/glog/LICENSE b/vendor/github.com/golang/glog/LICENSE new file mode 100644 index 000000000..37ec93a14 --- /dev/null +++ b/vendor/github.com/golang/glog/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/golang/glog/README b/vendor/github.com/golang/glog/README new file mode 100644 index 000000000..5f9c11485 --- /dev/null +++ b/vendor/github.com/golang/glog/README @@ -0,0 +1,44 @@ +glog +==== + +Leveled execution logs for Go. + +This is an efficient pure Go implementation of leveled logs in the +manner of the open source C++ package + http://code.google.com/p/google-glog + +By binding methods to booleans it is possible to use the log package +without paying the expense of evaluating the arguments to the log. +Through the -vmodule flag, the package also provides fine-grained +control over logging at the file level. + +The comment from glog.go introduces the ideas: + + Package glog implements logging analogous to the Google-internal + C++ INFO/ERROR/V setup. It provides functions Info, Warning, + Error, Fatal, plus formatting variants such as Infof. It + also provides V-style logging controlled by the -v and + -vmodule=file=2 flags. + + Basic examples: + + glog.Info("Prepare to repel boarders") + + glog.Fatalf("Initialization failed: %s", err) + + See the documentation for the V function for an explanation + of these examples: + + if glog.V(2) { + glog.Info("Starting transaction...") + } + + glog.V(2).Infoln("Processed", nItems, "elements") + + +The repository contains an open source version of the log package +used inside Google. The master copy of the source lives inside +Google, not here. The code in this repo is for export only and is not itself +under development. Feature requests will be ignored. + +Send bug reports to golang-nuts@googlegroups.com. diff --git a/vendor/github.com/golang/glog/glog.go b/vendor/github.com/golang/glog/glog.go new file mode 100644 index 000000000..3e63fffd5 --- /dev/null +++ b/vendor/github.com/golang/glog/glog.go @@ -0,0 +1,1177 @@ +// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ +// +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package glog implements logging analogous to the Google-internal C++ INFO/ERROR/V setup. +// It provides functions Info, Warning, Error, Fatal, plus formatting variants such as +// Infof. It also provides V-style logging controlled by the -v and -vmodule=file=2 flags. +// +// Basic examples: +// +// glog.Info("Prepare to repel boarders") +// +// glog.Fatalf("Initialization failed: %s", err) +// +// See the documentation for the V function for an explanation of these examples: +// +// if glog.V(2) { +// glog.Info("Starting transaction...") +// } +// +// glog.V(2).Infoln("Processed", nItems, "elements") +// +// Log output is buffered and written periodically using Flush. Programs +// should call Flush before exiting to guarantee all log output is written. +// +// By default, all log statements write to files in a temporary directory. +// This package provides several flags that modify this behavior. +// As a result, flag.Parse must be called before any logging is done. +// +// -logtostderr=false +// Logs are written to standard error instead of to files. +// -alsologtostderr=false +// Logs are written to standard error as well as to files. +// -stderrthreshold=ERROR +// Log events at or above this severity are logged to standard +// error as well as to files. +// -log_dir="" +// Log files will be written to this directory instead of the +// default temporary directory. +// +// Other flags provide aids to debugging. +// +// -log_backtrace_at="" +// When set to a file and line number holding a logging statement, +// such as +// -log_backtrace_at=gopherflakes.go:234 +// a stack trace will be written to the Info log whenever execution +// hits that statement. (Unlike with -vmodule, the ".go" must be +// present.) +// -v=0 +// Enable V-leveled logging at the specified level. +// -vmodule="" +// The syntax of the argument is a comma-separated list of pattern=N, +// where pattern is a literal file name (minus the ".go" suffix) or +// "glob" pattern and N is a V level. For instance, +// -vmodule=gopher*=3 +// sets the V level to 3 in all Go files whose names begin "gopher". +// +package glog + +import ( + "bufio" + "bytes" + "errors" + "flag" + "fmt" + "io" + stdLog "log" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) + +// severity identifies the sort of log: info, warning etc. It also implements +// the flag.Value interface. The -stderrthreshold flag is of type severity and +// should be modified only through the flag.Value interface. The values match +// the corresponding constants in C++. +type severity int32 // sync/atomic int32 + +// These constants identify the log levels in order of increasing severity. +// A message written to a high-severity log file is also written to each +// lower-severity log file. +const ( + infoLog severity = iota + warningLog + errorLog + fatalLog + numSeverity = 4 +) + +const severityChar = "IWEF" + +var severityName = []string{ + infoLog: "INFO", + warningLog: "WARNING", + errorLog: "ERROR", + fatalLog: "FATAL", +} + +// get returns the value of the severity. +func (s *severity) get() severity { + return severity(atomic.LoadInt32((*int32)(s))) +} + +// set sets the value of the severity. +func (s *severity) set(val severity) { + atomic.StoreInt32((*int32)(s), int32(val)) +} + +// String is part of the flag.Value interface. +func (s *severity) String() string { + return strconv.FormatInt(int64(*s), 10) +} + +// Get is part of the flag.Value interface. +func (s *severity) Get() interface{} { + return *s +} + +// Set is part of the flag.Value interface. +func (s *severity) Set(value string) error { + var threshold severity + // Is it a known name? + if v, ok := severityByName(value); ok { + threshold = v + } else { + v, err := strconv.Atoi(value) + if err != nil { + return err + } + threshold = severity(v) + } + logging.stderrThreshold.set(threshold) + return nil +} + +func severityByName(s string) (severity, bool) { + s = strings.ToUpper(s) + for i, name := range severityName { + if name == s { + return severity(i), true + } + } + return 0, false +} + +// OutputStats tracks the number of output lines and bytes written. +type OutputStats struct { + lines int64 + bytes int64 +} + +// Lines returns the number of lines written. +func (s *OutputStats) Lines() int64 { + return atomic.LoadInt64(&s.lines) +} + +// Bytes returns the number of bytes written. +func (s *OutputStats) Bytes() int64 { + return atomic.LoadInt64(&s.bytes) +} + +// Stats tracks the number of lines of output and number of bytes +// per severity level. Values must be read with atomic.LoadInt64. +var Stats struct { + Info, Warning, Error OutputStats +} + +var severityStats = [numSeverity]*OutputStats{ + infoLog: &Stats.Info, + warningLog: &Stats.Warning, + errorLog: &Stats.Error, +} + +// Level is exported because it appears in the arguments to V and is +// the type of the v flag, which can be set programmatically. +// It's a distinct type because we want to discriminate it from logType. +// Variables of type level are only changed under logging.mu. +// The -v flag is read only with atomic ops, so the state of the logging +// module is consistent. + +// Level is treated as a sync/atomic int32. + +// Level specifies a level of verbosity for V logs. *Level implements +// flag.Value; the -v flag is of type Level and should be modified +// only through the flag.Value interface. +type Level int32 + +// get returns the value of the Level. +func (l *Level) get() Level { + return Level(atomic.LoadInt32((*int32)(l))) +} + +// set sets the value of the Level. +func (l *Level) set(val Level) { + atomic.StoreInt32((*int32)(l), int32(val)) +} + +// String is part of the flag.Value interface. +func (l *Level) String() string { + return strconv.FormatInt(int64(*l), 10) +} + +// Get is part of the flag.Value interface. +func (l *Level) Get() interface{} { + return *l +} + +// Set is part of the flag.Value interface. +func (l *Level) Set(value string) error { + v, err := strconv.Atoi(value) + if err != nil { + return err + } + logging.mu.Lock() + defer logging.mu.Unlock() + logging.setVState(Level(v), logging.vmodule.filter, false) + return nil +} + +// moduleSpec represents the setting of the -vmodule flag. +type moduleSpec struct { + filter []modulePat +} + +// modulePat contains a filter for the -vmodule flag. +// It holds a verbosity level and a file pattern to match. +type modulePat struct { + pattern string + literal bool // The pattern is a literal string + level Level +} + +// match reports whether the file matches the pattern. It uses a string +// comparison if the pattern contains no metacharacters. +func (m *modulePat) match(file string) bool { + if m.literal { + return file == m.pattern + } + match, _ := filepath.Match(m.pattern, file) + return match +} + +func (m *moduleSpec) String() string { + // Lock because the type is not atomic. TODO: clean this up. + logging.mu.Lock() + defer logging.mu.Unlock() + var b bytes.Buffer + for i, f := range m.filter { + if i > 0 { + b.WriteRune(',') + } + fmt.Fprintf(&b, "%s=%d", f.pattern, f.level) + } + return b.String() +} + +// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the +// struct is not exported. +func (m *moduleSpec) Get() interface{} { + return nil +} + +var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N") + +// Syntax: -vmodule=recordio=2,file=1,gfs*=3 +func (m *moduleSpec) Set(value string) error { + var filter []modulePat + for _, pat := range strings.Split(value, ",") { + if len(pat) == 0 { + // Empty strings such as from a trailing comma can be ignored. + continue + } + patLev := strings.Split(pat, "=") + if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 { + return errVmoduleSyntax + } + pattern := patLev[0] + v, err := strconv.Atoi(patLev[1]) + if err != nil { + return errors.New("syntax error: expect comma-separated list of filename=N") + } + if v < 0 { + return errors.New("negative value for vmodule level") + } + if v == 0 { + continue // Ignore. It's harmless but no point in paying the overhead. + } + // TODO: check syntax of filter? + filter = append(filter, modulePat{pattern, isLiteral(pattern), Level(v)}) + } + logging.mu.Lock() + defer logging.mu.Unlock() + logging.setVState(logging.verbosity, filter, true) + return nil +} + +// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters +// that require filepath.Match to be called to match the pattern. +func isLiteral(pattern string) bool { + return !strings.ContainsAny(pattern, `\*?[]`) +} + +// traceLocation represents the setting of the -log_backtrace_at flag. +type traceLocation struct { + file string + line int +} + +// isSet reports whether the trace location has been specified. +// logging.mu is held. +func (t *traceLocation) isSet() bool { + return t.line > 0 +} + +// match reports whether the specified file and line matches the trace location. +// The argument file name is the full path, not the basename specified in the flag. +// logging.mu is held. +func (t *traceLocation) match(file string, line int) bool { + if t.line != line { + return false + } + if i := strings.LastIndex(file, "/"); i >= 0 { + file = file[i+1:] + } + return t.file == file +} + +func (t *traceLocation) String() string { + // Lock because the type is not atomic. TODO: clean this up. + logging.mu.Lock() + defer logging.mu.Unlock() + return fmt.Sprintf("%s:%d", t.file, t.line) +} + +// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the +// struct is not exported +func (t *traceLocation) Get() interface{} { + return nil +} + +var errTraceSyntax = errors.New("syntax error: expect file.go:234") + +// Syntax: -log_backtrace_at=gopherflakes.go:234 +// Note that unlike vmodule the file extension is included here. +func (t *traceLocation) Set(value string) error { + if value == "" { + // Unset. + t.line = 0 + t.file = "" + } + fields := strings.Split(value, ":") + if len(fields) != 2 { + return errTraceSyntax + } + file, line := fields[0], fields[1] + if !strings.Contains(file, ".") { + return errTraceSyntax + } + v, err := strconv.Atoi(line) + if err != nil { + return errTraceSyntax + } + if v <= 0 { + return errors.New("negative or zero value for level") + } + logging.mu.Lock() + defer logging.mu.Unlock() + t.line = v + t.file = file + return nil +} + +// flushSyncWriter is the interface satisfied by logging destinations. +type flushSyncWriter interface { + Flush() error + Sync() error + io.Writer +} + +func init() { + flag.BoolVar(&logging.toStderr, "logtostderr", false, "log to standard error instead of files") + flag.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files") + flag.Var(&logging.verbosity, "v", "log level for V logs") + flag.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr") + flag.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging") + flag.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace") + + // Default stderrThreshold is ERROR. + logging.stderrThreshold = errorLog + + logging.setVState(0, nil, false) + go logging.flushDaemon() +} + +// Flush flushes all pending log I/O. +func Flush() { + logging.lockAndFlushAll() +} + +// loggingT collects all the global state of the logging setup. +type loggingT struct { + // Boolean flags. Not handled atomically because the flag.Value interface + // does not let us avoid the =true, and that shorthand is necessary for + // compatibility. TODO: does this matter enough to fix? Seems unlikely. + toStderr bool // The -logtostderr flag. + alsoToStderr bool // The -alsologtostderr flag. + + // Level flag. Handled atomically. + stderrThreshold severity // The -stderrthreshold flag. + + // freeList is a list of byte buffers, maintained under freeListMu. + freeList *buffer + // freeListMu maintains the free list. It is separate from the main mutex + // so buffers can be grabbed and printed to without holding the main lock, + // for better parallelization. + freeListMu sync.Mutex + + // mu protects the remaining elements of this structure and is + // used to synchronize logging. + mu sync.Mutex + // file holds writer for each of the log types. + file [numSeverity]flushSyncWriter + // pcs is used in V to avoid an allocation when computing the caller's PC. + pcs [1]uintptr + // vmap is a cache of the V Level for each V() call site, identified by PC. + // It is wiped whenever the vmodule flag changes state. + vmap map[uintptr]Level + // filterLength stores the length of the vmodule filter chain. If greater + // than zero, it means vmodule is enabled. It may be read safely + // using sync.LoadInt32, but is only modified under mu. + filterLength int32 + // traceLocation is the state of the -log_backtrace_at flag. + traceLocation traceLocation + // These flags are modified only under lock, although verbosity may be fetched + // safely using atomic.LoadInt32. + vmodule moduleSpec // The state of the -vmodule flag. + verbosity Level // V logging level, the value of the -v flag/ +} + +// buffer holds a byte Buffer for reuse. The zero value is ready for use. +type buffer struct { + bytes.Buffer + tmp [64]byte // temporary byte array for creating headers. + next *buffer +} + +var logging loggingT + +// setVState sets a consistent state for V logging. +// l.mu is held. +func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool) { + // Turn verbosity off so V will not fire while we are in transition. + logging.verbosity.set(0) + // Ditto for filter length. + atomic.StoreInt32(&logging.filterLength, 0) + + // Set the new filters and wipe the pc->Level map if the filter has changed. + if setFilter { + logging.vmodule.filter = filter + logging.vmap = make(map[uintptr]Level) + } + + // Things are consistent now, so enable filtering and verbosity. + // They are enabled in order opposite to that in V. + atomic.StoreInt32(&logging.filterLength, int32(len(filter))) + logging.verbosity.set(verbosity) +} + +// getBuffer returns a new, ready-to-use buffer. +func (l *loggingT) getBuffer() *buffer { + l.freeListMu.Lock() + b := l.freeList + if b != nil { + l.freeList = b.next + } + l.freeListMu.Unlock() + if b == nil { + b = new(buffer) + } else { + b.next = nil + b.Reset() + } + return b +} + +// putBuffer returns a buffer to the free list. +func (l *loggingT) putBuffer(b *buffer) { + if b.Len() >= 256 { + // Let big buffers die a natural death. + return + } + l.freeListMu.Lock() + b.next = l.freeList + l.freeList = b + l.freeListMu.Unlock() +} + +var timeNow = time.Now // Stubbed out for testing. + +/* +header formats a log header as defined by the C++ implementation. +It returns a buffer containing the formatted header and the user's file and line number. +The depth specifies how many stack frames above lives the source line to be identified in the log message. + +Log lines have this form: + Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg... +where the fields are defined as follows: + L A single character, representing the log level (eg 'I' for INFO) + mm The month (zero padded; ie May is '05') + dd The day (zero padded) + hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds + threadid The space-padded thread ID as returned by GetTID() + file The file name + line The line number + msg The user-supplied message +*/ +func (l *loggingT) header(s severity, depth int) (*buffer, string, int) { + _, file, line, ok := runtime.Caller(3 + depth) + if !ok { + file = "???" + line = 1 + } else { + slash := strings.LastIndex(file, "/") + if slash >= 0 { + file = file[slash+1:] + } + } + return l.formatHeader(s, file, line), file, line +} + +// formatHeader formats a log header using the provided file name and line number. +func (l *loggingT) formatHeader(s severity, file string, line int) *buffer { + now := timeNow() + if line < 0 { + line = 0 // not a real line number, but acceptable to someDigits + } + if s > fatalLog { + s = infoLog // for safety. + } + buf := l.getBuffer() + + // Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand. + // It's worth about 3X. Fprintf is hard. + _, month, day := now.Date() + hour, minute, second := now.Clock() + // Lmmdd hh:mm:ss.uuuuuu threadid file:line] + buf.tmp[0] = severityChar[s] + buf.twoDigits(1, int(month)) + buf.twoDigits(3, day) + buf.tmp[5] = ' ' + buf.twoDigits(6, hour) + buf.tmp[8] = ':' + buf.twoDigits(9, minute) + buf.tmp[11] = ':' + buf.twoDigits(12, second) + buf.tmp[14] = '.' + buf.nDigits(6, 15, now.Nanosecond()/1000, '0') + buf.tmp[21] = ' ' + buf.nDigits(7, 22, pid, ' ') // TODO: should be TID + buf.tmp[29] = ' ' + buf.Write(buf.tmp[:30]) + buf.WriteString(file) + buf.tmp[0] = ':' + n := buf.someDigits(1, line) + buf.tmp[n+1] = ']' + buf.tmp[n+2] = ' ' + buf.Write(buf.tmp[:n+3]) + return buf +} + +// Some custom tiny helper functions to print the log header efficiently. + +const digits = "0123456789" + +// twoDigits formats a zero-prefixed two-digit integer at buf.tmp[i]. +func (buf *buffer) twoDigits(i, d int) { + buf.tmp[i+1] = digits[d%10] + d /= 10 + buf.tmp[i] = digits[d%10] +} + +// nDigits formats an n-digit integer at buf.tmp[i], +// padding with pad on the left. +// It assumes d >= 0. +func (buf *buffer) nDigits(n, i, d int, pad byte) { + j := n - 1 + for ; j >= 0 && d > 0; j-- { + buf.tmp[i+j] = digits[d%10] + d /= 10 + } + for ; j >= 0; j-- { + buf.tmp[i+j] = pad + } +} + +// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i]. +func (buf *buffer) someDigits(i, d int) int { + // Print into the top, then copy down. We know there's space for at least + // a 10-digit number. + j := len(buf.tmp) + for { + j-- + buf.tmp[j] = digits[d%10] + d /= 10 + if d == 0 { + break + } + } + return copy(buf.tmp[i:], buf.tmp[j:]) +} + +func (l *loggingT) println(s severity, args ...interface{}) { + buf, file, line := l.header(s, 0) + fmt.Fprintln(buf, args...) + l.output(s, buf, file, line, false) +} + +func (l *loggingT) print(s severity, args ...interface{}) { + l.printDepth(s, 1, args...) +} + +func (l *loggingT) printDepth(s severity, depth int, args ...interface{}) { + buf, file, line := l.header(s, depth) + fmt.Fprint(buf, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, false) +} + +func (l *loggingT) printf(s severity, format string, args ...interface{}) { + buf, file, line := l.header(s, 0) + fmt.Fprintf(buf, format, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, false) +} + +// printWithFileLine behaves like print but uses the provided file and line number. If +// alsoLogToStderr is true, the log message always appears on standard error; it +// will also appear in the log file unless --logtostderr is set. +func (l *loggingT) printWithFileLine(s severity, file string, line int, alsoToStderr bool, args ...interface{}) { + buf := l.formatHeader(s, file, line) + fmt.Fprint(buf, args...) + if buf.Bytes()[buf.Len()-1] != '\n' { + buf.WriteByte('\n') + } + l.output(s, buf, file, line, alsoToStderr) +} + +// output writes the data to the log files and releases the buffer. +func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoToStderr bool) { + l.mu.Lock() + if l.traceLocation.isSet() { + if l.traceLocation.match(file, line) { + buf.Write(stacks(false)) + } + } + data := buf.Bytes() + if l.toStderr { + os.Stderr.Write(data) + } else { + if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() { + os.Stderr.Write(data) + } + if l.file[s] == nil { + if err := l.createFiles(s); err != nil { + os.Stderr.Write(data) // Make sure the message appears somewhere. + l.exit(err) + } + } + switch s { + case fatalLog: + l.file[fatalLog].Write(data) + fallthrough + case errorLog: + l.file[errorLog].Write(data) + fallthrough + case warningLog: + l.file[warningLog].Write(data) + fallthrough + case infoLog: + l.file[infoLog].Write(data) + } + } + if s == fatalLog { + // If we got here via Exit rather than Fatal, print no stacks. + if atomic.LoadUint32(&fatalNoStacks) > 0 { + l.mu.Unlock() + timeoutFlush(10 * time.Second) + os.Exit(1) + } + // Dump all goroutine stacks before exiting. + // First, make sure we see the trace for the current goroutine on standard error. + // If -logtostderr has been specified, the loop below will do that anyway + // as the first stack in the full dump. + if !l.toStderr { + os.Stderr.Write(stacks(false)) + } + // Write the stack trace for all goroutines to the files. + trace := stacks(true) + logExitFunc = func(error) {} // If we get a write error, we'll still exit below. + for log := fatalLog; log >= infoLog; log-- { + if f := l.file[log]; f != nil { // Can be nil if -logtostderr is set. + f.Write(trace) + } + } + l.mu.Unlock() + timeoutFlush(10 * time.Second) + os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway. + } + l.putBuffer(buf) + l.mu.Unlock() + if stats := severityStats[s]; stats != nil { + atomic.AddInt64(&stats.lines, 1) + atomic.AddInt64(&stats.bytes, int64(len(data))) + } +} + +// timeoutFlush calls Flush and returns when it completes or after timeout +// elapses, whichever happens first. This is needed because the hooks invoked +// by Flush may deadlock when glog.Fatal is called from a hook that holds +// a lock. +func timeoutFlush(timeout time.Duration) { + done := make(chan bool, 1) + go func() { + Flush() // calls logging.lockAndFlushAll() + done <- true + }() + select { + case <-done: + case <-time.After(timeout): + fmt.Fprintln(os.Stderr, "glog: Flush took longer than", timeout) + } +} + +// stacks is a wrapper for runtime.Stack that attempts to recover the data for all goroutines. +func stacks(all bool) []byte { + // We don't know how big the traces are, so grow a few times if they don't fit. Start large, though. + n := 10000 + if all { + n = 100000 + } + var trace []byte + for i := 0; i < 5; i++ { + trace = make([]byte, n) + nbytes := runtime.Stack(trace, all) + if nbytes < len(trace) { + return trace[:nbytes] + } + n *= 2 + } + return trace +} + +// logExitFunc provides a simple mechanism to override the default behavior +// of exiting on error. Used in testing and to guarantee we reach a required exit +// for fatal logs. Instead, exit could be a function rather than a method but that +// would make its use clumsier. +var logExitFunc func(error) + +// exit is called if there is trouble creating or writing log files. +// It flushes the logs and exits the program; there's no point in hanging around. +// l.mu is held. +func (l *loggingT) exit(err error) { + fmt.Fprintf(os.Stderr, "log: exiting because of error: %s\n", err) + // If logExitFunc is set, we do that instead of exiting. + if logExitFunc != nil { + logExitFunc(err) + return + } + l.flushAll() + os.Exit(2) +} + +// syncBuffer joins a bufio.Writer to its underlying file, providing access to the +// file's Sync method and providing a wrapper for the Write method that provides log +// file rotation. There are conflicting methods, so the file cannot be embedded. +// l.mu is held for all its methods. +type syncBuffer struct { + logger *loggingT + *bufio.Writer + file *os.File + sev severity + nbytes uint64 // The number of bytes written to this file +} + +func (sb *syncBuffer) Sync() error { + return sb.file.Sync() +} + +func (sb *syncBuffer) Write(p []byte) (n int, err error) { + if sb.nbytes+uint64(len(p)) >= MaxSize { + if err := sb.rotateFile(time.Now()); err != nil { + sb.logger.exit(err) + } + } + n, err = sb.Writer.Write(p) + sb.nbytes += uint64(n) + if err != nil { + sb.logger.exit(err) + } + return +} + +// rotateFile closes the syncBuffer's file and starts a new one. +func (sb *syncBuffer) rotateFile(now time.Time) error { + if sb.file != nil { + sb.Flush() + sb.file.Close() + } + var err error + sb.file, _, err = create(severityName[sb.sev], now) + sb.nbytes = 0 + if err != nil { + return err + } + + sb.Writer = bufio.NewWriterSize(sb.file, bufferSize) + + // Write header. + var buf bytes.Buffer + fmt.Fprintf(&buf, "Log file created at: %s\n", now.Format("2006/01/02 15:04:05")) + fmt.Fprintf(&buf, "Running on machine: %s\n", host) + fmt.Fprintf(&buf, "Binary: Built with %s %s for %s/%s\n", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH) + fmt.Fprintf(&buf, "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg\n") + n, err := sb.file.Write(buf.Bytes()) + sb.nbytes += uint64(n) + return err +} + +// bufferSize sizes the buffer associated with each log file. It's large +// so that log records can accumulate without the logging thread blocking +// on disk I/O. The flushDaemon will block instead. +const bufferSize = 256 * 1024 + +// createFiles creates all the log files for severity from sev down to infoLog. +// l.mu is held. +func (l *loggingT) createFiles(sev severity) error { + now := time.Now() + // Files are created in decreasing severity order, so as soon as we find one + // has already been created, we can stop. + for s := sev; s >= infoLog && l.file[s] == nil; s-- { + sb := &syncBuffer{ + logger: l, + sev: s, + } + if err := sb.rotateFile(now); err != nil { + return err + } + l.file[s] = sb + } + return nil +} + +const flushInterval = 30 * time.Second + +// flushDaemon periodically flushes the log file buffers. +func (l *loggingT) flushDaemon() { + for _ = range time.NewTicker(flushInterval).C { + l.lockAndFlushAll() + } +} + +// lockAndFlushAll is like flushAll but locks l.mu first. +func (l *loggingT) lockAndFlushAll() { + l.mu.Lock() + l.flushAll() + l.mu.Unlock() +} + +// flushAll flushes all the logs and attempts to "sync" their data to disk. +// l.mu is held. +func (l *loggingT) flushAll() { + // Flush from fatal down, in case there's trouble flushing. + for s := fatalLog; s >= infoLog; s-- { + file := l.file[s] + if file != nil { + file.Flush() // ignore error + file.Sync() // ignore error + } + } +} + +// CopyStandardLogTo arranges for messages written to the Go "log" package's +// default logs to also appear in the Google logs for the named and lower +// severities. Subsequent changes to the standard log's default output location +// or format may break this behavior. +// +// Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not +// recognized, CopyStandardLogTo panics. +func CopyStandardLogTo(name string) { + sev, ok := severityByName(name) + if !ok { + panic(fmt.Sprintf("log.CopyStandardLogTo(%q): unrecognized severity name", name)) + } + // Set a log format that captures the user's file and line: + // d.go:23: message + stdLog.SetFlags(stdLog.Lshortfile) + stdLog.SetOutput(logBridge(sev)) +} + +// logBridge provides the Write method that enables CopyStandardLogTo to connect +// Go's standard logs to the logs provided by this package. +type logBridge severity + +// Write parses the standard logging line and passes its components to the +// logger for severity(lb). +func (lb logBridge) Write(b []byte) (n int, err error) { + var ( + file = "???" + line = 1 + text string + ) + // Split "d.go:23: message" into "d.go", "23", and "message". + if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 { + text = fmt.Sprintf("bad log format: %s", b) + } else { + file = string(parts[0]) + text = string(parts[2][1:]) // skip leading space + line, err = strconv.Atoi(string(parts[1])) + if err != nil { + text = fmt.Sprintf("bad line number: %s", b) + line = 1 + } + } + // printWithFileLine with alsoToStderr=true, so standard log messages + // always appear on standard error. + logging.printWithFileLine(severity(lb), file, line, true, text) + return len(b), nil +} + +// setV computes and remembers the V level for a given PC +// when vmodule is enabled. +// File pattern matching takes the basename of the file, stripped +// of its .go suffix, and uses filepath.Match, which is a little more +// general than the *? matching used in C++. +// l.mu is held. +func (l *loggingT) setV(pc uintptr) Level { + fn := runtime.FuncForPC(pc) + file, _ := fn.FileLine(pc) + // The file is something like /a/b/c/d.go. We want just the d. + if strings.HasSuffix(file, ".go") { + file = file[:len(file)-3] + } + if slash := strings.LastIndex(file, "/"); slash >= 0 { + file = file[slash+1:] + } + for _, filter := range l.vmodule.filter { + if filter.match(file) { + l.vmap[pc] = filter.level + return filter.level + } + } + l.vmap[pc] = 0 + return 0 +} + +// Verbose is a boolean type that implements Infof (like Printf) etc. +// See the documentation of V for more information. +type Verbose bool + +// V reports whether verbosity at the call site is at least the requested level. +// The returned value is a boolean of type Verbose, which implements Info, Infoln +// and Infof. These methods will write to the Info log if called. +// Thus, one may write either +// if glog.V(2) { glog.Info("log this") } +// or +// glog.V(2).Info("log this") +// The second form is shorter but the first is cheaper if logging is off because it does +// not evaluate its arguments. +// +// Whether an individual call to V generates a log record depends on the setting of +// the -v and --vmodule flags; both are off by default. If the level in the call to +// V is at least the value of -v, or of -vmodule for the source file containing the +// call, the V call will log. +func V(level Level) Verbose { + // This function tries hard to be cheap unless there's work to do. + // The fast path is two atomic loads and compares. + + // Here is a cheap but safe test to see if V logging is enabled globally. + if logging.verbosity.get() >= level { + return Verbose(true) + } + + // It's off globally but it vmodule may still be set. + // Here is another cheap but safe test to see if vmodule is enabled. + if atomic.LoadInt32(&logging.filterLength) > 0 { + // Now we need a proper lock to use the logging structure. The pcs field + // is shared so we must lock before accessing it. This is fairly expensive, + // but if V logging is enabled we're slow anyway. + logging.mu.Lock() + defer logging.mu.Unlock() + if runtime.Callers(2, logging.pcs[:]) == 0 { + return Verbose(false) + } + v, ok := logging.vmap[logging.pcs[0]] + if !ok { + v = logging.setV(logging.pcs[0]) + } + return Verbose(v >= level) + } + return Verbose(false) +} + +// Info is equivalent to the global Info function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Info(args ...interface{}) { + if v { + logging.print(infoLog, args...) + } +} + +// Infoln is equivalent to the global Infoln function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Infoln(args ...interface{}) { + if v { + logging.println(infoLog, args...) + } +} + +// Infof is equivalent to the global Infof function, guarded by the value of v. +// See the documentation of V for usage. +func (v Verbose) Infof(format string, args ...interface{}) { + if v { + logging.printf(infoLog, format, args...) + } +} + +// Info logs to the INFO log. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Info(args ...interface{}) { + logging.print(infoLog, args...) +} + +// InfoDepth acts as Info but uses depth to determine which call frame to log. +// InfoDepth(0, "msg") is the same as Info("msg"). +func InfoDepth(depth int, args ...interface{}) { + logging.printDepth(infoLog, depth, args...) +} + +// Infoln logs to the INFO log. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Infoln(args ...interface{}) { + logging.println(infoLog, args...) +} + +// Infof logs to the INFO log. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Infof(format string, args ...interface{}) { + logging.printf(infoLog, format, args...) +} + +// Warning logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Warning(args ...interface{}) { + logging.print(warningLog, args...) +} + +// WarningDepth acts as Warning but uses depth to determine which call frame to log. +// WarningDepth(0, "msg") is the same as Warning("msg"). +func WarningDepth(depth int, args ...interface{}) { + logging.printDepth(warningLog, depth, args...) +} + +// Warningln logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Warningln(args ...interface{}) { + logging.println(warningLog, args...) +} + +// Warningf logs to the WARNING and INFO logs. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Warningf(format string, args ...interface{}) { + logging.printf(warningLog, format, args...) +} + +// Error logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Error(args ...interface{}) { + logging.print(errorLog, args...) +} + +// ErrorDepth acts as Error but uses depth to determine which call frame to log. +// ErrorDepth(0, "msg") is the same as Error("msg"). +func ErrorDepth(depth int, args ...interface{}) { + logging.printDepth(errorLog, depth, args...) +} + +// Errorln logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Errorln(args ...interface{}) { + logging.println(errorLog, args...) +} + +// Errorf logs to the ERROR, WARNING, and INFO logs. +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Errorf(format string, args ...interface{}) { + logging.printf(errorLog, format, args...) +} + +// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Fatal(args ...interface{}) { + logging.print(fatalLog, args...) +} + +// FatalDepth acts as Fatal but uses depth to determine which call frame to log. +// FatalDepth(0, "msg") is the same as Fatal("msg"). +func FatalDepth(depth int, args ...interface{}) { + logging.printDepth(fatalLog, depth, args...) +} + +// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Println; a newline is appended if missing. +func Fatalln(args ...interface{}) { + logging.println(fatalLog, args...) +} + +// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs, +// including a stack trace of all running goroutines, then calls os.Exit(255). +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Fatalf(format string, args ...interface{}) { + logging.printf(fatalLog, format, args...) +} + +// fatalNoStacks is non-zero if we are to exit without dumping goroutine stacks. +// It allows Exit and relatives to use the Fatal logs. +var fatalNoStacks uint32 + +// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +// Arguments are handled in the manner of fmt.Print; a newline is appended if missing. +func Exit(args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.print(fatalLog, args...) +} + +// ExitDepth acts as Exit but uses depth to determine which call frame to log. +// ExitDepth(0, "msg") is the same as Exit("msg"). +func ExitDepth(depth int, args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.printDepth(fatalLog, depth, args...) +} + +// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +func Exitln(args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.println(fatalLog, args...) +} + +// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). +// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. +func Exitf(format string, args ...interface{}) { + atomic.StoreUint32(&fatalNoStacks, 1) + logging.printf(fatalLog, format, args...) +} diff --git a/vendor/github.com/golang/glog/glog_file.go b/vendor/github.com/golang/glog/glog_file.go new file mode 100644 index 000000000..65075d281 --- /dev/null +++ b/vendor/github.com/golang/glog/glog_file.go @@ -0,0 +1,124 @@ +// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ +// +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// File I/O for logs. + +package glog + +import ( + "errors" + "flag" + "fmt" + "os" + "os/user" + "path/filepath" + "strings" + "sync" + "time" +) + +// MaxSize is the maximum size of a log file in bytes. +var MaxSize uint64 = 1024 * 1024 * 1800 + +// logDirs lists the candidate directories for new log files. +var logDirs []string + +// If non-empty, overrides the choice of directory in which to write logs. +// See createLogDirs for the full list of possible destinations. +var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory") + +func createLogDirs() { + if *logDir != "" { + logDirs = append(logDirs, *logDir) + } + logDirs = append(logDirs, os.TempDir()) +} + +var ( + pid = os.Getpid() + program = filepath.Base(os.Args[0]) + host = "unknownhost" + userName = "unknownuser" +) + +func init() { + h, err := os.Hostname() + if err == nil { + host = shortHostname(h) + } + + current, err := user.Current() + if err == nil { + userName = current.Username + } + + // Sanitize userName since it may contain filepath separators on Windows. + userName = strings.Replace(userName, `\`, "_", -1) +} + +// shortHostname returns its argument, truncating at the first period. +// For instance, given "www.google.com" it returns "www". +func shortHostname(hostname string) string { + if i := strings.Index(hostname, "."); i >= 0 { + return hostname[:i] + } + return hostname +} + +// logName returns a new log file name containing tag, with start time t, and +// the name for the symlink for tag. +func logName(tag string, t time.Time) (name, link string) { + name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d", + program, + host, + userName, + tag, + t.Year(), + t.Month(), + t.Day(), + t.Hour(), + t.Minute(), + t.Second(), + pid) + return name, program + "." + tag +} + +var onceLogDirs sync.Once + +// create creates a new log file and returns the file and its filename, which +// contains tag ("INFO", "FATAL", etc.) and t. If the file is created +// successfully, create also attempts to update the symlink for that tag, ignoring +// errors. +func create(tag string, t time.Time) (f *os.File, filename string, err error) { + onceLogDirs.Do(createLogDirs) + if len(logDirs) == 0 { + return nil, "", errors.New("log: no log dirs") + } + name, link := logName(tag, t) + var lastErr error + for _, dir := range logDirs { + fname := filepath.Join(dir, name) + f, err := os.Create(fname) + if err == nil { + symlink := filepath.Join(dir, link) + os.Remove(symlink) // ignore err + os.Symlink(name, symlink) // ignore err + return f, fname, nil + } + lastErr = err + } + return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr) +} diff --git a/vendor/github.com/golang/protobuf/AUTHORS b/vendor/github.com/golang/protobuf/AUTHORS new file mode 100644 index 000000000..15167cd74 --- /dev/null +++ b/vendor/github.com/golang/protobuf/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/github.com/golang/protobuf/CONTRIBUTORS b/vendor/github.com/golang/protobuf/CONTRIBUTORS new file mode 100644 index 000000000..1c4577e96 --- /dev/null +++ b/vendor/github.com/golang/protobuf/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/github.com/golang/protobuf/LICENSE b/vendor/github.com/golang/protobuf/LICENSE new file mode 100644 index 000000000..1b1b1921e --- /dev/null +++ b/vendor/github.com/golang/protobuf/LICENSE @@ -0,0 +1,31 @@ +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/vendor/github.com/golang/protobuf/proto/Makefile b/vendor/github.com/golang/protobuf/proto/Makefile new file mode 100644 index 000000000..e2e0651a9 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/Makefile @@ -0,0 +1,43 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +install: + go install + +test: install generate-test-pbs + go test + + +generate-test-pbs: + make install + make -C testdata + protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto + make diff --git a/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go new file mode 100644 index 000000000..e392575b3 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/clone.go @@ -0,0 +1,229 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer deep copy and merge. +// TODO: RawMessage. + +package proto + +import ( + "log" + "reflect" + "strings" +) + +// Clone returns a deep copy of a protocol buffer. +func Clone(pb Message) Message { + in := reflect.ValueOf(pb) + if in.IsNil() { + return pb + } + + out := reflect.New(in.Type().Elem()) + // out is empty so a merge is a deep copy. + mergeStruct(out.Elem(), in.Elem()) + return out.Interface().(Message) +} + +// Merge merges src into dst. +// Required and optional fields that are set in src will be set to that value in dst. +// Elements of repeated fields will be appended. +// Merge panics if src and dst are not the same type, or if dst is nil. +func Merge(dst, src Message) { + in := reflect.ValueOf(src) + out := reflect.ValueOf(dst) + if out.IsNil() { + panic("proto: nil destination") + } + if in.Type() != out.Type() { + // Explicit test prior to mergeStruct so that mistyped nils will fail + panic("proto: type mismatch") + } + if in.IsNil() { + // Merging nil into non-nil is a quiet no-op + return + } + mergeStruct(out.Elem(), in.Elem()) +} + +func mergeStruct(out, in reflect.Value) { + sprop := GetProperties(in.Type()) + for i := 0; i < in.NumField(); i++ { + f := in.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) + } + + if emIn, ok := extendable(in.Addr().Interface()); ok { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + uf := in.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return + } + uin := uf.Bytes() + if len(uin) > 0 { + out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) + } +} + +// mergeAny performs a merge between two values of the same type. +// viaPtr indicates whether the values were indirected through a pointer (implying proto2). +// prop is set if this is a struct field (it may be nil). +func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { + if in.Type() == protoMessageType { + if !in.IsNil() { + if out.IsNil() { + out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) + } else { + Merge(out.Interface().(Message), in.Interface().(Message)) + } + } + return + } + switch in.Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + if !viaPtr && isProto3Zero(in) { + return + } + out.Set(in) + case reflect.Interface: + // Probably a oneof field; copy non-nil values. + if in.IsNil() { + return + } + // Allocate destination if it is not set, or set to a different type. + // Otherwise we will merge as normal. + if out.IsNil() || out.Elem().Type() != in.Elem().Type() { + out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) + } + mergeAny(out.Elem(), in.Elem(), false, nil) + case reflect.Map: + if in.Len() == 0 { + return + } + if out.IsNil() { + out.Set(reflect.MakeMap(in.Type())) + } + // For maps with value types of *T or []byte we need to deep copy each value. + elemKind := in.Type().Elem().Kind() + for _, key := range in.MapKeys() { + var val reflect.Value + switch elemKind { + case reflect.Ptr: + val = reflect.New(in.Type().Elem().Elem()) + mergeAny(val, in.MapIndex(key), false, nil) + case reflect.Slice: + val = in.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + default: + val = in.MapIndex(key) + } + out.SetMapIndex(key, val) + } + case reflect.Ptr: + if in.IsNil() { + return + } + if out.IsNil() { + out.Set(reflect.New(in.Elem().Type())) + } + mergeAny(out.Elem(), in.Elem(), true, nil) + case reflect.Slice: + if in.IsNil() { + return + } + if in.Type().Elem().Kind() == reflect.Uint8 { + // []byte is a scalar bytes field, not a repeated field. + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value, and should not + // be merged. + if prop != nil && prop.proto3 && in.Len() == 0 { + return + } + + // Make a deep copy. + // Append to []byte{} instead of []byte(nil) so that we never end up + // with a nil result. + out.SetBytes(append([]byte{}, in.Bytes()...)) + return + } + n := in.Len() + if out.IsNil() { + out.Set(reflect.MakeSlice(in.Type(), 0, n)) + } + switch in.Type().Elem().Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + out.Set(reflect.AppendSlice(out, in)) + default: + for i := 0; i < n; i++ { + x := reflect.Indirect(reflect.New(in.Type().Elem())) + mergeAny(x, in.Index(i), false, nil) + out.Set(reflect.Append(out, x)) + } + } + case reflect.Struct: + mergeStruct(out, in) + default: + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to copy %v", in) + } +} + +func mergeExtension(out, in map[int32]Extension) { + for extNum, eIn := range in { + eOut := Extension{desc: eIn.desc} + if eIn.value != nil { + v := reflect.New(reflect.TypeOf(eIn.value)).Elem() + mergeAny(v, reflect.ValueOf(eIn.value), false, nil) + eOut.value = v.Interface() + } + if eIn.enc != nil { + eOut.enc = make([]byte, len(eIn.enc)) + copy(eOut.enc, eIn.enc) + } + + out[extNum] = eOut + } +} diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go new file mode 100644 index 000000000..aa207298f --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/decode.go @@ -0,0 +1,970 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for decoding protocol buffer data to construct in-memory representations. + */ + +import ( + "errors" + "fmt" + "io" + "os" + "reflect" +) + +// errOverflow is returned when an integer is too large to be represented. +var errOverflow = errors.New("proto: integer overflow") + +// ErrInternalBadWireType is returned by generated code when an incorrect +// wire type is encountered. It does not get returned to user code. +var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") + +// The fundamental decoders that interpret bytes on the wire. +// Those that take integer types all return uint64 and are +// therefore of type valueDecoder. + +// DecodeVarint reads a varint-encoded integer from the slice. +// It returns the integer and the number of bytes consumed, or +// zero if there is not enough. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func DecodeVarint(buf []byte) (x uint64, n int) { + for shift := uint(0); shift < 64; shift += 7 { + if n >= len(buf) { + return 0, 0 + } + b := uint64(buf[n]) + n++ + x |= (b & 0x7F) << shift + if (b & 0x80) == 0 { + return x, n + } + } + + // The number is too large to represent in a 64-bit value. + return 0, 0 +} + +func (p *Buffer) decodeVarintSlow() (x uint64, err error) { + i := p.index + l := len(p.buf) + + for shift := uint(0); shift < 64; shift += 7 { + if i >= l { + err = io.ErrUnexpectedEOF + return + } + b := p.buf[i] + i++ + x |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + p.index = i + return + } + } + + // The number is too large to represent in a 64-bit value. + err = errOverflow + return +} + +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) DecodeVarint() (x uint64, err error) { + i := p.index + buf := p.buf + + if i >= len(buf) { + return 0, io.ErrUnexpectedEOF + } else if buf[i] < 0x80 { + p.index++ + return uint64(buf[i]), nil + } else if len(buf)-i < 10 { + return p.decodeVarintSlow() + } + + var b uint64 + // we already checked the first byte + x = uint64(buf[i]) - 0x80 + i++ + + b = uint64(buf[i]) + i++ + x += b << 7 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 7 + + b = uint64(buf[i]) + i++ + x += b << 14 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 14 + + b = uint64(buf[i]) + i++ + x += b << 21 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 21 + + b = uint64(buf[i]) + i++ + x += b << 28 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 28 + + b = uint64(buf[i]) + i++ + x += b << 35 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 35 + + b = uint64(buf[i]) + i++ + x += b << 42 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 42 + + b = uint64(buf[i]) + i++ + x += b << 49 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 49 + + b = uint64(buf[i]) + i++ + x += b << 56 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 56 + + b = uint64(buf[i]) + i++ + x += b << 63 + if b&0x80 == 0 { + goto done + } + // x -= 0x80 << 63 // Always zero. + + return 0, errOverflow + +done: + p.index = i + return x, nil +} + +// DecodeFixed64 reads a 64-bit integer from the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) DecodeFixed64() (x uint64, err error) { + // x, err already 0 + i := p.index + 8 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-8]) + x |= uint64(p.buf[i-7]) << 8 + x |= uint64(p.buf[i-6]) << 16 + x |= uint64(p.buf[i-5]) << 24 + x |= uint64(p.buf[i-4]) << 32 + x |= uint64(p.buf[i-3]) << 40 + x |= uint64(p.buf[i-2]) << 48 + x |= uint64(p.buf[i-1]) << 56 + return +} + +// DecodeFixed32 reads a 32-bit integer from the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) DecodeFixed32() (x uint64, err error) { + // x, err already 0 + i := p.index + 4 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-4]) + x |= uint64(p.buf[i-3]) << 8 + x |= uint64(p.buf[i-2]) << 16 + x |= uint64(p.buf[i-1]) << 24 + return +} + +// DecodeZigzag64 reads a zigzag-encoded 64-bit integer +// from the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) DecodeZigzag64() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) + return +} + +// DecodeZigzag32 reads a zigzag-encoded 32-bit integer +// from the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) DecodeZigzag32() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) + return +} + +// These are not ValueDecoders: they produce an array of bytes or a string. +// bytes, embedded messages + +// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { + n, err := p.DecodeVarint() + if err != nil { + return nil, err + } + + nb := int(n) + if nb < 0 { + return nil, fmt.Errorf("proto: bad byte length %d", nb) + } + end := p.index + nb + if end < p.index || end > len(p.buf) { + return nil, io.ErrUnexpectedEOF + } + + if !alloc { + // todo: check if can get more uses of alloc=false + buf = p.buf[p.index:end] + p.index += nb + return + } + + buf = make([]byte, nb) + copy(buf, p.buf[p.index:]) + p.index += nb + return +} + +// DecodeStringBytes reads an encoded string from the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) DecodeStringBytes() (s string, err error) { + buf, err := p.DecodeRawBytes(false) + if err != nil { + return + } + return string(buf), nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +// If the protocol buffer has extensions, and the field matches, add it as an extension. +// Otherwise, if the XXX_unrecognized field exists, append the skipped data there. +func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { + oi := o.index + + err := o.skip(t, tag, wire) + if err != nil { + return err + } + + if !unrecField.IsValid() { + return nil + } + + ptr := structPointer_Bytes(base, unrecField) + + // Add the skipped field to struct field + obuf := o.buf + + o.buf = *ptr + o.EncodeVarint(uint64(tag<<3 | wire)) + *ptr = append(o.buf, obuf[oi:o.index]...) + + o.buf = obuf + + return nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +func (o *Buffer) skip(t reflect.Type, tag, wire int) error { + + var u uint64 + var err error + + switch wire { + case WireVarint: + _, err = o.DecodeVarint() + case WireFixed64: + _, err = o.DecodeFixed64() + case WireBytes: + _, err = o.DecodeRawBytes(false) + case WireFixed32: + _, err = o.DecodeFixed32() + case WireStartGroup: + for { + u, err = o.DecodeVarint() + if err != nil { + break + } + fwire := int(u & 0x7) + if fwire == WireEndGroup { + break + } + ftag := int(u >> 3) + err = o.skip(t, ftag, fwire) + if err != nil { + break + } + } + default: + err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) + } + return err +} + +// Unmarshaler is the interface representing objects that can +// unmarshal themselves. The method should reset the receiver before +// decoding starts. The argument points to data that may be +// overwritten, so implementations should not keep references to the +// buffer. +type Unmarshaler interface { + Unmarshal([]byte) error +} + +// Unmarshal parses the protocol buffer representation in buf and places the +// decoded result in pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// Unmarshal resets pb before starting to unmarshal, so any +// existing data in pb is always removed. Use UnmarshalMerge +// to preserve and append to existing data. +func Unmarshal(buf []byte, pb Message) error { + pb.Reset() + return UnmarshalMerge(buf, pb) +} + +// UnmarshalMerge parses the protocol buffer representation in buf and +// writes the decoded result to pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// UnmarshalMerge merges into existing data in pb. +// Most code should use Unmarshal instead. +func UnmarshalMerge(buf []byte, pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) +} + +// DecodeMessage reads a count-delimited message from the Buffer. +func (p *Buffer) DecodeMessage(pb Message) error { + enc, err := p.DecodeRawBytes(false) + if err != nil { + return err + } + return NewBuffer(enc).Unmarshal(pb) +} + +// DecodeGroup reads a tag-delimited group from the Buffer. +func (p *Buffer) DecodeGroup(pb Message) error { + typ, base, err := getbase(pb) + if err != nil { + return err + } + return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) +} + +// Unmarshal parses the protocol buffer representation in the +// Buffer and places the decoded result in pb. If the struct +// underlying pb does not match the data in the buffer, the results can be +// unpredictable. +// +// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. +func (p *Buffer) Unmarshal(pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + err := u.Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } + + typ, base, err := getbase(pb) + if err != nil { + return err + } + + err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) + + if collectStats { + stats.Decode++ + } + + return err +} + +// unmarshalType does the work of unmarshaling a structure. +func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { + var state errorState + required, reqFields := prop.reqCount, uint64(0) + + var err error + for err == nil && o.index < len(o.buf) { + oi := o.index + var u uint64 + u, err = o.DecodeVarint() + if err != nil { + break + } + wire := int(u & 0x7) + if wire == WireEndGroup { + if is_group { + if required > 0 { + // Not enough information to determine the exact field. + // (See below.) + return &RequiredNotSetError{"{Unknown}"} + } + return nil // input is satisfied + } + return fmt.Errorf("proto: %s: wiretype end group for non-group", st) + } + tag := int(u >> 3) + if tag <= 0 { + return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) + } + fieldnum, ok := prop.decoderTags.get(tag) + if !ok { + // Maybe it's an extension? + if prop.extendable { + if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { + if err = o.skip(st, tag, wire); err == nil { + extmap := e.extensionsWrite() + ext := extmap[int32(tag)] // may be missing + ext.enc = append(ext.enc, o.buf[oi:o.index]...) + extmap[int32(tag)] = ext + } + continue + } + } + // Maybe it's a oneof? + if prop.oneofUnmarshaler != nil { + m := structPointer_Interface(base, st).(Message) + // First return value indicates whether tag is a oneof field. + ok, err = prop.oneofUnmarshaler(m, tag, wire, o) + if err == ErrInternalBadWireType { + // Map the error to something more descriptive. + // Do the formatting here to save generated code space. + err = fmt.Errorf("bad wiretype for oneof field in %T", m) + } + if ok { + continue + } + } + err = o.skipAndSave(st, tag, wire, base, prop.unrecField) + continue + } + p := prop.Prop[fieldnum] + + if p.dec == nil { + fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) + continue + } + dec := p.dec + if wire != WireStartGroup && wire != p.WireType { + if wire == WireBytes && p.packedDec != nil { + // a packable field + dec = p.packedDec + } else { + err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) + continue + } + } + decErr := dec(o, p, base) + if decErr != nil && !state.shouldContinue(decErr, p) { + err = decErr + } + if err == nil && p.Required { + // Successfully decoded a required field. + if tag <= 64 { + // use bitmap for fields 1-64 to catch field reuse. + var mask uint64 = 1 << uint64(tag-1) + if reqFields&mask == 0 { + // new required field + reqFields |= mask + required-- + } + } else { + // This is imprecise. It can be fooled by a required field + // with a tag > 64 that is encoded twice; that's very rare. + // A fully correct implementation would require allocating + // a data structure, which we would like to avoid. + required-- + } + } + } + if err == nil { + if is_group { + return io.ErrUnexpectedEOF + } + if state.err != nil { + return state.err + } + if required > 0 { + // Not enough information to determine the exact field. If we use extra + // CPU, we could determine the field only if the missing required field + // has a tag <= 64 and we check reqFields. + return &RequiredNotSetError{"{Unknown}"} + } + } + return err +} + +// Individual type decoders +// For each, +// u is the decoded value, +// v is a pointer to the field (pointer) in the struct + +// Sizes of the pools to allocate inside the Buffer. +// The goal is modest amortization and allocation +// on at least 16-byte boundaries. +const ( + boolPoolSize = 16 + uint32PoolSize = 8 + uint64PoolSize = 4 +) + +// Decode a bool. +func (o *Buffer) dec_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + if len(o.bools) == 0 { + o.bools = make([]bool, boolPoolSize) + } + o.bools[0] = u != 0 + *structPointer_Bool(base, p.field) = &o.bools[0] + o.bools = o.bools[1:] + return nil +} + +func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + *structPointer_BoolVal(base, p.field) = u != 0 + return nil +} + +// Decode an int32. +func (o *Buffer) dec_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) + return nil +} + +func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) + return nil +} + +// Decode an int64. +func (o *Buffer) dec_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64_Set(structPointer_Word64(base, p.field), o, u) + return nil +} + +func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64Val_Set(structPointer_Word64Val(base, p.field), o, u) + return nil +} + +// Decode a string. +func (o *Buffer) dec_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_String(base, p.field) = &s + return nil +} + +func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_StringVal(base, p.field) = s + return nil +} + +// Decode a slice of bytes ([]byte). +func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + *structPointer_Bytes(base, p.field) = b + return nil +} + +// Decode a slice of bools ([]bool). +func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + v := structPointer_BoolSlice(base, p.field) + *v = append(*v, u != 0) + return nil +} + +// Decode a slice of bools ([]bool) in packed format. +func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { + v := structPointer_BoolSlice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded bools + fin := o.index + nb + if fin < o.index { + return errOverflow + } + + y := *v + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + y = append(y, u != 0) + } + + *v = y + return nil +} + +// Decode a slice of int32s ([]int32). +func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + structPointer_Word32Slice(base, p.field).Append(uint32(u)) + return nil +} + +// Decode a slice of int32s ([]int32) in packed format. +func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int32s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(uint32(u)) + } + return nil +} + +// Decode a slice of int64s ([]int64). +func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + + structPointer_Word64Slice(base, p.field).Append(u) + return nil +} + +// Decode a slice of int64s ([]int64) in packed format. +func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int64s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(u) + } + return nil +} + +// Decode a slice of strings ([]string). +func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + v := structPointer_StringSlice(base, p.field) + *v = append(*v, s) + return nil +} + +// Decode a slice of slice of bytes ([][]byte). +func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + v := structPointer_BytesSlice(base, p.field) + *v = append(*v, b) + return nil +} + +// Decode a map field. +func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + oi := o.index // index at the end of this map entry + o.index -= len(raw) // move buffer back to start of map entry + + mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V + if mptr.Elem().IsNil() { + mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) + } + v := mptr.Elem() // map[K]V + + // Prepare addressable doubly-indirect placeholders for the key and value types. + // See enc_new_map for why. + keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K + keybase := toStructPointer(keyptr.Addr()) // **K + + var valbase structPointer + var valptr reflect.Value + switch p.mtype.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valptr = reflect.ValueOf(&dummy) // *[]byte + valbase = toStructPointer(valptr) // *[]byte + case reflect.Ptr: + // message; valptr is **Msg; need to allocate the intermediate pointer + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valptr.Set(reflect.New(valptr.Type().Elem())) + valbase = toStructPointer(valptr) + default: + // everything else + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valbase = toStructPointer(valptr.Addr()) // **V + } + + // Decode. + // This parses a restricted wire format, namely the encoding of a message + // with two fields. See enc_new_map for the format. + for o.index < oi { + // tagcode for key and value properties are always a single byte + // because they have tags 1 and 2. + tagcode := o.buf[o.index] + o.index++ + switch tagcode { + case p.mkeyprop.tagcode[0]: + if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { + return err + } + case p.mvalprop.tagcode[0]: + if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { + return err + } + default: + // TODO: Should we silently skip this instead? + return fmt.Errorf("proto: bad map data tag %d", raw[0]) + } + } + keyelem, valelem := keyptr.Elem(), valptr.Elem() + if !keyelem.IsValid() { + keyelem = reflect.Zero(p.mtype.Key()) + } + if !valelem.IsValid() { + valelem = reflect.Zero(p.mtype.Elem()) + } + + v.SetMapIndex(keyelem, valelem) + return nil +} + +// Decode a group. +func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + return o.unmarshalType(p.stype, p.sprop, true, bas) +} + +// Decode an embedded message. +func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { + raw, e := o.DecodeRawBytes(false) + if e != nil { + return e + } + + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := structPointer_Interface(bas, p.stype) + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, false, bas) + o.buf = obuf + o.index = oi + + return err +} + +// Decode a slice of embedded messages. +func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, false, base) +} + +// Decode a slice of embedded groups. +func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, true, base) +} + +// Decode a slice of structs ([]*struct). +func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { + v := reflect.New(p.stype) + bas := toStructPointer(v) + structPointer_StructPointerSlice(base, p.field).Append(bas) + + if is_group { + err := o.unmarshalType(p.stype, p.sprop, is_group, bas) + return err + } + + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := v.Interface() + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, is_group, bas) + + o.buf = obuf + o.index = oi + + return err +} diff --git a/vendor/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/golang/protobuf/proto/encode.go new file mode 100644 index 000000000..8b84d1b22 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/encode.go @@ -0,0 +1,1362 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "errors" + "fmt" + "reflect" + "sort" +) + +// RequiredNotSetError is the error returned if Marshal is called with +// a protocol buffer struct whose required fields have not +// all been initialized. It is also the error returned if Unmarshal is +// called with an encoded protocol buffer that does not include all the +// required fields. +// +// When printed, RequiredNotSetError reports the first unset required field in a +// message. If the field cannot be precisely determined, it is reported as +// "{Unknown}". +type RequiredNotSetError struct { + field string +} + +func (e *RequiredNotSetError) Error() string { + return fmt.Sprintf("proto: required field %q not set", e.field) +} + +var ( + // errRepeatedHasNil is the error returned if Marshal is called with + // a struct with a repeated field containing a nil element. + errRepeatedHasNil = errors.New("proto: repeated field has nil element") + + // errOneofHasNil is the error returned if Marshal is called with + // a struct with a oneof field containing a nil element. + errOneofHasNil = errors.New("proto: oneof field has nil value") + + // ErrNil is the error returned if Marshal is called with nil. + ErrNil = errors.New("proto: Marshal called with nil") + + // ErrTooLarge is the error returned if Marshal is called with a + // message that encodes to >2GB. + ErrTooLarge = errors.New("proto: message encodes to over 2 GB") +) + +// The fundamental encoders that put bytes on the wire. +// Those that take integer types all accept uint64 and are +// therefore of type valueEncoder. + +const maxVarintBytes = 10 // maximum length of a varint + +// maxMarshalSize is the largest allowed size of an encoded protobuf, +// since C++ and Java use signed int32s for the size. +const maxMarshalSize = 1<<31 - 1 + +// EncodeVarint returns the varint encoding of x. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +// Not used by the package itself, but helpful to clients +// wishing to use the same encoding. +func EncodeVarint(x uint64) []byte { + var buf [maxVarintBytes]byte + var n int + for n = 0; x > 127; n++ { + buf[n] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + buf[n] = uint8(x) + n++ + return buf[0:n] +} + +// EncodeVarint writes a varint-encoded integer to the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) EncodeVarint(x uint64) error { + for x >= 1<<7 { + p.buf = append(p.buf, uint8(x&0x7f|0x80)) + x >>= 7 + } + p.buf = append(p.buf, uint8(x)) + return nil +} + +// SizeVarint returns the varint encoding size of an integer. +func SizeVarint(x uint64) int { + return sizeVarint(x) +} + +func sizeVarint(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} + +// EncodeFixed64 writes a 64-bit integer to the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) EncodeFixed64(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24), + uint8(x>>32), + uint8(x>>40), + uint8(x>>48), + uint8(x>>56)) + return nil +} + +func sizeFixed64(x uint64) int { + return 8 +} + +// EncodeFixed32 writes a 32-bit integer to the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) EncodeFixed32(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24)) + return nil +} + +func sizeFixed32(x uint64) int { + return 4 +} + +// EncodeZigzag64 writes a zigzag-encoded 64-bit integer +// to the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) EncodeZigzag64(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63))) +} + +func sizeZigzag64(x uint64) int { + return sizeVarint((x << 1) ^ uint64((int64(x) >> 63))) +} + +// EncodeZigzag32 writes a zigzag-encoded 32-bit integer +// to the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) EncodeZigzag32(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +func sizeZigzag32(x uint64) int { + return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) EncodeRawBytes(b []byte) error { + p.EncodeVarint(uint64(len(b))) + p.buf = append(p.buf, b...) + return nil +} + +func sizeRawBytes(b []byte) int { + return sizeVarint(uint64(len(b))) + + len(b) +} + +// EncodeStringBytes writes an encoded string to the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) EncodeStringBytes(s string) error { + p.EncodeVarint(uint64(len(s))) + p.buf = append(p.buf, s...) + return nil +} + +func sizeStringBytes(s string) int { + return sizeVarint(uint64(len(s))) + + len(s) +} + +// Marshaler is the interface representing objects that can marshal themselves. +type Marshaler interface { + Marshal() ([]byte, error) +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, returning the data. +func Marshal(pb Message) ([]byte, error) { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + return m.Marshal() + } + p := NewBuffer(nil) + err := p.Marshal(pb) + if p.buf == nil && err == nil { + // Return a non-nil slice on success. + return []byte{}, nil + } + return p.buf, err +} + +// EncodeMessage writes the protocol buffer to the Buffer, +// prefixed by a varint-encoded length. +func (p *Buffer) EncodeMessage(pb Message) error { + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + var state errorState + err = p.enc_len_struct(GetProperties(t.Elem()), base, &state) + } + return err +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, writing the result to the +// Buffer. +func (p *Buffer) Marshal(pb Message) error { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + data, err := m.Marshal() + p.buf = append(p.buf, data...) + return err + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + err = p.enc_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + (stats).Encode++ // Parens are to work around a goimports bug. + } + + if len(p.buf) > maxMarshalSize { + return ErrTooLarge + } + return err +} + +// Size returns the encoded size of a protocol buffer. +func Size(pb Message) (n int) { + // Can the object marshal itself? If so, Size is slow. + // TODO: add Size to Marshaler, or add a Sizer interface. + if m, ok := pb.(Marshaler); ok { + b, _ := m.Marshal() + return len(b) + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return 0 + } + if err == nil { + n = size_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + (stats).Size++ // Parens are to work around a goimports bug. + } + + return +} + +// Individual type encoders. + +// Encode a bool. +func (o *Buffer) enc_bool(p *Properties, base structPointer) error { + v := *structPointer_Bool(base, p.field) + if v == nil { + return ErrNil + } + x := 0 + if *v { + x = 1 + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { + v := *structPointer_BoolVal(base, p.field) + if !v { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, 1) + return nil +} + +func size_bool(p *Properties, base structPointer) int { + v := *structPointer_Bool(base, p.field) + if v == nil { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +func size_proto3_bool(p *Properties, base structPointer) int { + v := *structPointer_BoolVal(base, p.field) + if !v && !p.oneof { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +// Encode an int32. +func (o *Buffer) enc_int32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode a uint32. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := word32_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := word32_Get(v) + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode an int64. +func (o *Buffer) enc_int64(p *Properties, base structPointer) error { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return ErrNil + } + x := word64_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func size_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return 0 + } + x := word64_Get(v) + n += len(p.tagcode) + n += p.valSize(x) + return +} + +func size_proto3_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(x) + return +} + +// Encode a string. +func (o *Buffer) enc_string(p *Properties, base structPointer) error { + v := *structPointer_String(base, p.field) + if v == nil { + return ErrNil + } + x := *v + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(x) + return nil +} + +func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { + v := *structPointer_StringVal(base, p.field) + if v == "" { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(v) + return nil +} + +func size_string(p *Properties, base structPointer) (n int) { + v := *structPointer_String(base, p.field) + if v == nil { + return 0 + } + x := *v + n += len(p.tagcode) + n += sizeStringBytes(x) + return +} + +func size_proto3_string(p *Properties, base structPointer) (n int) { + v := *structPointer_StringVal(base, p.field) + if v == "" && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeStringBytes(v) + return +} + +// All protocol buffer fields are nillable, but be careful. +func isNil(v reflect.Value) bool { + switch v.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + } + return false +} + +// Encode a message struct. +func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { + var state errorState + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return state.err + } + + o.buf = append(o.buf, p.tagcode...) + return o.enc_len_struct(p.sprop, structp, &state) +} + +func size_struct_message(p *Properties, base structPointer) int { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n0 := len(p.tagcode) + n1 := sizeRawBytes(data) + return n0 + n1 + } + + n0 := len(p.tagcode) + n1 := size_struct(p.sprop, structp) + n2 := sizeVarint(uint64(n1)) // size of encoded length + return n0 + n1 + n2 +} + +// Encode a group struct. +func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { + var state errorState + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return ErrNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + err := o.enc_struct(p.sprop, b) + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return state.err +} + +func size_struct_group(p *Properties, base structPointer) (n int) { + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return 0 + } + + n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) + n += size_struct(p.sprop, b) + n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return +} + +// Encode a slice of bools ([]bool). +func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + for _, x := range s { + o.buf = append(o.buf, p.tagcode...) + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_bool(p *Properties, base structPointer) int { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + return l * (len(p.tagcode) + 1) // each bool takes exactly one byte +} + +// Encode a slice of bools ([]bool) in packed format. +func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(l)) // each bool takes exactly one byte + for _, x := range s { + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_packed_bool(p *Properties, base structPointer) (n int) { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + n += len(p.tagcode) + n += sizeVarint(uint64(l)) + n += l // each bool takes exactly one byte + return +} + +// Encode a slice of bytes ([]byte). +func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func size_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if s == nil && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +// Encode a slice of int32s ([]int32). +func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of int32s ([]int32) in packed format. +func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(buf, uint64(x)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + bufSize += p.valSize(uint64(x)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of uint32s ([]uint32). +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := s.Index(i) + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := s.Index(i) + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of uint32s ([]uint32) in packed format. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, uint64(s.Index(i))) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(uint64(s.Index(i))) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of int64s ([]int64). +func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, s.Index(i)) + } + return nil +} + +func size_slice_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + n += p.valSize(s.Index(i)) + } + return +} + +// Encode a slice of int64s ([]int64) in packed format. +func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, s.Index(i)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(s.Index(i)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of slice of bytes ([][]byte). +func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(ss[i]) + } + return nil +} + +func size_slice_slice_byte(p *Properties, base structPointer) (n int) { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return 0 + } + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeRawBytes(ss[i]) + } + return +} + +// Encode a slice of strings ([]string). +func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(ss[i]) + } + return nil +} + +func size_slice_string(p *Properties, base structPointer) (n int) { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeStringBytes(ss[i]) + } + return +} + +// Encode a slice of message structs ([]*struct). +func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return errRepeatedHasNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + continue + } + + o.buf = append(o.buf, p.tagcode...) + err := o.enc_len_struct(p.sprop, structp, &state) + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + } + return state.err +} + +func size_slice_struct_message(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return // return the size up to this point + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n += sizeRawBytes(data) + continue + } + + n0 := size_struct(p.sprop, structp) + n1 := sizeVarint(uint64(n0)) // size of encoded length + n += n0 + n1 + } + return +} + +// Encode a slice of group structs ([]*struct). +func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return errRepeatedHasNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + + err := o.enc_struct(p.sprop, b) + + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + } + return state.err +} + +func size_slice_struct_group(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) + n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return // return size up to this point + } + + n += size_struct(p.sprop, b) + } + return +} + +// Encode an extension map. +func (o *Buffer) enc_map(p *Properties, base structPointer) error { + exts := structPointer_ExtMap(base, p.field) + if err := encodeExtensionsMap(*exts); err != nil { + return err + } + + return o.enc_map_body(*exts) +} + +func (o *Buffer) enc_exts(p *Properties, base structPointer) error { + exts := structPointer_Extensions(base, p.field) + + v, mu := exts.extensionsRead() + if v == nil { + return nil + } + + mu.Lock() + defer mu.Unlock() + if err := encodeExtensionsMap(v); err != nil { + return err + } + + return o.enc_map_body(v) +} + +func (o *Buffer) enc_map_body(v map[int32]Extension) error { + // Fast-path for common cases: zero or one extensions. + if len(v) <= 1 { + for _, e := range v { + o.buf = append(o.buf, e.enc...) + } + return nil + } + + // Sort keys to provide a deterministic encoding. + keys := make([]int, 0, len(v)) + for k := range v { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, k := range keys { + o.buf = append(o.buf, v[int32(k)].enc...) + } + return nil +} + +func size_map(p *Properties, base structPointer) int { + v := structPointer_ExtMap(base, p.field) + return extensionsMapSize(*v) +} + +func size_exts(p *Properties, base structPointer) int { + v := structPointer_Extensions(base, p.field) + return extensionsSize(v) +} + +// Encode a map field. +func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { + var state errorState // XXX: or do we need to plumb this through? + + /* + A map defined as + map map_field = N; + is encoded in the same way as + message MapFieldEntry { + key_type key = 1; + value_type value = 2; + } + repeated MapFieldEntry map_field = N; + */ + + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V + if v.Len() == 0 { + return nil + } + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + enc := func() error { + if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { + return err + } + if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { + return err + } + return nil + } + + // Don't sort map keys. It is not required by the spec, and C++ doesn't do it. + for _, key := range v.MapKeys() { + val := v.MapIndex(key) + + keycopy.Set(key) + valcopy.Set(val) + + o.buf = append(o.buf, p.tagcode...) + if err := o.enc_len_thing(enc, &state); err != nil { + return err + } + } + return nil +} + +func size_new_map(p *Properties, base structPointer) int { + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + n := 0 + for _, key := range v.MapKeys() { + val := v.MapIndex(key) + keycopy.Set(key) + valcopy.Set(val) + + // Tag codes for key and val are the responsibility of the sub-sizer. + keysize := p.mkeyprop.size(p.mkeyprop, keybase) + valsize := p.mvalprop.size(p.mvalprop, valbase) + entry := keysize + valsize + // Add on tag code and length of map entry itself. + n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry + } + return n +} + +// mapEncodeScratch returns a new reflect.Value matching the map's value type, +// and a structPointer suitable for passing to an encoder or sizer. +func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { + // Prepare addressable doubly-indirect placeholders for the key and value types. + // This is needed because the element-type encoders expect **T, but the map iteration produces T. + + keycopy = reflect.New(mapType.Key()).Elem() // addressable K + keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K + keyptr.Set(keycopy.Addr()) // + keybase = toStructPointer(keyptr.Addr()) // **K + + // Value types are more varied and require special handling. + switch mapType.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte + valbase = toStructPointer(valcopy.Addr()) + case reflect.Ptr: + // message; the generated field type is map[K]*Msg (so V is *Msg), + // so we only need one level of indirection. + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valbase = toStructPointer(valcopy.Addr()) + default: + // everything else + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V + valptr.Set(valcopy.Addr()) // + valbase = toStructPointer(valptr.Addr()) // **V + } + return +} + +// Encode a struct. +func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { + var state errorState + // Encode fields in tag order so that decoders may use optimizations + // that depend on the ordering. + // https://developers.google.com/protocol-buffers/docs/encoding#order + for _, i := range prop.order { + p := prop.Prop[i] + if p.enc != nil { + err := p.enc(o, p, base) + if err != nil { + if err == ErrNil { + if p.Required && state.err == nil { + state.err = &RequiredNotSetError{p.Name} + } + } else if err == errRepeatedHasNil { + // Give more context to nil values in repeated fields. + return errors.New("repeated field " + p.OrigName + " has nil element") + } else if !state.shouldContinue(err, p) { + return err + } + } + if len(o.buf) > maxMarshalSize { + return ErrTooLarge + } + } + } + + // Do oneof fields. + if prop.oneofMarshaler != nil { + m := structPointer_Interface(base, prop.stype).(Message) + if err := prop.oneofMarshaler(m, o); err == ErrNil { + return errOneofHasNil + } else if err != nil { + return err + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + if len(o.buf)+len(v) > maxMarshalSize { + return ErrTooLarge + } + if len(v) > 0 { + o.buf = append(o.buf, v...) + } + } + + return state.err +} + +func size_struct(prop *StructProperties, base structPointer) (n int) { + for _, i := range prop.order { + p := prop.Prop[i] + if p.size != nil { + n += p.size(p, base) + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + n += len(v) + } + + // Factor in any oneof fields. + if prop.oneofSizer != nil { + m := structPointer_Interface(base, prop.stype).(Message) + n += prop.oneofSizer(m) + } + + return +} + +var zeroes [20]byte // longer than any conceivable sizeVarint + +// Encode a struct, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { + return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) +} + +// Encode something, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { + iLen := len(o.buf) + o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length + iMsg := len(o.buf) + err := enc() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + lMsg := len(o.buf) - iMsg + lLen := sizeVarint(uint64(lMsg)) + switch x := lLen - (iMsg - iLen); { + case x > 0: // actual length is x bytes larger than the space we reserved + // Move msg x bytes right. + o.buf = append(o.buf, zeroes[:x]...) + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + case x < 0: // actual length is x bytes smaller than the space we reserved + // Move msg x bytes left. + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + o.buf = o.buf[:len(o.buf)+x] // x is negative + } + // Encode the length in the reserved space. + o.buf = o.buf[:iLen] + o.EncodeVarint(uint64(lMsg)) + o.buf = o.buf[:len(o.buf)+lMsg] + return state.err +} + +// errorState maintains the first error that occurs and updates that error +// with additional context. +type errorState struct { + err error +} + +// shouldContinue reports whether encoding should continue upon encountering the +// given error. If the error is RequiredNotSetError, shouldContinue returns true +// and, if this is the first appearance of that error, remembers it for future +// reporting. +// +// If prop is not nil, it may update any error with additional context about the +// field with the error. +func (s *errorState) shouldContinue(err error, prop *Properties) bool { + // Ignore unset required fields. + reqNotSet, ok := err.(*RequiredNotSetError) + if !ok { + return false + } + if s.err == nil { + if prop != nil { + err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} + } + s.err = err + } + return true +} diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go new file mode 100644 index 000000000..2ed1cf596 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/equal.go @@ -0,0 +1,300 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer comparison. + +package proto + +import ( + "bytes" + "log" + "reflect" + "strings" +) + +/* +Equal returns true iff protocol buffers a and b are equal. +The arguments must both be pointers to protocol buffer structs. + +Equality is defined in this way: + - Two messages are equal iff they are the same type, + corresponding fields are equal, unknown field sets + are equal, and extensions sets are equal. + - Two set scalar fields are equal iff their values are equal. + If the fields are of a floating-point type, remember that + NaN != x for all x, including NaN. If the message is defined + in a proto3 .proto file, fields are not "set"; specifically, + zero length proto3 "bytes" fields are equal (nil == {}). + - Two repeated fields are equal iff their lengths are the same, + and their corresponding elements are equal. Note a "bytes" field, + although represented by []byte, is not a repeated field and the + rule for the scalar fields described above applies. + - Two unset fields are equal. + - Two unknown field sets are equal if their current + encoded state is equal. + - Two extension sets are equal iff they have corresponding + elements that are pairwise equal. + - Two map fields are equal iff their lengths are the same, + and they contain the same set of elements. Zero-length map + fields are equal. + - Every other combination of things are not equal. + +The return value is undefined if a and b are not protocol buffers. +*/ +func Equal(a, b Message) bool { + if a == nil || b == nil { + return a == b + } + v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) + if v1.Type() != v2.Type() { + return false + } + if v1.Kind() == reflect.Ptr { + if v1.IsNil() { + return v2.IsNil() + } + if v2.IsNil() { + return false + } + v1, v2 = v1.Elem(), v2.Elem() + } + if v1.Kind() != reflect.Struct { + return false + } + return equalStruct(v1, v2) +} + +// v1 and v2 are known to have the same type. +func equalStruct(v1, v2 reflect.Value) bool { + sprop := GetProperties(v1.Type()) + for i := 0; i < v1.NumField(); i++ { + f := v1.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + f1, f2 := v1.Field(i), v2.Field(i) + if f.Type.Kind() == reflect.Ptr { + if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { + // both unset + continue + } else if n1 != n2 { + // set/unset mismatch + return false + } + b1, ok := f1.Interface().(raw) + if ok { + b2 := f2.Interface().(raw) + // RawMessage + if !bytes.Equal(b1.Bytes(), b2.Bytes()) { + return false + } + continue + } + f1, f2 = f1.Elem(), f2.Elem() + } + if !equalAny(f1, f2, sprop.Prop[i]) { + return false + } + } + + if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_InternalExtensions") + if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { + return false + } + } + + if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_extensions") + if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { + return false + } + } + + uf := v1.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return true + } + + u1 := uf.Bytes() + u2 := v2.FieldByName("XXX_unrecognized").Bytes() + if !bytes.Equal(u1, u2) { + return false + } + + return true +} + +// v1 and v2 are known to have the same type. +// prop may be nil. +func equalAny(v1, v2 reflect.Value, prop *Properties) bool { + if v1.Type() == protoMessageType { + m1, _ := v1.Interface().(Message) + m2, _ := v2.Interface().(Message) + return Equal(m1, m2) + } + switch v1.Kind() { + case reflect.Bool: + return v1.Bool() == v2.Bool() + case reflect.Float32, reflect.Float64: + return v1.Float() == v2.Float() + case reflect.Int32, reflect.Int64: + return v1.Int() == v2.Int() + case reflect.Interface: + // Probably a oneof field; compare the inner values. + n1, n2 := v1.IsNil(), v2.IsNil() + if n1 || n2 { + return n1 == n2 + } + e1, e2 := v1.Elem(), v2.Elem() + if e1.Type() != e2.Type() { + return false + } + return equalAny(e1, e2, nil) + case reflect.Map: + if v1.Len() != v2.Len() { + return false + } + for _, key := range v1.MapKeys() { + val2 := v2.MapIndex(key) + if !val2.IsValid() { + // This key was not found in the second map. + return false + } + if !equalAny(v1.MapIndex(key), val2, nil) { + return false + } + } + return true + case reflect.Ptr: + // Maps may have nil values in them, so check for nil. + if v1.IsNil() && v2.IsNil() { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return equalAny(v1.Elem(), v2.Elem(), prop) + case reflect.Slice: + if v1.Type().Elem().Kind() == reflect.Uint8 { + // short circuit: []byte + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value. + if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) + } + + if v1.Len() != v2.Len() { + return false + } + for i := 0; i < v1.Len(); i++ { + if !equalAny(v1.Index(i), v2.Index(i), prop) { + return false + } + } + return true + case reflect.String: + return v1.Interface().(string) == v2.Interface().(string) + case reflect.Struct: + return equalStruct(v1, v2) + case reflect.Uint32, reflect.Uint64: + return v1.Uint() == v2.Uint() + } + + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to compare %v", v1) + return false +} + +// base is the struct type that the extensions are based on. +// x1 and x2 are InternalExtensions. +func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { + em1, _ := x1.extensionsRead() + em2, _ := x2.extensionsRead() + return equalExtMap(base, em1, em2) +} + +func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { + if len(em1) != len(em2) { + return false + } + + for extNum, e1 := range em1 { + e2, ok := em2[extNum] + if !ok { + return false + } + + m1, m2 := e1.value, e2.value + + if m1 != nil && m2 != nil { + // Both are unencoded. + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + continue + } + + // At least one is encoded. To do a semantically correct comparison + // we need to unmarshal them first. + var desc *ExtensionDesc + if m := extensionMaps[base]; m != nil { + desc = m[extNum] + } + if desc == nil { + log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) + continue + } + var err error + if m1 == nil { + m1, err = decodeExtension(e1.enc, desc) + } + if m2 == nil && err == nil { + m2, err = decodeExtension(e2.enc, desc) + } + if err != nil { + // The encoded form is invalid. + log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) + return false + } + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + } + + return true +} diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go new file mode 100644 index 000000000..eaad21831 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/extensions.go @@ -0,0 +1,587 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Types and routines for supporting protocol buffer extensions. + */ + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "sync" +) + +// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. +var ErrMissingExtension = errors.New("proto: missing extension") + +// ExtensionRange represents a range of message extensions for a protocol buffer. +// Used in code generated by the protocol compiler. +type ExtensionRange struct { + Start, End int32 // both inclusive +} + +// extendableProto is an interface implemented by any protocol buffer generated by the current +// proto compiler that may be extended. +type extendableProto interface { + Message + ExtensionRangeArray() []ExtensionRange + extensionsWrite() map[int32]Extension + extensionsRead() (map[int32]Extension, sync.Locker) +} + +// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous +// version of the proto compiler that may be extended. +type extendableProtoV1 interface { + Message + ExtensionRangeArray() []ExtensionRange + ExtensionMap() map[int32]Extension +} + +// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. +type extensionAdapter struct { + extendableProtoV1 +} + +func (e extensionAdapter) extensionsWrite() map[int32]Extension { + return e.ExtensionMap() +} + +func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { + return e.ExtensionMap(), notLocker{} +} + +// notLocker is a sync.Locker whose Lock and Unlock methods are nops. +type notLocker struct{} + +func (n notLocker) Lock() {} +func (n notLocker) Unlock() {} + +// extendable returns the extendableProto interface for the given generated proto message. +// If the proto message has the old extension format, it returns a wrapper that implements +// the extendableProto interface. +func extendable(p interface{}) (extendableProto, bool) { + if ep, ok := p.(extendableProto); ok { + return ep, ok + } + if ep, ok := p.(extendableProtoV1); ok { + return extensionAdapter{ep}, ok + } + return nil, false +} + +// XXX_InternalExtensions is an internal representation of proto extensions. +// +// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, +// thus gaining the unexported 'extensions' method, which can be called only from the proto package. +// +// The methods of XXX_InternalExtensions are not concurrency safe in general, +// but calls to logically read-only methods such as has and get may be executed concurrently. +type XXX_InternalExtensions struct { + // The struct must be indirect so that if a user inadvertently copies a + // generated message and its embedded XXX_InternalExtensions, they + // avoid the mayhem of a copied mutex. + // + // The mutex serializes all logically read-only operations to p.extensionMap. + // It is up to the client to ensure that write operations to p.extensionMap are + // mutually exclusive with other accesses. + p *struct { + mu sync.Mutex + extensionMap map[int32]Extension + } +} + +// extensionsWrite returns the extension map, creating it on first use. +func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { + if e.p == nil { + e.p = new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }) + e.p.extensionMap = make(map[int32]Extension) + } + return e.p.extensionMap +} + +// extensionsRead returns the extensions map for read-only use. It may be nil. +// The caller must hold the returned mutex's lock when accessing Elements within the map. +func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { + if e.p == nil { + return nil, nil + } + return e.p.extensionMap, &e.p.mu +} + +var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() +var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() + +// ExtensionDesc represents an extension specification. +// Used in generated code from the protocol compiler. +type ExtensionDesc struct { + ExtendedType Message // nil pointer to the type that is being extended + ExtensionType interface{} // nil pointer to the extension type + Field int32 // field number + Name string // fully-qualified name of extension, for text formatting + Tag string // protobuf tag style + Filename string // name of the file in which the extension is defined +} + +func (ed *ExtensionDesc) repeated() bool { + t := reflect.TypeOf(ed.ExtensionType) + return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 +} + +// Extension represents an extension in a message. +type Extension struct { + // When an extension is stored in a message using SetExtension + // only desc and value are set. When the message is marshaled + // enc will be set to the encoded form of the message. + // + // When a message is unmarshaled and contains extensions, each + // extension will have only enc set. When such an extension is + // accessed using GetExtension (or GetExtensions) desc and value + // will be set. + desc *ExtensionDesc + value interface{} + enc []byte +} + +// SetRawExtension is for testing only. +func SetRawExtension(base Message, id int32, b []byte) { + epb, ok := extendable(base) + if !ok { + return + } + extmap := epb.extensionsWrite() + extmap[id] = Extension{enc: b} +} + +// isExtensionField returns true iff the given field number is in an extension range. +func isExtensionField(pb extendableProto, field int32) bool { + for _, er := range pb.ExtensionRangeArray() { + if er.Start <= field && field <= er.End { + return true + } + } + return false +} + +// checkExtensionTypes checks that the given extension is valid for pb. +func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { + var pbi interface{} = pb + // Check the extended type. + if ea, ok := pbi.(extensionAdapter); ok { + pbi = ea.extendableProtoV1 + } + if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { + return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) + } + // Check the range. + if !isExtensionField(pb, extension.Field) { + return errors.New("proto: bad extension number; not in declared ranges") + } + return nil +} + +// extPropKey is sufficient to uniquely identify an extension. +type extPropKey struct { + base reflect.Type + field int32 +} + +var extProp = struct { + sync.RWMutex + m map[extPropKey]*Properties +}{ + m: make(map[extPropKey]*Properties), +} + +func extensionProperties(ed *ExtensionDesc) *Properties { + key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} + + extProp.RLock() + if prop, ok := extProp.m[key]; ok { + extProp.RUnlock() + return prop + } + extProp.RUnlock() + + extProp.Lock() + defer extProp.Unlock() + // Check again. + if prop, ok := extProp.m[key]; ok { + return prop + } + + prop := new(Properties) + prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) + extProp.m[key] = prop + return prop +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensions(e *XXX_InternalExtensions) error { + m, mu := e.extensionsRead() + if m == nil { + return nil // fast path + } + mu.Lock() + defer mu.Unlock() + return encodeExtensionsMap(m) +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensionsMap(m map[int32]Extension) error { + for k, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + p := NewBuffer(nil) + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + e.enc = p.buf + m[k] = e + } + return nil +} + +func extensionsSize(e *XXX_InternalExtensions) (n int) { + m, mu := e.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + defer mu.Unlock() + return extensionsMapSize(m) +} + +func extensionsMapSize(m map[int32]Extension) (n int) { + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + n += props.size(props, toStructPointer(x)) + } + return +} + +// HasExtension returns whether the given extension is present in pb. +func HasExtension(pb Message, extension *ExtensionDesc) bool { + // TODO: Check types, field numbers, etc.? + epb, ok := extendable(pb) + if !ok { + return false + } + extmap, mu := epb.extensionsRead() + if extmap == nil { + return false + } + mu.Lock() + _, ok = extmap[extension.Field] + mu.Unlock() + return ok +} + +// ClearExtension removes the given extension from pb. +func ClearExtension(pb Message, extension *ExtensionDesc) { + epb, ok := extendable(pb) + if !ok { + return + } + // TODO: Check types, field numbers, etc.? + extmap := epb.extensionsWrite() + delete(extmap, extension.Field) +} + +// GetExtension parses and returns the given extension of pb. +// If the extension is not present and has no default value it returns ErrMissingExtension. +func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { + epb, ok := extendable(pb) + if !ok { + return nil, errors.New("proto: not an extendable proto") + } + + if err := checkExtensionTypes(epb, extension); err != nil { + return nil, err + } + + emap, mu := epb.extensionsRead() + if emap == nil { + return defaultExtensionValue(extension) + } + mu.Lock() + defer mu.Unlock() + e, ok := emap[extension.Field] + if !ok { + // defaultExtensionValue returns the default value or + // ErrMissingExtension if there is no default. + return defaultExtensionValue(extension) + } + + if e.value != nil { + // Already decoded. Check the descriptor, though. + if e.desc != extension { + // This shouldn't happen. If it does, it means that + // GetExtension was called twice with two different + // descriptors with the same field number. + return nil, errors.New("proto: descriptor conflict") + } + return e.value, nil + } + + v, err := decodeExtension(e.enc, extension) + if err != nil { + return nil, err + } + + // Remember the decoded version and drop the encoded version. + // That way it is safe to mutate what we return. + e.value = v + e.desc = extension + e.enc = nil + emap[extension.Field] = e + return e.value, nil +} + +// defaultExtensionValue returns the default value for extension. +// If no default for an extension is defined ErrMissingExtension is returned. +func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { + t := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + + sf, _, err := fieldDefault(t, props) + if err != nil { + return nil, err + } + + if sf == nil || sf.value == nil { + // There is no default value. + return nil, ErrMissingExtension + } + + if t.Kind() != reflect.Ptr { + // We do not need to return a Ptr, we can directly return sf.value. + return sf.value, nil + } + + // We need to return an interface{} that is a pointer to sf.value. + value := reflect.New(t).Elem() + value.Set(reflect.New(value.Type().Elem())) + if sf.kind == reflect.Int32 { + // We may have an int32 or an enum, but the underlying data is int32. + // Since we can't set an int32 into a non int32 reflect.value directly + // set it as a int32. + value.Elem().SetInt(int64(sf.value.(int32))) + } else { + value.Elem().Set(reflect.ValueOf(sf.value)) + } + return value.Interface(), nil +} + +// decodeExtension decodes an extension encoded in b. +func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { + o := NewBuffer(b) + + t := reflect.TypeOf(extension.ExtensionType) + + props := extensionProperties(extension) + + // t is a pointer to a struct, pointer to basic type or a slice. + // Allocate a "field" to store the pointer/slice itself; the + // pointer/slice will be stored here. We pass + // the address of this field to props.dec. + // This passes a zero field and a *t and lets props.dec + // interpret it as a *struct{ x t }. + value := reflect.New(t).Elem() + + for { + // Discard wire type and field number varint. It isn't needed. + if _, err := o.DecodeVarint(); err != nil { + return nil, err + } + + if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { + return nil, err + } + + if o.index >= len(o.buf) { + break + } + } + return value.Interface(), nil +} + +// GetExtensions returns a slice of the extensions present in pb that are also listed in es. +// The returned slice has the same length as es; missing extensions will appear as nil elements. +func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { + epb, ok := extendable(pb) + if !ok { + return nil, errors.New("proto: not an extendable proto") + } + extensions = make([]interface{}, len(es)) + for i, e := range es { + extensions[i], err = GetExtension(epb, e) + if err == ErrMissingExtension { + err = nil + } + if err != nil { + return + } + } + return +} + +// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. +// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing +// just the Field field, which defines the extension's field number. +func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { + epb, ok := extendable(pb) + if !ok { + return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) + } + registeredExtensions := RegisteredExtensions(pb) + + emap, mu := epb.extensionsRead() + if emap == nil { + return nil, nil + } + mu.Lock() + defer mu.Unlock() + extensions := make([]*ExtensionDesc, 0, len(emap)) + for extid, e := range emap { + desc := e.desc + if desc == nil { + desc = registeredExtensions[extid] + if desc == nil { + desc = &ExtensionDesc{Field: extid} + } + } + + extensions = append(extensions, desc) + } + return extensions, nil +} + +// SetExtension sets the specified extension of pb to the specified value. +func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { + epb, ok := extendable(pb) + if !ok { + return errors.New("proto: not an extendable proto") + } + if err := checkExtensionTypes(epb, extension); err != nil { + return err + } + typ := reflect.TypeOf(extension.ExtensionType) + if typ != reflect.TypeOf(value) { + return errors.New("proto: bad extension value type") + } + // nil extension values need to be caught early, because the + // encoder can't distinguish an ErrNil due to a nil extension + // from an ErrNil due to a missing field. Extensions are + // always optional, so the encoder would just swallow the error + // and drop all the extensions from the encoded message. + if reflect.ValueOf(value).IsNil() { + return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) + } + + extmap := epb.extensionsWrite() + extmap[extension.Field] = Extension{desc: extension, value: value} + return nil +} + +// ClearAllExtensions clears all extensions from pb. +func ClearAllExtensions(pb Message) { + epb, ok := extendable(pb) + if !ok { + return + } + m := epb.extensionsWrite() + for k := range m { + delete(m, k) + } +} + +// A global registry of extensions. +// The generated code will register the generated descriptors by calling RegisterExtension. + +var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) + +// RegisterExtension is called from the generated code. +func RegisterExtension(desc *ExtensionDesc) { + st := reflect.TypeOf(desc.ExtendedType).Elem() + m := extensionMaps[st] + if m == nil { + m = make(map[int32]*ExtensionDesc) + extensionMaps[st] = m + } + if _, ok := m[desc.Field]; ok { + panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) + } + m[desc.Field] = desc +} + +// RegisteredExtensions returns a map of the registered extensions of a +// protocol buffer struct, indexed by the extension number. +// The argument pb should be a nil pointer to the struct type. +func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { + return extensionMaps[reflect.TypeOf(pb).Elem()] +} diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go new file mode 100644 index 000000000..1c225504a --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/lib.go @@ -0,0 +1,897 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* +Package proto converts data structures to and from the wire format of +protocol buffers. It works in concert with the Go source code generated +for .proto files by the protocol compiler. + +A summary of the properties of the protocol buffer interface +for a protocol buffer variable v: + + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. + - Nested messages, groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Oneof field sets are given a single field in their message, + with distinguished wrapper types for each possible field value. + - Marshal and Unmarshal are functions to encode and decode the wire format. + +When the .proto file specifies `syntax="proto3"`, there are some differences: + + - Non-repeated fields of non-message type are values instead of pointers. + - Enum types do not get an Enum method. + +The simplest way to describe this is to see an example. +Given file test.proto, containing + + package example; + + enum FOO { X = 17; } + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + oneof union { + int32 number = 6; + string name = 7; + } + } + +The resulting file, test.pb.go, is: + + package example + + import proto "github.com/golang/protobuf/proto" + import math "math" + + type FOO int32 + const ( + FOO_X FOO = 17 + ) + var FOO_name = map[int32]string{ + 17: "X", + } + var FOO_value = map[string]int32{ + "X": 17, + } + + func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p + } + func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) + } + func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data) + if err != nil { + return err + } + *x = FOO(value) + return nil + } + + type Test struct { + Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` + Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` + Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` + Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` + // Types that are valid to be assigned to Union: + // *Test_Number + // *Test_Name + Union isTest_Union `protobuf_oneof:"union"` + XXX_unrecognized []byte `json:"-"` + } + func (m *Test) Reset() { *m = Test{} } + func (m *Test) String() string { return proto.CompactTextString(m) } + func (*Test) ProtoMessage() {} + + type isTest_Union interface { + isTest_Union() + } + + type Test_Number struct { + Number int32 `protobuf:"varint,6,opt,name=number"` + } + type Test_Name struct { + Name string `protobuf:"bytes,7,opt,name=name"` + } + + func (*Test_Number) isTest_Union() {} + func (*Test_Name) isTest_Union() {} + + func (m *Test) GetUnion() isTest_Union { + if m != nil { + return m.Union + } + return nil + } + const Default_Test_Type int32 = 77 + + func (m *Test) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" + } + + func (m *Test) GetType() int32 { + if m != nil && m.Type != nil { + return *m.Type + } + return Default_Test_Type + } + + func (m *Test) GetOptionalgroup() *Test_OptionalGroup { + if m != nil { + return m.Optionalgroup + } + return nil + } + + type Test_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` + } + func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } + func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } + + func (m *Test_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" + } + + func (m *Test) GetNumber() int32 { + if x, ok := m.GetUnion().(*Test_Number); ok { + return x.Number + } + return 0 + } + + func (m *Test) GetName() string { + if x, ok := m.GetUnion().(*Test_Name); ok { + return x.Name + } + return "" + } + + func init() { + proto.RegisterEnum("example.FOO", FOO_name, FOO_value) + } + +To create and play with a Test object: + + package main + + import ( + "log" + + "github.com/golang/protobuf/proto" + pb "./example.pb" + ) + + func main() { + test := &pb.Test{ + Label: proto.String("hello"), + Type: proto.Int32(17), + Reps: []int64{1, 2, 3}, + Optionalgroup: &pb.Test_OptionalGroup{ + RequiredField: proto.String("good bye"), + }, + Union: &pb.Test_Name{"fred"}, + } + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) + } + newTest := &pb.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) + } + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) + } + // Use a type switch to determine which oneof was set. + switch u := test.Union.(type) { + case *pb.Test_Number: // u.Number contains the number. + case *pb.Test_Name: // u.Name contains the string. + } + // etc. + } +*/ +package proto + +import ( + "encoding/json" + "fmt" + "log" + "reflect" + "sort" + "strconv" + "sync" +) + +// Message is implemented by generated protocol buffer messages. +type Message interface { + Reset() + String() string + ProtoMessage() +} + +// Stats records allocation details about the protocol buffer encoders +// and decoders. Useful for tuning the library itself. +type Stats struct { + Emalloc uint64 // mallocs in encode + Dmalloc uint64 // mallocs in decode + Encode uint64 // number of encodes + Decode uint64 // number of decodes + Chit uint64 // number of cache hits + Cmiss uint64 // number of cache misses + Size uint64 // number of sizes +} + +// Set to true to enable stats collection. +const collectStats = false + +var stats Stats + +// GetStats returns a copy of the global Stats structure. +func GetStats() Stats { return stats } + +// A Buffer is a buffer manager for marshaling and unmarshaling +// protocol buffers. It may be reused between invocations to +// reduce memory usage. It is not necessary to use a Buffer; +// the global functions Marshal and Unmarshal create a +// temporary Buffer and are fine for most applications. +type Buffer struct { + buf []byte // encode/decode byte stream + index int // read point + + // pools of basic types to amortize allocation. + bools []bool + uint32s []uint32 + uint64s []uint64 + + // extra pools, only used with pointer_reflect.go + int32s []int32 + int64s []int64 + float32s []float32 + float64s []float64 +} + +// NewBuffer allocates a new Buffer and initializes its internal data to +// the contents of the argument slice. +func NewBuffer(e []byte) *Buffer { + return &Buffer{buf: e} +} + +// Reset resets the Buffer, ready for marshaling a new protocol buffer. +func (p *Buffer) Reset() { + p.buf = p.buf[0:0] // for reading/writing + p.index = 0 // for reading +} + +// SetBuf replaces the internal buffer with the slice, +// ready for unmarshaling the contents of the slice. +func (p *Buffer) SetBuf(s []byte) { + p.buf = s + p.index = 0 +} + +// Bytes returns the contents of the Buffer. +func (p *Buffer) Bytes() []byte { return p.buf } + +/* + * Helper routines for simplifying the creation of optional fields of basic type. + */ + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { + return &v +} + +// Int32 is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it. +func Int32(v int32) *int32 { + return &v +} + +// Int is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it, but unlike Int32 +// its argument value is an int. +func Int(v int) *int32 { + p := new(int32) + *p = int32(v) + return p +} + +// Int64 is a helper routine that allocates a new int64 value +// to store v and returns a pointer to it. +func Int64(v int64) *int64 { + return &v +} + +// Float32 is a helper routine that allocates a new float32 value +// to store v and returns a pointer to it. +func Float32(v float32) *float32 { + return &v +} + +// Float64 is a helper routine that allocates a new float64 value +// to store v and returns a pointer to it. +func Float64(v float64) *float64 { + return &v +} + +// Uint32 is a helper routine that allocates a new uint32 value +// to store v and returns a pointer to it. +func Uint32(v uint32) *uint32 { + return &v +} + +// Uint64 is a helper routine that allocates a new uint64 value +// to store v and returns a pointer to it. +func Uint64(v uint64) *uint64 { + return &v +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { + return &v +} + +// EnumName is a helper function to simplify printing protocol buffer enums +// by name. Given an enum map and a value, it returns a useful string. +func EnumName(m map[int32]string, v int32) string { + s, ok := m[v] + if ok { + return s + } + return strconv.Itoa(int(v)) +} + +// UnmarshalJSONEnum is a helper function to simplify recovering enum int values +// from their JSON-encoded representation. Given a map from the enum's symbolic +// names to its int values, and a byte buffer containing the JSON-encoded +// value, it returns an int32 that can be cast to the enum type by the caller. +// +// The function can deal with both JSON representations, numeric and symbolic. +func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { + if data[0] == '"' { + // New style: enums are strings. + var repr string + if err := json.Unmarshal(data, &repr); err != nil { + return -1, err + } + val, ok := m[repr] + if !ok { + return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) + } + return val, nil + } + // Old style: enums are ints. + var val int32 + if err := json.Unmarshal(data, &val); err != nil { + return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) + } + return val, nil +} + +// DebugPrint dumps the encoded data in b in a debugging format with a header +// including the string s. Used in testing but made available for general debugging. +func (p *Buffer) DebugPrint(s string, b []byte) { + var u uint64 + + obuf := p.buf + index := p.index + p.buf = b + p.index = 0 + depth := 0 + + fmt.Printf("\n--- %s ---\n", s) + +out: + for { + for i := 0; i < depth; i++ { + fmt.Print(" ") + } + + index := p.index + if index == len(p.buf) { + break + } + + op, err := p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: fetching op err %v\n", index, err) + break out + } + tag := op >> 3 + wire := op & 7 + + switch wire { + default: + fmt.Printf("%3d: t=%3d unknown wire=%d\n", + index, tag, wire) + break out + + case WireBytes: + var r []byte + + r, err = p.DecodeRawBytes(false) + if err != nil { + break out + } + fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) + if len(r) <= 6 { + for i := 0; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } else { + for i := 0; i < 3; i++ { + fmt.Printf(" %.2x", r[i]) + } + fmt.Printf(" ..") + for i := len(r) - 3; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } + fmt.Printf("\n") + + case WireFixed32: + u, err = p.DecodeFixed32() + if err != nil { + fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) + + case WireFixed64: + u, err = p.DecodeFixed64() + if err != nil { + fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) + + case WireVarint: + u, err = p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) + + case WireStartGroup: + fmt.Printf("%3d: t=%3d start\n", index, tag) + depth++ + + case WireEndGroup: + depth-- + fmt.Printf("%3d: t=%3d end\n", index, tag) + } + } + + if depth != 0 { + fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) + } + fmt.Printf("\n") + + p.buf = obuf + p.index = index +} + +// SetDefaults sets unset protocol buffer fields to their default values. +// It only modifies fields that are both unset and have defined defaults. +// It recursively sets default values in any non-nil sub-messages. +func SetDefaults(pb Message) { + setDefaults(reflect.ValueOf(pb), true, false) +} + +// v is a pointer to a struct. +func setDefaults(v reflect.Value, recur, zeros bool) { + v = v.Elem() + + defaultMu.RLock() + dm, ok := defaults[v.Type()] + defaultMu.RUnlock() + if !ok { + dm = buildDefaultMessage(v.Type()) + defaultMu.Lock() + defaults[v.Type()] = dm + defaultMu.Unlock() + } + + for _, sf := range dm.scalars { + f := v.Field(sf.index) + if !f.IsNil() { + // field already set + continue + } + dv := sf.value + if dv == nil && !zeros { + // no explicit default, and don't want to set zeros + continue + } + fptr := f.Addr().Interface() // **T + // TODO: Consider batching the allocations we do here. + switch sf.kind { + case reflect.Bool: + b := new(bool) + if dv != nil { + *b = dv.(bool) + } + *(fptr.(**bool)) = b + case reflect.Float32: + f := new(float32) + if dv != nil { + *f = dv.(float32) + } + *(fptr.(**float32)) = f + case reflect.Float64: + f := new(float64) + if dv != nil { + *f = dv.(float64) + } + *(fptr.(**float64)) = f + case reflect.Int32: + // might be an enum + if ft := f.Type(); ft != int32PtrType { + // enum + f.Set(reflect.New(ft.Elem())) + if dv != nil { + f.Elem().SetInt(int64(dv.(int32))) + } + } else { + // int32 field + i := new(int32) + if dv != nil { + *i = dv.(int32) + } + *(fptr.(**int32)) = i + } + case reflect.Int64: + i := new(int64) + if dv != nil { + *i = dv.(int64) + } + *(fptr.(**int64)) = i + case reflect.String: + s := new(string) + if dv != nil { + *s = dv.(string) + } + *(fptr.(**string)) = s + case reflect.Uint8: + // exceptional case: []byte + var b []byte + if dv != nil { + db := dv.([]byte) + b = make([]byte, len(db)) + copy(b, db) + } else { + b = []byte{} + } + *(fptr.(*[]byte)) = b + case reflect.Uint32: + u := new(uint32) + if dv != nil { + *u = dv.(uint32) + } + *(fptr.(**uint32)) = u + case reflect.Uint64: + u := new(uint64) + if dv != nil { + *u = dv.(uint64) + } + *(fptr.(**uint64)) = u + default: + log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) + } + } + + for _, ni := range dm.nested { + f := v.Field(ni) + // f is *T or []*T or map[T]*T + switch f.Kind() { + case reflect.Ptr: + if f.IsNil() { + continue + } + setDefaults(f, recur, zeros) + + case reflect.Slice: + for i := 0; i < f.Len(); i++ { + e := f.Index(i) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + + case reflect.Map: + for _, k := range f.MapKeys() { + e := f.MapIndex(k) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + } + } +} + +var ( + // defaults maps a protocol buffer struct type to a slice of the fields, + // with its scalar fields set to their proto-declared non-zero default values. + defaultMu sync.RWMutex + defaults = make(map[reflect.Type]defaultMessage) + + int32PtrType = reflect.TypeOf((*int32)(nil)) +) + +// defaultMessage represents information about the default values of a message. +type defaultMessage struct { + scalars []scalarField + nested []int // struct field index of nested messages +} + +type scalarField struct { + index int // struct field index + kind reflect.Kind // element type (the T in *T or []T) + value interface{} // the proto-declared default value, or nil +} + +// t is a struct type. +func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { + sprop := GetProperties(t) + for _, prop := range sprop.Prop { + fi, ok := sprop.decoderTags.get(prop.Tag) + if !ok { + // XXX_unrecognized + continue + } + ft := t.Field(fi).Type + + sf, nested, err := fieldDefault(ft, prop) + switch { + case err != nil: + log.Print(err) + case nested: + dm.nested = append(dm.nested, fi) + case sf != nil: + sf.index = fi + dm.scalars = append(dm.scalars, *sf) + } + } + + return dm +} + +// fieldDefault returns the scalarField for field type ft. +// sf will be nil if the field can not have a default. +// nestedMessage will be true if this is a nested message. +// Note that sf.index is not set on return. +func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { + var canHaveDefault bool + switch ft.Kind() { + case reflect.Ptr: + if ft.Elem().Kind() == reflect.Struct { + nestedMessage = true + } else { + canHaveDefault = true // proto2 scalar field + } + + case reflect.Slice: + switch ft.Elem().Kind() { + case reflect.Ptr: + nestedMessage = true // repeated message + case reflect.Uint8: + canHaveDefault = true // bytes field + } + + case reflect.Map: + if ft.Elem().Kind() == reflect.Ptr { + nestedMessage = true // map with message values + } + } + + if !canHaveDefault { + if nestedMessage { + return nil, true, nil + } + return nil, false, nil + } + + // We now know that ft is a pointer or slice. + sf = &scalarField{kind: ft.Elem().Kind()} + + // scalar fields without defaults + if !prop.HasDefault { + return sf, false, nil + } + + // a scalar field: either *T or []byte + switch ft.Elem().Kind() { + case reflect.Bool: + x, err := strconv.ParseBool(prop.Default) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Float32: + x, err := strconv.ParseFloat(prop.Default, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) + } + sf.value = float32(x) + case reflect.Float64: + x, err := strconv.ParseFloat(prop.Default, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Int32: + x, err := strconv.ParseInt(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) + } + sf.value = int32(x) + case reflect.Int64: + x, err := strconv.ParseInt(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.String: + sf.value = prop.Default + case reflect.Uint8: + // []byte (not *uint8) + sf.value = []byte(prop.Default) + case reflect.Uint32: + x, err := strconv.ParseUint(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) + } + sf.value = uint32(x) + case reflect.Uint64: + x, err := strconv.ParseUint(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) + } + sf.value = x + default: + return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) + } + + return sf, false, nil +} + +// Map fields may have key types of non-float scalars, strings and enums. +// The easiest way to sort them in some deterministic order is to use fmt. +// If this turns out to be inefficient we can always consider other options, +// such as doing a Schwartzian transform. + +func mapKeys(vs []reflect.Value) sort.Interface { + s := mapKeySorter{ + vs: vs, + // default Less function: textual comparison + less: func(a, b reflect.Value) bool { + return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) + }, + } + + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; + // numeric keys are sorted numerically. + if len(vs) == 0 { + return s + } + switch vs[0].Kind() { + case reflect.Int32, reflect.Int64: + s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } + case reflect.Uint32, reflect.Uint64: + s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } + } + + return s +} + +type mapKeySorter struct { + vs []reflect.Value + less func(a, b reflect.Value) bool +} + +func (s mapKeySorter) Len() int { return len(s.vs) } +func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } +func (s mapKeySorter) Less(i, j int) bool { + return s.less(s.vs[i], s.vs[j]) +} + +// isProto3Zero reports whether v is a zero proto3 value. +func isProto3Zero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint32, reflect.Uint64: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.String: + return v.String() == "" + } + return false +} + +// ProtoPackageIsVersion2 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const ProtoPackageIsVersion2 = true + +// ProtoPackageIsVersion1 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const ProtoPackageIsVersion1 = true diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go new file mode 100644 index 000000000..fd982decd --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/message_set.go @@ -0,0 +1,311 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Support for message sets. + */ + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" +) + +// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. +// A message type ID is required for storing a protocol buffer in a message set. +var errNoMessageTypeID = errors.New("proto does not have a message type ID") + +// The first two types (_MessageSet_Item and messageSet) +// model what the protocol compiler produces for the following protocol message: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } +// That is the MessageSet wire format. We can't use a proto to generate these +// because that would introduce a circular dependency between it and this package. + +type _MessageSet_Item struct { + TypeId *int32 `protobuf:"varint,2,req,name=type_id"` + Message []byte `protobuf:"bytes,3,req,name=message"` +} + +type messageSet struct { + Item []*_MessageSet_Item `protobuf:"group,1,rep"` + XXX_unrecognized []byte + // TODO: caching? +} + +// Make sure messageSet is a Message. +var _ Message = (*messageSet)(nil) + +// messageTypeIder is an interface satisfied by a protocol buffer type +// that may be stored in a MessageSet. +type messageTypeIder interface { + MessageTypeId() int32 +} + +func (ms *messageSet) find(pb Message) *_MessageSet_Item { + mti, ok := pb.(messageTypeIder) + if !ok { + return nil + } + id := mti.MessageTypeId() + for _, item := range ms.Item { + if *item.TypeId == id { + return item + } + } + return nil +} + +func (ms *messageSet) Has(pb Message) bool { + if ms.find(pb) != nil { + return true + } + return false +} + +func (ms *messageSet) Unmarshal(pb Message) error { + if item := ms.find(pb); item != nil { + return Unmarshal(item.Message, pb) + } + if _, ok := pb.(messageTypeIder); !ok { + return errNoMessageTypeID + } + return nil // TODO: return error instead? +} + +func (ms *messageSet) Marshal(pb Message) error { + msg, err := Marshal(pb) + if err != nil { + return err + } + if item := ms.find(pb); item != nil { + // reuse existing item + item.Message = msg + return nil + } + + mti, ok := pb.(messageTypeIder) + if !ok { + return errNoMessageTypeID + } + + mtid := mti.MessageTypeId() + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: &mtid, + Message: msg, + }) + return nil +} + +func (ms *messageSet) Reset() { *ms = messageSet{} } +func (ms *messageSet) String() string { return CompactTextString(ms) } +func (*messageSet) ProtoMessage() {} + +// Support for the message_set_wire_format message option. + +func skipVarint(buf []byte) []byte { + i := 0 + for ; buf[i]&0x80 != 0; i++ { + } + return buf[i+1:] +} + +// MarshalMessageSet encodes the extension map represented by m in the message set wire format. +// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSet(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + if err := encodeExtensions(exts); err != nil { + return nil, err + } + m, _ = exts.extensionsRead() + case map[int32]Extension: + if err := encodeExtensionsMap(exts); err != nil { + return nil, err + } + m = exts + default: + return nil, errors.New("proto: not an extension map") + } + + // Sort extension IDs to provide a deterministic encoding. + // See also enc_map in encode.go. + ids := make([]int, 0, len(m)) + for id := range m { + ids = append(ids, int(id)) + } + sort.Ints(ids) + + ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} + for _, id := range ids { + e := m[int32(id)] + // Remove the wire type and field number varint, as well as the length varint. + msg := skipVarint(skipVarint(e.enc)) + + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: Int32(int32(id)), + Message: msg, + }) + } + return Marshal(ms) +} + +// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSet(buf []byte, exts interface{}) error { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m = exts.extensionsWrite() + case map[int32]Extension: + m = exts + default: + return errors.New("proto: not an extension map") + } + + ms := new(messageSet) + if err := Unmarshal(buf, ms); err != nil { + return err + } + for _, item := range ms.Item { + id := *item.TypeId + msg := item.Message + + // Restore wire type and field number varint, plus length varint. + // Be careful to preserve duplicate items. + b := EncodeVarint(uint64(id)<<3 | WireBytes) + if ext, ok := m[id]; ok { + // Existing data; rip off the tag and length varint + // so we join the new data correctly. + // We can assume that ext.enc is set because we are unmarshaling. + o := ext.enc[len(b):] // skip wire type and field number + _, n := DecodeVarint(o) // calculate length of length varint + o = o[n:] // skip length varint + msg = append(o, msg...) // join old data and new data + } + b = append(b, EncodeVarint(uint64(len(msg)))...) + b = append(b, msg...) + + m[id] = Extension{enc: b} + } + return nil +} + +// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. +// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m, _ = exts.extensionsRead() + case map[int32]Extension: + m = exts + default: + return nil, errors.New("proto: not an extension map") + } + var b bytes.Buffer + b.WriteByte('{') + + // Process the map in key order for deterministic output. + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) // int32Slice defined in text.go + + for i, id := range ids { + ext := m[id] + if i > 0 { + b.WriteByte(',') + } + + msd, ok := messageSetMap[id] + if !ok { + // Unknown type; we can't render it, so skip it. + continue + } + fmt.Fprintf(&b, `"[%s]":`, msd.name) + + x := ext.value + if x == nil { + x = reflect.New(msd.t.Elem()).Interface() + if err := Unmarshal(ext.enc, x.(Message)); err != nil { + return nil, err + } + } + d, err := json.Marshal(x) + if err != nil { + return nil, err + } + b.Write(d) + } + b.WriteByte('}') + return b.Bytes(), nil +} + +// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. +// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { + // Common-case fast path. + if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { + return nil + } + + // This is fairly tricky, and it's not clear that it is needed. + return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") +} + +// A global registry of types that can be used in a MessageSet. + +var messageSetMap = make(map[int32]messageSetDesc) + +type messageSetDesc struct { + t reflect.Type // pointer to struct + name string +} + +// RegisterMessageSetType is called from the generated code. +func RegisterMessageSetType(m Message, fieldNum int32, name string) { + messageSetMap[fieldNum] = messageSetDesc{ + t: reflect.TypeOf(m), + name: name, + } +} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go new file mode 100644 index 000000000..fb512e2e1 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go @@ -0,0 +1,484 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build appengine js + +// This file contains an implementation of proto field accesses using package reflect. +// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can +// be used on App Engine. + +package proto + +import ( + "math" + "reflect" +) + +// A structPointer is a pointer to a struct. +type structPointer struct { + v reflect.Value +} + +// toStructPointer returns a structPointer equivalent to the given reflect value. +// The reflect value must itself be a pointer to a struct. +func toStructPointer(v reflect.Value) structPointer { + return structPointer{v} +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p.v.IsNil() +} + +// Interface returns the struct pointer as an interface value. +func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { + return p.v.Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by the sequence of field indices +// passed to reflect's FieldByIndex. +type field []int + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return f.Index +} + +// invalidField is an invalid field identifier. +var invalidField = field(nil) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { return f != nil } + +// field returns the given field in the struct as a reflect value. +func structPointer_field(p structPointer, f field) reflect.Value { + // Special case: an extension map entry with a value of type T + // passes a *T to the struct-handling code with a zero field, + // expecting that it will be treated as equivalent to *struct{ X T }, + // which has the same memory layout. We have to handle that case + // specially, because reflect will panic if we call FieldByIndex on a + // non-struct. + if f == nil { + return p.v.Elem() + } + + return p.v.Elem().FieldByIndex(f) +} + +// ifield returns the given field in the struct as an interface value. +func structPointer_ifield(p structPointer, f field) interface{} { + return structPointer_field(p, f).Addr().Interface() +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return structPointer_ifield(p, f).(*[]byte) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return structPointer_ifield(p, f).(*[][]byte) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return structPointer_ifield(p, f).(**bool) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return structPointer_ifield(p, f).(*bool) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return structPointer_ifield(p, f).(*[]bool) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return structPointer_ifield(p, f).(**string) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return structPointer_ifield(p, f).(*string) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return structPointer_ifield(p, f).(*[]string) +} + +// Extensions returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return structPointer_ifield(p, f).(*XXX_InternalExtensions) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return structPointer_ifield(p, f).(*map[int32]Extension) +} + +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { + return structPointer_field(p, f).Addr() +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + structPointer_field(p, f).Set(q.v) +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return structPointer{structPointer_field(p, f)} +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { + return structPointerSlice{structPointer_field(p, f)} +} + +// A structPointerSlice represents the address of a slice of pointers to structs +// (themselves messages or groups). That is, v.Type() is *[]*struct{...}. +type structPointerSlice struct { + v reflect.Value +} + +func (p structPointerSlice) Len() int { return p.v.Len() } +func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } +func (p structPointerSlice) Append(q structPointer) { + p.v.Set(reflect.Append(p.v, q.v)) +} + +var ( + int32Type = reflect.TypeOf(int32(0)) + uint32Type = reflect.TypeOf(uint32(0)) + float32Type = reflect.TypeOf(float32(0)) + int64Type = reflect.TypeOf(int64(0)) + uint64Type = reflect.TypeOf(uint64(0)) + float64Type = reflect.TypeOf(float64(0)) +) + +// A word32 represents a field of type *int32, *uint32, *float32, or *enum. +// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. +type word32 struct { + v reflect.Value +} + +// IsNil reports whether p is nil. +func word32_IsNil(p word32) bool { + return p.v.IsNil() +} + +// Set sets p to point at a newly allocated word with bits set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + t := p.v.Type().Elem() + switch t { + case int32Type: + if len(o.int32s) == 0 { + o.int32s = make([]int32, uint32PoolSize) + } + o.int32s[0] = int32(x) + p.v.Set(reflect.ValueOf(&o.int32s[0])) + o.int32s = o.int32s[1:] + return + case uint32Type: + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + p.v.Set(reflect.ValueOf(&o.uint32s[0])) + o.uint32s = o.uint32s[1:] + return + case float32Type: + if len(o.float32s) == 0 { + o.float32s = make([]float32, uint32PoolSize) + } + o.float32s[0] = math.Float32frombits(x) + p.v.Set(reflect.ValueOf(&o.float32s[0])) + o.float32s = o.float32s[1:] + return + } + + // must be enum + p.v.Set(reflect.New(t)) + p.v.Elem().SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32_Get(p word32) uint32 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32{structPointer_field(p, f)} +} + +// A word32Val represents a field of type int32, uint32, float32, or enum. +// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. +type word32Val struct { + v reflect.Value +} + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + switch p.v.Type() { + case int32Type: + p.v.SetInt(int64(x)) + return + case uint32Type: + p.v.SetUint(uint64(x)) + return + case float32Type: + p.v.SetFloat(float64(math.Float32frombits(x))) + return + } + + // must be enum + p.v.SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32Val_Get(p word32Val) uint32 { + elem := p.v + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val{structPointer_field(p, f)} +} + +// A word32Slice is a slice of 32-bit values. +// That is, v.Type() is []int32, []uint32, []float32, or []enum. +type word32Slice struct { + v reflect.Value +} + +func (p word32Slice) Append(x uint32) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int32: + elem.SetInt(int64(int32(x))) + case reflect.Uint32: + elem.SetUint(uint64(x)) + case reflect.Float32: + elem.SetFloat(float64(math.Float32frombits(x))) + } +} + +func (p word32Slice) Len() int { + return p.v.Len() +} + +func (p word32Slice) Index(i int) uint32 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) word32Slice { + return word32Slice{structPointer_field(p, f)} +} + +// word64 is like word32 but for 64-bit values. +type word64 struct { + v reflect.Value +} + +func word64_Set(p word64, o *Buffer, x uint64) { + t := p.v.Type().Elem() + switch t { + case int64Type: + if len(o.int64s) == 0 { + o.int64s = make([]int64, uint64PoolSize) + } + o.int64s[0] = int64(x) + p.v.Set(reflect.ValueOf(&o.int64s[0])) + o.int64s = o.int64s[1:] + return + case uint64Type: + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + p.v.Set(reflect.ValueOf(&o.uint64s[0])) + o.uint64s = o.uint64s[1:] + return + case float64Type: + if len(o.float64s) == 0 { + o.float64s = make([]float64, uint64PoolSize) + } + o.float64s[0] = math.Float64frombits(x) + p.v.Set(reflect.ValueOf(&o.float64s[0])) + o.float64s = o.float64s[1:] + return + } + panic("unreachable") +} + +func word64_IsNil(p word64) bool { + return p.v.IsNil() +} + +func word64_Get(p word64) uint64 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64{structPointer_field(p, f)} +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val struct { + v reflect.Value +} + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + switch p.v.Type() { + case int64Type: + p.v.SetInt(int64(x)) + return + case uint64Type: + p.v.SetUint(x) + return + case float64Type: + p.v.SetFloat(math.Float64frombits(x)) + return + } + panic("unreachable") +} + +func word64Val_Get(p word64Val) uint64 { + elem := p.v + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val{structPointer_field(p, f)} +} + +type word64Slice struct { + v reflect.Value +} + +func (p word64Slice) Append(x uint64) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int64: + elem.SetInt(int64(int64(x))) + case reflect.Uint64: + elem.SetUint(uint64(x)) + case reflect.Float64: + elem.SetFloat(float64(math.Float64frombits(x))) + } +} + +func (p word64Slice) Len() int { + return p.v.Len() +} + +func (p word64Slice) Index(i int) uint64 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return uint64(elem.Uint()) + case reflect.Float64: + return math.Float64bits(float64(elem.Float())) + } + panic("unreachable") +} + +func structPointer_Word64Slice(p structPointer, f field) word64Slice { + return word64Slice{structPointer_field(p, f)} +} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go new file mode 100644 index 000000000..6b5567d47 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -0,0 +1,270 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build !appengine,!js + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "unsafe" +) + +// NOTE: These type_Foo functions would more idiomatically be methods, +// but Go does not allow methods on pointer types, and we must preserve +// some pointer type for the garbage collector. We use these +// funcs with clunky names as our poor approximation to methods. +// +// An alternative would be +// type structPointer struct { p unsafe.Pointer } +// but that does not registerize as well. + +// A structPointer is a pointer to a struct. +type structPointer unsafe.Pointer + +// toStructPointer returns a structPointer equivalent to the given reflect value. +func toStructPointer(v reflect.Value) structPointer { + return structPointer(unsafe.Pointer(v.Pointer())) +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p == nil +} + +// Interface returns the struct pointer, assumed to have element type t, +// as an interface value. +func structPointer_Interface(p structPointer, t reflect.Type) interface{} { + return reflect.NewAt(t, unsafe.Pointer(p)).Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by its byte offset from the start of the struct. +type field uintptr + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return field(f.Offset) +} + +// invalidField is an invalid field identifier. +const invalidField = ^field(0) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { + return f != ^field(0) +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { + return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { + return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). +type structPointerSlice []structPointer + +func (v *structPointerSlice) Len() int { return len(*v) } +func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } +func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } + +// A word32 is the address of a "pointer to 32-bit value" field. +type word32 **uint32 + +// IsNil reports whether *v is nil. +func word32_IsNil(p word32) bool { + return *p == nil +} + +// Set sets *v to point at a newly allocated word set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + *p = &o.uint32s[0] + o.uint32s = o.uint32s[1:] +} + +// Get gets the value pointed at by *v. +func word32_Get(p word32) uint32 { + return **p +} + +// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Val is the address of a 32-bit value field. +type word32Val *uint32 + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + *p = x +} + +// Get gets the value pointed at by p. +func word32Val_Get(p word32Val) uint32 { + return *p +} + +// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Slice is a slice of 32-bit values. +type word32Slice []uint32 + +func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } +func (v *word32Slice) Len() int { return len(*v) } +func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } + +// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) *word32Slice { + return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// word64 is like word32 but for 64-bit values. +type word64 **uint64 + +func word64_Set(p word64, o *Buffer, x uint64) { + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + *p = &o.uint64s[0] + o.uint64s = o.uint64s[1:] +} + +func word64_IsNil(p word64) bool { + return *p == nil +} + +func word64_Get(p word64) uint64 { + return **p +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val *uint64 + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + *p = x +} + +func word64Val_Get(p word64Val) uint64 { + return *p +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Slice is like word32Slice but for 64-bit values. +type word64Slice []uint64 + +func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } +func (v *word64Slice) Len() int { return len(*v) } +func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } + +func structPointer_Word64Slice(p structPointer, f field) *word64Slice { + return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go new file mode 100644 index 000000000..ec2289c00 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/properties.go @@ -0,0 +1,872 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "fmt" + "log" + "os" + "reflect" + "sort" + "strconv" + "strings" + "sync" +) + +const debug bool = false + +// Constants that identify the encoding of a value on the wire. +const ( + WireVarint = 0 + WireFixed64 = 1 + WireBytes = 2 + WireStartGroup = 3 + WireEndGroup = 4 + WireFixed32 = 5 +) + +const startSize = 10 // initial slice/string sizes + +// Encoders are defined in encode.go +// An encoder outputs the full representation of a field, including its +// tag and encoder type. +type encoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueEncoder encodes a single integer in a particular encoding. +type valueEncoder func(o *Buffer, x uint64) error + +// Sizers are defined in encode.go +// A sizer returns the encoded size of a field, including its tag and encoder +// type. +type sizer func(prop *Properties, base structPointer) int + +// A valueSizer returns the encoded size of a single integer in a particular +// encoding. +type valueSizer func(x uint64) int + +// Decoders are defined in decode.go +// A decoder creates a value from its wire representation. +// Unrecognized subelements are saved in unrec. +type decoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueDecoder decodes a single integer in a particular encoding. +type valueDecoder func(o *Buffer) (x uint64, err error) + +// A oneofMarshaler does the marshaling for all oneof fields in a message. +type oneofMarshaler func(Message, *Buffer) error + +// A oneofUnmarshaler does the unmarshaling for a oneof field in a message. +type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) + +// A oneofSizer does the sizing for all oneof fields in a message. +type oneofSizer func(Message) int + +// tagMap is an optimization over map[int]int for typical protocol buffer +// use-cases. Encoded protocol buffers are often in tag order with small tag +// numbers. +type tagMap struct { + fastTags []int + slowTags map[int]int +} + +// tagMapFastLimit is the upper bound on the tag number that will be stored in +// the tagMap slice rather than its map. +const tagMapFastLimit = 1024 + +func (p *tagMap) get(t int) (int, bool) { + if t > 0 && t < tagMapFastLimit { + if t >= len(p.fastTags) { + return 0, false + } + fi := p.fastTags[t] + return fi, fi >= 0 + } + fi, ok := p.slowTags[t] + return fi, ok +} + +func (p *tagMap) put(t int, fi int) { + if t > 0 && t < tagMapFastLimit { + for len(p.fastTags) < t+1 { + p.fastTags = append(p.fastTags, -1) + } + p.fastTags[t] = fi + return + } + if p.slowTags == nil { + p.slowTags = make(map[int]int) + } + p.slowTags[t] = fi +} + +// StructProperties represents properties for all the fields of a struct. +// decoderTags and decoderOrigNames should only be used by the decoder. +type StructProperties struct { + Prop []*Properties // properties for each field + reqCount int // required count + decoderTags tagMap // map from proto tag to struct field number + decoderOrigNames map[string]int // map from original name to struct field number + order []int // list of struct field numbers in tag order + unrecField field // field id of the XXX_unrecognized []byte field + extendable bool // is this an extendable proto + + oneofMarshaler oneofMarshaler + oneofUnmarshaler oneofUnmarshaler + oneofSizer oneofSizer + stype reflect.Type + + // OneofTypes contains information about the oneof fields in this message. + // It is keyed by the original name of a field. + OneofTypes map[string]*OneofProperties +} + +// OneofProperties represents information about a specific field in a oneof. +type OneofProperties struct { + Type reflect.Type // pointer to generated struct type for this oneof field + Field int // struct field number of the containing oneof in the message + Prop *Properties +} + +// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. +// See encode.go, (*Buffer).enc_struct. + +func (sp *StructProperties) Len() int { return len(sp.order) } +func (sp *StructProperties) Less(i, j int) bool { + return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag +} +func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } + +// Properties represents the protocol-specific behavior of a single struct field. +type Properties struct { + Name string // name of the field, for error messages + OrigName string // original name before protocol compiler (always set) + JSONName string // name to use for JSON; determined by protoc + Wire string + WireType int + Tag int + Required bool + Optional bool + Repeated bool + Packed bool // relevant for repeated primitives only + Enum string // set for enum types only + proto3 bool // whether this is known to be a proto3 field; set for []byte only + oneof bool // whether this is a oneof field + + Default string // default value + HasDefault bool // whether an explicit default was provided + def_uint64 uint64 + + enc encoder + valEnc valueEncoder // set for bool and numeric types only + field field + tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) + tagbuf [8]byte + stype reflect.Type // set for struct types only + sprop *StructProperties // set for struct types only + isMarshaler bool + isUnmarshaler bool + + mtype reflect.Type // set for map types only + mkeyprop *Properties // set for map types only + mvalprop *Properties // set for map types only + + size sizer + valSize valueSizer // set for bool and numeric types only + + dec decoder + valDec valueDecoder // set for bool and numeric types only + + // If this is a packable field, this will be the decoder for the packed version of the field. + packedDec decoder +} + +// String formats the properties in the protobuf struct field tag style. +func (p *Properties) String() string { + s := p.Wire + s = "," + s += strconv.Itoa(p.Tag) + if p.Required { + s += ",req" + } + if p.Optional { + s += ",opt" + } + if p.Repeated { + s += ",rep" + } + if p.Packed { + s += ",packed" + } + s += ",name=" + p.OrigName + if p.JSONName != p.OrigName { + s += ",json=" + p.JSONName + } + if p.proto3 { + s += ",proto3" + } + if p.oneof { + s += ",oneof" + } + if len(p.Enum) > 0 { + s += ",enum=" + p.Enum + } + if p.HasDefault { + s += ",def=" + p.Default + } + return s +} + +// Parse populates p by parsing a string in the protobuf struct field tag style. +func (p *Properties) Parse(s string) { + // "bytes,49,opt,name=foo,def=hello!" + fields := strings.Split(s, ",") // breaks def=, but handled below. + if len(fields) < 2 { + fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) + return + } + + p.Wire = fields[0] + switch p.Wire { + case "varint": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeVarint + p.valDec = (*Buffer).DecodeVarint + p.valSize = sizeVarint + case "fixed32": + p.WireType = WireFixed32 + p.valEnc = (*Buffer).EncodeFixed32 + p.valDec = (*Buffer).DecodeFixed32 + p.valSize = sizeFixed32 + case "fixed64": + p.WireType = WireFixed64 + p.valEnc = (*Buffer).EncodeFixed64 + p.valDec = (*Buffer).DecodeFixed64 + p.valSize = sizeFixed64 + case "zigzag32": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag32 + p.valDec = (*Buffer).DecodeZigzag32 + p.valSize = sizeZigzag32 + case "zigzag64": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag64 + p.valDec = (*Buffer).DecodeZigzag64 + p.valSize = sizeZigzag64 + case "bytes", "group": + p.WireType = WireBytes + // no numeric converter for non-numeric types + default: + fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) + return + } + + var err error + p.Tag, err = strconv.Atoi(fields[1]) + if err != nil { + return + } + + for i := 2; i < len(fields); i++ { + f := fields[i] + switch { + case f == "req": + p.Required = true + case f == "opt": + p.Optional = true + case f == "rep": + p.Repeated = true + case f == "packed": + p.Packed = true + case strings.HasPrefix(f, "name="): + p.OrigName = f[5:] + case strings.HasPrefix(f, "json="): + p.JSONName = f[5:] + case strings.HasPrefix(f, "enum="): + p.Enum = f[5:] + case f == "proto3": + p.proto3 = true + case f == "oneof": + p.oneof = true + case strings.HasPrefix(f, "def="): + p.HasDefault = true + p.Default = f[4:] // rest of string + if i+1 < len(fields) { + // Commas aren't escaped, and def is always last. + p.Default += "," + strings.Join(fields[i+1:], ",") + break + } + } + } +} + +func logNoSliceEnc(t1, t2 reflect.Type) { + fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) +} + +var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() + +// Initialize the fields for encoding and decoding. +func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { + p.enc = nil + p.dec = nil + p.size = nil + + switch t1 := typ; t1.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) + + // proto3 scalar types + + case reflect.Bool: + p.enc = (*Buffer).enc_proto3_bool + p.dec = (*Buffer).dec_proto3_bool + p.size = size_proto3_bool + case reflect.Int32: + p.enc = (*Buffer).enc_proto3_int32 + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_int32 + case reflect.Uint32: + p.enc = (*Buffer).enc_proto3_uint32 + p.dec = (*Buffer).dec_proto3_int32 // can reuse + p.size = size_proto3_uint32 + case reflect.Int64, reflect.Uint64: + p.enc = (*Buffer).enc_proto3_int64 + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + case reflect.Float32: + p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_uint32 + case reflect.Float64: + p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + case reflect.String: + p.enc = (*Buffer).enc_proto3_string + p.dec = (*Buffer).dec_proto3_string + p.size = size_proto3_string + + case reflect.Ptr: + switch t2 := t1.Elem(); t2.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) + break + case reflect.Bool: + p.enc = (*Buffer).enc_bool + p.dec = (*Buffer).dec_bool + p.size = size_bool + case reflect.Int32: + p.enc = (*Buffer).enc_int32 + p.dec = (*Buffer).dec_int32 + p.size = size_int32 + case reflect.Uint32: + p.enc = (*Buffer).enc_uint32 + p.dec = (*Buffer).dec_int32 // can reuse + p.size = size_uint32 + case reflect.Int64, reflect.Uint64: + p.enc = (*Buffer).enc_int64 + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.Float32: + p.enc = (*Buffer).enc_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_int32 + p.size = size_uint32 + case reflect.Float64: + p.enc = (*Buffer).enc_int64 // can just treat them as bits + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.String: + p.enc = (*Buffer).enc_string + p.dec = (*Buffer).dec_string + p.size = size_string + case reflect.Struct: + p.stype = t1.Elem() + p.isMarshaler = isMarshaler(t1) + p.isUnmarshaler = isUnmarshaler(t1) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_struct_message + p.dec = (*Buffer).dec_struct_message + p.size = size_struct_message + } else { + p.enc = (*Buffer).enc_struct_group + p.dec = (*Buffer).dec_struct_group + p.size = size_struct_group + } + } + + case reflect.Slice: + switch t2 := t1.Elem(); t2.Kind() { + default: + logNoSliceEnc(t1, t2) + break + case reflect.Bool: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_bool + p.size = size_slice_packed_bool + } else { + p.enc = (*Buffer).enc_slice_bool + p.size = size_slice_bool + } + p.dec = (*Buffer).dec_slice_bool + p.packedDec = (*Buffer).dec_slice_packed_bool + case reflect.Int32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int32 + p.size = size_slice_packed_int32 + } else { + p.enc = (*Buffer).enc_slice_int32 + p.size = size_slice_int32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Uint32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Int64, reflect.Uint64: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + case reflect.Uint8: + p.dec = (*Buffer).dec_slice_byte + if p.proto3 { + p.enc = (*Buffer).enc_proto3_slice_byte + p.size = size_proto3_slice_byte + } else { + p.enc = (*Buffer).enc_slice_byte + p.size = size_slice_byte + } + case reflect.Float32, reflect.Float64: + switch t2.Bits() { + case 32: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case 64: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + default: + logNoSliceEnc(t1, t2) + break + } + case reflect.String: + p.enc = (*Buffer).enc_slice_string + p.dec = (*Buffer).dec_slice_string + p.size = size_slice_string + case reflect.Ptr: + switch t3 := t2.Elem(); t3.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) + break + case reflect.Struct: + p.stype = t2.Elem() + p.isMarshaler = isMarshaler(t2) + p.isUnmarshaler = isUnmarshaler(t2) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_slice_struct_message + p.dec = (*Buffer).dec_slice_struct_message + p.size = size_slice_struct_message + } else { + p.enc = (*Buffer).enc_slice_struct_group + p.dec = (*Buffer).dec_slice_struct_group + p.size = size_slice_struct_group + } + } + case reflect.Slice: + switch t2.Elem().Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) + break + case reflect.Uint8: + p.enc = (*Buffer).enc_slice_slice_byte + p.dec = (*Buffer).dec_slice_slice_byte + p.size = size_slice_slice_byte + } + } + + case reflect.Map: + p.enc = (*Buffer).enc_new_map + p.dec = (*Buffer).dec_new_map + p.size = size_new_map + + p.mtype = t1 + p.mkeyprop = &Properties{} + p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) + p.mvalprop = &Properties{} + vtype := p.mtype.Elem() + if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { + // The value type is not a message (*T) or bytes ([]byte), + // so we need encoders for the pointer to this type. + vtype = reflect.PtrTo(vtype) + } + p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) + } + + // precalculate tag code + wire := p.WireType + if p.Packed { + wire = WireBytes + } + x := uint32(p.Tag)<<3 | uint32(wire) + i := 0 + for i = 0; x > 127; i++ { + p.tagbuf[i] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + p.tagbuf[i] = uint8(x) + p.tagcode = p.tagbuf[0 : i+1] + + if p.stype != nil { + if lockGetProp { + p.sprop = GetProperties(p.stype) + } else { + p.sprop = getPropertiesLocked(p.stype) + } + } +} + +var ( + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() +) + +// isMarshaler reports whether type t implements Marshaler. +func isMarshaler(t reflect.Type) bool { + // We're checking for (likely) pointer-receiver methods + // so if t is not a pointer, something is very wrong. + // The calls above only invoke isMarshaler on pointer types. + if t.Kind() != reflect.Ptr { + panic("proto: misuse of isMarshaler") + } + return t.Implements(marshalerType) +} + +// isUnmarshaler reports whether type t implements Unmarshaler. +func isUnmarshaler(t reflect.Type) bool { + // We're checking for (likely) pointer-receiver methods + // so if t is not a pointer, something is very wrong. + // The calls above only invoke isUnmarshaler on pointer types. + if t.Kind() != reflect.Ptr { + panic("proto: misuse of isUnmarshaler") + } + return t.Implements(unmarshalerType) +} + +// Init populates the properties from a protocol buffer struct tag. +func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { + p.init(typ, name, tag, f, true) +} + +func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { + // "bytes,49,opt,def=hello!" + p.Name = name + p.OrigName = name + if f != nil { + p.field = toField(f) + } + if tag == "" { + return + } + p.Parse(tag) + p.setEncAndDec(typ, f, lockGetProp) +} + +var ( + propertiesMu sync.RWMutex + propertiesMap = make(map[reflect.Type]*StructProperties) +) + +// GetProperties returns the list of properties for the type represented by t. +// t must represent a generated struct type of a protocol message. +func GetProperties(t reflect.Type) *StructProperties { + if t.Kind() != reflect.Struct { + panic("proto: type must have kind struct") + } + + // Most calls to GetProperties in a long-running program will be + // retrieving details for types we have seen before. + propertiesMu.RLock() + sprop, ok := propertiesMap[t] + propertiesMu.RUnlock() + if ok { + if collectStats { + stats.Chit++ + } + return sprop + } + + propertiesMu.Lock() + sprop = getPropertiesLocked(t) + propertiesMu.Unlock() + return sprop +} + +// getPropertiesLocked requires that propertiesMu is held. +func getPropertiesLocked(t reflect.Type) *StructProperties { + if prop, ok := propertiesMap[t]; ok { + if collectStats { + stats.Chit++ + } + return prop + } + if collectStats { + stats.Cmiss++ + } + + prop := new(StructProperties) + // in case of recursive protos, fill this in now. + propertiesMap[t] = prop + + // build properties + prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || + reflect.PtrTo(t).Implements(extendableProtoV1Type) + prop.unrecField = invalidField + prop.Prop = make([]*Properties, t.NumField()) + prop.order = make([]int, t.NumField()) + + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + p := new(Properties) + name := f.Name + p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) + + if f.Name == "XXX_InternalExtensions" { // special case + p.enc = (*Buffer).enc_exts + p.dec = nil // not needed + p.size = size_exts + } else if f.Name == "XXX_extensions" { // special case + p.enc = (*Buffer).enc_map + p.dec = nil // not needed + p.size = size_map + } else if f.Name == "XXX_unrecognized" { // special case + prop.unrecField = toField(&f) + } + oneof := f.Tag.Get("protobuf_oneof") // special case + if oneof != "" { + // Oneof fields don't use the traditional protobuf tag. + p.OrigName = oneof + } + prop.Prop[i] = p + prop.order[i] = i + if debug { + print(i, " ", f.Name, " ", t.String(), " ") + if p.Tag > 0 { + print(p.String()) + } + print("\n") + } + if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { + fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") + } + } + + // Re-order prop.order. + sort.Sort(prop) + + type oneofMessage interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + } + if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { + var oots []interface{} + prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() + prop.stype = t + + // Interpret oneof metadata. + prop.OneofTypes = make(map[string]*OneofProperties) + for _, oot := range oots { + oop := &OneofProperties{ + Type: reflect.ValueOf(oot).Type(), // *T + Prop: new(Properties), + } + sft := oop.Type.Elem().Field(0) + oop.Prop.Name = sft.Name + oop.Prop.Parse(sft.Tag.Get("protobuf")) + // There will be exactly one interface field that + // this new value is assignable to. + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Type.Kind() != reflect.Interface { + continue + } + if !oop.Type.AssignableTo(f.Type) { + continue + } + oop.Field = i + break + } + prop.OneofTypes[oop.Prop.OrigName] = oop + } + } + + // build required counts + // build tags + reqCount := 0 + prop.decoderOrigNames = make(map[string]int) + for i, p := range prop.Prop { + if strings.HasPrefix(p.Name, "XXX_") { + // Internal fields should not appear in tags/origNames maps. + // They are handled specially when encoding and decoding. + continue + } + if p.Required { + reqCount++ + } + prop.decoderTags.put(p.Tag, i) + prop.decoderOrigNames[p.OrigName] = i + } + prop.reqCount = reqCount + + return prop +} + +// Return the Properties object for the x[0]'th field of the structure. +func propByIndex(t reflect.Type, x []int) *Properties { + if len(x) != 1 { + fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) + return nil + } + prop := GetProperties(t) + return prop.Prop[x[0]] +} + +// Get the address and type of a pointer to a struct from an interface. +func getbase(pb Message) (t reflect.Type, b structPointer, err error) { + if pb == nil { + err = ErrNil + return + } + // get the reflect type of the pointer to the struct. + t = reflect.TypeOf(pb) + // get the address of the struct. + value := reflect.ValueOf(pb) + b = toStructPointer(value) + return +} + +// A global registry of enum types. +// The generated code will register the generated maps by calling RegisterEnum. + +var enumValueMaps = make(map[string]map[string]int32) + +// RegisterEnum is called from the generated code to install the enum descriptor +// maps into the global table to aid parsing text format protocol buffers. +func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { + if _, ok := enumValueMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumValueMaps[typeName] = valueMap +} + +// EnumValueMap returns the mapping from names to integers of the +// enum type enumType, or a nil if not found. +func EnumValueMap(enumType string) map[string]int32 { + return enumValueMaps[enumType] +} + +// A registry of all linked message types. +// The string is a fully-qualified proto name ("pkg.Message"). +var ( + protoTypes = make(map[string]reflect.Type) + revProtoTypes = make(map[reflect.Type]string) +) + +// RegisterType is called from generated code and maps from the fully qualified +// proto name to the type (pointer to struct) of the protocol buffer. +func RegisterType(x Message, name string) { + if _, ok := protoTypes[name]; ok { + // TODO: Some day, make this a panic. + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + protoTypes[name] = t + revProtoTypes[t] = name +} + +// MessageName returns the fully-qualified proto name for the given message type. +func MessageName(x Message) string { + type xname interface { + XXX_MessageName() string + } + if m, ok := x.(xname); ok { + return m.XXX_MessageName() + } + return revProtoTypes[reflect.TypeOf(x)] +} + +// MessageType returns the message type (pointer to struct) for a named message. +func MessageType(name string) reflect.Type { return protoTypes[name] } + +// A registry of all linked proto files. +var ( + protoFiles = make(map[string][]byte) // file name => fileDescriptor +) + +// RegisterFile is called from generated code and maps from the +// full file name of a .proto file to its compressed FileDescriptorProto. +func RegisterFile(filename string, fileDescriptor []byte) { + protoFiles[filename] = fileDescriptor +} + +// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. +func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/golang/protobuf/proto/text.go b/vendor/github.com/golang/protobuf/proto/text.go new file mode 100644 index 000000000..965876bf0 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/text.go @@ -0,0 +1,854 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for writing the text protocol buffer format. + +import ( + "bufio" + "bytes" + "encoding" + "errors" + "fmt" + "io" + "log" + "math" + "reflect" + "sort" + "strings" +) + +var ( + newline = []byte("\n") + spaces = []byte(" ") + gtNewline = []byte(">\n") + endBraceNewline = []byte("}\n") + backslashN = []byte{'\\', 'n'} + backslashR = []byte{'\\', 'r'} + backslashT = []byte{'\\', 't'} + backslashDQ = []byte{'\\', '"'} + backslashBS = []byte{'\\', '\\'} + posInf = []byte("inf") + negInf = []byte("-inf") + nan = []byte("nan") +) + +type writer interface { + io.Writer + WriteByte(byte) error +} + +// textWriter is an io.Writer that tracks its indentation level. +type textWriter struct { + ind int + complete bool // if the current position is a complete line + compact bool // whether to write out as a one-liner + w writer +} + +func (w *textWriter) WriteString(s string) (n int, err error) { + if !strings.Contains(s, "\n") { + if !w.compact && w.complete { + w.writeIndent() + } + w.complete = false + return io.WriteString(w.w, s) + } + // WriteString is typically called without newlines, so this + // codepath and its copy are rare. We copy to avoid + // duplicating all of Write's logic here. + return w.Write([]byte(s)) +} + +func (w *textWriter) Write(p []byte) (n int, err error) { + newlines := bytes.Count(p, newline) + if newlines == 0 { + if !w.compact && w.complete { + w.writeIndent() + } + n, err = w.w.Write(p) + w.complete = false + return n, err + } + + frags := bytes.SplitN(p, newline, newlines+1) + if w.compact { + for i, frag := range frags { + if i > 0 { + if err := w.w.WriteByte(' '); err != nil { + return n, err + } + n++ + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + } + return n, nil + } + + for i, frag := range frags { + if w.complete { + w.writeIndent() + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + if i+1 < len(frags) { + if err := w.w.WriteByte('\n'); err != nil { + return n, err + } + n++ + } + } + w.complete = len(frags[len(frags)-1]) == 0 + return n, nil +} + +func (w *textWriter) WriteByte(c byte) error { + if w.compact && c == '\n' { + c = ' ' + } + if !w.compact && w.complete { + w.writeIndent() + } + err := w.w.WriteByte(c) + w.complete = c == '\n' + return err +} + +func (w *textWriter) indent() { w.ind++ } + +func (w *textWriter) unindent() { + if w.ind == 0 { + log.Print("proto: textWriter unindented too far") + return + } + w.ind-- +} + +func writeName(w *textWriter, props *Properties) error { + if _, err := w.WriteString(props.OrigName); err != nil { + return err + } + if props.Wire != "group" { + return w.WriteByte(':') + } + return nil +} + +// raw is the interface satisfied by RawMessage. +type raw interface { + Bytes() []byte +} + +func requiresQuotes(u string) bool { + // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. + for _, ch := range u { + switch { + case ch == '.' || ch == '/' || ch == '_': + continue + case '0' <= ch && ch <= '9': + continue + case 'A' <= ch && ch <= 'Z': + continue + case 'a' <= ch && ch <= 'z': + continue + default: + return true + } + } + return false +} + +// isAny reports whether sv is a google.protobuf.Any message +func isAny(sv reflect.Value) bool { + type wkt interface { + XXX_WellKnownType() string + } + t, ok := sv.Addr().Interface().(wkt) + return ok && t.XXX_WellKnownType() == "Any" +} + +// writeProto3Any writes an expanded google.protobuf.Any message. +// +// It returns (false, nil) if sv value can't be unmarshaled (e.g. because +// required messages are not linked in). +// +// It returns (true, error) when sv was written in expanded format or an error +// was encountered. +func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { + turl := sv.FieldByName("TypeUrl") + val := sv.FieldByName("Value") + if !turl.IsValid() || !val.IsValid() { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + b, ok := val.Interface().([]byte) + if !ok { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + parts := strings.Split(turl.String(), "/") + mt := MessageType(parts[len(parts)-1]) + if mt == nil { + return false, nil + } + m := reflect.New(mt.Elem()) + if err := Unmarshal(b, m.Interface().(Message)); err != nil { + return false, nil + } + w.Write([]byte("[")) + u := turl.String() + if requiresQuotes(u) { + writeString(w, u) + } else { + w.Write([]byte(u)) + } + if w.compact { + w.Write([]byte("]:<")) + } else { + w.Write([]byte("]: <\n")) + w.ind++ + } + if err := tm.writeStruct(w, m.Elem()); err != nil { + return true, err + } + if w.compact { + w.Write([]byte("> ")) + } else { + w.ind-- + w.Write([]byte(">\n")) + } + return true, nil +} + +func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { + if tm.ExpandAny && isAny(sv) { + if canExpand, err := tm.writeProto3Any(w, sv); canExpand { + return err + } + } + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < sv.NumField(); i++ { + fv := sv.Field(i) + props := sprops.Prop[i] + name := st.Field(i).Name + + if strings.HasPrefix(name, "XXX_") { + // There are two XXX_ fields: + // XXX_unrecognized []byte + // XXX_extensions map[int32]proto.Extension + // The first is handled here; + // the second is handled at the bottom of this function. + if name == "XXX_unrecognized" && !fv.IsNil() { + if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Field not filled in. This could be an optional field or + // a required field that wasn't filled in. Either way, there + // isn't anything we can show for it. + continue + } + if fv.Kind() == reflect.Slice && fv.IsNil() { + // Repeated field that is empty, or a bytes field that is unused. + continue + } + + if props.Repeated && fv.Kind() == reflect.Slice { + // Repeated field. + for j := 0; j < fv.Len(); j++ { + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + v := fv.Index(j) + if v.Kind() == reflect.Ptr && v.IsNil() { + // A nil message in a repeated field is not valid, + // but we can handle that more gracefully than panicking. + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + continue + } + if err := tm.writeAny(w, v, props); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Map { + // Map fields are rendered as a repeated struct with key/value fields. + keys := fv.MapKeys() + sort.Sort(mapKeys(keys)) + for _, key := range keys { + val := fv.MapIndex(key) + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + // open struct + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + // key + if _, err := w.WriteString("key:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, key, props.mkeyprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // nil values aren't legal, but we can avoid panicking because of them. + if val.Kind() != reflect.Ptr || !val.IsNil() { + // value + if _, err := w.WriteString("value:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, val, props.mvalprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + // close struct + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { + // empty bytes field + continue + } + if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { + // proto3 non-repeated scalar field; skip if zero value + if isProto3Zero(fv) { + continue + } + } + + if fv.Kind() == reflect.Interface { + // Check if it is a oneof. + if st.Field(i).Tag.Get("protobuf_oneof") != "" { + // fv is nil, or holds a pointer to generated struct. + // That generated struct has exactly one field, + // which has a protobuf struct tag. + if fv.IsNil() { + continue + } + inner := fv.Elem().Elem() // interface -> *T -> T + tag := inner.Type().Field(0).Tag.Get("protobuf") + props = new(Properties) // Overwrite the outer props var, but not its pointee. + props.Parse(tag) + // Write the value in the oneof, not the oneof itself. + fv = inner.Field(0) + + // Special case to cope with malformed messages gracefully: + // If the value in the oneof is a nil pointer, don't panic + // in writeAny. + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Use errors.New so writeAny won't render quotes. + msg := errors.New("/* nil */") + fv = reflect.ValueOf(&msg).Elem() + } + } + } + + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if b, ok := fv.Interface().(raw); ok { + if err := writeRaw(w, b.Bytes()); err != nil { + return err + } + continue + } + + // Enums have a String method, so writeAny will work fine. + if err := tm.writeAny(w, fv, props); err != nil { + return err + } + + if err := w.WriteByte('\n'); err != nil { + return err + } + } + + // Extensions (the XXX_extensions field). + pv := sv.Addr() + if _, ok := extendable(pv.Interface()); ok { + if err := tm.writeExtensions(w, pv); err != nil { + return err + } + } + + return nil +} + +// writeRaw writes an uninterpreted raw message. +func writeRaw(w *textWriter, b []byte) error { + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if err := writeUnknownStruct(w, b); err != nil { + return err + } + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + return nil +} + +// writeAny writes an arbitrary field. +func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { + v = reflect.Indirect(v) + + // Floats have special cases. + if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { + x := v.Float() + var b []byte + switch { + case math.IsInf(x, 1): + b = posInf + case math.IsInf(x, -1): + b = negInf + case math.IsNaN(x): + b = nan + } + if b != nil { + _, err := w.Write(b) + return err + } + // Other values are handled below. + } + + // We don't attempt to serialise every possible value type; only those + // that can occur in protocol buffers. + switch v.Kind() { + case reflect.Slice: + // Should only be a []byte; repeated fields are handled in writeStruct. + if err := writeString(w, string(v.Bytes())); err != nil { + return err + } + case reflect.String: + if err := writeString(w, v.String()); err != nil { + return err + } + case reflect.Struct: + // Required/optional group/message. + var bra, ket byte = '<', '>' + if props != nil && props.Wire == "group" { + bra, ket = '{', '}' + } + if err := w.WriteByte(bra); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if etm, ok := v.Interface().(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = w.Write(text); err != nil { + return err + } + } else if err := tm.writeStruct(w, v); err != nil { + return err + } + w.unindent() + if err := w.WriteByte(ket); err != nil { + return err + } + default: + _, err := fmt.Fprint(w, v.Interface()) + return err + } + return nil +} + +// equivalent to C's isprint. +func isprint(c byte) bool { + return c >= 0x20 && c < 0x7f +} + +// writeString writes a string in the protocol buffer text format. +// It is similar to strconv.Quote except we don't use Go escape sequences, +// we treat the string as a byte sequence, and we use octal escapes. +// These differences are to maintain interoperability with the other +// languages' implementations of the text format. +func writeString(w *textWriter, s string) error { + // use WriteByte here to get any needed indent + if err := w.WriteByte('"'); err != nil { + return err + } + // Loop over the bytes, not the runes. + for i := 0; i < len(s); i++ { + var err error + // Divergence from C++: we don't escape apostrophes. + // There's no need to escape them, and the C++ parser + // copes with a naked apostrophe. + switch c := s[i]; c { + case '\n': + _, err = w.w.Write(backslashN) + case '\r': + _, err = w.w.Write(backslashR) + case '\t': + _, err = w.w.Write(backslashT) + case '"': + _, err = w.w.Write(backslashDQ) + case '\\': + _, err = w.w.Write(backslashBS) + default: + if isprint(c) { + err = w.w.WriteByte(c) + } else { + _, err = fmt.Fprintf(w.w, "\\%03o", c) + } + } + if err != nil { + return err + } + } + return w.WriteByte('"') +} + +func writeUnknownStruct(w *textWriter, data []byte) (err error) { + if !w.compact { + if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { + return err + } + } + b := NewBuffer(data) + for b.index < len(b.buf) { + x, err := b.DecodeVarint() + if err != nil { + _, err := fmt.Fprintf(w, "/* %v */\n", err) + return err + } + wire, tag := x&7, x>>3 + if wire == WireEndGroup { + w.unindent() + if _, err := w.Write(endBraceNewline); err != nil { + return err + } + continue + } + if _, err := fmt.Fprint(w, tag); err != nil { + return err + } + if wire != WireStartGroup { + if err := w.WriteByte(':'); err != nil { + return err + } + } + if !w.compact || wire == WireStartGroup { + if err := w.WriteByte(' '); err != nil { + return err + } + } + switch wire { + case WireBytes: + buf, e := b.DecodeRawBytes(false) + if e == nil { + _, err = fmt.Fprintf(w, "%q", buf) + } else { + _, err = fmt.Fprintf(w, "/* %v */", e) + } + case WireFixed32: + x, err = b.DecodeFixed32() + err = writeUnknownInt(w, x, err) + case WireFixed64: + x, err = b.DecodeFixed64() + err = writeUnknownInt(w, x, err) + case WireStartGroup: + err = w.WriteByte('{') + w.indent() + case WireVarint: + x, err = b.DecodeVarint() + err = writeUnknownInt(w, x, err) + default: + _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) + } + if err != nil { + return err + } + if err = w.WriteByte('\n'); err != nil { + return err + } + } + return nil +} + +func writeUnknownInt(w *textWriter, x uint64, err error) error { + if err == nil { + _, err = fmt.Fprint(w, x) + } else { + _, err = fmt.Fprintf(w, "/* %v */", err) + } + return err +} + +type int32Slice []int32 + +func (s int32Slice) Len() int { return len(s) } +func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } +func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// writeExtensions writes all the extensions in pv. +// pv is assumed to be a pointer to a protocol message struct that is extendable. +func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { + emap := extensionMaps[pv.Type().Elem()] + ep, _ := extendable(pv.Interface()) + + // Order the extensions by ID. + // This isn't strictly necessary, but it will give us + // canonical output, which will also make testing easier. + m, mu := ep.extensionsRead() + if m == nil { + return nil + } + mu.Lock() + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) + mu.Unlock() + + for _, extNum := range ids { + ext := m[extNum] + var desc *ExtensionDesc + if emap != nil { + desc = emap[extNum] + } + if desc == nil { + // Unknown extension. + if err := writeUnknownStruct(w, ext.enc); err != nil { + return err + } + continue + } + + pb, err := GetExtension(ep, desc) + if err != nil { + return fmt.Errorf("failed getting extension: %v", err) + } + + // Repeated extensions will appear as a slice. + if !desc.repeated() { + if err := tm.writeExtension(w, desc.Name, pb); err != nil { + return err + } + } else { + v := reflect.ValueOf(pb) + for i := 0; i < v.Len(); i++ { + if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { + return err + } + } + } + } + return nil +} + +func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { + if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + return nil +} + +func (w *textWriter) writeIndent() { + if !w.complete { + return + } + remain := w.ind * 2 + for remain > 0 { + n := remain + if n > len(spaces) { + n = len(spaces) + } + w.w.Write(spaces[:n]) + remain -= n + } + w.complete = false +} + +// TextMarshaler is a configurable text format marshaler. +type TextMarshaler struct { + Compact bool // use compact text format (one line). + ExpandAny bool // expand google.protobuf.Any messages of known types +} + +// Marshal writes a given protocol buffer in text format. +// The only errors returned are from w. +func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { + val := reflect.ValueOf(pb) + if pb == nil || val.IsNil() { + w.Write([]byte("")) + return nil + } + var bw *bufio.Writer + ww, ok := w.(writer) + if !ok { + bw = bufio.NewWriter(w) + ww = bw + } + aw := &textWriter{ + w: ww, + complete: true, + compact: tm.Compact, + } + + if etm, ok := pb.(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = aw.Write(text); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil + } + // Dereference the received pointer so we don't have outer < and >. + v := reflect.Indirect(val) + if err := tm.writeStruct(aw, v); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil +} + +// Text is the same as Marshal, but returns the string directly. +func (tm *TextMarshaler) Text(pb Message) string { + var buf bytes.Buffer + tm.Marshal(&buf, pb) + return buf.String() +} + +var ( + defaultTextMarshaler = TextMarshaler{} + compactTextMarshaler = TextMarshaler{Compact: true} +) + +// TODO: consider removing some of the Marshal functions below. + +// MarshalText writes a given protocol buffer in text format. +// The only errors returned are from w. +func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } + +// MarshalTextString is the same as MarshalText, but returns the string directly. +func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } + +// CompactText writes a given protocol buffer in compact text format (one line). +func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } + +// CompactTextString is the same as CompactText, but returns the string directly. +func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go new file mode 100644 index 000000000..5e14513f2 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/text_parser.go @@ -0,0 +1,895 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for parsing the Text protocol buffer format. +// TODO: message sets. + +import ( + "encoding" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "unicode/utf8" +) + +// Error string emitted when deserializing Any and fields are already set +const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" + +type ParseError struct { + Message string + Line int // 1-based line number + Offset int // 0-based byte offset from start of input +} + +func (p *ParseError) Error() string { + if p.Line == 1 { + // show offset only for first line + return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) + } + return fmt.Sprintf("line %d: %v", p.Line, p.Message) +} + +type token struct { + value string + err *ParseError + line int // line number + offset int // byte number from start of input, not start of line + unquoted string // the unquoted version of value, if it was a quoted string +} + +func (t *token) String() string { + if t.err == nil { + return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) + } + return fmt.Sprintf("parse error: %v", t.err) +} + +type textParser struct { + s string // remaining input + done bool // whether the parsing is finished (success or error) + backed bool // whether back() was called + offset, line int + cur token +} + +func newTextParser(s string) *textParser { + p := new(textParser) + p.s = s + p.line = 1 + p.cur.line = 1 + return p +} + +func (p *textParser) errorf(format string, a ...interface{}) *ParseError { + pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} + p.cur.err = pe + p.done = true + return pe +} + +// Numbers and identifiers are matched by [-+._A-Za-z0-9] +func isIdentOrNumberChar(c byte) bool { + switch { + case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': + return true + case '0' <= c && c <= '9': + return true + } + switch c { + case '-', '+', '.', '_': + return true + } + return false +} + +func isWhitespace(c byte) bool { + switch c { + case ' ', '\t', '\n', '\r': + return true + } + return false +} + +func isQuote(c byte) bool { + switch c { + case '"', '\'': + return true + } + return false +} + +func (p *textParser) skipWhitespace() { + i := 0 + for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { + if p.s[i] == '#' { + // comment; skip to end of line or input + for i < len(p.s) && p.s[i] != '\n' { + i++ + } + if i == len(p.s) { + break + } + } + if p.s[i] == '\n' { + p.line++ + } + i++ + } + p.offset += i + p.s = p.s[i:len(p.s)] + if len(p.s) == 0 { + p.done = true + } +} + +func (p *textParser) advance() { + // Skip whitespace + p.skipWhitespace() + if p.done { + return + } + + // Start of non-whitespace + p.cur.err = nil + p.cur.offset, p.cur.line = p.offset, p.line + p.cur.unquoted = "" + switch p.s[0] { + case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': + // Single symbol + p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] + case '"', '\'': + // Quoted string + i := 1 + for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { + if p.s[i] == '\\' && i+1 < len(p.s) { + // skip escaped char + i++ + } + i++ + } + if i >= len(p.s) || p.s[i] != p.s[0] { + p.errorf("unmatched quote") + return + } + unq, err := unquoteC(p.s[1:i], rune(p.s[0])) + if err != nil { + p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) + return + } + p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] + p.cur.unquoted = unq + default: + i := 0 + for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { + i++ + } + if i == 0 { + p.errorf("unexpected byte %#x", p.s[0]) + return + } + p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] + } + p.offset += len(p.cur.value) +} + +var ( + errBadUTF8 = errors.New("proto: bad UTF-8") + errBadHex = errors.New("proto: bad hexadecimal") +) + +func unquoteC(s string, quote rune) (string, error) { + // This is based on C++'s tokenizer.cc. + // Despite its name, this is *not* parsing C syntax. + // For instance, "\0" is an invalid quoted string. + + // Avoid allocation in trivial cases. + simple := true + for _, r := range s { + if r == '\\' || r == quote { + simple = false + break + } + } + if simple { + return s, nil + } + + buf := make([]byte, 0, 3*len(s)/2) + for len(s) > 0 { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", errBadUTF8 + } + s = s[n:] + if r != '\\' { + if r < utf8.RuneSelf { + buf = append(buf, byte(r)) + } else { + buf = append(buf, string(r)...) + } + continue + } + + ch, tail, err := unescape(s) + if err != nil { + return "", err + } + buf = append(buf, ch...) + s = tail + } + return string(buf), nil +} + +func unescape(s string) (ch string, tail string, err error) { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", "", errBadUTF8 + } + s = s[n:] + switch r { + case 'a': + return "\a", s, nil + case 'b': + return "\b", s, nil + case 'f': + return "\f", s, nil + case 'n': + return "\n", s, nil + case 'r': + return "\r", s, nil + case 't': + return "\t", s, nil + case 'v': + return "\v", s, nil + case '?': + return "?", s, nil // trigraph workaround + case '\'', '"', '\\': + return string(r), s, nil + case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': + if len(s) < 2 { + return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) + } + base := 8 + ss := s[:2] + s = s[2:] + if r == 'x' || r == 'X' { + base = 16 + } else { + ss = string(r) + ss + } + i, err := strconv.ParseUint(ss, base, 8) + if err != nil { + return "", "", err + } + return string([]byte{byte(i)}), s, nil + case 'u', 'U': + n := 4 + if r == 'U' { + n = 8 + } + if len(s) < n { + return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) + } + + bs := make([]byte, n/2) + for i := 0; i < n; i += 2 { + a, ok1 := unhex(s[i]) + b, ok2 := unhex(s[i+1]) + if !ok1 || !ok2 { + return "", "", errBadHex + } + bs[i/2] = a<<4 | b + } + s = s[n:] + return string(bs), s, nil + } + return "", "", fmt.Errorf(`unknown escape \%c`, r) +} + +// Adapted from src/pkg/strconv/quote.go. +func unhex(b byte) (v byte, ok bool) { + switch { + case '0' <= b && b <= '9': + return b - '0', true + case 'a' <= b && b <= 'f': + return b - 'a' + 10, true + case 'A' <= b && b <= 'F': + return b - 'A' + 10, true + } + return 0, false +} + +// Back off the parser by one token. Can only be done between calls to next(). +// It makes the next advance() a no-op. +func (p *textParser) back() { p.backed = true } + +// Advances the parser and returns the new current token. +func (p *textParser) next() *token { + if p.backed || p.done { + p.backed = false + return &p.cur + } + p.advance() + if p.done { + p.cur.value = "" + } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { + // Look for multiple quoted strings separated by whitespace, + // and concatenate them. + cat := p.cur + for { + p.skipWhitespace() + if p.done || !isQuote(p.s[0]) { + break + } + p.advance() + if p.cur.err != nil { + return &p.cur + } + cat.value += " " + p.cur.value + cat.unquoted += p.cur.unquoted + } + p.done = false // parser may have seen EOF, but we want to return cat + p.cur = cat + } + return &p.cur +} + +func (p *textParser) consumeToken(s string) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != s { + p.back() + return p.errorf("expected %q, found %q", s, tok.value) + } + return nil +} + +// Return a RequiredNotSetError indicating which required field was not set. +func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < st.NumField(); i++ { + if !isNil(sv.Field(i)) { + continue + } + + props := sprops.Prop[i] + if props.Required { + return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} + } + } + return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen +} + +// Returns the index in the struct for the named field, as well as the parsed tag properties. +func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { + i, ok := sprops.decoderOrigNames[name] + if ok { + return i, sprops.Prop[i], true + } + return -1, nil, false +} + +// Consume a ':' from the input stream (if the next token is a colon), +// returning an error if a colon is needed but not present. +func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ":" { + // Colon is optional when the field is a group or message. + needColon := true + switch props.Wire { + case "group": + needColon = false + case "bytes": + // A "bytes" field is either a message, a string, or a repeated field; + // those three become *T, *string and []T respectively, so we can check for + // this field being a pointer to a non-string. + if typ.Kind() == reflect.Ptr { + // *T or *string + if typ.Elem().Kind() == reflect.String { + break + } + } else if typ.Kind() == reflect.Slice { + // []T or []*T + if typ.Elem().Kind() != reflect.Ptr { + break + } + } else if typ.Kind() == reflect.String { + // The proto3 exception is for a string field, + // which requires a colon. + break + } + needColon = false + } + if needColon { + return p.errorf("expected ':', found %q", tok.value) + } + p.back() + } + return nil +} + +func (p *textParser) readStruct(sv reflect.Value, terminator string) error { + st := sv.Type() + sprops := GetProperties(st) + reqCount := sprops.reqCount + var reqFieldErr error + fieldSet := make(map[string]bool) + // A struct is a sequence of "name: value", terminated by one of + // '>' or '}', or the end of the input. A name may also be + // "[extension]" or "[type/url]". + // + // The whole struct can also be an expanded Any message, like: + // [type/url] < ... struct contents ... > + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + if tok.value == "[" { + // Looks like an extension or an Any. + // + // TODO: Check whether we need to handle + // namespace rooted names (e.g. ".something.Foo"). + extName, err := p.consumeExtName() + if err != nil { + return err + } + + if s := strings.LastIndex(extName, "/"); s >= 0 { + // If it contains a slash, it's an Any type URL. + messageName := extName[s+1:] + mt := MessageType(messageName) + if mt == nil { + return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) + } + tok = p.next() + if tok.err != nil { + return tok.err + } + // consume an optional colon + if tok.value == ":" { + tok = p.next() + if tok.err != nil { + return tok.err + } + } + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + v := reflect.New(mt.Elem()) + if pe := p.readStruct(v.Elem(), terminator); pe != nil { + return pe + } + b, err := Marshal(v.Interface().(Message)) + if err != nil { + return p.errorf("failed to marshal message of type %q: %v", messageName, err) + } + if fieldSet["type_url"] { + return p.errorf(anyRepeatedlyUnpacked, "type_url") + } + if fieldSet["value"] { + return p.errorf(anyRepeatedlyUnpacked, "value") + } + sv.FieldByName("TypeUrl").SetString(extName) + sv.FieldByName("Value").SetBytes(b) + fieldSet["type_url"] = true + fieldSet["value"] = true + continue + } + + var desc *ExtensionDesc + // This could be faster, but it's functional. + // TODO: Do something smarter than a linear scan. + for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { + if d.Name == extName { + desc = d + break + } + } + if desc == nil { + return p.errorf("unrecognized extension %q", extName) + } + + props := &Properties{} + props.Parse(desc.Tag) + + typ := reflect.TypeOf(desc.ExtensionType) + if err := p.checkForColon(props, typ); err != nil { + return err + } + + rep := desc.repeated() + + // Read the extension structure, and set it in + // the value we're constructing. + var ext reflect.Value + if !rep { + ext = reflect.New(typ).Elem() + } else { + ext = reflect.New(typ.Elem()).Elem() + } + if err := p.readAny(ext, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + ep := sv.Addr().Interface().(Message) + if !rep { + SetExtension(ep, desc, ext.Interface()) + } else { + old, err := GetExtension(ep, desc) + var sl reflect.Value + if err == nil { + sl = reflect.ValueOf(old) // existing slice + } else { + sl = reflect.MakeSlice(typ, 0, 1) + } + sl = reflect.Append(sl, ext) + SetExtension(ep, desc, sl.Interface()) + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + continue + } + + // This is a normal, non-extension field. + name := tok.value + var dst reflect.Value + fi, props, ok := structFieldByName(sprops, name) + if ok { + dst = sv.Field(fi) + } else if oop, ok := sprops.OneofTypes[name]; ok { + // It is a oneof. + props = oop.Prop + nv := reflect.New(oop.Type.Elem()) + dst = nv.Elem().Field(0) + field := sv.Field(oop.Field) + if !field.IsNil() { + return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) + } + field.Set(nv) + } + if !dst.IsValid() { + return p.errorf("unknown field name %q in %v", name, st) + } + + if dst.Kind() == reflect.Map { + // Consume any colon. + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Construct the map if it doesn't already exist. + if dst.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) + } + key := reflect.New(dst.Type().Key()).Elem() + val := reflect.New(dst.Type().Elem()).Elem() + + // The map entry should be this sequence of tokens: + // < key : KEY value : VALUE > + // However, implementations may omit key or value, and technically + // we should support them in any order. See b/28924776 for a time + // this went wrong. + + tok := p.next() + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + switch tok.value { + case "key": + if err := p.consumeToken(":"); err != nil { + return err + } + if err := p.readAny(key, props.mkeyprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + case "value": + if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + return err + } + if err := p.readAny(val, props.mvalprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + default: + p.back() + return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) + } + } + + dst.SetMapIndex(key, val) + continue + } + + // Check that it's not already set if it's not a repeated field. + if !props.Repeated && fieldSet[name] { + return p.errorf("non-repeated field %q was repeated", name) + } + + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Parse into the field. + fieldSet[name] = true + if err := p.readAny(dst, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + if props.Required { + reqCount-- + } + + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + + } + + if reqCount > 0 { + return p.missingRequiredFieldError(sv) + } + return reqFieldErr +} + +// consumeExtName consumes extension name or expanded Any type URL and the +// following ']'. It returns the name or URL consumed. +func (p *textParser) consumeExtName() (string, error) { + tok := p.next() + if tok.err != nil { + return "", tok.err + } + + // If extension name or type url is quoted, it's a single token. + if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { + name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) + if err != nil { + return "", err + } + return name, p.consumeToken("]") + } + + // Consume everything up to "]" + var parts []string + for tok.value != "]" { + parts = append(parts, tok.value) + tok = p.next() + if tok.err != nil { + return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) + } + } + return strings.Join(parts, ""), nil +} + +// consumeOptionalSeparator consumes an optional semicolon or comma. +// It is used in readStruct to provide backward compatibility. +func (p *textParser) consumeOptionalSeparator() error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ";" && tok.value != "," { + p.back() + } + return nil +} + +func (p *textParser) readAny(v reflect.Value, props *Properties) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "" { + return p.errorf("unexpected EOF") + } + + switch fv := v; fv.Kind() { + case reflect.Slice: + at := v.Type() + if at.Elem().Kind() == reflect.Uint8 { + // Special case for []byte + if tok.value[0] != '"' && tok.value[0] != '\'' { + // Deliberately written out here, as the error after + // this switch statement would write "invalid []byte: ...", + // which is not as user-friendly. + return p.errorf("invalid string: %v", tok.value) + } + bytes := []byte(tok.unquoted) + fv.Set(reflect.ValueOf(bytes)) + return nil + } + // Repeated field. + if tok.value == "[" { + // Repeated field with list notation, like [1,2,3]. + for { + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + err := p.readAny(fv.Index(fv.Len()-1), props) + if err != nil { + return err + } + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "]" { + break + } + if tok.value != "," { + return p.errorf("Expected ']' or ',' found %q", tok.value) + } + } + return nil + } + // One value of the repeated field. + p.back() + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + return p.readAny(fv.Index(fv.Len()-1), props) + case reflect.Bool: + // true/1/t/True or false/f/0/False. + switch tok.value { + case "true", "1", "t", "True": + fv.SetBool(true) + return nil + case "false", "0", "f", "False": + fv.SetBool(false) + return nil + } + case reflect.Float32, reflect.Float64: + v := tok.value + // Ignore 'f' for compatibility with output generated by C++, but don't + // remove 'f' when the value is "-inf" or "inf". + if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { + v = v[:len(v)-1] + } + if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { + fv.SetFloat(f) + return nil + } + case reflect.Int32: + if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { + fv.SetInt(x) + return nil + } + + if len(props.Enum) == 0 { + break + } + m, ok := enumValueMaps[props.Enum] + if !ok { + break + } + x, ok := m[tok.value] + if !ok { + break + } + fv.SetInt(int64(x)) + return nil + case reflect.Int64: + if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { + fv.SetInt(x) + return nil + } + + case reflect.Ptr: + // A basic field (indirected through pointer), or a repeated message/group + p.back() + fv.Set(reflect.New(fv.Type().Elem())) + return p.readAny(fv.Elem(), props) + case reflect.String: + if tok.value[0] == '"' || tok.value[0] == '\'' { + fv.SetString(tok.unquoted) + return nil + } + case reflect.Struct: + var terminator string + switch tok.value { + case "{": + terminator = "}" + case "<": + terminator = ">" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + // TODO: Handle nested messages which implement encoding.TextUnmarshaler. + return p.readStruct(fv, terminator) + case reflect.Uint32: + if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { + fv.SetUint(x) + return nil + } + case reflect.Uint64: + if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { + fv.SetUint(x) + return nil + } + } + return p.errorf("invalid %v: %v", v.Type(), tok.value) +} + +// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb +// before starting to unmarshal, so any existing data in pb is always removed. +// If a required field is not set and no other error occurs, +// UnmarshalText returns *RequiredNotSetError. +func UnmarshalText(s string, pb Message) error { + if um, ok := pb.(encoding.TextUnmarshaler); ok { + err := um.UnmarshalText([]byte(s)) + return err + } + pb.Reset() + v := reflect.ValueOf(pb) + if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { + return pe + } + return nil +} diff --git a/vendor/github.com/golang/protobuf/ptypes/any.go b/vendor/github.com/golang/protobuf/ptypes/any.go new file mode 100644 index 000000000..b2af97f4a --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any.go @@ -0,0 +1,139 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package ptypes + +// This file implements functions to marshal proto.Message to/from +// google.protobuf.Any message. + +import ( + "fmt" + "reflect" + "strings" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +const googleApis = "type.googleapis.com/" + +// AnyMessageName returns the name of the message contained in a google.protobuf.Any message. +// +// Note that regular type assertions should be done using the Is +// function. AnyMessageName is provided for less common use cases like filtering a +// sequence of Any messages based on a set of allowed message type names. +func AnyMessageName(any *any.Any) (string, error) { + if any == nil { + return "", fmt.Errorf("message is nil") + } + slash := strings.LastIndex(any.TypeUrl, "/") + if slash < 0 { + return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl) + } + return any.TypeUrl[slash+1:], nil +} + +// MarshalAny takes the protocol buffer and encodes it into google.protobuf.Any. +func MarshalAny(pb proto.Message) (*any.Any, error) { + value, err := proto.Marshal(pb) + if err != nil { + return nil, err + } + return &any.Any{TypeUrl: googleApis + proto.MessageName(pb), Value: value}, nil +} + +// DynamicAny is a value that can be passed to UnmarshalAny to automatically +// allocate a proto.Message for the type specified in a google.protobuf.Any +// message. The allocated message is stored in the embedded proto.Message. +// +// Example: +// +// var x ptypes.DynamicAny +// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... } +// fmt.Printf("unmarshaled message: %v", x.Message) +type DynamicAny struct { + proto.Message +} + +// Empty returns a new proto.Message of the type specified in a +// google.protobuf.Any message. It returns an error if corresponding message +// type isn't linked in. +func Empty(any *any.Any) (proto.Message, error) { + aname, err := AnyMessageName(any) + if err != nil { + return nil, err + } + + t := proto.MessageType(aname) + if t == nil { + return nil, fmt.Errorf("any: message type %q isn't linked in", aname) + } + return reflect.New(t.Elem()).Interface().(proto.Message), nil +} + +// UnmarshalAny parses the protocol buffer representation in a google.protobuf.Any +// message and places the decoded result in pb. It returns an error if type of +// contents of Any message does not match type of pb message. +// +// pb can be a proto.Message, or a *DynamicAny. +func UnmarshalAny(any *any.Any, pb proto.Message) error { + if d, ok := pb.(*DynamicAny); ok { + if d.Message == nil { + var err error + d.Message, err = Empty(any) + if err != nil { + return err + } + } + return UnmarshalAny(any, d.Message) + } + + aname, err := AnyMessageName(any) + if err != nil { + return err + } + + mname := proto.MessageName(pb) + if aname != mname { + return fmt.Errorf("mismatched message type: got %q want %q", aname, mname) + } + return proto.Unmarshal(any.Value, pb) +} + +// Is returns true if any value contains a given message type. +func Is(any *any.Any, pb proto.Message) bool { + aname, err := AnyMessageName(any) + if err != nil { + return false + } + + return aname == proto.MessageName(pb) +} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go new file mode 100644 index 000000000..f34601723 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go @@ -0,0 +1,178 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/any.proto + +/* +Package any is a generated protocol buffer package. + +It is generated from these files: + google/protobuf/any.proto + +It has these top-level messages: + Any +*/ +package any + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := ptypes.MarshalAny(foo) +// ... +// foo := &pb.Foo{} +// if err := ptypes.UnmarshalAny(any, foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +type Any struct { + // A URL/resource name whose content describes the type of the + // serialized protocol buffer message. + // + // For URLs which use the scheme `http`, `https`, or no scheme, the + // following restrictions and interpretations apply: + // + // * If no scheme is provided, `https` is assumed. + // * The last segment of the URL's path must represent the fully + // qualified name of the type (as in `path/google.protobuf.Duration`). + // The name should be in a canonical form (e.g., leading "." is + // not accepted). + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"` + // Must be a valid serialized protocol buffer of the above specified type. + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *Any) Reset() { *m = Any{} } +func (m *Any) String() string { return proto.CompactTextString(m) } +func (*Any) ProtoMessage() {} +func (*Any) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (*Any) XXX_WellKnownType() string { return "Any" } + +func (m *Any) GetTypeUrl() string { + if m != nil { + return m.TypeUrl + } + return "" +} + +func (m *Any) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func init() { + proto.RegisterType((*Any)(nil), "google.protobuf.Any") +} + +func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 185 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f, + 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4, + 0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x25, 0x33, 0x2e, 0x66, 0xc7, 0xbc, 0x4a, + 0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46, + 0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7, + 0x34, 0x55, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xc2, 0x71, 0xca, 0xe7, 0x12, 0x4e, 0xce, + 0xcf, 0xd5, 0x43, 0x33, 0xce, 0x89, 0xc3, 0x31, 0xaf, 0x32, 0x00, 0xc4, 0x09, 0x60, 0x8c, 0x52, + 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc, + 0x4b, 0x47, 0xb8, 0xa8, 0x00, 0x64, 0x7a, 0x31, 0xc8, 0x61, 0x8b, 0x98, 0x98, 0xdd, 0x03, 0x9c, + 0x56, 0x31, 0xc9, 0xb9, 0x43, 0x8c, 0x0a, 0x80, 0x2a, 0xd1, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce, + 0xcb, 0x2f, 0xcf, 0x0b, 0x01, 0x29, 0x4d, 0x62, 0x03, 0xeb, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff, + 0xff, 0x13, 0xf8, 0xe8, 0x42, 0xdd, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.proto b/vendor/github.com/golang/protobuf/ptypes/any/any.proto new file mode 100644 index 000000000..c74866762 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any/any.proto @@ -0,0 +1,149 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/any"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := ptypes.MarshalAny(foo) +// ... +// foo := &pb.Foo{} +// if err := ptypes.UnmarshalAny(any, foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name whose content describes the type of the + // serialized protocol buffer message. + // + // For URLs which use the scheme `http`, `https`, or no scheme, the + // following restrictions and interpretations apply: + // + // * If no scheme is provided, `https` is assumed. + // * The last segment of the URL's path must represent the fully + // qualified name of the type (as in `path/google.protobuf.Duration`). + // The name should be in a canonical form (e.g., leading "." is + // not accepted). + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} diff --git a/vendor/github.com/golang/protobuf/ptypes/doc.go b/vendor/github.com/golang/protobuf/ptypes/doc.go new file mode 100644 index 000000000..c0d595da7 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/doc.go @@ -0,0 +1,35 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* +Package ptypes contains code for interacting with well-known types. +*/ +package ptypes diff --git a/vendor/github.com/golang/protobuf/ptypes/duration.go b/vendor/github.com/golang/protobuf/ptypes/duration.go new file mode 100644 index 000000000..65cb0f8eb --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration.go @@ -0,0 +1,102 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package ptypes + +// This file implements conversions between google.protobuf.Duration +// and time.Duration. + +import ( + "errors" + "fmt" + "time" + + durpb "github.com/golang/protobuf/ptypes/duration" +) + +const ( + // Range of a durpb.Duration in seconds, as specified in + // google/protobuf/duration.proto. This is about 10,000 years in seconds. + maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) + minSeconds = -maxSeconds +) + +// validateDuration determines whether the durpb.Duration is valid according to the +// definition in google/protobuf/duration.proto. A valid durpb.Duration +// may still be too large to fit into a time.Duration (the range of durpb.Duration +// is about 10,000 years, and the range of time.Duration is about 290). +func validateDuration(d *durpb.Duration) error { + if d == nil { + return errors.New("duration: nil Duration") + } + if d.Seconds < minSeconds || d.Seconds > maxSeconds { + return fmt.Errorf("duration: %v: seconds out of range", d) + } + if d.Nanos <= -1e9 || d.Nanos >= 1e9 { + return fmt.Errorf("duration: %v: nanos out of range", d) + } + // Seconds and Nanos must have the same sign, unless d.Nanos is zero. + if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) { + return fmt.Errorf("duration: %v: seconds and nanos have different signs", d) + } + return nil +} + +// Duration converts a durpb.Duration to a time.Duration. Duration +// returns an error if the durpb.Duration is invalid or is too large to be +// represented in a time.Duration. +func Duration(p *durpb.Duration) (time.Duration, error) { + if err := validateDuration(p); err != nil { + return 0, err + } + d := time.Duration(p.Seconds) * time.Second + if int64(d/time.Second) != p.Seconds { + return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p) + } + if p.Nanos != 0 { + d += time.Duration(p.Nanos) + if (d < 0) != (p.Nanos < 0) { + return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p) + } + } + return d, nil +} + +// DurationProto converts a time.Duration to a durpb.Duration. +func DurationProto(d time.Duration) *durpb.Duration { + nanos := d.Nanoseconds() + secs := nanos / 1e9 + nanos -= secs * 1e9 + return &durpb.Duration{ + Seconds: secs, + Nanos: int32(nanos), + } +} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go new file mode 100644 index 000000000..b2410a098 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go @@ -0,0 +1,144 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/duration.proto + +/* +Package duration is a generated protocol buffer package. + +It is generated from these files: + google/protobuf/duration.proto + +It has these top-level messages: + Duration +*/ +package duration + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (durations.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +// +type Duration struct { + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` +} + +func (m *Duration) Reset() { *m = Duration{} } +func (m *Duration) String() string { return proto.CompactTextString(m) } +func (*Duration) ProtoMessage() {} +func (*Duration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (*Duration) XXX_WellKnownType() string { return "Duration" } + +func (m *Duration) GetSeconds() int64 { + if m != nil { + return m.Seconds + } + return 0 +} + +func (m *Duration) GetNanos() int32 { + if m != nil { + return m.Nanos + } + return 0 +} + +func init() { + proto.RegisterType((*Duration)(nil), "google.protobuf.Duration") +} + +func init() { proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 190 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f, + 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a, + 0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0x56, + 0x5c, 0x1c, 0x2e, 0x50, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0xc9, 0xf9, 0x79, 0x29, 0xc5, + 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x5e, 0x62, 0x5e, + 0x7e, 0xb1, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x6b, 0x10, 0x84, 0xe3, 0x54, 0xc3, 0x25, 0x9c, 0x9c, + 0x9f, 0xab, 0x87, 0x66, 0xa4, 0x13, 0x2f, 0xcc, 0xc0, 0x00, 0x90, 0x48, 0x00, 0x63, 0x94, 0x56, + 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e, + 0x3a, 0xc2, 0x7d, 0x05, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x70, 0x67, 0xfe, 0x60, 0x64, 0x5c, 0xc4, + 0xc4, 0xec, 0x1e, 0xe0, 0xb4, 0x8a, 0x49, 0xce, 0x1d, 0x62, 0x6e, 0x00, 0x54, 0xa9, 0x5e, 0x78, + 0x6a, 0x4e, 0x8e, 0x77, 0x5e, 0x7e, 0x79, 0x5e, 0x08, 0x48, 0x4b, 0x12, 0x1b, 0xd8, 0x0c, 0x63, + 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x84, 0x30, 0xff, 0xf3, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto b/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto new file mode 100644 index 000000000..975fce41a --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto @@ -0,0 +1,117 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/duration"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DurationProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (durations.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +// +message Duration { + + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + int64 seconds = 1; + + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + int32 nanos = 2; +} diff --git a/vendor/github.com/golang/protobuf/ptypes/regen.sh b/vendor/github.com/golang/protobuf/ptypes/regen.sh new file mode 100755 index 000000000..b50a9414a --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/regen.sh @@ -0,0 +1,43 @@ +#!/bin/bash -e +# +# This script fetches and rebuilds the "well-known types" protocol buffers. +# To run this you will need protoc and goprotobuf installed; +# see https://github.com/golang/protobuf for instructions. +# You also need Go and Git installed. + +PKG=github.com/golang/protobuf/ptypes +UPSTREAM=https://github.com/google/protobuf +UPSTREAM_SUBDIR=src/google/protobuf +PROTO_FILES=(any duration empty struct timestamp wrappers) + +function die() { + echo 1>&2 $* + exit 1 +} + +# Sanity check that the right tools are accessible. +for tool in go git protoc protoc-gen-go; do + q=$(which $tool) || die "didn't find $tool" + echo 1>&2 "$tool: $q" +done + +tmpdir=$(mktemp -d -t regen-wkt.XXXXXX) +trap 'rm -rf $tmpdir' EXIT + +echo -n 1>&2 "finding package dir... " +pkgdir=$(go list -f '{{.Dir}}' $PKG) +echo 1>&2 $pkgdir +base=$(echo $pkgdir | sed "s,/$PKG\$,,") +echo 1>&2 "base: $base" +cd "$base" + +echo 1>&2 "fetching latest protos... " +git clone -q $UPSTREAM $tmpdir + +for file in ${PROTO_FILES[@]}; do + echo 1>&2 "* $file" + protoc --go_out=. -I$tmpdir/src $tmpdir/src/google/protobuf/$file.proto || die + cp $tmpdir/src/google/protobuf/$file.proto $PKG/$file +done + +echo 1>&2 "All OK" diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp.go b/vendor/github.com/golang/protobuf/ptypes/timestamp.go new file mode 100644 index 000000000..47f10dbc2 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp.go @@ -0,0 +1,134 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package ptypes + +// This file implements operations on google.protobuf.Timestamp. + +import ( + "errors" + "fmt" + "time" + + tspb "github.com/golang/protobuf/ptypes/timestamp" +) + +const ( + // Seconds field of the earliest valid Timestamp. + // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + minValidSeconds = -62135596800 + // Seconds field just after the latest valid Timestamp. + // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + maxValidSeconds = 253402300800 +) + +// validateTimestamp determines whether a Timestamp is valid. +// A valid timestamp represents a time in the range +// [0001-01-01, 10000-01-01) and has a Nanos field +// in the range [0, 1e9). +// +// If the Timestamp is valid, validateTimestamp returns nil. +// Otherwise, it returns an error that describes +// the problem. +// +// Every valid Timestamp can be represented by a time.Time, but the converse is not true. +func validateTimestamp(ts *tspb.Timestamp) error { + if ts == nil { + return errors.New("timestamp: nil Timestamp") + } + if ts.Seconds < minValidSeconds { + return fmt.Errorf("timestamp: %v before 0001-01-01", ts) + } + if ts.Seconds >= maxValidSeconds { + return fmt.Errorf("timestamp: %v after 10000-01-01", ts) + } + if ts.Nanos < 0 || ts.Nanos >= 1e9 { + return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts) + } + return nil +} + +// Timestamp converts a google.protobuf.Timestamp proto to a time.Time. +// It returns an error if the argument is invalid. +// +// Unlike most Go functions, if Timestamp returns an error, the first return value +// is not the zero time.Time. Instead, it is the value obtained from the +// time.Unix function when passed the contents of the Timestamp, in the UTC +// locale. This may or may not be a meaningful time; many invalid Timestamps +// do map to valid time.Times. +// +// A nil Timestamp returns an error. The first return value in that case is +// undefined. +func Timestamp(ts *tspb.Timestamp) (time.Time, error) { + // Don't return the zero value on error, because corresponds to a valid + // timestamp. Instead return whatever time.Unix gives us. + var t time.Time + if ts == nil { + t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp + } else { + t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() + } + return t, validateTimestamp(ts) +} + +// TimestampNow returns a google.protobuf.Timestamp for the current time. +func TimestampNow() *tspb.Timestamp { + ts, err := TimestampProto(time.Now()) + if err != nil { + panic("ptypes: time.Now() out of Timestamp range") + } + return ts +} + +// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. +// It returns an error if the resulting Timestamp is invalid. +func TimestampProto(t time.Time) (*tspb.Timestamp, error) { + seconds := t.Unix() + nanos := int32(t.Sub(time.Unix(seconds, 0))) + ts := &tspb.Timestamp{ + Seconds: seconds, + Nanos: nanos, + } + if err := validateTimestamp(ts); err != nil { + return nil, err + } + return ts, nil +} + +// TimestampString returns the RFC 3339 string for valid Timestamps. For invalid +// Timestamps, it returns an error message in parentheses. +func TimestampString(ts *tspb.Timestamp) string { + t, err := Timestamp(ts) + if err != nil { + return fmt.Sprintf("(%v)", err) + } + return t.Format(time.RFC3339Nano) +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go new file mode 100644 index 000000000..e23e4a25d --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go @@ -0,0 +1,160 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/timestamp.proto + +/* +Package timestamp is a generated protocol buffer package. + +It is generated from these files: + google/protobuf/timestamp.proto + +It has these top-level messages: + Timestamp +*/ +package timestamp + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// A Timestamp represents a point in time independent of any time zone +// or calendar, represented as seconds and fractions of seconds at +// nanosecond resolution in UTC Epoch time. It is encoded using the +// Proleptic Gregorian Calendar which extends the Gregorian calendar +// backwards to year one. It is encoded assuming all minutes are 60 +// seconds long, i.e. leap seconds are "smeared" so that no leap second +// table is needed for interpretation. Range is from +// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. +// By restricting to that range, we ensure that we can convert to +// and from RFC 3339 date strings. +// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// +// Example 5: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required, though only UTC (as indicated by "Z") is presently supported. +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) +// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one +// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()) +// to obtain a formatter capable of generating timestamps in this format. +// +// +type Timestamp struct { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` +} + +func (m *Timestamp) Reset() { *m = Timestamp{} } +func (m *Timestamp) String() string { return proto.CompactTextString(m) } +func (*Timestamp) ProtoMessage() {} +func (*Timestamp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" } + +func (m *Timestamp) GetSeconds() int64 { + if m != nil { + return m.Seconds + } + return 0 +} + +func (m *Timestamp) GetNanos() int32 { + if m != nil { + return m.Nanos + } + return 0 +} + +func init() { + proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp") +} + +func init() { proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 191 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f, + 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d, + 0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0xd0, 0x03, 0x0b, 0x09, 0xf1, 0x43, 0x14, 0xe8, 0xc1, 0x14, 0x28, + 0x59, 0x73, 0x71, 0x86, 0xc0, 0xd4, 0x08, 0x49, 0x70, 0xb1, 0x17, 0xa7, 0x26, 0xe7, 0xe7, 0xa5, + 0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0xc1, 0xb8, 0x42, 0x22, 0x5c, 0xac, 0x79, 0x89, + 0x79, 0xf9, 0xc5, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x10, 0x8e, 0x53, 0x1d, 0x97, 0x70, + 0x72, 0x7e, 0xae, 0x1e, 0x9a, 0x99, 0x4e, 0x7c, 0x70, 0x13, 0x03, 0x40, 0x42, 0x01, 0x8c, 0x51, + 0xda, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0x39, 0x89, + 0x79, 0xe9, 0x08, 0x27, 0x16, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x23, 0x5c, 0xfa, 0x83, 0x91, 0x71, + 0x11, 0x13, 0xb3, 0x7b, 0x80, 0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xc9, 0x01, 0x50, 0xb5, 0x7a, + 0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x20, 0x3d, 0x49, 0x6c, 0x60, 0x43, + 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x77, 0x4a, 0x07, 0xf7, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto new file mode 100644 index 000000000..b7cbd1750 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto @@ -0,0 +1,133 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/timestamp"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TimestampProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Timestamp represents a point in time independent of any time zone +// or calendar, represented as seconds and fractions of seconds at +// nanosecond resolution in UTC Epoch time. It is encoded using the +// Proleptic Gregorian Calendar which extends the Gregorian calendar +// backwards to year one. It is encoded assuming all minutes are 60 +// seconds long, i.e. leap seconds are "smeared" so that no leap second +// table is needed for interpretation. Range is from +// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. +// By restricting to that range, we ensure that we can convert to +// and from RFC 3339 date strings. +// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// +// Example 5: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required, though only UTC (as indicated by "Z") is presently supported. +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) +// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one +// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()) +// to obtain a formatter capable of generating timestamps in this format. +// +// +message Timestamp { + + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + int32 nanos = 2; +} diff --git a/vendor/github.com/google/btree/.travis.yml b/vendor/github.com/google/btree/.travis.yml new file mode 100644 index 000000000..4f2ee4d97 --- /dev/null +++ b/vendor/github.com/google/btree/.travis.yml @@ -0,0 +1 @@ +language: go diff --git a/vendor/github.com/google/btree/LICENSE b/vendor/github.com/google/btree/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/google/btree/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/google/btree/README.md b/vendor/github.com/google/btree/README.md new file mode 100644 index 000000000..6062a4dac --- /dev/null +++ b/vendor/github.com/google/btree/README.md @@ -0,0 +1,12 @@ +# BTree implementation for Go + +![Travis CI Build Status](https://api.travis-ci.org/google/btree.svg?branch=master) + +This package provides an in-memory B-Tree implementation for Go, useful as +an ordered, mutable data structure. + +The API is based off of the wonderful +http://godoc.org/github.com/petar/GoLLRB/llrb, and is meant to allow btree to +act as a drop-in replacement for gollrb trees. + +See http://godoc.org/github.com/google/btree for documentation. diff --git a/vendor/github.com/google/btree/btree.go b/vendor/github.com/google/btree/btree.go new file mode 100644 index 000000000..fc5aaaa13 --- /dev/null +++ b/vendor/github.com/google/btree/btree.go @@ -0,0 +1,649 @@ +// Copyright 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package btree implements in-memory B-Trees of arbitrary degree. +// +// btree implements an in-memory B-Tree for use as an ordered data structure. +// It is not meant for persistent storage solutions. +// +// It has a flatter structure than an equivalent red-black or other binary tree, +// which in some cases yields better memory usage and/or performance. +// See some discussion on the matter here: +// http://google-opensource.blogspot.com/2013/01/c-containers-that-save-memory-and-time.html +// Note, though, that this project is in no way related to the C++ B-Tree +// implmentation written about there. +// +// Within this tree, each node contains a slice of items and a (possibly nil) +// slice of children. For basic numeric values or raw structs, this can cause +// efficiency differences when compared to equivalent C++ template code that +// stores values in arrays within the node: +// * Due to the overhead of storing values as interfaces (each +// value needs to be stored as the value itself, then 2 words for the +// interface pointing to that value and its type), resulting in higher +// memory use. +// * Since interfaces can point to values anywhere in memory, values are +// most likely not stored in contiguous blocks, resulting in a higher +// number of cache misses. +// These issues don't tend to matter, though, when working with strings or other +// heap-allocated structures, since C++-equivalent structures also must store +// pointers and also distribute their values across the heap. +// +// This implementation is designed to be a drop-in replacement to gollrb.LLRB +// trees, (http://github.com/petar/gollrb), an excellent and probably the most +// widely used ordered tree implementation in the Go ecosystem currently. +// Its functions, therefore, exactly mirror those of +// llrb.LLRB where possible. Unlike gollrb, though, we currently don't +// support storing multiple equivalent values or backwards iteration. +package btree + +import ( + "fmt" + "io" + "sort" + "strings" +) + +// Item represents a single object in the tree. +type Item interface { + // Less tests whether the current item is less than the given argument. + // + // This must provide a strict weak ordering. + // If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only + // hold one of either a or b in the tree). + Less(than Item) bool +} + +const ( + DefaultFreeListSize = 32 +) + +// FreeList represents a free list of btree nodes. By default each +// BTree has its own FreeList, but multiple BTrees can share the same +// FreeList. +// Two Btrees using the same freelist are not safe for concurrent write access. +type FreeList struct { + freelist []*node +} + +// NewFreeList creates a new free list. +// size is the maximum size of the returned free list. +func NewFreeList(size int) *FreeList { + return &FreeList{freelist: make([]*node, 0, size)} +} + +func (f *FreeList) newNode() (n *node) { + index := len(f.freelist) - 1 + if index < 0 { + return new(node) + } + f.freelist, n = f.freelist[:index], f.freelist[index] + return +} + +func (f *FreeList) freeNode(n *node) { + if len(f.freelist) < cap(f.freelist) { + f.freelist = append(f.freelist, n) + } +} + +// ItemIterator allows callers of Ascend* to iterate in-order over portions of +// the tree. When this function returns false, iteration will stop and the +// associated Ascend* function will immediately return. +type ItemIterator func(i Item) bool + +// New creates a new B-Tree with the given degree. +// +// New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items +// and 2-4 children). +func New(degree int) *BTree { + return NewWithFreeList(degree, NewFreeList(DefaultFreeListSize)) +} + +// NewWithFreeList creates a new B-Tree that uses the given node free list. +func NewWithFreeList(degree int, f *FreeList) *BTree { + if degree <= 1 { + panic("bad degree") + } + return &BTree{ + degree: degree, + freelist: f, + } +} + +// items stores items in a node. +type items []Item + +// insertAt inserts a value into the given index, pushing all subsequent values +// forward. +func (s *items) insertAt(index int, item Item) { + *s = append(*s, nil) + if index < len(*s) { + copy((*s)[index+1:], (*s)[index:]) + } + (*s)[index] = item +} + +// removeAt removes a value at a given index, pulling all subsequent values +// back. +func (s *items) removeAt(index int) Item { + item := (*s)[index] + (*s)[index] = nil + copy((*s)[index:], (*s)[index+1:]) + *s = (*s)[:len(*s)-1] + return item +} + +// pop removes and returns the last element in the list. +func (s *items) pop() (out Item) { + index := len(*s) - 1 + out = (*s)[index] + (*s)[index] = nil + *s = (*s)[:index] + return +} + +// find returns the index where the given item should be inserted into this +// list. 'found' is true if the item already exists in the list at the given +// index. +func (s items) find(item Item) (index int, found bool) { + i := sort.Search(len(s), func(i int) bool { + return item.Less(s[i]) + }) + if i > 0 && !s[i-1].Less(item) { + return i - 1, true + } + return i, false +} + +// children stores child nodes in a node. +type children []*node + +// insertAt inserts a value into the given index, pushing all subsequent values +// forward. +func (s *children) insertAt(index int, n *node) { + *s = append(*s, nil) + if index < len(*s) { + copy((*s)[index+1:], (*s)[index:]) + } + (*s)[index] = n +} + +// removeAt removes a value at a given index, pulling all subsequent values +// back. +func (s *children) removeAt(index int) *node { + n := (*s)[index] + (*s)[index] = nil + copy((*s)[index:], (*s)[index+1:]) + *s = (*s)[:len(*s)-1] + return n +} + +// pop removes and returns the last element in the list. +func (s *children) pop() (out *node) { + index := len(*s) - 1 + out = (*s)[index] + (*s)[index] = nil + *s = (*s)[:index] + return +} + +// node is an internal node in a tree. +// +// It must at all times maintain the invariant that either +// * len(children) == 0, len(items) unconstrained +// * len(children) == len(items) + 1 +type node struct { + items items + children children + t *BTree +} + +// split splits the given node at the given index. The current node shrinks, +// and this function returns the item that existed at that index and a new node +// containing all items/children after it. +func (n *node) split(i int) (Item, *node) { + item := n.items[i] + next := n.t.newNode() + next.items = append(next.items, n.items[i+1:]...) + n.items = n.items[:i] + if len(n.children) > 0 { + next.children = append(next.children, n.children[i+1:]...) + n.children = n.children[:i+1] + } + return item, next +} + +// maybeSplitChild checks if a child should be split, and if so splits it. +// Returns whether or not a split occurred. +func (n *node) maybeSplitChild(i, maxItems int) bool { + if len(n.children[i].items) < maxItems { + return false + } + first := n.children[i] + item, second := first.split(maxItems / 2) + n.items.insertAt(i, item) + n.children.insertAt(i+1, second) + return true +} + +// insert inserts an item into the subtree rooted at this node, making sure +// no nodes in the subtree exceed maxItems items. Should an equivalent item be +// be found/replaced by insert, it will be returned. +func (n *node) insert(item Item, maxItems int) Item { + i, found := n.items.find(item) + if found { + out := n.items[i] + n.items[i] = item + return out + } + if len(n.children) == 0 { + n.items.insertAt(i, item) + return nil + } + if n.maybeSplitChild(i, maxItems) { + inTree := n.items[i] + switch { + case item.Less(inTree): + // no change, we want first split node + case inTree.Less(item): + i++ // we want second split node + default: + out := n.items[i] + n.items[i] = item + return out + } + } + return n.children[i].insert(item, maxItems) +} + +// get finds the given key in the subtree and returns it. +func (n *node) get(key Item) Item { + i, found := n.items.find(key) + if found { + return n.items[i] + } else if len(n.children) > 0 { + return n.children[i].get(key) + } + return nil +} + +// min returns the first item in the subtree. +func min(n *node) Item { + if n == nil { + return nil + } + for len(n.children) > 0 { + n = n.children[0] + } + if len(n.items) == 0 { + return nil + } + return n.items[0] +} + +// max returns the last item in the subtree. +func max(n *node) Item { + if n == nil { + return nil + } + for len(n.children) > 0 { + n = n.children[len(n.children)-1] + } + if len(n.items) == 0 { + return nil + } + return n.items[len(n.items)-1] +} + +// toRemove details what item to remove in a node.remove call. +type toRemove int + +const ( + removeItem toRemove = iota // removes the given item + removeMin // removes smallest item in the subtree + removeMax // removes largest item in the subtree +) + +// remove removes an item from the subtree rooted at this node. +func (n *node) remove(item Item, minItems int, typ toRemove) Item { + var i int + var found bool + switch typ { + case removeMax: + if len(n.children) == 0 { + return n.items.pop() + } + i = len(n.items) + case removeMin: + if len(n.children) == 0 { + return n.items.removeAt(0) + } + i = 0 + case removeItem: + i, found = n.items.find(item) + if len(n.children) == 0 { + if found { + return n.items.removeAt(i) + } + return nil + } + default: + panic("invalid type") + } + // If we get to here, we have children. + child := n.children[i] + if len(child.items) <= minItems { + return n.growChildAndRemove(i, item, minItems, typ) + } + // Either we had enough items to begin with, or we've done some + // merging/stealing, because we've got enough now and we're ready to return + // stuff. + if found { + // The item exists at index 'i', and the child we've selected can give us a + // predecessor, since if we've gotten here it's got > minItems items in it. + out := n.items[i] + // We use our special-case 'remove' call with typ=maxItem to pull the + // predecessor of item i (the rightmost leaf of our immediate left child) + // and set it into where we pulled the item from. + n.items[i] = child.remove(nil, minItems, removeMax) + return out + } + // Final recursive call. Once we're here, we know that the item isn't in this + // node and that the child is big enough to remove from. + return child.remove(item, minItems, typ) +} + +// growChildAndRemove grows child 'i' to make sure it's possible to remove an +// item from it while keeping it at minItems, then calls remove to actually +// remove it. +// +// Most documentation says we have to do two sets of special casing: +// 1) item is in this node +// 2) item is in child +// In both cases, we need to handle the two subcases: +// A) node has enough values that it can spare one +// B) node doesn't have enough values +// For the latter, we have to check: +// a) left sibling has node to spare +// b) right sibling has node to spare +// c) we must merge +// To simplify our code here, we handle cases #1 and #2 the same: +// If a node doesn't have enough items, we make sure it does (using a,b,c). +// We then simply redo our remove call, and the second time (regardless of +// whether we're in case 1 or 2), we'll have enough items and can guarantee +// that we hit case A. +func (n *node) growChildAndRemove(i int, item Item, minItems int, typ toRemove) Item { + child := n.children[i] + if i > 0 && len(n.children[i-1].items) > minItems { + // Steal from left child + stealFrom := n.children[i-1] + stolenItem := stealFrom.items.pop() + child.items.insertAt(0, n.items[i-1]) + n.items[i-1] = stolenItem + if len(stealFrom.children) > 0 { + child.children.insertAt(0, stealFrom.children.pop()) + } + } else if i < len(n.items) && len(n.children[i+1].items) > minItems { + // steal from right child + stealFrom := n.children[i+1] + stolenItem := stealFrom.items.removeAt(0) + child.items = append(child.items, n.items[i]) + n.items[i] = stolenItem + if len(stealFrom.children) > 0 { + child.children = append(child.children, stealFrom.children.removeAt(0)) + } + } else { + if i >= len(n.items) { + i-- + child = n.children[i] + } + // merge with right child + mergeItem := n.items.removeAt(i) + mergeChild := n.children.removeAt(i + 1) + child.items = append(child.items, mergeItem) + child.items = append(child.items, mergeChild.items...) + child.children = append(child.children, mergeChild.children...) + n.t.freeNode(mergeChild) + } + return n.remove(item, minItems, typ) +} + +// iterate provides a simple method for iterating over elements in the tree. +// It could probably use some work to be extra-efficient (it calls from() a +// little more than it should), but it works pretty well for now. +// +// It requires that 'from' and 'to' both return true for values we should hit +// with the iterator. It should also be the case that 'from' returns true for +// values less than or equal to values 'to' returns true for, and 'to' +// returns true for values greater than or equal to those that 'from' +// does. +func (n *node) iterate(from, to func(Item) bool, iter ItemIterator) bool { + for i, item := range n.items { + if !from(item) { + continue + } + if len(n.children) > 0 && !n.children[i].iterate(from, to, iter) { + return false + } + if !to(item) { + return false + } + if !iter(item) { + return false + } + } + if len(n.children) > 0 { + return n.children[len(n.children)-1].iterate(from, to, iter) + } + return true +} + +// Used for testing/debugging purposes. +func (n *node) print(w io.Writer, level int) { + fmt.Fprintf(w, "%sNODE:%v\n", strings.Repeat(" ", level), n.items) + for _, c := range n.children { + c.print(w, level+1) + } +} + +// BTree is an implementation of a B-Tree. +// +// BTree stores Item instances in an ordered structure, allowing easy insertion, +// removal, and iteration. +// +// Write operations are not safe for concurrent mutation by multiple +// goroutines, but Read operations are. +type BTree struct { + degree int + length int + root *node + freelist *FreeList +} + +// maxItems returns the max number of items to allow per node. +func (t *BTree) maxItems() int { + return t.degree*2 - 1 +} + +// minItems returns the min number of items to allow per node (ignored for the +// root node). +func (t *BTree) minItems() int { + return t.degree - 1 +} + +func (t *BTree) newNode() (n *node) { + n = t.freelist.newNode() + n.t = t + return +} + +func (t *BTree) freeNode(n *node) { + for i := range n.items { + n.items[i] = nil // clear to allow GC + } + n.items = n.items[:0] + for i := range n.children { + n.children[i] = nil // clear to allow GC + } + n.children = n.children[:0] + n.t = nil // clear to allow GC + t.freelist.freeNode(n) +} + +// ReplaceOrInsert adds the given item to the tree. If an item in the tree +// already equals the given one, it is removed from the tree and returned. +// Otherwise, nil is returned. +// +// nil cannot be added to the tree (will panic). +func (t *BTree) ReplaceOrInsert(item Item) Item { + if item == nil { + panic("nil item being added to BTree") + } + if t.root == nil { + t.root = t.newNode() + t.root.items = append(t.root.items, item) + t.length++ + return nil + } else if len(t.root.items) >= t.maxItems() { + item2, second := t.root.split(t.maxItems() / 2) + oldroot := t.root + t.root = t.newNode() + t.root.items = append(t.root.items, item2) + t.root.children = append(t.root.children, oldroot, second) + } + out := t.root.insert(item, t.maxItems()) + if out == nil { + t.length++ + } + return out +} + +// Delete removes an item equal to the passed in item from the tree, returning +// it. If no such item exists, returns nil. +func (t *BTree) Delete(item Item) Item { + return t.deleteItem(item, removeItem) +} + +// DeleteMin removes the smallest item in the tree and returns it. +// If no such item exists, returns nil. +func (t *BTree) DeleteMin() Item { + return t.deleteItem(nil, removeMin) +} + +// DeleteMax removes the largest item in the tree and returns it. +// If no such item exists, returns nil. +func (t *BTree) DeleteMax() Item { + return t.deleteItem(nil, removeMax) +} + +func (t *BTree) deleteItem(item Item, typ toRemove) Item { + if t.root == nil || len(t.root.items) == 0 { + return nil + } + out := t.root.remove(item, t.minItems(), typ) + if len(t.root.items) == 0 && len(t.root.children) > 0 { + oldroot := t.root + t.root = t.root.children[0] + t.freeNode(oldroot) + } + if out != nil { + t.length-- + } + return out +} + +// AscendRange calls the iterator for every value in the tree within the range +// [greaterOrEqual, lessThan), until iterator returns false. +func (t *BTree) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate( + func(a Item) bool { return !a.Less(greaterOrEqual) }, + func(a Item) bool { return a.Less(lessThan) }, + iterator) +} + +// AscendLessThan calls the iterator for every value in the tree within the range +// [first, pivot), until iterator returns false. +func (t *BTree) AscendLessThan(pivot Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate( + func(a Item) bool { return true }, + func(a Item) bool { return a.Less(pivot) }, + iterator) +} + +// AscendGreaterOrEqual calls the iterator for every value in the tree within +// the range [pivot, last], until iterator returns false. +func (t *BTree) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate( + func(a Item) bool { return !a.Less(pivot) }, + func(a Item) bool { return true }, + iterator) +} + +// Ascend calls the iterator for every value in the tree within the range +// [first, last], until iterator returns false. +func (t *BTree) Ascend(iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate( + func(a Item) bool { return true }, + func(a Item) bool { return true }, + iterator) +} + +// Get looks for the key item in the tree, returning it. It returns nil if +// unable to find that item. +func (t *BTree) Get(key Item) Item { + if t.root == nil { + return nil + } + return t.root.get(key) +} + +// Min returns the smallest item in the tree, or nil if the tree is empty. +func (t *BTree) Min() Item { + return min(t.root) +} + +// Max returns the largest item in the tree, or nil if the tree is empty. +func (t *BTree) Max() Item { + return max(t.root) +} + +// Has returns true if the given key is in the tree. +func (t *BTree) Has(key Item) bool { + return t.Get(key) != nil +} + +// Len returns the number of items currently in the tree. +func (t *BTree) Len() int { + return t.length +} + +// Int implements the Item interface for integers. +type Int int + +// Less returns true if int(a) < int(b). +func (a Int) Less(b Item) bool { + return a < b.(Int) +} diff --git a/vendor/github.com/google/btree/btree_mem.go b/vendor/github.com/google/btree/btree_mem.go new file mode 100644 index 000000000..cb95b7fa1 --- /dev/null +++ b/vendor/github.com/google/btree/btree_mem.go @@ -0,0 +1,76 @@ +// Copyright 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build ignore + +// This binary compares memory usage between btree and gollrb. +package main + +import ( + "flag" + "fmt" + "math/rand" + "runtime" + "time" + + "github.com/google/btree" + "github.com/petar/GoLLRB/llrb" +) + +var ( + size = flag.Int("size", 1000000, "size of the tree to build") + degree = flag.Int("degree", 8, "degree of btree") + gollrb = flag.Bool("llrb", false, "use llrb instead of btree") +) + +func main() { + flag.Parse() + vals := rand.Perm(*size) + var t, v interface{} + v = vals + var stats runtime.MemStats + for i := 0; i < 10; i++ { + runtime.GC() + } + fmt.Println("-------- BEFORE ----------") + runtime.ReadMemStats(&stats) + fmt.Printf("%+v\n", stats) + start := time.Now() + if *gollrb { + tr := llrb.New() + for _, v := range vals { + tr.ReplaceOrInsert(llrb.Int(v)) + } + t = tr // keep it around + } else { + tr := btree.New(*degree) + for _, v := range vals { + tr.ReplaceOrInsert(btree.Int(v)) + } + t = tr // keep it around + } + fmt.Printf("%v inserts in %v\n", *size, time.Since(start)) + fmt.Println("-------- AFTER ----------") + runtime.ReadMemStats(&stats) + fmt.Printf("%+v\n", stats) + for i := 0; i < 10; i++ { + runtime.GC() + } + fmt.Println("-------- AFTER GC ----------") + runtime.ReadMemStats(&stats) + fmt.Printf("%+v\n", stats) + if t == v { + fmt.Println("to make sure vals and tree aren't GC'd") + } +} diff --git a/vendor/github.com/google/gofuzz/.travis.yml b/vendor/github.com/google/gofuzz/.travis.yml new file mode 100644 index 000000000..f8684d99f --- /dev/null +++ b/vendor/github.com/google/gofuzz/.travis.yml @@ -0,0 +1,13 @@ +language: go + +go: + - 1.4 + - 1.3 + - 1.2 + - tip + +install: + - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi + +script: + - go test -cover diff --git a/vendor/github.com/google/gofuzz/CONTRIBUTING.md b/vendor/github.com/google/gofuzz/CONTRIBUTING.md new file mode 100644 index 000000000..51cf5cd1a --- /dev/null +++ b/vendor/github.com/google/gofuzz/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# How to contribute # + +We'd love to accept your patches and contributions to this project. There are +a just a few small guidelines you need to follow. + + +## Contributor License Agreement ## + +Contributions to any Google project must be accompanied by a Contributor +License Agreement. This is not a copyright **assignment**, it simply gives +Google permission to use and redistribute your contributions as part of the +project. + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual + CLA][]. + + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA][]. + +You generally only need to submit a CLA once, so if you've already submitted +one (even if it was for a different project), you probably don't need to do it +again. + +[individual CLA]: https://developers.google.com/open-source/cla/individual +[corporate CLA]: https://developers.google.com/open-source/cla/corporate + + +## Submitting a patch ## + + 1. It's generally best to start by opening a new issue describing the bug or + feature you're intending to fix. Even if you think it's relatively minor, + it's helpful to know what people are working on. Mention in the initial + issue that you are planning to work on that bug or feature so that it can + be assigned to you. + + 1. Follow the normal process of [forking][] the project, and setup a new + branch to work in. It's important that each group of changes be done in + separate branches in order to ensure that a pull request only includes the + commits related to that bug or feature. + + 1. Go makes it very simple to ensure properly formatted code, so always run + `go fmt` on your code before committing it. You should also run + [golint][] over your code. As noted in the [golint readme][], it's not + strictly necessary that your code be completely "lint-free", but this will + help you find common style issues. + + 1. Any significant changes should almost always be accompanied by tests. The + project already has good test coverage, so look at some of the existing + tests if you're unsure how to go about it. [gocov][] and [gocov-html][] + are invaluable tools for seeing which parts of your code aren't being + exercised by your tests. + + 1. Do your best to have [well-formed commit messages][] for each change. + This provides consistency throughout the project, and ensures that commit + messages are able to be formatted properly by various git tools. + + 1. Finally, push the commits to your fork and submit a [pull request][]. + +[forking]: https://help.github.com/articles/fork-a-repo +[golint]: https://github.com/golang/lint +[golint readme]: https://github.com/golang/lint/blob/master/README +[gocov]: https://github.com/axw/gocov +[gocov-html]: https://github.com/matm/gocov-html +[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[squash]: http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits +[pull request]: https://help.github.com/articles/creating-a-pull-request diff --git a/vendor/github.com/google/gofuzz/LICENSE b/vendor/github.com/google/gofuzz/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/google/gofuzz/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/google/gofuzz/README.md b/vendor/github.com/google/gofuzz/README.md new file mode 100644 index 000000000..64869af34 --- /dev/null +++ b/vendor/github.com/google/gofuzz/README.md @@ -0,0 +1,71 @@ +gofuzz +====== + +gofuzz is a library for populating go objects with random values. + +[![GoDoc](https://godoc.org/github.com/google/gofuzz?status.png)](https://godoc.org/github.com/google/gofuzz) +[![Travis](https://travis-ci.org/google/gofuzz.svg?branch=master)](https://travis-ci.org/google/gofuzz) + +This is useful for testing: + +* Do your project's objects really serialize/unserialize correctly in all cases? +* Is there an incorrectly formatted object that will cause your project to panic? + +Import with ```import "github.com/google/gofuzz"``` + +You can use it on single variables: +```go +f := fuzz.New() +var myInt int +f.Fuzz(&myInt) // myInt gets a random value. +``` + +You can use it on maps: +```go +f := fuzz.New().NilChance(0).NumElements(1, 1) +var myMap map[ComplexKeyType]string +f.Fuzz(&myMap) // myMap will have exactly one element. +``` + +Customize the chance of getting a nil pointer: +```go +f := fuzz.New().NilChance(.5) +var fancyStruct struct { + A, B, C, D *string +} +f.Fuzz(&fancyStruct) // About half the pointers should be set. +``` + +You can even customize the randomization completely if needed: +```go +type MyEnum string +const ( + A MyEnum = "A" + B MyEnum = "B" +) +type MyInfo struct { + Type MyEnum + AInfo *string + BInfo *string +} + +f := fuzz.New().NilChance(0).Funcs( + func(e *MyInfo, c fuzz.Continue) { + switch c.Intn(2) { + case 0: + e.Type = A + c.Fuzz(&e.AInfo) + case 1: + e.Type = B + c.Fuzz(&e.BInfo) + } + }, +) + +var myObject MyInfo +f.Fuzz(&myObject) // Type will correspond to whether A or B info is set. +``` + +See more examples in ```example_test.go```. + +Happy testing! diff --git a/vendor/github.com/google/gofuzz/doc.go b/vendor/github.com/google/gofuzz/doc.go new file mode 100644 index 000000000..9f9956d4a --- /dev/null +++ b/vendor/github.com/google/gofuzz/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package fuzz is a library for populating go objects with random values. +package fuzz diff --git a/vendor/github.com/google/gofuzz/fuzz.go b/vendor/github.com/google/gofuzz/fuzz.go new file mode 100644 index 000000000..4f888fbc8 --- /dev/null +++ b/vendor/github.com/google/gofuzz/fuzz.go @@ -0,0 +1,453 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fuzz + +import ( + "fmt" + "math/rand" + "reflect" + "time" +) + +// fuzzFuncMap is a map from a type to a fuzzFunc that handles that type. +type fuzzFuncMap map[reflect.Type]reflect.Value + +// Fuzzer knows how to fill any object with random fields. +type Fuzzer struct { + fuzzFuncs fuzzFuncMap + defaultFuzzFuncs fuzzFuncMap + r *rand.Rand + nilChance float64 + minElements int + maxElements int +} + +// New returns a new Fuzzer. Customize your Fuzzer further by calling Funcs, +// RandSource, NilChance, or NumElements in any order. +func New() *Fuzzer { + f := &Fuzzer{ + defaultFuzzFuncs: fuzzFuncMap{ + reflect.TypeOf(&time.Time{}): reflect.ValueOf(fuzzTime), + }, + + fuzzFuncs: fuzzFuncMap{}, + r: rand.New(rand.NewSource(time.Now().UnixNano())), + nilChance: .2, + minElements: 1, + maxElements: 10, + } + return f +} + +// Funcs adds each entry in fuzzFuncs as a custom fuzzing function. +// +// Each entry in fuzzFuncs must be a function taking two parameters. +// The first parameter must be a pointer or map. It is the variable that +// function will fill with random data. The second parameter must be a +// fuzz.Continue, which will provide a source of randomness and a way +// to automatically continue fuzzing smaller pieces of the first parameter. +// +// These functions are called sensibly, e.g., if you wanted custom string +// fuzzing, the function `func(s *string, c fuzz.Continue)` would get +// called and passed the address of strings. Maps and pointers will always +// be made/new'd for you, ignoring the NilChange option. For slices, it +// doesn't make much sense to pre-create them--Fuzzer doesn't know how +// long you want your slice--so take a pointer to a slice, and make it +// yourself. (If you don't want your map/pointer type pre-made, take a +// pointer to it, and make it yourself.) See the examples for a range of +// custom functions. +func (f *Fuzzer) Funcs(fuzzFuncs ...interface{}) *Fuzzer { + for i := range fuzzFuncs { + v := reflect.ValueOf(fuzzFuncs[i]) + if v.Kind() != reflect.Func { + panic("Need only funcs!") + } + t := v.Type() + if t.NumIn() != 2 || t.NumOut() != 0 { + panic("Need 2 in and 0 out params!") + } + argT := t.In(0) + switch argT.Kind() { + case reflect.Ptr, reflect.Map: + default: + panic("fuzzFunc must take pointer or map type") + } + if t.In(1) != reflect.TypeOf(Continue{}) { + panic("fuzzFunc's second parameter must be type fuzz.Continue") + } + f.fuzzFuncs[argT] = v + } + return f +} + +// RandSource causes f to get values from the given source of randomness. +// Use if you want deterministic fuzzing. +func (f *Fuzzer) RandSource(s rand.Source) *Fuzzer { + f.r = rand.New(s) + return f +} + +// NilChance sets the probability of creating a nil pointer, map, or slice to +// 'p'. 'p' should be between 0 (no nils) and 1 (all nils), inclusive. +func (f *Fuzzer) NilChance(p float64) *Fuzzer { + if p < 0 || p > 1 { + panic("p should be between 0 and 1, inclusive.") + } + f.nilChance = p + return f +} + +// NumElements sets the minimum and maximum number of elements that will be +// added to a non-nil map or slice. +func (f *Fuzzer) NumElements(atLeast, atMost int) *Fuzzer { + if atLeast > atMost { + panic("atLeast must be <= atMost") + } + if atLeast < 0 { + panic("atLeast must be >= 0") + } + f.minElements = atLeast + f.maxElements = atMost + return f +} + +func (f *Fuzzer) genElementCount() int { + if f.minElements == f.maxElements { + return f.minElements + } + return f.minElements + f.r.Intn(f.maxElements-f.minElements+1) +} + +func (f *Fuzzer) genShouldFill() bool { + return f.r.Float64() > f.nilChance +} + +// Fuzz recursively fills all of obj's fields with something random. First +// this tries to find a custom fuzz function (see Funcs). If there is no +// custom function this tests whether the object implements fuzz.Interface and, +// if so, calls Fuzz on it to fuzz itself. If that fails, this will see if +// there is a default fuzz function provided by this package. If all of that +// fails, this will generate random values for all primitive fields and then +// recurse for all non-primitives. +// +// Not safe for cyclic or tree-like structs! +// +// obj must be a pointer. Only exported (public) fields can be set (thanks, golang :/ ) +// Intended for tests, so will panic on bad input or unimplemented fields. +func (f *Fuzzer) Fuzz(obj interface{}) { + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("needed ptr!") + } + v = v.Elem() + f.doFuzz(v, 0) +} + +// FuzzNoCustom is just like Fuzz, except that any custom fuzz function for +// obj's type will not be called and obj will not be tested for fuzz.Interface +// conformance. This applies only to obj and not other instances of obj's +// type. +// Not safe for cyclic or tree-like structs! +// obj must be a pointer. Only exported (public) fields can be set (thanks, golang :/ ) +// Intended for tests, so will panic on bad input or unimplemented fields. +func (f *Fuzzer) FuzzNoCustom(obj interface{}) { + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("needed ptr!") + } + v = v.Elem() + f.doFuzz(v, flagNoCustomFuzz) +} + +const ( + // Do not try to find a custom fuzz function. Does not apply recursively. + flagNoCustomFuzz uint64 = 1 << iota +) + +func (f *Fuzzer) doFuzz(v reflect.Value, flags uint64) { + if !v.CanSet() { + return + } + + if flags&flagNoCustomFuzz == 0 { + // Check for both pointer and non-pointer custom functions. + if v.CanAddr() && f.tryCustom(v.Addr()) { + return + } + if f.tryCustom(v) { + return + } + } + + if fn, ok := fillFuncMap[v.Kind()]; ok { + fn(v, f.r) + return + } + switch v.Kind() { + case reflect.Map: + if f.genShouldFill() { + v.Set(reflect.MakeMap(v.Type())) + n := f.genElementCount() + for i := 0; i < n; i++ { + key := reflect.New(v.Type().Key()).Elem() + f.doFuzz(key, 0) + val := reflect.New(v.Type().Elem()).Elem() + f.doFuzz(val, 0) + v.SetMapIndex(key, val) + } + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Ptr: + if f.genShouldFill() { + v.Set(reflect.New(v.Type().Elem())) + f.doFuzz(v.Elem(), 0) + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Slice: + if f.genShouldFill() { + n := f.genElementCount() + v.Set(reflect.MakeSlice(v.Type(), n, n)) + for i := 0; i < n; i++ { + f.doFuzz(v.Index(i), 0) + } + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Array: + if f.genShouldFill() { + n := v.Len() + for i := 0; i < n; i++ { + f.doFuzz(v.Index(i), 0) + } + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + f.doFuzz(v.Field(i), 0) + } + case reflect.Chan: + fallthrough + case reflect.Func: + fallthrough + case reflect.Interface: + fallthrough + default: + panic(fmt.Sprintf("Can't handle %#v", v.Interface())) + } +} + +// tryCustom searches for custom handlers, and returns true iff it finds a match +// and successfully randomizes v. +func (f *Fuzzer) tryCustom(v reflect.Value) bool { + // First: see if we have a fuzz function for it. + doCustom, ok := f.fuzzFuncs[v.Type()] + if !ok { + // Second: see if it can fuzz itself. + if v.CanInterface() { + intf := v.Interface() + if fuzzable, ok := intf.(Interface); ok { + fuzzable.Fuzz(Continue{f: f, Rand: f.r}) + return true + } + } + // Finally: see if there is a default fuzz function. + doCustom, ok = f.defaultFuzzFuncs[v.Type()] + if !ok { + return false + } + } + + switch v.Kind() { + case reflect.Ptr: + if v.IsNil() { + if !v.CanSet() { + return false + } + v.Set(reflect.New(v.Type().Elem())) + } + case reflect.Map: + if v.IsNil() { + if !v.CanSet() { + return false + } + v.Set(reflect.MakeMap(v.Type())) + } + default: + return false + } + + doCustom.Call([]reflect.Value{v, reflect.ValueOf(Continue{ + f: f, + Rand: f.r, + })}) + return true +} + +// Interface represents an object that knows how to fuzz itself. Any time we +// find a type that implements this interface we will delegate the act of +// fuzzing itself. +type Interface interface { + Fuzz(c Continue) +} + +// Continue can be passed to custom fuzzing functions to allow them to use +// the correct source of randomness and to continue fuzzing their members. +type Continue struct { + f *Fuzzer + + // For convenience, Continue implements rand.Rand via embedding. + // Use this for generating any randomness if you want your fuzzing + // to be repeatable for a given seed. + *rand.Rand +} + +// Fuzz continues fuzzing obj. obj must be a pointer. +func (c Continue) Fuzz(obj interface{}) { + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("needed ptr!") + } + v = v.Elem() + c.f.doFuzz(v, 0) +} + +// FuzzNoCustom continues fuzzing obj, except that any custom fuzz function for +// obj's type will not be called and obj will not be tested for fuzz.Interface +// conformance. This applies only to obj and not other instances of obj's +// type. +func (c Continue) FuzzNoCustom(obj interface{}) { + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("needed ptr!") + } + v = v.Elem() + c.f.doFuzz(v, flagNoCustomFuzz) +} + +// RandString makes a random string up to 20 characters long. The returned string +// may include a variety of (valid) UTF-8 encodings. +func (c Continue) RandString() string { + return randString(c.Rand) +} + +// RandUint64 makes random 64 bit numbers. +// Weirdly, rand doesn't have a function that gives you 64 random bits. +func (c Continue) RandUint64() uint64 { + return randUint64(c.Rand) +} + +// RandBool returns true or false randomly. +func (c Continue) RandBool() bool { + return randBool(c.Rand) +} + +func fuzzInt(v reflect.Value, r *rand.Rand) { + v.SetInt(int64(randUint64(r))) +} + +func fuzzUint(v reflect.Value, r *rand.Rand) { + v.SetUint(randUint64(r)) +} + +func fuzzTime(t *time.Time, c Continue) { + var sec, nsec int64 + // Allow for about 1000 years of random time values, which keeps things + // like JSON parsing reasonably happy. + sec = c.Rand.Int63n(1000 * 365 * 24 * 60 * 60) + c.Fuzz(&nsec) + *t = time.Unix(sec, nsec) +} + +var fillFuncMap = map[reflect.Kind]func(reflect.Value, *rand.Rand){ + reflect.Bool: func(v reflect.Value, r *rand.Rand) { + v.SetBool(randBool(r)) + }, + reflect.Int: fuzzInt, + reflect.Int8: fuzzInt, + reflect.Int16: fuzzInt, + reflect.Int32: fuzzInt, + reflect.Int64: fuzzInt, + reflect.Uint: fuzzUint, + reflect.Uint8: fuzzUint, + reflect.Uint16: fuzzUint, + reflect.Uint32: fuzzUint, + reflect.Uint64: fuzzUint, + reflect.Uintptr: fuzzUint, + reflect.Float32: func(v reflect.Value, r *rand.Rand) { + v.SetFloat(float64(r.Float32())) + }, + reflect.Float64: func(v reflect.Value, r *rand.Rand) { + v.SetFloat(r.Float64()) + }, + reflect.Complex64: func(v reflect.Value, r *rand.Rand) { + panic("unimplemented") + }, + reflect.Complex128: func(v reflect.Value, r *rand.Rand) { + panic("unimplemented") + }, + reflect.String: func(v reflect.Value, r *rand.Rand) { + v.SetString(randString(r)) + }, + reflect.UnsafePointer: func(v reflect.Value, r *rand.Rand) { + panic("unimplemented") + }, +} + +// randBool returns true or false randomly. +func randBool(r *rand.Rand) bool { + if r.Int()&1 == 1 { + return true + } + return false +} + +type charRange struct { + first, last rune +} + +// choose returns a random unicode character from the given range, using the +// given randomness source. +func (r *charRange) choose(rand *rand.Rand) rune { + count := int64(r.last - r.first) + return r.first + rune(rand.Int63n(count)) +} + +var unicodeRanges = []charRange{ + {' ', '~'}, // ASCII characters + {'\u00a0', '\u02af'}, // Multi-byte encoded characters + {'\u4e00', '\u9fff'}, // Common CJK (even longer encodings) +} + +// randString makes a random string up to 20 characters long. The returned string +// may include a variety of (valid) UTF-8 encodings. +func randString(r *rand.Rand) string { + n := r.Intn(20) + runes := make([]rune, n) + for i := range runes { + runes[i] = unicodeRanges[r.Intn(len(unicodeRanges))].choose(r) + } + return string(runes) +} + +// randUint64 makes random 64 bit numbers. +// Weirdly, rand doesn't have a function that gives you 64 random bits. +func randUint64(r *rand.Rand) uint64 { + return uint64(r.Uint32())<<32 | uint64(r.Uint32()) +} diff --git a/vendor/github.com/googleapis/gnostic/LICENSE b/vendor/github.com/googleapis/gnostic/LICENSE new file mode 100644 index 000000000..6b0b1270f --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.go b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.go new file mode 100644 index 000000000..0e32451a3 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.go @@ -0,0 +1,8728 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// THIS FILE IS AUTOMATICALLY GENERATED. + +package openapi_v2 + +import ( + "fmt" + "github.com/googleapis/gnostic/compiler" + "gopkg.in/yaml.v2" + "regexp" + "strings" +) + +// Version returns the package name (and OpenAPI version). +func Version() string { + return "openapi_v2" +} + +// NewAdditionalPropertiesItem creates an object of type AdditionalPropertiesItem if possible, returning an error if not. +func NewAdditionalPropertiesItem(in interface{}, context *compiler.Context) (*AdditionalPropertiesItem, error) { + errors := make([]error, 0) + x := &AdditionalPropertiesItem{} + matched := false + // Schema schema = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewSchema(m, compiler.NewContext("schema", context)) + if matchingError == nil { + x.Oneof = &AdditionalPropertiesItem_Schema{Schema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // bool boolean = 2; + boolValue, ok := in.(bool) + if ok { + x.Oneof = &AdditionalPropertiesItem_Boolean{Boolean: boolValue} + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewAny creates an object of type Any if possible, returning an error if not. +func NewAny(in interface{}, context *compiler.Context) (*Any, error) { + errors := make([]error, 0) + x := &Any{} + bytes, _ := yaml.Marshal(in) + x.Yaml = string(bytes) + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewApiKeySecurity creates an object of type ApiKeySecurity if possible, returning an error if not. +func NewApiKeySecurity(in interface{}, context *compiler.Context) (*ApiKeySecurity, error) { + errors := make([]error, 0) + x := &ApiKeySecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"in", "name", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "in", "name", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [apiKey] + if ok && !compiler.StringArrayContainsValue([]string{"apiKey"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 2; + v2 := compiler.MapValueForKey(m, "name") + if v2 != nil { + x.Name, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 3; + v3 := compiler.MapValueForKey(m, "in") + if v3 != nil { + x.In, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [header query] + if ok && !compiler.StringArrayContainsValue([]string{"header", "query"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 4; + v4 := compiler.MapValueForKey(m, "description") + if v4 != nil { + x.Description, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 5; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewBasicAuthenticationSecurity creates an object of type BasicAuthenticationSecurity if possible, returning an error if not. +func NewBasicAuthenticationSecurity(in interface{}, context *compiler.Context) (*BasicAuthenticationSecurity, error) { + errors := make([]error, 0) + x := &BasicAuthenticationSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [basic] + if ok && !compiler.StringArrayContainsValue([]string{"basic"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 3; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewBodyParameter creates an object of type BodyParameter if possible, returning an error if not. +func NewBodyParameter(in interface{}, context *compiler.Context) (*BodyParameter, error) { + errors := make([]error, 0) + x := &BodyParameter{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"in", "name", "schema"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "in", "name", "required", "schema"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 2; + v2 := compiler.MapValueForKey(m, "name") + if v2 != nil { + x.Name, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 3; + v3 := compiler.MapValueForKey(m, "in") + if v3 != nil { + x.In, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [body] + if ok && !compiler.StringArrayContainsValue([]string{"body"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool required = 4; + v4 := compiler.MapValueForKey(m, "required") + if v4 != nil { + x.Required, ok = v4.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Schema schema = 5; + v5 := compiler.MapValueForKey(m, "schema") + if v5 != nil { + var err error + x.Schema, err = NewSchema(v5, compiler.NewContext("schema", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewContact creates an object of type Contact if possible, returning an error if not. +func NewContact(in interface{}, context *compiler.Context) (*Contact, error) { + errors := make([]error, 0) + x := &Contact{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"email", "name", "url"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string url = 2; + v2 := compiler.MapValueForKey(m, "url") + if v2 != nil { + x.Url, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string email = 3; + v3 := compiler.MapValueForKey(m, "email") + if v3 != nil { + x.Email, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for email: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 4; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewDefault creates an object of type Default if possible, returning an error if not. +func NewDefault(in interface{}, context *compiler.Context) (*Default, error) { + errors := make([]error, 0) + x := &Default{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedAny additional_properties = 1; + // MAP: Any + x.AdditionalProperties = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewDefinitions creates an object of type Definitions if possible, returning an error if not. +func NewDefinitions(in interface{}, context *compiler.Context) (*Definitions, error) { + errors := make([]error, 0) + x := &Definitions{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedSchema additional_properties = 1; + // MAP: Schema + x.AdditionalProperties = make([]*NamedSchema, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedSchema{} + pair.Name = k + var err error + pair.Value, err = NewSchema(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewDocument creates an object of type Document if possible, returning an error if not. +func NewDocument(in interface{}, context *compiler.Context) (*Document, error) { + errors := make([]error, 0) + x := &Document{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"info", "paths", "swagger"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"basePath", "consumes", "definitions", "externalDocs", "host", "info", "parameters", "paths", "produces", "responses", "schemes", "security", "securityDefinitions", "swagger", "tags"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string swagger = 1; + v1 := compiler.MapValueForKey(m, "swagger") + if v1 != nil { + x.Swagger, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for swagger: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [2.0] + if ok && !compiler.StringArrayContainsValue([]string{"2.0"}, x.Swagger) { + message := fmt.Sprintf("has unexpected value for swagger: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Info info = 2; + v2 := compiler.MapValueForKey(m, "info") + if v2 != nil { + var err error + x.Info, err = NewInfo(v2, compiler.NewContext("info", context)) + if err != nil { + errors = append(errors, err) + } + } + // string host = 3; + v3 := compiler.MapValueForKey(m, "host") + if v3 != nil { + x.Host, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for host: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string base_path = 4; + v4 := compiler.MapValueForKey(m, "basePath") + if v4 != nil { + x.BasePath, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for basePath: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string schemes = 5; + v5 := compiler.MapValueForKey(m, "schemes") + if v5 != nil { + v, ok := v5.([]interface{}) + if ok { + x.Schemes = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for schemes: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [http https ws wss] + if ok && !compiler.StringArrayContainsValues([]string{"http", "https", "ws", "wss"}, x.Schemes) { + message := fmt.Sprintf("has unexpected value for schemes: %+v", v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string consumes = 6; + v6 := compiler.MapValueForKey(m, "consumes") + if v6 != nil { + v, ok := v6.([]interface{}) + if ok { + x.Consumes = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for consumes: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string produces = 7; + v7 := compiler.MapValueForKey(m, "produces") + if v7 != nil { + v, ok := v7.([]interface{}) + if ok { + x.Produces = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for produces: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Paths paths = 8; + v8 := compiler.MapValueForKey(m, "paths") + if v8 != nil { + var err error + x.Paths, err = NewPaths(v8, compiler.NewContext("paths", context)) + if err != nil { + errors = append(errors, err) + } + } + // Definitions definitions = 9; + v9 := compiler.MapValueForKey(m, "definitions") + if v9 != nil { + var err error + x.Definitions, err = NewDefinitions(v9, compiler.NewContext("definitions", context)) + if err != nil { + errors = append(errors, err) + } + } + // ParameterDefinitions parameters = 10; + v10 := compiler.MapValueForKey(m, "parameters") + if v10 != nil { + var err error + x.Parameters, err = NewParameterDefinitions(v10, compiler.NewContext("parameters", context)) + if err != nil { + errors = append(errors, err) + } + } + // ResponseDefinitions responses = 11; + v11 := compiler.MapValueForKey(m, "responses") + if v11 != nil { + var err error + x.Responses, err = NewResponseDefinitions(v11, compiler.NewContext("responses", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated SecurityRequirement security = 12; + v12 := compiler.MapValueForKey(m, "security") + if v12 != nil { + // repeated SecurityRequirement + x.Security = make([]*SecurityRequirement, 0) + a, ok := v12.([]interface{}) + if ok { + for _, item := range a { + y, err := NewSecurityRequirement(item, compiler.NewContext("security", context)) + if err != nil { + errors = append(errors, err) + } + x.Security = append(x.Security, y) + } + } + } + // SecurityDefinitions security_definitions = 13; + v13 := compiler.MapValueForKey(m, "securityDefinitions") + if v13 != nil { + var err error + x.SecurityDefinitions, err = NewSecurityDefinitions(v13, compiler.NewContext("securityDefinitions", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated Tag tags = 14; + v14 := compiler.MapValueForKey(m, "tags") + if v14 != nil { + // repeated Tag + x.Tags = make([]*Tag, 0) + a, ok := v14.([]interface{}) + if ok { + for _, item := range a { + y, err := NewTag(item, compiler.NewContext("tags", context)) + if err != nil { + errors = append(errors, err) + } + x.Tags = append(x.Tags, y) + } + } + } + // ExternalDocs external_docs = 15; + v15 := compiler.MapValueForKey(m, "externalDocs") + if v15 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v15, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 16; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewExamples creates an object of type Examples if possible, returning an error if not. +func NewExamples(in interface{}, context *compiler.Context) (*Examples, error) { + errors := make([]error, 0) + x := &Examples{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedAny additional_properties = 1; + // MAP: Any + x.AdditionalProperties = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewExternalDocs creates an object of type ExternalDocs if possible, returning an error if not. +func NewExternalDocs(in interface{}, context *compiler.Context) (*ExternalDocs, error) { + errors := make([]error, 0) + x := &ExternalDocs{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"url"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "url"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string url = 2; + v2 := compiler.MapValueForKey(m, "url") + if v2 != nil { + x.Url, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 3; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewFileSchema creates an object of type FileSchema if possible, returning an error if not. +func NewFileSchema(in interface{}, context *compiler.Context) (*FileSchema, error) { + errors := make([]error, 0) + x := &FileSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"default", "description", "example", "externalDocs", "format", "readOnly", "required", "title", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string format = 1; + v1 := compiler.MapValueForKey(m, "format") + if v1 != nil { + x.Format, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string title = 2; + v2 := compiler.MapValueForKey(m, "title") + if v2 != nil { + x.Title, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for title: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 4; + v4 := compiler.MapValueForKey(m, "default") + if v4 != nil { + var err error + x.Default, err = NewAny(v4, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated string required = 5; + v5 := compiler.MapValueForKey(m, "required") + if v5 != nil { + v, ok := v5.([]interface{}) + if ok { + x.Required = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 6; + v6 := compiler.MapValueForKey(m, "type") + if v6 != nil { + x.Type, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [file] + if ok && !compiler.StringArrayContainsValue([]string{"file"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool read_only = 7; + v7 := compiler.MapValueForKey(m, "readOnly") + if v7 != nil { + x.ReadOnly, ok = v7.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for readOnly: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ExternalDocs external_docs = 8; + v8 := compiler.MapValueForKey(m, "externalDocs") + if v8 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v8, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // Any example = 9; + v9 := compiler.MapValueForKey(m, "example") + if v9 != nil { + var err error + x.Example, err = NewAny(v9, compiler.NewContext("example", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 10; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewFormDataParameterSubSchema creates an object of type FormDataParameterSubSchema if possible, returning an error if not. +func NewFormDataParameterSubSchema(in interface{}, context *compiler.Context) (*FormDataParameterSubSchema, error) { + errors := make([]error, 0) + x := &FormDataParameterSubSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"allowEmptyValue", "collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "in", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "name", "pattern", "required", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // bool required = 1; + v1 := compiler.MapValueForKey(m, "required") + if v1 != nil { + x.Required, ok = v1.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 2; + v2 := compiler.MapValueForKey(m, "in") + if v2 != nil { + x.In, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [formData] + if ok && !compiler.StringArrayContainsValue([]string{"formData"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 4; + v4 := compiler.MapValueForKey(m, "name") + if v4 != nil { + x.Name, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool allow_empty_value = 5; + v5 := compiler.MapValueForKey(m, "allowEmptyValue") + if v5 != nil { + x.AllowEmptyValue, ok = v5.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for allowEmptyValue: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 6; + v6 := compiler.MapValueForKey(m, "type") + if v6 != nil { + x.Type, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number boolean integer array file] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "boolean", "integer", "array", "file"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 7; + v7 := compiler.MapValueForKey(m, "format") + if v7 != nil { + x.Format, ok = v7.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 8; + v8 := compiler.MapValueForKey(m, "items") + if v8 != nil { + var err error + x.Items, err = NewPrimitivesItems(v8, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 9; + v9 := compiler.MapValueForKey(m, "collectionFormat") + if v9 != nil { + x.CollectionFormat, ok = v9.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes multi] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes", "multi"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 10; + v10 := compiler.MapValueForKey(m, "default") + if v10 != nil { + var err error + x.Default, err = NewAny(v10, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 11; + v11 := compiler.MapValueForKey(m, "maximum") + if v11 != nil { + switch v11 := v11.(type) { + case float64: + x.Maximum = v11 + case float32: + x.Maximum = float64(v11) + case uint64: + x.Maximum = float64(v11) + case uint32: + x.Maximum = float64(v11) + case int64: + x.Maximum = float64(v11) + case int32: + x.Maximum = float64(v11) + case int: + x.Maximum = float64(v11) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 12; + v12 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v12 != nil { + x.ExclusiveMaximum, ok = v12.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 13; + v13 := compiler.MapValueForKey(m, "minimum") + if v13 != nil { + switch v13 := v13.(type) { + case float64: + x.Minimum = v13 + case float32: + x.Minimum = float64(v13) + case uint64: + x.Minimum = float64(v13) + case uint32: + x.Minimum = float64(v13) + case int64: + x.Minimum = float64(v13) + case int32: + x.Minimum = float64(v13) + case int: + x.Minimum = float64(v13) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 14; + v14 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v14 != nil { + x.ExclusiveMinimum, ok = v14.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 15; + v15 := compiler.MapValueForKey(m, "maxLength") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 16; + v16 := compiler.MapValueForKey(m, "minLength") + if v16 != nil { + t, ok := v16.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 17; + v17 := compiler.MapValueForKey(m, "pattern") + if v17 != nil { + x.Pattern, ok = v17.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 18; + v18 := compiler.MapValueForKey(m, "maxItems") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 19; + v19 := compiler.MapValueForKey(m, "minItems") + if v19 != nil { + t, ok := v19.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 20; + v20 := compiler.MapValueForKey(m, "uniqueItems") + if v20 != nil { + x.UniqueItems, ok = v20.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v20, v20) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 21; + v21 := compiler.MapValueForKey(m, "enum") + if v21 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v21.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 22; + v22 := compiler.MapValueForKey(m, "multipleOf") + if v22 != nil { + switch v22 := v22.(type) { + case float64: + x.MultipleOf = v22 + case float32: + x.MultipleOf = float64(v22) + case uint64: + x.MultipleOf = float64(v22) + case uint32: + x.MultipleOf = float64(v22) + case int64: + x.MultipleOf = float64(v22) + case int32: + x.MultipleOf = float64(v22) + case int: + x.MultipleOf = float64(v22) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v22, v22) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 23; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewHeader creates an object of type Header if possible, returning an error if not. +func NewHeader(in interface{}, context *compiler.Context) (*Header, error) { + errors := make([]error, 0) + x := &Header{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "pattern", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number integer boolean array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "integer", "boolean", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 2; + v2 := compiler.MapValueForKey(m, "format") + if v2 != nil { + x.Format, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 3; + v3 := compiler.MapValueForKey(m, "items") + if v3 != nil { + var err error + x.Items, err = NewPrimitivesItems(v3, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 4; + v4 := compiler.MapValueForKey(m, "collectionFormat") + if v4 != nil { + x.CollectionFormat, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 5; + v5 := compiler.MapValueForKey(m, "default") + if v5 != nil { + var err error + x.Default, err = NewAny(v5, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 6; + v6 := compiler.MapValueForKey(m, "maximum") + if v6 != nil { + switch v6 := v6.(type) { + case float64: + x.Maximum = v6 + case float32: + x.Maximum = float64(v6) + case uint64: + x.Maximum = float64(v6) + case uint32: + x.Maximum = float64(v6) + case int64: + x.Maximum = float64(v6) + case int32: + x.Maximum = float64(v6) + case int: + x.Maximum = float64(v6) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 7; + v7 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v7 != nil { + x.ExclusiveMaximum, ok = v7.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 8; + v8 := compiler.MapValueForKey(m, "minimum") + if v8 != nil { + switch v8 := v8.(type) { + case float64: + x.Minimum = v8 + case float32: + x.Minimum = float64(v8) + case uint64: + x.Minimum = float64(v8) + case uint32: + x.Minimum = float64(v8) + case int64: + x.Minimum = float64(v8) + case int32: + x.Minimum = float64(v8) + case int: + x.Minimum = float64(v8) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 9; + v9 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v9 != nil { + x.ExclusiveMinimum, ok = v9.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 10; + v10 := compiler.MapValueForKey(m, "maxLength") + if v10 != nil { + t, ok := v10.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 11; + v11 := compiler.MapValueForKey(m, "minLength") + if v11 != nil { + t, ok := v11.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 12; + v12 := compiler.MapValueForKey(m, "pattern") + if v12 != nil { + x.Pattern, ok = v12.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 13; + v13 := compiler.MapValueForKey(m, "maxItems") + if v13 != nil { + t, ok := v13.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 14; + v14 := compiler.MapValueForKey(m, "minItems") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 15; + v15 := compiler.MapValueForKey(m, "uniqueItems") + if v15 != nil { + x.UniqueItems, ok = v15.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 16; + v16 := compiler.MapValueForKey(m, "enum") + if v16 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v16.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 17; + v17 := compiler.MapValueForKey(m, "multipleOf") + if v17 != nil { + switch v17 := v17.(type) { + case float64: + x.MultipleOf = v17 + case float32: + x.MultipleOf = float64(v17) + case uint64: + x.MultipleOf = float64(v17) + case uint32: + x.MultipleOf = float64(v17) + case int64: + x.MultipleOf = float64(v17) + case int32: + x.MultipleOf = float64(v17) + case int: + x.MultipleOf = float64(v17) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 18; + v18 := compiler.MapValueForKey(m, "description") + if v18 != nil { + x.Description, ok = v18.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 19; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewHeaderParameterSubSchema creates an object of type HeaderParameterSubSchema if possible, returning an error if not. +func NewHeaderParameterSubSchema(in interface{}, context *compiler.Context) (*HeaderParameterSubSchema, error) { + errors := make([]error, 0) + x := &HeaderParameterSubSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "in", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "name", "pattern", "required", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // bool required = 1; + v1 := compiler.MapValueForKey(m, "required") + if v1 != nil { + x.Required, ok = v1.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 2; + v2 := compiler.MapValueForKey(m, "in") + if v2 != nil { + x.In, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [header] + if ok && !compiler.StringArrayContainsValue([]string{"header"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 4; + v4 := compiler.MapValueForKey(m, "name") + if v4 != nil { + x.Name, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 5; + v5 := compiler.MapValueForKey(m, "type") + if v5 != nil { + x.Type, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number boolean integer array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "boolean", "integer", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 6; + v6 := compiler.MapValueForKey(m, "format") + if v6 != nil { + x.Format, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 7; + v7 := compiler.MapValueForKey(m, "items") + if v7 != nil { + var err error + x.Items, err = NewPrimitivesItems(v7, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 8; + v8 := compiler.MapValueForKey(m, "collectionFormat") + if v8 != nil { + x.CollectionFormat, ok = v8.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 9; + v9 := compiler.MapValueForKey(m, "default") + if v9 != nil { + var err error + x.Default, err = NewAny(v9, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 10; + v10 := compiler.MapValueForKey(m, "maximum") + if v10 != nil { + switch v10 := v10.(type) { + case float64: + x.Maximum = v10 + case float32: + x.Maximum = float64(v10) + case uint64: + x.Maximum = float64(v10) + case uint32: + x.Maximum = float64(v10) + case int64: + x.Maximum = float64(v10) + case int32: + x.Maximum = float64(v10) + case int: + x.Maximum = float64(v10) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 11; + v11 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v11 != nil { + x.ExclusiveMaximum, ok = v11.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 12; + v12 := compiler.MapValueForKey(m, "minimum") + if v12 != nil { + switch v12 := v12.(type) { + case float64: + x.Minimum = v12 + case float32: + x.Minimum = float64(v12) + case uint64: + x.Minimum = float64(v12) + case uint32: + x.Minimum = float64(v12) + case int64: + x.Minimum = float64(v12) + case int32: + x.Minimum = float64(v12) + case int: + x.Minimum = float64(v12) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 13; + v13 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v13 != nil { + x.ExclusiveMinimum, ok = v13.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 14; + v14 := compiler.MapValueForKey(m, "maxLength") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 15; + v15 := compiler.MapValueForKey(m, "minLength") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 16; + v16 := compiler.MapValueForKey(m, "pattern") + if v16 != nil { + x.Pattern, ok = v16.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 17; + v17 := compiler.MapValueForKey(m, "maxItems") + if v17 != nil { + t, ok := v17.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 18; + v18 := compiler.MapValueForKey(m, "minItems") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 19; + v19 := compiler.MapValueForKey(m, "uniqueItems") + if v19 != nil { + x.UniqueItems, ok = v19.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 20; + v20 := compiler.MapValueForKey(m, "enum") + if v20 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v20.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 21; + v21 := compiler.MapValueForKey(m, "multipleOf") + if v21 != nil { + switch v21 := v21.(type) { + case float64: + x.MultipleOf = v21 + case float32: + x.MultipleOf = float64(v21) + case uint64: + x.MultipleOf = float64(v21) + case uint32: + x.MultipleOf = float64(v21) + case int64: + x.MultipleOf = float64(v21) + case int32: + x.MultipleOf = float64(v21) + case int: + x.MultipleOf = float64(v21) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v21, v21) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 22; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewHeaders creates an object of type Headers if possible, returning an error if not. +func NewHeaders(in interface{}, context *compiler.Context) (*Headers, error) { + errors := make([]error, 0) + x := &Headers{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedHeader additional_properties = 1; + // MAP: Header + x.AdditionalProperties = make([]*NamedHeader, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedHeader{} + pair.Name = k + var err error + pair.Value, err = NewHeader(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewInfo creates an object of type Info if possible, returning an error if not. +func NewInfo(in interface{}, context *compiler.Context) (*Info, error) { + errors := make([]error, 0) + x := &Info{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"title", "version"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"contact", "description", "license", "termsOfService", "title", "version"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string title = 1; + v1 := compiler.MapValueForKey(m, "title") + if v1 != nil { + x.Title, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for title: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string version = 2; + v2 := compiler.MapValueForKey(m, "version") + if v2 != nil { + x.Version, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for version: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string terms_of_service = 4; + v4 := compiler.MapValueForKey(m, "termsOfService") + if v4 != nil { + x.TermsOfService, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for termsOfService: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Contact contact = 5; + v5 := compiler.MapValueForKey(m, "contact") + if v5 != nil { + var err error + x.Contact, err = NewContact(v5, compiler.NewContext("contact", context)) + if err != nil { + errors = append(errors, err) + } + } + // License license = 6; + v6 := compiler.MapValueForKey(m, "license") + if v6 != nil { + var err error + x.License, err = NewLicense(v6, compiler.NewContext("license", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 7; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewItemsItem creates an object of type ItemsItem if possible, returning an error if not. +func NewItemsItem(in interface{}, context *compiler.Context) (*ItemsItem, error) { + errors := make([]error, 0) + x := &ItemsItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value for item array: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + x.Schema = make([]*Schema, 0) + y, err := NewSchema(m, compiler.NewContext("", context)) + if err != nil { + return nil, err + } + x.Schema = append(x.Schema, y) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewJsonReference creates an object of type JsonReference if possible, returning an error if not. +func NewJsonReference(in interface{}, context *compiler.Context) (*JsonReference, error) { + errors := make([]error, 0) + x := &JsonReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"$ref"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"$ref", "description"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string _ref = 1; + v1 := compiler.MapValueForKey(m, "$ref") + if v1 != nil { + x.XRef, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for $ref: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewLicense creates an object of type License if possible, returning an error if not. +func NewLicense(in interface{}, context *compiler.Context) (*License, error) { + errors := make([]error, 0) + x := &License{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"name"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"name", "url"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string url = 2; + v2 := compiler.MapValueForKey(m, "url") + if v2 != nil { + x.Url, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 3; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedAny creates an object of type NamedAny if possible, returning an error if not. +func NewNamedAny(in interface{}, context *compiler.Context) (*NamedAny, error) { + errors := make([]error, 0) + x := &NamedAny{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewAny(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedHeader creates an object of type NamedHeader if possible, returning an error if not. +func NewNamedHeader(in interface{}, context *compiler.Context) (*NamedHeader, error) { + errors := make([]error, 0) + x := &NamedHeader{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Header value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewHeader(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedParameter creates an object of type NamedParameter if possible, returning an error if not. +func NewNamedParameter(in interface{}, context *compiler.Context) (*NamedParameter, error) { + errors := make([]error, 0) + x := &NamedParameter{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Parameter value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewParameter(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedPathItem creates an object of type NamedPathItem if possible, returning an error if not. +func NewNamedPathItem(in interface{}, context *compiler.Context) (*NamedPathItem, error) { + errors := make([]error, 0) + x := &NamedPathItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PathItem value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewPathItem(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedResponse creates an object of type NamedResponse if possible, returning an error if not. +func NewNamedResponse(in interface{}, context *compiler.Context) (*NamedResponse, error) { + errors := make([]error, 0) + x := &NamedResponse{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Response value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewResponse(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedResponseValue creates an object of type NamedResponseValue if possible, returning an error if not. +func NewNamedResponseValue(in interface{}, context *compiler.Context) (*NamedResponseValue, error) { + errors := make([]error, 0) + x := &NamedResponseValue{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ResponseValue value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewResponseValue(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedSchema creates an object of type NamedSchema if possible, returning an error if not. +func NewNamedSchema(in interface{}, context *compiler.Context) (*NamedSchema, error) { + errors := make([]error, 0) + x := &NamedSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Schema value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewSchema(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedSecurityDefinitionsItem creates an object of type NamedSecurityDefinitionsItem if possible, returning an error if not. +func NewNamedSecurityDefinitionsItem(in interface{}, context *compiler.Context) (*NamedSecurityDefinitionsItem, error) { + errors := make([]error, 0) + x := &NamedSecurityDefinitionsItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // SecurityDefinitionsItem value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewSecurityDefinitionsItem(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedString creates an object of type NamedString if possible, returning an error if not. +func NewNamedString(in interface{}, context *compiler.Context) (*NamedString, error) { + errors := make([]error, 0) + x := &NamedString{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + x.Value, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for value: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedStringArray creates an object of type NamedStringArray if possible, returning an error if not. +func NewNamedStringArray(in interface{}, context *compiler.Context) (*NamedStringArray, error) { + errors := make([]error, 0) + x := &NamedStringArray{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // StringArray value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewStringArray(v2, compiler.NewContext("value", context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNonBodyParameter creates an object of type NonBodyParameter if possible, returning an error if not. +func NewNonBodyParameter(in interface{}, context *compiler.Context) (*NonBodyParameter, error) { + errors := make([]error, 0) + x := &NonBodyParameter{} + matched := false + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"in", "name", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // HeaderParameterSubSchema header_parameter_sub_schema = 1; + { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewHeaderParameterSubSchema(m, compiler.NewContext("headerParameterSubSchema", context)) + if matchingError == nil { + x.Oneof = &NonBodyParameter_HeaderParameterSubSchema{HeaderParameterSubSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + // FormDataParameterSubSchema form_data_parameter_sub_schema = 2; + { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewFormDataParameterSubSchema(m, compiler.NewContext("formDataParameterSubSchema", context)) + if matchingError == nil { + x.Oneof = &NonBodyParameter_FormDataParameterSubSchema{FormDataParameterSubSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + // QueryParameterSubSchema query_parameter_sub_schema = 3; + { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewQueryParameterSubSchema(m, compiler.NewContext("queryParameterSubSchema", context)) + if matchingError == nil { + x.Oneof = &NonBodyParameter_QueryParameterSubSchema{QueryParameterSubSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + // PathParameterSubSchema path_parameter_sub_schema = 4; + { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewPathParameterSubSchema(m, compiler.NewContext("pathParameterSubSchema", context)) + if matchingError == nil { + x.Oneof = &NonBodyParameter_PathParameterSubSchema{PathParameterSubSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2AccessCodeSecurity creates an object of type Oauth2AccessCodeSecurity if possible, returning an error if not. +func NewOauth2AccessCodeSecurity(in interface{}, context *compiler.Context) (*Oauth2AccessCodeSecurity, error) { + errors := make([]error, 0) + x := &Oauth2AccessCodeSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"authorizationUrl", "flow", "tokenUrl", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"authorizationUrl", "description", "flow", "scopes", "tokenUrl", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [oauth2] + if ok && !compiler.StringArrayContainsValue([]string{"oauth2"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string flow = 2; + v2 := compiler.MapValueForKey(m, "flow") + if v2 != nil { + x.Flow, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [accessCode] + if ok && !compiler.StringArrayContainsValue([]string{"accessCode"}, x.Flow) { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Oauth2Scopes scopes = 3; + v3 := compiler.MapValueForKey(m, "scopes") + if v3 != nil { + var err error + x.Scopes, err = NewOauth2Scopes(v3, compiler.NewContext("scopes", context)) + if err != nil { + errors = append(errors, err) + } + } + // string authorization_url = 4; + v4 := compiler.MapValueForKey(m, "authorizationUrl") + if v4 != nil { + x.AuthorizationUrl, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for authorizationUrl: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string token_url = 5; + v5 := compiler.MapValueForKey(m, "tokenUrl") + if v5 != nil { + x.TokenUrl, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for tokenUrl: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 6; + v6 := compiler.MapValueForKey(m, "description") + if v6 != nil { + x.Description, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 7; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2ApplicationSecurity creates an object of type Oauth2ApplicationSecurity if possible, returning an error if not. +func NewOauth2ApplicationSecurity(in interface{}, context *compiler.Context) (*Oauth2ApplicationSecurity, error) { + errors := make([]error, 0) + x := &Oauth2ApplicationSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"flow", "tokenUrl", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "flow", "scopes", "tokenUrl", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [oauth2] + if ok && !compiler.StringArrayContainsValue([]string{"oauth2"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string flow = 2; + v2 := compiler.MapValueForKey(m, "flow") + if v2 != nil { + x.Flow, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [application] + if ok && !compiler.StringArrayContainsValue([]string{"application"}, x.Flow) { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Oauth2Scopes scopes = 3; + v3 := compiler.MapValueForKey(m, "scopes") + if v3 != nil { + var err error + x.Scopes, err = NewOauth2Scopes(v3, compiler.NewContext("scopes", context)) + if err != nil { + errors = append(errors, err) + } + } + // string token_url = 4; + v4 := compiler.MapValueForKey(m, "tokenUrl") + if v4 != nil { + x.TokenUrl, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for tokenUrl: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 5; + v5 := compiler.MapValueForKey(m, "description") + if v5 != nil { + x.Description, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2ImplicitSecurity creates an object of type Oauth2ImplicitSecurity if possible, returning an error if not. +func NewOauth2ImplicitSecurity(in interface{}, context *compiler.Context) (*Oauth2ImplicitSecurity, error) { + errors := make([]error, 0) + x := &Oauth2ImplicitSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"authorizationUrl", "flow", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"authorizationUrl", "description", "flow", "scopes", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [oauth2] + if ok && !compiler.StringArrayContainsValue([]string{"oauth2"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string flow = 2; + v2 := compiler.MapValueForKey(m, "flow") + if v2 != nil { + x.Flow, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [implicit] + if ok && !compiler.StringArrayContainsValue([]string{"implicit"}, x.Flow) { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Oauth2Scopes scopes = 3; + v3 := compiler.MapValueForKey(m, "scopes") + if v3 != nil { + var err error + x.Scopes, err = NewOauth2Scopes(v3, compiler.NewContext("scopes", context)) + if err != nil { + errors = append(errors, err) + } + } + // string authorization_url = 4; + v4 := compiler.MapValueForKey(m, "authorizationUrl") + if v4 != nil { + x.AuthorizationUrl, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for authorizationUrl: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 5; + v5 := compiler.MapValueForKey(m, "description") + if v5 != nil { + x.Description, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2PasswordSecurity creates an object of type Oauth2PasswordSecurity if possible, returning an error if not. +func NewOauth2PasswordSecurity(in interface{}, context *compiler.Context) (*Oauth2PasswordSecurity, error) { + errors := make([]error, 0) + x := &Oauth2PasswordSecurity{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"flow", "tokenUrl", "type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "flow", "scopes", "tokenUrl", "type"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [oauth2] + if ok && !compiler.StringArrayContainsValue([]string{"oauth2"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string flow = 2; + v2 := compiler.MapValueForKey(m, "flow") + if v2 != nil { + x.Flow, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [password] + if ok && !compiler.StringArrayContainsValue([]string{"password"}, x.Flow) { + message := fmt.Sprintf("has unexpected value for flow: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Oauth2Scopes scopes = 3; + v3 := compiler.MapValueForKey(m, "scopes") + if v3 != nil { + var err error + x.Scopes, err = NewOauth2Scopes(v3, compiler.NewContext("scopes", context)) + if err != nil { + errors = append(errors, err) + } + } + // string token_url = 4; + v4 := compiler.MapValueForKey(m, "tokenUrl") + if v4 != nil { + x.TokenUrl, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for tokenUrl: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 5; + v5 := compiler.MapValueForKey(m, "description") + if v5 != nil { + x.Description, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauth2Scopes creates an object of type Oauth2Scopes if possible, returning an error if not. +func NewOauth2Scopes(in interface{}, context *compiler.Context) (*Oauth2Scopes, error) { + errors := make([]error, 0) + x := &Oauth2Scopes{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedString additional_properties = 1; + // MAP: string + x.AdditionalProperties = make([]*NamedString, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedString{} + pair.Name = k + pair.Value = v.(string) + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOperation creates an object of type Operation if possible, returning an error if not. +func NewOperation(in interface{}, context *compiler.Context) (*Operation, error) { + errors := make([]error, 0) + x := &Operation{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"responses"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"consumes", "deprecated", "description", "externalDocs", "operationId", "parameters", "produces", "responses", "schemes", "security", "summary", "tags"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated string tags = 1; + v1 := compiler.MapValueForKey(m, "tags") + if v1 != nil { + v, ok := v1.([]interface{}) + if ok { + x.Tags = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for tags: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string summary = 2; + v2 := compiler.MapValueForKey(m, "summary") + if v2 != nil { + x.Summary, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for summary: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ExternalDocs external_docs = 4; + v4 := compiler.MapValueForKey(m, "externalDocs") + if v4 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v4, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // string operation_id = 5; + v5 := compiler.MapValueForKey(m, "operationId") + if v5 != nil { + x.OperationId, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for operationId: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string produces = 6; + v6 := compiler.MapValueForKey(m, "produces") + if v6 != nil { + v, ok := v6.([]interface{}) + if ok { + x.Produces = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for produces: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string consumes = 7; + v7 := compiler.MapValueForKey(m, "consumes") + if v7 != nil { + v, ok := v7.([]interface{}) + if ok { + x.Consumes = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for consumes: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated ParametersItem parameters = 8; + v8 := compiler.MapValueForKey(m, "parameters") + if v8 != nil { + // repeated ParametersItem + x.Parameters = make([]*ParametersItem, 0) + a, ok := v8.([]interface{}) + if ok { + for _, item := range a { + y, err := NewParametersItem(item, compiler.NewContext("parameters", context)) + if err != nil { + errors = append(errors, err) + } + x.Parameters = append(x.Parameters, y) + } + } + } + // Responses responses = 9; + v9 := compiler.MapValueForKey(m, "responses") + if v9 != nil { + var err error + x.Responses, err = NewResponses(v9, compiler.NewContext("responses", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated string schemes = 10; + v10 := compiler.MapValueForKey(m, "schemes") + if v10 != nil { + v, ok := v10.([]interface{}) + if ok { + x.Schemes = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for schemes: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [http https ws wss] + if ok && !compiler.StringArrayContainsValues([]string{"http", "https", "ws", "wss"}, x.Schemes) { + message := fmt.Sprintf("has unexpected value for schemes: %+v", v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool deprecated = 11; + v11 := compiler.MapValueForKey(m, "deprecated") + if v11 != nil { + x.Deprecated, ok = v11.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for deprecated: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated SecurityRequirement security = 12; + v12 := compiler.MapValueForKey(m, "security") + if v12 != nil { + // repeated SecurityRequirement + x.Security = make([]*SecurityRequirement, 0) + a, ok := v12.([]interface{}) + if ok { + for _, item := range a { + y, err := NewSecurityRequirement(item, compiler.NewContext("security", context)) + if err != nil { + errors = append(errors, err) + } + x.Security = append(x.Security, y) + } + } + } + // repeated NamedAny vendor_extension = 13; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewParameter creates an object of type Parameter if possible, returning an error if not. +func NewParameter(in interface{}, context *compiler.Context) (*Parameter, error) { + errors := make([]error, 0) + x := &Parameter{} + matched := false + // BodyParameter body_parameter = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewBodyParameter(m, compiler.NewContext("bodyParameter", context)) + if matchingError == nil { + x.Oneof = &Parameter_BodyParameter{BodyParameter: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // NonBodyParameter non_body_parameter = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewNonBodyParameter(m, compiler.NewContext("nonBodyParameter", context)) + if matchingError == nil { + x.Oneof = &Parameter_NonBodyParameter{NonBodyParameter: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewParameterDefinitions creates an object of type ParameterDefinitions if possible, returning an error if not. +func NewParameterDefinitions(in interface{}, context *compiler.Context) (*ParameterDefinitions, error) { + errors := make([]error, 0) + x := &ParameterDefinitions{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedParameter additional_properties = 1; + // MAP: Parameter + x.AdditionalProperties = make([]*NamedParameter, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedParameter{} + pair.Name = k + var err error + pair.Value, err = NewParameter(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewParametersItem creates an object of type ParametersItem if possible, returning an error if not. +func NewParametersItem(in interface{}, context *compiler.Context) (*ParametersItem, error) { + errors := make([]error, 0) + x := &ParametersItem{} + matched := false + // Parameter parameter = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewParameter(m, compiler.NewContext("parameter", context)) + if matchingError == nil { + x.Oneof = &ParametersItem_Parameter{Parameter: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // JsonReference json_reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewJsonReference(m, compiler.NewContext("jsonReference", context)) + if matchingError == nil { + x.Oneof = &ParametersItem_JsonReference{JsonReference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPathItem creates an object of type PathItem if possible, returning an error if not. +func NewPathItem(in interface{}, context *compiler.Context) (*PathItem, error) { + errors := make([]error, 0) + x := &PathItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"$ref", "delete", "get", "head", "options", "parameters", "patch", "post", "put"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string _ref = 1; + v1 := compiler.MapValueForKey(m, "$ref") + if v1 != nil { + x.XRef, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for $ref: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Operation get = 2; + v2 := compiler.MapValueForKey(m, "get") + if v2 != nil { + var err error + x.Get, err = NewOperation(v2, compiler.NewContext("get", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation put = 3; + v3 := compiler.MapValueForKey(m, "put") + if v3 != nil { + var err error + x.Put, err = NewOperation(v3, compiler.NewContext("put", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation post = 4; + v4 := compiler.MapValueForKey(m, "post") + if v4 != nil { + var err error + x.Post, err = NewOperation(v4, compiler.NewContext("post", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation delete = 5; + v5 := compiler.MapValueForKey(m, "delete") + if v5 != nil { + var err error + x.Delete, err = NewOperation(v5, compiler.NewContext("delete", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation options = 6; + v6 := compiler.MapValueForKey(m, "options") + if v6 != nil { + var err error + x.Options, err = NewOperation(v6, compiler.NewContext("options", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation head = 7; + v7 := compiler.MapValueForKey(m, "head") + if v7 != nil { + var err error + x.Head, err = NewOperation(v7, compiler.NewContext("head", context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation patch = 8; + v8 := compiler.MapValueForKey(m, "patch") + if v8 != nil { + var err error + x.Patch, err = NewOperation(v8, compiler.NewContext("patch", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated ParametersItem parameters = 9; + v9 := compiler.MapValueForKey(m, "parameters") + if v9 != nil { + // repeated ParametersItem + x.Parameters = make([]*ParametersItem, 0) + a, ok := v9.([]interface{}) + if ok { + for _, item := range a { + y, err := NewParametersItem(item, compiler.NewContext("parameters", context)) + if err != nil { + errors = append(errors, err) + } + x.Parameters = append(x.Parameters, y) + } + } + } + // repeated NamedAny vendor_extension = 10; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPathParameterSubSchema creates an object of type PathParameterSubSchema if possible, returning an error if not. +func NewPathParameterSubSchema(in interface{}, context *compiler.Context) (*PathParameterSubSchema, error) { + errors := make([]error, 0) + x := &PathParameterSubSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"required"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "in", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "name", "pattern", "required", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // bool required = 1; + v1 := compiler.MapValueForKey(m, "required") + if v1 != nil { + x.Required, ok = v1.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 2; + v2 := compiler.MapValueForKey(m, "in") + if v2 != nil { + x.In, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [path] + if ok && !compiler.StringArrayContainsValue([]string{"path"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 4; + v4 := compiler.MapValueForKey(m, "name") + if v4 != nil { + x.Name, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 5; + v5 := compiler.MapValueForKey(m, "type") + if v5 != nil { + x.Type, ok = v5.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number boolean integer array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "boolean", "integer", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 6; + v6 := compiler.MapValueForKey(m, "format") + if v6 != nil { + x.Format, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 7; + v7 := compiler.MapValueForKey(m, "items") + if v7 != nil { + var err error + x.Items, err = NewPrimitivesItems(v7, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 8; + v8 := compiler.MapValueForKey(m, "collectionFormat") + if v8 != nil { + x.CollectionFormat, ok = v8.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 9; + v9 := compiler.MapValueForKey(m, "default") + if v9 != nil { + var err error + x.Default, err = NewAny(v9, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 10; + v10 := compiler.MapValueForKey(m, "maximum") + if v10 != nil { + switch v10 := v10.(type) { + case float64: + x.Maximum = v10 + case float32: + x.Maximum = float64(v10) + case uint64: + x.Maximum = float64(v10) + case uint32: + x.Maximum = float64(v10) + case int64: + x.Maximum = float64(v10) + case int32: + x.Maximum = float64(v10) + case int: + x.Maximum = float64(v10) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 11; + v11 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v11 != nil { + x.ExclusiveMaximum, ok = v11.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 12; + v12 := compiler.MapValueForKey(m, "minimum") + if v12 != nil { + switch v12 := v12.(type) { + case float64: + x.Minimum = v12 + case float32: + x.Minimum = float64(v12) + case uint64: + x.Minimum = float64(v12) + case uint32: + x.Minimum = float64(v12) + case int64: + x.Minimum = float64(v12) + case int32: + x.Minimum = float64(v12) + case int: + x.Minimum = float64(v12) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 13; + v13 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v13 != nil { + x.ExclusiveMinimum, ok = v13.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 14; + v14 := compiler.MapValueForKey(m, "maxLength") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 15; + v15 := compiler.MapValueForKey(m, "minLength") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 16; + v16 := compiler.MapValueForKey(m, "pattern") + if v16 != nil { + x.Pattern, ok = v16.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 17; + v17 := compiler.MapValueForKey(m, "maxItems") + if v17 != nil { + t, ok := v17.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 18; + v18 := compiler.MapValueForKey(m, "minItems") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 19; + v19 := compiler.MapValueForKey(m, "uniqueItems") + if v19 != nil { + x.UniqueItems, ok = v19.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 20; + v20 := compiler.MapValueForKey(m, "enum") + if v20 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v20.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 21; + v21 := compiler.MapValueForKey(m, "multipleOf") + if v21 != nil { + switch v21 := v21.(type) { + case float64: + x.MultipleOf = v21 + case float32: + x.MultipleOf = float64(v21) + case uint64: + x.MultipleOf = float64(v21) + case uint32: + x.MultipleOf = float64(v21) + case int64: + x.MultipleOf = float64(v21) + case int32: + x.MultipleOf = float64(v21) + case int: + x.MultipleOf = float64(v21) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v21, v21) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 22; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPaths creates an object of type Paths if possible, returning an error if not. +func NewPaths(in interface{}, context *compiler.Context) (*Paths, error) { + errors := make([]error, 0) + x := &Paths{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{} + allowedPatterns := []*regexp.Regexp{pattern0, pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated NamedAny vendor_extension = 1; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + // repeated NamedPathItem path = 2; + // MAP: PathItem ^/ + x.Path = make([]*NamedPathItem, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "/") { + pair := &NamedPathItem{} + pair.Name = k + var err error + pair.Value, err = NewPathItem(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.Path = append(x.Path, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPrimitivesItems creates an object of type PrimitivesItems if possible, returning an error if not. +func NewPrimitivesItems(in interface{}, context *compiler.Context) (*PrimitivesItems, error) { + errors := make([]error, 0) + x := &PrimitivesItems{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"collectionFormat", "default", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "pattern", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number integer boolean array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "integer", "boolean", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 2; + v2 := compiler.MapValueForKey(m, "format") + if v2 != nil { + x.Format, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 3; + v3 := compiler.MapValueForKey(m, "items") + if v3 != nil { + var err error + x.Items, err = NewPrimitivesItems(v3, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 4; + v4 := compiler.MapValueForKey(m, "collectionFormat") + if v4 != nil { + x.CollectionFormat, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 5; + v5 := compiler.MapValueForKey(m, "default") + if v5 != nil { + var err error + x.Default, err = NewAny(v5, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 6; + v6 := compiler.MapValueForKey(m, "maximum") + if v6 != nil { + switch v6 := v6.(type) { + case float64: + x.Maximum = v6 + case float32: + x.Maximum = float64(v6) + case uint64: + x.Maximum = float64(v6) + case uint32: + x.Maximum = float64(v6) + case int64: + x.Maximum = float64(v6) + case int32: + x.Maximum = float64(v6) + case int: + x.Maximum = float64(v6) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 7; + v7 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v7 != nil { + x.ExclusiveMaximum, ok = v7.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 8; + v8 := compiler.MapValueForKey(m, "minimum") + if v8 != nil { + switch v8 := v8.(type) { + case float64: + x.Minimum = v8 + case float32: + x.Minimum = float64(v8) + case uint64: + x.Minimum = float64(v8) + case uint32: + x.Minimum = float64(v8) + case int64: + x.Minimum = float64(v8) + case int32: + x.Minimum = float64(v8) + case int: + x.Minimum = float64(v8) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 9; + v9 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v9 != nil { + x.ExclusiveMinimum, ok = v9.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 10; + v10 := compiler.MapValueForKey(m, "maxLength") + if v10 != nil { + t, ok := v10.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 11; + v11 := compiler.MapValueForKey(m, "minLength") + if v11 != nil { + t, ok := v11.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 12; + v12 := compiler.MapValueForKey(m, "pattern") + if v12 != nil { + x.Pattern, ok = v12.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 13; + v13 := compiler.MapValueForKey(m, "maxItems") + if v13 != nil { + t, ok := v13.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 14; + v14 := compiler.MapValueForKey(m, "minItems") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 15; + v15 := compiler.MapValueForKey(m, "uniqueItems") + if v15 != nil { + x.UniqueItems, ok = v15.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 16; + v16 := compiler.MapValueForKey(m, "enum") + if v16 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v16.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 17; + v17 := compiler.MapValueForKey(m, "multipleOf") + if v17 != nil { + switch v17 := v17.(type) { + case float64: + x.MultipleOf = v17 + case float32: + x.MultipleOf = float64(v17) + case uint64: + x.MultipleOf = float64(v17) + case uint32: + x.MultipleOf = float64(v17) + case int64: + x.MultipleOf = float64(v17) + case int32: + x.MultipleOf = float64(v17) + case int: + x.MultipleOf = float64(v17) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 18; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewProperties creates an object of type Properties if possible, returning an error if not. +func NewProperties(in interface{}, context *compiler.Context) (*Properties, error) { + errors := make([]error, 0) + x := &Properties{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedSchema additional_properties = 1; + // MAP: Schema + x.AdditionalProperties = make([]*NamedSchema, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedSchema{} + pair.Name = k + var err error + pair.Value, err = NewSchema(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewQueryParameterSubSchema creates an object of type QueryParameterSubSchema if possible, returning an error if not. +func NewQueryParameterSubSchema(in interface{}, context *compiler.Context) (*QueryParameterSubSchema, error) { + errors := make([]error, 0) + x := &QueryParameterSubSchema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"allowEmptyValue", "collectionFormat", "default", "description", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "in", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "name", "pattern", "required", "type", "uniqueItems"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // bool required = 1; + v1 := compiler.MapValueForKey(m, "required") + if v1 != nil { + x.Required, ok = v1.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 2; + v2 := compiler.MapValueForKey(m, "in") + if v2 != nil { + x.In, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [query] + if ok && !compiler.StringArrayContainsValue([]string{"query"}, x.In) { + message := fmt.Sprintf("has unexpected value for in: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 4; + v4 := compiler.MapValueForKey(m, "name") + if v4 != nil { + x.Name, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool allow_empty_value = 5; + v5 := compiler.MapValueForKey(m, "allowEmptyValue") + if v5 != nil { + x.AllowEmptyValue, ok = v5.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for allowEmptyValue: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string type = 6; + v6 := compiler.MapValueForKey(m, "type") + if v6 != nil { + x.Type, ok = v6.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [string number boolean integer array] + if ok && !compiler.StringArrayContainsValue([]string{"string", "number", "boolean", "integer", "array"}, x.Type) { + message := fmt.Sprintf("has unexpected value for type: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 7; + v7 := compiler.MapValueForKey(m, "format") + if v7 != nil { + x.Format, ok = v7.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PrimitivesItems items = 8; + v8 := compiler.MapValueForKey(m, "items") + if v8 != nil { + var err error + x.Items, err = NewPrimitivesItems(v8, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // string collection_format = 9; + v9 := compiler.MapValueForKey(m, "collectionFormat") + if v9 != nil { + x.CollectionFormat, ok = v9.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + // check for valid enum values + // [csv ssv tsv pipes multi] + if ok && !compiler.StringArrayContainsValue([]string{"csv", "ssv", "tsv", "pipes", "multi"}, x.CollectionFormat) { + message := fmt.Sprintf("has unexpected value for collectionFormat: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 10; + v10 := compiler.MapValueForKey(m, "default") + if v10 != nil { + var err error + x.Default, err = NewAny(v10, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float maximum = 11; + v11 := compiler.MapValueForKey(m, "maximum") + if v11 != nil { + switch v11 := v11.(type) { + case float64: + x.Maximum = v11 + case float32: + x.Maximum = float64(v11) + case uint64: + x.Maximum = float64(v11) + case uint32: + x.Maximum = float64(v11) + case int64: + x.Maximum = float64(v11) + case int32: + x.Maximum = float64(v11) + case int: + x.Maximum = float64(v11) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 12; + v12 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v12 != nil { + x.ExclusiveMaximum, ok = v12.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 13; + v13 := compiler.MapValueForKey(m, "minimum") + if v13 != nil { + switch v13 := v13.(type) { + case float64: + x.Minimum = v13 + case float32: + x.Minimum = float64(v13) + case uint64: + x.Minimum = float64(v13) + case uint32: + x.Minimum = float64(v13) + case int64: + x.Minimum = float64(v13) + case int32: + x.Minimum = float64(v13) + case int: + x.Minimum = float64(v13) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 14; + v14 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v14 != nil { + x.ExclusiveMinimum, ok = v14.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 15; + v15 := compiler.MapValueForKey(m, "maxLength") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 16; + v16 := compiler.MapValueForKey(m, "minLength") + if v16 != nil { + t, ok := v16.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 17; + v17 := compiler.MapValueForKey(m, "pattern") + if v17 != nil { + x.Pattern, ok = v17.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 18; + v18 := compiler.MapValueForKey(m, "maxItems") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 19; + v19 := compiler.MapValueForKey(m, "minItems") + if v19 != nil { + t, ok := v19.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 20; + v20 := compiler.MapValueForKey(m, "uniqueItems") + if v20 != nil { + x.UniqueItems, ok = v20.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v20, v20) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 21; + v21 := compiler.MapValueForKey(m, "enum") + if v21 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v21.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // float multiple_of = 22; + v22 := compiler.MapValueForKey(m, "multipleOf") + if v22 != nil { + switch v22 := v22.(type) { + case float64: + x.MultipleOf = v22 + case float32: + x.MultipleOf = float64(v22) + case uint64: + x.MultipleOf = float64(v22) + case uint32: + x.MultipleOf = float64(v22) + case int64: + x.MultipleOf = float64(v22) + case int32: + x.MultipleOf = float64(v22) + case int: + x.MultipleOf = float64(v22) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v22, v22) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 23; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponse creates an object of type Response if possible, returning an error if not. +func NewResponse(in interface{}, context *compiler.Context) (*Response, error) { + errors := make([]error, 0) + x := &Response{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"description"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "examples", "headers", "schema"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // SchemaItem schema = 2; + v2 := compiler.MapValueForKey(m, "schema") + if v2 != nil { + var err error + x.Schema, err = NewSchemaItem(v2, compiler.NewContext("schema", context)) + if err != nil { + errors = append(errors, err) + } + } + // Headers headers = 3; + v3 := compiler.MapValueForKey(m, "headers") + if v3 != nil { + var err error + x.Headers, err = NewHeaders(v3, compiler.NewContext("headers", context)) + if err != nil { + errors = append(errors, err) + } + } + // Examples examples = 4; + v4 := compiler.MapValueForKey(m, "examples") + if v4 != nil { + var err error + x.Examples, err = NewExamples(v4, compiler.NewContext("examples", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 5; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponseDefinitions creates an object of type ResponseDefinitions if possible, returning an error if not. +func NewResponseDefinitions(in interface{}, context *compiler.Context) (*ResponseDefinitions, error) { + errors := make([]error, 0) + x := &ResponseDefinitions{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedResponse additional_properties = 1; + // MAP: Response + x.AdditionalProperties = make([]*NamedResponse, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedResponse{} + pair.Name = k + var err error + pair.Value, err = NewResponse(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponseValue creates an object of type ResponseValue if possible, returning an error if not. +func NewResponseValue(in interface{}, context *compiler.Context) (*ResponseValue, error) { + errors := make([]error, 0) + x := &ResponseValue{} + matched := false + // Response response = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewResponse(m, compiler.NewContext("response", context)) + if matchingError == nil { + x.Oneof = &ResponseValue_Response{Response: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // JsonReference json_reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewJsonReference(m, compiler.NewContext("jsonReference", context)) + if matchingError == nil { + x.Oneof = &ResponseValue_JsonReference{JsonReference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponses creates an object of type Responses if possible, returning an error if not. +func NewResponses(in interface{}, context *compiler.Context) (*Responses, error) { + errors := make([]error, 0) + x := &Responses{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{} + allowedPatterns := []*regexp.Regexp{pattern2, pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated NamedResponseValue response_code = 1; + // MAP: ResponseValue ^([0-9]{3})$|^(default)$ + x.ResponseCode = make([]*NamedResponseValue, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if pattern2.MatchString(k) { + pair := &NamedResponseValue{} + pair.Name = k + var err error + pair.Value, err = NewResponseValue(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.ResponseCode = append(x.ResponseCode, pair) + } + } + } + // repeated NamedAny vendor_extension = 2; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSchema creates an object of type Schema if possible, returning an error if not. +func NewSchema(in interface{}, context *compiler.Context) (*Schema, error) { + errors := make([]error, 0) + x := &Schema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"$ref", "additionalProperties", "allOf", "default", "description", "discriminator", "enum", "example", "exclusiveMaximum", "exclusiveMinimum", "externalDocs", "format", "items", "maxItems", "maxLength", "maxProperties", "maximum", "minItems", "minLength", "minProperties", "minimum", "multipleOf", "pattern", "properties", "readOnly", "required", "title", "type", "uniqueItems", "xml"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string _ref = 1; + v1 := compiler.MapValueForKey(m, "$ref") + if v1 != nil { + x.XRef, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for $ref: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 2; + v2 := compiler.MapValueForKey(m, "format") + if v2 != nil { + x.Format, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string title = 3; + v3 := compiler.MapValueForKey(m, "title") + if v3 != nil { + x.Title, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for title: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 4; + v4 := compiler.MapValueForKey(m, "description") + if v4 != nil { + x.Description, ok = v4.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any default = 5; + v5 := compiler.MapValueForKey(m, "default") + if v5 != nil { + var err error + x.Default, err = NewAny(v5, compiler.NewContext("default", context)) + if err != nil { + errors = append(errors, err) + } + } + // float multiple_of = 6; + v6 := compiler.MapValueForKey(m, "multipleOf") + if v6 != nil { + switch v6 := v6.(type) { + case float64: + x.MultipleOf = v6 + case float32: + x.MultipleOf = float64(v6) + case uint64: + x.MultipleOf = float64(v6) + case uint32: + x.MultipleOf = float64(v6) + case int64: + x.MultipleOf = float64(v6) + case int32: + x.MultipleOf = float64(v6) + case int: + x.MultipleOf = float64(v6) + default: + message := fmt.Sprintf("has unexpected value for multipleOf: %+v (%T)", v6, v6) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float maximum = 7; + v7 := compiler.MapValueForKey(m, "maximum") + if v7 != nil { + switch v7 := v7.(type) { + case float64: + x.Maximum = v7 + case float32: + x.Maximum = float64(v7) + case uint64: + x.Maximum = float64(v7) + case uint32: + x.Maximum = float64(v7) + case int64: + x.Maximum = float64(v7) + case int32: + x.Maximum = float64(v7) + case int: + x.Maximum = float64(v7) + default: + message := fmt.Sprintf("has unexpected value for maximum: %+v (%T)", v7, v7) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 8; + v8 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v8 != nil { + x.ExclusiveMaximum, ok = v8.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %+v (%T)", v8, v8) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 9; + v9 := compiler.MapValueForKey(m, "minimum") + if v9 != nil { + switch v9 := v9.(type) { + case float64: + x.Minimum = v9 + case float32: + x.Minimum = float64(v9) + case uint64: + x.Minimum = float64(v9) + case uint32: + x.Minimum = float64(v9) + case int64: + x.Minimum = float64(v9) + case int32: + x.Minimum = float64(v9) + case int: + x.Minimum = float64(v9) + default: + message := fmt.Sprintf("has unexpected value for minimum: %+v (%T)", v9, v9) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 10; + v10 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v10 != nil { + x.ExclusiveMinimum, ok = v10.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %+v (%T)", v10, v10) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 11; + v11 := compiler.MapValueForKey(m, "maxLength") + if v11 != nil { + t, ok := v11.(int) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %+v (%T)", v11, v11) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 12; + v12 := compiler.MapValueForKey(m, "minLength") + if v12 != nil { + t, ok := v12.(int) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %+v (%T)", v12, v12) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 13; + v13 := compiler.MapValueForKey(m, "pattern") + if v13 != nil { + x.Pattern, ok = v13.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %+v (%T)", v13, v13) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 14; + v14 := compiler.MapValueForKey(m, "maxItems") + if v14 != nil { + t, ok := v14.(int) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %+v (%T)", v14, v14) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 15; + v15 := compiler.MapValueForKey(m, "minItems") + if v15 != nil { + t, ok := v15.(int) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %+v (%T)", v15, v15) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 16; + v16 := compiler.MapValueForKey(m, "uniqueItems") + if v16 != nil { + x.UniqueItems, ok = v16.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %+v (%T)", v16, v16) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_properties = 17; + v17 := compiler.MapValueForKey(m, "maxProperties") + if v17 != nil { + t, ok := v17.(int) + if ok { + x.MaxProperties = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxProperties: %+v (%T)", v17, v17) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_properties = 18; + v18 := compiler.MapValueForKey(m, "minProperties") + if v18 != nil { + t, ok := v18.(int) + if ok { + x.MinProperties = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minProperties: %+v (%T)", v18, v18) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string required = 19; + v19 := compiler.MapValueForKey(m, "required") + if v19 != nil { + v, ok := v19.([]interface{}) + if ok { + x.Required = compiler.ConvertInterfaceArrayToStringArray(v) + } else { + message := fmt.Sprintf("has unexpected value for required: %+v (%T)", v19, v19) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 20; + v20 := compiler.MapValueForKey(m, "enum") + if v20 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := v20.([]interface{}) + if ok { + for _, item := range a { + y, err := NewAny(item, compiler.NewContext("enum", context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // AdditionalPropertiesItem additional_properties = 21; + v21 := compiler.MapValueForKey(m, "additionalProperties") + if v21 != nil { + var err error + x.AdditionalProperties, err = NewAdditionalPropertiesItem(v21, compiler.NewContext("additionalProperties", context)) + if err != nil { + errors = append(errors, err) + } + } + // TypeItem type = 22; + v22 := compiler.MapValueForKey(m, "type") + if v22 != nil { + var err error + x.Type, err = NewTypeItem(v22, compiler.NewContext("type", context)) + if err != nil { + errors = append(errors, err) + } + } + // ItemsItem items = 23; + v23 := compiler.MapValueForKey(m, "items") + if v23 != nil { + var err error + x.Items, err = NewItemsItem(v23, compiler.NewContext("items", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated Schema all_of = 24; + v24 := compiler.MapValueForKey(m, "allOf") + if v24 != nil { + // repeated Schema + x.AllOf = make([]*Schema, 0) + a, ok := v24.([]interface{}) + if ok { + for _, item := range a { + y, err := NewSchema(item, compiler.NewContext("allOf", context)) + if err != nil { + errors = append(errors, err) + } + x.AllOf = append(x.AllOf, y) + } + } + } + // Properties properties = 25; + v25 := compiler.MapValueForKey(m, "properties") + if v25 != nil { + var err error + x.Properties, err = NewProperties(v25, compiler.NewContext("properties", context)) + if err != nil { + errors = append(errors, err) + } + } + // string discriminator = 26; + v26 := compiler.MapValueForKey(m, "discriminator") + if v26 != nil { + x.Discriminator, ok = v26.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for discriminator: %+v (%T)", v26, v26) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool read_only = 27; + v27 := compiler.MapValueForKey(m, "readOnly") + if v27 != nil { + x.ReadOnly, ok = v27.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for readOnly: %+v (%T)", v27, v27) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Xml xml = 28; + v28 := compiler.MapValueForKey(m, "xml") + if v28 != nil { + var err error + x.Xml, err = NewXml(v28, compiler.NewContext("xml", context)) + if err != nil { + errors = append(errors, err) + } + } + // ExternalDocs external_docs = 29; + v29 := compiler.MapValueForKey(m, "externalDocs") + if v29 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v29, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // Any example = 30; + v30 := compiler.MapValueForKey(m, "example") + if v30 != nil { + var err error + x.Example, err = NewAny(v30, compiler.NewContext("example", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 31; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSchemaItem creates an object of type SchemaItem if possible, returning an error if not. +func NewSchemaItem(in interface{}, context *compiler.Context) (*SchemaItem, error) { + errors := make([]error, 0) + x := &SchemaItem{} + matched := false + // Schema schema = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewSchema(m, compiler.NewContext("schema", context)) + if matchingError == nil { + x.Oneof = &SchemaItem_Schema{Schema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // FileSchema file_schema = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewFileSchema(m, compiler.NewContext("fileSchema", context)) + if matchingError == nil { + x.Oneof = &SchemaItem_FileSchema{FileSchema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecurityDefinitions creates an object of type SecurityDefinitions if possible, returning an error if not. +func NewSecurityDefinitions(in interface{}, context *compiler.Context) (*SecurityDefinitions, error) { + errors := make([]error, 0) + x := &SecurityDefinitions{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedSecurityDefinitionsItem additional_properties = 1; + // MAP: SecurityDefinitionsItem + x.AdditionalProperties = make([]*NamedSecurityDefinitionsItem, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedSecurityDefinitionsItem{} + pair.Name = k + var err error + pair.Value, err = NewSecurityDefinitionsItem(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecurityDefinitionsItem creates an object of type SecurityDefinitionsItem if possible, returning an error if not. +func NewSecurityDefinitionsItem(in interface{}, context *compiler.Context) (*SecurityDefinitionsItem, error) { + errors := make([]error, 0) + x := &SecurityDefinitionsItem{} + matched := false + // BasicAuthenticationSecurity basic_authentication_security = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewBasicAuthenticationSecurity(m, compiler.NewContext("basicAuthenticationSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_BasicAuthenticationSecurity{BasicAuthenticationSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // ApiKeySecurity api_key_security = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewApiKeySecurity(m, compiler.NewContext("apiKeySecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_ApiKeySecurity{ApiKeySecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Oauth2ImplicitSecurity oauth2_implicit_security = 3; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewOauth2ImplicitSecurity(m, compiler.NewContext("oauth2ImplicitSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_Oauth2ImplicitSecurity{Oauth2ImplicitSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Oauth2PasswordSecurity oauth2_password_security = 4; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewOauth2PasswordSecurity(m, compiler.NewContext("oauth2PasswordSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_Oauth2PasswordSecurity{Oauth2PasswordSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Oauth2ApplicationSecurity oauth2_application_security = 5; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewOauth2ApplicationSecurity(m, compiler.NewContext("oauth2ApplicationSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_Oauth2ApplicationSecurity{Oauth2ApplicationSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Oauth2AccessCodeSecurity oauth2_access_code_security = 6; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewOauth2AccessCodeSecurity(m, compiler.NewContext("oauth2AccessCodeSecurity", context)) + if matchingError == nil { + x.Oneof = &SecurityDefinitionsItem_Oauth2AccessCodeSecurity{Oauth2AccessCodeSecurity: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecurityRequirement creates an object of type SecurityRequirement if possible, returning an error if not. +func NewSecurityRequirement(in interface{}, context *compiler.Context) (*SecurityRequirement, error) { + errors := make([]error, 0) + x := &SecurityRequirement{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedStringArray additional_properties = 1; + // MAP: StringArray + x.AdditionalProperties = make([]*NamedStringArray, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedStringArray{} + pair.Name = k + var err error + pair.Value, err = NewStringArray(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewStringArray creates an object of type StringArray if possible, returning an error if not. +func NewStringArray(in interface{}, context *compiler.Context) (*StringArray, error) { + errors := make([]error, 0) + x := &StringArray{} + a, ok := in.([]interface{}) + if !ok { + message := fmt.Sprintf("has unexpected value for StringArray: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + x.Value = make([]string, 0) + for _, s := range a { + x.Value = append(x.Value, s.(string)) + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewTag creates an object of type Tag if possible, returning an error if not. +func NewTag(in interface{}, context *compiler.Context) (*Tag, error) { + errors := make([]error, 0) + x := &Tag{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"name"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "externalDocs", "name"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ExternalDocs external_docs = 3; + v3 := compiler.MapValueForKey(m, "externalDocs") + if v3 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v3, compiler.NewContext("externalDocs", context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny vendor_extension = 4; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewTypeItem creates an object of type TypeItem if possible, returning an error if not. +func NewTypeItem(in interface{}, context *compiler.Context) (*TypeItem, error) { + errors := make([]error, 0) + x := &TypeItem{} + switch in := in.(type) { + case string: + x.Value = make([]string, 0) + x.Value = append(x.Value, in) + case []interface{}: + x.Value = make([]string, 0) + for _, v := range in { + value, ok := v.(string) + if ok { + x.Value = append(x.Value, value) + } else { + message := fmt.Sprintf("has unexpected value for string array element: %+v (%T)", value, value) + errors = append(errors, compiler.NewError(context, message)) + } + } + default: + message := fmt.Sprintf("has unexpected value for string array: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewVendorExtension creates an object of type VendorExtension if possible, returning an error if not. +func NewVendorExtension(in interface{}, context *compiler.Context) (*VendorExtension, error) { + errors := make([]error, 0) + x := &VendorExtension{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedAny additional_properties = 1; + // MAP: Any + x.AdditionalProperties = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewXml creates an object of type Xml if possible, returning an error if not. +func NewXml(in interface{}, context *compiler.Context) (*Xml, error) { + errors := make([]error, 0) + x := &Xml{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"attribute", "name", "namespace", "prefix", "wrapped"} + allowedPatterns := []*regexp.Regexp{pattern0} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = v1.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %+v (%T)", v1, v1) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string namespace = 2; + v2 := compiler.MapValueForKey(m, "namespace") + if v2 != nil { + x.Namespace, ok = v2.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for namespace: %+v (%T)", v2, v2) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string prefix = 3; + v3 := compiler.MapValueForKey(m, "prefix") + if v3 != nil { + x.Prefix, ok = v3.(string) + if !ok { + message := fmt.Sprintf("has unexpected value for prefix: %+v (%T)", v3, v3) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool attribute = 4; + v4 := compiler.MapValueForKey(m, "attribute") + if v4 != nil { + x.Attribute, ok = v4.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for attribute: %+v (%T)", v4, v4) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool wrapped = 5; + v5 := compiler.MapValueForKey(m, "wrapped") + if v5 != nil { + x.Wrapped, ok = v5.(bool) + if !ok { + message := fmt.Sprintf("has unexpected value for wrapped: %+v (%T)", v5, v5) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny vendor_extension = 6; + // MAP: Any ^x- + x.VendorExtension = make([]*NamedAny, 0) + for _, item := range m { + k, ok := compiler.StringValue(item.Key) + if ok { + v := item.Value + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.HandleExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes, _ := yaml.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, context)) + if err != nil { + errors = append(errors, err) + } + } + x.VendorExtension = append(x.VendorExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside AdditionalPropertiesItem objects. +func (m *AdditionalPropertiesItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*AdditionalPropertiesItem_Schema) + if ok { + _, err := p.Schema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Any objects. +func (m *Any) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ApiKeySecurity objects. +func (m *ApiKeySecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside BasicAuthenticationSecurity objects. +func (m *BasicAuthenticationSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside BodyParameter objects. +func (m *BodyParameter) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Schema != nil { + _, err := m.Schema.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Contact objects. +func (m *Contact) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Default objects. +func (m *Default) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Definitions objects. +func (m *Definitions) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Document objects. +func (m *Document) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Info != nil { + _, err := m.Info.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Paths != nil { + _, err := m.Paths.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Definitions != nil { + _, err := m.Definitions.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Parameters != nil { + _, err := m.Parameters.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Responses != nil { + _, err := m.Responses.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Security { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.SecurityDefinitions != nil { + _, err := m.SecurityDefinitions.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Tags { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Examples objects. +func (m *Examples) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ExternalDocs objects. +func (m *ExternalDocs) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside FileSchema objects. +func (m *FileSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Example != nil { + _, err := m.Example.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside FormDataParameterSubSchema objects. +func (m *FormDataParameterSubSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Header objects. +func (m *Header) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside HeaderParameterSubSchema objects. +func (m *HeaderParameterSubSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Headers objects. +func (m *Headers) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Info objects. +func (m *Info) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Contact != nil { + _, err := m.Contact.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.License != nil { + _, err := m.License.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ItemsItem objects. +func (m *ItemsItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.Schema { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside JsonReference objects. +func (m *JsonReference) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.XRef != "" { + info, err := compiler.ReadInfoForRef(root, m.XRef) + if err != nil { + return nil, err + } + if info != nil { + replacement, err := NewJsonReference(info, nil) + if err == nil { + *m = *replacement + return m.ResolveReferences(root) + } + } + return info, nil + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside License objects. +func (m *License) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedAny objects. +func (m *NamedAny) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedHeader objects. +func (m *NamedHeader) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedParameter objects. +func (m *NamedParameter) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedPathItem objects. +func (m *NamedPathItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedResponse objects. +func (m *NamedResponse) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedResponseValue objects. +func (m *NamedResponseValue) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedSchema objects. +func (m *NamedSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedSecurityDefinitionsItem objects. +func (m *NamedSecurityDefinitionsItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedString objects. +func (m *NamedString) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NamedStringArray objects. +func (m *NamedStringArray) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Value != nil { + _, err := m.Value.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside NonBodyParameter objects. +func (m *NonBodyParameter) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*NonBodyParameter_HeaderParameterSubSchema) + if ok { + _, err := p.HeaderParameterSubSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*NonBodyParameter_FormDataParameterSubSchema) + if ok { + _, err := p.FormDataParameterSubSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*NonBodyParameter_QueryParameterSubSchema) + if ok { + _, err := p.QueryParameterSubSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*NonBodyParameter_PathParameterSubSchema) + if ok { + _, err := p.PathParameterSubSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2AccessCodeSecurity objects. +func (m *Oauth2AccessCodeSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Scopes != nil { + _, err := m.Scopes.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2ApplicationSecurity objects. +func (m *Oauth2ApplicationSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Scopes != nil { + _, err := m.Scopes.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2ImplicitSecurity objects. +func (m *Oauth2ImplicitSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Scopes != nil { + _, err := m.Scopes.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2PasswordSecurity objects. +func (m *Oauth2PasswordSecurity) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Scopes != nil { + _, err := m.Scopes.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Oauth2Scopes objects. +func (m *Oauth2Scopes) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Operation objects. +func (m *Operation) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Parameters { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.Responses != nil { + _, err := m.Responses.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Security { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Parameter objects. +func (m *Parameter) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*Parameter_BodyParameter) + if ok { + _, err := p.BodyParameter.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*Parameter_NonBodyParameter) + if ok { + _, err := p.NonBodyParameter.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ParameterDefinitions objects. +func (m *ParameterDefinitions) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ParametersItem objects. +func (m *ParametersItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*ParametersItem_Parameter) + if ok { + _, err := p.Parameter.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*ParametersItem_JsonReference) + if ok { + info, err := p.JsonReference.ResolveReferences(root) + if err != nil { + return nil, err + } else if info != nil { + n, err := NewParametersItem(info, nil) + if err != nil { + return nil, err + } else if n != nil { + *m = *n + return nil, nil + } + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside PathItem objects. +func (m *PathItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.XRef != "" { + info, err := compiler.ReadInfoForRef(root, m.XRef) + if err != nil { + return nil, err + } + if info != nil { + replacement, err := NewPathItem(info, nil) + if err == nil { + *m = *replacement + return m.ResolveReferences(root) + } + } + return info, nil + } + if m.Get != nil { + _, err := m.Get.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Put != nil { + _, err := m.Put.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Post != nil { + _, err := m.Post.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Delete != nil { + _, err := m.Delete.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Options != nil { + _, err := m.Options.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Head != nil { + _, err := m.Head.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Patch != nil { + _, err := m.Patch.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Parameters { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside PathParameterSubSchema objects. +func (m *PathParameterSubSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Paths objects. +func (m *Paths) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.Path { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside PrimitivesItems objects. +func (m *PrimitivesItems) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Properties objects. +func (m *Properties) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside QueryParameterSubSchema objects. +func (m *QueryParameterSubSchema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Response objects. +func (m *Response) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.Schema != nil { + _, err := m.Schema.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Headers != nil { + _, err := m.Headers.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Examples != nil { + _, err := m.Examples.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ResponseDefinitions objects. +func (m *ResponseDefinitions) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside ResponseValue objects. +func (m *ResponseValue) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*ResponseValue_Response) + if ok { + _, err := p.Response.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*ResponseValue_JsonReference) + if ok { + info, err := p.JsonReference.ResolveReferences(root) + if err != nil { + return nil, err + } else if info != nil { + n, err := NewResponseValue(info, nil) + if err != nil { + return nil, err + } else if n != nil { + *m = *n + return nil, nil + } + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Responses objects. +func (m *Responses) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.ResponseCode { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Schema objects. +func (m *Schema) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.XRef != "" { + info, err := compiler.ReadInfoForRef(root, m.XRef) + if err != nil { + return nil, err + } + if info != nil { + replacement, err := NewSchema(info, nil) + if err == nil { + *m = *replacement + return m.ResolveReferences(root) + } + } + return info, nil + } + if m.Default != nil { + _, err := m.Default.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.Enum { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.AdditionalProperties != nil { + _, err := m.AdditionalProperties.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Type != nil { + _, err := m.Type.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Items != nil { + _, err := m.Items.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.AllOf { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + if m.Properties != nil { + _, err := m.Properties.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Xml != nil { + _, err := m.Xml.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + if m.Example != nil { + _, err := m.Example.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside SchemaItem objects. +func (m *SchemaItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*SchemaItem_Schema) + if ok { + _, err := p.Schema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SchemaItem_FileSchema) + if ok { + _, err := p.FileSchema.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside SecurityDefinitions objects. +func (m *SecurityDefinitions) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside SecurityDefinitionsItem objects. +func (m *SecurityDefinitionsItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_BasicAuthenticationSecurity) + if ok { + _, err := p.BasicAuthenticationSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_ApiKeySecurity) + if ok { + _, err := p.ApiKeySecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_Oauth2ImplicitSecurity) + if ok { + _, err := p.Oauth2ImplicitSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_Oauth2PasswordSecurity) + if ok { + _, err := p.Oauth2PasswordSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_Oauth2ApplicationSecurity) + if ok { + _, err := p.Oauth2ApplicationSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + { + p, ok := m.Oneof.(*SecurityDefinitionsItem_Oauth2AccessCodeSecurity) + if ok { + _, err := p.Oauth2AccessCodeSecurity.ResolveReferences(root) + if err != nil { + return nil, err + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside SecurityRequirement objects. +func (m *SecurityRequirement) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside StringArray objects. +func (m *StringArray) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Tag objects. +func (m *Tag) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + if m.ExternalDocs != nil { + _, err := m.ExternalDocs.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside TypeItem objects. +func (m *TypeItem) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside VendorExtension objects. +func (m *VendorExtension) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.AdditionalProperties { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ResolveReferences resolves references found inside Xml objects. +func (m *Xml) ResolveReferences(root string) (interface{}, error) { + errors := make([]error, 0) + for _, item := range m.VendorExtension { + if item != nil { + _, err := item.ResolveReferences(root) + if err != nil { + errors = append(errors, err) + } + } + } + return nil, compiler.NewErrorGroupOrNil(errors) +} + +// ToRawInfo returns a description of AdditionalPropertiesItem suitable for JSON or YAML export. +func (m *AdditionalPropertiesItem) ToRawInfo() interface{} { + // ONE OF WRAPPER + // AdditionalPropertiesItem + // {Name:schema Type:Schema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetSchema() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:boolean Type:bool StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if v1, ok := m.GetOneof().(*AdditionalPropertiesItem_Boolean); ok { + return v1.Boolean + } + return nil +} + +// ToRawInfo returns a description of Any suitable for JSON or YAML export. +func (m *Any) ToRawInfo() interface{} { + var err error + var info1 []yaml.MapSlice + err = yaml.Unmarshal([]byte(m.Yaml), &info1) + if err == nil { + return info1 + } + var info2 yaml.MapSlice + err = yaml.Unmarshal([]byte(m.Yaml), &info2) + if err == nil { + return info2 + } + var info3 interface{} + err = yaml.Unmarshal([]byte(m.Yaml), &info3) + if err == nil { + return info3 + } + return nil +} + +// ToRawInfo returns a description of ApiKeySecurity suitable for JSON or YAML export. +func (m *ApiKeySecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.In != "" { + info = append(info, yaml.MapItem{"in", m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of BasicAuthenticationSecurity suitable for JSON or YAML export. +func (m *BasicAuthenticationSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of BodyParameter suitable for JSON or YAML export. +func (m *BodyParameter) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.In != "" { + info = append(info, yaml.MapItem{"in", m.In}) + } + if m.Required != false { + info = append(info, yaml.MapItem{"required", m.Required}) + } + if m.Schema != nil { + info = append(info, yaml.MapItem{"schema", m.Schema.ToRawInfo()}) + } + // &{Name:schema Type:Schema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Contact suitable for JSON or YAML export. +func (m *Contact) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.Url != "" { + info = append(info, yaml.MapItem{"url", m.Url}) + } + if m.Email != "" { + info = append(info, yaml.MapItem{"email", m.Email}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Default suitable for JSON or YAML export. +func (m *Default) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern: Implicit:false Description:} + return info +} + +// ToRawInfo returns a description of Definitions suitable for JSON or YAML export. +func (m *Definitions) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedSchema StringEnumValues:[] MapType:Schema Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Document suitable for JSON or YAML export. +func (m *Document) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Swagger != "" { + info = append(info, yaml.MapItem{"swagger", m.Swagger}) + } + if m.Info != nil { + info = append(info, yaml.MapItem{"info", m.Info.ToRawInfo()}) + } + // &{Name:info Type:Info StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Host != "" { + info = append(info, yaml.MapItem{"host", m.Host}) + } + if m.BasePath != "" { + info = append(info, yaml.MapItem{"basePath", m.BasePath}) + } + if len(m.Schemes) != 0 { + info = append(info, yaml.MapItem{"schemes", m.Schemes}) + } + if len(m.Consumes) != 0 { + info = append(info, yaml.MapItem{"consumes", m.Consumes}) + } + if len(m.Produces) != 0 { + info = append(info, yaml.MapItem{"produces", m.Produces}) + } + if m.Paths != nil { + info = append(info, yaml.MapItem{"paths", m.Paths.ToRawInfo()}) + } + // &{Name:paths Type:Paths StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Definitions != nil { + info = append(info, yaml.MapItem{"definitions", m.Definitions.ToRawInfo()}) + } + // &{Name:definitions Type:Definitions StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Parameters != nil { + info = append(info, yaml.MapItem{"parameters", m.Parameters.ToRawInfo()}) + } + // &{Name:parameters Type:ParameterDefinitions StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Responses != nil { + info = append(info, yaml.MapItem{"responses", m.Responses.ToRawInfo()}) + } + // &{Name:responses Type:ResponseDefinitions StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Security) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Security { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"security", items}) + } + // &{Name:security Type:SecurityRequirement StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.SecurityDefinitions != nil { + info = append(info, yaml.MapItem{"securityDefinitions", m.SecurityDefinitions.ToRawInfo()}) + } + // &{Name:securityDefinitions Type:SecurityDefinitions StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Tags) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Tags { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"tags", items}) + } + // &{Name:tags Type:Tag StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{"externalDocs", m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Examples suitable for JSON or YAML export. +func (m *Examples) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ExternalDocs suitable for JSON or YAML export. +func (m *ExternalDocs) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.Url != "" { + info = append(info, yaml.MapItem{"url", m.Url}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of FileSchema suitable for JSON or YAML export. +func (m *FileSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Format != "" { + info = append(info, yaml.MapItem{"format", m.Format}) + } + if m.Title != "" { + info = append(info, yaml.MapItem{"title", m.Title}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{"default", m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Required) != 0 { + info = append(info, yaml.MapItem{"required", m.Required}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.ReadOnly != false { + info = append(info, yaml.MapItem{"readOnly", m.ReadOnly}) + } + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{"externalDocs", m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Example != nil { + info = append(info, yaml.MapItem{"example", m.Example.ToRawInfo()}) + } + // &{Name:example Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of FormDataParameterSubSchema suitable for JSON or YAML export. +func (m *FormDataParameterSubSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Required != false { + info = append(info, yaml.MapItem{"required", m.Required}) + } + if m.In != "" { + info = append(info, yaml.MapItem{"in", m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.AllowEmptyValue != false { + info = append(info, yaml.MapItem{"allowEmptyValue", m.AllowEmptyValue}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{"format", m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{"items", m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{"collectionFormat", m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{"default", m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{"maximum", m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{"exclusiveMaximum", m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{"minimum", m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{"exclusiveMinimum", m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{"maxLength", m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{"minLength", m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{"pattern", m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{"maxItems", m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{"minItems", m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{"uniqueItems", m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"enum", items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{"multipleOf", m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Header suitable for JSON or YAML export. +func (m *Header) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{"format", m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{"items", m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{"collectionFormat", m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{"default", m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{"maximum", m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{"exclusiveMaximum", m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{"minimum", m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{"exclusiveMinimum", m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{"maxLength", m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{"minLength", m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{"pattern", m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{"maxItems", m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{"minItems", m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{"uniqueItems", m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"enum", items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{"multipleOf", m.MultipleOf}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of HeaderParameterSubSchema suitable for JSON or YAML export. +func (m *HeaderParameterSubSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Required != false { + info = append(info, yaml.MapItem{"required", m.Required}) + } + if m.In != "" { + info = append(info, yaml.MapItem{"in", m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{"format", m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{"items", m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{"collectionFormat", m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{"default", m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{"maximum", m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{"exclusiveMaximum", m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{"minimum", m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{"exclusiveMinimum", m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{"maxLength", m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{"minLength", m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{"pattern", m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{"maxItems", m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{"minItems", m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{"uniqueItems", m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"enum", items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{"multipleOf", m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Headers suitable for JSON or YAML export. +func (m *Headers) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedHeader StringEnumValues:[] MapType:Header Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Info suitable for JSON or YAML export. +func (m *Info) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Title != "" { + info = append(info, yaml.MapItem{"title", m.Title}) + } + if m.Version != "" { + info = append(info, yaml.MapItem{"version", m.Version}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.TermsOfService != "" { + info = append(info, yaml.MapItem{"termsOfService", m.TermsOfService}) + } + if m.Contact != nil { + info = append(info, yaml.MapItem{"contact", m.Contact.ToRawInfo()}) + } + // &{Name:contact Type:Contact StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.License != nil { + info = append(info, yaml.MapItem{"license", m.License.ToRawInfo()}) + } + // &{Name:license Type:License StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ItemsItem suitable for JSON or YAML export. +func (m *ItemsItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if len(m.Schema) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Schema { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"schema", items}) + } + // &{Name:schema Type:Schema StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + return info +} + +// ToRawInfo returns a description of JsonReference suitable for JSON or YAML export. +func (m *JsonReference) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.XRef != "" { + info = append(info, yaml.MapItem{"$ref", m.XRef}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + return info +} + +// ToRawInfo returns a description of License suitable for JSON or YAML export. +func (m *License) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.Url != "" { + info = append(info, yaml.MapItem{"url", m.Url}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of NamedAny suitable for JSON or YAML export. +func (m *NamedAny) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + // &{Name:value Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedHeader suitable for JSON or YAML export. +func (m *NamedHeader) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + // &{Name:value Type:Header StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedParameter suitable for JSON or YAML export. +func (m *NamedParameter) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + // &{Name:value Type:Parameter StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedPathItem suitable for JSON or YAML export. +func (m *NamedPathItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + // &{Name:value Type:PathItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedResponse suitable for JSON or YAML export. +func (m *NamedResponse) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + // &{Name:value Type:Response StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedResponseValue suitable for JSON or YAML export. +func (m *NamedResponseValue) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + // &{Name:value Type:ResponseValue StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedSchema suitable for JSON or YAML export. +func (m *NamedSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + // &{Name:value Type:Schema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedSecurityDefinitionsItem suitable for JSON or YAML export. +func (m *NamedSecurityDefinitionsItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + // &{Name:value Type:SecurityDefinitionsItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NamedString suitable for JSON or YAML export. +func (m *NamedString) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.Value != "" { + info = append(info, yaml.MapItem{"value", m.Value}) + } + return info +} + +// ToRawInfo returns a description of NamedStringArray suitable for JSON or YAML export. +func (m *NamedStringArray) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + // &{Name:value Type:StringArray StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:Mapped value} + return info +} + +// ToRawInfo returns a description of NonBodyParameter suitable for JSON or YAML export. +func (m *NonBodyParameter) ToRawInfo() interface{} { + // ONE OF WRAPPER + // NonBodyParameter + // {Name:headerParameterSubSchema Type:HeaderParameterSubSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetHeaderParameterSubSchema() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:formDataParameterSubSchema Type:FormDataParameterSubSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetFormDataParameterSubSchema() + if v1 != nil { + return v1.ToRawInfo() + } + // {Name:queryParameterSubSchema Type:QueryParameterSubSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v2 := m.GetQueryParameterSubSchema() + if v2 != nil { + return v2.ToRawInfo() + } + // {Name:pathParameterSubSchema Type:PathParameterSubSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v3 := m.GetPathParameterSubSchema() + if v3 != nil { + return v3.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of Oauth2AccessCodeSecurity suitable for JSON or YAML export. +func (m *Oauth2AccessCodeSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Flow != "" { + info = append(info, yaml.MapItem{"flow", m.Flow}) + } + if m.Scopes != nil { + info = append(info, yaml.MapItem{"scopes", m.Scopes.ToRawInfo()}) + } + // &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.AuthorizationUrl != "" { + info = append(info, yaml.MapItem{"authorizationUrl", m.AuthorizationUrl}) + } + if m.TokenUrl != "" { + info = append(info, yaml.MapItem{"tokenUrl", m.TokenUrl}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Oauth2ApplicationSecurity suitable for JSON or YAML export. +func (m *Oauth2ApplicationSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Flow != "" { + info = append(info, yaml.MapItem{"flow", m.Flow}) + } + if m.Scopes != nil { + info = append(info, yaml.MapItem{"scopes", m.Scopes.ToRawInfo()}) + } + // &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.TokenUrl != "" { + info = append(info, yaml.MapItem{"tokenUrl", m.TokenUrl}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Oauth2ImplicitSecurity suitable for JSON or YAML export. +func (m *Oauth2ImplicitSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Flow != "" { + info = append(info, yaml.MapItem{"flow", m.Flow}) + } + if m.Scopes != nil { + info = append(info, yaml.MapItem{"scopes", m.Scopes.ToRawInfo()}) + } + // &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.AuthorizationUrl != "" { + info = append(info, yaml.MapItem{"authorizationUrl", m.AuthorizationUrl}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Oauth2PasswordSecurity suitable for JSON or YAML export. +func (m *Oauth2PasswordSecurity) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Flow != "" { + info = append(info, yaml.MapItem{"flow", m.Flow}) + } + if m.Scopes != nil { + info = append(info, yaml.MapItem{"scopes", m.Scopes.ToRawInfo()}) + } + // &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.TokenUrl != "" { + info = append(info, yaml.MapItem{"tokenUrl", m.TokenUrl}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Oauth2Scopes suitable for JSON or YAML export. +func (m *Oauth2Scopes) ToRawInfo() interface{} { + info := yaml.MapSlice{} + // &{Name:additionalProperties Type:NamedString StringEnumValues:[] MapType:string Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Operation suitable for JSON or YAML export. +func (m *Operation) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if len(m.Tags) != 0 { + info = append(info, yaml.MapItem{"tags", m.Tags}) + } + if m.Summary != "" { + info = append(info, yaml.MapItem{"summary", m.Summary}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{"externalDocs", m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.OperationId != "" { + info = append(info, yaml.MapItem{"operationId", m.OperationId}) + } + if len(m.Produces) != 0 { + info = append(info, yaml.MapItem{"produces", m.Produces}) + } + if len(m.Consumes) != 0 { + info = append(info, yaml.MapItem{"consumes", m.Consumes}) + } + if len(m.Parameters) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Parameters { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"parameters", items}) + } + // &{Name:parameters Type:ParametersItem StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:The parameters needed to send a valid API call.} + if m.Responses != nil { + info = append(info, yaml.MapItem{"responses", m.Responses.ToRawInfo()}) + } + // &{Name:responses Type:Responses StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Schemes) != 0 { + info = append(info, yaml.MapItem{"schemes", m.Schemes}) + } + if m.Deprecated != false { + info = append(info, yaml.MapItem{"deprecated", m.Deprecated}) + } + if len(m.Security) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Security { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"security", items}) + } + // &{Name:security Type:SecurityRequirement StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Parameter suitable for JSON or YAML export. +func (m *Parameter) ToRawInfo() interface{} { + // ONE OF WRAPPER + // Parameter + // {Name:bodyParameter Type:BodyParameter StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetBodyParameter() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:nonBodyParameter Type:NonBodyParameter StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetNonBodyParameter() + if v1 != nil { + return v1.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of ParameterDefinitions suitable for JSON or YAML export. +func (m *ParameterDefinitions) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedParameter StringEnumValues:[] MapType:Parameter Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ParametersItem suitable for JSON or YAML export. +func (m *ParametersItem) ToRawInfo() interface{} { + // ONE OF WRAPPER + // ParametersItem + // {Name:parameter Type:Parameter StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetParameter() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:jsonReference Type:JsonReference StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetJsonReference() + if v1 != nil { + return v1.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of PathItem suitable for JSON or YAML export. +func (m *PathItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.XRef != "" { + info = append(info, yaml.MapItem{"$ref", m.XRef}) + } + if m.Get != nil { + info = append(info, yaml.MapItem{"get", m.Get.ToRawInfo()}) + } + // &{Name:get Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Put != nil { + info = append(info, yaml.MapItem{"put", m.Put.ToRawInfo()}) + } + // &{Name:put Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Post != nil { + info = append(info, yaml.MapItem{"post", m.Post.ToRawInfo()}) + } + // &{Name:post Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Delete != nil { + info = append(info, yaml.MapItem{"delete", m.Delete.ToRawInfo()}) + } + // &{Name:delete Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Options != nil { + info = append(info, yaml.MapItem{"options", m.Options.ToRawInfo()}) + } + // &{Name:options Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Head != nil { + info = append(info, yaml.MapItem{"head", m.Head.ToRawInfo()}) + } + // &{Name:head Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Patch != nil { + info = append(info, yaml.MapItem{"patch", m.Patch.ToRawInfo()}) + } + // &{Name:patch Type:Operation StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.Parameters) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Parameters { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"parameters", items}) + } + // &{Name:parameters Type:ParametersItem StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:The parameters needed to send a valid API call.} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of PathParameterSubSchema suitable for JSON or YAML export. +func (m *PathParameterSubSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Required != false { + info = append(info, yaml.MapItem{"required", m.Required}) + } + if m.In != "" { + info = append(info, yaml.MapItem{"in", m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{"format", m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{"items", m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{"collectionFormat", m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{"default", m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{"maximum", m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{"exclusiveMaximum", m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{"minimum", m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{"exclusiveMinimum", m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{"maxLength", m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{"minLength", m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{"pattern", m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{"maxItems", m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{"minItems", m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{"uniqueItems", m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"enum", items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{"multipleOf", m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Paths suitable for JSON or YAML export. +func (m *Paths) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + if m.Path != nil { + for _, item := range m.Path { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:Path Type:NamedPathItem StringEnumValues:[] MapType:PathItem Repeated:true Pattern:^/ Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of PrimitivesItems suitable for JSON or YAML export. +func (m *PrimitivesItems) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{"format", m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{"items", m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{"collectionFormat", m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{"default", m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{"maximum", m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{"exclusiveMaximum", m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{"minimum", m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{"exclusiveMinimum", m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{"maxLength", m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{"minLength", m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{"pattern", m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{"maxItems", m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{"minItems", m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{"uniqueItems", m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"enum", items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{"multipleOf", m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Properties suitable for JSON or YAML export. +func (m *Properties) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedSchema StringEnumValues:[] MapType:Schema Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of QueryParameterSubSchema suitable for JSON or YAML export. +func (m *QueryParameterSubSchema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Required != false { + info = append(info, yaml.MapItem{"required", m.Required}) + } + if m.In != "" { + info = append(info, yaml.MapItem{"in", m.In}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.AllowEmptyValue != false { + info = append(info, yaml.MapItem{"allowEmptyValue", m.AllowEmptyValue}) + } + if m.Type != "" { + info = append(info, yaml.MapItem{"type", m.Type}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{"format", m.Format}) + } + if m.Items != nil { + info = append(info, yaml.MapItem{"items", m.Items.ToRawInfo()}) + } + // &{Name:items Type:PrimitivesItems StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.CollectionFormat != "" { + info = append(info, yaml.MapItem{"collectionFormat", m.CollectionFormat}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{"default", m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{"maximum", m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{"exclusiveMaximum", m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{"minimum", m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{"exclusiveMinimum", m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{"maxLength", m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{"minLength", m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{"pattern", m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{"maxItems", m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{"minItems", m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{"uniqueItems", m.UniqueItems}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"enum", items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{"multipleOf", m.MultipleOf}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Response suitable for JSON or YAML export. +func (m *Response) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.Schema != nil { + info = append(info, yaml.MapItem{"schema", m.Schema.ToRawInfo()}) + } + // &{Name:schema Type:SchemaItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Headers != nil { + info = append(info, yaml.MapItem{"headers", m.Headers.ToRawInfo()}) + } + // &{Name:headers Type:Headers StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Examples != nil { + info = append(info, yaml.MapItem{"examples", m.Examples.ToRawInfo()}) + } + // &{Name:examples Type:Examples StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ResponseDefinitions suitable for JSON or YAML export. +func (m *ResponseDefinitions) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedResponse StringEnumValues:[] MapType:Response Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of ResponseValue suitable for JSON or YAML export. +func (m *ResponseValue) ToRawInfo() interface{} { + // ONE OF WRAPPER + // ResponseValue + // {Name:response Type:Response StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetResponse() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:jsonReference Type:JsonReference StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetJsonReference() + if v1 != nil { + return v1.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of Responses suitable for JSON or YAML export. +func (m *Responses) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.ResponseCode != nil { + for _, item := range m.ResponseCode { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:ResponseCode Type:NamedResponseValue StringEnumValues:[] MapType:ResponseValue Repeated:true Pattern:^([0-9]{3})$|^(default)$ Implicit:true Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Schema suitable for JSON or YAML export. +func (m *Schema) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.XRef != "" { + info = append(info, yaml.MapItem{"$ref", m.XRef}) + } + if m.Format != "" { + info = append(info, yaml.MapItem{"format", m.Format}) + } + if m.Title != "" { + info = append(info, yaml.MapItem{"title", m.Title}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.Default != nil { + info = append(info, yaml.MapItem{"default", m.Default.ToRawInfo()}) + } + // &{Name:default Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.MultipleOf != 0.0 { + info = append(info, yaml.MapItem{"multipleOf", m.MultipleOf}) + } + if m.Maximum != 0.0 { + info = append(info, yaml.MapItem{"maximum", m.Maximum}) + } + if m.ExclusiveMaximum != false { + info = append(info, yaml.MapItem{"exclusiveMaximum", m.ExclusiveMaximum}) + } + if m.Minimum != 0.0 { + info = append(info, yaml.MapItem{"minimum", m.Minimum}) + } + if m.ExclusiveMinimum != false { + info = append(info, yaml.MapItem{"exclusiveMinimum", m.ExclusiveMinimum}) + } + if m.MaxLength != 0 { + info = append(info, yaml.MapItem{"maxLength", m.MaxLength}) + } + if m.MinLength != 0 { + info = append(info, yaml.MapItem{"minLength", m.MinLength}) + } + if m.Pattern != "" { + info = append(info, yaml.MapItem{"pattern", m.Pattern}) + } + if m.MaxItems != 0 { + info = append(info, yaml.MapItem{"maxItems", m.MaxItems}) + } + if m.MinItems != 0 { + info = append(info, yaml.MapItem{"minItems", m.MinItems}) + } + if m.UniqueItems != false { + info = append(info, yaml.MapItem{"uniqueItems", m.UniqueItems}) + } + if m.MaxProperties != 0 { + info = append(info, yaml.MapItem{"maxProperties", m.MaxProperties}) + } + if m.MinProperties != 0 { + info = append(info, yaml.MapItem{"minProperties", m.MinProperties}) + } + if len(m.Required) != 0 { + info = append(info, yaml.MapItem{"required", m.Required}) + } + if len(m.Enum) != 0 { + items := make([]interface{}, 0) + for _, item := range m.Enum { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"enum", items}) + } + // &{Name:enum Type:Any StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.AdditionalProperties != nil { + info = append(info, yaml.MapItem{"additionalProperties", m.AdditionalProperties.ToRawInfo()}) + } + // &{Name:additionalProperties Type:AdditionalPropertiesItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Type != nil { + if len(m.Type.Value) == 1 { + info = append(info, yaml.MapItem{"type", m.Type.Value[0]}) + } else { + info = append(info, yaml.MapItem{"type", m.Type.Value}) + } + } + // &{Name:type Type:TypeItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Items != nil { + items := make([]interface{}, 0) + for _, item := range m.Items.Schema { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"items", items[0]}) + } + // &{Name:items Type:ItemsItem StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if len(m.AllOf) != 0 { + items := make([]interface{}, 0) + for _, item := range m.AllOf { + items = append(items, item.ToRawInfo()) + } + info = append(info, yaml.MapItem{"allOf", items}) + } + // &{Name:allOf Type:Schema StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:} + if m.Properties != nil { + info = append(info, yaml.MapItem{"properties", m.Properties.ToRawInfo()}) + } + // &{Name:properties Type:Properties StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Discriminator != "" { + info = append(info, yaml.MapItem{"discriminator", m.Discriminator}) + } + if m.ReadOnly != false { + info = append(info, yaml.MapItem{"readOnly", m.ReadOnly}) + } + if m.Xml != nil { + info = append(info, yaml.MapItem{"xml", m.Xml.ToRawInfo()}) + } + // &{Name:xml Type:Xml StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{"externalDocs", m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.Example != nil { + info = append(info, yaml.MapItem{"example", m.Example.ToRawInfo()}) + } + // &{Name:example Type:Any StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of SchemaItem suitable for JSON or YAML export. +func (m *SchemaItem) ToRawInfo() interface{} { + // ONE OF WRAPPER + // SchemaItem + // {Name:schema Type:Schema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetSchema() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:fileSchema Type:FileSchema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetFileSchema() + if v1 != nil { + return v1.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of SecurityDefinitions suitable for JSON or YAML export. +func (m *SecurityDefinitions) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedSecurityDefinitionsItem StringEnumValues:[] MapType:SecurityDefinitionsItem Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of SecurityDefinitionsItem suitable for JSON or YAML export. +func (m *SecurityDefinitionsItem) ToRawInfo() interface{} { + // ONE OF WRAPPER + // SecurityDefinitionsItem + // {Name:basicAuthenticationSecurity Type:BasicAuthenticationSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v0 := m.GetBasicAuthenticationSecurity() + if v0 != nil { + return v0.ToRawInfo() + } + // {Name:apiKeySecurity Type:ApiKeySecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v1 := m.GetApiKeySecurity() + if v1 != nil { + return v1.ToRawInfo() + } + // {Name:oauth2ImplicitSecurity Type:Oauth2ImplicitSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v2 := m.GetOauth2ImplicitSecurity() + if v2 != nil { + return v2.ToRawInfo() + } + // {Name:oauth2PasswordSecurity Type:Oauth2PasswordSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v3 := m.GetOauth2PasswordSecurity() + if v3 != nil { + return v3.ToRawInfo() + } + // {Name:oauth2ApplicationSecurity Type:Oauth2ApplicationSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v4 := m.GetOauth2ApplicationSecurity() + if v4 != nil { + return v4.ToRawInfo() + } + // {Name:oauth2AccessCodeSecurity Type:Oauth2AccessCodeSecurity StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + v5 := m.GetOauth2AccessCodeSecurity() + if v5 != nil { + return v5.ToRawInfo() + } + return nil +} + +// ToRawInfo returns a description of SecurityRequirement suitable for JSON or YAML export. +func (m *SecurityRequirement) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedStringArray StringEnumValues:[] MapType:StringArray Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of StringArray suitable for JSON or YAML export. +func (m *StringArray) ToRawInfo() interface{} { + return m.Value +} + +// ToRawInfo returns a description of Tag suitable for JSON or YAML export. +func (m *Tag) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.Description != "" { + info = append(info, yaml.MapItem{"description", m.Description}) + } + if m.ExternalDocs != nil { + info = append(info, yaml.MapItem{"externalDocs", m.ExternalDocs.ToRawInfo()}) + } + // &{Name:externalDocs Type:ExternalDocs StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:} + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of TypeItem suitable for JSON or YAML export. +func (m *TypeItem) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if len(m.Value) != 0 { + info = append(info, yaml.MapItem{"value", m.Value}) + } + return info +} + +// ToRawInfo returns a description of VendorExtension suitable for JSON or YAML export. +func (m *VendorExtension) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.AdditionalProperties != nil { + for _, item := range m.AdditionalProperties { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:additionalProperties Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern: Implicit:true Description:} + return info +} + +// ToRawInfo returns a description of Xml suitable for JSON or YAML export. +func (m *Xml) ToRawInfo() interface{} { + info := yaml.MapSlice{} + if m.Name != "" { + info = append(info, yaml.MapItem{"name", m.Name}) + } + if m.Namespace != "" { + info = append(info, yaml.MapItem{"namespace", m.Namespace}) + } + if m.Prefix != "" { + info = append(info, yaml.MapItem{"prefix", m.Prefix}) + } + if m.Attribute != false { + info = append(info, yaml.MapItem{"attribute", m.Attribute}) + } + if m.Wrapped != false { + info = append(info, yaml.MapItem{"wrapped", m.Wrapped}) + } + if m.VendorExtension != nil { + for _, item := range m.VendorExtension { + info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()}) + } + } + // &{Name:VendorExtension Type:NamedAny StringEnumValues:[] MapType:Any Repeated:true Pattern:^x- Implicit:true Description:} + return info +} + +var ( + pattern0 = regexp.MustCompile("^x-") + pattern1 = regexp.MustCompile("^/") + pattern2 = regexp.MustCompile("^([0-9]{3})$|^(default)$") +) diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.pb.go b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.pb.go new file mode 100644 index 000000000..37da7df25 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.pb.go @@ -0,0 +1,4456 @@ +// Code generated by protoc-gen-go. +// source: OpenAPIv2/OpenAPIv2.proto +// DO NOT EDIT! + +/* +Package openapi_v2 is a generated protocol buffer package. + +It is generated from these files: + OpenAPIv2/OpenAPIv2.proto + +It has these top-level messages: + AdditionalPropertiesItem + Any + ApiKeySecurity + BasicAuthenticationSecurity + BodyParameter + Contact + Default + Definitions + Document + Examples + ExternalDocs + FileSchema + FormDataParameterSubSchema + Header + HeaderParameterSubSchema + Headers + Info + ItemsItem + JsonReference + License + NamedAny + NamedHeader + NamedParameter + NamedPathItem + NamedResponse + NamedResponseValue + NamedSchema + NamedSecurityDefinitionsItem + NamedString + NamedStringArray + NonBodyParameter + Oauth2AccessCodeSecurity + Oauth2ApplicationSecurity + Oauth2ImplicitSecurity + Oauth2PasswordSecurity + Oauth2Scopes + Operation + Parameter + ParameterDefinitions + ParametersItem + PathItem + PathParameterSubSchema + Paths + PrimitivesItems + Properties + QueryParameterSubSchema + Response + ResponseDefinitions + ResponseValue + Responses + Schema + SchemaItem + SecurityDefinitions + SecurityDefinitionsItem + SecurityRequirement + StringArray + Tag + TypeItem + VendorExtension + Xml +*/ +package openapi_v2 + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import google_protobuf "github.com/golang/protobuf/ptypes/any" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type AdditionalPropertiesItem struct { + // Types that are valid to be assigned to Oneof: + // *AdditionalPropertiesItem_Schema + // *AdditionalPropertiesItem_Boolean + Oneof isAdditionalPropertiesItem_Oneof `protobuf_oneof:"oneof"` +} + +func (m *AdditionalPropertiesItem) Reset() { *m = AdditionalPropertiesItem{} } +func (m *AdditionalPropertiesItem) String() string { return proto.CompactTextString(m) } +func (*AdditionalPropertiesItem) ProtoMessage() {} +func (*AdditionalPropertiesItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +type isAdditionalPropertiesItem_Oneof interface { + isAdditionalPropertiesItem_Oneof() +} + +type AdditionalPropertiesItem_Schema struct { + Schema *Schema `protobuf:"bytes,1,opt,name=schema,oneof"` +} +type AdditionalPropertiesItem_Boolean struct { + Boolean bool `protobuf:"varint,2,opt,name=boolean,oneof"` +} + +func (*AdditionalPropertiesItem_Schema) isAdditionalPropertiesItem_Oneof() {} +func (*AdditionalPropertiesItem_Boolean) isAdditionalPropertiesItem_Oneof() {} + +func (m *AdditionalPropertiesItem) GetOneof() isAdditionalPropertiesItem_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *AdditionalPropertiesItem) GetSchema() *Schema { + if x, ok := m.GetOneof().(*AdditionalPropertiesItem_Schema); ok { + return x.Schema + } + return nil +} + +func (m *AdditionalPropertiesItem) GetBoolean() bool { + if x, ok := m.GetOneof().(*AdditionalPropertiesItem_Boolean); ok { + return x.Boolean + } + return false +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*AdditionalPropertiesItem) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _AdditionalPropertiesItem_OneofMarshaler, _AdditionalPropertiesItem_OneofUnmarshaler, _AdditionalPropertiesItem_OneofSizer, []interface{}{ + (*AdditionalPropertiesItem_Schema)(nil), + (*AdditionalPropertiesItem_Boolean)(nil), + } +} + +func _AdditionalPropertiesItem_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*AdditionalPropertiesItem) + // oneof + switch x := m.Oneof.(type) { + case *AdditionalPropertiesItem_Schema: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Schema); err != nil { + return err + } + case *AdditionalPropertiesItem_Boolean: + t := uint64(0) + if x.Boolean { + t = 1 + } + b.EncodeVarint(2<<3 | proto.WireVarint) + b.EncodeVarint(t) + case nil: + default: + return fmt.Errorf("AdditionalPropertiesItem.Oneof has unexpected type %T", x) + } + return nil +} + +func _AdditionalPropertiesItem_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*AdditionalPropertiesItem) + switch tag { + case 1: // oneof.schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Schema) + err := b.DecodeMessage(msg) + m.Oneof = &AdditionalPropertiesItem_Schema{msg} + return true, err + case 2: // oneof.boolean + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Oneof = &AdditionalPropertiesItem_Boolean{x != 0} + return true, err + default: + return false, nil + } +} + +func _AdditionalPropertiesItem_OneofSizer(msg proto.Message) (n int) { + m := msg.(*AdditionalPropertiesItem) + // oneof + switch x := m.Oneof.(type) { + case *AdditionalPropertiesItem_Schema: + s := proto.Size(x.Schema) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *AdditionalPropertiesItem_Boolean: + n += proto.SizeVarint(2<<3 | proto.WireVarint) + n += 1 + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type Any struct { + Value *google_protobuf.Any `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + Yaml string `protobuf:"bytes,2,opt,name=yaml" json:"yaml,omitempty"` +} + +func (m *Any) Reset() { *m = Any{} } +func (m *Any) String() string { return proto.CompactTextString(m) } +func (*Any) ProtoMessage() {} +func (*Any) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *Any) GetValue() *google_protobuf.Any { + if m != nil { + return m.Value + } + return nil +} + +func (m *Any) GetYaml() string { + if m != nil { + return m.Yaml + } + return "" +} + +type ApiKeySecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + In string `protobuf:"bytes,3,opt,name=in" json:"in,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,5,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *ApiKeySecurity) Reset() { *m = ApiKeySecurity{} } +func (m *ApiKeySecurity) String() string { return proto.CompactTextString(m) } +func (*ApiKeySecurity) ProtoMessage() {} +func (*ApiKeySecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *ApiKeySecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *ApiKeySecurity) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ApiKeySecurity) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *ApiKeySecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *ApiKeySecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type BasicAuthenticationSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,3,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *BasicAuthenticationSecurity) Reset() { *m = BasicAuthenticationSecurity{} } +func (m *BasicAuthenticationSecurity) String() string { return proto.CompactTextString(m) } +func (*BasicAuthenticationSecurity) ProtoMessage() {} +func (*BasicAuthenticationSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *BasicAuthenticationSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *BasicAuthenticationSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *BasicAuthenticationSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type BodyParameter struct { + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,1,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,3,opt,name=in" json:"in,omitempty"` + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,4,opt,name=required" json:"required,omitempty"` + Schema *Schema `protobuf:"bytes,5,opt,name=schema" json:"schema,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *BodyParameter) Reset() { *m = BodyParameter{} } +func (m *BodyParameter) String() string { return proto.CompactTextString(m) } +func (*BodyParameter) ProtoMessage() {} +func (*BodyParameter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *BodyParameter) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *BodyParameter) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *BodyParameter) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *BodyParameter) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *BodyParameter) GetSchema() *Schema { + if m != nil { + return m.Schema + } + return nil +} + +func (m *BodyParameter) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// Contact information for the owners of the API. +type Contact struct { + // The identifying name of the contact person/organization. + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // The URL pointing to the contact information. + Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"` + // The email address of the contact person/organization. + Email string `protobuf:"bytes,3,opt,name=email" json:"email,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,4,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Contact) Reset() { *m = Contact{} } +func (m *Contact) String() string { return proto.CompactTextString(m) } +func (*Contact) ProtoMessage() {} +func (*Contact) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *Contact) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Contact) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *Contact) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *Contact) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Default struct { + AdditionalProperties []*NamedAny `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Default) Reset() { *m = Default{} } +func (m *Default) String() string { return proto.CompactTextString(m) } +func (*Default) ProtoMessage() {} +func (*Default) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *Default) GetAdditionalProperties() []*NamedAny { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +// One or more JSON objects describing the schemas being consumed and produced by the API. +type Definitions struct { + AdditionalProperties []*NamedSchema `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Definitions) Reset() { *m = Definitions{} } +func (m *Definitions) String() string { return proto.CompactTextString(m) } +func (*Definitions) ProtoMessage() {} +func (*Definitions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *Definitions) GetAdditionalProperties() []*NamedSchema { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type Document struct { + // The Swagger version of this document. + Swagger string `protobuf:"bytes,1,opt,name=swagger" json:"swagger,omitempty"` + Info *Info `protobuf:"bytes,2,opt,name=info" json:"info,omitempty"` + // The host (name or ip) of the API. Example: 'swagger.io' + Host string `protobuf:"bytes,3,opt,name=host" json:"host,omitempty"` + // The base path to the API. Example: '/api'. + BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath" json:"base_path,omitempty"` + // The transfer protocol of the API. + Schemes []string `protobuf:"bytes,5,rep,name=schemes" json:"schemes,omitempty"` + // A list of MIME types accepted by the API. + Consumes []string `protobuf:"bytes,6,rep,name=consumes" json:"consumes,omitempty"` + // A list of MIME types the API can produce. + Produces []string `protobuf:"bytes,7,rep,name=produces" json:"produces,omitempty"` + Paths *Paths `protobuf:"bytes,8,opt,name=paths" json:"paths,omitempty"` + Definitions *Definitions `protobuf:"bytes,9,opt,name=definitions" json:"definitions,omitempty"` + Parameters *ParameterDefinitions `protobuf:"bytes,10,opt,name=parameters" json:"parameters,omitempty"` + Responses *ResponseDefinitions `protobuf:"bytes,11,opt,name=responses" json:"responses,omitempty"` + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security" json:"security,omitempty"` + SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,13,opt,name=security_definitions,json=securityDefinitions" json:"security_definitions,omitempty"` + Tags []*Tag `protobuf:"bytes,14,rep,name=tags" json:"tags,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,15,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,16,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Document) Reset() { *m = Document{} } +func (m *Document) String() string { return proto.CompactTextString(m) } +func (*Document) ProtoMessage() {} +func (*Document) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *Document) GetSwagger() string { + if m != nil { + return m.Swagger + } + return "" +} + +func (m *Document) GetInfo() *Info { + if m != nil { + return m.Info + } + return nil +} + +func (m *Document) GetHost() string { + if m != nil { + return m.Host + } + return "" +} + +func (m *Document) GetBasePath() string { + if m != nil { + return m.BasePath + } + return "" +} + +func (m *Document) GetSchemes() []string { + if m != nil { + return m.Schemes + } + return nil +} + +func (m *Document) GetConsumes() []string { + if m != nil { + return m.Consumes + } + return nil +} + +func (m *Document) GetProduces() []string { + if m != nil { + return m.Produces + } + return nil +} + +func (m *Document) GetPaths() *Paths { + if m != nil { + return m.Paths + } + return nil +} + +func (m *Document) GetDefinitions() *Definitions { + if m != nil { + return m.Definitions + } + return nil +} + +func (m *Document) GetParameters() *ParameterDefinitions { + if m != nil { + return m.Parameters + } + return nil +} + +func (m *Document) GetResponses() *ResponseDefinitions { + if m != nil { + return m.Responses + } + return nil +} + +func (m *Document) GetSecurity() []*SecurityRequirement { + if m != nil { + return m.Security + } + return nil +} + +func (m *Document) GetSecurityDefinitions() *SecurityDefinitions { + if m != nil { + return m.SecurityDefinitions + } + return nil +} + +func (m *Document) GetTags() []*Tag { + if m != nil { + return m.Tags + } + return nil +} + +func (m *Document) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *Document) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Examples struct { + AdditionalProperties []*NamedAny `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Examples) Reset() { *m = Examples{} } +func (m *Examples) String() string { return proto.CompactTextString(m) } +func (*Examples) ProtoMessage() {} +func (*Examples) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } + +func (m *Examples) GetAdditionalProperties() []*NamedAny { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +// information about external documentation +type ExternalDocs struct { + Description string `protobuf:"bytes,1,opt,name=description" json:"description,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,3,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *ExternalDocs) Reset() { *m = ExternalDocs{} } +func (m *ExternalDocs) String() string { return proto.CompactTextString(m) } +func (*ExternalDocs) ProtoMessage() {} +func (*ExternalDocs) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } + +func (m *ExternalDocs) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *ExternalDocs) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *ExternalDocs) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// A deterministic version of a JSON Schema object. +type FileSchema struct { + Format string `protobuf:"bytes,1,opt,name=format" json:"format,omitempty"` + Title string `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + Default *Any `protobuf:"bytes,4,opt,name=default" json:"default,omitempty"` + Required []string `protobuf:"bytes,5,rep,name=required" json:"required,omitempty"` + Type string `protobuf:"bytes,6,opt,name=type" json:"type,omitempty"` + ReadOnly bool `protobuf:"varint,7,opt,name=read_only,json=readOnly" json:"read_only,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,8,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + Example *Any `protobuf:"bytes,9,opt,name=example" json:"example,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,10,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *FileSchema) Reset() { *m = FileSchema{} } +func (m *FileSchema) String() string { return proto.CompactTextString(m) } +func (*FileSchema) ProtoMessage() {} +func (*FileSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +func (m *FileSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *FileSchema) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *FileSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *FileSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *FileSchema) GetRequired() []string { + if m != nil { + return m.Required + } + return nil +} + +func (m *FileSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *FileSchema) GetReadOnly() bool { + if m != nil { + return m.ReadOnly + } + return false +} + +func (m *FileSchema) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *FileSchema) GetExample() *Any { + if m != nil { + return m.Example + } + return nil +} + +func (m *FileSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type FormDataParameterSubSchema struct { + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,1,opt,name=required" json:"required,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,2,opt,name=in" json:"in,omitempty"` + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` + // allows sending a parameter by name only or with an empty value. + AllowEmptyValue bool `protobuf:"varint,5,opt,name=allow_empty_value,json=allowEmptyValue" json:"allow_empty_value,omitempty"` + Type string `protobuf:"bytes,6,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,7,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,8,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,9,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,10,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,11,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,13,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,15,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,16,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,17,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,18,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,19,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,20,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,21,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,22,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,23,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *FormDataParameterSubSchema) Reset() { *m = FormDataParameterSubSchema{} } +func (m *FormDataParameterSubSchema) String() string { return proto.CompactTextString(m) } +func (*FormDataParameterSubSchema) ProtoMessage() {} +func (*FormDataParameterSubSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } + +func (m *FormDataParameterSubSchema) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *FormDataParameterSubSchema) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *FormDataParameterSubSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *FormDataParameterSubSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *FormDataParameterSubSchema) GetAllowEmptyValue() bool { + if m != nil { + return m.AllowEmptyValue + } + return false +} + +func (m *FormDataParameterSubSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *FormDataParameterSubSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *FormDataParameterSubSchema) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *FormDataParameterSubSchema) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *FormDataParameterSubSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *FormDataParameterSubSchema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *FormDataParameterSubSchema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *FormDataParameterSubSchema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *FormDataParameterSubSchema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *FormDataParameterSubSchema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *FormDataParameterSubSchema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *FormDataParameterSubSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Header struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,2,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,3,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,4,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,5,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,6,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,7,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,8,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,9,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,10,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,11,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,12,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,13,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,14,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,15,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,16,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,17,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + Description string `protobuf:"bytes,18,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,19,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Header) Reset() { *m = Header{} } +func (m *Header) String() string { return proto.CompactTextString(m) } +func (*Header) ProtoMessage() {} +func (*Header) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } + +func (m *Header) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Header) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *Header) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *Header) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *Header) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *Header) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *Header) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *Header) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *Header) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *Header) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *Header) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *Header) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *Header) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *Header) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *Header) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *Header) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *Header) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *Header) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Header) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type HeaderParameterSubSchema struct { + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,1,opt,name=required" json:"required,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,2,opt,name=in" json:"in,omitempty"` + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` + Type string `protobuf:"bytes,5,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,6,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,7,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,8,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,9,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,10,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,11,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,12,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,13,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,14,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,15,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,16,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,17,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,18,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,19,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,20,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,21,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,22,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *HeaderParameterSubSchema) Reset() { *m = HeaderParameterSubSchema{} } +func (m *HeaderParameterSubSchema) String() string { return proto.CompactTextString(m) } +func (*HeaderParameterSubSchema) ProtoMessage() {} +func (*HeaderParameterSubSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } + +func (m *HeaderParameterSubSchema) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *HeaderParameterSubSchema) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *HeaderParameterSubSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *HeaderParameterSubSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *HeaderParameterSubSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *HeaderParameterSubSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *HeaderParameterSubSchema) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *HeaderParameterSubSchema) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *HeaderParameterSubSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *HeaderParameterSubSchema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *HeaderParameterSubSchema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *HeaderParameterSubSchema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *HeaderParameterSubSchema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *HeaderParameterSubSchema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *HeaderParameterSubSchema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *HeaderParameterSubSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Headers struct { + AdditionalProperties []*NamedHeader `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Headers) Reset() { *m = Headers{} } +func (m *Headers) String() string { return proto.CompactTextString(m) } +func (*Headers) ProtoMessage() {} +func (*Headers) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } + +func (m *Headers) GetAdditionalProperties() []*NamedHeader { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +// General information about the API. +type Info struct { + // A unique and precise title of the API. + Title string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"` + // A semantic version number of the API. + Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` + // A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The terms of service for the API. + TermsOfService string `protobuf:"bytes,4,opt,name=terms_of_service,json=termsOfService" json:"terms_of_service,omitempty"` + Contact *Contact `protobuf:"bytes,5,opt,name=contact" json:"contact,omitempty"` + License *License `protobuf:"bytes,6,opt,name=license" json:"license,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,7,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Info) Reset() { *m = Info{} } +func (m *Info) String() string { return proto.CompactTextString(m) } +func (*Info) ProtoMessage() {} +func (*Info) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } + +func (m *Info) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *Info) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *Info) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Info) GetTermsOfService() string { + if m != nil { + return m.TermsOfService + } + return "" +} + +func (m *Info) GetContact() *Contact { + if m != nil { + return m.Contact + } + return nil +} + +func (m *Info) GetLicense() *License { + if m != nil { + return m.License + } + return nil +} + +func (m *Info) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type ItemsItem struct { + Schema []*Schema `protobuf:"bytes,1,rep,name=schema" json:"schema,omitempty"` +} + +func (m *ItemsItem) Reset() { *m = ItemsItem{} } +func (m *ItemsItem) String() string { return proto.CompactTextString(m) } +func (*ItemsItem) ProtoMessage() {} +func (*ItemsItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } + +func (m *ItemsItem) GetSchema() []*Schema { + if m != nil { + return m.Schema + } + return nil +} + +type JsonReference struct { + XRef string `protobuf:"bytes,1,opt,name=_ref,json=Ref" json:"_ref,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` +} + +func (m *JsonReference) Reset() { *m = JsonReference{} } +func (m *JsonReference) String() string { return proto.CompactTextString(m) } +func (*JsonReference) ProtoMessage() {} +func (*JsonReference) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } + +func (m *JsonReference) GetXRef() string { + if m != nil { + return m.XRef + } + return "" +} + +func (m *JsonReference) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +type License struct { + // The name of the license type. It's encouraged to use an OSI compatible license. + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // The URL pointing to the license. + Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,3,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *License) Reset() { *m = License{} } +func (m *License) String() string { return proto.CompactTextString(m) } +func (*License) ProtoMessage() {} +func (*License) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } + +func (m *License) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *License) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *License) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// Automatically-generated message used to represent maps of Any as ordered (name,value) pairs. +type NamedAny struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Any `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedAny) Reset() { *m = NamedAny{} } +func (m *NamedAny) String() string { return proto.CompactTextString(m) } +func (*NamedAny) ProtoMessage() {} +func (*NamedAny) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} } + +func (m *NamedAny) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedAny) GetValue() *Any { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of Header as ordered (name,value) pairs. +type NamedHeader struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Header `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedHeader) Reset() { *m = NamedHeader{} } +func (m *NamedHeader) String() string { return proto.CompactTextString(m) } +func (*NamedHeader) ProtoMessage() {} +func (*NamedHeader) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} } + +func (m *NamedHeader) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedHeader) GetValue() *Header { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of Parameter as ordered (name,value) pairs. +type NamedParameter struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Parameter `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedParameter) Reset() { *m = NamedParameter{} } +func (m *NamedParameter) String() string { return proto.CompactTextString(m) } +func (*NamedParameter) ProtoMessage() {} +func (*NamedParameter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} } + +func (m *NamedParameter) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedParameter) GetValue() *Parameter { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of PathItem as ordered (name,value) pairs. +type NamedPathItem struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *PathItem `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedPathItem) Reset() { *m = NamedPathItem{} } +func (m *NamedPathItem) String() string { return proto.CompactTextString(m) } +func (*NamedPathItem) ProtoMessage() {} +func (*NamedPathItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} } + +func (m *NamedPathItem) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedPathItem) GetValue() *PathItem { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of Response as ordered (name,value) pairs. +type NamedResponse struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Response `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedResponse) Reset() { *m = NamedResponse{} } +func (m *NamedResponse) String() string { return proto.CompactTextString(m) } +func (*NamedResponse) ProtoMessage() {} +func (*NamedResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} } + +func (m *NamedResponse) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedResponse) GetValue() *Response { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of ResponseValue as ordered (name,value) pairs. +type NamedResponseValue struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *ResponseValue `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedResponseValue) Reset() { *m = NamedResponseValue{} } +func (m *NamedResponseValue) String() string { return proto.CompactTextString(m) } +func (*NamedResponseValue) ProtoMessage() {} +func (*NamedResponseValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25} } + +func (m *NamedResponseValue) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedResponseValue) GetValue() *ResponseValue { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of Schema as ordered (name,value) pairs. +type NamedSchema struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *Schema `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedSchema) Reset() { *m = NamedSchema{} } +func (m *NamedSchema) String() string { return proto.CompactTextString(m) } +func (*NamedSchema) ProtoMessage() {} +func (*NamedSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} } + +func (m *NamedSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedSchema) GetValue() *Schema { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of SecurityDefinitionsItem as ordered (name,value) pairs. +type NamedSecurityDefinitionsItem struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *SecurityDefinitionsItem `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedSecurityDefinitionsItem) Reset() { *m = NamedSecurityDefinitionsItem{} } +func (m *NamedSecurityDefinitionsItem) String() string { return proto.CompactTextString(m) } +func (*NamedSecurityDefinitionsItem) ProtoMessage() {} +func (*NamedSecurityDefinitionsItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} } + +func (m *NamedSecurityDefinitionsItem) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedSecurityDefinitionsItem) GetValue() *SecurityDefinitionsItem { + if m != nil { + return m.Value + } + return nil +} + +// Automatically-generated message used to represent maps of string as ordered (name,value) pairs. +type NamedString struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedString) Reset() { *m = NamedString{} } +func (m *NamedString) String() string { return proto.CompactTextString(m) } +func (*NamedString) ProtoMessage() {} +func (*NamedString) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} } + +func (m *NamedString) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedString) GetValue() string { + if m != nil { + return m.Value + } + return "" +} + +// Automatically-generated message used to represent maps of StringArray as ordered (name,value) pairs. +type NamedStringArray struct { + // Map key + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Mapped value + Value *StringArray `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *NamedStringArray) Reset() { *m = NamedStringArray{} } +func (m *NamedStringArray) String() string { return proto.CompactTextString(m) } +func (*NamedStringArray) ProtoMessage() {} +func (*NamedStringArray) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} } + +func (m *NamedStringArray) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NamedStringArray) GetValue() *StringArray { + if m != nil { + return m.Value + } + return nil +} + +type NonBodyParameter struct { + // Types that are valid to be assigned to Oneof: + // *NonBodyParameter_HeaderParameterSubSchema + // *NonBodyParameter_FormDataParameterSubSchema + // *NonBodyParameter_QueryParameterSubSchema + // *NonBodyParameter_PathParameterSubSchema + Oneof isNonBodyParameter_Oneof `protobuf_oneof:"oneof"` +} + +func (m *NonBodyParameter) Reset() { *m = NonBodyParameter{} } +func (m *NonBodyParameter) String() string { return proto.CompactTextString(m) } +func (*NonBodyParameter) ProtoMessage() {} +func (*NonBodyParameter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} } + +type isNonBodyParameter_Oneof interface { + isNonBodyParameter_Oneof() +} + +type NonBodyParameter_HeaderParameterSubSchema struct { + HeaderParameterSubSchema *HeaderParameterSubSchema `protobuf:"bytes,1,opt,name=header_parameter_sub_schema,json=headerParameterSubSchema,oneof"` +} +type NonBodyParameter_FormDataParameterSubSchema struct { + FormDataParameterSubSchema *FormDataParameterSubSchema `protobuf:"bytes,2,opt,name=form_data_parameter_sub_schema,json=formDataParameterSubSchema,oneof"` +} +type NonBodyParameter_QueryParameterSubSchema struct { + QueryParameterSubSchema *QueryParameterSubSchema `protobuf:"bytes,3,opt,name=query_parameter_sub_schema,json=queryParameterSubSchema,oneof"` +} +type NonBodyParameter_PathParameterSubSchema struct { + PathParameterSubSchema *PathParameterSubSchema `protobuf:"bytes,4,opt,name=path_parameter_sub_schema,json=pathParameterSubSchema,oneof"` +} + +func (*NonBodyParameter_HeaderParameterSubSchema) isNonBodyParameter_Oneof() {} +func (*NonBodyParameter_FormDataParameterSubSchema) isNonBodyParameter_Oneof() {} +func (*NonBodyParameter_QueryParameterSubSchema) isNonBodyParameter_Oneof() {} +func (*NonBodyParameter_PathParameterSubSchema) isNonBodyParameter_Oneof() {} + +func (m *NonBodyParameter) GetOneof() isNonBodyParameter_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *NonBodyParameter) GetHeaderParameterSubSchema() *HeaderParameterSubSchema { + if x, ok := m.GetOneof().(*NonBodyParameter_HeaderParameterSubSchema); ok { + return x.HeaderParameterSubSchema + } + return nil +} + +func (m *NonBodyParameter) GetFormDataParameterSubSchema() *FormDataParameterSubSchema { + if x, ok := m.GetOneof().(*NonBodyParameter_FormDataParameterSubSchema); ok { + return x.FormDataParameterSubSchema + } + return nil +} + +func (m *NonBodyParameter) GetQueryParameterSubSchema() *QueryParameterSubSchema { + if x, ok := m.GetOneof().(*NonBodyParameter_QueryParameterSubSchema); ok { + return x.QueryParameterSubSchema + } + return nil +} + +func (m *NonBodyParameter) GetPathParameterSubSchema() *PathParameterSubSchema { + if x, ok := m.GetOneof().(*NonBodyParameter_PathParameterSubSchema); ok { + return x.PathParameterSubSchema + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*NonBodyParameter) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _NonBodyParameter_OneofMarshaler, _NonBodyParameter_OneofUnmarshaler, _NonBodyParameter_OneofSizer, []interface{}{ + (*NonBodyParameter_HeaderParameterSubSchema)(nil), + (*NonBodyParameter_FormDataParameterSubSchema)(nil), + (*NonBodyParameter_QueryParameterSubSchema)(nil), + (*NonBodyParameter_PathParameterSubSchema)(nil), + } +} + +func _NonBodyParameter_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*NonBodyParameter) + // oneof + switch x := m.Oneof.(type) { + case *NonBodyParameter_HeaderParameterSubSchema: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.HeaderParameterSubSchema); err != nil { + return err + } + case *NonBodyParameter_FormDataParameterSubSchema: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.FormDataParameterSubSchema); err != nil { + return err + } + case *NonBodyParameter_QueryParameterSubSchema: + b.EncodeVarint(3<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.QueryParameterSubSchema); err != nil { + return err + } + case *NonBodyParameter_PathParameterSubSchema: + b.EncodeVarint(4<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.PathParameterSubSchema); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("NonBodyParameter.Oneof has unexpected type %T", x) + } + return nil +} + +func _NonBodyParameter_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*NonBodyParameter) + switch tag { + case 1: // oneof.header_parameter_sub_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(HeaderParameterSubSchema) + err := b.DecodeMessage(msg) + m.Oneof = &NonBodyParameter_HeaderParameterSubSchema{msg} + return true, err + case 2: // oneof.form_data_parameter_sub_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(FormDataParameterSubSchema) + err := b.DecodeMessage(msg) + m.Oneof = &NonBodyParameter_FormDataParameterSubSchema{msg} + return true, err + case 3: // oneof.query_parameter_sub_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(QueryParameterSubSchema) + err := b.DecodeMessage(msg) + m.Oneof = &NonBodyParameter_QueryParameterSubSchema{msg} + return true, err + case 4: // oneof.path_parameter_sub_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(PathParameterSubSchema) + err := b.DecodeMessage(msg) + m.Oneof = &NonBodyParameter_PathParameterSubSchema{msg} + return true, err + default: + return false, nil + } +} + +func _NonBodyParameter_OneofSizer(msg proto.Message) (n int) { + m := msg.(*NonBodyParameter) + // oneof + switch x := m.Oneof.(type) { + case *NonBodyParameter_HeaderParameterSubSchema: + s := proto.Size(x.HeaderParameterSubSchema) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *NonBodyParameter_FormDataParameterSubSchema: + s := proto.Size(x.FormDataParameterSubSchema) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *NonBodyParameter_QueryParameterSubSchema: + s := proto.Size(x.QueryParameterSubSchema) + n += proto.SizeVarint(3<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *NonBodyParameter_PathParameterSubSchema: + s := proto.Size(x.PathParameterSubSchema) + n += proto.SizeVarint(4<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type Oauth2AccessCodeSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Flow string `protobuf:"bytes,2,opt,name=flow" json:"flow,omitempty"` + Scopes *Oauth2Scopes `protobuf:"bytes,3,opt,name=scopes" json:"scopes,omitempty"` + AuthorizationUrl string `protobuf:"bytes,4,opt,name=authorization_url,json=authorizationUrl" json:"authorization_url,omitempty"` + TokenUrl string `protobuf:"bytes,5,opt,name=token_url,json=tokenUrl" json:"token_url,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,7,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Oauth2AccessCodeSecurity) Reset() { *m = Oauth2AccessCodeSecurity{} } +func (m *Oauth2AccessCodeSecurity) String() string { return proto.CompactTextString(m) } +func (*Oauth2AccessCodeSecurity) ProtoMessage() {} +func (*Oauth2AccessCodeSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} } + +func (m *Oauth2AccessCodeSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetFlow() string { + if m != nil { + return m.Flow + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetScopes() *Oauth2Scopes { + if m != nil { + return m.Scopes + } + return nil +} + +func (m *Oauth2AccessCodeSecurity) GetAuthorizationUrl() string { + if m != nil { + return m.AuthorizationUrl + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetTokenUrl() string { + if m != nil { + return m.TokenUrl + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Oauth2AccessCodeSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Oauth2ApplicationSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Flow string `protobuf:"bytes,2,opt,name=flow" json:"flow,omitempty"` + Scopes *Oauth2Scopes `protobuf:"bytes,3,opt,name=scopes" json:"scopes,omitempty"` + TokenUrl string `protobuf:"bytes,4,opt,name=token_url,json=tokenUrl" json:"token_url,omitempty"` + Description string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Oauth2ApplicationSecurity) Reset() { *m = Oauth2ApplicationSecurity{} } +func (m *Oauth2ApplicationSecurity) String() string { return proto.CompactTextString(m) } +func (*Oauth2ApplicationSecurity) ProtoMessage() {} +func (*Oauth2ApplicationSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} } + +func (m *Oauth2ApplicationSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Oauth2ApplicationSecurity) GetFlow() string { + if m != nil { + return m.Flow + } + return "" +} + +func (m *Oauth2ApplicationSecurity) GetScopes() *Oauth2Scopes { + if m != nil { + return m.Scopes + } + return nil +} + +func (m *Oauth2ApplicationSecurity) GetTokenUrl() string { + if m != nil { + return m.TokenUrl + } + return "" +} + +func (m *Oauth2ApplicationSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Oauth2ApplicationSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Oauth2ImplicitSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Flow string `protobuf:"bytes,2,opt,name=flow" json:"flow,omitempty"` + Scopes *Oauth2Scopes `protobuf:"bytes,3,opt,name=scopes" json:"scopes,omitempty"` + AuthorizationUrl string `protobuf:"bytes,4,opt,name=authorization_url,json=authorizationUrl" json:"authorization_url,omitempty"` + Description string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Oauth2ImplicitSecurity) Reset() { *m = Oauth2ImplicitSecurity{} } +func (m *Oauth2ImplicitSecurity) String() string { return proto.CompactTextString(m) } +func (*Oauth2ImplicitSecurity) ProtoMessage() {} +func (*Oauth2ImplicitSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} } + +func (m *Oauth2ImplicitSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Oauth2ImplicitSecurity) GetFlow() string { + if m != nil { + return m.Flow + } + return "" +} + +func (m *Oauth2ImplicitSecurity) GetScopes() *Oauth2Scopes { + if m != nil { + return m.Scopes + } + return nil +} + +func (m *Oauth2ImplicitSecurity) GetAuthorizationUrl() string { + if m != nil { + return m.AuthorizationUrl + } + return "" +} + +func (m *Oauth2ImplicitSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Oauth2ImplicitSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Oauth2PasswordSecurity struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Flow string `protobuf:"bytes,2,opt,name=flow" json:"flow,omitempty"` + Scopes *Oauth2Scopes `protobuf:"bytes,3,opt,name=scopes" json:"scopes,omitempty"` + TokenUrl string `protobuf:"bytes,4,opt,name=token_url,json=tokenUrl" json:"token_url,omitempty"` + Description string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Oauth2PasswordSecurity) Reset() { *m = Oauth2PasswordSecurity{} } +func (m *Oauth2PasswordSecurity) String() string { return proto.CompactTextString(m) } +func (*Oauth2PasswordSecurity) ProtoMessage() {} +func (*Oauth2PasswordSecurity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} } + +func (m *Oauth2PasswordSecurity) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Oauth2PasswordSecurity) GetFlow() string { + if m != nil { + return m.Flow + } + return "" +} + +func (m *Oauth2PasswordSecurity) GetScopes() *Oauth2Scopes { + if m != nil { + return m.Scopes + } + return nil +} + +func (m *Oauth2PasswordSecurity) GetTokenUrl() string { + if m != nil { + return m.TokenUrl + } + return "" +} + +func (m *Oauth2PasswordSecurity) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Oauth2PasswordSecurity) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Oauth2Scopes struct { + AdditionalProperties []*NamedString `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Oauth2Scopes) Reset() { *m = Oauth2Scopes{} } +func (m *Oauth2Scopes) String() string { return proto.CompactTextString(m) } +func (*Oauth2Scopes) ProtoMessage() {} +func (*Oauth2Scopes) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } + +func (m *Oauth2Scopes) GetAdditionalProperties() []*NamedString { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type Operation struct { + Tags []string `protobuf:"bytes,1,rep,name=tags" json:"tags,omitempty"` + // A brief summary of the operation. + Summary string `protobuf:"bytes,2,opt,name=summary" json:"summary,omitempty"` + // A longer description of the operation, GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + // A unique identifier of the operation. + OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId" json:"operation_id,omitempty"` + // A list of MIME types the API can produce. + Produces []string `protobuf:"bytes,6,rep,name=produces" json:"produces,omitempty"` + // A list of MIME types the API can consume. + Consumes []string `protobuf:"bytes,7,rep,name=consumes" json:"consumes,omitempty"` + // The parameters needed to send a valid API call. + Parameters []*ParametersItem `protobuf:"bytes,8,rep,name=parameters" json:"parameters,omitempty"` + Responses *Responses `protobuf:"bytes,9,opt,name=responses" json:"responses,omitempty"` + // The transfer protocol of the API. + Schemes []string `protobuf:"bytes,10,rep,name=schemes" json:"schemes,omitempty"` + Deprecated bool `protobuf:"varint,11,opt,name=deprecated" json:"deprecated,omitempty"` + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security" json:"security,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,13,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Operation) Reset() { *m = Operation{} } +func (m *Operation) String() string { return proto.CompactTextString(m) } +func (*Operation) ProtoMessage() {} +func (*Operation) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } + +func (m *Operation) GetTags() []string { + if m != nil { + return m.Tags + } + return nil +} + +func (m *Operation) GetSummary() string { + if m != nil { + return m.Summary + } + return "" +} + +func (m *Operation) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Operation) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *Operation) GetOperationId() string { + if m != nil { + return m.OperationId + } + return "" +} + +func (m *Operation) GetProduces() []string { + if m != nil { + return m.Produces + } + return nil +} + +func (m *Operation) GetConsumes() []string { + if m != nil { + return m.Consumes + } + return nil +} + +func (m *Operation) GetParameters() []*ParametersItem { + if m != nil { + return m.Parameters + } + return nil +} + +func (m *Operation) GetResponses() *Responses { + if m != nil { + return m.Responses + } + return nil +} + +func (m *Operation) GetSchemes() []string { + if m != nil { + return m.Schemes + } + return nil +} + +func (m *Operation) GetDeprecated() bool { + if m != nil { + return m.Deprecated + } + return false +} + +func (m *Operation) GetSecurity() []*SecurityRequirement { + if m != nil { + return m.Security + } + return nil +} + +func (m *Operation) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Parameter struct { + // Types that are valid to be assigned to Oneof: + // *Parameter_BodyParameter + // *Parameter_NonBodyParameter + Oneof isParameter_Oneof `protobuf_oneof:"oneof"` +} + +func (m *Parameter) Reset() { *m = Parameter{} } +func (m *Parameter) String() string { return proto.CompactTextString(m) } +func (*Parameter) ProtoMessage() {} +func (*Parameter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} } + +type isParameter_Oneof interface { + isParameter_Oneof() +} + +type Parameter_BodyParameter struct { + BodyParameter *BodyParameter `protobuf:"bytes,1,opt,name=body_parameter,json=bodyParameter,oneof"` +} +type Parameter_NonBodyParameter struct { + NonBodyParameter *NonBodyParameter `protobuf:"bytes,2,opt,name=non_body_parameter,json=nonBodyParameter,oneof"` +} + +func (*Parameter_BodyParameter) isParameter_Oneof() {} +func (*Parameter_NonBodyParameter) isParameter_Oneof() {} + +func (m *Parameter) GetOneof() isParameter_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *Parameter) GetBodyParameter() *BodyParameter { + if x, ok := m.GetOneof().(*Parameter_BodyParameter); ok { + return x.BodyParameter + } + return nil +} + +func (m *Parameter) GetNonBodyParameter() *NonBodyParameter { + if x, ok := m.GetOneof().(*Parameter_NonBodyParameter); ok { + return x.NonBodyParameter + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*Parameter) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _Parameter_OneofMarshaler, _Parameter_OneofUnmarshaler, _Parameter_OneofSizer, []interface{}{ + (*Parameter_BodyParameter)(nil), + (*Parameter_NonBodyParameter)(nil), + } +} + +func _Parameter_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*Parameter) + // oneof + switch x := m.Oneof.(type) { + case *Parameter_BodyParameter: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.BodyParameter); err != nil { + return err + } + case *Parameter_NonBodyParameter: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.NonBodyParameter); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("Parameter.Oneof has unexpected type %T", x) + } + return nil +} + +func _Parameter_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*Parameter) + switch tag { + case 1: // oneof.body_parameter + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(BodyParameter) + err := b.DecodeMessage(msg) + m.Oneof = &Parameter_BodyParameter{msg} + return true, err + case 2: // oneof.non_body_parameter + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(NonBodyParameter) + err := b.DecodeMessage(msg) + m.Oneof = &Parameter_NonBodyParameter{msg} + return true, err + default: + return false, nil + } +} + +func _Parameter_OneofSizer(msg proto.Message) (n int) { + m := msg.(*Parameter) + // oneof + switch x := m.Oneof.(type) { + case *Parameter_BodyParameter: + s := proto.Size(x.BodyParameter) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *Parameter_NonBodyParameter: + s := proto.Size(x.NonBodyParameter) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +// One or more JSON representations for parameters +type ParameterDefinitions struct { + AdditionalProperties []*NamedParameter `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *ParameterDefinitions) Reset() { *m = ParameterDefinitions{} } +func (m *ParameterDefinitions) String() string { return proto.CompactTextString(m) } +func (*ParameterDefinitions) ProtoMessage() {} +func (*ParameterDefinitions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} } + +func (m *ParameterDefinitions) GetAdditionalProperties() []*NamedParameter { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type ParametersItem struct { + // Types that are valid to be assigned to Oneof: + // *ParametersItem_Parameter + // *ParametersItem_JsonReference + Oneof isParametersItem_Oneof `protobuf_oneof:"oneof"` +} + +func (m *ParametersItem) Reset() { *m = ParametersItem{} } +func (m *ParametersItem) String() string { return proto.CompactTextString(m) } +func (*ParametersItem) ProtoMessage() {} +func (*ParametersItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{39} } + +type isParametersItem_Oneof interface { + isParametersItem_Oneof() +} + +type ParametersItem_Parameter struct { + Parameter *Parameter `protobuf:"bytes,1,opt,name=parameter,oneof"` +} +type ParametersItem_JsonReference struct { + JsonReference *JsonReference `protobuf:"bytes,2,opt,name=json_reference,json=jsonReference,oneof"` +} + +func (*ParametersItem_Parameter) isParametersItem_Oneof() {} +func (*ParametersItem_JsonReference) isParametersItem_Oneof() {} + +func (m *ParametersItem) GetOneof() isParametersItem_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *ParametersItem) GetParameter() *Parameter { + if x, ok := m.GetOneof().(*ParametersItem_Parameter); ok { + return x.Parameter + } + return nil +} + +func (m *ParametersItem) GetJsonReference() *JsonReference { + if x, ok := m.GetOneof().(*ParametersItem_JsonReference); ok { + return x.JsonReference + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*ParametersItem) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _ParametersItem_OneofMarshaler, _ParametersItem_OneofUnmarshaler, _ParametersItem_OneofSizer, []interface{}{ + (*ParametersItem_Parameter)(nil), + (*ParametersItem_JsonReference)(nil), + } +} + +func _ParametersItem_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*ParametersItem) + // oneof + switch x := m.Oneof.(type) { + case *ParametersItem_Parameter: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Parameter); err != nil { + return err + } + case *ParametersItem_JsonReference: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.JsonReference); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("ParametersItem.Oneof has unexpected type %T", x) + } + return nil +} + +func _ParametersItem_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*ParametersItem) + switch tag { + case 1: // oneof.parameter + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Parameter) + err := b.DecodeMessage(msg) + m.Oneof = &ParametersItem_Parameter{msg} + return true, err + case 2: // oneof.json_reference + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(JsonReference) + err := b.DecodeMessage(msg) + m.Oneof = &ParametersItem_JsonReference{msg} + return true, err + default: + return false, nil + } +} + +func _ParametersItem_OneofSizer(msg proto.Message) (n int) { + m := msg.(*ParametersItem) + // oneof + switch x := m.Oneof.(type) { + case *ParametersItem_Parameter: + s := proto.Size(x.Parameter) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *ParametersItem_JsonReference: + s := proto.Size(x.JsonReference) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type PathItem struct { + XRef string `protobuf:"bytes,1,opt,name=_ref,json=Ref" json:"_ref,omitempty"` + Get *Operation `protobuf:"bytes,2,opt,name=get" json:"get,omitempty"` + Put *Operation `protobuf:"bytes,3,opt,name=put" json:"put,omitempty"` + Post *Operation `protobuf:"bytes,4,opt,name=post" json:"post,omitempty"` + Delete *Operation `protobuf:"bytes,5,opt,name=delete" json:"delete,omitempty"` + Options *Operation `protobuf:"bytes,6,opt,name=options" json:"options,omitempty"` + Head *Operation `protobuf:"bytes,7,opt,name=head" json:"head,omitempty"` + Patch *Operation `protobuf:"bytes,8,opt,name=patch" json:"patch,omitempty"` + // The parameters needed to send a valid API call. + Parameters []*ParametersItem `protobuf:"bytes,9,rep,name=parameters" json:"parameters,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,10,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *PathItem) Reset() { *m = PathItem{} } +func (m *PathItem) String() string { return proto.CompactTextString(m) } +func (*PathItem) ProtoMessage() {} +func (*PathItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{40} } + +func (m *PathItem) GetXRef() string { + if m != nil { + return m.XRef + } + return "" +} + +func (m *PathItem) GetGet() *Operation { + if m != nil { + return m.Get + } + return nil +} + +func (m *PathItem) GetPut() *Operation { + if m != nil { + return m.Put + } + return nil +} + +func (m *PathItem) GetPost() *Operation { + if m != nil { + return m.Post + } + return nil +} + +func (m *PathItem) GetDelete() *Operation { + if m != nil { + return m.Delete + } + return nil +} + +func (m *PathItem) GetOptions() *Operation { + if m != nil { + return m.Options + } + return nil +} + +func (m *PathItem) GetHead() *Operation { + if m != nil { + return m.Head + } + return nil +} + +func (m *PathItem) GetPatch() *Operation { + if m != nil { + return m.Patch + } + return nil +} + +func (m *PathItem) GetParameters() []*ParametersItem { + if m != nil { + return m.Parameters + } + return nil +} + +func (m *PathItem) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type PathParameterSubSchema struct { + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,1,opt,name=required" json:"required,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,2,opt,name=in" json:"in,omitempty"` + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` + Type string `protobuf:"bytes,5,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,6,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,7,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,8,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,9,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,10,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,11,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,12,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,13,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,14,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,15,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,16,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,17,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,18,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,19,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,20,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,21,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,22,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *PathParameterSubSchema) Reset() { *m = PathParameterSubSchema{} } +func (m *PathParameterSubSchema) String() string { return proto.CompactTextString(m) } +func (*PathParameterSubSchema) ProtoMessage() {} +func (*PathParameterSubSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} } + +func (m *PathParameterSubSchema) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *PathParameterSubSchema) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *PathParameterSubSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *PathParameterSubSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *PathParameterSubSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *PathParameterSubSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *PathParameterSubSchema) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *PathParameterSubSchema) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *PathParameterSubSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *PathParameterSubSchema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *PathParameterSubSchema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *PathParameterSubSchema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *PathParameterSubSchema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *PathParameterSubSchema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *PathParameterSubSchema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *PathParameterSubSchema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *PathParameterSubSchema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *PathParameterSubSchema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *PathParameterSubSchema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *PathParameterSubSchema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *PathParameterSubSchema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *PathParameterSubSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// Relative paths to the individual endpoints. They must be relative to the 'basePath'. +type Paths struct { + VendorExtension []*NamedAny `protobuf:"bytes,1,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` + Path []*NamedPathItem `protobuf:"bytes,2,rep,name=path" json:"path,omitempty"` +} + +func (m *Paths) Reset() { *m = Paths{} } +func (m *Paths) String() string { return proto.CompactTextString(m) } +func (*Paths) ProtoMessage() {} +func (*Paths) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{42} } + +func (m *Paths) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +func (m *Paths) GetPath() []*NamedPathItem { + if m != nil { + return m.Path + } + return nil +} + +type PrimitivesItems struct { + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,2,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,3,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,4,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,5,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,6,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,7,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,8,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,9,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,10,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,11,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,12,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,13,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,14,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,15,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,16,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,17,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,18,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *PrimitivesItems) Reset() { *m = PrimitivesItems{} } +func (m *PrimitivesItems) String() string { return proto.CompactTextString(m) } +func (*PrimitivesItems) ProtoMessage() {} +func (*PrimitivesItems) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{43} } + +func (m *PrimitivesItems) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *PrimitivesItems) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *PrimitivesItems) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *PrimitivesItems) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *PrimitivesItems) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *PrimitivesItems) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *PrimitivesItems) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *PrimitivesItems) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *PrimitivesItems) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *PrimitivesItems) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *PrimitivesItems) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *PrimitivesItems) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *PrimitivesItems) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *PrimitivesItems) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *PrimitivesItems) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *PrimitivesItems) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *PrimitivesItems) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *PrimitivesItems) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Properties struct { + AdditionalProperties []*NamedSchema `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *Properties) Reset() { *m = Properties{} } +func (m *Properties) String() string { return proto.CompactTextString(m) } +func (*Properties) ProtoMessage() {} +func (*Properties) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} } + +func (m *Properties) GetAdditionalProperties() []*NamedSchema { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type QueryParameterSubSchema struct { + // Determines whether or not this parameter is required or optional. + Required bool `protobuf:"varint,1,opt,name=required" json:"required,omitempty"` + // Determines the location of the parameter. + In string `protobuf:"bytes,2,opt,name=in" json:"in,omitempty"` + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // The name of the parameter. + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` + // allows sending a parameter by name only or with an empty value. + AllowEmptyValue bool `protobuf:"varint,5,opt,name=allow_empty_value,json=allowEmptyValue" json:"allow_empty_value,omitempty"` + Type string `protobuf:"bytes,6,opt,name=type" json:"type,omitempty"` + Format string `protobuf:"bytes,7,opt,name=format" json:"format,omitempty"` + Items *PrimitivesItems `protobuf:"bytes,8,opt,name=items" json:"items,omitempty"` + CollectionFormat string `protobuf:"bytes,9,opt,name=collection_format,json=collectionFormat" json:"collection_format,omitempty"` + Default *Any `protobuf:"bytes,10,opt,name=default" json:"default,omitempty"` + Maximum float64 `protobuf:"fixed64,11,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,13,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,15,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,16,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,17,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,18,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,19,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,20,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + Enum []*Any `protobuf:"bytes,21,rep,name=enum" json:"enum,omitempty"` + MultipleOf float64 `protobuf:"fixed64,22,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,23,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *QueryParameterSubSchema) Reset() { *m = QueryParameterSubSchema{} } +func (m *QueryParameterSubSchema) String() string { return proto.CompactTextString(m) } +func (*QueryParameterSubSchema) ProtoMessage() {} +func (*QueryParameterSubSchema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{45} } + +func (m *QueryParameterSubSchema) GetRequired() bool { + if m != nil { + return m.Required + } + return false +} + +func (m *QueryParameterSubSchema) GetIn() string { + if m != nil { + return m.In + } + return "" +} + +func (m *QueryParameterSubSchema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *QueryParameterSubSchema) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *QueryParameterSubSchema) GetAllowEmptyValue() bool { + if m != nil { + return m.AllowEmptyValue + } + return false +} + +func (m *QueryParameterSubSchema) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *QueryParameterSubSchema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *QueryParameterSubSchema) GetItems() *PrimitivesItems { + if m != nil { + return m.Items + } + return nil +} + +func (m *QueryParameterSubSchema) GetCollectionFormat() string { + if m != nil { + return m.CollectionFormat + } + return "" +} + +func (m *QueryParameterSubSchema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *QueryParameterSubSchema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *QueryParameterSubSchema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *QueryParameterSubSchema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *QueryParameterSubSchema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *QueryParameterSubSchema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *QueryParameterSubSchema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *QueryParameterSubSchema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *QueryParameterSubSchema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *QueryParameterSubSchema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *QueryParameterSubSchema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *QueryParameterSubSchema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *QueryParameterSubSchema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *QueryParameterSubSchema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type Response struct { + Description string `protobuf:"bytes,1,opt,name=description" json:"description,omitempty"` + Schema *SchemaItem `protobuf:"bytes,2,opt,name=schema" json:"schema,omitempty"` + Headers *Headers `protobuf:"bytes,3,opt,name=headers" json:"headers,omitempty"` + Examples *Examples `protobuf:"bytes,4,opt,name=examples" json:"examples,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,5,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Response) Reset() { *m = Response{} } +func (m *Response) String() string { return proto.CompactTextString(m) } +func (*Response) ProtoMessage() {} +func (*Response) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{46} } + +func (m *Response) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Response) GetSchema() *SchemaItem { + if m != nil { + return m.Schema + } + return nil +} + +func (m *Response) GetHeaders() *Headers { + if m != nil { + return m.Headers + } + return nil +} + +func (m *Response) GetExamples() *Examples { + if m != nil { + return m.Examples + } + return nil +} + +func (m *Response) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// One or more JSON representations for parameters +type ResponseDefinitions struct { + AdditionalProperties []*NamedResponse `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *ResponseDefinitions) Reset() { *m = ResponseDefinitions{} } +func (m *ResponseDefinitions) String() string { return proto.CompactTextString(m) } +func (*ResponseDefinitions) ProtoMessage() {} +func (*ResponseDefinitions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{47} } + +func (m *ResponseDefinitions) GetAdditionalProperties() []*NamedResponse { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type ResponseValue struct { + // Types that are valid to be assigned to Oneof: + // *ResponseValue_Response + // *ResponseValue_JsonReference + Oneof isResponseValue_Oneof `protobuf_oneof:"oneof"` +} + +func (m *ResponseValue) Reset() { *m = ResponseValue{} } +func (m *ResponseValue) String() string { return proto.CompactTextString(m) } +func (*ResponseValue) ProtoMessage() {} +func (*ResponseValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{48} } + +type isResponseValue_Oneof interface { + isResponseValue_Oneof() +} + +type ResponseValue_Response struct { + Response *Response `protobuf:"bytes,1,opt,name=response,oneof"` +} +type ResponseValue_JsonReference struct { + JsonReference *JsonReference `protobuf:"bytes,2,opt,name=json_reference,json=jsonReference,oneof"` +} + +func (*ResponseValue_Response) isResponseValue_Oneof() {} +func (*ResponseValue_JsonReference) isResponseValue_Oneof() {} + +func (m *ResponseValue) GetOneof() isResponseValue_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *ResponseValue) GetResponse() *Response { + if x, ok := m.GetOneof().(*ResponseValue_Response); ok { + return x.Response + } + return nil +} + +func (m *ResponseValue) GetJsonReference() *JsonReference { + if x, ok := m.GetOneof().(*ResponseValue_JsonReference); ok { + return x.JsonReference + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*ResponseValue) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _ResponseValue_OneofMarshaler, _ResponseValue_OneofUnmarshaler, _ResponseValue_OneofSizer, []interface{}{ + (*ResponseValue_Response)(nil), + (*ResponseValue_JsonReference)(nil), + } +} + +func _ResponseValue_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*ResponseValue) + // oneof + switch x := m.Oneof.(type) { + case *ResponseValue_Response: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Response); err != nil { + return err + } + case *ResponseValue_JsonReference: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.JsonReference); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("ResponseValue.Oneof has unexpected type %T", x) + } + return nil +} + +func _ResponseValue_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*ResponseValue) + switch tag { + case 1: // oneof.response + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Response) + err := b.DecodeMessage(msg) + m.Oneof = &ResponseValue_Response{msg} + return true, err + case 2: // oneof.json_reference + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(JsonReference) + err := b.DecodeMessage(msg) + m.Oneof = &ResponseValue_JsonReference{msg} + return true, err + default: + return false, nil + } +} + +func _ResponseValue_OneofSizer(msg proto.Message) (n int) { + m := msg.(*ResponseValue) + // oneof + switch x := m.Oneof.(type) { + case *ResponseValue_Response: + s := proto.Size(x.Response) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *ResponseValue_JsonReference: + s := proto.Size(x.JsonReference) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +// Response objects names can either be any valid HTTP status code or 'default'. +type Responses struct { + ResponseCode []*NamedResponseValue `protobuf:"bytes,1,rep,name=response_code,json=responseCode" json:"response_code,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,2,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Responses) Reset() { *m = Responses{} } +func (m *Responses) String() string { return proto.CompactTextString(m) } +func (*Responses) ProtoMessage() {} +func (*Responses) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{49} } + +func (m *Responses) GetResponseCode() []*NamedResponseValue { + if m != nil { + return m.ResponseCode + } + return nil +} + +func (m *Responses) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +// A deterministic version of a JSON Schema object. +type Schema struct { + XRef string `protobuf:"bytes,1,opt,name=_ref,json=Ref" json:"_ref,omitempty"` + Format string `protobuf:"bytes,2,opt,name=format" json:"format,omitempty"` + Title string `protobuf:"bytes,3,opt,name=title" json:"title,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` + Default *Any `protobuf:"bytes,5,opt,name=default" json:"default,omitempty"` + MultipleOf float64 `protobuf:"fixed64,6,opt,name=multiple_of,json=multipleOf" json:"multiple_of,omitempty"` + Maximum float64 `protobuf:"fixed64,7,opt,name=maximum" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,8,opt,name=exclusive_maximum,json=exclusiveMaximum" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,9,opt,name=minimum" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,10,opt,name=exclusive_minimum,json=exclusiveMinimum" json:"exclusive_minimum,omitempty"` + MaxLength int64 `protobuf:"varint,11,opt,name=max_length,json=maxLength" json:"max_length,omitempty"` + MinLength int64 `protobuf:"varint,12,opt,name=min_length,json=minLength" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,13,opt,name=pattern" json:"pattern,omitempty"` + MaxItems int64 `protobuf:"varint,14,opt,name=max_items,json=maxItems" json:"max_items,omitempty"` + MinItems int64 `protobuf:"varint,15,opt,name=min_items,json=minItems" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,16,opt,name=unique_items,json=uniqueItems" json:"unique_items,omitempty"` + MaxProperties int64 `protobuf:"varint,17,opt,name=max_properties,json=maxProperties" json:"max_properties,omitempty"` + MinProperties int64 `protobuf:"varint,18,opt,name=min_properties,json=minProperties" json:"min_properties,omitempty"` + Required []string `protobuf:"bytes,19,rep,name=required" json:"required,omitempty"` + Enum []*Any `protobuf:"bytes,20,rep,name=enum" json:"enum,omitempty"` + AdditionalProperties *AdditionalPropertiesItem `protobuf:"bytes,21,opt,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` + Type *TypeItem `protobuf:"bytes,22,opt,name=type" json:"type,omitempty"` + Items *ItemsItem `protobuf:"bytes,23,opt,name=items" json:"items,omitempty"` + AllOf []*Schema `protobuf:"bytes,24,rep,name=all_of,json=allOf" json:"all_of,omitempty"` + Properties *Properties `protobuf:"bytes,25,opt,name=properties" json:"properties,omitempty"` + Discriminator string `protobuf:"bytes,26,opt,name=discriminator" json:"discriminator,omitempty"` + ReadOnly bool `protobuf:"varint,27,opt,name=read_only,json=readOnly" json:"read_only,omitempty"` + Xml *Xml `protobuf:"bytes,28,opt,name=xml" json:"xml,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,29,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + Example *Any `protobuf:"bytes,30,opt,name=example" json:"example,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,31,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Schema) Reset() { *m = Schema{} } +func (m *Schema) String() string { return proto.CompactTextString(m) } +func (*Schema) ProtoMessage() {} +func (*Schema) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{50} } + +func (m *Schema) GetXRef() string { + if m != nil { + return m.XRef + } + return "" +} + +func (m *Schema) GetFormat() string { + if m != nil { + return m.Format + } + return "" +} + +func (m *Schema) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *Schema) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Schema) GetDefault() *Any { + if m != nil { + return m.Default + } + return nil +} + +func (m *Schema) GetMultipleOf() float64 { + if m != nil { + return m.MultipleOf + } + return 0 +} + +func (m *Schema) GetMaximum() float64 { + if m != nil { + return m.Maximum + } + return 0 +} + +func (m *Schema) GetExclusiveMaximum() bool { + if m != nil { + return m.ExclusiveMaximum + } + return false +} + +func (m *Schema) GetMinimum() float64 { + if m != nil { + return m.Minimum + } + return 0 +} + +func (m *Schema) GetExclusiveMinimum() bool { + if m != nil { + return m.ExclusiveMinimum + } + return false +} + +func (m *Schema) GetMaxLength() int64 { + if m != nil { + return m.MaxLength + } + return 0 +} + +func (m *Schema) GetMinLength() int64 { + if m != nil { + return m.MinLength + } + return 0 +} + +func (m *Schema) GetPattern() string { + if m != nil { + return m.Pattern + } + return "" +} + +func (m *Schema) GetMaxItems() int64 { + if m != nil { + return m.MaxItems + } + return 0 +} + +func (m *Schema) GetMinItems() int64 { + if m != nil { + return m.MinItems + } + return 0 +} + +func (m *Schema) GetUniqueItems() bool { + if m != nil { + return m.UniqueItems + } + return false +} + +func (m *Schema) GetMaxProperties() int64 { + if m != nil { + return m.MaxProperties + } + return 0 +} + +func (m *Schema) GetMinProperties() int64 { + if m != nil { + return m.MinProperties + } + return 0 +} + +func (m *Schema) GetRequired() []string { + if m != nil { + return m.Required + } + return nil +} + +func (m *Schema) GetEnum() []*Any { + if m != nil { + return m.Enum + } + return nil +} + +func (m *Schema) GetAdditionalProperties() *AdditionalPropertiesItem { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +func (m *Schema) GetType() *TypeItem { + if m != nil { + return m.Type + } + return nil +} + +func (m *Schema) GetItems() *ItemsItem { + if m != nil { + return m.Items + } + return nil +} + +func (m *Schema) GetAllOf() []*Schema { + if m != nil { + return m.AllOf + } + return nil +} + +func (m *Schema) GetProperties() *Properties { + if m != nil { + return m.Properties + } + return nil +} + +func (m *Schema) GetDiscriminator() string { + if m != nil { + return m.Discriminator + } + return "" +} + +func (m *Schema) GetReadOnly() bool { + if m != nil { + return m.ReadOnly + } + return false +} + +func (m *Schema) GetXml() *Xml { + if m != nil { + return m.Xml + } + return nil +} + +func (m *Schema) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *Schema) GetExample() *Any { + if m != nil { + return m.Example + } + return nil +} + +func (m *Schema) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type SchemaItem struct { + // Types that are valid to be assigned to Oneof: + // *SchemaItem_Schema + // *SchemaItem_FileSchema + Oneof isSchemaItem_Oneof `protobuf_oneof:"oneof"` +} + +func (m *SchemaItem) Reset() { *m = SchemaItem{} } +func (m *SchemaItem) String() string { return proto.CompactTextString(m) } +func (*SchemaItem) ProtoMessage() {} +func (*SchemaItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{51} } + +type isSchemaItem_Oneof interface { + isSchemaItem_Oneof() +} + +type SchemaItem_Schema struct { + Schema *Schema `protobuf:"bytes,1,opt,name=schema,oneof"` +} +type SchemaItem_FileSchema struct { + FileSchema *FileSchema `protobuf:"bytes,2,opt,name=file_schema,json=fileSchema,oneof"` +} + +func (*SchemaItem_Schema) isSchemaItem_Oneof() {} +func (*SchemaItem_FileSchema) isSchemaItem_Oneof() {} + +func (m *SchemaItem) GetOneof() isSchemaItem_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *SchemaItem) GetSchema() *Schema { + if x, ok := m.GetOneof().(*SchemaItem_Schema); ok { + return x.Schema + } + return nil +} + +func (m *SchemaItem) GetFileSchema() *FileSchema { + if x, ok := m.GetOneof().(*SchemaItem_FileSchema); ok { + return x.FileSchema + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*SchemaItem) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _SchemaItem_OneofMarshaler, _SchemaItem_OneofUnmarshaler, _SchemaItem_OneofSizer, []interface{}{ + (*SchemaItem_Schema)(nil), + (*SchemaItem_FileSchema)(nil), + } +} + +func _SchemaItem_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*SchemaItem) + // oneof + switch x := m.Oneof.(type) { + case *SchemaItem_Schema: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Schema); err != nil { + return err + } + case *SchemaItem_FileSchema: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.FileSchema); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("SchemaItem.Oneof has unexpected type %T", x) + } + return nil +} + +func _SchemaItem_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*SchemaItem) + switch tag { + case 1: // oneof.schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Schema) + err := b.DecodeMessage(msg) + m.Oneof = &SchemaItem_Schema{msg} + return true, err + case 2: // oneof.file_schema + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(FileSchema) + err := b.DecodeMessage(msg) + m.Oneof = &SchemaItem_FileSchema{msg} + return true, err + default: + return false, nil + } +} + +func _SchemaItem_OneofSizer(msg proto.Message) (n int) { + m := msg.(*SchemaItem) + // oneof + switch x := m.Oneof.(type) { + case *SchemaItem_Schema: + s := proto.Size(x.Schema) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SchemaItem_FileSchema: + s := proto.Size(x.FileSchema) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type SecurityDefinitions struct { + AdditionalProperties []*NamedSecurityDefinitionsItem `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *SecurityDefinitions) Reset() { *m = SecurityDefinitions{} } +func (m *SecurityDefinitions) String() string { return proto.CompactTextString(m) } +func (*SecurityDefinitions) ProtoMessage() {} +func (*SecurityDefinitions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{52} } + +func (m *SecurityDefinitions) GetAdditionalProperties() []*NamedSecurityDefinitionsItem { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type SecurityDefinitionsItem struct { + // Types that are valid to be assigned to Oneof: + // *SecurityDefinitionsItem_BasicAuthenticationSecurity + // *SecurityDefinitionsItem_ApiKeySecurity + // *SecurityDefinitionsItem_Oauth2ImplicitSecurity + // *SecurityDefinitionsItem_Oauth2PasswordSecurity + // *SecurityDefinitionsItem_Oauth2ApplicationSecurity + // *SecurityDefinitionsItem_Oauth2AccessCodeSecurity + Oneof isSecurityDefinitionsItem_Oneof `protobuf_oneof:"oneof"` +} + +func (m *SecurityDefinitionsItem) Reset() { *m = SecurityDefinitionsItem{} } +func (m *SecurityDefinitionsItem) String() string { return proto.CompactTextString(m) } +func (*SecurityDefinitionsItem) ProtoMessage() {} +func (*SecurityDefinitionsItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{53} } + +type isSecurityDefinitionsItem_Oneof interface { + isSecurityDefinitionsItem_Oneof() +} + +type SecurityDefinitionsItem_BasicAuthenticationSecurity struct { + BasicAuthenticationSecurity *BasicAuthenticationSecurity `protobuf:"bytes,1,opt,name=basic_authentication_security,json=basicAuthenticationSecurity,oneof"` +} +type SecurityDefinitionsItem_ApiKeySecurity struct { + ApiKeySecurity *ApiKeySecurity `protobuf:"bytes,2,opt,name=api_key_security,json=apiKeySecurity,oneof"` +} +type SecurityDefinitionsItem_Oauth2ImplicitSecurity struct { + Oauth2ImplicitSecurity *Oauth2ImplicitSecurity `protobuf:"bytes,3,opt,name=oauth2_implicit_security,json=oauth2ImplicitSecurity,oneof"` +} +type SecurityDefinitionsItem_Oauth2PasswordSecurity struct { + Oauth2PasswordSecurity *Oauth2PasswordSecurity `protobuf:"bytes,4,opt,name=oauth2_password_security,json=oauth2PasswordSecurity,oneof"` +} +type SecurityDefinitionsItem_Oauth2ApplicationSecurity struct { + Oauth2ApplicationSecurity *Oauth2ApplicationSecurity `protobuf:"bytes,5,opt,name=oauth2_application_security,json=oauth2ApplicationSecurity,oneof"` +} +type SecurityDefinitionsItem_Oauth2AccessCodeSecurity struct { + Oauth2AccessCodeSecurity *Oauth2AccessCodeSecurity `protobuf:"bytes,6,opt,name=oauth2_access_code_security,json=oauth2AccessCodeSecurity,oneof"` +} + +func (*SecurityDefinitionsItem_BasicAuthenticationSecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_ApiKeySecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_Oauth2ImplicitSecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_Oauth2PasswordSecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_Oauth2ApplicationSecurity) isSecurityDefinitionsItem_Oneof() {} +func (*SecurityDefinitionsItem_Oauth2AccessCodeSecurity) isSecurityDefinitionsItem_Oneof() {} + +func (m *SecurityDefinitionsItem) GetOneof() isSecurityDefinitionsItem_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *SecurityDefinitionsItem) GetBasicAuthenticationSecurity() *BasicAuthenticationSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_BasicAuthenticationSecurity); ok { + return x.BasicAuthenticationSecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetApiKeySecurity() *ApiKeySecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_ApiKeySecurity); ok { + return x.ApiKeySecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetOauth2ImplicitSecurity() *Oauth2ImplicitSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_Oauth2ImplicitSecurity); ok { + return x.Oauth2ImplicitSecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetOauth2PasswordSecurity() *Oauth2PasswordSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_Oauth2PasswordSecurity); ok { + return x.Oauth2PasswordSecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetOauth2ApplicationSecurity() *Oauth2ApplicationSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_Oauth2ApplicationSecurity); ok { + return x.Oauth2ApplicationSecurity + } + return nil +} + +func (m *SecurityDefinitionsItem) GetOauth2AccessCodeSecurity() *Oauth2AccessCodeSecurity { + if x, ok := m.GetOneof().(*SecurityDefinitionsItem_Oauth2AccessCodeSecurity); ok { + return x.Oauth2AccessCodeSecurity + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*SecurityDefinitionsItem) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _SecurityDefinitionsItem_OneofMarshaler, _SecurityDefinitionsItem_OneofUnmarshaler, _SecurityDefinitionsItem_OneofSizer, []interface{}{ + (*SecurityDefinitionsItem_BasicAuthenticationSecurity)(nil), + (*SecurityDefinitionsItem_ApiKeySecurity)(nil), + (*SecurityDefinitionsItem_Oauth2ImplicitSecurity)(nil), + (*SecurityDefinitionsItem_Oauth2PasswordSecurity)(nil), + (*SecurityDefinitionsItem_Oauth2ApplicationSecurity)(nil), + (*SecurityDefinitionsItem_Oauth2AccessCodeSecurity)(nil), + } +} + +func _SecurityDefinitionsItem_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*SecurityDefinitionsItem) + // oneof + switch x := m.Oneof.(type) { + case *SecurityDefinitionsItem_BasicAuthenticationSecurity: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.BasicAuthenticationSecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_ApiKeySecurity: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.ApiKeySecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_Oauth2ImplicitSecurity: + b.EncodeVarint(3<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Oauth2ImplicitSecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_Oauth2PasswordSecurity: + b.EncodeVarint(4<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Oauth2PasswordSecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_Oauth2ApplicationSecurity: + b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Oauth2ApplicationSecurity); err != nil { + return err + } + case *SecurityDefinitionsItem_Oauth2AccessCodeSecurity: + b.EncodeVarint(6<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Oauth2AccessCodeSecurity); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("SecurityDefinitionsItem.Oneof has unexpected type %T", x) + } + return nil +} + +func _SecurityDefinitionsItem_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*SecurityDefinitionsItem) + switch tag { + case 1: // oneof.basic_authentication_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(BasicAuthenticationSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_BasicAuthenticationSecurity{msg} + return true, err + case 2: // oneof.api_key_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(ApiKeySecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_ApiKeySecurity{msg} + return true, err + case 3: // oneof.oauth2_implicit_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Oauth2ImplicitSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_Oauth2ImplicitSecurity{msg} + return true, err + case 4: // oneof.oauth2_password_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Oauth2PasswordSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_Oauth2PasswordSecurity{msg} + return true, err + case 5: // oneof.oauth2_application_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Oauth2ApplicationSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_Oauth2ApplicationSecurity{msg} + return true, err + case 6: // oneof.oauth2_access_code_security + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Oauth2AccessCodeSecurity) + err := b.DecodeMessage(msg) + m.Oneof = &SecurityDefinitionsItem_Oauth2AccessCodeSecurity{msg} + return true, err + default: + return false, nil + } +} + +func _SecurityDefinitionsItem_OneofSizer(msg proto.Message) (n int) { + m := msg.(*SecurityDefinitionsItem) + // oneof + switch x := m.Oneof.(type) { + case *SecurityDefinitionsItem_BasicAuthenticationSecurity: + s := proto.Size(x.BasicAuthenticationSecurity) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_ApiKeySecurity: + s := proto.Size(x.ApiKeySecurity) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_Oauth2ImplicitSecurity: + s := proto.Size(x.Oauth2ImplicitSecurity) + n += proto.SizeVarint(3<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_Oauth2PasswordSecurity: + s := proto.Size(x.Oauth2PasswordSecurity) + n += proto.SizeVarint(4<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_Oauth2ApplicationSecurity: + s := proto.Size(x.Oauth2ApplicationSecurity) + n += proto.SizeVarint(5<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SecurityDefinitionsItem_Oauth2AccessCodeSecurity: + s := proto.Size(x.Oauth2AccessCodeSecurity) + n += proto.SizeVarint(6<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type SecurityRequirement struct { + AdditionalProperties []*NamedStringArray `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *SecurityRequirement) Reset() { *m = SecurityRequirement{} } +func (m *SecurityRequirement) String() string { return proto.CompactTextString(m) } +func (*SecurityRequirement) ProtoMessage() {} +func (*SecurityRequirement) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{54} } + +func (m *SecurityRequirement) GetAdditionalProperties() []*NamedStringArray { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type StringArray struct { + Value []string `protobuf:"bytes,1,rep,name=value" json:"value,omitempty"` +} + +func (m *StringArray) Reset() { *m = StringArray{} } +func (m *StringArray) String() string { return proto.CompactTextString(m) } +func (*StringArray) ProtoMessage() {} +func (*StringArray) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{55} } + +func (m *StringArray) GetValue() []string { + if m != nil { + return m.Value + } + return nil +} + +type Tag struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` + ExternalDocs *ExternalDocs `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs" json:"external_docs,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,4,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Tag) Reset() { *m = Tag{} } +func (m *Tag) String() string { return proto.CompactTextString(m) } +func (*Tag) ProtoMessage() {} +func (*Tag) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{56} } + +func (m *Tag) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Tag) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Tag) GetExternalDocs() *ExternalDocs { + if m != nil { + return m.ExternalDocs + } + return nil +} + +func (m *Tag) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +type TypeItem struct { + Value []string `protobuf:"bytes,1,rep,name=value" json:"value,omitempty"` +} + +func (m *TypeItem) Reset() { *m = TypeItem{} } +func (m *TypeItem) String() string { return proto.CompactTextString(m) } +func (*TypeItem) ProtoMessage() {} +func (*TypeItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{57} } + +func (m *TypeItem) GetValue() []string { + if m != nil { + return m.Value + } + return nil +} + +// Any property starting with x- is valid. +type VendorExtension struct { + AdditionalProperties []*NamedAny `protobuf:"bytes,1,rep,name=additional_properties,json=additionalProperties" json:"additional_properties,omitempty"` +} + +func (m *VendorExtension) Reset() { *m = VendorExtension{} } +func (m *VendorExtension) String() string { return proto.CompactTextString(m) } +func (*VendorExtension) ProtoMessage() {} +func (*VendorExtension) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{58} } + +func (m *VendorExtension) GetAdditionalProperties() []*NamedAny { + if m != nil { + return m.AdditionalProperties + } + return nil +} + +type Xml struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` + Prefix string `protobuf:"bytes,3,opt,name=prefix" json:"prefix,omitempty"` + Attribute bool `protobuf:"varint,4,opt,name=attribute" json:"attribute,omitempty"` + Wrapped bool `protobuf:"varint,5,opt,name=wrapped" json:"wrapped,omitempty"` + VendorExtension []*NamedAny `protobuf:"bytes,6,rep,name=vendor_extension,json=vendorExtension" json:"vendor_extension,omitempty"` +} + +func (m *Xml) Reset() { *m = Xml{} } +func (m *Xml) String() string { return proto.CompactTextString(m) } +func (*Xml) ProtoMessage() {} +func (*Xml) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{59} } + +func (m *Xml) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Xml) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *Xml) GetPrefix() string { + if m != nil { + return m.Prefix + } + return "" +} + +func (m *Xml) GetAttribute() bool { + if m != nil { + return m.Attribute + } + return false +} + +func (m *Xml) GetWrapped() bool { + if m != nil { + return m.Wrapped + } + return false +} + +func (m *Xml) GetVendorExtension() []*NamedAny { + if m != nil { + return m.VendorExtension + } + return nil +} + +func init() { + proto.RegisterType((*AdditionalPropertiesItem)(nil), "openapi.v2.AdditionalPropertiesItem") + proto.RegisterType((*Any)(nil), "openapi.v2.Any") + proto.RegisterType((*ApiKeySecurity)(nil), "openapi.v2.ApiKeySecurity") + proto.RegisterType((*BasicAuthenticationSecurity)(nil), "openapi.v2.BasicAuthenticationSecurity") + proto.RegisterType((*BodyParameter)(nil), "openapi.v2.BodyParameter") + proto.RegisterType((*Contact)(nil), "openapi.v2.Contact") + proto.RegisterType((*Default)(nil), "openapi.v2.Default") + proto.RegisterType((*Definitions)(nil), "openapi.v2.Definitions") + proto.RegisterType((*Document)(nil), "openapi.v2.Document") + proto.RegisterType((*Examples)(nil), "openapi.v2.Examples") + proto.RegisterType((*ExternalDocs)(nil), "openapi.v2.ExternalDocs") + proto.RegisterType((*FileSchema)(nil), "openapi.v2.FileSchema") + proto.RegisterType((*FormDataParameterSubSchema)(nil), "openapi.v2.FormDataParameterSubSchema") + proto.RegisterType((*Header)(nil), "openapi.v2.Header") + proto.RegisterType((*HeaderParameterSubSchema)(nil), "openapi.v2.HeaderParameterSubSchema") + proto.RegisterType((*Headers)(nil), "openapi.v2.Headers") + proto.RegisterType((*Info)(nil), "openapi.v2.Info") + proto.RegisterType((*ItemsItem)(nil), "openapi.v2.ItemsItem") + proto.RegisterType((*JsonReference)(nil), "openapi.v2.JsonReference") + proto.RegisterType((*License)(nil), "openapi.v2.License") + proto.RegisterType((*NamedAny)(nil), "openapi.v2.NamedAny") + proto.RegisterType((*NamedHeader)(nil), "openapi.v2.NamedHeader") + proto.RegisterType((*NamedParameter)(nil), "openapi.v2.NamedParameter") + proto.RegisterType((*NamedPathItem)(nil), "openapi.v2.NamedPathItem") + proto.RegisterType((*NamedResponse)(nil), "openapi.v2.NamedResponse") + proto.RegisterType((*NamedResponseValue)(nil), "openapi.v2.NamedResponseValue") + proto.RegisterType((*NamedSchema)(nil), "openapi.v2.NamedSchema") + proto.RegisterType((*NamedSecurityDefinitionsItem)(nil), "openapi.v2.NamedSecurityDefinitionsItem") + proto.RegisterType((*NamedString)(nil), "openapi.v2.NamedString") + proto.RegisterType((*NamedStringArray)(nil), "openapi.v2.NamedStringArray") + proto.RegisterType((*NonBodyParameter)(nil), "openapi.v2.NonBodyParameter") + proto.RegisterType((*Oauth2AccessCodeSecurity)(nil), "openapi.v2.Oauth2AccessCodeSecurity") + proto.RegisterType((*Oauth2ApplicationSecurity)(nil), "openapi.v2.Oauth2ApplicationSecurity") + proto.RegisterType((*Oauth2ImplicitSecurity)(nil), "openapi.v2.Oauth2ImplicitSecurity") + proto.RegisterType((*Oauth2PasswordSecurity)(nil), "openapi.v2.Oauth2PasswordSecurity") + proto.RegisterType((*Oauth2Scopes)(nil), "openapi.v2.Oauth2Scopes") + proto.RegisterType((*Operation)(nil), "openapi.v2.Operation") + proto.RegisterType((*Parameter)(nil), "openapi.v2.Parameter") + proto.RegisterType((*ParameterDefinitions)(nil), "openapi.v2.ParameterDefinitions") + proto.RegisterType((*ParametersItem)(nil), "openapi.v2.ParametersItem") + proto.RegisterType((*PathItem)(nil), "openapi.v2.PathItem") + proto.RegisterType((*PathParameterSubSchema)(nil), "openapi.v2.PathParameterSubSchema") + proto.RegisterType((*Paths)(nil), "openapi.v2.Paths") + proto.RegisterType((*PrimitivesItems)(nil), "openapi.v2.PrimitivesItems") + proto.RegisterType((*Properties)(nil), "openapi.v2.Properties") + proto.RegisterType((*QueryParameterSubSchema)(nil), "openapi.v2.QueryParameterSubSchema") + proto.RegisterType((*Response)(nil), "openapi.v2.Response") + proto.RegisterType((*ResponseDefinitions)(nil), "openapi.v2.ResponseDefinitions") + proto.RegisterType((*ResponseValue)(nil), "openapi.v2.ResponseValue") + proto.RegisterType((*Responses)(nil), "openapi.v2.Responses") + proto.RegisterType((*Schema)(nil), "openapi.v2.Schema") + proto.RegisterType((*SchemaItem)(nil), "openapi.v2.SchemaItem") + proto.RegisterType((*SecurityDefinitions)(nil), "openapi.v2.SecurityDefinitions") + proto.RegisterType((*SecurityDefinitionsItem)(nil), "openapi.v2.SecurityDefinitionsItem") + proto.RegisterType((*SecurityRequirement)(nil), "openapi.v2.SecurityRequirement") + proto.RegisterType((*StringArray)(nil), "openapi.v2.StringArray") + proto.RegisterType((*Tag)(nil), "openapi.v2.Tag") + proto.RegisterType((*TypeItem)(nil), "openapi.v2.TypeItem") + proto.RegisterType((*VendorExtension)(nil), "openapi.v2.VendorExtension") + proto.RegisterType((*Xml)(nil), "openapi.v2.Xml") +} + +func init() { proto.RegisterFile("OpenAPIv2/OpenAPIv2.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 3129 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xec, 0x3b, 0x4b, 0x73, 0x1c, 0x57, + 0xd5, 0xf3, 0x7e, 0x1c, 0x69, 0x46, 0xa3, 0x96, 0x2c, 0xb7, 0x24, 0xc7, 0x71, 0xe4, 0x3c, 0x6c, + 0xe7, 0xb3, 0x9c, 0x4f, 0x29, 0x48, 0x05, 0x2a, 0x05, 0xf2, 0xab, 0xc6, 0xc4, 0x44, 0x4a, 0xcb, + 0x0e, 0x09, 0x04, 0xba, 0xae, 0x66, 0xee, 0x48, 0x9d, 0x74, 0xf7, 0x6d, 0x77, 0xf7, 0xc8, 0x1a, + 0x16, 0x2c, 0xa0, 0x8a, 0x35, 0x50, 0x59, 0x53, 0x15, 0x16, 0x14, 0x55, 0x59, 0xb0, 0x62, 0xc5, + 0x1f, 0x60, 0xc7, 0x3f, 0x60, 0x0d, 0x5b, 0xaa, 0x58, 0x51, 0x3c, 0xea, 0xbe, 0xfa, 0x31, 0x7d, + 0x7b, 0x1e, 0x96, 0x0b, 0x28, 0xd0, 0x6a, 0xe6, 0xde, 0x73, 0xee, 0xb9, 0xa7, 0x4f, 0x9f, 0xd7, + 0x3d, 0xe7, 0x36, 0xac, 0xef, 0x79, 0xd8, 0xdd, 0xdd, 0x7f, 0x70, 0xb2, 0x73, 0x2b, 0xfa, 0xb7, + 0xed, 0xf9, 0x24, 0x24, 0x1a, 0x10, 0x0f, 0xbb, 0xc8, 0xb3, 0xb6, 0x4f, 0x76, 0x36, 0xd6, 0x8f, + 0x08, 0x39, 0xb2, 0xf1, 0x2d, 0x06, 0x39, 0x1c, 0x0e, 0x6e, 0x21, 0x77, 0xc4, 0xd1, 0xb6, 0x1c, + 0xd0, 0x77, 0xfb, 0x7d, 0x2b, 0xb4, 0x88, 0x8b, 0xec, 0x7d, 0x9f, 0x78, 0xd8, 0x0f, 0x2d, 0x1c, + 0x3c, 0x08, 0xb1, 0xa3, 0xfd, 0x1f, 0xd4, 0x82, 0xde, 0x31, 0x76, 0x90, 0x5e, 0xbc, 0x52, 0xbc, + 0xb6, 0xb0, 0xa3, 0x6d, 0xc7, 0x34, 0xb7, 0x0f, 0x18, 0xa4, 0x5b, 0x30, 0x04, 0x8e, 0xb6, 0x01, + 0xf5, 0x43, 0x42, 0x6c, 0x8c, 0x5c, 0xbd, 0x74, 0xa5, 0x78, 0xad, 0xd1, 0x2d, 0x18, 0x72, 0xe2, + 0x76, 0x1d, 0xaa, 0xc4, 0xc5, 0x64, 0xb0, 0x75, 0x0f, 0xca, 0xbb, 0xee, 0x48, 0xbb, 0x01, 0xd5, + 0x13, 0x64, 0x0f, 0xb1, 0x20, 0xbc, 0xba, 0xcd, 0x19, 0xdc, 0x96, 0x0c, 0x6e, 0xef, 0xba, 0x23, + 0x83, 0xa3, 0x68, 0x1a, 0x54, 0x46, 0xc8, 0xb1, 0x19, 0xd1, 0xa6, 0xc1, 0xfe, 0x6f, 0x7d, 0x51, + 0x84, 0xf6, 0xae, 0x67, 0xbd, 0x8b, 0x47, 0x07, 0xb8, 0x37, 0xf4, 0xad, 0x70, 0x44, 0xd1, 0xc2, + 0x91, 0xc7, 0x29, 0x36, 0x0d, 0xf6, 0x9f, 0xce, 0xb9, 0xc8, 0xc1, 0x72, 0x29, 0xfd, 0xaf, 0xb5, + 0xa1, 0x64, 0xb9, 0x7a, 0x99, 0xcd, 0x94, 0x2c, 0x57, 0xbb, 0x02, 0x0b, 0x7d, 0x1c, 0xf4, 0x7c, + 0xcb, 0xa3, 0x32, 0xd0, 0x2b, 0x0c, 0x90, 0x9c, 0xd2, 0xbe, 0x06, 0x9d, 0x13, 0xec, 0xf6, 0x89, + 0x6f, 0xe2, 0xd3, 0x10, 0xbb, 0x01, 0x45, 0xab, 0x5e, 0x29, 0x33, 0xbe, 0x13, 0x02, 0x79, 0x0f, + 0x39, 0xb8, 0x4f, 0xf9, 0x5e, 0xe2, 0xd8, 0xf7, 0x24, 0xf2, 0xd6, 0x67, 0x45, 0xd8, 0xbc, 0x8d, + 0x02, 0xab, 0xb7, 0x3b, 0x0c, 0x8f, 0xb1, 0x1b, 0x5a, 0x3d, 0x44, 0x09, 0x4f, 0x64, 0x7d, 0x8c, + 0xad, 0xd2, 0x6c, 0x6c, 0x95, 0xe7, 0x61, 0xeb, 0x0f, 0x45, 0x68, 0xdd, 0x26, 0xfd, 0xd1, 0x3e, + 0xf2, 0x91, 0x83, 0x43, 0xec, 0x8f, 0x6f, 0x5a, 0xcc, 0x6e, 0x3a, 0x8b, 0x44, 0x37, 0xa0, 0xe1, + 0xe3, 0x27, 0x43, 0xcb, 0xc7, 0x7d, 0x26, 0xce, 0x86, 0x11, 0x8d, 0xb5, 0x1b, 0x91, 0x4a, 0x55, + 0xf3, 0x54, 0x2a, 0x52, 0x28, 0xd5, 0x03, 0xd6, 0xe6, 0x79, 0xc0, 0x1f, 0x17, 0xa1, 0x7e, 0x87, + 0xb8, 0x21, 0xea, 0x85, 0x11, 0xe3, 0xc5, 0x04, 0xe3, 0x1d, 0x28, 0x0f, 0x7d, 0xa9, 0x58, 0xf4, + 0xaf, 0xb6, 0x0a, 0x55, 0xec, 0x20, 0xcb, 0x16, 0x4f, 0xc3, 0x07, 0x4a, 0x46, 0x2a, 0xf3, 0x30, + 0xf2, 0x08, 0xea, 0x77, 0xf1, 0x00, 0x0d, 0xed, 0x50, 0x7b, 0x00, 0x17, 0x50, 0x64, 0x6f, 0xa6, + 0x17, 0x19, 0x9c, 0x5e, 0x9c, 0x40, 0x70, 0x15, 0x29, 0x4c, 0x74, 0xeb, 0x3b, 0xb0, 0x70, 0x17, + 0x0f, 0x2c, 0x97, 0x41, 0x02, 0xed, 0xe1, 0x64, 0xca, 0x17, 0x33, 0x94, 0x85, 0xb8, 0xd5, 0xc4, + 0xff, 0x58, 0x85, 0xc6, 0x5d, 0xd2, 0x1b, 0x3a, 0xd8, 0x0d, 0x35, 0x1d, 0xea, 0xc1, 0x53, 0x74, + 0x74, 0x84, 0x7d, 0x21, 0x3f, 0x39, 0xd4, 0x5e, 0x86, 0x8a, 0xe5, 0x0e, 0x08, 0x93, 0xe1, 0xc2, + 0x4e, 0x27, 0xb9, 0xc7, 0x03, 0x77, 0x40, 0x0c, 0x06, 0xa5, 0xc2, 0x3f, 0x26, 0x41, 0x28, 0xa4, + 0xca, 0xfe, 0x6b, 0x9b, 0xd0, 0x3c, 0x44, 0x01, 0x36, 0x3d, 0x14, 0x1e, 0x0b, 0xab, 0x6b, 0xd0, + 0x89, 0x7d, 0x14, 0x1e, 0xb3, 0x0d, 0x29, 0x77, 0x38, 0x60, 0x96, 0x46, 0x37, 0xe4, 0x43, 0xaa, + 0x5c, 0x3d, 0xe2, 0x06, 0x43, 0x0a, 0xaa, 0x31, 0x50, 0x34, 0xa6, 0x30, 0xcf, 0x27, 0xfd, 0x61, + 0x0f, 0x07, 0x7a, 0x9d, 0xc3, 0xe4, 0x58, 0x7b, 0x0d, 0xaa, 0x74, 0xa7, 0x40, 0x6f, 0x30, 0x4e, + 0x97, 0x93, 0x9c, 0xd2, 0x2d, 0x03, 0x83, 0xc3, 0xb5, 0xb7, 0xa9, 0x0d, 0x44, 0x52, 0xd5, 0x9b, + 0x0c, 0x3d, 0x25, 0xbc, 0x84, 0xd0, 0x8d, 0x24, 0xae, 0xf6, 0x75, 0x00, 0x4f, 0xda, 0x52, 0xa0, + 0x03, 0x5b, 0x79, 0x25, 0xbd, 0x91, 0x80, 0x26, 0x49, 0x24, 0xd6, 0x68, 0xef, 0x40, 0xd3, 0xc7, + 0x81, 0x47, 0xdc, 0x00, 0x07, 0xfa, 0x02, 0x23, 0xf0, 0x62, 0x92, 0x80, 0x21, 0x80, 0xc9, 0xf5, + 0xf1, 0x0a, 0xed, 0xab, 0xd0, 0x08, 0x84, 0x53, 0xd1, 0x17, 0xd9, 0x5b, 0x4f, 0xad, 0x96, 0x0e, + 0xc7, 0xe0, 0xd6, 0x48, 0x5f, 0xad, 0x11, 0x2d, 0xd0, 0x0c, 0x58, 0x95, 0xff, 0xcd, 0xa4, 0x04, + 0x5a, 0x59, 0x36, 0x24, 0xa1, 0x24, 0x1b, 0x2b, 0x41, 0x76, 0x52, 0xbb, 0x0a, 0x95, 0x10, 0x1d, + 0x05, 0x7a, 0x9b, 0x31, 0xb3, 0x94, 0xa4, 0xf1, 0x08, 0x1d, 0x19, 0x0c, 0xa8, 0xbd, 0x03, 0x2d, + 0x6a, 0x57, 0x3e, 0x55, 0xdb, 0x3e, 0xe9, 0x05, 0xfa, 0x12, 0xdb, 0x51, 0x4f, 0x62, 0xdf, 0x13, + 0x08, 0x77, 0x49, 0x2f, 0x30, 0x16, 0x71, 0x62, 0xa4, 0xb4, 0xce, 0xce, 0x3c, 0xd6, 0xf9, 0x18, + 0x1a, 0xf7, 0x4e, 0x91, 0xe3, 0xd9, 0x38, 0x78, 0x9e, 0xe6, 0xf9, 0xa3, 0x22, 0x2c, 0x26, 0xd9, + 0x9e, 0xc1, 0xbb, 0x66, 0x1d, 0xd2, 0x99, 0x9d, 0xfc, 0x3f, 0x4a, 0x00, 0xf7, 0x2d, 0x1b, 0x73, + 0x63, 0xd7, 0xd6, 0xa0, 0x36, 0x20, 0xbe, 0x83, 0x42, 0xb1, 0xbd, 0x18, 0x51, 0xc7, 0x17, 0x5a, + 0xa1, 0x2d, 0x1d, 0x3b, 0x1f, 0x8c, 0x73, 0x5c, 0xce, 0x72, 0x7c, 0x1d, 0xea, 0x7d, 0xee, 0xd9, + 0x98, 0x0d, 0x8f, 0xbd, 0x63, 0xca, 0x91, 0x84, 0xa7, 0xc2, 0x02, 0x37, 0xea, 0x38, 0x2c, 0xc8, + 0x08, 0x58, 0x4b, 0x44, 0xc0, 0x4d, 0x6a, 0x0b, 0xa8, 0x6f, 0x12, 0xd7, 0x1e, 0xe9, 0x75, 0x19, + 0x47, 0x50, 0x7f, 0xcf, 0xb5, 0x47, 0x59, 0x9d, 0x69, 0xcc, 0xa5, 0x33, 0xd7, 0xa1, 0x8e, 0xf9, + 0x2b, 0x17, 0x06, 0x9e, 0x65, 0x5b, 0xc0, 0x95, 0x6f, 0x00, 0xe6, 0x79, 0x03, 0x5f, 0xd4, 0x60, + 0xe3, 0x3e, 0xf1, 0x9d, 0xbb, 0x28, 0x44, 0x91, 0x03, 0x38, 0x18, 0x1e, 0x1e, 0xc8, 0xb4, 0x29, + 0x16, 0x4b, 0x71, 0x2c, 0x5a, 0xf2, 0xc8, 0x5a, 0xca, 0xcb, 0x55, 0xca, 0xf9, 0xf1, 0xb9, 0x92, + 0x08, 0x73, 0x37, 0x60, 0x19, 0xd9, 0x36, 0x79, 0x6a, 0x62, 0xc7, 0x0b, 0x47, 0x26, 0x4f, 0xbc, + 0xaa, 0x6c, 0xab, 0x25, 0x06, 0xb8, 0x47, 0xe7, 0x3f, 0x90, 0xc9, 0x56, 0xe6, 0x45, 0xc4, 0x3a, + 0x53, 0x4f, 0xe9, 0xcc, 0xff, 0x43, 0xd5, 0x0a, 0xb1, 0x23, 0x65, 0xbf, 0x99, 0xf2, 0x74, 0xbe, + 0xe5, 0x58, 0xa1, 0x75, 0xc2, 0x33, 0xc9, 0xc0, 0xe0, 0x98, 0xda, 0xeb, 0xb0, 0xdc, 0x23, 0xb6, + 0x8d, 0x7b, 0x94, 0x59, 0x53, 0x50, 0x6d, 0x32, 0xaa, 0x9d, 0x18, 0x70, 0x9f, 0xd3, 0x4f, 0xe8, + 0x16, 0x4c, 0xd1, 0x2d, 0x1d, 0xea, 0x0e, 0x3a, 0xb5, 0x9c, 0xa1, 0xc3, 0xbc, 0x66, 0xd1, 0x90, + 0x43, 0xba, 0x23, 0x3e, 0xed, 0xd9, 0xc3, 0xc0, 0x3a, 0xc1, 0xa6, 0xc4, 0x59, 0x64, 0x0f, 0xdf, + 0x89, 0x00, 0xdf, 0x14, 0xc8, 0x94, 0x8c, 0xe5, 0x32, 0x94, 0x96, 0x20, 0xc3, 0x87, 0x63, 0x64, + 0x04, 0x4e, 0x7b, 0x9c, 0x8c, 0x40, 0x7e, 0x01, 0xc0, 0x41, 0xa7, 0xa6, 0x8d, 0xdd, 0xa3, 0xf0, + 0x98, 0x79, 0xb3, 0xb2, 0xd1, 0x74, 0xd0, 0xe9, 0x43, 0x36, 0xc1, 0xc0, 0x96, 0x2b, 0xc1, 0x1d, + 0x01, 0xb6, 0x5c, 0x01, 0xd6, 0xa1, 0xee, 0xa1, 0x90, 0x2a, 0xab, 0xbe, 0xcc, 0x83, 0xad, 0x18, + 0x52, 0x8b, 0xa0, 0x74, 0xb9, 0xd0, 0x35, 0xb6, 0xae, 0xe1, 0xa0, 0x53, 0x26, 0x61, 0x06, 0xb4, + 0x5c, 0x01, 0x5c, 0x11, 0x40, 0xcb, 0xe5, 0xc0, 0x97, 0x60, 0x71, 0xe8, 0x5a, 0x4f, 0x86, 0x58, + 0xc0, 0x57, 0x19, 0xe7, 0x0b, 0x7c, 0x8e, 0xa3, 0x5c, 0x85, 0x0a, 0x76, 0x87, 0x8e, 0x7e, 0x21, + 0xeb, 0xaa, 0xa9, 0xa8, 0x19, 0x50, 0x7b, 0x11, 0x16, 0x9c, 0xa1, 0x1d, 0x5a, 0x9e, 0x8d, 0x4d, + 0x32, 0xd0, 0xd7, 0x98, 0x90, 0x40, 0x4e, 0xed, 0x0d, 0x94, 0xd6, 0x72, 0x71, 0x2e, 0x6b, 0xa9, + 0x42, 0xad, 0x8b, 0x51, 0x1f, 0xfb, 0xca, 0xb4, 0x38, 0xd6, 0xc5, 0x92, 0x5a, 0x17, 0xcb, 0x67, + 0xd3, 0xc5, 0xca, 0x74, 0x5d, 0xac, 0xce, 0xae, 0x8b, 0xb5, 0x19, 0x74, 0xb1, 0x3e, 0x5d, 0x17, + 0x1b, 0x33, 0xe8, 0x62, 0x73, 0x26, 0x5d, 0x84, 0xc9, 0xba, 0xb8, 0x30, 0x41, 0x17, 0x17, 0x27, + 0xe8, 0x62, 0x6b, 0x92, 0x2e, 0xb6, 0xa7, 0xe8, 0xe2, 0x52, 0xbe, 0x2e, 0x76, 0xe6, 0xd0, 0xc5, + 0xe5, 0x8c, 0x2e, 0x8e, 0x79, 0x4b, 0x6d, 0xb6, 0x23, 0xd4, 0xca, 0x3c, 0xda, 0xfa, 0xb7, 0x2a, + 0xe8, 0x5c, 0x5b, 0xff, 0x2d, 0x9e, 0x5d, 0x5a, 0x48, 0x55, 0x69, 0x21, 0x35, 0xb5, 0x85, 0xd4, + 0xcf, 0x66, 0x21, 0x8d, 0xe9, 0x16, 0xd2, 0x9c, 0xdd, 0x42, 0x60, 0x06, 0x0b, 0x59, 0x98, 0x6e, + 0x21, 0x8b, 0x33, 0x58, 0x48, 0x6b, 0x26, 0x0b, 0x69, 0x4f, 0xb6, 0x90, 0xa5, 0x09, 0x16, 0xd2, + 0x99, 0x60, 0x21, 0xcb, 0x93, 0x2c, 0x44, 0x9b, 0x62, 0x21, 0x2b, 0xf9, 0x16, 0xb2, 0x3a, 0x87, + 0x85, 0x5c, 0x98, 0xc9, 0x5b, 0xaf, 0xcd, 0xa3, 0xff, 0xdf, 0x82, 0x3a, 0x57, 0xff, 0x67, 0x38, + 0x7e, 0xf2, 0x85, 0x39, 0xc9, 0xf3, 0xe7, 0x25, 0xa8, 0xd0, 0x03, 0x64, 0x9c, 0x98, 0x16, 0x93, + 0x89, 0xa9, 0x0e, 0xf5, 0x13, 0xec, 0x07, 0x71, 0x65, 0x44, 0x0e, 0x67, 0x30, 0xa4, 0x6b, 0xd0, + 0x09, 0xb1, 0xef, 0x04, 0x26, 0x19, 0x98, 0x01, 0xf6, 0x4f, 0xac, 0x9e, 0x34, 0xaa, 0x36, 0x9b, + 0xdf, 0x1b, 0x1c, 0xf0, 0x59, 0xed, 0x26, 0xd4, 0x7b, 0xbc, 0x7c, 0x20, 0x9c, 0xfe, 0x4a, 0xf2, + 0x21, 0x44, 0x65, 0xc1, 0x90, 0x38, 0x14, 0xdd, 0xb6, 0x7a, 0xd8, 0x0d, 0x78, 0xfa, 0x34, 0x86, + 0xfe, 0x90, 0x83, 0x0c, 0x89, 0xa3, 0x14, 0x7e, 0x7d, 0x1e, 0xe1, 0xbf, 0x05, 0x4d, 0xa6, 0x0c, + 0xac, 0x56, 0x77, 0x23, 0x51, 0xab, 0x2b, 0x4f, 0x2e, 0xac, 0x6c, 0xdd, 0x85, 0xd6, 0x37, 0x02, + 0xe2, 0x1a, 0x78, 0x80, 0x7d, 0xec, 0xf6, 0xb0, 0xb6, 0x0c, 0x15, 0xd3, 0xc7, 0x03, 0x21, 0xe3, + 0xb2, 0x81, 0x07, 0xd3, 0xeb, 0x4f, 0x5b, 0x1e, 0xd4, 0xc5, 0x33, 0xcd, 0x58, 0x5c, 0x39, 0xf3, + 0x59, 0xe6, 0x1e, 0x34, 0x24, 0x50, 0xb9, 0xe5, 0x2b, 0xb2, 0xaa, 0x58, 0x52, 0x3b, 0x20, 0x0e, + 0xdd, 0x7a, 0x17, 0x16, 0x12, 0x0a, 0xa8, 0xa4, 0x74, 0x2d, 0x4d, 0x29, 0x25, 0x4c, 0xa1, 0xb7, + 0x82, 0xd8, 0xfb, 0xd0, 0x66, 0xc4, 0xe2, 0x22, 0x9a, 0x8a, 0xde, 0xeb, 0x69, 0x7a, 0x17, 0x94, + 0x45, 0x01, 0x49, 0x72, 0x0f, 0x5a, 0x82, 0x64, 0x78, 0xcc, 0xde, 0xad, 0x8a, 0xe2, 0x8d, 0x34, + 0xc5, 0xd5, 0xf1, 0x7a, 0x06, 0x5d, 0x38, 0x4e, 0x50, 0x56, 0x0f, 0xe6, 0x26, 0x28, 0x17, 0x4a, + 0x82, 0x1f, 0x81, 0x96, 0x22, 0x18, 0x9d, 0x1d, 0x32, 0x54, 0x6f, 0xa5, 0xa9, 0xae, 0xab, 0xa8, + 0xb2, 0xd5, 0xe3, 0x2f, 0x47, 0xc4, 0xd0, 0x79, 0x5f, 0x8e, 0xd0, 0x74, 0x41, 0xcc, 0x81, 0x4b, + 0x9c, 0x58, 0xb6, 0x34, 0x91, 0x2b, 0xd8, 0xb7, 0xd3, 0xd4, 0xaf, 0x4e, 0xa9, 0x7b, 0x24, 0xe5, + 0xfc, 0x96, 0xe4, 0x3d, 0xf4, 0x2d, 0xf7, 0x48, 0x49, 0x7d, 0x35, 0x49, 0xbd, 0x29, 0x17, 0x3e, + 0x86, 0x4e, 0x62, 0xe1, 0xae, 0xef, 0x23, 0xb5, 0x82, 0xdf, 0x4c, 0xf3, 0x96, 0xf2, 0xa9, 0x89, + 0xb5, 0x92, 0xec, 0x6f, 0xca, 0xd0, 0x79, 0x8f, 0xb8, 0xe9, 0x1a, 0x2f, 0x86, 0xcd, 0x63, 0xa6, + 0xc1, 0x66, 0x54, 0x77, 0x32, 0x83, 0xe1, 0xa1, 0x99, 0xaa, 0xf4, 0xbf, 0x9c, 0x55, 0xf8, 0x6c, + 0x82, 0xd3, 0x2d, 0x18, 0xfa, 0x71, 0x5e, 0xf2, 0x63, 0xc3, 0x65, 0x9a, 0x30, 0x98, 0x7d, 0x14, + 0x22, 0xf5, 0x4e, 0xfc, 0x19, 0x5e, 0x4d, 0xee, 0x94, 0x7f, 0x4c, 0xee, 0x16, 0x8c, 0x8d, 0x41, + 0xfe, 0x21, 0xfa, 0x10, 0x36, 0x9e, 0x0c, 0xb1, 0x3f, 0x52, 0xef, 0x54, 0xce, 0xbe, 0xc9, 0xf7, + 0x29, 0xb6, 0x72, 0x9b, 0x8b, 0x4f, 0xd4, 0x20, 0xcd, 0x84, 0x75, 0x0f, 0x85, 0xc7, 0xea, 0x2d, + 0x78, 0xf1, 0x63, 0x6b, 0xdc, 0x0a, 0x95, 0x3b, 0xac, 0x79, 0x4a, 0x48, 0xdc, 0x24, 0xf9, 0xbc, + 0x04, 0xfa, 0x1e, 0x1a, 0x86, 0xc7, 0x3b, 0xbb, 0xbd, 0x1e, 0x0e, 0x82, 0x3b, 0xa4, 0x8f, 0xa7, + 0xf5, 0x39, 0x06, 0x36, 0x79, 0x2a, 0xab, 0xf2, 0xf4, 0xbf, 0xf6, 0x06, 0x0d, 0x08, 0xc4, 0xc3, + 0xf2, 0x48, 0x94, 0x2a, 0x8d, 0x70, 0xea, 0x07, 0x0c, 0x6e, 0x08, 0x3c, 0x9a, 0x35, 0xd1, 0x69, + 0xe2, 0x5b, 0xdf, 0x67, 0xfd, 0x09, 0x93, 0xfa, 0x6f, 0x71, 0x20, 0x4a, 0x01, 0x1e, 0xfb, 0x36, + 0x4d, 0x60, 0x42, 0xf2, 0x29, 0xe6, 0x48, 0x3c, 0xff, 0x6c, 0xb0, 0x09, 0x0a, 0x1c, 0x0b, 0x1e, + 0xb5, 0xd9, 0x32, 0xef, 0xb9, 0x82, 0xdf, 0x5f, 0x8a, 0xb0, 0x2e, 0x64, 0xe4, 0x79, 0xf6, 0x2c, + 0x1d, 0x95, 0xe7, 0x23, 0xa4, 0xd4, 0x73, 0x57, 0x26, 0x3f, 0x77, 0x75, 0xb6, 0xe7, 0x9e, 0xab, + 0xa7, 0xf1, 0xc3, 0x12, 0xac, 0x71, 0xc6, 0x1e, 0x38, 0xf4, 0xb9, 0xad, 0xf0, 0x3f, 0x4d, 0x33, + 0xfe, 0x05, 0x42, 0xf8, 0x73, 0x51, 0x0a, 0x61, 0x1f, 0x05, 0xc1, 0x53, 0xe2, 0xf7, 0xff, 0x07, + 0xde, 0xfc, 0xc7, 0xb0, 0x98, 0xe4, 0xeb, 0x19, 0xfa, 0x3d, 0x2c, 0x42, 0xe4, 0x24, 0xdc, 0x3f, + 0xaf, 0x40, 0x73, 0xcf, 0xc3, 0x3e, 0x92, 0x87, 0x4d, 0x56, 0xb7, 0x2f, 0xb2, 0x3a, 0x2d, 0x2f, + 0xd3, 0xeb, 0x50, 0x0f, 0x86, 0x8e, 0x83, 0xfc, 0x91, 0xcc, 0xb9, 0xc5, 0x70, 0x86, 0x9c, 0x3b, + 0x53, 0xae, 0xad, 0xcc, 0x55, 0xae, 0x7d, 0x09, 0x16, 0x89, 0xe4, 0xcd, 0xb4, 0xfa, 0x52, 0xbc, + 0xd1, 0xdc, 0x83, 0x7e, 0xaa, 0xf7, 0x53, 0x1b, 0xeb, 0xfd, 0x24, 0x7b, 0x46, 0xf5, 0xb1, 0x9e, + 0xd1, 0x57, 0x52, 0x3d, 0x9b, 0x06, 0x13, 0xdd, 0x86, 0x32, 0x3d, 0xe3, 0xa1, 0x3e, 0xd9, 0xad, + 0x79, 0x33, 0xd9, 0xad, 0x69, 0x66, 0x33, 0x3b, 0x99, 0xe0, 0xa4, 0x7a, 0x34, 0x89, 0xd6, 0x16, + 0xa4, 0x5b, 0x5b, 0x97, 0x01, 0xfa, 0xd8, 0xf3, 0x71, 0x0f, 0x85, 0xb8, 0x2f, 0x4e, 0xbd, 0x89, + 0x99, 0xb3, 0x75, 0x77, 0x54, 0xea, 0xd7, 0x9a, 0x47, 0xfd, 0x7e, 0x59, 0x84, 0x66, 0x9c, 0x45, + 0xdc, 0x86, 0xf6, 0x21, 0xe9, 0x27, 0xe2, 0xad, 0x48, 0x1c, 0x52, 0x09, 0x5e, 0x2a, 0xf1, 0xe8, + 0x16, 0x8c, 0xd6, 0x61, 0x2a, 0x13, 0x79, 0x08, 0x9a, 0x4b, 0x5c, 0x73, 0x8c, 0x0e, 0x4f, 0x0b, + 0x2e, 0xa5, 0x98, 0x1a, 0xcb, 0x61, 0xba, 0x05, 0xa3, 0xe3, 0x8e, 0xcd, 0xc5, 0xd1, 0xf3, 0x08, + 0x56, 0x55, 0x7d, 0x36, 0x6d, 0x6f, 0xb2, 0xbd, 0x6c, 0x64, 0xc4, 0x10, 0x27, 0xe6, 0x6a, 0x93, + 0xf9, 0xac, 0x08, 0xed, 0xb4, 0x76, 0x68, 0x5f, 0x82, 0xe6, 0xb8, 0x44, 0xd4, 0xb9, 0x7e, 0xb7, + 0x60, 0xc4, 0x98, 0x54, 0x9a, 0x9f, 0x04, 0xc4, 0xa5, 0x67, 0x30, 0x7e, 0x22, 0x53, 0xa5, 0xcb, + 0xa9, 0x23, 0x1b, 0x95, 0xe6, 0x27, 0xc9, 0x89, 0xf8, 0xf9, 0x7f, 0x5f, 0x86, 0x46, 0x74, 0x74, + 0x50, 0x9c, 0xec, 0x5e, 0x83, 0xf2, 0x11, 0x0e, 0x55, 0x27, 0x91, 0xc8, 0xfe, 0x0d, 0x8a, 0x41, + 0x11, 0xbd, 0x61, 0x28, 0xfc, 0x63, 0x1e, 0xa2, 0x37, 0x0c, 0xb5, 0xeb, 0x50, 0xf1, 0x48, 0x20, + 0x3b, 0x40, 0x39, 0x98, 0x0c, 0x45, 0xbb, 0x09, 0xb5, 0x3e, 0xb6, 0x71, 0x88, 0xc5, 0x89, 0x3a, + 0x07, 0x59, 0x20, 0x69, 0xb7, 0xa0, 0x4e, 0x3c, 0xde, 0x86, 0xac, 0x4d, 0xc2, 0x97, 0x58, 0x94, + 0x15, 0x9a, 0x92, 0x8a, 0x22, 0x57, 0x1e, 0x2b, 0x14, 0x85, 0x9e, 0xc9, 0x3c, 0x14, 0xf6, 0x8e, + 0x45, 0xfb, 0x22, 0x07, 0x97, 0xe3, 0x8c, 0xb9, 0x89, 0xe6, 0x5c, 0x6e, 0xe2, 0xcc, 0x1d, 0xa4, + 0xbf, 0x56, 0x61, 0x4d, 0x9d, 0x4d, 0x9e, 0xd7, 0x18, 0xcf, 0x6b, 0x8c, 0xff, 0xed, 0x35, 0xc6, + 0xa7, 0x50, 0x65, 0x17, 0x34, 0x94, 0x94, 0x8a, 0x73, 0x50, 0xd2, 0x6e, 0x42, 0x85, 0xdd, 0x36, + 0x29, 0xb1, 0x45, 0xeb, 0x0a, 0x87, 0x2f, 0xea, 0x26, 0x0c, 0x6d, 0xeb, 0x67, 0x55, 0x58, 0x1a, + 0xd3, 0xda, 0xf3, 0x9e, 0xd4, 0x79, 0x4f, 0xea, 0x4c, 0x3d, 0x29, 0x95, 0x0e, 0x6b, 0xf3, 0x58, + 0xc3, 0xb7, 0x01, 0xe2, 0x14, 0xe4, 0x39, 0xdf, 0xf9, 0xfa, 0x55, 0x0d, 0x2e, 0xe6, 0x14, 0x46, + 0xce, 0xaf, 0x29, 0x9c, 0x5f, 0x53, 0x38, 0xbf, 0xa6, 0x10, 0x9b, 0xe1, 0xdf, 0x8b, 0xd0, 0x88, + 0xca, 0xe9, 0xd3, 0x2f, 0x76, 0x6d, 0x47, 0xdd, 0x19, 0x9e, 0x76, 0xaf, 0x65, 0x6b, 0xd6, 0x2c, + 0xf0, 0xc8, 0xab, 0xaf, 0x37, 0xa1, 0xce, 0x2b, 0xab, 0x32, 0x78, 0xac, 0x64, 0x0b, 0xb2, 0x81, + 0x21, 0x71, 0xb4, 0x37, 0xa0, 0x21, 0xae, 0x2b, 0xc9, 0x93, 0xf5, 0x6a, 0xfa, 0x64, 0xcd, 0x61, + 0x46, 0x84, 0x75, 0xf6, 0x3b, 0xcd, 0x18, 0x56, 0x14, 0x97, 0x11, 0xb5, 0xf7, 0x26, 0x3b, 0xa4, + 0x6c, 0xcc, 0x8d, 0x5a, 0x0b, 0x6a, 0x97, 0xf4, 0x93, 0x22, 0xb4, 0xd2, 0x5d, 0x86, 0x1d, 0xea, + 0x88, 0xf8, 0x44, 0x74, 0x7b, 0x5c, 0x71, 0xe6, 0xee, 0x16, 0x8c, 0x08, 0xef, 0xf9, 0x9e, 0xaf, + 0x7e, 0x5a, 0x84, 0x66, 0x74, 0xb2, 0xd7, 0xee, 0x40, 0x4b, 0x6e, 0x63, 0xf6, 0x48, 0x1f, 0x8b, + 0x07, 0xbd, 0x9c, 0xfb, 0xa0, 0xbc, 0xdb, 0xb1, 0x28, 0x17, 0xdd, 0x21, 0x7d, 0x75, 0x2b, 0xb0, + 0x34, 0xcf, 0xdb, 0xf8, 0x75, 0x13, 0x6a, 0xc2, 0x51, 0x2b, 0x4e, 0x7c, 0x79, 0x09, 0x4a, 0xd4, + 0x5b, 0x2d, 0x4f, 0xb8, 0xf4, 0x57, 0x99, 0x78, 0xe9, 0x6f, 0x5a, 0xe2, 0x31, 0x66, 0x89, 0xb5, + 0x8c, 0x25, 0x26, 0x5c, 0x62, 0x7d, 0x06, 0x97, 0xd8, 0x98, 0xee, 0x12, 0x9b, 0x33, 0xb8, 0x44, + 0x98, 0xc9, 0x25, 0x2e, 0x4c, 0x76, 0x89, 0x8b, 0x13, 0x5c, 0x62, 0x6b, 0x82, 0x4b, 0x6c, 0x4f, + 0x72, 0x89, 0x4b, 0x53, 0x5c, 0x62, 0x27, 0xeb, 0x12, 0x5f, 0x81, 0x36, 0x25, 0x9e, 0x30, 0x36, + 0x7e, 0x12, 0x68, 0x39, 0xe8, 0x34, 0x91, 0x2b, 0x50, 0x34, 0xcb, 0x4d, 0xa2, 0x69, 0x02, 0xcd, + 0x72, 0x13, 0x68, 0xc9, 0x40, 0xbf, 0x32, 0x76, 0x4d, 0x73, 0xa6, 0x13, 0xc1, 0x47, 0x79, 0x2e, + 0xe0, 0x42, 0xb6, 0xb5, 0x94, 0xf7, 0xe9, 0x89, 0xda, 0x1b, 0x68, 0xd7, 0x44, 0xd8, 0x5f, 0xcb, + 0xda, 0xfd, 0xa3, 0x91, 0x87, 0x79, 0xee, 0xce, 0x92, 0x81, 0xd7, 0x65, 0xd0, 0xbf, 0x98, 0x3d, + 0xdc, 0x47, 0x4d, 0x73, 0x19, 0xee, 0xaf, 0x43, 0x0d, 0xd9, 0x36, 0xd5, 0x4f, 0x3d, 0xb7, 0x77, + 0x5e, 0x45, 0xb6, 0xbd, 0x37, 0xd0, 0xbe, 0x0c, 0x90, 0x78, 0xa2, 0xf5, 0xac, 0x33, 0x8f, 0xb9, + 0x35, 0x12, 0x98, 0xda, 0xcb, 0xd0, 0xea, 0x5b, 0xd4, 0x82, 0x1c, 0xcb, 0x45, 0x21, 0xf1, 0xf5, + 0x0d, 0xa6, 0x20, 0xe9, 0xc9, 0xf4, 0x95, 0xd7, 0xcd, 0xb1, 0x2b, 0xaf, 0x2f, 0x41, 0xf9, 0xd4, + 0xb1, 0xf5, 0x4b, 0x59, 0x8b, 0xfb, 0xd0, 0xb1, 0x0d, 0x0a, 0xcb, 0x96, 0x59, 0x5f, 0x78, 0xd6, + 0x5b, 0xb1, 0x97, 0x9f, 0xe1, 0x56, 0xec, 0x8b, 0xf3, 0x78, 0xac, 0x1f, 0x00, 0xc4, 0x71, 0x6f, + 0xce, 0x2f, 0x8d, 0xde, 0x86, 0x85, 0x81, 0x65, 0x63, 0x33, 0x3f, 0xa4, 0xc6, 0x37, 0x9e, 0xbb, + 0x05, 0x03, 0x06, 0xd1, 0x28, 0xf6, 0xe2, 0x21, 0xac, 0x28, 0xba, 0xb9, 0xda, 0x77, 0x27, 0xc7, + 0xaf, 0x6b, 0xd9, 0x84, 0x3a, 0xa7, 0x25, 0xac, 0x0e, 0x67, 0x7f, 0xaa, 0xc0, 0xc5, 0xbc, 0x66, + 0xb4, 0x03, 0x2f, 0x1c, 0xa2, 0xc0, 0xea, 0x99, 0x28, 0xf5, 0x95, 0x90, 0x19, 0xd5, 0x7c, 0xb9, + 0x68, 0x5e, 0x4b, 0x55, 0x58, 0xf3, 0xbf, 0x2a, 0xea, 0x16, 0x8c, 0xcd, 0xc3, 0x09, 0x1f, 0x1d, + 0xdd, 0x87, 0x0e, 0xf2, 0x2c, 0xf3, 0x53, 0x3c, 0x8a, 0x77, 0xe0, 0x92, 0x4c, 0xd5, 0xb5, 0xd2, + 0x5f, 0x59, 0x75, 0x0b, 0x46, 0x1b, 0xa5, 0xbf, 0xbb, 0xfa, 0x1e, 0xe8, 0x84, 0xb5, 0x25, 0x4c, + 0x4b, 0x34, 0xa4, 0x62, 0x7a, 0xe5, 0x6c, 0x57, 0x54, 0xdd, 0xbb, 0xea, 0x16, 0x8c, 0x35, 0xa2, + 0xee, 0x6a, 0xc5, 0xf4, 0x3d, 0xd1, 0xeb, 0x89, 0xe9, 0x57, 0xf2, 0xe8, 0x8f, 0xb7, 0x85, 0x62, + 0xfa, 0x99, 0x86, 0xd1, 0x11, 0x6c, 0x0a, 0xfa, 0x28, 0x6e, 0x24, 0xc6, 0x5b, 0xf0, 0x00, 0xf7, + 0x4a, 0x76, 0x0b, 0x45, 0xdb, 0xb1, 0x5b, 0x30, 0xd6, 0x49, 0x6e, 0x4f, 0x12, 0xc7, 0x1b, 0xb1, + 0xae, 0x2e, 0x4b, 0x17, 0xe2, 0x8d, 0x6a, 0x59, 0xef, 0x98, 0xd7, 0x03, 0xee, 0x16, 0x0c, 0x21, + 0x93, 0x2c, 0x2c, 0xd6, 0xf0, 0xe3, 0x58, 0xc3, 0x13, 0x2d, 0x01, 0xed, 0xfd, 0xc9, 0x1a, 0x7e, + 0x29, 0xa7, 0x6d, 0xc4, 0x2f, 0x16, 0xa8, 0xb5, 0xfa, 0x2a, 0x2c, 0x24, 0x6f, 0x2e, 0xac, 0xc6, + 0x1f, 0xf7, 0x95, 0xe3, 0x3b, 0x0e, 0xbf, 0x2d, 0x42, 0xf9, 0x11, 0x52, 0xdf, 0x8a, 0x98, 0xfe, + 0xb1, 0x5b, 0xc6, 0xb3, 0x95, 0xcf, 0xfc, 0x8d, 0xc8, 0x5c, 0x5f, 0x70, 0x5d, 0x81, 0x86, 0x8c, + 0x30, 0x39, 0xcf, 0xf7, 0x31, 0x2c, 0x7d, 0x30, 0x56, 0x6f, 0x7a, 0x8e, 0x1f, 0x93, 0xfc, 0xae, + 0x08, 0xe5, 0x0f, 0x1d, 0x5b, 0x29, 0xbd, 0x4b, 0xd0, 0xa4, 0xbf, 0x81, 0x87, 0x7a, 0xf2, 0x5e, + 0x49, 0x3c, 0x41, 0x93, 0x3f, 0xcf, 0xc7, 0x03, 0xeb, 0x54, 0x64, 0x79, 0x62, 0x44, 0x57, 0xa1, + 0x30, 0xf4, 0xad, 0xc3, 0x61, 0x88, 0xc5, 0x67, 0x7a, 0xf1, 0x04, 0x4d, 0x65, 0x9e, 0xfa, 0xc8, + 0xf3, 0x70, 0x5f, 0x1c, 0xc1, 0xe5, 0xf0, 0xcc, 0x7d, 0xcc, 0xdb, 0xaf, 0x42, 0x9b, 0xf8, 0x47, + 0x12, 0xd7, 0x3c, 0xd9, 0xb9, 0xbd, 0x28, 0xbe, 0x5d, 0xdd, 0xf7, 0x49, 0x48, 0xf6, 0x8b, 0xbf, + 0x28, 0x95, 0xf7, 0x76, 0x0f, 0x0e, 0x6b, 0xec, 0x63, 0xd0, 0x37, 0xff, 0x19, 0x00, 0x00, 0xff, + 0xff, 0xd4, 0x0a, 0xef, 0xca, 0xe4, 0x3a, 0x00, 0x00, +} diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto new file mode 100644 index 000000000..557c88072 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto @@ -0,0 +1,663 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// THIS FILE IS AUTOMATICALLY GENERATED. + +syntax = "proto3"; + +package openapi.v2; + +import "google/protobuf/any.proto"; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "OpenAPIProto"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.openapi_v2"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +option objc_class_prefix = "OAS"; + +message AdditionalPropertiesItem { + oneof oneof { + Schema schema = 1; + bool boolean = 2; + } +} + +message Any { + google.protobuf.Any value = 1; + string yaml = 2; +} + +message ApiKeySecurity { + string type = 1; + string name = 2; + string in = 3; + string description = 4; + repeated NamedAny vendor_extension = 5; +} + +message BasicAuthenticationSecurity { + string type = 1; + string description = 2; + repeated NamedAny vendor_extension = 3; +} + +message BodyParameter { + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 1; + // The name of the parameter. + string name = 2; + // Determines the location of the parameter. + string in = 3; + // Determines whether or not this parameter is required or optional. + bool required = 4; + Schema schema = 5; + repeated NamedAny vendor_extension = 6; +} + +// Contact information for the owners of the API. +message Contact { + // The identifying name of the contact person/organization. + string name = 1; + // The URL pointing to the contact information. + string url = 2; + // The email address of the contact person/organization. + string email = 3; + repeated NamedAny vendor_extension = 4; +} + +message Default { + repeated NamedAny additional_properties = 1; +} + +// One or more JSON objects describing the schemas being consumed and produced by the API. +message Definitions { + repeated NamedSchema additional_properties = 1; +} + +message Document { + // The Swagger version of this document. + string swagger = 1; + Info info = 2; + // The host (name or ip) of the API. Example: 'swagger.io' + string host = 3; + // The base path to the API. Example: '/api'. + string base_path = 4; + // The transfer protocol of the API. + repeated string schemes = 5; + // A list of MIME types accepted by the API. + repeated string consumes = 6; + // A list of MIME types the API can produce. + repeated string produces = 7; + Paths paths = 8; + Definitions definitions = 9; + ParameterDefinitions parameters = 10; + ResponseDefinitions responses = 11; + repeated SecurityRequirement security = 12; + SecurityDefinitions security_definitions = 13; + repeated Tag tags = 14; + ExternalDocs external_docs = 15; + repeated NamedAny vendor_extension = 16; +} + +message Examples { + repeated NamedAny additional_properties = 1; +} + +// information about external documentation +message ExternalDocs { + string description = 1; + string url = 2; + repeated NamedAny vendor_extension = 3; +} + +// A deterministic version of a JSON Schema object. +message FileSchema { + string format = 1; + string title = 2; + string description = 3; + Any default = 4; + repeated string required = 5; + string type = 6; + bool read_only = 7; + ExternalDocs external_docs = 8; + Any example = 9; + repeated NamedAny vendor_extension = 10; +} + +message FormDataParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + // allows sending a parameter by name only or with an empty value. + bool allow_empty_value = 5; + string type = 6; + string format = 7; + PrimitivesItems items = 8; + string collection_format = 9; + Any default = 10; + double maximum = 11; + bool exclusive_maximum = 12; + double minimum = 13; + bool exclusive_minimum = 14; + int64 max_length = 15; + int64 min_length = 16; + string pattern = 17; + int64 max_items = 18; + int64 min_items = 19; + bool unique_items = 20; + repeated Any enum = 21; + double multiple_of = 22; + repeated NamedAny vendor_extension = 23; +} + +message Header { + string type = 1; + string format = 2; + PrimitivesItems items = 3; + string collection_format = 4; + Any default = 5; + double maximum = 6; + bool exclusive_maximum = 7; + double minimum = 8; + bool exclusive_minimum = 9; + int64 max_length = 10; + int64 min_length = 11; + string pattern = 12; + int64 max_items = 13; + int64 min_items = 14; + bool unique_items = 15; + repeated Any enum = 16; + double multiple_of = 17; + string description = 18; + repeated NamedAny vendor_extension = 19; +} + +message HeaderParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + string type = 5; + string format = 6; + PrimitivesItems items = 7; + string collection_format = 8; + Any default = 9; + double maximum = 10; + bool exclusive_maximum = 11; + double minimum = 12; + bool exclusive_minimum = 13; + int64 max_length = 14; + int64 min_length = 15; + string pattern = 16; + int64 max_items = 17; + int64 min_items = 18; + bool unique_items = 19; + repeated Any enum = 20; + double multiple_of = 21; + repeated NamedAny vendor_extension = 22; +} + +message Headers { + repeated NamedHeader additional_properties = 1; +} + +// General information about the API. +message Info { + // A unique and precise title of the API. + string title = 1; + // A semantic version number of the API. + string version = 2; + // A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed. + string description = 3; + // The terms of service for the API. + string terms_of_service = 4; + Contact contact = 5; + License license = 6; + repeated NamedAny vendor_extension = 7; +} + +message ItemsItem { + repeated Schema schema = 1; +} + +message JsonReference { + string _ref = 1; + string description = 2; +} + +message License { + // The name of the license type. It's encouraged to use an OSI compatible license. + string name = 1; + // The URL pointing to the license. + string url = 2; + repeated NamedAny vendor_extension = 3; +} + +// Automatically-generated message used to represent maps of Any as ordered (name,value) pairs. +message NamedAny { + // Map key + string name = 1; + // Mapped value + Any value = 2; +} + +// Automatically-generated message used to represent maps of Header as ordered (name,value) pairs. +message NamedHeader { + // Map key + string name = 1; + // Mapped value + Header value = 2; +} + +// Automatically-generated message used to represent maps of Parameter as ordered (name,value) pairs. +message NamedParameter { + // Map key + string name = 1; + // Mapped value + Parameter value = 2; +} + +// Automatically-generated message used to represent maps of PathItem as ordered (name,value) pairs. +message NamedPathItem { + // Map key + string name = 1; + // Mapped value + PathItem value = 2; +} + +// Automatically-generated message used to represent maps of Response as ordered (name,value) pairs. +message NamedResponse { + // Map key + string name = 1; + // Mapped value + Response value = 2; +} + +// Automatically-generated message used to represent maps of ResponseValue as ordered (name,value) pairs. +message NamedResponseValue { + // Map key + string name = 1; + // Mapped value + ResponseValue value = 2; +} + +// Automatically-generated message used to represent maps of Schema as ordered (name,value) pairs. +message NamedSchema { + // Map key + string name = 1; + // Mapped value + Schema value = 2; +} + +// Automatically-generated message used to represent maps of SecurityDefinitionsItem as ordered (name,value) pairs. +message NamedSecurityDefinitionsItem { + // Map key + string name = 1; + // Mapped value + SecurityDefinitionsItem value = 2; +} + +// Automatically-generated message used to represent maps of string as ordered (name,value) pairs. +message NamedString { + // Map key + string name = 1; + // Mapped value + string value = 2; +} + +// Automatically-generated message used to represent maps of StringArray as ordered (name,value) pairs. +message NamedStringArray { + // Map key + string name = 1; + // Mapped value + StringArray value = 2; +} + +message NonBodyParameter { + oneof oneof { + HeaderParameterSubSchema header_parameter_sub_schema = 1; + FormDataParameterSubSchema form_data_parameter_sub_schema = 2; + QueryParameterSubSchema query_parameter_sub_schema = 3; + PathParameterSubSchema path_parameter_sub_schema = 4; + } +} + +message Oauth2AccessCodeSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string authorization_url = 4; + string token_url = 5; + string description = 6; + repeated NamedAny vendor_extension = 7; +} + +message Oauth2ApplicationSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string token_url = 4; + string description = 5; + repeated NamedAny vendor_extension = 6; +} + +message Oauth2ImplicitSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string authorization_url = 4; + string description = 5; + repeated NamedAny vendor_extension = 6; +} + +message Oauth2PasswordSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string token_url = 4; + string description = 5; + repeated NamedAny vendor_extension = 6; +} + +message Oauth2Scopes { + repeated NamedString additional_properties = 1; +} + +message Operation { + repeated string tags = 1; + // A brief summary of the operation. + string summary = 2; + // A longer description of the operation, GitHub Flavored Markdown is allowed. + string description = 3; + ExternalDocs external_docs = 4; + // A unique identifier of the operation. + string operation_id = 5; + // A list of MIME types the API can produce. + repeated string produces = 6; + // A list of MIME types the API can consume. + repeated string consumes = 7; + // The parameters needed to send a valid API call. + repeated ParametersItem parameters = 8; + Responses responses = 9; + // The transfer protocol of the API. + repeated string schemes = 10; + bool deprecated = 11; + repeated SecurityRequirement security = 12; + repeated NamedAny vendor_extension = 13; +} + +message Parameter { + oneof oneof { + BodyParameter body_parameter = 1; + NonBodyParameter non_body_parameter = 2; + } +} + +// One or more JSON representations for parameters +message ParameterDefinitions { + repeated NamedParameter additional_properties = 1; +} + +message ParametersItem { + oneof oneof { + Parameter parameter = 1; + JsonReference json_reference = 2; + } +} + +message PathItem { + string _ref = 1; + Operation get = 2; + Operation put = 3; + Operation post = 4; + Operation delete = 5; + Operation options = 6; + Operation head = 7; + Operation patch = 8; + // The parameters needed to send a valid API call. + repeated ParametersItem parameters = 9; + repeated NamedAny vendor_extension = 10; +} + +message PathParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + string type = 5; + string format = 6; + PrimitivesItems items = 7; + string collection_format = 8; + Any default = 9; + double maximum = 10; + bool exclusive_maximum = 11; + double minimum = 12; + bool exclusive_minimum = 13; + int64 max_length = 14; + int64 min_length = 15; + string pattern = 16; + int64 max_items = 17; + int64 min_items = 18; + bool unique_items = 19; + repeated Any enum = 20; + double multiple_of = 21; + repeated NamedAny vendor_extension = 22; +} + +// Relative paths to the individual endpoints. They must be relative to the 'basePath'. +message Paths { + repeated NamedAny vendor_extension = 1; + repeated NamedPathItem path = 2; +} + +message PrimitivesItems { + string type = 1; + string format = 2; + PrimitivesItems items = 3; + string collection_format = 4; + Any default = 5; + double maximum = 6; + bool exclusive_maximum = 7; + double minimum = 8; + bool exclusive_minimum = 9; + int64 max_length = 10; + int64 min_length = 11; + string pattern = 12; + int64 max_items = 13; + int64 min_items = 14; + bool unique_items = 15; + repeated Any enum = 16; + double multiple_of = 17; + repeated NamedAny vendor_extension = 18; +} + +message Properties { + repeated NamedSchema additional_properties = 1; +} + +message QueryParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + // allows sending a parameter by name only or with an empty value. + bool allow_empty_value = 5; + string type = 6; + string format = 7; + PrimitivesItems items = 8; + string collection_format = 9; + Any default = 10; + double maximum = 11; + bool exclusive_maximum = 12; + double minimum = 13; + bool exclusive_minimum = 14; + int64 max_length = 15; + int64 min_length = 16; + string pattern = 17; + int64 max_items = 18; + int64 min_items = 19; + bool unique_items = 20; + repeated Any enum = 21; + double multiple_of = 22; + repeated NamedAny vendor_extension = 23; +} + +message Response { + string description = 1; + SchemaItem schema = 2; + Headers headers = 3; + Examples examples = 4; + repeated NamedAny vendor_extension = 5; +} + +// One or more JSON representations for parameters +message ResponseDefinitions { + repeated NamedResponse additional_properties = 1; +} + +message ResponseValue { + oneof oneof { + Response response = 1; + JsonReference json_reference = 2; + } +} + +// Response objects names can either be any valid HTTP status code or 'default'. +message Responses { + repeated NamedResponseValue response_code = 1; + repeated NamedAny vendor_extension = 2; +} + +// A deterministic version of a JSON Schema object. +message Schema { + string _ref = 1; + string format = 2; + string title = 3; + string description = 4; + Any default = 5; + double multiple_of = 6; + double maximum = 7; + bool exclusive_maximum = 8; + double minimum = 9; + bool exclusive_minimum = 10; + int64 max_length = 11; + int64 min_length = 12; + string pattern = 13; + int64 max_items = 14; + int64 min_items = 15; + bool unique_items = 16; + int64 max_properties = 17; + int64 min_properties = 18; + repeated string required = 19; + repeated Any enum = 20; + AdditionalPropertiesItem additional_properties = 21; + TypeItem type = 22; + ItemsItem items = 23; + repeated Schema all_of = 24; + Properties properties = 25; + string discriminator = 26; + bool read_only = 27; + Xml xml = 28; + ExternalDocs external_docs = 29; + Any example = 30; + repeated NamedAny vendor_extension = 31; +} + +message SchemaItem { + oneof oneof { + Schema schema = 1; + FileSchema file_schema = 2; + } +} + +message SecurityDefinitions { + repeated NamedSecurityDefinitionsItem additional_properties = 1; +} + +message SecurityDefinitionsItem { + oneof oneof { + BasicAuthenticationSecurity basic_authentication_security = 1; + ApiKeySecurity api_key_security = 2; + Oauth2ImplicitSecurity oauth2_implicit_security = 3; + Oauth2PasswordSecurity oauth2_password_security = 4; + Oauth2ApplicationSecurity oauth2_application_security = 5; + Oauth2AccessCodeSecurity oauth2_access_code_security = 6; + } +} + +message SecurityRequirement { + repeated NamedStringArray additional_properties = 1; +} + +message StringArray { + repeated string value = 1; +} + +message Tag { + string name = 1; + string description = 2; + ExternalDocs external_docs = 3; + repeated NamedAny vendor_extension = 4; +} + +message TypeItem { + repeated string value = 1; +} + +// Any property starting with x- is valid. +message VendorExtension { + repeated NamedAny additional_properties = 1; +} + +message Xml { + string name = 1; + string namespace = 2; + string prefix = 3; + bool attribute = 4; + bool wrapped = 5; + repeated NamedAny vendor_extension = 6; +} + diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md b/vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md new file mode 100644 index 000000000..836fb32a7 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md @@ -0,0 +1,16 @@ +# OpenAPI v2 Protocol Buffer Models + +This directory contains a Protocol Buffer-language model +and related code for supporting OpenAPI v2. + +Gnostic applications and plugins can use OpenAPIv2.proto +to generate Protocol Buffer support code for their preferred languages. + +OpenAPIv2.go is used by Gnostic to read JSON and YAML OpenAPI +descriptions into the Protocol Buffer-based datastructures +generated from OpenAPIv2.proto. + +OpenAPIv2.proto and OpenAPIv2.go are generated by the Gnostic +compiler generator, and OpenAPIv2.pb.go is generated by +protoc, the Protocol Buffer compiler, and protoc-gen-go, the +Protocol Buffer Go code generation plugin. diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json b/vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json new file mode 100644 index 000000000..2815a26ea --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json @@ -0,0 +1,1610 @@ +{ + "title": "A JSON Schema for Swagger 2.0 API.", + "id": "http://swagger.io/v2/schema.json#", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "required": [ + "swagger", + "info", + "paths" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "swagger": { + "type": "string", + "enum": [ + "2.0" + ], + "description": "The Swagger version of this document." + }, + "info": { + "$ref": "#/definitions/info" + }, + "host": { + "type": "string", + "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", + "description": "The host (name or ip) of the API. Example: 'swagger.io'" + }, + "basePath": { + "type": "string", + "pattern": "^/", + "description": "The base path to the API. Example: '/api'." + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "consumes": { + "description": "A list of MIME types accepted by the API.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "paths": { + "$ref": "#/definitions/paths" + }, + "definitions": { + "$ref": "#/definitions/definitions" + }, + "parameters": { + "$ref": "#/definitions/parameterDefinitions" + }, + "responses": { + "$ref": "#/definitions/responseDefinitions" + }, + "security": { + "$ref": "#/definitions/security" + }, + "securityDefinitions": { + "$ref": "#/definitions/securityDefinitions" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "definitions": { + "info": { + "type": "object", + "description": "General information about the API.", + "required": [ + "version", + "title" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "title": { + "type": "string", + "description": "A unique and precise title of the API." + }, + "version": { + "type": "string", + "description": "A semantic version number of the API." + }, + "description": { + "type": "string", + "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." + }, + "termsOfService": { + "type": "string", + "description": "The terms of service for the API." + }, + "contact": { + "$ref": "#/definitions/contact" + }, + "license": { + "$ref": "#/definitions/license" + } + } + }, + "contact": { + "type": "object", + "description": "Contact information for the owners of the API.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The identifying name of the contact person/organization." + }, + "url": { + "type": "string", + "description": "The URL pointing to the contact information.", + "format": "uri" + }, + "email": { + "type": "string", + "description": "The email address of the contact person/organization.", + "format": "email" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "license": { + "type": "object", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The name of the license type. It's encouraged to use an OSI compatible license." + }, + "url": { + "type": "string", + "description": "The URL pointing to the license.", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "paths": { + "type": "object", + "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + }, + "^/": { + "$ref": "#/definitions/pathItem" + } + }, + "additionalProperties": false + }, + "definitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "description": "One or more JSON objects describing the schemas being consumed and produced by the API." + }, + "parameterDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/parameter" + }, + "description": "One or more JSON representations for parameters" + }, + "responseDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/response" + }, + "description": "One or more JSON representations for parameters" + }, + "externalDocs": { + "type": "object", + "additionalProperties": false, + "description": "information about external documentation", + "required": [ + "url" + ], + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "examples": { + "type": "object", + "additionalProperties": true + }, + "mimeType": { + "type": "string", + "description": "The MIME type of the HTTP message." + }, + "operation": { + "type": "object", + "required": [ + "responses" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "summary": { + "type": "string", + "description": "A brief summary of the operation." + }, + "description": { + "type": "string", + "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "operationId": { + "type": "string", + "description": "A unique identifier of the operation." + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "consumes": { + "description": "A list of MIME types the API can consume.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "parameters": { + "$ref": "#/definitions/parametersList" + }, + "responses": { + "$ref": "#/definitions/responses" + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "security": { + "$ref": "#/definitions/security" + } + } + }, + "pathItem": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "get": { + "$ref": "#/definitions/operation" + }, + "put": { + "$ref": "#/definitions/operation" + }, + "post": { + "$ref": "#/definitions/operation" + }, + "delete": { + "$ref": "#/definitions/operation" + }, + "options": { + "$ref": "#/definitions/operation" + }, + "head": { + "$ref": "#/definitions/operation" + }, + "patch": { + "$ref": "#/definitions/operation" + }, + "parameters": { + "$ref": "#/definitions/parametersList" + } + } + }, + "responses": { + "type": "object", + "description": "Response objects names can either be any valid HTTP status code or 'default'.", + "minProperties": 1, + "additionalProperties": false, + "patternProperties": { + "^([0-9]{3})$|^(default)$": { + "$ref": "#/definitions/responseValue" + }, + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "not": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + } + }, + "responseValue": { + "oneOf": [ + { + "$ref": "#/definitions/response" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "response": { + "type": "object", + "required": [ + "description" + ], + "properties": { + "description": { + "type": "string" + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "$ref": "#/definitions/fileSchema" + } + ] + }, + "headers": { + "$ref": "#/definitions/headers" + }, + "examples": { + "$ref": "#/definitions/examples" + } + }, + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/header" + } + }, + "header": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "vendorExtension": { + "description": "Any property starting with x- is valid.", + "additionalProperties": true, + "additionalItems": true + }, + "bodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "schema" + ], + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "body" + ] + }, + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "schema": { + "$ref": "#/definitions/schema" + } + }, + "additionalProperties": false + }, + "headerParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "header" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "queryParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "query" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "formDataParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "formData" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array", + "file" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "pathParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "required" + ], + "properties": { + "required": { + "type": "boolean", + "enum": [ + true + ], + "description": "Determines whether or not this parameter is required or optional." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "path" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "nonBodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "type" + ], + "oneOf": [ + { + "$ref": "#/definitions/headerParameterSubSchema" + }, + { + "$ref": "#/definitions/formDataParameterSubSchema" + }, + { + "$ref": "#/definitions/queryParameterSubSchema" + }, + { + "$ref": "#/definitions/pathParameterSubSchema" + } + ] + }, + "parameter": { + "oneOf": [ + { + "$ref": "#/definitions/bodyParameter" + }, + { + "$ref": "#/definitions/nonBodyParameter" + } + ] + }, + "schema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "maxProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "boolean" + } + ], + "default": {} + }, + "type": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/type" + }, + "items": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + } + ], + "default": {} + }, + "allOf": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "default": {} + }, + "discriminator": { + "type": "string" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "xml": { + "$ref": "#/definitions/xml" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "fileSchema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "type" + ], + "properties": { + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "type": { + "type": "string", + "enum": [ + "file" + ] + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "primitivesItems": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "securityRequirement": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + }, + "xml": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean", + "default": false + }, + "wrapped": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "tag": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "securityDefinitions": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/basicAuthenticationSecurity" + }, + { + "$ref": "#/definitions/apiKeySecurity" + }, + { + "$ref": "#/definitions/oauth2ImplicitSecurity" + }, + { + "$ref": "#/definitions/oauth2PasswordSecurity" + }, + { + "$ref": "#/definitions/oauth2ApplicationSecurity" + }, + { + "$ref": "#/definitions/oauth2AccessCodeSecurity" + } + ] + } + }, + "basicAuthenticationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "basic" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "apiKeySecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "name", + "in" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "apiKey" + ] + }, + "name": { + "type": "string" + }, + "in": { + "type": "string", + "enum": [ + "header", + "query" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ImplicitSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "implicit" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2PasswordSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "password" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ApplicationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "application" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2AccessCodeSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "accessCode" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2Scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "mediaTypeList": { + "type": "array", + "items": { + "$ref": "#/definitions/mimeType" + }, + "uniqueItems": true + }, + "parametersList": { + "type": "array", + "description": "The parameters needed to send a valid API call.", + "additionalItems": false, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/parameter" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "uniqueItems": true + }, + "schemesList": { + "type": "array", + "description": "The transfer protocol of the API.", + "items": { + "type": "string", + "enum": [ + "http", + "https", + "ws", + "wss" + ] + }, + "uniqueItems": true + }, + "collectionFormat": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes" + ], + "default": "csv" + }, + "collectionFormatWithMulti": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes", + "multi" + ], + "default": "csv" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "jsonReference": { + "type": "object", + "required": [ + "$ref" + ], + "additionalProperties": false, + "properties": { + "$ref": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/README.md b/vendor/github.com/googleapis/gnostic/compiler/README.md new file mode 100644 index 000000000..848b16c69 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/README.md @@ -0,0 +1,3 @@ +# Compiler support code + +This directory contains compiler support code used by Gnostic and Gnostic extensions. \ No newline at end of file diff --git a/vendor/github.com/googleapis/gnostic/compiler/context.go b/vendor/github.com/googleapis/gnostic/compiler/context.go new file mode 100644 index 000000000..a64c1b75d --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/context.go @@ -0,0 +1,43 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +// Context contains state of the compiler as it traverses a document. +type Context struct { + Parent *Context + Name string + ExtensionHandlers *[]ExtensionHandler +} + +// NewContextWithExtensions returns a new object representing the compiler state +func NewContextWithExtensions(name string, parent *Context, extensionHandlers *[]ExtensionHandler) *Context { + return &Context{Name: name, Parent: parent, ExtensionHandlers: extensionHandlers} +} + +// NewContext returns a new object representing the compiler state +func NewContext(name string, parent *Context) *Context { + if parent != nil { + return &Context{Name: name, Parent: parent, ExtensionHandlers: parent.ExtensionHandlers} + } + return &Context{Name: name, Parent: parent, ExtensionHandlers: nil} +} + +// Description returns a text description of the compiler state +func (context *Context) Description() string { + if context.Parent != nil { + return context.Parent.Description() + "." + context.Name + } + return context.Name +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/error.go b/vendor/github.com/googleapis/gnostic/compiler/error.go new file mode 100644 index 000000000..d8672c100 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/error.go @@ -0,0 +1,61 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +// Error represents compiler errors and their location in the document. +type Error struct { + Context *Context + Message string +} + +// NewError creates an Error. +func NewError(context *Context, message string) *Error { + return &Error{Context: context, Message: message} +} + +// Error returns the string value of an Error. +func (err *Error) Error() string { + if err.Context == nil { + return "ERROR " + err.Message + } + return "ERROR " + err.Context.Description() + " " + err.Message +} + +// ErrorGroup is a container for groups of Error values. +type ErrorGroup struct { + Errors []error +} + +// NewErrorGroupOrNil returns a new ErrorGroup for a slice of errors or nil if the slice is empty. +func NewErrorGroupOrNil(errors []error) error { + if len(errors) == 0 { + return nil + } else if len(errors) == 1 { + return errors[0] + } else { + return &ErrorGroup{Errors: errors} + } +} + +func (group *ErrorGroup) Error() string { + result := "" + for i, err := range group.Errors { + if i > 0 { + result += "\n" + } + result += err.Error() + } + return result +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/extension-handler.go b/vendor/github.com/googleapis/gnostic/compiler/extension-handler.go new file mode 100644 index 000000000..1f85b650e --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/extension-handler.go @@ -0,0 +1,101 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +import ( + "bytes" + "fmt" + "os/exec" + + "strings" + + "errors" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" + ext_plugin "github.com/googleapis/gnostic/extensions" + yaml "gopkg.in/yaml.v2" +) + +// ExtensionHandler describes a binary that is called by the compiler to handle specification extensions. +type ExtensionHandler struct { + Name string +} + +// HandleExtension calls a binary extension handler. +func HandleExtension(context *Context, in interface{}, extensionName string) (bool, *any.Any, error) { + handled := false + var errFromPlugin error + var outFromPlugin *any.Any + + if context != nil && context.ExtensionHandlers != nil && len(*(context.ExtensionHandlers)) != 0 { + for _, customAnyProtoGenerator := range *(context.ExtensionHandlers) { + outFromPlugin, errFromPlugin = customAnyProtoGenerator.handle(in, extensionName) + if outFromPlugin == nil { + continue + } else { + handled = true + break + } + } + } + return handled, outFromPlugin, errFromPlugin +} + +func (extensionHandlers *ExtensionHandler) handle(in interface{}, extensionName string) (*any.Any, error) { + if extensionHandlers.Name != "" { + binary, _ := yaml.Marshal(in) + + request := &ext_plugin.ExtensionHandlerRequest{} + + version := &ext_plugin.Version{} + version.Major = 0 + version.Minor = 1 + version.Patch = 0 + request.CompilerVersion = version + + request.Wrapper = &ext_plugin.Wrapper{} + + request.Wrapper.Version = "v2" + request.Wrapper.Yaml = string(binary) + request.Wrapper.ExtensionName = extensionName + + requestBytes, _ := proto.Marshal(request) + cmd := exec.Command(extensionHandlers.Name) + cmd.Stdin = bytes.NewReader(requestBytes) + output, err := cmd.Output() + + if err != nil { + fmt.Printf("Error: %+v\n", err) + return nil, err + } + response := &ext_plugin.ExtensionHandlerResponse{} + err = proto.Unmarshal(output, response) + if err != nil { + fmt.Printf("Error: %+v\n", err) + fmt.Printf("%s\n", string(output)) + return nil, err + } + if !response.Handled { + return nil, nil + } + if len(response.Error) != 0 { + message := fmt.Sprintf("Errors when parsing: %+v for field %s by vendor extension handler %s. Details %+v", in, extensionName, extensionHandlers.Name, strings.Join(response.Error, ",")) + return nil, errors.New(message) + } + return response.Value, nil + } + return nil, nil +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/helpers.go b/vendor/github.com/googleapis/gnostic/compiler/helpers.go new file mode 100644 index 000000000..76df635ff --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/helpers.go @@ -0,0 +1,197 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +import ( + "fmt" + "gopkg.in/yaml.v2" + "regexp" + "sort" + "strconv" +) + +// compiler helper functions, usually called from generated code + +// UnpackMap gets a yaml.MapSlice if possible. +func UnpackMap(in interface{}) (yaml.MapSlice, bool) { + m, ok := in.(yaml.MapSlice) + if ok { + return m, true + } + // do we have an empty array? + a, ok := in.([]interface{}) + if ok && len(a) == 0 { + // if so, return an empty map + return yaml.MapSlice{}, true + } + return nil, false +} + +// SortedKeysForMap returns the sorted keys of a yaml.MapSlice. +func SortedKeysForMap(m yaml.MapSlice) []string { + keys := make([]string, 0) + for _, item := range m { + keys = append(keys, item.Key.(string)) + } + sort.Strings(keys) + return keys +} + +// MapHasKey returns true if a yaml.MapSlice contains a specified key. +func MapHasKey(m yaml.MapSlice, key string) bool { + for _, item := range m { + itemKey, ok := item.Key.(string) + if ok && key == itemKey { + return true + } + } + return false +} + +// MapValueForKey gets the value of a map value for a specified key. +func MapValueForKey(m yaml.MapSlice, key string) interface{} { + for _, item := range m { + itemKey, ok := item.Key.(string) + if ok && key == itemKey { + return item.Value + } + } + return nil +} + +// ConvertInterfaceArrayToStringArray converts an array of interfaces to an array of strings, if possible. +func ConvertInterfaceArrayToStringArray(interfaceArray []interface{}) []string { + stringArray := make([]string, 0) + for _, item := range interfaceArray { + v, ok := item.(string) + if ok { + stringArray = append(stringArray, v) + } + } + return stringArray +} + +// MissingKeysInMap identifies which keys from a list of required keys are not in a map. +func MissingKeysInMap(m yaml.MapSlice, requiredKeys []string) []string { + missingKeys := make([]string, 0) + for _, k := range requiredKeys { + if !MapHasKey(m, k) { + missingKeys = append(missingKeys, k) + } + } + return missingKeys +} + +// InvalidKeysInMap returns keys in a map that don't match a list of allowed keys and patterns. +func InvalidKeysInMap(m yaml.MapSlice, allowedKeys []string, allowedPatterns []*regexp.Regexp) []string { + invalidKeys := make([]string, 0) + for _, item := range m { + itemKey, ok := item.Key.(string) + if ok { + key := itemKey + found := false + // does the key match an allowed key? + for _, allowedKey := range allowedKeys { + if key == allowedKey { + found = true + break + } + } + if !found { + // does the key match an allowed pattern? + for _, allowedPattern := range allowedPatterns { + if allowedPattern.MatchString(key) { + found = true + break + } + } + if !found { + invalidKeys = append(invalidKeys, key) + } + } + } + } + return invalidKeys +} + +// DescribeMap describes a map (for debugging purposes). +func DescribeMap(in interface{}, indent string) string { + description := "" + m, ok := in.(map[string]interface{}) + if ok { + keys := make([]string, 0) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v := m[k] + description += fmt.Sprintf("%s%s:\n", indent, k) + description += DescribeMap(v, indent+" ") + } + return description + } + a, ok := in.([]interface{}) + if ok { + for i, v := range a { + description += fmt.Sprintf("%s%d:\n", indent, i) + description += DescribeMap(v, indent+" ") + } + return description + } + description += fmt.Sprintf("%s%+v\n", indent, in) + return description +} + +// PluralProperties returns the string "properties" pluralized. +func PluralProperties(count int) string { + if count == 1 { + return "property" + } + return "properties" +} + +// StringArrayContainsValue returns true if a string array contains a specified value. +func StringArrayContainsValue(array []string, value string) bool { + for _, item := range array { + if item == value { + return true + } + } + return false +} + +// StringArrayContainsValues returns true if a string array contains all of a list of specified values. +func StringArrayContainsValues(array []string, values []string) bool { + for _, value := range values { + if !StringArrayContainsValue(array, value) { + return false + } + } + return true +} + +// StringValue returns the string value of an item. +func StringValue(item interface{}) (value string, ok bool) { + value, ok = item.(string) + if ok { + return value, ok + } + intValue, ok := item.(int) + if ok { + return strconv.Itoa(intValue), true + } + return "", false +} diff --git a/vendor/github.com/googleapis/gnostic/compiler/main.go b/vendor/github.com/googleapis/gnostic/compiler/main.go new file mode 100644 index 000000000..9713a21cc --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/main.go @@ -0,0 +1,16 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package compiler provides support functions to generated compiler code. +package compiler diff --git a/vendor/github.com/googleapis/gnostic/compiler/reader.go b/vendor/github.com/googleapis/gnostic/compiler/reader.go new file mode 100644 index 000000000..604a46a6a --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/reader.go @@ -0,0 +1,167 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compiler + +import ( + "fmt" + "gopkg.in/yaml.v2" + "io/ioutil" + "log" + "net/http" + "net/url" + "path/filepath" + "strings" +) + +var fileCache map[string][]byte +var infoCache map[string]interface{} +var count int64 + +var verboseReader = false + +func initializeFileCache() { + if fileCache == nil { + fileCache = make(map[string][]byte, 0) + } +} + +func initializeInfoCache() { + if infoCache == nil { + infoCache = make(map[string]interface{}, 0) + } +} + +// FetchFile gets a specified file from the local filesystem or a remote location. +func FetchFile(fileurl string) ([]byte, error) { + initializeFileCache() + bytes, ok := fileCache[fileurl] + if ok { + if verboseReader { + log.Printf("Cache hit %s", fileurl) + } + return bytes, nil + } + log.Printf("Fetching %s", fileurl) + response, err := http.Get(fileurl) + if err != nil { + return nil, err + } + defer response.Body.Close() + bytes, err = ioutil.ReadAll(response.Body) + if err == nil { + fileCache[fileurl] = bytes + } + return bytes, err +} + +// ReadBytesForFile reads the bytes of a file. +func ReadBytesForFile(filename string) ([]byte, error) { + // is the filename a url? + fileurl, _ := url.Parse(filename) + if fileurl.Scheme != "" { + // yes, fetch it + bytes, err := FetchFile(filename) + if err != nil { + return nil, err + } + return bytes, nil + } + // no, it's a local filename + bytes, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + return bytes, nil +} + +// ReadInfoFromBytes unmarshals a file as a yaml.MapSlice. +func ReadInfoFromBytes(filename string, bytes []byte) (interface{}, error) { + initializeInfoCache() + cachedInfo, ok := infoCache[filename] + if ok { + if verboseReader { + log.Printf("Cache hit info for file %s", filename) + } + return cachedInfo, nil + } + if verboseReader { + log.Printf("Reading info for file %s", filename) + } + var info yaml.MapSlice + err := yaml.Unmarshal(bytes, &info) + if err != nil { + return nil, err + } + infoCache[filename] = info + return info, nil +} + +// ReadInfoForRef reads a file and return the fragment needed to resolve a $ref. +func ReadInfoForRef(basefile string, ref string) (interface{}, error) { + initializeInfoCache() + { + info, ok := infoCache[ref] + if ok { + if verboseReader { + log.Printf("Cache hit for ref %s#%s", basefile, ref) + } + return info, nil + } + } + if verboseReader { + log.Printf("Reading info for ref %s#%s", basefile, ref) + } + count = count + 1 + basedir, _ := filepath.Split(basefile) + parts := strings.Split(ref, "#") + var filename string + if parts[0] != "" { + filename = basedir + parts[0] + } else { + filename = basefile + } + bytes, err := ReadBytesForFile(filename) + if err != nil { + return nil, err + } + info, err := ReadInfoFromBytes(filename, bytes) + if err != nil { + log.Printf("File error: %v\n", err) + } else { + if len(parts) > 1 { + path := strings.Split(parts[1], "/") + for i, key := range path { + if i > 0 { + m, ok := info.(yaml.MapSlice) + if ok { + found := false + for _, section := range m { + if section.Key == key { + info = section.Value + found = true + } + } + if !found { + infoCache[ref] = nil + return nil, NewError(nil, fmt.Sprintf("could not resolve %s", ref)) + } + } + } + } + } + } + infoCache[ref] = info + return info, nil +} diff --git a/vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh b/vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh new file mode 100755 index 000000000..68d02a02a --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh @@ -0,0 +1,5 @@ +go get github.com/golang/protobuf/protoc-gen-go + +protoc \ +--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. *.proto + diff --git a/vendor/github.com/googleapis/gnostic/extensions/README.md b/vendor/github.com/googleapis/gnostic/extensions/README.md new file mode 100644 index 000000000..ff1c2eb1e --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/README.md @@ -0,0 +1,5 @@ +# Extensions + +This directory contains support code for building Gnostic extensions and associated examples. + +Extensions are used to compile vendor or specification extensions into protocol buffer structures. diff --git a/vendor/github.com/googleapis/gnostic/extensions/extension.pb.go b/vendor/github.com/googleapis/gnostic/extensions/extension.pb.go new file mode 100644 index 000000000..b14f1f945 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/extension.pb.go @@ -0,0 +1,219 @@ +// Code generated by protoc-gen-go. +// source: extension.proto +// DO NOT EDIT! + +/* +Package openapiextension_v1 is a generated protocol buffer package. + +It is generated from these files: + extension.proto + +It has these top-level messages: + Version + ExtensionHandlerRequest + ExtensionHandlerResponse + Wrapper +*/ +package openapiextension_v1 + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import google_protobuf "github.com/golang/protobuf/ptypes/any" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// The version number of OpenAPI compiler. +type Version struct { + Major int32 `protobuf:"varint,1,opt,name=major" json:"major,omitempty"` + Minor int32 `protobuf:"varint,2,opt,name=minor" json:"minor,omitempty"` + Patch int32 `protobuf:"varint,3,opt,name=patch" json:"patch,omitempty"` + // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should + // be empty for mainline stable releases. + Suffix string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"` +} + +func (m *Version) Reset() { *m = Version{} } +func (m *Version) String() string { return proto.CompactTextString(m) } +func (*Version) ProtoMessage() {} +func (*Version) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *Version) GetMajor() int32 { + if m != nil { + return m.Major + } + return 0 +} + +func (m *Version) GetMinor() int32 { + if m != nil { + return m.Minor + } + return 0 +} + +func (m *Version) GetPatch() int32 { + if m != nil { + return m.Patch + } + return 0 +} + +func (m *Version) GetSuffix() string { + if m != nil { + return m.Suffix + } + return "" +} + +// An encoded Request is written to the ExtensionHandler's stdin. +type ExtensionHandlerRequest struct { + // The OpenAPI descriptions that were explicitly listed on the command line. + // The specifications will appear in the order they are specified to openapic. + Wrapper *Wrapper `protobuf:"bytes,1,opt,name=wrapper" json:"wrapper,omitempty"` + // The version number of openapi compiler. + CompilerVersion *Version `protobuf:"bytes,3,opt,name=compiler_version,json=compilerVersion" json:"compiler_version,omitempty"` +} + +func (m *ExtensionHandlerRequest) Reset() { *m = ExtensionHandlerRequest{} } +func (m *ExtensionHandlerRequest) String() string { return proto.CompactTextString(m) } +func (*ExtensionHandlerRequest) ProtoMessage() {} +func (*ExtensionHandlerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *ExtensionHandlerRequest) GetWrapper() *Wrapper { + if m != nil { + return m.Wrapper + } + return nil +} + +func (m *ExtensionHandlerRequest) GetCompilerVersion() *Version { + if m != nil { + return m.CompilerVersion + } + return nil +} + +// The extensions writes an encoded ExtensionHandlerResponse to stdout. +type ExtensionHandlerResponse struct { + // true if the extension is handled by the extension handler; false otherwise + Handled bool `protobuf:"varint,1,opt,name=handled" json:"handled,omitempty"` + // Error message. If non-empty, the extension handling failed. + // The extension handler process should exit with status code zero + // even if it reports an error in this way. + // + // This should be used to indicate errors which prevent the extension from + // operating as intended. Errors which indicate a problem in gnostic + // itself -- such as the input Document being unparseable -- should be + // reported by writing a message to stderr and exiting with a non-zero + // status code. + Error []string `protobuf:"bytes,2,rep,name=error" json:"error,omitempty"` + // text output + Value *google_protobuf.Any `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"` +} + +func (m *ExtensionHandlerResponse) Reset() { *m = ExtensionHandlerResponse{} } +func (m *ExtensionHandlerResponse) String() string { return proto.CompactTextString(m) } +func (*ExtensionHandlerResponse) ProtoMessage() {} +func (*ExtensionHandlerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *ExtensionHandlerResponse) GetHandled() bool { + if m != nil { + return m.Handled + } + return false +} + +func (m *ExtensionHandlerResponse) GetError() []string { + if m != nil { + return m.Error + } + return nil +} + +func (m *ExtensionHandlerResponse) GetValue() *google_protobuf.Any { + if m != nil { + return m.Value + } + return nil +} + +type Wrapper struct { + // version of the OpenAPI specification in which this extension was written. + Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` + // Name of the extension + ExtensionName string `protobuf:"bytes,2,opt,name=extension_name,json=extensionName" json:"extension_name,omitempty"` + // Must be a valid yaml for the proto + Yaml string `protobuf:"bytes,3,opt,name=yaml" json:"yaml,omitempty"` +} + +func (m *Wrapper) Reset() { *m = Wrapper{} } +func (m *Wrapper) String() string { return proto.CompactTextString(m) } +func (*Wrapper) ProtoMessage() {} +func (*Wrapper) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *Wrapper) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *Wrapper) GetExtensionName() string { + if m != nil { + return m.ExtensionName + } + return "" +} + +func (m *Wrapper) GetYaml() string { + if m != nil { + return m.Yaml + } + return "" +} + +func init() { + proto.RegisterType((*Version)(nil), "openapiextension.v1.Version") + proto.RegisterType((*ExtensionHandlerRequest)(nil), "openapiextension.v1.ExtensionHandlerRequest") + proto.RegisterType((*ExtensionHandlerResponse)(nil), "openapiextension.v1.ExtensionHandlerResponse") + proto.RegisterType((*Wrapper)(nil), "openapiextension.v1.Wrapper") +} + +func init() { proto.RegisterFile("extension.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 355 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x91, 0x4d, 0x4b, 0xf3, 0x40, + 0x1c, 0xc4, 0x49, 0xdf, 0xf2, 0x64, 0x1f, 0xb4, 0xb2, 0x16, 0x8d, 0xe2, 0xa1, 0x04, 0x84, 0x22, + 0xb8, 0xa5, 0x0a, 0xde, 0x5b, 0x28, 0xea, 0xc5, 0x96, 0x3d, 0xd4, 0x9b, 0x65, 0x9b, 0xfe, 0xdb, + 0x46, 0x92, 0xdd, 0x75, 0xf3, 0x62, 0xfb, 0x55, 0x3c, 0xfa, 0x49, 0x25, 0xbb, 0xd9, 0x7a, 0x50, + 0x6f, 0x99, 0x1f, 0x93, 0xfc, 0x67, 0x26, 0xa8, 0x0d, 0xdb, 0x0c, 0x78, 0x1a, 0x09, 0x4e, 0xa4, + 0x12, 0x99, 0xc0, 0xc7, 0x42, 0x02, 0x67, 0x32, 0xfa, 0xe6, 0xc5, 0xe0, 0xfc, 0x6c, 0x2d, 0xc4, + 0x3a, 0x86, 0xbe, 0xb6, 0x2c, 0xf2, 0x55, 0x9f, 0xf1, 0x9d, 0xf1, 0x07, 0x21, 0x72, 0x67, 0xa0, + 0x4a, 0x23, 0xee, 0xa0, 0x66, 0xc2, 0x5e, 0x85, 0xf2, 0x9d, 0xae, 0xd3, 0x6b, 0x52, 0x23, 0x34, + 0x8d, 0xb8, 0x50, 0x7e, 0xad, 0xa2, 0xa5, 0x28, 0xa9, 0x64, 0x59, 0xb8, 0xf1, 0xeb, 0x86, 0x6a, + 0x81, 0x4f, 0x50, 0x2b, 0xcd, 0x57, 0xab, 0x68, 0xeb, 0x37, 0xba, 0x4e, 0xcf, 0xa3, 0x95, 0x0a, + 0x3e, 0x1c, 0x74, 0x3a, 0xb6, 0x81, 0x1e, 0x18, 0x5f, 0xc6, 0xa0, 0x28, 0xbc, 0xe5, 0x90, 0x66, + 0xf8, 0x0e, 0xb9, 0xef, 0x8a, 0x49, 0x09, 0xe6, 0xee, 0xff, 0x9b, 0x0b, 0xf2, 0x4b, 0x05, 0xf2, + 0x6c, 0x3c, 0xd4, 0x9a, 0xf1, 0x3d, 0x3a, 0x0a, 0x45, 0x22, 0xa3, 0x18, 0xd4, 0xbc, 0x30, 0x0d, + 0x74, 0x98, 0xbf, 0x3e, 0x50, 0xb5, 0xa4, 0x6d, 0xfb, 0x56, 0x05, 0x82, 0x02, 0xf9, 0x3f, 0xb3, + 0xa5, 0x52, 0xf0, 0x14, 0xb0, 0x8f, 0xdc, 0x8d, 0x46, 0x4b, 0x1d, 0xee, 0x1f, 0xb5, 0xb2, 0x1c, + 0x00, 0x94, 0xd2, 0xb3, 0xd4, 0x7b, 0x1e, 0x35, 0x02, 0x5f, 0xa1, 0x66, 0xc1, 0xe2, 0x1c, 0xaa, + 0x24, 0x1d, 0x62, 0x86, 0x27, 0x76, 0x78, 0x32, 0xe4, 0x3b, 0x6a, 0x2c, 0xc1, 0x0b, 0x72, 0xab, + 0x52, 0xe5, 0x19, 0x5b, 0xc1, 0xd1, 0xc3, 0x59, 0x89, 0x2f, 0xd1, 0xe1, 0xbe, 0xc5, 0x9c, 0xb3, + 0x04, 0xf4, 0x6f, 0xf0, 0xe8, 0xc1, 0x9e, 0x3e, 0xb1, 0x04, 0x30, 0x46, 0x8d, 0x1d, 0x4b, 0x62, + 0x7d, 0xd6, 0xa3, 0xfa, 0x79, 0x74, 0x8d, 0xda, 0x42, 0xad, 0xed, 0x16, 0x21, 0x29, 0x06, 0x23, + 0x3c, 0x91, 0xc0, 0x87, 0xd3, 0xc7, 0x7d, 0xdf, 0xd9, 0x60, 0xea, 0x7c, 0xd6, 0xea, 0x93, 0xe1, + 0x78, 0xd1, 0xd2, 0x19, 0x6f, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xfc, 0x56, 0x40, 0x4d, 0x52, + 0x02, 0x00, 0x00, +} diff --git a/vendor/github.com/googleapis/gnostic/extensions/extension.proto b/vendor/github.com/googleapis/gnostic/extensions/extension.proto new file mode 100644 index 000000000..806760a13 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/extension.proto @@ -0,0 +1,93 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "google/protobuf/any.proto"; +package openapiextension.v1; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "OpenAPIExtensionV1"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.openapic.v1"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +// +option objc_class_prefix = "OAE"; // "OpenAPI Extension" + +// The version number of OpenAPI compiler. +message Version { + int32 major = 1; + int32 minor = 2; + int32 patch = 3; + // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should + // be empty for mainline stable releases. + string suffix = 4; +} + +// An encoded Request is written to the ExtensionHandler's stdin. +message ExtensionHandlerRequest { + + // The OpenAPI descriptions that were explicitly listed on the command line. + // The specifications will appear in the order they are specified to openapic. + Wrapper wrapper = 1; + + // The version number of openapi compiler. + Version compiler_version = 3; +} + +// The extensions writes an encoded ExtensionHandlerResponse to stdout. +message ExtensionHandlerResponse { + + // true if the extension is handled by the extension handler; false otherwise + bool handled = 1; + + // Error message. If non-empty, the extension handling failed. + // The extension handler process should exit with status code zero + // even if it reports an error in this way. + // + // This should be used to indicate errors which prevent the extension from + // operating as intended. Errors which indicate a problem in gnostic + // itself -- such as the input Document being unparseable -- should be + // reported by writing a message to stderr and exiting with a non-zero + // status code. + repeated string error = 2; + + // text output + google.protobuf.Any value = 3; +} + +message Wrapper { + // version of the OpenAPI specification in which this extension was written. + string version = 1; + + // Name of the extension + string extension_name = 2; + + // Must be a valid yaml for the proto + string yaml = 3; +} diff --git a/vendor/github.com/googleapis/gnostic/extensions/extensions.go b/vendor/github.com/googleapis/gnostic/extensions/extensions.go new file mode 100644 index 000000000..94a8e62a7 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/extensions.go @@ -0,0 +1,82 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openapiextension_v1 + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" +) + +type documentHandler func(version string, extensionName string, document string) +type extensionHandler func(name string, yamlInput string) (bool, proto.Message, error) + +func forInputYamlFromOpenapic(handler documentHandler) { + data, err := ioutil.ReadAll(os.Stdin) + if err != nil { + fmt.Println("File error:", err.Error()) + os.Exit(1) + } + if len(data) == 0 { + fmt.Println("No input data.") + os.Exit(1) + } + request := &ExtensionHandlerRequest{} + err = proto.Unmarshal(data, request) + if err != nil { + fmt.Println("Input error:", err.Error()) + os.Exit(1) + } + handler(request.Wrapper.Version, request.Wrapper.ExtensionName, request.Wrapper.Yaml) +} + +// ProcessExtension calles the handler for a specified extension. +func ProcessExtension(handleExtension extensionHandler) { + response := &ExtensionHandlerResponse{} + forInputYamlFromOpenapic( + func(version string, extensionName string, yamlInput string) { + var newObject proto.Message + var err error + + handled, newObject, err := handleExtension(extensionName, yamlInput) + if !handled { + responseBytes, _ := proto.Marshal(response) + os.Stdout.Write(responseBytes) + os.Exit(0) + } + + // If we reach here, then the extension is handled + response.Handled = true + if err != nil { + response.Error = append(response.Error, err.Error()) + responseBytes, _ := proto.Marshal(response) + os.Stdout.Write(responseBytes) + os.Exit(0) + } + response.Value, err = ptypes.MarshalAny(newObject) + if err != nil { + response.Error = append(response.Error, err.Error()) + responseBytes, _ := proto.Marshal(response) + os.Stdout.Write(responseBytes) + os.Exit(0) + } + }) + + responseBytes, _ := proto.Marshal(response) + os.Stdout.Write(responseBytes) +} diff --git a/vendor/github.com/gorilla/context/.travis.yml b/vendor/github.com/gorilla/context/.travis.yml new file mode 100644 index 000000000..6f440f1e4 --- /dev/null +++ b/vendor/github.com/gorilla/context/.travis.yml @@ -0,0 +1,19 @@ +language: go +sudo: false + +matrix: + include: + - go: 1.3 + - go: 1.4 + - go: 1.5 + - go: 1.6 + - go: 1.7 + - go: tip + allow_failures: + - go: tip + +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - go vet $(go list ./... | grep -v /vendor/) + - go test -v -race ./... diff --git a/vendor/github.com/gorilla/context/LICENSE b/vendor/github.com/gorilla/context/LICENSE new file mode 100644 index 000000000..0e5fb8728 --- /dev/null +++ b/vendor/github.com/gorilla/context/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/context/README.md b/vendor/github.com/gorilla/context/README.md new file mode 100644 index 000000000..08f86693b --- /dev/null +++ b/vendor/github.com/gorilla/context/README.md @@ -0,0 +1,10 @@ +context +======= +[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) + +gorilla/context is a general purpose registry for global request variables. + +> Note: gorilla/context, having been born well before `context.Context` existed, does not play well +> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. You should either use *just* gorilla/context, or moving forward, the new `http.Request.Context()`. + +Read the full documentation here: http://www.gorillatoolkit.org/pkg/context diff --git a/vendor/github.com/gorilla/context/context.go b/vendor/github.com/gorilla/context/context.go new file mode 100644 index 000000000..81cb128b1 --- /dev/null +++ b/vendor/github.com/gorilla/context/context.go @@ -0,0 +1,143 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package context + +import ( + "net/http" + "sync" + "time" +) + +var ( + mutex sync.RWMutex + data = make(map[*http.Request]map[interface{}]interface{}) + datat = make(map[*http.Request]int64) +) + +// Set stores a value for a given key in a given request. +func Set(r *http.Request, key, val interface{}) { + mutex.Lock() + if data[r] == nil { + data[r] = make(map[interface{}]interface{}) + datat[r] = time.Now().Unix() + } + data[r][key] = val + mutex.Unlock() +} + +// Get returns a value stored for a given key in a given request. +func Get(r *http.Request, key interface{}) interface{} { + mutex.RLock() + if ctx := data[r]; ctx != nil { + value := ctx[key] + mutex.RUnlock() + return value + } + mutex.RUnlock() + return nil +} + +// GetOk returns stored value and presence state like multi-value return of map access. +func GetOk(r *http.Request, key interface{}) (interface{}, bool) { + mutex.RLock() + if _, ok := data[r]; ok { + value, ok := data[r][key] + mutex.RUnlock() + return value, ok + } + mutex.RUnlock() + return nil, false +} + +// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. +func GetAll(r *http.Request) map[interface{}]interface{} { + mutex.RLock() + if context, ok := data[r]; ok { + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } + mutex.RUnlock() + return result + } + mutex.RUnlock() + return nil +} + +// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if +// the request was registered. +func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { + mutex.RLock() + context, ok := data[r] + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } + mutex.RUnlock() + return result, ok +} + +// Delete removes a value stored for a given key in a given request. +func Delete(r *http.Request, key interface{}) { + mutex.Lock() + if data[r] != nil { + delete(data[r], key) + } + mutex.Unlock() +} + +// Clear removes all values stored for a given request. +// +// This is usually called by a handler wrapper to clean up request +// variables at the end of a request lifetime. See ClearHandler(). +func Clear(r *http.Request) { + mutex.Lock() + clear(r) + mutex.Unlock() +} + +// clear is Clear without the lock. +func clear(r *http.Request) { + delete(data, r) + delete(datat, r) +} + +// Purge removes request data stored for longer than maxAge, in seconds. +// It returns the amount of requests removed. +// +// If maxAge <= 0, all request data is removed. +// +// This is only used for sanity check: in case context cleaning was not +// properly set some request data can be kept forever, consuming an increasing +// amount of memory. In case this is detected, Purge() must be called +// periodically until the problem is fixed. +func Purge(maxAge int) int { + mutex.Lock() + count := 0 + if maxAge <= 0 { + count = len(data) + data = make(map[*http.Request]map[interface{}]interface{}) + datat = make(map[*http.Request]int64) + } else { + min := time.Now().Unix() - int64(maxAge) + for r := range data { + if datat[r] < min { + clear(r) + count++ + } + } + } + mutex.Unlock() + return count +} + +// ClearHandler wraps an http.Handler and clears request values at the end +// of a request lifetime. +func ClearHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer Clear(r) + h.ServeHTTP(w, r) + }) +} diff --git a/vendor/github.com/gorilla/context/doc.go b/vendor/github.com/gorilla/context/doc.go new file mode 100644 index 000000000..448d1bfca --- /dev/null +++ b/vendor/github.com/gorilla/context/doc.go @@ -0,0 +1,88 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package context stores values shared during a request lifetime. + +Note: gorilla/context, having been born well before `context.Context` existed, +does not play well > with the shallow copying of the request that +[`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) +(added to net/http Go 1.7 onwards) performs. You should either use *just* +gorilla/context, or moving forward, the new `http.Request.Context()`. + +For example, a router can set variables extracted from the URL and later +application handlers can access those values, or it can be used to store +sessions values to be saved at the end of a request. There are several +others common uses. + +The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: + + http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 + +Here's the basic usage: first define the keys that you will need. The key +type is interface{} so a key can be of any type that supports equality. +Here we define a key using a custom int type to avoid name collisions: + + package foo + + import ( + "github.com/gorilla/context" + ) + + type key int + + const MyKey key = 0 + +Then set a variable. Variables are bound to an http.Request object, so you +need a request instance to set a value: + + context.Set(r, MyKey, "bar") + +The application can later access the variable using the same key you provided: + + func MyHandler(w http.ResponseWriter, r *http.Request) { + // val is "bar". + val := context.Get(r, foo.MyKey) + + // returns ("bar", true) + val, ok := context.GetOk(r, foo.MyKey) + // ... + } + +And that's all about the basic usage. We discuss some other ideas below. + +Any type can be stored in the context. To enforce a given type, make the key +private and wrap Get() and Set() to accept and return values of a specific +type: + + type key int + + const mykey key = 0 + + // GetMyKey returns a value for this package from the request values. + func GetMyKey(r *http.Request) SomeType { + if rv := context.Get(r, mykey); rv != nil { + return rv.(SomeType) + } + return nil + } + + // SetMyKey sets a value for this package in the request values. + func SetMyKey(r *http.Request, val SomeType) { + context.Set(r, mykey, val) + } + +Variables must be cleared at the end of a request, to remove all values +that were stored. This can be done in an http.Handler, after a request was +served. Just call Clear() passing the request: + + context.Clear(r) + +...or use ClearHandler(), which conveniently wraps an http.Handler to clear +variables at the end of a request lifetime. + +The Routers from the packages gorilla/mux and gorilla/pat call Clear() +so if you are using either of them you don't need to clear the context manually. +*/ +package context diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml new file mode 100644 index 000000000..3302233f3 --- /dev/null +++ b/vendor/github.com/gorilla/mux/.travis.yml @@ -0,0 +1,22 @@ +language: go +sudo: false + +matrix: + include: + - go: 1.5 + - go: 1.6 + - go: 1.7 + - go: 1.8 + - go: 1.9 + - go: tip + allow_failures: + - go: tip + +install: + - # Skip + +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - go tool vet . + - go test -v -race ./... diff --git a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..232be82e4 --- /dev/null +++ b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md @@ -0,0 +1,11 @@ +**What version of Go are you running?** (Paste the output of `go version`) + + +**What version of gorilla/mux are you at?** (Paste the output of `git rev-parse HEAD` inside `$GOPATH/src/github.com/gorilla/mux`) + + +**Describe your problem** (and what you have tried so far) + + +**Paste a minimal, runnable, reproduction of your issue below** (use backticks to format it) + diff --git a/vendor/github.com/gorilla/mux/LICENSE b/vendor/github.com/gorilla/mux/LICENSE new file mode 100644 index 000000000..0e5fb8728 --- /dev/null +++ b/vendor/github.com/gorilla/mux/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md new file mode 100644 index 000000000..f9b3103f0 --- /dev/null +++ b/vendor/github.com/gorilla/mux/README.md @@ -0,0 +1,560 @@ +gorilla/mux +=== +[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux) +[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux) +[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge) + +![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png) + +http://www.gorillatoolkit.org/pkg/mux + +Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to +their respective handler. + +The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are: + +* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`. +* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers. +* URL hosts, paths and query values can have variables with an optional regular expression. +* Registered URLs can be built, or "reversed", which helps maintaining references to resources. +* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching. + +--- + +* [Install](#install) +* [Examples](#examples) +* [Matching Routes](#matching-routes) +* [Static Files](#static-files) +* [Registered URLs](#registered-urls) +* [Walking Routes](#walking-routes) +* [Graceful Shutdown](#graceful-shutdown) +* [Middleware](#middleware) +* [Full Example](#full-example) + +--- + +## Install + +With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain: + +```sh +go get -u github.com/gorilla/mux +``` + +## Examples + +Let's start registering a couple of URL paths and handlers: + +```go +func main() { + r := mux.NewRouter() + r.HandleFunc("/", HomeHandler) + r.HandleFunc("/products", ProductsHandler) + r.HandleFunc("/articles", ArticlesHandler) + http.Handle("/", r) +} +``` + +Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters. + +Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example: + +```go +r := mux.NewRouter() +r.HandleFunc("/products/{key}", ProductHandler) +r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) +r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) +``` + +The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`: + +```go +func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, "Category: %v\n", vars["category"]) +} +``` + +And this is all you need to know about the basic usage. More advanced options are explained below. + +### Matching Routes + +Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables: + +```go +r := mux.NewRouter() +// Only matches if domain is "www.example.com". +r.Host("www.example.com") +// Matches a dynamic subdomain. +r.Host("{subdomain:[a-z]+}.domain.com") +``` + +There are several other matchers that can be added. To match path prefixes: + +```go +r.PathPrefix("/products/") +``` + +...or HTTP methods: + +```go +r.Methods("GET", "POST") +``` + +...or URL schemes: + +```go +r.Schemes("https") +``` + +...or header values: + +```go +r.Headers("X-Requested-With", "XMLHttpRequest") +``` + +...or query values: + +```go +r.Queries("key", "value") +``` + +...or to use a custom matcher function: + +```go +r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { + return r.ProtoMajor == 0 +}) +``` + +...and finally, it is possible to combine several matchers in a single route: + +```go +r.HandleFunc("/products", ProductsHandler). + Host("www.example.com"). + Methods("GET"). + Schemes("http") +``` + +Routes are tested in the order they were added to the router. If two routes match, the first one wins: + +```go +r := mux.NewRouter() +r.HandleFunc("/specific", specificHandler) +r.PathPrefix("/").Handler(catchAllHandler) +``` + +Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting". + +For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it: + +```go +r := mux.NewRouter() +s := r.Host("www.example.com").Subrouter() +``` + +Then register routes in the subrouter: + +```go +s.HandleFunc("/products/", ProductsHandler) +s.HandleFunc("/products/{key}", ProductHandler) +s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) +``` + +The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route. + +Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter. + +There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths: + +```go +r := mux.NewRouter() +s := r.PathPrefix("/products").Subrouter() +// "/products/" +s.HandleFunc("/", ProductsHandler) +// "/products/{key}/" +s.HandleFunc("/{key}/", ProductHandler) +// "/products/{key}/details" +s.HandleFunc("/{key}/details", ProductDetailsHandler) +``` +### Listing Routes + +Routes on a mux can be listed using the Router.Walk method—useful for generating documentation: + +```go +package main + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +func handler(w http.ResponseWriter, r *http.Request) { + return +} + +func main() { + r := mux.NewRouter() + r.HandleFunc("/", handler) + r.HandleFunc("/products", handler).Methods("POST") + r.HandleFunc("/articles", handler).Methods("GET") + r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT") + r.HandleFunc("/authors", handler).Queries("surname", "{surname}") + r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { + t, err := route.GetPathTemplate() + if err != nil { + return err + } + qt, err := route.GetQueriesTemplates() + if err != nil { + return err + } + // p will contain regular expression is compatible with regular expression in Perl, Python, and other languages. + // for instance the regular expression for path '/articles/{id}' will be '^/articles/(?P[^/]+)$' + p, err := route.GetPathRegexp() + if err != nil { + return err + } + // qr will contain a list of regular expressions with the same semantics as GetPathRegexp, + // just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return + // {"^surname=(?P.*)$}. Where each combined query pair will have an entry in the list. + qr, err := route.GetQueriesRegexp() + if err != nil { + return err + } + m, err := route.GetMethods() + if err != nil { + return err + } + fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p) + return nil + }) + http.Handle("/", r) +} +``` + +### Static Files + +Note that the path provided to `PathPrefix()` represents a "wildcard": calling +`PathPrefix("/static/").Handler(...)` means that the handler will be passed any +request that matches "/static/*". This makes it easy to serve static files with mux: + +```go +func main() { + var dir string + + flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") + flag.Parse() + r := mux.NewRouter() + + // This will serve files under http://localhost:8000/static/ + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) + + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8000", + // Good practice: enforce timeouts for servers you create! + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Fatal(srv.ListenAndServe()) +} +``` + +### Registered URLs + +Now let's see how to build registered URLs. + +Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example: + +```go +r := mux.NewRouter() +r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). + Name("article") +``` + +To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do: + +```go +url, err := r.Get("article").URL("category", "technology", "id", "42") +``` + +...and the result will be a `url.URL` with the following path: + +``` +"/articles/technology/42" +``` + +This also works for host and query value variables: + +```go +r := mux.NewRouter() +r.Host("{subdomain}.domain.com"). + Path("/articles/{category}/{id:[0-9]+}"). + Queries("filter", "{filter}"). + HandlerFunc(ArticleHandler). + Name("article") + +// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla" +url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42", + "filter", "gorilla") +``` + +All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match. + +Regex support also exists for matching Headers within a route. For example, we could do: + +```go +r.HeadersRegexp("Content-Type", "application/(text|json)") +``` + +...and the route will match both requests with a Content-Type of `application/json` as well as `application/text` + +There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do: + +```go +// "http://news.domain.com/" +host, err := r.Get("article").URLHost("subdomain", "news") + +// "/articles/technology/42" +path, err := r.Get("article").URLPath("category", "technology", "id", "42") +``` + +And if you use subrouters, host and path defined separately can be built as well: + +```go +r := mux.NewRouter() +s := r.Host("{subdomain}.domain.com").Subrouter() +s.Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + +// "http://news.domain.com/articles/technology/42" +url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") +``` + +### Walking Routes + +The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example, +the following prints all of the registered routes: + +```go +r := mux.NewRouter() +r.HandleFunc("/", handler) +r.HandleFunc("/products", handler).Methods("POST") +r.HandleFunc("/articles", handler).Methods("GET") +r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT") +r.HandleFunc("/authors", handler).Queries("surname", "{surname}") +r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { + t, err := route.GetPathTemplate() + if err != nil { + return err + } + qt, err := route.GetQueriesTemplates() + if err != nil { + return err + } + // p will contain a regular expression that is compatible with regular expressions in Perl, Python, and other languages. + // For example, the regular expression for path '/articles/{id}' will be '^/articles/(?P[^/]+)$'. + p, err := route.GetPathRegexp() + if err != nil { + return err + } + // qr will contain a list of regular expressions with the same semantics as GetPathRegexp, + // just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return + // {"^surname=(?P.*)$}. Where each combined query pair will have an entry in the list. + qr, err := route.GetQueriesRegexp() + if err != nil { + return err + } + m, err := route.GetMethods() + if err != nil { + return err + } + fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p) + return nil +}) +``` + +### Graceful Shutdown + +Go 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`: + +```go +package main + +import ( + "context" + "flag" + "log" + "net/http" + "os" + "os/signal" + + "github.com/gorilla/mux" +) + +func main() { + var wait time.Duration + flag.DurationVar(&wait, "graceful-timeout", time.Second * 15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m") + flag.Parse() + + r := mux.NewRouter() + // Add your routes as needed + + srv := &http.Server{ + Addr: "0.0.0.0:8080", + // Good practice to set timeouts to avoid Slowloris attacks. + WriteTimeout: time.Second * 15, + ReadTimeout: time.Second * 15, + IdleTimeout: time.Second * 60, + Handler: r, // Pass our instance of gorilla/mux in. + } + + // Run our server in a goroutine so that it doesn't block. + go func() { + if err := srv.ListenAndServe(); err != nil { + log.Println(err) + } + }() + + c := make(chan os.Signal, 1) + // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) + // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught. + signal.Notify(c, os.Interrupt) + + // Block until we receive our signal. + <-c + + // Create a deadline to wait for. + ctx, cancel := context.WithTimeout(ctx, wait) + // Doesn't block if no connections, but will otherwise wait + // until the timeout deadline. + srv.Shutdown(ctx) + // Optionally, you could run srv.Shutdown in a goroutine and block on + // <-ctx.Done() if your application should wait for other services + // to finalize based on context cancellation. + log.Println("shutting down") + os.Exit(0) +} +``` + +### Middleware + +Mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed in the order they are added if a match is found, including its subrouters. +Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or `ResponseWriter` hijacking. + +Mux middlewares are defined using the de facto standard type: + +```go +type MiddlewareFunc func(http.Handler) http.Handler +``` + +Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers. + +A very basic middleware which logs the URI of the request being handled could be written as: + +```go +func simpleMw(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Do stuff here + log.Println(r.RequestURI) + // Call the next handler, which can be another middleware in the chain, or the final handler. + next.ServeHTTP(w, r) + }) +} +``` + +Middlewares can be added to a router using `Router.AddMiddlewareFunc()`: + +```go +r := mux.NewRouter() +r.HandleFunc("/", handler) +r.AddMiddleware(simpleMw) +``` + +A more complex authentication middleware, which maps session token to users, could be written as: + +```go +// Define our struct +type authenticationMiddleware struct { + tokenUsers map[string]string +} + +// Initialize it somewhere +func (amw *authenticationMiddleware) Populate() { + amw.tokenUsers["00000000"] = "user0" + amw.tokenUsers["aaaaaaaa"] = "userA" + amw.tokenUsers["05f717e5"] = "randomUser" + amw.tokenUsers["deadbeef"] = "user0" +} + +// Middleware function, which will be called for each request +func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("X-Session-Token") + + if user, found := amw.tokenUsers[token]; found { + // We found the token in our map + log.Printf("Authenticated user %s\n", user) + // Pass down the request to the next middleware (or final handler) + next.ServeHTTP(w, r) + } else { + // Write an error and stop the handler chain + http.Error(w, "Forbidden", 403) + } + }) +} +``` + +```go +r := mux.NewRouter() +r.HandleFunc("/", handler) + +amw := authenticationMiddleware{} +amw.Populate() + +r.AddMiddlewareFunc(amw.Middleware) +``` + +Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares *should* write to `ResponseWriter` if they *are* going to terminate the request, and they *should not* write to `ResponseWriter` if they *are not* going to terminate it. + +## Full Example + +Here's a complete, runnable example of a small `mux` based server: + +```go +package main + +import ( + "net/http" + "log" + "github.com/gorilla/mux" +) + +func YourHandler(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("Gorilla!\n")) +} + +func main() { + r := mux.NewRouter() + // Routes consist of a path and a handler function. + r.HandleFunc("/", YourHandler) + + // Bind to a port and pass our router in + log.Fatal(http.ListenAndServe(":8000", r)) +} +``` + +## License + +BSD licensed. See the LICENSE file for details. diff --git a/vendor/github.com/gorilla/mux/context_gorilla.go b/vendor/github.com/gorilla/mux/context_gorilla.go new file mode 100644 index 000000000..d7adaa8fa --- /dev/null +++ b/vendor/github.com/gorilla/mux/context_gorilla.go @@ -0,0 +1,26 @@ +// +build !go1.7 + +package mux + +import ( + "net/http" + + "github.com/gorilla/context" +) + +func contextGet(r *http.Request, key interface{}) interface{} { + return context.Get(r, key) +} + +func contextSet(r *http.Request, key, val interface{}) *http.Request { + if val == nil { + return r + } + + context.Set(r, key, val) + return r +} + +func contextClear(r *http.Request) { + context.Clear(r) +} diff --git a/vendor/github.com/gorilla/mux/context_native.go b/vendor/github.com/gorilla/mux/context_native.go new file mode 100644 index 000000000..209cbea7d --- /dev/null +++ b/vendor/github.com/gorilla/mux/context_native.go @@ -0,0 +1,24 @@ +// +build go1.7 + +package mux + +import ( + "context" + "net/http" +) + +func contextGet(r *http.Request, key interface{}) interface{} { + return r.Context().Value(key) +} + +func contextSet(r *http.Request, key, val interface{}) *http.Request { + if val == nil { + return r + } + + return r.WithContext(context.WithValue(r.Context(), key, val)) +} + +func contextClear(r *http.Request) { + return +} diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go new file mode 100644 index 000000000..013f08898 --- /dev/null +++ b/vendor/github.com/gorilla/mux/doc.go @@ -0,0 +1,307 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package mux implements a request router and dispatcher. + +The name mux stands for "HTTP request multiplexer". Like the standard +http.ServeMux, mux.Router matches incoming requests against a list of +registered routes and calls a handler for the route that matches the URL +or other conditions. The main features are: + + * Requests can be matched based on URL host, path, path prefix, schemes, + header and query values, HTTP methods or using custom matchers. + * URL hosts, paths and query values can have variables with an optional + regular expression. + * Registered URLs can be built, or "reversed", which helps maintaining + references to resources. + * Routes can be used as subrouters: nested routes are only tested if the + parent route matches. This is useful to define groups of routes that + share common conditions like a host, a path prefix or other repeated + attributes. As a bonus, this optimizes request matching. + * It implements the http.Handler interface so it is compatible with the + standard http.ServeMux. + +Let's start registering a couple of URL paths and handlers: + + func main() { + r := mux.NewRouter() + r.HandleFunc("/", HomeHandler) + r.HandleFunc("/products", ProductsHandler) + r.HandleFunc("/articles", ArticlesHandler) + http.Handle("/", r) + } + +Here we register three routes mapping URL paths to handlers. This is +equivalent to how http.HandleFunc() works: if an incoming request URL matches +one of the paths, the corresponding handler is called passing +(http.ResponseWriter, *http.Request) as parameters. + +Paths can have variables. They are defined using the format {name} or +{name:pattern}. If a regular expression pattern is not defined, the matched +variable will be anything until the next slash. For example: + + r := mux.NewRouter() + r.HandleFunc("/products/{key}", ProductHandler) + r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) + r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) + +Groups can be used inside patterns, as long as they are non-capturing (?:re). For example: + + r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler) + +The names are used to create a map of route variables which can be retrieved +calling mux.Vars(): + + vars := mux.Vars(request) + category := vars["category"] + +Note that if any capturing groups are present, mux will panic() during parsing. To prevent +this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to +"/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably +when capturing groups were present. + +And this is all you need to know about the basic usage. More advanced options +are explained below. + +Routes can also be restricted to a domain or subdomain. Just define a host +pattern to be matched. They can also have variables: + + r := mux.NewRouter() + // Only matches if domain is "www.example.com". + r.Host("www.example.com") + // Matches a dynamic subdomain. + r.Host("{subdomain:[a-z]+}.domain.com") + +There are several other matchers that can be added. To match path prefixes: + + r.PathPrefix("/products/") + +...or HTTP methods: + + r.Methods("GET", "POST") + +...or URL schemes: + + r.Schemes("https") + +...or header values: + + r.Headers("X-Requested-With", "XMLHttpRequest") + +...or query values: + + r.Queries("key", "value") + +...or to use a custom matcher function: + + r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { + return r.ProtoMajor == 0 + }) + +...and finally, it is possible to combine several matchers in a single route: + + r.HandleFunc("/products", ProductsHandler). + Host("www.example.com"). + Methods("GET"). + Schemes("http") + +Setting the same matching conditions again and again can be boring, so we have +a way to group several routes that share the same requirements. +We call it "subrouting". + +For example, let's say we have several URLs that should only match when the +host is "www.example.com". Create a route for that host and get a "subrouter" +from it: + + r := mux.NewRouter() + s := r.Host("www.example.com").Subrouter() + +Then register routes in the subrouter: + + s.HandleFunc("/products/", ProductsHandler) + s.HandleFunc("/products/{key}", ProductHandler) + s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) + +The three URL paths we registered above will only be tested if the domain is +"www.example.com", because the subrouter is tested first. This is not +only convenient, but also optimizes request matching. You can create +subrouters combining any attribute matchers accepted by a route. + +Subrouters can be used to create domain or path "namespaces": you define +subrouters in a central place and then parts of the app can register its +paths relatively to a given subrouter. + +There's one more thing about subroutes. When a subrouter has a path prefix, +the inner routes use it as base for their paths: + + r := mux.NewRouter() + s := r.PathPrefix("/products").Subrouter() + // "/products/" + s.HandleFunc("/", ProductsHandler) + // "/products/{key}/" + s.HandleFunc("/{key}/", ProductHandler) + // "/products/{key}/details" + s.HandleFunc("/{key}/details", ProductDetailsHandler) + +Note that the path provided to PathPrefix() represents a "wildcard": calling +PathPrefix("/static/").Handler(...) means that the handler will be passed any +request that matches "/static/*". This makes it easy to serve static files with mux: + + func main() { + var dir string + + flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") + flag.Parse() + r := mux.NewRouter() + + // This will serve files under http://localhost:8000/static/ + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) + + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8000", + // Good practice: enforce timeouts for servers you create! + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Fatal(srv.ListenAndServe()) + } + +Now let's see how to build registered URLs. + +Routes can be named. All routes that define a name can have their URLs built, +or "reversed". We define a name calling Name() on a route. For example: + + r := mux.NewRouter() + r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). + Name("article") + +To build a URL, get the route and call the URL() method, passing a sequence of +key/value pairs for the route variables. For the previous route, we would do: + + url, err := r.Get("article").URL("category", "technology", "id", "42") + +...and the result will be a url.URL with the following path: + + "/articles/technology/42" + +This also works for host and query value variables: + + r := mux.NewRouter() + r.Host("{subdomain}.domain.com"). + Path("/articles/{category}/{id:[0-9]+}"). + Queries("filter", "{filter}"). + HandlerFunc(ArticleHandler). + Name("article") + + // url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla" + url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42", + "filter", "gorilla") + +All variables defined in the route are required, and their values must +conform to the corresponding patterns. These requirements guarantee that a +generated URL will always match a registered route -- the only exception is +for explicitly defined "build-only" routes which never match. + +Regex support also exists for matching Headers within a route. For example, we could do: + + r.HeadersRegexp("Content-Type", "application/(text|json)") + +...and the route will match both requests with a Content-Type of `application/json` as well as +`application/text` + +There's also a way to build only the URL host or path for a route: +use the methods URLHost() or URLPath() instead. For the previous route, +we would do: + + // "http://news.domain.com/" + host, err := r.Get("article").URLHost("subdomain", "news") + + // "/articles/technology/42" + path, err := r.Get("article").URLPath("category", "technology", "id", "42") + +And if you use subrouters, host and path defined separately can be built +as well: + + r := mux.NewRouter() + s := r.Host("{subdomain}.domain.com").Subrouter() + s.Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + + // "http://news.domain.com/articles/technology/42" + url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") + +Since **vX.Y.Z**, mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed if a +match is found (including subrouters). Middlewares are defined using the de facto standard type: + + type MiddlewareFunc func(http.Handler) http.Handler + +Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created). + +A very basic middleware which logs the URI of the request being handled could be written as: + + func simpleMw(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Do stuff here + log.Println(r.RequestURI) + // Call the next handler, which can be another middleware in the chain, or the final handler. + next.ServeHTTP(w, r) + }) + } + +Middlewares can be added to a router using `Router.Use()`: + + r := mux.NewRouter() + r.HandleFunc("/", handler) + r.AddMiddleware(simpleMw) + +A more complex authentication middleware, which maps session token to users, could be written as: + + // Define our struct + type authenticationMiddleware struct { + tokenUsers map[string]string + } + + // Initialize it somewhere + func (amw *authenticationMiddleware) Populate() { + amw.tokenUsers["00000000"] = "user0" + amw.tokenUsers["aaaaaaaa"] = "userA" + amw.tokenUsers["05f717e5"] = "randomUser" + amw.tokenUsers["deadbeef"] = "user0" + } + + // Middleware function, which will be called for each request + func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("X-Session-Token") + + if user, found := amw.tokenUsers[token]; found { + // We found the token in our map + log.Printf("Authenticated user %s\n", user) + next.ServeHTTP(w, r) + } else { + http.Error(w, "Forbidden", 403) + } + }) + } + + r := mux.NewRouter() + r.HandleFunc("/", handler) + + amw := authenticationMiddleware{} + amw.Populate() + + r.Use(amw.Middleware) + +Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. + +*/ +package mux diff --git a/vendor/github.com/gorilla/mux/middleware.go b/vendor/github.com/gorilla/mux/middleware.go new file mode 100644 index 000000000..8f898675e --- /dev/null +++ b/vendor/github.com/gorilla/mux/middleware.go @@ -0,0 +1,28 @@ +package mux + +import "net/http" + +// MiddlewareFunc is a function which receives an http.Handler and returns another http.Handler. +// Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed +// to it, and then calls the handler passed as parameter to the MiddlewareFunc. +type MiddlewareFunc func(http.Handler) http.Handler + +// middleware interface is anything which implements a MiddlewareFunc named Middleware. +type middleware interface { + Middleware(handler http.Handler) http.Handler +} + +// MiddlewareFunc also implements the middleware interface. +func (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler { + return mw(handler) +} + +// Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router. +func (r *Router) Use(mwf MiddlewareFunc) { + r.middlewares = append(r.middlewares, mwf) +} + +// useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router. +func (r *Router) useInterface(mw middleware) { + r.middlewares = append(r.middlewares, mw) +} diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go new file mode 100644 index 000000000..efabd2417 --- /dev/null +++ b/vendor/github.com/gorilla/mux/mux.go @@ -0,0 +1,585 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mux + +import ( + "errors" + "fmt" + "net/http" + "path" + "regexp" +) + +var ( + ErrMethodMismatch = errors.New("method is not allowed") + ErrNotFound = errors.New("no matching route was found") +) + +// NewRouter returns a new router instance. +func NewRouter() *Router { + return &Router{namedRoutes: make(map[string]*Route), KeepContext: false} +} + +// Router registers routes to be matched and dispatches a handler. +// +// It implements the http.Handler interface, so it can be registered to serve +// requests: +// +// var router = mux.NewRouter() +// +// func main() { +// http.Handle("/", router) +// } +// +// Or, for Google App Engine, register it in a init() function: +// +// func init() { +// http.Handle("/", router) +// } +// +// This will send all incoming requests to the router. +type Router struct { + // Configurable Handler to be used when no route matches. + NotFoundHandler http.Handler + + // Configurable Handler to be used when the request method does not match the route. + MethodNotAllowedHandler http.Handler + + // Parent route, if this is a subrouter. + parent parentRoute + // Routes to be matched, in order. + routes []*Route + // Routes by name for URL building. + namedRoutes map[string]*Route + // See Router.StrictSlash(). This defines the flag for new routes. + strictSlash bool + // See Router.SkipClean(). This defines the flag for new routes. + skipClean bool + // If true, do not clear the request context after handling the request. + // This has no effect when go1.7+ is used, since the context is stored + // on the request itself. + KeepContext bool + // see Router.UseEncodedPath(). This defines a flag for all routes. + useEncodedPath bool + // Slice of middlewares to be called after a match is found + middlewares []middleware +} + +// Match attempts to match the given request against the router's registered routes. +// +// If the request matches a route of this router or one of its subrouters the Route, +// Handler, and Vars fields of the the match argument are filled and this function +// returns true. +// +// If the request does not match any of this router's or its subrouters' routes +// then this function returns false. If available, a reason for the match failure +// will be filled in the match argument's MatchErr field. If the match failure type +// (eg: not found) has a registered handler, the handler is assigned to the Handler +// field of the match argument. +func (r *Router) Match(req *http.Request, match *RouteMatch) bool { + for _, route := range r.routes { + if route.Match(req, match) { + // Build middleware chain if no error was found + if match.MatchErr == nil { + for i := len(r.middlewares) - 1; i >= 0; i-- { + match.Handler = r.middlewares[i].Middleware(match.Handler) + } + } + return true + } + } + + if match.MatchErr == ErrMethodMismatch { + if r.MethodNotAllowedHandler != nil { + match.Handler = r.MethodNotAllowedHandler + return true + } else { + return false + } + } + + // Closest match for a router (includes sub-routers) + if r.NotFoundHandler != nil { + match.Handler = r.NotFoundHandler + match.MatchErr = ErrNotFound + return true + } + + match.MatchErr = ErrNotFound + return false +} + +// ServeHTTP dispatches the handler registered in the matched route. +// +// When there is a match, the route variables can be retrieved calling +// mux.Vars(request). +func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { + if !r.skipClean { + path := req.URL.Path + if r.useEncodedPath { + path = req.URL.EscapedPath() + } + // Clean path to canonical form and redirect. + if p := cleanPath(path); p != path { + + // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query. + // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue: + // http://code.google.com/p/go/issues/detail?id=5252 + url := *req.URL + url.Path = p + p = url.String() + + w.Header().Set("Location", p) + w.WriteHeader(http.StatusMovedPermanently) + return + } + } + var match RouteMatch + var handler http.Handler + if r.Match(req, &match) { + handler = match.Handler + req = setVars(req, match.Vars) + req = setCurrentRoute(req, match.Route) + } + + if handler == nil && match.MatchErr == ErrMethodMismatch { + handler = methodNotAllowedHandler() + } + + if handler == nil { + handler = http.NotFoundHandler() + } + + if !r.KeepContext { + defer contextClear(req) + } + + handler.ServeHTTP(w, req) +} + +// Get returns a route registered with the given name. +func (r *Router) Get(name string) *Route { + return r.getNamedRoutes()[name] +} + +// GetRoute returns a route registered with the given name. This method +// was renamed to Get() and remains here for backwards compatibility. +func (r *Router) GetRoute(name string) *Route { + return r.getNamedRoutes()[name] +} + +// StrictSlash defines the trailing slash behavior for new routes. The initial +// value is false. +// +// When true, if the route path is "/path/", accessing "/path" will perform a redirect +// to the former and vice versa. In other words, your application will always +// see the path as specified in the route. +// +// When false, if the route path is "/path", accessing "/path/" will not match +// this route and vice versa. +// +// The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for +// routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed +// request will be made as a GET by most clients. Use middleware or client settings +// to modify this behaviour as needed. +// +// Special case: when a route sets a path prefix using the PathPrefix() method, +// strict slash is ignored for that route because the redirect behavior can't +// be determined from a prefix alone. However, any subrouters created from that +// route inherit the original StrictSlash setting. +func (r *Router) StrictSlash(value bool) *Router { + r.strictSlash = value + return r +} + +// SkipClean defines the path cleaning behaviour for new routes. The initial +// value is false. Users should be careful about which routes are not cleaned +// +// When true, if the route path is "/path//to", it will remain with the double +// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/ +// +// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will +// become /fetch/http/xkcd.com/534 +func (r *Router) SkipClean(value bool) *Router { + r.skipClean = value + return r +} + +// UseEncodedPath tells the router to match the encoded original path +// to the routes. +// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to". +// +// If not called, the router will match the unencoded path to the routes. +// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to" +func (r *Router) UseEncodedPath() *Router { + r.useEncodedPath = true + return r +} + +// ---------------------------------------------------------------------------- +// parentRoute +// ---------------------------------------------------------------------------- + +func (r *Router) getBuildScheme() string { + if r.parent != nil { + return r.parent.getBuildScheme() + } + return "" +} + +// getNamedRoutes returns the map where named routes are registered. +func (r *Router) getNamedRoutes() map[string]*Route { + if r.namedRoutes == nil { + if r.parent != nil { + r.namedRoutes = r.parent.getNamedRoutes() + } else { + r.namedRoutes = make(map[string]*Route) + } + } + return r.namedRoutes +} + +// getRegexpGroup returns regexp definitions from the parent route, if any. +func (r *Router) getRegexpGroup() *routeRegexpGroup { + if r.parent != nil { + return r.parent.getRegexpGroup() + } + return nil +} + +func (r *Router) buildVars(m map[string]string) map[string]string { + if r.parent != nil { + m = r.parent.buildVars(m) + } + return m +} + +// ---------------------------------------------------------------------------- +// Route factories +// ---------------------------------------------------------------------------- + +// NewRoute registers an empty route. +func (r *Router) NewRoute() *Route { + route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath} + r.routes = append(r.routes, route) + return route +} + +// Handle registers a new route with a matcher for the URL path. +// See Route.Path() and Route.Handler(). +func (r *Router) Handle(path string, handler http.Handler) *Route { + return r.NewRoute().Path(path).Handler(handler) +} + +// HandleFunc registers a new route with a matcher for the URL path. +// See Route.Path() and Route.HandlerFunc(). +func (r *Router) HandleFunc(path string, f func(http.ResponseWriter, + *http.Request)) *Route { + return r.NewRoute().Path(path).HandlerFunc(f) +} + +// Headers registers a new route with a matcher for request header values. +// See Route.Headers(). +func (r *Router) Headers(pairs ...string) *Route { + return r.NewRoute().Headers(pairs...) +} + +// Host registers a new route with a matcher for the URL host. +// See Route.Host(). +func (r *Router) Host(tpl string) *Route { + return r.NewRoute().Host(tpl) +} + +// MatcherFunc registers a new route with a custom matcher function. +// See Route.MatcherFunc(). +func (r *Router) MatcherFunc(f MatcherFunc) *Route { + return r.NewRoute().MatcherFunc(f) +} + +// Methods registers a new route with a matcher for HTTP methods. +// See Route.Methods(). +func (r *Router) Methods(methods ...string) *Route { + return r.NewRoute().Methods(methods...) +} + +// Path registers a new route with a matcher for the URL path. +// See Route.Path(). +func (r *Router) Path(tpl string) *Route { + return r.NewRoute().Path(tpl) +} + +// PathPrefix registers a new route with a matcher for the URL path prefix. +// See Route.PathPrefix(). +func (r *Router) PathPrefix(tpl string) *Route { + return r.NewRoute().PathPrefix(tpl) +} + +// Queries registers a new route with a matcher for URL query values. +// See Route.Queries(). +func (r *Router) Queries(pairs ...string) *Route { + return r.NewRoute().Queries(pairs...) +} + +// Schemes registers a new route with a matcher for URL schemes. +// See Route.Schemes(). +func (r *Router) Schemes(schemes ...string) *Route { + return r.NewRoute().Schemes(schemes...) +} + +// BuildVarsFunc registers a new route with a custom function for modifying +// route variables before building a URL. +func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route { + return r.NewRoute().BuildVarsFunc(f) +} + +// Walk walks the router and all its sub-routers, calling walkFn for each route +// in the tree. The routes are walked in the order they were added. Sub-routers +// are explored depth-first. +func (r *Router) Walk(walkFn WalkFunc) error { + return r.walk(walkFn, []*Route{}) +} + +// SkipRouter is used as a return value from WalkFuncs to indicate that the +// router that walk is about to descend down to should be skipped. +var SkipRouter = errors.New("skip this router") + +// WalkFunc is the type of the function called for each route visited by Walk. +// At every invocation, it is given the current route, and the current router, +// and a list of ancestor routes that lead to the current route. +type WalkFunc func(route *Route, router *Router, ancestors []*Route) error + +func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error { + for _, t := range r.routes { + err := walkFn(t, r, ancestors) + if err == SkipRouter { + continue + } + if err != nil { + return err + } + for _, sr := range t.matchers { + if h, ok := sr.(*Router); ok { + ancestors = append(ancestors, t) + err := h.walk(walkFn, ancestors) + if err != nil { + return err + } + ancestors = ancestors[:len(ancestors)-1] + } + } + if h, ok := t.handler.(*Router); ok { + ancestors = append(ancestors, t) + err := h.walk(walkFn, ancestors) + if err != nil { + return err + } + ancestors = ancestors[:len(ancestors)-1] + } + } + return nil +} + +// ---------------------------------------------------------------------------- +// Context +// ---------------------------------------------------------------------------- + +// RouteMatch stores information about a matched route. +type RouteMatch struct { + Route *Route + Handler http.Handler + Vars map[string]string + + // MatchErr is set to appropriate matching error + // It is set to ErrMethodMismatch if there is a mismatch in + // the request method and route method + MatchErr error +} + +type contextKey int + +const ( + varsKey contextKey = iota + routeKey +) + +// Vars returns the route variables for the current request, if any. +func Vars(r *http.Request) map[string]string { + if rv := contextGet(r, varsKey); rv != nil { + return rv.(map[string]string) + } + return nil +} + +// CurrentRoute returns the matched route for the current request, if any. +// This only works when called inside the handler of the matched route +// because the matched route is stored in the request context which is cleared +// after the handler returns, unless the KeepContext option is set on the +// Router. +func CurrentRoute(r *http.Request) *Route { + if rv := contextGet(r, routeKey); rv != nil { + return rv.(*Route) + } + return nil +} + +func setVars(r *http.Request, val interface{}) *http.Request { + return contextSet(r, varsKey, val) +} + +func setCurrentRoute(r *http.Request, val interface{}) *http.Request { + return contextSet(r, routeKey, val) +} + +// ---------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------- + +// cleanPath returns the canonical path for p, eliminating . and .. elements. +// Borrowed from the net/http package. +func cleanPath(p string) string { + if p == "" { + return "/" + } + if p[0] != '/' { + p = "/" + p + } + np := path.Clean(p) + // path.Clean removes trailing slash except for root; + // put the trailing slash back if necessary. + if p[len(p)-1] == '/' && np != "/" { + np += "/" + } + + return np +} + +// uniqueVars returns an error if two slices contain duplicated strings. +func uniqueVars(s1, s2 []string) error { + for _, v1 := range s1 { + for _, v2 := range s2 { + if v1 == v2 { + return fmt.Errorf("mux: duplicated route variable %q", v2) + } + } + } + return nil +} + +// checkPairs returns the count of strings passed in, and an error if +// the count is not an even number. +func checkPairs(pairs ...string) (int, error) { + length := len(pairs) + if length%2 != 0 { + return length, fmt.Errorf( + "mux: number of parameters must be multiple of 2, got %v", pairs) + } + return length, nil +} + +// mapFromPairsToString converts variadic string parameters to a +// string to string map. +func mapFromPairsToString(pairs ...string) (map[string]string, error) { + length, err := checkPairs(pairs...) + if err != nil { + return nil, err + } + m := make(map[string]string, length/2) + for i := 0; i < length; i += 2 { + m[pairs[i]] = pairs[i+1] + } + return m, nil +} + +// mapFromPairsToRegex converts variadic string parameters to a +// string to regex map. +func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) { + length, err := checkPairs(pairs...) + if err != nil { + return nil, err + } + m := make(map[string]*regexp.Regexp, length/2) + for i := 0; i < length; i += 2 { + regex, err := regexp.Compile(pairs[i+1]) + if err != nil { + return nil, err + } + m[pairs[i]] = regex + } + return m, nil +} + +// matchInArray returns true if the given string value is in the array. +func matchInArray(arr []string, value string) bool { + for _, v := range arr { + if v == value { + return true + } + } + return false +} + +// matchMapWithString returns true if the given key/value pairs exist in a given map. +func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool { + for k, v := range toCheck { + // Check if key exists. + if canonicalKey { + k = http.CanonicalHeaderKey(k) + } + if values := toMatch[k]; values == nil { + return false + } else if v != "" { + // If value was defined as an empty string we only check that the + // key exists. Otherwise we also check for equality. + valueExists := false + for _, value := range values { + if v == value { + valueExists = true + break + } + } + if !valueExists { + return false + } + } + } + return true +} + +// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against +// the given regex +func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool { + for k, v := range toCheck { + // Check if key exists. + if canonicalKey { + k = http.CanonicalHeaderKey(k) + } + if values := toMatch[k]; values == nil { + return false + } else if v != nil { + // If value was defined as an empty string we only check that the + // key exists. Otherwise we also check for equality. + valueExists := false + for _, value := range values { + if v.MatchString(value) { + valueExists = true + break + } + } + if !valueExists { + return false + } + } + } + return true +} + +// methodNotAllowed replies to the request with an HTTP status code 405. +func methodNotAllowed(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusMethodNotAllowed) +} + +// methodNotAllowedHandler returns a simple request handler +// that replies to each request with a status code 405. +func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) } diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go new file mode 100644 index 000000000..2b57e5627 --- /dev/null +++ b/vendor/github.com/gorilla/mux/regexp.go @@ -0,0 +1,332 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mux + +import ( + "bytes" + "fmt" + "net/http" + "net/url" + "regexp" + "strconv" + "strings" +) + +type routeRegexpOptions struct { + strictSlash bool + useEncodedPath bool +} + +type regexpType int + +const ( + regexpTypePath regexpType = 0 + regexpTypeHost regexpType = 1 + regexpTypePrefix regexpType = 2 + regexpTypeQuery regexpType = 3 +) + +// newRouteRegexp parses a route template and returns a routeRegexp, +// used to match a host, a path or a query string. +// +// It will extract named variables, assemble a regexp to be matched, create +// a "reverse" template to build URLs and compile regexps to validate variable +// values used in URL building. +// +// Previously we accepted only Python-like identifiers for variable +// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that +// name and pattern can't be empty, and names can't contain a colon. +func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*routeRegexp, error) { + // Check if it is well-formed. + idxs, errBraces := braceIndices(tpl) + if errBraces != nil { + return nil, errBraces + } + // Backup the original. + template := tpl + // Now let's parse it. + defaultPattern := "[^/]+" + if typ == regexpTypeQuery { + defaultPattern = ".*" + } else if typ == regexpTypeHost { + defaultPattern = "[^.]+" + } + // Only match strict slash if not matching + if typ != regexpTypePath { + options.strictSlash = false + } + // Set a flag for strictSlash. + endSlash := false + if options.strictSlash && strings.HasSuffix(tpl, "/") { + tpl = tpl[:len(tpl)-1] + endSlash = true + } + varsN := make([]string, len(idxs)/2) + varsR := make([]*regexp.Regexp, len(idxs)/2) + pattern := bytes.NewBufferString("") + pattern.WriteByte('^') + reverse := bytes.NewBufferString("") + var end int + var err error + for i := 0; i < len(idxs); i += 2 { + // Set all values we are interested in. + raw := tpl[end:idxs[i]] + end = idxs[i+1] + parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2) + name := parts[0] + patt := defaultPattern + if len(parts) == 2 { + patt = parts[1] + } + // Name or pattern can't be empty. + if name == "" || patt == "" { + return nil, fmt.Errorf("mux: missing name or pattern in %q", + tpl[idxs[i]:end]) + } + // Build the regexp pattern. + fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt) + + // Build the reverse template. + fmt.Fprintf(reverse, "%s%%s", raw) + + // Append variable name and compiled pattern. + varsN[i/2] = name + varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt)) + if err != nil { + return nil, err + } + } + // Add the remaining. + raw := tpl[end:] + pattern.WriteString(regexp.QuoteMeta(raw)) + if options.strictSlash { + pattern.WriteString("[/]?") + } + if typ == regexpTypeQuery { + // Add the default pattern if the query value is empty + if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" { + pattern.WriteString(defaultPattern) + } + } + if typ != regexpTypePrefix { + pattern.WriteByte('$') + } + reverse.WriteString(raw) + if endSlash { + reverse.WriteByte('/') + } + // Compile full regexp. + reg, errCompile := regexp.Compile(pattern.String()) + if errCompile != nil { + return nil, errCompile + } + + // Check for capturing groups which used to work in older versions + if reg.NumSubexp() != len(idxs)/2 { + panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) + + "Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)") + } + + // Done! + return &routeRegexp{ + template: template, + regexpType: typ, + options: options, + regexp: reg, + reverse: reverse.String(), + varsN: varsN, + varsR: varsR, + }, nil +} + +// routeRegexp stores a regexp to match a host or path and information to +// collect and validate route variables. +type routeRegexp struct { + // The unmodified template. + template string + // The type of match + regexpType regexpType + // Options for matching + options routeRegexpOptions + // Expanded regexp. + regexp *regexp.Regexp + // Reverse template. + reverse string + // Variable names. + varsN []string + // Variable regexps (validators). + varsR []*regexp.Regexp +} + +// Match matches the regexp against the URL host or path. +func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { + if r.regexpType != regexpTypeHost { + if r.regexpType == regexpTypeQuery { + return r.matchQueryString(req) + } + path := req.URL.Path + if r.options.useEncodedPath { + path = req.URL.EscapedPath() + } + return r.regexp.MatchString(path) + } + + return r.regexp.MatchString(getHost(req)) +} + +// url builds a URL part using the given values. +func (r *routeRegexp) url(values map[string]string) (string, error) { + urlValues := make([]interface{}, len(r.varsN)) + for k, v := range r.varsN { + value, ok := values[v] + if !ok { + return "", fmt.Errorf("mux: missing route variable %q", v) + } + if r.regexpType == regexpTypeQuery { + value = url.QueryEscape(value) + } + urlValues[k] = value + } + rv := fmt.Sprintf(r.reverse, urlValues...) + if !r.regexp.MatchString(rv) { + // The URL is checked against the full regexp, instead of checking + // individual variables. This is faster but to provide a good error + // message, we check individual regexps if the URL doesn't match. + for k, v := range r.varsN { + if !r.varsR[k].MatchString(values[v]) { + return "", fmt.Errorf( + "mux: variable %q doesn't match, expected %q", values[v], + r.varsR[k].String()) + } + } + } + return rv, nil +} + +// getURLQuery returns a single query parameter from a request URL. +// For a URL with foo=bar&baz=ding, we return only the relevant key +// value pair for the routeRegexp. +func (r *routeRegexp) getURLQuery(req *http.Request) string { + if r.regexpType != regexpTypeQuery { + return "" + } + templateKey := strings.SplitN(r.template, "=", 2)[0] + for key, vals := range req.URL.Query() { + if key == templateKey && len(vals) > 0 { + return key + "=" + vals[0] + } + } + return "" +} + +func (r *routeRegexp) matchQueryString(req *http.Request) bool { + return r.regexp.MatchString(r.getURLQuery(req)) +} + +// braceIndices returns the first level curly brace indices from a string. +// It returns an error in case of unbalanced braces. +func braceIndices(s string) ([]int, error) { + var level, idx int + var idxs []int + for i := 0; i < len(s); i++ { + switch s[i] { + case '{': + if level++; level == 1 { + idx = i + } + case '}': + if level--; level == 0 { + idxs = append(idxs, idx, i+1) + } else if level < 0 { + return nil, fmt.Errorf("mux: unbalanced braces in %q", s) + } + } + } + if level != 0 { + return nil, fmt.Errorf("mux: unbalanced braces in %q", s) + } + return idxs, nil +} + +// varGroupName builds a capturing group name for the indexed variable. +func varGroupName(idx int) string { + return "v" + strconv.Itoa(idx) +} + +// ---------------------------------------------------------------------------- +// routeRegexpGroup +// ---------------------------------------------------------------------------- + +// routeRegexpGroup groups the route matchers that carry variables. +type routeRegexpGroup struct { + host *routeRegexp + path *routeRegexp + queries []*routeRegexp +} + +// setMatch extracts the variables from the URL once a route matches. +func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) { + // Store host variables. + if v.host != nil { + host := getHost(req) + matches := v.host.regexp.FindStringSubmatchIndex(host) + if len(matches) > 0 { + extractVars(host, matches, v.host.varsN, m.Vars) + } + } + path := req.URL.Path + if r.useEncodedPath { + path = req.URL.EscapedPath() + } + // Store path variables. + if v.path != nil { + matches := v.path.regexp.FindStringSubmatchIndex(path) + if len(matches) > 0 { + extractVars(path, matches, v.path.varsN, m.Vars) + // Check if we should redirect. + if v.path.options.strictSlash { + p1 := strings.HasSuffix(path, "/") + p2 := strings.HasSuffix(v.path.template, "/") + if p1 != p2 { + u, _ := url.Parse(req.URL.String()) + if p1 { + u.Path = u.Path[:len(u.Path)-1] + } else { + u.Path += "/" + } + m.Handler = http.RedirectHandler(u.String(), 301) + } + } + } + } + // Store query string variables. + for _, q := range v.queries { + queryURL := q.getURLQuery(req) + matches := q.regexp.FindStringSubmatchIndex(queryURL) + if len(matches) > 0 { + extractVars(queryURL, matches, q.varsN, m.Vars) + } + } +} + +// getHost tries its best to return the request host. +func getHost(r *http.Request) string { + if r.URL.IsAbs() { + return r.URL.Host + } + host := r.Host + // Slice off any port information. + if i := strings.Index(host, ":"); i != -1 { + host = host[:i] + } + return host + +} + +func extractVars(input string, matches []int, names []string, output map[string]string) { + for i, name := range names { + output[name] = input[matches[2*i+2]:matches[2*i+3]] + } +} diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go new file mode 100644 index 000000000..4ce098d4f --- /dev/null +++ b/vendor/github.com/gorilla/mux/route.go @@ -0,0 +1,761 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mux + +import ( + "errors" + "fmt" + "net/http" + "net/url" + "regexp" + "strings" +) + +// Route stores information to match a request and build URLs. +type Route struct { + // Parent where the route was registered (a Router). + parent parentRoute + // Request handler for the route. + handler http.Handler + // List of matchers. + matchers []matcher + // Manager for the variables from host and path. + regexp *routeRegexpGroup + // If true, when the path pattern is "/path/", accessing "/path" will + // redirect to the former and vice versa. + strictSlash bool + // If true, when the path pattern is "/path//to", accessing "/path//to" + // will not redirect + skipClean bool + // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to" + useEncodedPath bool + // The scheme used when building URLs. + buildScheme string + // If true, this route never matches: it is only used to build URLs. + buildOnly bool + // The name used to build URLs. + name string + // Error resulted from building a route. + err error + + buildVarsFunc BuildVarsFunc +} + +func (r *Route) SkipClean() bool { + return r.skipClean +} + +// Match matches the route against the request. +func (r *Route) Match(req *http.Request, match *RouteMatch) bool { + if r.buildOnly || r.err != nil { + return false + } + + var matchErr error + + // Match everything. + for _, m := range r.matchers { + if matched := m.Match(req, match); !matched { + if _, ok := m.(methodMatcher); ok { + matchErr = ErrMethodMismatch + continue + } + matchErr = nil + return false + } + } + + if matchErr != nil { + match.MatchErr = matchErr + return false + } + + if match.MatchErr == ErrMethodMismatch { + // We found a route which matches request method, clear MatchErr + match.MatchErr = nil + // Then override the mis-matched handler + match.Handler = r.handler + } + + // Yay, we have a match. Let's collect some info about it. + if match.Route == nil { + match.Route = r + } + if match.Handler == nil { + match.Handler = r.handler + } + if match.Vars == nil { + match.Vars = make(map[string]string) + } + + // Set variables. + if r.regexp != nil { + r.regexp.setMatch(req, match, r) + } + return true +} + +// ---------------------------------------------------------------------------- +// Route attributes +// ---------------------------------------------------------------------------- + +// GetError returns an error resulted from building the route, if any. +func (r *Route) GetError() error { + return r.err +} + +// BuildOnly sets the route to never match: it is only used to build URLs. +func (r *Route) BuildOnly() *Route { + r.buildOnly = true + return r +} + +// Handler -------------------------------------------------------------------- + +// Handler sets a handler for the route. +func (r *Route) Handler(handler http.Handler) *Route { + if r.err == nil { + r.handler = handler + } + return r +} + +// HandlerFunc sets a handler function for the route. +func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route { + return r.Handler(http.HandlerFunc(f)) +} + +// GetHandler returns the handler for the route, if any. +func (r *Route) GetHandler() http.Handler { + return r.handler +} + +// Name ----------------------------------------------------------------------- + +// Name sets the name for the route, used to build URLs. +// If the name was registered already it will be overwritten. +func (r *Route) Name(name string) *Route { + if r.name != "" { + r.err = fmt.Errorf("mux: route already has name %q, can't set %q", + r.name, name) + } + if r.err == nil { + r.name = name + r.getNamedRoutes()[name] = r + } + return r +} + +// GetName returns the name for the route, if any. +func (r *Route) GetName() string { + return r.name +} + +// ---------------------------------------------------------------------------- +// Matchers +// ---------------------------------------------------------------------------- + +// matcher types try to match a request. +type matcher interface { + Match(*http.Request, *RouteMatch) bool +} + +// addMatcher adds a matcher to the route. +func (r *Route) addMatcher(m matcher) *Route { + if r.err == nil { + r.matchers = append(r.matchers, m) + } + return r +} + +// addRegexpMatcher adds a host or path matcher and builder to a route. +func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error { + if r.err != nil { + return r.err + } + r.regexp = r.getRegexpGroup() + if typ == regexpTypePath || typ == regexpTypePrefix { + if len(tpl) > 0 && tpl[0] != '/' { + return fmt.Errorf("mux: path must start with a slash, got %q", tpl) + } + if r.regexp.path != nil { + tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl + } + } + rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{ + strictSlash: r.strictSlash, + useEncodedPath: r.useEncodedPath, + }) + if err != nil { + return err + } + for _, q := range r.regexp.queries { + if err = uniqueVars(rr.varsN, q.varsN); err != nil { + return err + } + } + if typ == regexpTypeHost { + if r.regexp.path != nil { + if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil { + return err + } + } + r.regexp.host = rr + } else { + if r.regexp.host != nil { + if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil { + return err + } + } + if typ == regexpTypeQuery { + r.regexp.queries = append(r.regexp.queries, rr) + } else { + r.regexp.path = rr + } + } + r.addMatcher(rr) + return nil +} + +// Headers -------------------------------------------------------------------- + +// headerMatcher matches the request against header values. +type headerMatcher map[string]string + +func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchMapWithString(m, r.Header, true) +} + +// Headers adds a matcher for request header values. +// It accepts a sequence of key/value pairs to be matched. For example: +// +// r := mux.NewRouter() +// r.Headers("Content-Type", "application/json", +// "X-Requested-With", "XMLHttpRequest") +// +// The above route will only match if both request header values match. +// If the value is an empty string, it will match any value if the key is set. +func (r *Route) Headers(pairs ...string) *Route { + if r.err == nil { + var headers map[string]string + headers, r.err = mapFromPairsToString(pairs...) + return r.addMatcher(headerMatcher(headers)) + } + return r +} + +// headerRegexMatcher matches the request against the route given a regex for the header +type headerRegexMatcher map[string]*regexp.Regexp + +func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchMapWithRegex(m, r.Header, true) +} + +// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex +// support. For example: +// +// r := mux.NewRouter() +// r.HeadersRegexp("Content-Type", "application/(text|json)", +// "X-Requested-With", "XMLHttpRequest") +// +// The above route will only match if both the request header matches both regular expressions. +// If the value is an empty string, it will match any value if the key is set. +// Use the start and end of string anchors (^ and $) to match an exact value. +func (r *Route) HeadersRegexp(pairs ...string) *Route { + if r.err == nil { + var headers map[string]*regexp.Regexp + headers, r.err = mapFromPairsToRegex(pairs...) + return r.addMatcher(headerRegexMatcher(headers)) + } + return r +} + +// Host ----------------------------------------------------------------------- + +// Host adds a matcher for the URL host. +// It accepts a template with zero or more URL variables enclosed by {}. +// Variables can define an optional regexp pattern to be matched: +// +// - {name} matches anything until the next dot. +// +// - {name:pattern} matches the given regexp pattern. +// +// For example: +// +// r := mux.NewRouter() +// r.Host("www.example.com") +// r.Host("{subdomain}.domain.com") +// r.Host("{subdomain:[a-z]+}.domain.com") +// +// Variable names must be unique in a given route. They can be retrieved +// calling mux.Vars(request). +func (r *Route) Host(tpl string) *Route { + r.err = r.addRegexpMatcher(tpl, regexpTypeHost) + return r +} + +// MatcherFunc ---------------------------------------------------------------- + +// MatcherFunc is the function signature used by custom matchers. +type MatcherFunc func(*http.Request, *RouteMatch) bool + +// Match returns the match for a given request. +func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool { + return m(r, match) +} + +// MatcherFunc adds a custom function to be used as request matcher. +func (r *Route) MatcherFunc(f MatcherFunc) *Route { + return r.addMatcher(f) +} + +// Methods -------------------------------------------------------------------- + +// methodMatcher matches the request against HTTP methods. +type methodMatcher []string + +func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchInArray(m, r.Method) +} + +// Methods adds a matcher for HTTP methods. +// It accepts a sequence of one or more methods to be matched, e.g.: +// "GET", "POST", "PUT". +func (r *Route) Methods(methods ...string) *Route { + for k, v := range methods { + methods[k] = strings.ToUpper(v) + } + return r.addMatcher(methodMatcher(methods)) +} + +// Path ----------------------------------------------------------------------- + +// Path adds a matcher for the URL path. +// It accepts a template with zero or more URL variables enclosed by {}. The +// template must start with a "/". +// Variables can define an optional regexp pattern to be matched: +// +// - {name} matches anything until the next slash. +// +// - {name:pattern} matches the given regexp pattern. +// +// For example: +// +// r := mux.NewRouter() +// r.Path("/products/").Handler(ProductsHandler) +// r.Path("/products/{key}").Handler(ProductsHandler) +// r.Path("/articles/{category}/{id:[0-9]+}"). +// Handler(ArticleHandler) +// +// Variable names must be unique in a given route. They can be retrieved +// calling mux.Vars(request). +func (r *Route) Path(tpl string) *Route { + r.err = r.addRegexpMatcher(tpl, regexpTypePath) + return r +} + +// PathPrefix ----------------------------------------------------------------- + +// PathPrefix adds a matcher for the URL path prefix. This matches if the given +// template is a prefix of the full URL path. See Route.Path() for details on +// the tpl argument. +// +// Note that it does not treat slashes specially ("/foobar/" will be matched by +// the prefix "/foo") so you may want to use a trailing slash here. +// +// Also note that the setting of Router.StrictSlash() has no effect on routes +// with a PathPrefix matcher. +func (r *Route) PathPrefix(tpl string) *Route { + r.err = r.addRegexpMatcher(tpl, regexpTypePrefix) + return r +} + +// Query ---------------------------------------------------------------------- + +// Queries adds a matcher for URL query values. +// It accepts a sequence of key/value pairs. Values may define variables. +// For example: +// +// r := mux.NewRouter() +// r.Queries("foo", "bar", "id", "{id:[0-9]+}") +// +// The above route will only match if the URL contains the defined queries +// values, e.g.: ?foo=bar&id=42. +// +// It the value is an empty string, it will match any value if the key is set. +// +// Variables can define an optional regexp pattern to be matched: +// +// - {name} matches anything until the next slash. +// +// - {name:pattern} matches the given regexp pattern. +func (r *Route) Queries(pairs ...string) *Route { + length := len(pairs) + if length%2 != 0 { + r.err = fmt.Errorf( + "mux: number of parameters must be multiple of 2, got %v", pairs) + return nil + } + for i := 0; i < length; i += 2 { + if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery); r.err != nil { + return r + } + } + + return r +} + +// Schemes -------------------------------------------------------------------- + +// schemeMatcher matches the request against URL schemes. +type schemeMatcher []string + +func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchInArray(m, r.URL.Scheme) +} + +// Schemes adds a matcher for URL schemes. +// It accepts a sequence of schemes to be matched, e.g.: "http", "https". +func (r *Route) Schemes(schemes ...string) *Route { + for k, v := range schemes { + schemes[k] = strings.ToLower(v) + } + if r.buildScheme == "" && len(schemes) > 0 { + r.buildScheme = schemes[0] + } + return r.addMatcher(schemeMatcher(schemes)) +} + +// BuildVarsFunc -------------------------------------------------------------- + +// BuildVarsFunc is the function signature used by custom build variable +// functions (which can modify route variables before a route's URL is built). +type BuildVarsFunc func(map[string]string) map[string]string + +// BuildVarsFunc adds a custom function to be used to modify build variables +// before a route's URL is built. +func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route { + r.buildVarsFunc = f + return r +} + +// Subrouter ------------------------------------------------------------------ + +// Subrouter creates a subrouter for the route. +// +// It will test the inner routes only if the parent route matched. For example: +// +// r := mux.NewRouter() +// s := r.Host("www.example.com").Subrouter() +// s.HandleFunc("/products/", ProductsHandler) +// s.HandleFunc("/products/{key}", ProductHandler) +// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) +// +// Here, the routes registered in the subrouter won't be tested if the host +// doesn't match. +func (r *Route) Subrouter() *Router { + router := &Router{parent: r, strictSlash: r.strictSlash} + r.addMatcher(router) + return router +} + +// ---------------------------------------------------------------------------- +// URL building +// ---------------------------------------------------------------------------- + +// URL builds a URL for the route. +// +// It accepts a sequence of key/value pairs for the route variables. For +// example, given this route: +// +// r := mux.NewRouter() +// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). +// Name("article") +// +// ...a URL for it can be built using: +// +// url, err := r.Get("article").URL("category", "technology", "id", "42") +// +// ...which will return an url.URL with the following path: +// +// "/articles/technology/42" +// +// This also works for host variables: +// +// r := mux.NewRouter() +// r.Host("{subdomain}.domain.com"). +// HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). +// Name("article") +// +// // url.String() will be "http://news.domain.com/articles/technology/42" +// url, err := r.Get("article").URL("subdomain", "news", +// "category", "technology", +// "id", "42") +// +// All variables defined in the route are required, and their values must +// conform to the corresponding patterns. +func (r *Route) URL(pairs ...string) (*url.URL, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil { + return nil, errors.New("mux: route doesn't have a host or path") + } + values, err := r.prepareVars(pairs...) + if err != nil { + return nil, err + } + var scheme, host, path string + queries := make([]string, 0, len(r.regexp.queries)) + if r.regexp.host != nil { + if host, err = r.regexp.host.url(values); err != nil { + return nil, err + } + scheme = "http" + if s := r.getBuildScheme(); s != "" { + scheme = s + } + } + if r.regexp.path != nil { + if path, err = r.regexp.path.url(values); err != nil { + return nil, err + } + } + for _, q := range r.regexp.queries { + var query string + if query, err = q.url(values); err != nil { + return nil, err + } + queries = append(queries, query) + } + return &url.URL{ + Scheme: scheme, + Host: host, + Path: path, + RawQuery: strings.Join(queries, "&"), + }, nil +} + +// URLHost builds the host part of the URL for a route. See Route.URL(). +// +// The route must have a host defined. +func (r *Route) URLHost(pairs ...string) (*url.URL, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil || r.regexp.host == nil { + return nil, errors.New("mux: route doesn't have a host") + } + values, err := r.prepareVars(pairs...) + if err != nil { + return nil, err + } + host, err := r.regexp.host.url(values) + if err != nil { + return nil, err + } + u := &url.URL{ + Scheme: "http", + Host: host, + } + if s := r.getBuildScheme(); s != "" { + u.Scheme = s + } + return u, nil +} + +// URLPath builds the path part of the URL for a route. See Route.URL(). +// +// The route must have a path defined. +func (r *Route) URLPath(pairs ...string) (*url.URL, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil || r.regexp.path == nil { + return nil, errors.New("mux: route doesn't have a path") + } + values, err := r.prepareVars(pairs...) + if err != nil { + return nil, err + } + path, err := r.regexp.path.url(values) + if err != nil { + return nil, err + } + return &url.URL{ + Path: path, + }, nil +} + +// GetPathTemplate returns the template used to build the +// route match. +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An error will be returned if the route does not define a path. +func (r *Route) GetPathTemplate() (string, error) { + if r.err != nil { + return "", r.err + } + if r.regexp == nil || r.regexp.path == nil { + return "", errors.New("mux: route doesn't have a path") + } + return r.regexp.path.template, nil +} + +// GetPathRegexp returns the expanded regular expression used to match route path. +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An error will be returned if the route does not define a path. +func (r *Route) GetPathRegexp() (string, error) { + if r.err != nil { + return "", r.err + } + if r.regexp == nil || r.regexp.path == nil { + return "", errors.New("mux: route does not have a path") + } + return r.regexp.path.regexp.String(), nil +} + +// GetQueriesRegexp returns the expanded regular expressions used to match the +// route queries. +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An empty list will be returned if the route does not have queries. +func (r *Route) GetQueriesRegexp() ([]string, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil || r.regexp.queries == nil { + return nil, errors.New("mux: route doesn't have queries") + } + var queries []string + for _, query := range r.regexp.queries { + queries = append(queries, query.regexp.String()) + } + return queries, nil +} + +// GetQueriesTemplates returns the templates used to build the +// query matching. +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An empty list will be returned if the route does not define queries. +func (r *Route) GetQueriesTemplates() ([]string, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil || r.regexp.queries == nil { + return nil, errors.New("mux: route doesn't have queries") + } + var queries []string + for _, query := range r.regexp.queries { + queries = append(queries, query.template) + } + return queries, nil +} + +// GetMethods returns the methods the route matches against +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An empty list will be returned if route does not have methods. +func (r *Route) GetMethods() ([]string, error) { + if r.err != nil { + return nil, r.err + } + for _, m := range r.matchers { + if methods, ok := m.(methodMatcher); ok { + return []string(methods), nil + } + } + return nil, nil +} + +// GetHostTemplate returns the template used to build the +// route match. +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An error will be returned if the route does not define a host. +func (r *Route) GetHostTemplate() (string, error) { + if r.err != nil { + return "", r.err + } + if r.regexp == nil || r.regexp.host == nil { + return "", errors.New("mux: route doesn't have a host") + } + return r.regexp.host.template, nil +} + +// prepareVars converts the route variable pairs into a map. If the route has a +// BuildVarsFunc, it is invoked. +func (r *Route) prepareVars(pairs ...string) (map[string]string, error) { + m, err := mapFromPairsToString(pairs...) + if err != nil { + return nil, err + } + return r.buildVars(m), nil +} + +func (r *Route) buildVars(m map[string]string) map[string]string { + if r.parent != nil { + m = r.parent.buildVars(m) + } + if r.buildVarsFunc != nil { + m = r.buildVarsFunc(m) + } + return m +} + +// ---------------------------------------------------------------------------- +// parentRoute +// ---------------------------------------------------------------------------- + +// parentRoute allows routes to know about parent host and path definitions. +type parentRoute interface { + getBuildScheme() string + getNamedRoutes() map[string]*Route + getRegexpGroup() *routeRegexpGroup + buildVars(map[string]string) map[string]string +} + +func (r *Route) getBuildScheme() string { + if r.buildScheme != "" { + return r.buildScheme + } + if r.parent != nil { + return r.parent.getBuildScheme() + } + return "" +} + +// getNamedRoutes returns the map where named routes are registered. +func (r *Route) getNamedRoutes() map[string]*Route { + if r.parent == nil { + // During tests router is not always set. + r.parent = NewRouter() + } + return r.parent.getNamedRoutes() +} + +// getRegexpGroup returns regexp definitions from this route. +func (r *Route) getRegexpGroup() *routeRegexpGroup { + if r.regexp == nil { + if r.parent == nil { + // During tests router is not always set. + r.parent = NewRouter() + } + regexp := r.parent.getRegexpGroup() + if regexp == nil { + r.regexp = new(routeRegexpGroup) + } else { + // Copy. + r.regexp = &routeRegexpGroup{ + host: regexp.host, + path: regexp.path, + queries: regexp.queries, + } + } + } + return r.regexp +} diff --git a/vendor/github.com/gorilla/mux/test_helpers.go b/vendor/github.com/gorilla/mux/test_helpers.go new file mode 100644 index 000000000..8b2c4a4c5 --- /dev/null +++ b/vendor/github.com/gorilla/mux/test_helpers.go @@ -0,0 +1,18 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mux + +import "net/http" + +// SetURLVars sets the URL variables for the given request, to be accessed via +// mux.Vars for testing route behaviour. +// +// This API should only be used for testing purposes; it provides a way to +// inject variables into the request context. Alternatively, URL variables +// can be set by making a route that captures the required variables, +// starting a server and sending the request to that server. +func SetURLVars(r *http.Request, val map[string]string) *http.Request { + return setVars(r, val) +} diff --git a/vendor/github.com/gregjones/httpcache/.travis.yml b/vendor/github.com/gregjones/httpcache/.travis.yml new file mode 100644 index 000000000..2bca4c599 --- /dev/null +++ b/vendor/github.com/gregjones/httpcache/.travis.yml @@ -0,0 +1,18 @@ +sudo: false +language: go +go: + - 1.6.x + - 1.7.x + - 1.8.x + - master +matrix: + allow_failures: + - go: master + fast_finish: true +install: + - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step). +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - go tool vet . + - go test -v -race ./... diff --git a/vendor/github.com/gregjones/httpcache/LICENSE.txt b/vendor/github.com/gregjones/httpcache/LICENSE.txt new file mode 100644 index 000000000..81316beb0 --- /dev/null +++ b/vendor/github.com/gregjones/httpcache/LICENSE.txt @@ -0,0 +1,7 @@ +Copyright © 2012 Greg Jones (greg.jones@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/gregjones/httpcache/README.md b/vendor/github.com/gregjones/httpcache/README.md new file mode 100644 index 000000000..61bd830e5 --- /dev/null +++ b/vendor/github.com/gregjones/httpcache/README.md @@ -0,0 +1,24 @@ +httpcache +========= + +[![Build Status](https://travis-ci.org/gregjones/httpcache.svg?branch=master)](https://travis-ci.org/gregjones/httpcache) [![GoDoc](https://godoc.org/github.com/gregjones/httpcache?status.svg)](https://godoc.org/github.com/gregjones/httpcache) + +Package httpcache provides a http.RoundTripper implementation that works as a mostly RFC-compliant cache for http responses. + +It is only suitable for use as a 'private' cache (i.e. for a web-browser or an API-client and not for a shared proxy). + +Cache Backends +-------------- + +- The built-in 'memory' cache stores responses in an in-memory map. +- [`github.com/gregjones/httpcache/diskcache`](https://github.com/gregjones/httpcache/tree/master/diskcache) provides a filesystem-backed cache using the [diskv](https://github.com/peterbourgon/diskv) library. +- [`github.com/gregjones/httpcache/memcache`](https://github.com/gregjones/httpcache/tree/master/memcache) provides memcache implementations, for both App Engine and 'normal' memcache servers. +- [`sourcegraph.com/sourcegraph/s3cache`](https://sourcegraph.com/github.com/sourcegraph/s3cache) uses Amazon S3 for storage. +- [`github.com/gregjones/httpcache/leveldbcache`](https://github.com/gregjones/httpcache/tree/master/leveldbcache) provides a filesystem-backed cache using [leveldb](https://github.com/syndtr/goleveldb/leveldb). +- [`github.com/die-net/lrucache`](https://github.com/die-net/lrucache) provides an in-memory cache that will evict least-recently used entries. +- [`github.com/die-net/lrucache/twotier`](https://github.com/die-net/lrucache/tree/master/twotier) allows caches to be combined, for example to use lrucache above with a persistent disk-cache. + +License +------- + +- [MIT License](LICENSE.txt) diff --git a/vendor/github.com/gregjones/httpcache/diskcache/diskcache.go b/vendor/github.com/gregjones/httpcache/diskcache/diskcache.go new file mode 100644 index 000000000..42e3129d8 --- /dev/null +++ b/vendor/github.com/gregjones/httpcache/diskcache/diskcache.go @@ -0,0 +1,61 @@ +// Package diskcache provides an implementation of httpcache.Cache that uses the diskv package +// to supplement an in-memory map with persistent storage +// +package diskcache + +import ( + "bytes" + "crypto/md5" + "encoding/hex" + "github.com/peterbourgon/diskv" + "io" +) + +// Cache is an implementation of httpcache.Cache that supplements the in-memory map with persistent storage +type Cache struct { + d *diskv.Diskv +} + +// Get returns the response corresponding to key if present +func (c *Cache) Get(key string) (resp []byte, ok bool) { + key = keyToFilename(key) + resp, err := c.d.Read(key) + if err != nil { + return []byte{}, false + } + return resp, true +} + +// Set saves a response to the cache as key +func (c *Cache) Set(key string, resp []byte) { + key = keyToFilename(key) + c.d.WriteStream(key, bytes.NewReader(resp), true) +} + +// Delete removes the response with key from the cache +func (c *Cache) Delete(key string) { + key = keyToFilename(key) + c.d.Erase(key) +} + +func keyToFilename(key string) string { + h := md5.New() + io.WriteString(h, key) + return hex.EncodeToString(h.Sum(nil)) +} + +// New returns a new Cache that will store files in basePath +func New(basePath string) *Cache { + return &Cache{ + d: diskv.New(diskv.Options{ + BasePath: basePath, + CacheSizeMax: 100 * 1024 * 1024, // 100MB + }), + } +} + +// NewWithDiskv returns a new Cache using the provided Diskv as underlying +// storage. +func NewWithDiskv(d *diskv.Diskv) *Cache { + return &Cache{d} +} diff --git a/vendor/github.com/gregjones/httpcache/httpcache.go b/vendor/github.com/gregjones/httpcache/httpcache.go new file mode 100644 index 000000000..8239edc2c --- /dev/null +++ b/vendor/github.com/gregjones/httpcache/httpcache.go @@ -0,0 +1,553 @@ +// Package httpcache provides a http.RoundTripper implementation that works as a +// mostly RFC-compliant cache for http responses. +// +// It is only suitable for use as a 'private' cache (i.e. for a web-browser or an API-client +// and not for a shared proxy). +// +package httpcache + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/httputil" + "strings" + "sync" + "time" +) + +const ( + stale = iota + fresh + transparent + // XFromCache is the header added to responses that are returned from the cache + XFromCache = "X-From-Cache" +) + +// A Cache interface is used by the Transport to store and retrieve responses. +type Cache interface { + // Get returns the []byte representation of a cached response and a bool + // set to true if the value isn't empty + Get(key string) (responseBytes []byte, ok bool) + // Set stores the []byte representation of a response against a key + Set(key string, responseBytes []byte) + // Delete removes the value associated with the key + Delete(key string) +} + +// cacheKey returns the cache key for req. +func cacheKey(req *http.Request) string { + return req.URL.String() +} + +// CachedResponse returns the cached http.Response for req if present, and nil +// otherwise. +func CachedResponse(c Cache, req *http.Request) (resp *http.Response, err error) { + cachedVal, ok := c.Get(cacheKey(req)) + if !ok { + return + } + + b := bytes.NewBuffer(cachedVal) + return http.ReadResponse(bufio.NewReader(b), req) +} + +// MemoryCache is an implemtation of Cache that stores responses in an in-memory map. +type MemoryCache struct { + mu sync.RWMutex + items map[string][]byte +} + +// Get returns the []byte representation of the response and true if present, false if not +func (c *MemoryCache) Get(key string) (resp []byte, ok bool) { + c.mu.RLock() + resp, ok = c.items[key] + c.mu.RUnlock() + return resp, ok +} + +// Set saves response resp to the cache with key +func (c *MemoryCache) Set(key string, resp []byte) { + c.mu.Lock() + c.items[key] = resp + c.mu.Unlock() +} + +// Delete removes key from the cache +func (c *MemoryCache) Delete(key string) { + c.mu.Lock() + delete(c.items, key) + c.mu.Unlock() +} + +// NewMemoryCache returns a new Cache that will store items in an in-memory map +func NewMemoryCache() *MemoryCache { + c := &MemoryCache{items: map[string][]byte{}} + return c +} + +// Transport is an implementation of http.RoundTripper that will return values from a cache +// where possible (avoiding a network request) and will additionally add validators (etag/if-modified-since) +// to repeated requests allowing servers to return 304 / Not Modified +type Transport struct { + // The RoundTripper interface actually used to make requests + // If nil, http.DefaultTransport is used + Transport http.RoundTripper + Cache Cache + // If true, responses returned from the cache will be given an extra header, X-From-Cache + MarkCachedResponses bool +} + +// NewTransport returns a new Transport with the +// provided Cache implementation and MarkCachedResponses set to true +func NewTransport(c Cache) *Transport { + return &Transport{Cache: c, MarkCachedResponses: true} +} + +// Client returns an *http.Client that caches responses. +func (t *Transport) Client() *http.Client { + return &http.Client{Transport: t} +} + +// varyMatches will return false unless all of the cached values for the headers listed in Vary +// match the new request +func varyMatches(cachedResp *http.Response, req *http.Request) bool { + for _, header := range headerAllCommaSepValues(cachedResp.Header, "vary") { + header = http.CanonicalHeaderKey(header) + if header != "" && req.Header.Get(header) != cachedResp.Header.Get("X-Varied-"+header) { + return false + } + } + return true +} + +// RoundTrip takes a Request and returns a Response +// +// If there is a fresh Response already in cache, then it will be returned without connecting to +// the server. +// +// If there is a stale Response, then any validators it contains will be set on the new request +// to give the server a chance to respond with NotModified. If this happens, then the cached Response +// will be returned. +func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error) { + cacheKey := cacheKey(req) + cacheable := (req.Method == "GET" || req.Method == "HEAD") && req.Header.Get("range") == "" + var cachedResp *http.Response + if cacheable { + cachedResp, err = CachedResponse(t.Cache, req) + } else { + // Need to invalidate an existing value + t.Cache.Delete(cacheKey) + } + + transport := t.Transport + if transport == nil { + transport = http.DefaultTransport + } + + if cacheable && cachedResp != nil && err == nil { + if t.MarkCachedResponses { + cachedResp.Header.Set(XFromCache, "1") + } + + if varyMatches(cachedResp, req) { + // Can only use cached value if the new request doesn't Vary significantly + freshness := getFreshness(cachedResp.Header, req.Header) + if freshness == fresh { + return cachedResp, nil + } + + if freshness == stale { + var req2 *http.Request + // Add validators if caller hasn't already done so + etag := cachedResp.Header.Get("etag") + if etag != "" && req.Header.Get("etag") == "" { + req2 = cloneRequest(req) + req2.Header.Set("if-none-match", etag) + } + lastModified := cachedResp.Header.Get("last-modified") + if lastModified != "" && req.Header.Get("last-modified") == "" { + if req2 == nil { + req2 = cloneRequest(req) + } + req2.Header.Set("if-modified-since", lastModified) + } + if req2 != nil { + req = req2 + } + } + } + + resp, err = transport.RoundTrip(req) + if err == nil && req.Method == "GET" && resp.StatusCode == http.StatusNotModified { + // Replace the 304 response with the one from cache, but update with some new headers + endToEndHeaders := getEndToEndHeaders(resp.Header) + for _, header := range endToEndHeaders { + cachedResp.Header[header] = resp.Header[header] + } + cachedResp.Status = fmt.Sprintf("%d %s", http.StatusOK, http.StatusText(http.StatusOK)) + cachedResp.StatusCode = http.StatusOK + + resp = cachedResp + } else if (err != nil || (cachedResp != nil && resp.StatusCode >= 500)) && + req.Method == "GET" && canStaleOnError(cachedResp.Header, req.Header) { + // In case of transport failure and stale-if-error activated, returns cached content + // when available + cachedResp.Status = fmt.Sprintf("%d %s", http.StatusOK, http.StatusText(http.StatusOK)) + cachedResp.StatusCode = http.StatusOK + return cachedResp, nil + } else { + if err != nil || resp.StatusCode != http.StatusOK { + t.Cache.Delete(cacheKey) + } + if err != nil { + return nil, err + } + } + } else { + reqCacheControl := parseCacheControl(req.Header) + if _, ok := reqCacheControl["only-if-cached"]; ok { + resp = newGatewayTimeoutResponse(req) + } else { + resp, err = transport.RoundTrip(req) + if err != nil { + return nil, err + } + } + } + + if cacheable && canStore(parseCacheControl(req.Header), parseCacheControl(resp.Header)) { + for _, varyKey := range headerAllCommaSepValues(resp.Header, "vary") { + varyKey = http.CanonicalHeaderKey(varyKey) + fakeHeader := "X-Varied-" + varyKey + reqValue := req.Header.Get(varyKey) + if reqValue != "" { + resp.Header.Set(fakeHeader, reqValue) + } + } + switch req.Method { + case "GET": + // Delay caching until EOF is reached. + resp.Body = &cachingReadCloser{ + R: resp.Body, + OnEOF: func(r io.Reader) { + resp := *resp + resp.Body = ioutil.NopCloser(r) + respBytes, err := httputil.DumpResponse(&resp, true) + if err == nil { + t.Cache.Set(cacheKey, respBytes) + } + }, + } + default: + respBytes, err := httputil.DumpResponse(resp, true) + if err == nil { + t.Cache.Set(cacheKey, respBytes) + } + } + } else { + t.Cache.Delete(cacheKey) + } + return resp, nil +} + +// ErrNoDateHeader indicates that the HTTP headers contained no Date header. +var ErrNoDateHeader = errors.New("no Date header") + +// Date parses and returns the value of the Date header. +func Date(respHeaders http.Header) (date time.Time, err error) { + dateHeader := respHeaders.Get("date") + if dateHeader == "" { + err = ErrNoDateHeader + return + } + + return time.Parse(time.RFC1123, dateHeader) +} + +type realClock struct{} + +func (c *realClock) since(d time.Time) time.Duration { + return time.Since(d) +} + +type timer interface { + since(d time.Time) time.Duration +} + +var clock timer = &realClock{} + +// getFreshness will return one of fresh/stale/transparent based on the cache-control +// values of the request and the response +// +// fresh indicates the response can be returned +// stale indicates that the response needs validating before it is returned +// transparent indicates the response should not be used to fulfil the request +// +// Because this is only a private cache, 'public' and 'private' in cache-control aren't +// signficant. Similarly, smax-age isn't used. +func getFreshness(respHeaders, reqHeaders http.Header) (freshness int) { + respCacheControl := parseCacheControl(respHeaders) + reqCacheControl := parseCacheControl(reqHeaders) + if _, ok := reqCacheControl["no-cache"]; ok { + return transparent + } + if _, ok := respCacheControl["no-cache"]; ok { + return stale + } + if _, ok := reqCacheControl["only-if-cached"]; ok { + return fresh + } + + date, err := Date(respHeaders) + if err != nil { + return stale + } + currentAge := clock.since(date) + + var lifetime time.Duration + var zeroDuration time.Duration + + // If a response includes both an Expires header and a max-age directive, + // the max-age directive overrides the Expires header, even if the Expires header is more restrictive. + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err = time.ParseDuration(maxAge + "s") + if err != nil { + lifetime = zeroDuration + } + } else { + expiresHeader := respHeaders.Get("Expires") + if expiresHeader != "" { + expires, err := time.Parse(time.RFC1123, expiresHeader) + if err != nil { + lifetime = zeroDuration + } else { + lifetime = expires.Sub(date) + } + } + } + + if maxAge, ok := reqCacheControl["max-age"]; ok { + // the client is willing to accept a response whose age is no greater than the specified time in seconds + lifetime, err = time.ParseDuration(maxAge + "s") + if err != nil { + lifetime = zeroDuration + } + } + if minfresh, ok := reqCacheControl["min-fresh"]; ok { + // the client wants a response that will still be fresh for at least the specified number of seconds. + minfreshDuration, err := time.ParseDuration(minfresh + "s") + if err == nil { + currentAge = time.Duration(currentAge + minfreshDuration) + } + } + + if maxstale, ok := reqCacheControl["max-stale"]; ok { + // Indicates that the client is willing to accept a response that has exceeded its expiration time. + // If max-stale is assigned a value, then the client is willing to accept a response that has exceeded + // its expiration time by no more than the specified number of seconds. + // If no value is assigned to max-stale, then the client is willing to accept a stale response of any age. + // + // Responses served only because of a max-stale value are supposed to have a Warning header added to them, + // but that seems like a hassle, and is it actually useful? If so, then there needs to be a different + // return-value available here. + if maxstale == "" { + return fresh + } + maxstaleDuration, err := time.ParseDuration(maxstale + "s") + if err == nil { + currentAge = time.Duration(currentAge - maxstaleDuration) + } + } + + if lifetime > currentAge { + return fresh + } + + return stale +} + +// Returns true if either the request or the response includes the stale-if-error +// cache control extension: https://tools.ietf.org/html/rfc5861 +func canStaleOnError(respHeaders, reqHeaders http.Header) bool { + respCacheControl := parseCacheControl(respHeaders) + reqCacheControl := parseCacheControl(reqHeaders) + + var err error + lifetime := time.Duration(-1) + + if staleMaxAge, ok := respCacheControl["stale-if-error"]; ok { + if staleMaxAge != "" { + lifetime, err = time.ParseDuration(staleMaxAge + "s") + if err != nil { + return false + } + } else { + return true + } + } + if staleMaxAge, ok := reqCacheControl["stale-if-error"]; ok { + if staleMaxAge != "" { + lifetime, err = time.ParseDuration(staleMaxAge + "s") + if err != nil { + return false + } + } else { + return true + } + } + + if lifetime >= 0 { + date, err := Date(respHeaders) + if err != nil { + return false + } + currentAge := clock.since(date) + if lifetime > currentAge { + return true + } + } + + return false +} + +func getEndToEndHeaders(respHeaders http.Header) []string { + // These headers are always hop-by-hop + hopByHopHeaders := map[string]struct{}{ + "Connection": struct{}{}, + "Keep-Alive": struct{}{}, + "Proxy-Authenticate": struct{}{}, + "Proxy-Authorization": struct{}{}, + "Te": struct{}{}, + "Trailers": struct{}{}, + "Transfer-Encoding": struct{}{}, + "Upgrade": struct{}{}, + } + + for _, extra := range strings.Split(respHeaders.Get("connection"), ",") { + // any header listed in connection, if present, is also considered hop-by-hop + if strings.Trim(extra, " ") != "" { + hopByHopHeaders[http.CanonicalHeaderKey(extra)] = struct{}{} + } + } + endToEndHeaders := []string{} + for respHeader, _ := range respHeaders { + if _, ok := hopByHopHeaders[respHeader]; !ok { + endToEndHeaders = append(endToEndHeaders, respHeader) + } + } + return endToEndHeaders +} + +func canStore(reqCacheControl, respCacheControl cacheControl) (canStore bool) { + if _, ok := respCacheControl["no-store"]; ok { + return false + } + if _, ok := reqCacheControl["no-store"]; ok { + return false + } + return true +} + +func newGatewayTimeoutResponse(req *http.Request) *http.Response { + var braw bytes.Buffer + braw.WriteString("HTTP/1.1 504 Gateway Timeout\r\n\r\n") + resp, err := http.ReadResponse(bufio.NewReader(&braw), req) + if err != nil { + panic(err) + } + return resp +} + +// cloneRequest returns a clone of the provided *http.Request. +// The clone is a shallow copy of the struct and its Header map. +// (This function copyright goauth2 authors: https://code.google.com/p/goauth2) +func cloneRequest(r *http.Request) *http.Request { + // shallow copy of the struct + r2 := new(http.Request) + *r2 = *r + // deep copy of the Header + r2.Header = make(http.Header) + for k, s := range r.Header { + r2.Header[k] = s + } + return r2 +} + +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// headerAllCommaSepValues returns all comma-separated values (each +// with whitespace trimmed) for header name in headers. According to +// Section 4.2 of the HTTP/1.1 spec +// (http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2), +// values from multiple occurrences of a header should be concatenated, if +// the header's value is a comma-separated list. +func headerAllCommaSepValues(headers http.Header, name string) []string { + var vals []string + for _, val := range headers[http.CanonicalHeaderKey(name)] { + fields := strings.Split(val, ",") + for i, f := range fields { + fields[i] = strings.TrimSpace(f) + } + vals = append(vals, fields...) + } + return vals +} + +// cachingReadCloser is a wrapper around ReadCloser R that calls OnEOF +// handler with a full copy of the content read from R when EOF is +// reached. +type cachingReadCloser struct { + // Underlying ReadCloser. + R io.ReadCloser + // OnEOF is called with a copy of the content of R when EOF is reached. + OnEOF func(io.Reader) + + buf bytes.Buffer // buf stores a copy of the content of R. +} + +// Read reads the next len(p) bytes from R or until R is drained. The +// return value n is the number of bytes read. If R has no data to +// return, err is io.EOF and OnEOF is called with a full copy of what +// has been read so far. +func (r *cachingReadCloser) Read(p []byte) (n int, err error) { + n, err = r.R.Read(p) + r.buf.Write(p[:n]) + if err == io.EOF { + r.OnEOF(bytes.NewReader(r.buf.Bytes())) + } + return n, err +} + +func (r *cachingReadCloser) Close() error { + return r.R.Close() +} + +// NewMemoryCacheTransport returns a new Transport using the in-memory cache implementation +func NewMemoryCacheTransport() *Transport { + c := NewMemoryCache() + t := NewTransport(c) + return t +} diff --git a/vendor/github.com/hashicorp/hcl/.gitignore b/vendor/github.com/hashicorp/hcl/.gitignore new file mode 100644 index 000000000..15586a2b5 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/.gitignore @@ -0,0 +1,9 @@ +y.output + +# ignore intellij files +.idea +*.iml +*.ipr +*.iws + +*.test diff --git a/vendor/github.com/hashicorp/hcl/.travis.yml b/vendor/github.com/hashicorp/hcl/.travis.yml new file mode 100644 index 000000000..cb63a3216 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/.travis.yml @@ -0,0 +1,13 @@ +sudo: false + +language: go + +go: + - 1.x + - tip + +branches: + only: + - master + +script: make test diff --git a/vendor/github.com/hashicorp/hcl/LICENSE b/vendor/github.com/hashicorp/hcl/LICENSE new file mode 100644 index 000000000..c33dcc7c9 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/LICENSE @@ -0,0 +1,354 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/hcl/Makefile b/vendor/github.com/hashicorp/hcl/Makefile new file mode 100644 index 000000000..84fd743f5 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/Makefile @@ -0,0 +1,18 @@ +TEST?=./... + +default: test + +fmt: generate + go fmt ./... + +test: generate + go get -t ./... + go test $(TEST) $(TESTARGS) + +generate: + go generate ./... + +updatedeps: + go get -u golang.org/x/tools/cmd/stringer + +.PHONY: default generate test updatedeps diff --git a/vendor/github.com/hashicorp/hcl/README.md b/vendor/github.com/hashicorp/hcl/README.md new file mode 100644 index 000000000..c8223326d --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/README.md @@ -0,0 +1,125 @@ +# HCL + +[![GoDoc](https://godoc.org/github.com/hashicorp/hcl?status.png)](https://godoc.org/github.com/hashicorp/hcl) [![Build Status](https://travis-ci.org/hashicorp/hcl.svg?branch=master)](https://travis-ci.org/hashicorp/hcl) + +HCL (HashiCorp Configuration Language) is a configuration language built +by HashiCorp. The goal of HCL is to build a structured configuration language +that is both human and machine friendly for use with command-line tools, but +specifically targeted towards DevOps tools, servers, etc. + +HCL is also fully JSON compatible. That is, JSON can be used as completely +valid input to a system expecting HCL. This helps makes systems +interoperable with other systems. + +HCL is heavily inspired by +[libucl](https://github.com/vstakhov/libucl), +nginx configuration, and others similar. + +## Why? + +A common question when viewing HCL is to ask the question: why not +JSON, YAML, etc.? + +Prior to HCL, the tools we built at [HashiCorp](http://www.hashicorp.com) +used a variety of configuration languages from full programming languages +such as Ruby to complete data structure languages such as JSON. What we +learned is that some people wanted human-friendly configuration languages +and some people wanted machine-friendly languages. + +JSON fits a nice balance in this, but is fairly verbose and most +importantly doesn't support comments. With YAML, we found that beginners +had a really hard time determining what the actual structure was, and +ended up guessing more often than not whether to use a hyphen, colon, etc. +in order to represent some configuration key. + +Full programming languages such as Ruby enable complex behavior +a configuration language shouldn't usually allow, and also forces +people to learn some set of Ruby. + +Because of this, we decided to create our own configuration language +that is JSON-compatible. Our configuration language (HCL) is designed +to be written and modified by humans. The API for HCL allows JSON +as an input so that it is also machine-friendly (machines can generate +JSON instead of trying to generate HCL). + +Our goal with HCL is not to alienate other configuration languages. +It is instead to provide HCL as a specialized language for our tools, +and JSON as the interoperability layer. + +## Syntax + +For a complete grammar, please see the parser itself. A high-level overview +of the syntax and grammar is listed here. + + * Single line comments start with `#` or `//` + + * Multi-line comments are wrapped in `/*` and `*/`. Nested block comments + are not allowed. A multi-line comment (also known as a block comment) + terminates at the first `*/` found. + + * Values are assigned with the syntax `key = value` (whitespace doesn't + matter). The value can be any primitive: a string, number, boolean, + object, or list. + + * Strings are double-quoted and can contain any UTF-8 characters. + Example: `"Hello, World"` + + * Multi-line strings start with `<- + echo %Path% + + go version + + go env + + go get -t ./... + +build_script: +- cmd: go test -v ./... diff --git a/vendor/github.com/hashicorp/hcl/decoder.go b/vendor/github.com/hashicorp/hcl/decoder.go new file mode 100644 index 000000000..bed9ebbe1 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/decoder.go @@ -0,0 +1,729 @@ +package hcl + +import ( + "errors" + "fmt" + "reflect" + "sort" + "strconv" + "strings" + + "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/hcl/hcl/parser" + "github.com/hashicorp/hcl/hcl/token" +) + +// This is the tag to use with structures to have settings for HCL +const tagName = "hcl" + +var ( + // nodeType holds a reference to the type of ast.Node + nodeType reflect.Type = findNodeType() +) + +// Unmarshal accepts a byte slice as input and writes the +// data to the value pointed to by v. +func Unmarshal(bs []byte, v interface{}) error { + root, err := parse(bs) + if err != nil { + return err + } + + return DecodeObject(v, root) +} + +// Decode reads the given input and decodes it into the structure +// given by `out`. +func Decode(out interface{}, in string) error { + obj, err := Parse(in) + if err != nil { + return err + } + + return DecodeObject(out, obj) +} + +// DecodeObject is a lower-level version of Decode. It decodes a +// raw Object into the given output. +func DecodeObject(out interface{}, n ast.Node) error { + val := reflect.ValueOf(out) + if val.Kind() != reflect.Ptr { + return errors.New("result must be a pointer") + } + + // If we have the file, we really decode the root node + if f, ok := n.(*ast.File); ok { + n = f.Node + } + + var d decoder + return d.decode("root", n, val.Elem()) +} + +type decoder struct { + stack []reflect.Kind +} + +func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error { + k := result + + // If we have an interface with a valid value, we use that + // for the check. + if result.Kind() == reflect.Interface { + elem := result.Elem() + if elem.IsValid() { + k = elem + } + } + + // Push current onto stack unless it is an interface. + if k.Kind() != reflect.Interface { + d.stack = append(d.stack, k.Kind()) + + // Schedule a pop + defer func() { + d.stack = d.stack[:len(d.stack)-1] + }() + } + + switch k.Kind() { + case reflect.Bool: + return d.decodeBool(name, node, result) + case reflect.Float32, reflect.Float64: + return d.decodeFloat(name, node, result) + case reflect.Int, reflect.Int32, reflect.Int64: + return d.decodeInt(name, node, result) + case reflect.Interface: + // When we see an interface, we make our own thing + return d.decodeInterface(name, node, result) + case reflect.Map: + return d.decodeMap(name, node, result) + case reflect.Ptr: + return d.decodePtr(name, node, result) + case reflect.Slice: + return d.decodeSlice(name, node, result) + case reflect.String: + return d.decodeString(name, node, result) + case reflect.Struct: + return d.decodeStruct(name, node, result) + default: + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()), + } + } +} + +func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error { + switch n := node.(type) { + case *ast.LiteralType: + if n.Token.Type == token.BOOL { + v, err := strconv.ParseBool(n.Token.Text) + if err != nil { + return err + } + + result.Set(reflect.ValueOf(v)) + return nil + } + } + + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown type %T", name, node), + } +} + +func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error { + switch n := node.(type) { + case *ast.LiteralType: + if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER { + v, err := strconv.ParseFloat(n.Token.Text, 64) + if err != nil { + return err + } + + result.Set(reflect.ValueOf(v).Convert(result.Type())) + return nil + } + } + + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown type %T", name, node), + } +} + +func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error { + switch n := node.(type) { + case *ast.LiteralType: + switch n.Token.Type { + case token.NUMBER: + v, err := strconv.ParseInt(n.Token.Text, 0, 0) + if err != nil { + return err + } + + if result.Kind() == reflect.Interface { + result.Set(reflect.ValueOf(int(v))) + } else { + result.SetInt(v) + } + return nil + case token.STRING: + v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0) + if err != nil { + return err + } + + if result.Kind() == reflect.Interface { + result.Set(reflect.ValueOf(int(v))) + } else { + result.SetInt(v) + } + return nil + } + } + + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown type %T", name, node), + } +} + +func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error { + // When we see an ast.Node, we retain the value to enable deferred decoding. + // Very useful in situations where we want to preserve ast.Node information + // like Pos + if result.Type() == nodeType && result.CanSet() { + result.Set(reflect.ValueOf(node)) + return nil + } + + var set reflect.Value + redecode := true + + // For testing types, ObjectType should just be treated as a list. We + // set this to a temporary var because we want to pass in the real node. + testNode := node + if ot, ok := node.(*ast.ObjectType); ok { + testNode = ot.List + } + + switch n := testNode.(type) { + case *ast.ObjectList: + // If we're at the root or we're directly within a slice, then we + // decode objects into map[string]interface{}, otherwise we decode + // them into lists. + if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { + var temp map[string]interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeMap( + reflect.MapOf( + reflect.TypeOf(""), + tempVal.Type().Elem())) + + set = result + } else { + var temp []map[string]interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeSlice( + reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items)) + set = result + } + case *ast.ObjectType: + // If we're at the root or we're directly within a slice, then we + // decode objects into map[string]interface{}, otherwise we decode + // them into lists. + if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { + var temp map[string]interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeMap( + reflect.MapOf( + reflect.TypeOf(""), + tempVal.Type().Elem())) + + set = result + } else { + var temp []map[string]interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeSlice( + reflect.SliceOf(tempVal.Type().Elem()), 0, 1) + set = result + } + case *ast.ListType: + var temp []interface{} + tempVal := reflect.ValueOf(temp) + result := reflect.MakeSlice( + reflect.SliceOf(tempVal.Type().Elem()), 0, 0) + set = result + case *ast.LiteralType: + switch n.Token.Type { + case token.BOOL: + var result bool + set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) + case token.FLOAT: + var result float64 + set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) + case token.NUMBER: + var result int + set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) + case token.STRING, token.HEREDOC: + set = reflect.Indirect(reflect.New(reflect.TypeOf(""))) + default: + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node), + } + } + default: + return fmt.Errorf( + "%s: cannot decode into interface: %T", + name, node) + } + + // Set the result to what its supposed to be, then reset + // result so we don't reflect into this method anymore. + result.Set(set) + + if redecode { + // Revisit the node so that we can use the newly instantiated + // thing and populate it. + if err := d.decode(name, node, result); err != nil { + return err + } + } + + return nil +} + +func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error { + if item, ok := node.(*ast.ObjectItem); ok { + node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} + } + + if ot, ok := node.(*ast.ObjectType); ok { + node = ot.List + } + + n, ok := node.(*ast.ObjectList) + if !ok { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: not an object type for map (%T)", name, node), + } + } + + // If we have an interface, then we can address the interface, + // but not the slice itself, so get the element but set the interface + set := result + if result.Kind() == reflect.Interface { + result = result.Elem() + } + + resultType := result.Type() + resultElemType := resultType.Elem() + resultKeyType := resultType.Key() + if resultKeyType.Kind() != reflect.String { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: map must have string keys", name), + } + } + + // Make a map if it is nil + resultMap := result + if result.IsNil() { + resultMap = reflect.MakeMap( + reflect.MapOf(resultKeyType, resultElemType)) + } + + // Go through each element and decode it. + done := make(map[string]struct{}) + for _, item := range n.Items { + if item.Val == nil { + continue + } + + // github.com/hashicorp/terraform/issue/5740 + if len(item.Keys) == 0 { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: map must have string keys", name), + } + } + + // Get the key we're dealing with, which is the first item + keyStr := item.Keys[0].Token.Value().(string) + + // If we've already processed this key, then ignore it + if _, ok := done[keyStr]; ok { + continue + } + + // Determine the value. If we have more than one key, then we + // get the objectlist of only these keys. + itemVal := item.Val + if len(item.Keys) > 1 { + itemVal = n.Filter(keyStr) + done[keyStr] = struct{}{} + } + + // Make the field name + fieldName := fmt.Sprintf("%s.%s", name, keyStr) + + // Get the key/value as reflection values + key := reflect.ValueOf(keyStr) + val := reflect.Indirect(reflect.New(resultElemType)) + + // If we have a pre-existing value in the map, use that + oldVal := resultMap.MapIndex(key) + if oldVal.IsValid() { + val.Set(oldVal) + } + + // Decode! + if err := d.decode(fieldName, itemVal, val); err != nil { + return err + } + + // Set the value on the map + resultMap.SetMapIndex(key, val) + } + + // Set the final map if we can + set.Set(resultMap) + return nil +} + +func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error { + // Create an element of the concrete (non pointer) type and decode + // into that. Then set the value of the pointer to this type. + resultType := result.Type() + resultElemType := resultType.Elem() + val := reflect.New(resultElemType) + if err := d.decode(name, node, reflect.Indirect(val)); err != nil { + return err + } + + result.Set(val) + return nil +} + +func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error { + // If we have an interface, then we can address the interface, + // but not the slice itself, so get the element but set the interface + set := result + if result.Kind() == reflect.Interface { + result = result.Elem() + } + // Create the slice if it isn't nil + resultType := result.Type() + resultElemType := resultType.Elem() + if result.IsNil() { + resultSliceType := reflect.SliceOf(resultElemType) + result = reflect.MakeSlice( + resultSliceType, 0, 0) + } + + // Figure out the items we'll be copying into the slice + var items []ast.Node + switch n := node.(type) { + case *ast.ObjectList: + items = make([]ast.Node, len(n.Items)) + for i, item := range n.Items { + items[i] = item + } + case *ast.ObjectType: + items = []ast.Node{n} + case *ast.ListType: + items = n.List + default: + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("unknown slice type: %T", node), + } + } + + for i, item := range items { + fieldName := fmt.Sprintf("%s[%d]", name, i) + + // Decode + val := reflect.Indirect(reflect.New(resultElemType)) + + // if item is an object that was decoded from ambiguous JSON and + // flattened, make sure it's expanded if it needs to decode into a + // defined structure. + item := expandObject(item, val) + + if err := d.decode(fieldName, item, val); err != nil { + return err + } + + // Append it onto the slice + result = reflect.Append(result, val) + } + + set.Set(result) + return nil +} + +// expandObject detects if an ambiguous JSON object was flattened to a List which +// should be decoded into a struct, and expands the ast to properly deocode. +func expandObject(node ast.Node, result reflect.Value) ast.Node { + item, ok := node.(*ast.ObjectItem) + if !ok { + return node + } + + elemType := result.Type() + + // our target type must be a struct + switch elemType.Kind() { + case reflect.Ptr: + switch elemType.Elem().Kind() { + case reflect.Struct: + //OK + default: + return node + } + case reflect.Struct: + //OK + default: + return node + } + + // A list value will have a key and field name. If it had more fields, + // it wouldn't have been flattened. + if len(item.Keys) != 2 { + return node + } + + keyToken := item.Keys[0].Token + item.Keys = item.Keys[1:] + + // we need to un-flatten the ast enough to decode + newNode := &ast.ObjectItem{ + Keys: []*ast.ObjectKey{ + &ast.ObjectKey{ + Token: keyToken, + }, + }, + Val: &ast.ObjectType{ + List: &ast.ObjectList{ + Items: []*ast.ObjectItem{item}, + }, + }, + } + + return newNode +} + +func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error { + switch n := node.(type) { + case *ast.LiteralType: + switch n.Token.Type { + case token.NUMBER: + result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type())) + return nil + case token.STRING, token.HEREDOC: + result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type())) + return nil + } + } + + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unknown type for string %T", name, node), + } +} + +func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error { + var item *ast.ObjectItem + if it, ok := node.(*ast.ObjectItem); ok { + item = it + node = it.Val + } + + if ot, ok := node.(*ast.ObjectType); ok { + node = ot.List + } + + // Handle the special case where the object itself is a literal. Previously + // the yacc parser would always ensure top-level elements were arrays. The new + // parser does not make the same guarantees, thus we need to convert any + // top-level literal elements into a list. + if _, ok := node.(*ast.LiteralType); ok && item != nil { + node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} + } + + list, ok := node.(*ast.ObjectList) + if !ok { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node), + } + } + + // This slice will keep track of all the structs we'll be decoding. + // There can be more than one struct if there are embedded structs + // that are squashed. + structs := make([]reflect.Value, 1, 5) + structs[0] = result + + // Compile the list of all the fields that we're going to be decoding + // from all the structs. + type field struct { + field reflect.StructField + val reflect.Value + } + fields := []field{} + for len(structs) > 0 { + structVal := structs[0] + structs = structs[1:] + + structType := structVal.Type() + for i := 0; i < structType.NumField(); i++ { + fieldType := structType.Field(i) + tagParts := strings.Split(fieldType.Tag.Get(tagName), ",") + + // Ignore fields with tag name "-" + if tagParts[0] == "-" { + continue + } + + if fieldType.Anonymous { + fieldKind := fieldType.Type.Kind() + if fieldKind != reflect.Struct { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: unsupported type to struct: %s", + fieldType.Name, fieldKind), + } + } + + // We have an embedded field. We "squash" the fields down + // if specified in the tag. + squash := false + for _, tag := range tagParts[1:] { + if tag == "squash" { + squash = true + break + } + } + + if squash { + structs = append( + structs, result.FieldByName(fieldType.Name)) + continue + } + } + + // Normal struct field, store it away + fields = append(fields, field{fieldType, structVal.Field(i)}) + } + } + + usedKeys := make(map[string]struct{}) + decodedFields := make([]string, 0, len(fields)) + decodedFieldsVal := make([]reflect.Value, 0) + unusedKeysVal := make([]reflect.Value, 0) + for _, f := range fields { + field, fieldValue := f.field, f.val + if !fieldValue.IsValid() { + // This should never happen + panic("field is not valid") + } + + // If we can't set the field, then it is unexported or something, + // and we just continue onwards. + if !fieldValue.CanSet() { + continue + } + + fieldName := field.Name + + tagValue := field.Tag.Get(tagName) + tagParts := strings.SplitN(tagValue, ",", 2) + if len(tagParts) >= 2 { + switch tagParts[1] { + case "decodedFields": + decodedFieldsVal = append(decodedFieldsVal, fieldValue) + continue + case "key": + if item == nil { + return &parser.PosError{ + Pos: node.Pos(), + Err: fmt.Errorf("%s: %s asked for 'key', impossible", + name, fieldName), + } + } + + fieldValue.SetString(item.Keys[0].Token.Value().(string)) + continue + case "unusedKeys": + unusedKeysVal = append(unusedKeysVal, fieldValue) + continue + } + } + + if tagParts[0] != "" { + fieldName = tagParts[0] + } + + // Determine the element we'll use to decode. If it is a single + // match (only object with the field), then we decode it exactly. + // If it is a prefix match, then we decode the matches. + filter := list.Filter(fieldName) + + prefixMatches := filter.Children() + matches := filter.Elem() + if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 { + continue + } + + // Track the used key + usedKeys[fieldName] = struct{}{} + + // Create the field name and decode. We range over the elements + // because we actually want the value. + fieldName = fmt.Sprintf("%s.%s", name, fieldName) + if len(prefixMatches.Items) > 0 { + if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil { + return err + } + } + for _, match := range matches.Items { + var decodeNode ast.Node = match.Val + if ot, ok := decodeNode.(*ast.ObjectType); ok { + decodeNode = &ast.ObjectList{Items: ot.List.Items} + } + + if err := d.decode(fieldName, decodeNode, fieldValue); err != nil { + return err + } + } + + decodedFields = append(decodedFields, field.Name) + } + + if len(decodedFieldsVal) > 0 { + // Sort it so that it is deterministic + sort.Strings(decodedFields) + + for _, v := range decodedFieldsVal { + v.Set(reflect.ValueOf(decodedFields)) + } + } + + return nil +} + +// findNodeType returns the type of ast.Node +func findNodeType() reflect.Type { + var nodeContainer struct { + Node ast.Node + } + value := reflect.ValueOf(nodeContainer).FieldByName("Node") + return value.Type() +} diff --git a/vendor/github.com/hashicorp/hcl/hcl.go b/vendor/github.com/hashicorp/hcl/hcl.go new file mode 100644 index 000000000..575a20b50 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl.go @@ -0,0 +1,11 @@ +// Package hcl decodes HCL into usable Go structures. +// +// hcl input can come in either pure HCL format or JSON format. +// It can be parsed into an AST, and then decoded into a structure, +// or it can be decoded directly from a string into a structure. +// +// If you choose to parse HCL into a raw AST, the benefit is that you +// can write custom visitor implementations to implement custom +// semantic checks. By default, HCL does not perform any semantic +// checks. +package hcl diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go b/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go new file mode 100644 index 000000000..6e5ef654b --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go @@ -0,0 +1,219 @@ +// Package ast declares the types used to represent syntax trees for HCL +// (HashiCorp Configuration Language) +package ast + +import ( + "fmt" + "strings" + + "github.com/hashicorp/hcl/hcl/token" +) + +// Node is an element in the abstract syntax tree. +type Node interface { + node() + Pos() token.Pos +} + +func (File) node() {} +func (ObjectList) node() {} +func (ObjectKey) node() {} +func (ObjectItem) node() {} +func (Comment) node() {} +func (CommentGroup) node() {} +func (ObjectType) node() {} +func (LiteralType) node() {} +func (ListType) node() {} + +// File represents a single HCL file +type File struct { + Node Node // usually a *ObjectList + Comments []*CommentGroup // list of all comments in the source +} + +func (f *File) Pos() token.Pos { + return f.Node.Pos() +} + +// ObjectList represents a list of ObjectItems. An HCL file itself is an +// ObjectList. +type ObjectList struct { + Items []*ObjectItem +} + +func (o *ObjectList) Add(item *ObjectItem) { + o.Items = append(o.Items, item) +} + +// Filter filters out the objects with the given key list as a prefix. +// +// The returned list of objects contain ObjectItems where the keys have +// this prefix already stripped off. This might result in objects with +// zero-length key lists if they have no children. +// +// If no matches are found, an empty ObjectList (non-nil) is returned. +func (o *ObjectList) Filter(keys ...string) *ObjectList { + var result ObjectList + for _, item := range o.Items { + // If there aren't enough keys, then ignore this + if len(item.Keys) < len(keys) { + continue + } + + match := true + for i, key := range item.Keys[:len(keys)] { + key := key.Token.Value().(string) + if key != keys[i] && !strings.EqualFold(key, keys[i]) { + match = false + break + } + } + if !match { + continue + } + + // Strip off the prefix from the children + newItem := *item + newItem.Keys = newItem.Keys[len(keys):] + result.Add(&newItem) + } + + return &result +} + +// Children returns further nested objects (key length > 0) within this +// ObjectList. This should be used with Filter to get at child items. +func (o *ObjectList) Children() *ObjectList { + var result ObjectList + for _, item := range o.Items { + if len(item.Keys) > 0 { + result.Add(item) + } + } + + return &result +} + +// Elem returns items in the list that are direct element assignments +// (key length == 0). This should be used with Filter to get at elements. +func (o *ObjectList) Elem() *ObjectList { + var result ObjectList + for _, item := range o.Items { + if len(item.Keys) == 0 { + result.Add(item) + } + } + + return &result +} + +func (o *ObjectList) Pos() token.Pos { + // always returns the uninitiliazed position + return o.Items[0].Pos() +} + +// ObjectItem represents a HCL Object Item. An item is represented with a key +// (or keys). It can be an assignment or an object (both normal and nested) +type ObjectItem struct { + // keys is only one length long if it's of type assignment. If it's a + // nested object it can be larger than one. In that case "assign" is + // invalid as there is no assignments for a nested object. + Keys []*ObjectKey + + // assign contains the position of "=", if any + Assign token.Pos + + // val is the item itself. It can be an object,list, number, bool or a + // string. If key length is larger than one, val can be only of type + // Object. + Val Node + + LeadComment *CommentGroup // associated lead comment + LineComment *CommentGroup // associated line comment +} + +func (o *ObjectItem) Pos() token.Pos { + // I'm not entirely sure what causes this, but removing this causes + // a test failure. We should investigate at some point. + if len(o.Keys) == 0 { + return token.Pos{} + } + + return o.Keys[0].Pos() +} + +// ObjectKeys are either an identifier or of type string. +type ObjectKey struct { + Token token.Token +} + +func (o *ObjectKey) Pos() token.Pos { + return o.Token.Pos +} + +// LiteralType represents a literal of basic type. Valid types are: +// token.NUMBER, token.FLOAT, token.BOOL and token.STRING +type LiteralType struct { + Token token.Token + + // comment types, only used when in a list + LeadComment *CommentGroup + LineComment *CommentGroup +} + +func (l *LiteralType) Pos() token.Pos { + return l.Token.Pos +} + +// ListStatement represents a HCL List type +type ListType struct { + Lbrack token.Pos // position of "[" + Rbrack token.Pos // position of "]" + List []Node // the elements in lexical order +} + +func (l *ListType) Pos() token.Pos { + return l.Lbrack +} + +func (l *ListType) Add(node Node) { + l.List = append(l.List, node) +} + +// ObjectType represents a HCL Object Type +type ObjectType struct { + Lbrace token.Pos // position of "{" + Rbrace token.Pos // position of "}" + List *ObjectList // the nodes in lexical order +} + +func (o *ObjectType) Pos() token.Pos { + return o.Lbrace +} + +// Comment node represents a single //, # style or /*- style commment +type Comment struct { + Start token.Pos // position of / or # + Text string +} + +func (c *Comment) Pos() token.Pos { + return c.Start +} + +// CommentGroup node represents a sequence of comments with no other tokens and +// no empty lines between. +type CommentGroup struct { + List []*Comment // len(List) > 0 +} + +func (c *CommentGroup) Pos() token.Pos { + return c.List[0].Pos() +} + +//------------------------------------------------------------------- +// GoStringer +//------------------------------------------------------------------- + +func (o *ObjectKey) GoString() string { return fmt.Sprintf("*%#v", *o) } +func (o *ObjectList) GoString() string { return fmt.Sprintf("*%#v", *o) } diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go b/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go new file mode 100644 index 000000000..ba07ad42b --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go @@ -0,0 +1,52 @@ +package ast + +import "fmt" + +// WalkFunc describes a function to be called for each node during a Walk. The +// returned node can be used to rewrite the AST. Walking stops the returned +// bool is false. +type WalkFunc func(Node) (Node, bool) + +// Walk traverses an AST in depth-first order: It starts by calling fn(node); +// node must not be nil. If fn returns true, Walk invokes fn recursively for +// each of the non-nil children of node, followed by a call of fn(nil). The +// returned node of fn can be used to rewrite the passed node to fn. +func Walk(node Node, fn WalkFunc) Node { + rewritten, ok := fn(node) + if !ok { + return rewritten + } + + switch n := node.(type) { + case *File: + n.Node = Walk(n.Node, fn) + case *ObjectList: + for i, item := range n.Items { + n.Items[i] = Walk(item, fn).(*ObjectItem) + } + case *ObjectKey: + // nothing to do + case *ObjectItem: + for i, k := range n.Keys { + n.Keys[i] = Walk(k, fn).(*ObjectKey) + } + + if n.Val != nil { + n.Val = Walk(n.Val, fn) + } + case *LiteralType: + // nothing to do + case *ListType: + for i, l := range n.List { + n.List[i] = Walk(l, fn) + } + case *ObjectType: + n.List = Walk(n.List, fn).(*ObjectList) + default: + // should we panic here? + fmt.Printf("unknown type: %T\n", n) + } + + fn(nil) + return rewritten +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/error.go b/vendor/github.com/hashicorp/hcl/hcl/parser/error.go new file mode 100644 index 000000000..5c99381df --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/parser/error.go @@ -0,0 +1,17 @@ +package parser + +import ( + "fmt" + + "github.com/hashicorp/hcl/hcl/token" +) + +// PosError is a parse error that contains a position. +type PosError struct { + Pos token.Pos + Err error +} + +func (e *PosError) Error() string { + return fmt.Sprintf("At %s: %s", e.Pos, e.Err) +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go b/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go new file mode 100644 index 000000000..098e1bc49 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go @@ -0,0 +1,526 @@ +// Package parser implements a parser for HCL (HashiCorp Configuration +// Language) +package parser + +import ( + "bytes" + "errors" + "fmt" + "strings" + + "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/hcl/hcl/scanner" + "github.com/hashicorp/hcl/hcl/token" +) + +type Parser struct { + sc *scanner.Scanner + + // Last read token + tok token.Token + commaPrev token.Token + + comments []*ast.CommentGroup + leadComment *ast.CommentGroup // last lead comment + lineComment *ast.CommentGroup // last line comment + + enableTrace bool + indent int + n int // buffer size (max = 1) +} + +func newParser(src []byte) *Parser { + return &Parser{ + sc: scanner.New(src), + } +} + +// Parse returns the fully parsed source and returns the abstract syntax tree. +func Parse(src []byte) (*ast.File, error) { + // normalize all line endings + // since the scanner and output only work with "\n" line endings, we may + // end up with dangling "\r" characters in the parsed data. + src = bytes.Replace(src, []byte("\r\n"), []byte("\n"), -1) + + p := newParser(src) + return p.Parse() +} + +var errEofToken = errors.New("EOF token found") + +// Parse returns the fully parsed source and returns the abstract syntax tree. +func (p *Parser) Parse() (*ast.File, error) { + f := &ast.File{} + var err, scerr error + p.sc.Error = func(pos token.Pos, msg string) { + scerr = &PosError{Pos: pos, Err: errors.New(msg)} + } + + f.Node, err = p.objectList(false) + if scerr != nil { + return nil, scerr + } + if err != nil { + return nil, err + } + + f.Comments = p.comments + return f, nil +} + +// objectList parses a list of items within an object (generally k/v pairs). +// The parameter" obj" tells this whether to we are within an object (braces: +// '{', '}') or just at the top level. If we're within an object, we end +// at an RBRACE. +func (p *Parser) objectList(obj bool) (*ast.ObjectList, error) { + defer un(trace(p, "ParseObjectList")) + node := &ast.ObjectList{} + + for { + if obj { + tok := p.scan() + p.unscan() + if tok.Type == token.RBRACE { + break + } + } + + n, err := p.objectItem() + if err == errEofToken { + break // we are finished + } + + // we don't return a nil node, because might want to use already + // collected items. + if err != nil { + return node, err + } + + node.Add(n) + + // object lists can be optionally comma-delimited e.g. when a list of maps + // is being expressed, so a comma is allowed here - it's simply consumed + tok := p.scan() + if tok.Type != token.COMMA { + p.unscan() + } + } + return node, nil +} + +func (p *Parser) consumeComment() (comment *ast.Comment, endline int) { + endline = p.tok.Pos.Line + + // count the endline if it's multiline comment, ie starting with /* + if len(p.tok.Text) > 1 && p.tok.Text[1] == '*' { + // don't use range here - no need to decode Unicode code points + for i := 0; i < len(p.tok.Text); i++ { + if p.tok.Text[i] == '\n' { + endline++ + } + } + } + + comment = &ast.Comment{Start: p.tok.Pos, Text: p.tok.Text} + p.tok = p.sc.Scan() + return +} + +func (p *Parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) { + var list []*ast.Comment + endline = p.tok.Pos.Line + + for p.tok.Type == token.COMMENT && p.tok.Pos.Line <= endline+n { + var comment *ast.Comment + comment, endline = p.consumeComment() + list = append(list, comment) + } + + // add comment group to the comments list + comments = &ast.CommentGroup{List: list} + p.comments = append(p.comments, comments) + + return +} + +// objectItem parses a single object item +func (p *Parser) objectItem() (*ast.ObjectItem, error) { + defer un(trace(p, "ParseObjectItem")) + + keys, err := p.objectKey() + if len(keys) > 0 && err == errEofToken { + // We ignore eof token here since it is an error if we didn't + // receive a value (but we did receive a key) for the item. + err = nil + } + if len(keys) > 0 && err != nil && p.tok.Type == token.RBRACE { + // This is a strange boolean statement, but what it means is: + // We have keys with no value, and we're likely in an object + // (since RBrace ends an object). For this, we set err to nil so + // we continue and get the error below of having the wrong value + // type. + err = nil + + // Reset the token type so we don't think it completed fine. See + // objectType which uses p.tok.Type to check if we're done with + // the object. + p.tok.Type = token.EOF + } + if err != nil { + return nil, err + } + + o := &ast.ObjectItem{ + Keys: keys, + } + + if p.leadComment != nil { + o.LeadComment = p.leadComment + p.leadComment = nil + } + + switch p.tok.Type { + case token.ASSIGN: + o.Assign = p.tok.Pos + o.Val, err = p.object() + if err != nil { + return nil, err + } + case token.LBRACE: + o.Val, err = p.objectType() + if err != nil { + return nil, err + } + default: + keyStr := make([]string, 0, len(keys)) + for _, k := range keys { + keyStr = append(keyStr, k.Token.Text) + } + + return nil, &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf( + "key '%s' expected start of object ('{') or assignment ('=')", + strings.Join(keyStr, " ")), + } + } + + // do a look-ahead for line comment + p.scan() + if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil { + o.LineComment = p.lineComment + p.lineComment = nil + } + p.unscan() + return o, nil +} + +// objectKey parses an object key and returns a ObjectKey AST +func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { + keyCount := 0 + keys := make([]*ast.ObjectKey, 0) + + for { + tok := p.scan() + switch tok.Type { + case token.EOF: + // It is very important to also return the keys here as well as + // the error. This is because we need to be able to tell if we + // did parse keys prior to finding the EOF, or if we just found + // a bare EOF. + return keys, errEofToken + case token.ASSIGN: + // assignment or object only, but not nested objects. this is not + // allowed: `foo bar = {}` + if keyCount > 1 { + return nil, &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf("nested object expected: LBRACE got: %s", p.tok.Type), + } + } + + if keyCount == 0 { + return nil, &PosError{ + Pos: p.tok.Pos, + Err: errors.New("no object keys found!"), + } + } + + return keys, nil + case token.LBRACE: + var err error + + // If we have no keys, then it is a syntax error. i.e. {{}} is not + // allowed. + if len(keys) == 0 { + err = &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf("expected: IDENT | STRING got: %s", p.tok.Type), + } + } + + // object + return keys, err + case token.IDENT, token.STRING: + keyCount++ + keys = append(keys, &ast.ObjectKey{Token: p.tok}) + case token.ILLEGAL: + return keys, &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf("illegal character"), + } + default: + return keys, &PosError{ + Pos: p.tok.Pos, + Err: fmt.Errorf("expected: IDENT | STRING | ASSIGN | LBRACE got: %s", p.tok.Type), + } + } + } +} + +// object parses any type of object, such as number, bool, string, object or +// list. +func (p *Parser) object() (ast.Node, error) { + defer un(trace(p, "ParseType")) + tok := p.scan() + + switch tok.Type { + case token.NUMBER, token.FLOAT, token.BOOL, token.STRING, token.HEREDOC: + return p.literalType() + case token.LBRACE: + return p.objectType() + case token.LBRACK: + return p.listType() + case token.COMMENT: + // implement comment + case token.EOF: + return nil, errEofToken + } + + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf("Unknown token: %+v", tok), + } +} + +// objectType parses an object type and returns a ObjectType AST +func (p *Parser) objectType() (*ast.ObjectType, error) { + defer un(trace(p, "ParseObjectType")) + + // we assume that the currently scanned token is a LBRACE + o := &ast.ObjectType{ + Lbrace: p.tok.Pos, + } + + l, err := p.objectList(true) + + // if we hit RBRACE, we are good to go (means we parsed all Items), if it's + // not a RBRACE, it's an syntax error and we just return it. + if err != nil && p.tok.Type != token.RBRACE { + return nil, err + } + + // No error, scan and expect the ending to be a brace + if tok := p.scan(); tok.Type != token.RBRACE { + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type), + } + } + + o.List = l + o.Rbrace = p.tok.Pos // advanced via parseObjectList + return o, nil +} + +// listType parses a list type and returns a ListType AST +func (p *Parser) listType() (*ast.ListType, error) { + defer un(trace(p, "ParseListType")) + + // we assume that the currently scanned token is a LBRACK + l := &ast.ListType{ + Lbrack: p.tok.Pos, + } + + needComma := false + for { + tok := p.scan() + if needComma { + switch tok.Type { + case token.COMMA, token.RBRACK: + default: + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf( + "error parsing list, expected comma or list end, got: %s", + tok.Type), + } + } + } + switch tok.Type { + case token.BOOL, token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC: + node, err := p.literalType() + if err != nil { + return nil, err + } + + // If there is a lead comment, apply it + if p.leadComment != nil { + node.LeadComment = p.leadComment + p.leadComment = nil + } + + l.Add(node) + needComma = true + case token.COMMA: + // get next list item or we are at the end + // do a look-ahead for line comment + p.scan() + if p.lineComment != nil && len(l.List) > 0 { + lit, ok := l.List[len(l.List)-1].(*ast.LiteralType) + if ok { + lit.LineComment = p.lineComment + l.List[len(l.List)-1] = lit + p.lineComment = nil + } + } + p.unscan() + + needComma = false + continue + case token.LBRACE: + // Looks like a nested object, so parse it out + node, err := p.objectType() + if err != nil { + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf( + "error while trying to parse object within list: %s", err), + } + } + l.Add(node) + needComma = true + case token.LBRACK: + node, err := p.listType() + if err != nil { + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf( + "error while trying to parse list within list: %s", err), + } + } + l.Add(node) + case token.RBRACK: + // finished + l.Rbrack = p.tok.Pos + return l, nil + default: + return nil, &PosError{ + Pos: tok.Pos, + Err: fmt.Errorf("unexpected token while parsing list: %s", tok.Type), + } + } + } +} + +// literalType parses a literal type and returns a LiteralType AST +func (p *Parser) literalType() (*ast.LiteralType, error) { + defer un(trace(p, "ParseLiteral")) + + return &ast.LiteralType{ + Token: p.tok, + }, nil +} + +// scan returns the next token from the underlying scanner. If a token has +// been unscanned then read that instead. In the process, it collects any +// comment groups encountered, and remembers the last lead and line comments. +func (p *Parser) scan() token.Token { + // If we have a token on the buffer, then return it. + if p.n != 0 { + p.n = 0 + return p.tok + } + + // Otherwise read the next token from the scanner and Save it to the buffer + // in case we unscan later. + prev := p.tok + p.tok = p.sc.Scan() + + if p.tok.Type == token.COMMENT { + var comment *ast.CommentGroup + var endline int + + // fmt.Printf("p.tok.Pos.Line = %+v prev: %d endline %d \n", + // p.tok.Pos.Line, prev.Pos.Line, endline) + if p.tok.Pos.Line == prev.Pos.Line { + // The comment is on same line as the previous token; it + // cannot be a lead comment but may be a line comment. + comment, endline = p.consumeCommentGroup(0) + if p.tok.Pos.Line != endline { + // The next token is on a different line, thus + // the last comment group is a line comment. + p.lineComment = comment + } + } + + // consume successor comments, if any + endline = -1 + for p.tok.Type == token.COMMENT { + comment, endline = p.consumeCommentGroup(1) + } + + if endline+1 == p.tok.Pos.Line && p.tok.Type != token.RBRACE { + switch p.tok.Type { + case token.RBRACE, token.RBRACK: + // Do not count for these cases + default: + // The next token is following on the line immediately after the + // comment group, thus the last comment group is a lead comment. + p.leadComment = comment + } + } + + } + + return p.tok +} + +// unscan pushes the previously read token back onto the buffer. +func (p *Parser) unscan() { + p.n = 1 +} + +// ---------------------------------------------------------------------------- +// Parsing support + +func (p *Parser) printTrace(a ...interface{}) { + if !p.enableTrace { + return + } + + const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + const n = len(dots) + fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) + + i := 2 * p.indent + for i > n { + fmt.Print(dots) + i -= n + } + // i <= n + fmt.Print(dots[0:i]) + fmt.Println(a...) +} + +func trace(p *Parser, msg string) *Parser { + p.printTrace(msg, "(") + p.indent++ + return p +} + +// Usage pattern: defer un(trace(p, "...")) +func un(p *Parser) { + p.indent-- + p.printTrace(")") +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go new file mode 100644 index 000000000..6601ef76e --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go @@ -0,0 +1,651 @@ +// Package scanner implements a scanner for HCL (HashiCorp Configuration +// Language) source text. +package scanner + +import ( + "bytes" + "fmt" + "os" + "regexp" + "unicode" + "unicode/utf8" + + "github.com/hashicorp/hcl/hcl/token" +) + +// eof represents a marker rune for the end of the reader. +const eof = rune(0) + +// Scanner defines a lexical scanner +type Scanner struct { + buf *bytes.Buffer // Source buffer for advancing and scanning + src []byte // Source buffer for immutable access + + // Source Position + srcPos token.Pos // current position + prevPos token.Pos // previous position, used for peek() method + + lastCharLen int // length of last character in bytes + lastLineLen int // length of last line in characters (for correct column reporting) + + tokStart int // token text start position + tokEnd int // token text end position + + // Error is called for each error encountered. If no Error + // function is set, the error is reported to os.Stderr. + Error func(pos token.Pos, msg string) + + // ErrorCount is incremented by one for each error encountered. + ErrorCount int + + // tokPos is the start position of most recently scanned token; set by + // Scan. The Filename field is always left untouched by the Scanner. If + // an error is reported (via Error) and Position is invalid, the scanner is + // not inside a token. + tokPos token.Pos +} + +// New creates and initializes a new instance of Scanner using src as +// its source content. +func New(src []byte) *Scanner { + // even though we accept a src, we read from a io.Reader compatible type + // (*bytes.Buffer). So in the future we might easily change it to streaming + // read. + b := bytes.NewBuffer(src) + s := &Scanner{ + buf: b, + src: src, + } + + // srcPosition always starts with 1 + s.srcPos.Line = 1 + return s +} + +// next reads the next rune from the bufferred reader. Returns the rune(0) if +// an error occurs (or io.EOF is returned). +func (s *Scanner) next() rune { + ch, size, err := s.buf.ReadRune() + if err != nil { + // advance for error reporting + s.srcPos.Column++ + s.srcPos.Offset += size + s.lastCharLen = size + return eof + } + + if ch == utf8.RuneError && size == 1 { + s.srcPos.Column++ + s.srcPos.Offset += size + s.lastCharLen = size + s.err("illegal UTF-8 encoding") + return ch + } + + // remember last position + s.prevPos = s.srcPos + + s.srcPos.Column++ + s.lastCharLen = size + s.srcPos.Offset += size + + if ch == '\n' { + s.srcPos.Line++ + s.lastLineLen = s.srcPos.Column + s.srcPos.Column = 0 + } + + // If we see a null character with data left, then that is an error + if ch == '\x00' && s.buf.Len() > 0 { + s.err("unexpected null character (0x00)") + return eof + } + + // debug + // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) + return ch +} + +// unread unreads the previous read Rune and updates the source position +func (s *Scanner) unread() { + if err := s.buf.UnreadRune(); err != nil { + panic(err) // this is user fault, we should catch it + } + s.srcPos = s.prevPos // put back last position +} + +// peek returns the next rune without advancing the reader. +func (s *Scanner) peek() rune { + peek, _, err := s.buf.ReadRune() + if err != nil { + return eof + } + + s.buf.UnreadRune() + return peek +} + +// Scan scans the next token and returns the token. +func (s *Scanner) Scan() token.Token { + ch := s.next() + + // skip white space + for isWhitespace(ch) { + ch = s.next() + } + + var tok token.Type + + // token text markings + s.tokStart = s.srcPos.Offset - s.lastCharLen + + // token position, initial next() is moving the offset by one(size of rune + // actually), though we are interested with the starting point + s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen + if s.srcPos.Column > 0 { + // common case: last character was not a '\n' + s.tokPos.Line = s.srcPos.Line + s.tokPos.Column = s.srcPos.Column + } else { + // last character was a '\n' + // (we cannot be at the beginning of the source + // since we have called next() at least once) + s.tokPos.Line = s.srcPos.Line - 1 + s.tokPos.Column = s.lastLineLen + } + + switch { + case isLetter(ch): + tok = token.IDENT + lit := s.scanIdentifier() + if lit == "true" || lit == "false" { + tok = token.BOOL + } + case isDecimal(ch): + tok = s.scanNumber(ch) + default: + switch ch { + case eof: + tok = token.EOF + case '"': + tok = token.STRING + s.scanString() + case '#', '/': + tok = token.COMMENT + s.scanComment(ch) + case '.': + tok = token.PERIOD + ch = s.peek() + if isDecimal(ch) { + tok = token.FLOAT + ch = s.scanMantissa(ch) + ch = s.scanExponent(ch) + } + case '<': + tok = token.HEREDOC + s.scanHeredoc() + case '[': + tok = token.LBRACK + case ']': + tok = token.RBRACK + case '{': + tok = token.LBRACE + case '}': + tok = token.RBRACE + case ',': + tok = token.COMMA + case '=': + tok = token.ASSIGN + case '+': + tok = token.ADD + case '-': + if isDecimal(s.peek()) { + ch := s.next() + tok = s.scanNumber(ch) + } else { + tok = token.SUB + } + default: + s.err("illegal char") + } + } + + // finish token ending + s.tokEnd = s.srcPos.Offset + + // create token literal + var tokenText string + if s.tokStart >= 0 { + tokenText = string(s.src[s.tokStart:s.tokEnd]) + } + s.tokStart = s.tokEnd // ensure idempotency of tokenText() call + + return token.Token{ + Type: tok, + Pos: s.tokPos, + Text: tokenText, + } +} + +func (s *Scanner) scanComment(ch rune) { + // single line comments + if ch == '#' || (ch == '/' && s.peek() != '*') { + if ch == '/' && s.peek() != '/' { + s.err("expected '/' for comment") + return + } + + ch = s.next() + for ch != '\n' && ch >= 0 && ch != eof { + ch = s.next() + } + if ch != eof && ch >= 0 { + s.unread() + } + return + } + + // be sure we get the character after /* This allows us to find comment's + // that are not erminated + if ch == '/' { + s.next() + ch = s.next() // read character after "/*" + } + + // look for /* - style comments + for { + if ch < 0 || ch == eof { + s.err("comment not terminated") + break + } + + ch0 := ch + ch = s.next() + if ch0 == '*' && ch == '/' { + break + } + } +} + +// scanNumber scans a HCL number definition starting with the given rune +func (s *Scanner) scanNumber(ch rune) token.Type { + if ch == '0' { + // check for hexadecimal, octal or float + ch = s.next() + if ch == 'x' || ch == 'X' { + // hexadecimal + ch = s.next() + found := false + for isHexadecimal(ch) { + ch = s.next() + found = true + } + + if !found { + s.err("illegal hexadecimal number") + } + + if ch != eof { + s.unread() + } + + return token.NUMBER + } + + // now it's either something like: 0421(octal) or 0.1231(float) + illegalOctal := false + for isDecimal(ch) { + ch = s.next() + if ch == '8' || ch == '9' { + // this is just a possibility. For example 0159 is illegal, but + // 0159.23 is valid. So we mark a possible illegal octal. If + // the next character is not a period, we'll print the error. + illegalOctal = true + } + } + + if ch == 'e' || ch == 'E' { + ch = s.scanExponent(ch) + return token.FLOAT + } + + if ch == '.' { + ch = s.scanFraction(ch) + + if ch == 'e' || ch == 'E' { + ch = s.next() + ch = s.scanExponent(ch) + } + return token.FLOAT + } + + if illegalOctal { + s.err("illegal octal number") + } + + if ch != eof { + s.unread() + } + return token.NUMBER + } + + s.scanMantissa(ch) + ch = s.next() // seek forward + if ch == 'e' || ch == 'E' { + ch = s.scanExponent(ch) + return token.FLOAT + } + + if ch == '.' { + ch = s.scanFraction(ch) + if ch == 'e' || ch == 'E' { + ch = s.next() + ch = s.scanExponent(ch) + } + return token.FLOAT + } + + if ch != eof { + s.unread() + } + return token.NUMBER +} + +// scanMantissa scans the mantissa beginning from the rune. It returns the next +// non decimal rune. It's used to determine wheter it's a fraction or exponent. +func (s *Scanner) scanMantissa(ch rune) rune { + scanned := false + for isDecimal(ch) { + ch = s.next() + scanned = true + } + + if scanned && ch != eof { + s.unread() + } + return ch +} + +// scanFraction scans the fraction after the '.' rune +func (s *Scanner) scanFraction(ch rune) rune { + if ch == '.' { + ch = s.peek() // we peek just to see if we can move forward + ch = s.scanMantissa(ch) + } + return ch +} + +// scanExponent scans the remaining parts of an exponent after the 'e' or 'E' +// rune. +func (s *Scanner) scanExponent(ch rune) rune { + if ch == 'e' || ch == 'E' { + ch = s.next() + if ch == '-' || ch == '+' { + ch = s.next() + } + ch = s.scanMantissa(ch) + } + return ch +} + +// scanHeredoc scans a heredoc string +func (s *Scanner) scanHeredoc() { + // Scan the second '<' in example: '<= len(identBytes) && identRegexp.Match(s.src[lineStart:s.srcPos.Offset-s.lastCharLen]) { + break + } + + // Not an anchor match, record the start of a new line + lineStart = s.srcPos.Offset + } + + if ch == eof { + s.err("heredoc not terminated") + return + } + } + + return +} + +// scanString scans a quoted string +func (s *Scanner) scanString() { + braces := 0 + for { + // '"' opening already consumed + // read character after quote + ch := s.next() + + if (ch == '\n' && braces == 0) || ch < 0 || ch == eof { + s.err("literal not terminated") + return + } + + if ch == '"' && braces == 0 { + break + } + + // If we're going into a ${} then we can ignore quotes for awhile + if braces == 0 && ch == '$' && s.peek() == '{' { + braces++ + s.next() + } else if braces > 0 && ch == '{' { + braces++ + } + if braces > 0 && ch == '}' { + braces-- + } + + if ch == '\\' { + s.scanEscape() + } + } + + return +} + +// scanEscape scans an escape sequence +func (s *Scanner) scanEscape() rune { + // http://en.cppreference.com/w/cpp/language/escape + ch := s.next() // read character after '/' + switch ch { + case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': + // nothing to do + case '0', '1', '2', '3', '4', '5', '6', '7': + // octal notation + ch = s.scanDigits(ch, 8, 3) + case 'x': + // hexademical notation + ch = s.scanDigits(s.next(), 16, 2) + case 'u': + // universal character name + ch = s.scanDigits(s.next(), 16, 4) + case 'U': + // universal character name + ch = s.scanDigits(s.next(), 16, 8) + default: + s.err("illegal char escape") + } + return ch +} + +// scanDigits scans a rune with the given base for n times. For example an +// octal notation \184 would yield in scanDigits(ch, 8, 3) +func (s *Scanner) scanDigits(ch rune, base, n int) rune { + start := n + for n > 0 && digitVal(ch) < base { + ch = s.next() + if ch == eof { + // If we see an EOF, we halt any more scanning of digits + // immediately. + break + } + + n-- + } + if n > 0 { + s.err("illegal char escape") + } + + if n != start { + // we scanned all digits, put the last non digit char back, + // only if we read anything at all + s.unread() + } + + return ch +} + +// scanIdentifier scans an identifier and returns the literal string +func (s *Scanner) scanIdentifier() string { + offs := s.srcPos.Offset - s.lastCharLen + ch := s.next() + for isLetter(ch) || isDigit(ch) || ch == '-' || ch == '.' { + ch = s.next() + } + + if ch != eof { + s.unread() // we got identifier, put back latest char + } + + return string(s.src[offs:s.srcPos.Offset]) +} + +// recentPosition returns the position of the character immediately after the +// character or token returned by the last call to Scan. +func (s *Scanner) recentPosition() (pos token.Pos) { + pos.Offset = s.srcPos.Offset - s.lastCharLen + switch { + case s.srcPos.Column > 0: + // common case: last character was not a '\n' + pos.Line = s.srcPos.Line + pos.Column = s.srcPos.Column + case s.lastLineLen > 0: + // last character was a '\n' + // (we cannot be at the beginning of the source + // since we have called next() at least once) + pos.Line = s.srcPos.Line - 1 + pos.Column = s.lastLineLen + default: + // at the beginning of the source + pos.Line = 1 + pos.Column = 1 + } + return +} + +// err prints the error of any scanning to s.Error function. If the function is +// not defined, by default it prints them to os.Stderr +func (s *Scanner) err(msg string) { + s.ErrorCount++ + pos := s.recentPosition() + + if s.Error != nil { + s.Error(pos, msg) + return + } + + fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) +} + +// isHexadecimal returns true if the given rune is a letter +func isLetter(ch rune) bool { + return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) +} + +// isDigit returns true if the given rune is a decimal digit +func isDigit(ch rune) bool { + return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) +} + +// isDecimal returns true if the given rune is a decimal number +func isDecimal(ch rune) bool { + return '0' <= ch && ch <= '9' +} + +// isHexadecimal returns true if the given rune is an hexadecimal number +func isHexadecimal(ch rune) bool { + return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' +} + +// isWhitespace returns true if the rune is a space, tab, newline or carriage return +func isWhitespace(ch rune) bool { + return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' +} + +// digitVal returns the integer value of a given octal,decimal or hexadecimal rune +func digitVal(ch rune) int { + switch { + case '0' <= ch && ch <= '9': + return int(ch - '0') + case 'a' <= ch && ch <= 'f': + return int(ch - 'a' + 10) + case 'A' <= ch && ch <= 'F': + return int(ch - 'A' + 10) + } + return 16 // larger than any legal digit val +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go b/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go new file mode 100644 index 000000000..5f981eaa2 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go @@ -0,0 +1,241 @@ +package strconv + +import ( + "errors" + "unicode/utf8" +) + +// ErrSyntax indicates that a value does not have the right syntax for the target type. +var ErrSyntax = errors.New("invalid syntax") + +// Unquote interprets s as a single-quoted, double-quoted, +// or backquoted Go string literal, returning the string value +// that s quotes. (If s is single-quoted, it would be a Go +// character literal; Unquote returns the corresponding +// one-character string.) +func Unquote(s string) (t string, err error) { + n := len(s) + if n < 2 { + return "", ErrSyntax + } + quote := s[0] + if quote != s[n-1] { + return "", ErrSyntax + } + s = s[1 : n-1] + + if quote != '"' { + return "", ErrSyntax + } + if !contains(s, '$') && !contains(s, '{') && contains(s, '\n') { + return "", ErrSyntax + } + + // Is it trivial? Avoid allocation. + if !contains(s, '\\') && !contains(s, quote) && !contains(s, '$') { + switch quote { + case '"': + return s, nil + case '\'': + r, size := utf8.DecodeRuneInString(s) + if size == len(s) && (r != utf8.RuneError || size != 1) { + return s, nil + } + } + } + + var runeTmp [utf8.UTFMax]byte + buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations. + for len(s) > 0 { + // If we're starting a '${}' then let it through un-unquoted. + // Specifically: we don't unquote any characters within the `${}` + // section. + if s[0] == '$' && len(s) > 1 && s[1] == '{' { + buf = append(buf, '$', '{') + s = s[2:] + + // Continue reading until we find the closing brace, copying as-is + braces := 1 + for len(s) > 0 && braces > 0 { + r, size := utf8.DecodeRuneInString(s) + if r == utf8.RuneError { + return "", ErrSyntax + } + + s = s[size:] + + n := utf8.EncodeRune(runeTmp[:], r) + buf = append(buf, runeTmp[:n]...) + + switch r { + case '{': + braces++ + case '}': + braces-- + } + } + if braces != 0 { + return "", ErrSyntax + } + if len(s) == 0 { + // If there's no string left, we're done! + break + } else { + // If there's more left, we need to pop back up to the top of the loop + // in case there's another interpolation in this string. + continue + } + } + + if s[0] == '\n' { + return "", ErrSyntax + } + + c, multibyte, ss, err := unquoteChar(s, quote) + if err != nil { + return "", err + } + s = ss + if c < utf8.RuneSelf || !multibyte { + buf = append(buf, byte(c)) + } else { + n := utf8.EncodeRune(runeTmp[:], c) + buf = append(buf, runeTmp[:n]...) + } + if quote == '\'' && len(s) != 0 { + // single-quoted must be single character + return "", ErrSyntax + } + } + return string(buf), nil +} + +// contains reports whether the string contains the byte c. +func contains(s string, c byte) bool { + for i := 0; i < len(s); i++ { + if s[i] == c { + return true + } + } + return false +} + +func unhex(b byte) (v rune, ok bool) { + c := rune(b) + switch { + case '0' <= c && c <= '9': + return c - '0', true + case 'a' <= c && c <= 'f': + return c - 'a' + 10, true + case 'A' <= c && c <= 'F': + return c - 'A' + 10, true + } + return +} + +func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { + // easy cases + switch c := s[0]; { + case c == quote && (quote == '\'' || quote == '"'): + err = ErrSyntax + return + case c >= utf8.RuneSelf: + r, size := utf8.DecodeRuneInString(s) + return r, true, s[size:], nil + case c != '\\': + return rune(s[0]), false, s[1:], nil + } + + // hard case: c is backslash + if len(s) <= 1 { + err = ErrSyntax + return + } + c := s[1] + s = s[2:] + + switch c { + case 'a': + value = '\a' + case 'b': + value = '\b' + case 'f': + value = '\f' + case 'n': + value = '\n' + case 'r': + value = '\r' + case 't': + value = '\t' + case 'v': + value = '\v' + case 'x', 'u', 'U': + n := 0 + switch c { + case 'x': + n = 2 + case 'u': + n = 4 + case 'U': + n = 8 + } + var v rune + if len(s) < n { + err = ErrSyntax + return + } + for j := 0; j < n; j++ { + x, ok := unhex(s[j]) + if !ok { + err = ErrSyntax + return + } + v = v<<4 | x + } + s = s[n:] + if c == 'x' { + // single-byte string, possibly not UTF-8 + value = v + break + } + if v > utf8.MaxRune { + err = ErrSyntax + return + } + value = v + multibyte = true + case '0', '1', '2', '3', '4', '5', '6', '7': + v := rune(c) - '0' + if len(s) < 2 { + err = ErrSyntax + return + } + for j := 0; j < 2; j++ { // one digit already; two more + x := rune(s[j]) - '0' + if x < 0 || x > 7 { + err = ErrSyntax + return + } + v = (v << 3) | x + } + s = s[2:] + if v > 255 { + err = ErrSyntax + return + } + value = v + case '\\': + value = '\\' + case '\'', '"': + if c != quote { + err = ErrSyntax + return + } + value = rune(c) + default: + err = ErrSyntax + return + } + tail = s + return +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/position.go b/vendor/github.com/hashicorp/hcl/hcl/token/position.go new file mode 100644 index 000000000..59c1bb72d --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/token/position.go @@ -0,0 +1,46 @@ +package token + +import "fmt" + +// Pos describes an arbitrary source position +// including the file, line, and column location. +// A Position is valid if the line number is > 0. +type Pos struct { + Filename string // filename, if any + Offset int // offset, starting at 0 + Line int // line number, starting at 1 + Column int // column number, starting at 1 (character count) +} + +// IsValid returns true if the position is valid. +func (p *Pos) IsValid() bool { return p.Line > 0 } + +// String returns a string in one of several forms: +// +// file:line:column valid position with file name +// line:column valid position without file name +// file invalid position with file name +// - invalid position without file name +func (p Pos) String() string { + s := p.Filename + if p.IsValid() { + if s != "" { + s += ":" + } + s += fmt.Sprintf("%d:%d", p.Line, p.Column) + } + if s == "" { + s = "-" + } + return s +} + +// Before reports whether the position p is before u. +func (p Pos) Before(u Pos) bool { + return u.Offset > p.Offset || u.Line > p.Line +} + +// After reports whether the position p is after u. +func (p Pos) After(u Pos) bool { + return u.Offset < p.Offset || u.Line < p.Line +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/token.go b/vendor/github.com/hashicorp/hcl/hcl/token/token.go new file mode 100644 index 000000000..e37c0664e --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/hcl/token/token.go @@ -0,0 +1,219 @@ +// Package token defines constants representing the lexical tokens for HCL +// (HashiCorp Configuration Language) +package token + +import ( + "fmt" + "strconv" + "strings" + + hclstrconv "github.com/hashicorp/hcl/hcl/strconv" +) + +// Token defines a single HCL token which can be obtained via the Scanner +type Token struct { + Type Type + Pos Pos + Text string + JSON bool +} + +// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) +type Type int + +const ( + // Special tokens + ILLEGAL Type = iota + EOF + COMMENT + + identifier_beg + IDENT // literals + literal_beg + NUMBER // 12345 + FLOAT // 123.45 + BOOL // true,false + STRING // "abc" + HEREDOC // < 0 { + // Pop the current item + n := len(frontier) + item := frontier[n-1] + frontier = frontier[:n-1] + + switch v := item.Val.(type) { + case *ast.ObjectType: + items, frontier = flattenObjectType(v, item, items, frontier) + case *ast.ListType: + items, frontier = flattenListType(v, item, items, frontier) + default: + items = append(items, item) + } + } + + // Reverse the list since the frontier model runs things backwards + for i := len(items)/2 - 1; i >= 0; i-- { + opp := len(items) - 1 - i + items[i], items[opp] = items[opp], items[i] + } + + // Done! Set the original items + list.Items = items + return n, true + }) +} + +func flattenListType( + ot *ast.ListType, + item *ast.ObjectItem, + items []*ast.ObjectItem, + frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { + // If the list is empty, keep the original list + if len(ot.List) == 0 { + items = append(items, item) + return items, frontier + } + + // All the elements of this object must also be objects! + for _, subitem := range ot.List { + if _, ok := subitem.(*ast.ObjectType); !ok { + items = append(items, item) + return items, frontier + } + } + + // Great! We have a match go through all the items and flatten + for _, elem := range ot.List { + // Add it to the frontier so that we can recurse + frontier = append(frontier, &ast.ObjectItem{ + Keys: item.Keys, + Assign: item.Assign, + Val: elem, + LeadComment: item.LeadComment, + LineComment: item.LineComment, + }) + } + + return items, frontier +} + +func flattenObjectType( + ot *ast.ObjectType, + item *ast.ObjectItem, + items []*ast.ObjectItem, + frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { + // If the list has no items we do not have to flatten anything + if ot.List.Items == nil { + items = append(items, item) + return items, frontier + } + + // All the elements of this object must also be objects! + for _, subitem := range ot.List.Items { + if _, ok := subitem.Val.(*ast.ObjectType); !ok { + items = append(items, item) + return items, frontier + } + } + + // Great! We have a match go through all the items and flatten + for _, subitem := range ot.List.Items { + // Copy the new key + keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys)) + copy(keys, item.Keys) + copy(keys[len(item.Keys):], subitem.Keys) + + // Add it to the frontier so that we can recurse + frontier = append(frontier, &ast.ObjectItem{ + Keys: keys, + Assign: item.Assign, + Val: subitem.Val, + LeadComment: item.LeadComment, + LineComment: item.LineComment, + }) + } + + return items, frontier +} diff --git a/vendor/github.com/hashicorp/hcl/json/parser/parser.go b/vendor/github.com/hashicorp/hcl/json/parser/parser.go new file mode 100644 index 000000000..125a5f072 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/json/parser/parser.go @@ -0,0 +1,313 @@ +package parser + +import ( + "errors" + "fmt" + + "github.com/hashicorp/hcl/hcl/ast" + hcltoken "github.com/hashicorp/hcl/hcl/token" + "github.com/hashicorp/hcl/json/scanner" + "github.com/hashicorp/hcl/json/token" +) + +type Parser struct { + sc *scanner.Scanner + + // Last read token + tok token.Token + commaPrev token.Token + + enableTrace bool + indent int + n int // buffer size (max = 1) +} + +func newParser(src []byte) *Parser { + return &Parser{ + sc: scanner.New(src), + } +} + +// Parse returns the fully parsed source and returns the abstract syntax tree. +func Parse(src []byte) (*ast.File, error) { + p := newParser(src) + return p.Parse() +} + +var errEofToken = errors.New("EOF token found") + +// Parse returns the fully parsed source and returns the abstract syntax tree. +func (p *Parser) Parse() (*ast.File, error) { + f := &ast.File{} + var err, scerr error + p.sc.Error = func(pos token.Pos, msg string) { + scerr = fmt.Errorf("%s: %s", pos, msg) + } + + // The root must be an object in JSON + object, err := p.object() + if scerr != nil { + return nil, scerr + } + if err != nil { + return nil, err + } + + // We make our final node an object list so it is more HCL compatible + f.Node = object.List + + // Flatten it, which finds patterns and turns them into more HCL-like + // AST trees. + flattenObjects(f.Node) + + return f, nil +} + +func (p *Parser) objectList() (*ast.ObjectList, error) { + defer un(trace(p, "ParseObjectList")) + node := &ast.ObjectList{} + + for { + n, err := p.objectItem() + if err == errEofToken { + break // we are finished + } + + // we don't return a nil node, because might want to use already + // collected items. + if err != nil { + return node, err + } + + node.Add(n) + + // Check for a followup comma. If it isn't a comma, then we're done + if tok := p.scan(); tok.Type != token.COMMA { + break + } + } + + return node, nil +} + +// objectItem parses a single object item +func (p *Parser) objectItem() (*ast.ObjectItem, error) { + defer un(trace(p, "ParseObjectItem")) + + keys, err := p.objectKey() + if err != nil { + return nil, err + } + + o := &ast.ObjectItem{ + Keys: keys, + } + + switch p.tok.Type { + case token.COLON: + pos := p.tok.Pos + o.Assign = hcltoken.Pos{ + Filename: pos.Filename, + Offset: pos.Offset, + Line: pos.Line, + Column: pos.Column, + } + + o.Val, err = p.objectValue() + if err != nil { + return nil, err + } + } + + return o, nil +} + +// objectKey parses an object key and returns a ObjectKey AST +func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { + keyCount := 0 + keys := make([]*ast.ObjectKey, 0) + + for { + tok := p.scan() + switch tok.Type { + case token.EOF: + return nil, errEofToken + case token.STRING: + keyCount++ + keys = append(keys, &ast.ObjectKey{ + Token: p.tok.HCLToken(), + }) + case token.COLON: + // If we have a zero keycount it means that we never got + // an object key, i.e. `{ :`. This is a syntax error. + if keyCount == 0 { + return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) + } + + // Done + return keys, nil + case token.ILLEGAL: + return nil, errors.New("illegal") + default: + return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) + } + } +} + +// object parses any type of object, such as number, bool, string, object or +// list. +func (p *Parser) objectValue() (ast.Node, error) { + defer un(trace(p, "ParseObjectValue")) + tok := p.scan() + + switch tok.Type { + case token.NUMBER, token.FLOAT, token.BOOL, token.NULL, token.STRING: + return p.literalType() + case token.LBRACE: + return p.objectType() + case token.LBRACK: + return p.listType() + case token.EOF: + return nil, errEofToken + } + + return nil, fmt.Errorf("Expected object value, got unknown token: %+v", tok) +} + +// object parses any type of object, such as number, bool, string, object or +// list. +func (p *Parser) object() (*ast.ObjectType, error) { + defer un(trace(p, "ParseType")) + tok := p.scan() + + switch tok.Type { + case token.LBRACE: + return p.objectType() + case token.EOF: + return nil, errEofToken + } + + return nil, fmt.Errorf("Expected object, got unknown token: %+v", tok) +} + +// objectType parses an object type and returns a ObjectType AST +func (p *Parser) objectType() (*ast.ObjectType, error) { + defer un(trace(p, "ParseObjectType")) + + // we assume that the currently scanned token is a LBRACE + o := &ast.ObjectType{} + + l, err := p.objectList() + + // if we hit RBRACE, we are good to go (means we parsed all Items), if it's + // not a RBRACE, it's an syntax error and we just return it. + if err != nil && p.tok.Type != token.RBRACE { + return nil, err + } + + o.List = l + return o, nil +} + +// listType parses a list type and returns a ListType AST +func (p *Parser) listType() (*ast.ListType, error) { + defer un(trace(p, "ParseListType")) + + // we assume that the currently scanned token is a LBRACK + l := &ast.ListType{} + + for { + tok := p.scan() + switch tok.Type { + case token.NUMBER, token.FLOAT, token.STRING: + node, err := p.literalType() + if err != nil { + return nil, err + } + + l.Add(node) + case token.COMMA: + continue + case token.LBRACE: + node, err := p.objectType() + if err != nil { + return nil, err + } + + l.Add(node) + case token.BOOL: + // TODO(arslan) should we support? not supported by HCL yet + case token.LBRACK: + // TODO(arslan) should we support nested lists? Even though it's + // written in README of HCL, it's not a part of the grammar + // (not defined in parse.y) + case token.RBRACK: + // finished + return l, nil + default: + return nil, fmt.Errorf("unexpected token while parsing list: %s", tok.Type) + } + + } +} + +// literalType parses a literal type and returns a LiteralType AST +func (p *Parser) literalType() (*ast.LiteralType, error) { + defer un(trace(p, "ParseLiteral")) + + return &ast.LiteralType{ + Token: p.tok.HCLToken(), + }, nil +} + +// scan returns the next token from the underlying scanner. If a token has +// been unscanned then read that instead. +func (p *Parser) scan() token.Token { + // If we have a token on the buffer, then return it. + if p.n != 0 { + p.n = 0 + return p.tok + } + + p.tok = p.sc.Scan() + return p.tok +} + +// unscan pushes the previously read token back onto the buffer. +func (p *Parser) unscan() { + p.n = 1 +} + +// ---------------------------------------------------------------------------- +// Parsing support + +func (p *Parser) printTrace(a ...interface{}) { + if !p.enableTrace { + return + } + + const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + const n = len(dots) + fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) + + i := 2 * p.indent + for i > n { + fmt.Print(dots) + i -= n + } + // i <= n + fmt.Print(dots[0:i]) + fmt.Println(a...) +} + +func trace(p *Parser, msg string) *Parser { + p.printTrace(msg, "(") + p.indent++ + return p +} + +// Usage pattern: defer un(trace(p, "...")) +func un(p *Parser) { + p.indent-- + p.printTrace(")") +} diff --git a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go new file mode 100644 index 000000000..fe3f0f095 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go @@ -0,0 +1,451 @@ +package scanner + +import ( + "bytes" + "fmt" + "os" + "unicode" + "unicode/utf8" + + "github.com/hashicorp/hcl/json/token" +) + +// eof represents a marker rune for the end of the reader. +const eof = rune(0) + +// Scanner defines a lexical scanner +type Scanner struct { + buf *bytes.Buffer // Source buffer for advancing and scanning + src []byte // Source buffer for immutable access + + // Source Position + srcPos token.Pos // current position + prevPos token.Pos // previous position, used for peek() method + + lastCharLen int // length of last character in bytes + lastLineLen int // length of last line in characters (for correct column reporting) + + tokStart int // token text start position + tokEnd int // token text end position + + // Error is called for each error encountered. If no Error + // function is set, the error is reported to os.Stderr. + Error func(pos token.Pos, msg string) + + // ErrorCount is incremented by one for each error encountered. + ErrorCount int + + // tokPos is the start position of most recently scanned token; set by + // Scan. The Filename field is always left untouched by the Scanner. If + // an error is reported (via Error) and Position is invalid, the scanner is + // not inside a token. + tokPos token.Pos +} + +// New creates and initializes a new instance of Scanner using src as +// its source content. +func New(src []byte) *Scanner { + // even though we accept a src, we read from a io.Reader compatible type + // (*bytes.Buffer). So in the future we might easily change it to streaming + // read. + b := bytes.NewBuffer(src) + s := &Scanner{ + buf: b, + src: src, + } + + // srcPosition always starts with 1 + s.srcPos.Line = 1 + return s +} + +// next reads the next rune from the bufferred reader. Returns the rune(0) if +// an error occurs (or io.EOF is returned). +func (s *Scanner) next() rune { + ch, size, err := s.buf.ReadRune() + if err != nil { + // advance for error reporting + s.srcPos.Column++ + s.srcPos.Offset += size + s.lastCharLen = size + return eof + } + + if ch == utf8.RuneError && size == 1 { + s.srcPos.Column++ + s.srcPos.Offset += size + s.lastCharLen = size + s.err("illegal UTF-8 encoding") + return ch + } + + // remember last position + s.prevPos = s.srcPos + + s.srcPos.Column++ + s.lastCharLen = size + s.srcPos.Offset += size + + if ch == '\n' { + s.srcPos.Line++ + s.lastLineLen = s.srcPos.Column + s.srcPos.Column = 0 + } + + // debug + // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) + return ch +} + +// unread unreads the previous read Rune and updates the source position +func (s *Scanner) unread() { + if err := s.buf.UnreadRune(); err != nil { + panic(err) // this is user fault, we should catch it + } + s.srcPos = s.prevPos // put back last position +} + +// peek returns the next rune without advancing the reader. +func (s *Scanner) peek() rune { + peek, _, err := s.buf.ReadRune() + if err != nil { + return eof + } + + s.buf.UnreadRune() + return peek +} + +// Scan scans the next token and returns the token. +func (s *Scanner) Scan() token.Token { + ch := s.next() + + // skip white space + for isWhitespace(ch) { + ch = s.next() + } + + var tok token.Type + + // token text markings + s.tokStart = s.srcPos.Offset - s.lastCharLen + + // token position, initial next() is moving the offset by one(size of rune + // actually), though we are interested with the starting point + s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen + if s.srcPos.Column > 0 { + // common case: last character was not a '\n' + s.tokPos.Line = s.srcPos.Line + s.tokPos.Column = s.srcPos.Column + } else { + // last character was a '\n' + // (we cannot be at the beginning of the source + // since we have called next() at least once) + s.tokPos.Line = s.srcPos.Line - 1 + s.tokPos.Column = s.lastLineLen + } + + switch { + case isLetter(ch): + lit := s.scanIdentifier() + if lit == "true" || lit == "false" { + tok = token.BOOL + } else if lit == "null" { + tok = token.NULL + } else { + s.err("illegal char") + } + case isDecimal(ch): + tok = s.scanNumber(ch) + default: + switch ch { + case eof: + tok = token.EOF + case '"': + tok = token.STRING + s.scanString() + case '.': + tok = token.PERIOD + ch = s.peek() + if isDecimal(ch) { + tok = token.FLOAT + ch = s.scanMantissa(ch) + ch = s.scanExponent(ch) + } + case '[': + tok = token.LBRACK + case ']': + tok = token.RBRACK + case '{': + tok = token.LBRACE + case '}': + tok = token.RBRACE + case ',': + tok = token.COMMA + case ':': + tok = token.COLON + case '-': + if isDecimal(s.peek()) { + ch := s.next() + tok = s.scanNumber(ch) + } else { + s.err("illegal char") + } + default: + s.err("illegal char: " + string(ch)) + } + } + + // finish token ending + s.tokEnd = s.srcPos.Offset + + // create token literal + var tokenText string + if s.tokStart >= 0 { + tokenText = string(s.src[s.tokStart:s.tokEnd]) + } + s.tokStart = s.tokEnd // ensure idempotency of tokenText() call + + return token.Token{ + Type: tok, + Pos: s.tokPos, + Text: tokenText, + } +} + +// scanNumber scans a HCL number definition starting with the given rune +func (s *Scanner) scanNumber(ch rune) token.Type { + zero := ch == '0' + pos := s.srcPos + + s.scanMantissa(ch) + ch = s.next() // seek forward + if ch == 'e' || ch == 'E' { + ch = s.scanExponent(ch) + return token.FLOAT + } + + if ch == '.' { + ch = s.scanFraction(ch) + if ch == 'e' || ch == 'E' { + ch = s.next() + ch = s.scanExponent(ch) + } + return token.FLOAT + } + + if ch != eof { + s.unread() + } + + // If we have a larger number and this is zero, error + if zero && pos != s.srcPos { + s.err("numbers cannot start with 0") + } + + return token.NUMBER +} + +// scanMantissa scans the mantissa beginning from the rune. It returns the next +// non decimal rune. It's used to determine wheter it's a fraction or exponent. +func (s *Scanner) scanMantissa(ch rune) rune { + scanned := false + for isDecimal(ch) { + ch = s.next() + scanned = true + } + + if scanned && ch != eof { + s.unread() + } + return ch +} + +// scanFraction scans the fraction after the '.' rune +func (s *Scanner) scanFraction(ch rune) rune { + if ch == '.' { + ch = s.peek() // we peek just to see if we can move forward + ch = s.scanMantissa(ch) + } + return ch +} + +// scanExponent scans the remaining parts of an exponent after the 'e' or 'E' +// rune. +func (s *Scanner) scanExponent(ch rune) rune { + if ch == 'e' || ch == 'E' { + ch = s.next() + if ch == '-' || ch == '+' { + ch = s.next() + } + ch = s.scanMantissa(ch) + } + return ch +} + +// scanString scans a quoted string +func (s *Scanner) scanString() { + braces := 0 + for { + // '"' opening already consumed + // read character after quote + ch := s.next() + + if ch == '\n' || ch < 0 || ch == eof { + s.err("literal not terminated") + return + } + + if ch == '"' { + break + } + + // If we're going into a ${} then we can ignore quotes for awhile + if braces == 0 && ch == '$' && s.peek() == '{' { + braces++ + s.next() + } else if braces > 0 && ch == '{' { + braces++ + } + if braces > 0 && ch == '}' { + braces-- + } + + if ch == '\\' { + s.scanEscape() + } + } + + return +} + +// scanEscape scans an escape sequence +func (s *Scanner) scanEscape() rune { + // http://en.cppreference.com/w/cpp/language/escape + ch := s.next() // read character after '/' + switch ch { + case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': + // nothing to do + case '0', '1', '2', '3', '4', '5', '6', '7': + // octal notation + ch = s.scanDigits(ch, 8, 3) + case 'x': + // hexademical notation + ch = s.scanDigits(s.next(), 16, 2) + case 'u': + // universal character name + ch = s.scanDigits(s.next(), 16, 4) + case 'U': + // universal character name + ch = s.scanDigits(s.next(), 16, 8) + default: + s.err("illegal char escape") + } + return ch +} + +// scanDigits scans a rune with the given base for n times. For example an +// octal notation \184 would yield in scanDigits(ch, 8, 3) +func (s *Scanner) scanDigits(ch rune, base, n int) rune { + for n > 0 && digitVal(ch) < base { + ch = s.next() + n-- + } + if n > 0 { + s.err("illegal char escape") + } + + // we scanned all digits, put the last non digit char back + s.unread() + return ch +} + +// scanIdentifier scans an identifier and returns the literal string +func (s *Scanner) scanIdentifier() string { + offs := s.srcPos.Offset - s.lastCharLen + ch := s.next() + for isLetter(ch) || isDigit(ch) || ch == '-' { + ch = s.next() + } + + if ch != eof { + s.unread() // we got identifier, put back latest char + } + + return string(s.src[offs:s.srcPos.Offset]) +} + +// recentPosition returns the position of the character immediately after the +// character or token returned by the last call to Scan. +func (s *Scanner) recentPosition() (pos token.Pos) { + pos.Offset = s.srcPos.Offset - s.lastCharLen + switch { + case s.srcPos.Column > 0: + // common case: last character was not a '\n' + pos.Line = s.srcPos.Line + pos.Column = s.srcPos.Column + case s.lastLineLen > 0: + // last character was a '\n' + // (we cannot be at the beginning of the source + // since we have called next() at least once) + pos.Line = s.srcPos.Line - 1 + pos.Column = s.lastLineLen + default: + // at the beginning of the source + pos.Line = 1 + pos.Column = 1 + } + return +} + +// err prints the error of any scanning to s.Error function. If the function is +// not defined, by default it prints them to os.Stderr +func (s *Scanner) err(msg string) { + s.ErrorCount++ + pos := s.recentPosition() + + if s.Error != nil { + s.Error(pos, msg) + return + } + + fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) +} + +// isHexadecimal returns true if the given rune is a letter +func isLetter(ch rune) bool { + return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) +} + +// isHexadecimal returns true if the given rune is a decimal digit +func isDigit(ch rune) bool { + return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) +} + +// isHexadecimal returns true if the given rune is a decimal number +func isDecimal(ch rune) bool { + return '0' <= ch && ch <= '9' +} + +// isHexadecimal returns true if the given rune is an hexadecimal number +func isHexadecimal(ch rune) bool { + return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' +} + +// isWhitespace returns true if the rune is a space, tab, newline or carriage return +func isWhitespace(ch rune) bool { + return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' +} + +// digitVal returns the integer value of a given octal,decimal or hexadecimal rune +func digitVal(ch rune) int { + switch { + case '0' <= ch && ch <= '9': + return int(ch - '0') + case 'a' <= ch && ch <= 'f': + return int(ch - 'a' + 10) + case 'A' <= ch && ch <= 'F': + return int(ch - 'A' + 10) + } + return 16 // larger than any legal digit val +} diff --git a/vendor/github.com/hashicorp/hcl/json/token/position.go b/vendor/github.com/hashicorp/hcl/json/token/position.go new file mode 100644 index 000000000..59c1bb72d --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/json/token/position.go @@ -0,0 +1,46 @@ +package token + +import "fmt" + +// Pos describes an arbitrary source position +// including the file, line, and column location. +// A Position is valid if the line number is > 0. +type Pos struct { + Filename string // filename, if any + Offset int // offset, starting at 0 + Line int // line number, starting at 1 + Column int // column number, starting at 1 (character count) +} + +// IsValid returns true if the position is valid. +func (p *Pos) IsValid() bool { return p.Line > 0 } + +// String returns a string in one of several forms: +// +// file:line:column valid position with file name +// line:column valid position without file name +// file invalid position with file name +// - invalid position without file name +func (p Pos) String() string { + s := p.Filename + if p.IsValid() { + if s != "" { + s += ":" + } + s += fmt.Sprintf("%d:%d", p.Line, p.Column) + } + if s == "" { + s = "-" + } + return s +} + +// Before reports whether the position p is before u. +func (p Pos) Before(u Pos) bool { + return u.Offset > p.Offset || u.Line > p.Line +} + +// After reports whether the position p is after u. +func (p Pos) After(u Pos) bool { + return u.Offset < p.Offset || u.Line < p.Line +} diff --git a/vendor/github.com/hashicorp/hcl/json/token/token.go b/vendor/github.com/hashicorp/hcl/json/token/token.go new file mode 100644 index 000000000..95a0c3eee --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/json/token/token.go @@ -0,0 +1,118 @@ +package token + +import ( + "fmt" + "strconv" + + hcltoken "github.com/hashicorp/hcl/hcl/token" +) + +// Token defines a single HCL token which can be obtained via the Scanner +type Token struct { + Type Type + Pos Pos + Text string +} + +// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) +type Type int + +const ( + // Special tokens + ILLEGAL Type = iota + EOF + + identifier_beg + literal_beg + NUMBER // 12345 + FLOAT // 123.45 + BOOL // true,false + STRING // "abc" + NULL // null + literal_end + identifier_end + + operator_beg + LBRACK // [ + LBRACE // { + COMMA // , + PERIOD // . + COLON // : + + RBRACK // ] + RBRACE // } + + operator_end +) + +var tokens = [...]string{ + ILLEGAL: "ILLEGAL", + + EOF: "EOF", + + NUMBER: "NUMBER", + FLOAT: "FLOAT", + BOOL: "BOOL", + STRING: "STRING", + NULL: "NULL", + + LBRACK: "LBRACK", + LBRACE: "LBRACE", + COMMA: "COMMA", + PERIOD: "PERIOD", + COLON: "COLON", + + RBRACK: "RBRACK", + RBRACE: "RBRACE", +} + +// String returns the string corresponding to the token tok. +func (t Type) String() string { + s := "" + if 0 <= t && t < Type(len(tokens)) { + s = tokens[t] + } + if s == "" { + s = "token(" + strconv.Itoa(int(t)) + ")" + } + return s +} + +// IsIdentifier returns true for tokens corresponding to identifiers and basic +// type literals; it returns false otherwise. +func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end } + +// IsLiteral returns true for tokens corresponding to basic type literals; it +// returns false otherwise. +func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end } + +// IsOperator returns true for tokens corresponding to operators and +// delimiters; it returns false otherwise. +func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end } + +// String returns the token's literal text. Note that this is only +// applicable for certain token types, such as token.IDENT, +// token.STRING, etc.. +func (t Token) String() string { + return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text) +} + +// HCLToken converts this token to an HCL token. +// +// The token type must be a literal type or this will panic. +func (t Token) HCLToken() hcltoken.Token { + switch t.Type { + case BOOL: + return hcltoken.Token{Type: hcltoken.BOOL, Text: t.Text} + case FLOAT: + return hcltoken.Token{Type: hcltoken.FLOAT, Text: t.Text} + case NULL: + return hcltoken.Token{Type: hcltoken.STRING, Text: ""} + case NUMBER: + return hcltoken.Token{Type: hcltoken.NUMBER, Text: t.Text} + case STRING: + return hcltoken.Token{Type: hcltoken.STRING, Text: t.Text, JSON: true} + default: + panic(fmt.Sprintf("unimplemented HCLToken for type: %s", t.Type)) + } +} diff --git a/vendor/github.com/hashicorp/hcl/lex.go b/vendor/github.com/hashicorp/hcl/lex.go new file mode 100644 index 000000000..d9993c292 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/lex.go @@ -0,0 +1,38 @@ +package hcl + +import ( + "unicode" + "unicode/utf8" +) + +type lexModeValue byte + +const ( + lexModeUnknown lexModeValue = iota + lexModeHcl + lexModeJson +) + +// lexMode returns whether we're going to be parsing in JSON +// mode or HCL mode. +func lexMode(v []byte) lexModeValue { + var ( + r rune + w int + offset int + ) + + for { + r, w = utf8.DecodeRune(v[offset:]) + offset += w + if unicode.IsSpace(r) { + continue + } + if r == '{' { + return lexModeJson + } + break + } + + return lexModeHcl +} diff --git a/vendor/github.com/hashicorp/hcl/parse.go b/vendor/github.com/hashicorp/hcl/parse.go new file mode 100644 index 000000000..1fca53c4c --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/parse.go @@ -0,0 +1,39 @@ +package hcl + +import ( + "fmt" + + "github.com/hashicorp/hcl/hcl/ast" + hclParser "github.com/hashicorp/hcl/hcl/parser" + jsonParser "github.com/hashicorp/hcl/json/parser" +) + +// ParseBytes accepts as input byte slice and returns ast tree. +// +// Input can be either JSON or HCL +func ParseBytes(in []byte) (*ast.File, error) { + return parse(in) +} + +// ParseString accepts input as a string and returns ast tree. +func ParseString(input string) (*ast.File, error) { + return parse([]byte(input)) +} + +func parse(in []byte) (*ast.File, error) { + switch lexMode(in) { + case lexModeHcl: + return hclParser.Parse(in) + case lexModeJson: + return jsonParser.Parse(in) + } + + return nil, fmt.Errorf("unknown config format") +} + +// Parse parses the given input and returns the root object. +// +// The input format can be either HCL or JSON. +func Parse(input string) (*ast.File, error) { + return parse([]byte(input)) +} diff --git a/vendor/github.com/howeyc/gopass/.travis.yml b/vendor/github.com/howeyc/gopass/.travis.yml new file mode 100644 index 000000000..cc5d509fd --- /dev/null +++ b/vendor/github.com/howeyc/gopass/.travis.yml @@ -0,0 +1,11 @@ +language: go + +os: + - linux + - osx + +go: + - 1.3 + - 1.4 + - 1.5 + - tip diff --git a/vendor/github.com/howeyc/gopass/LICENSE.txt b/vendor/github.com/howeyc/gopass/LICENSE.txt new file mode 100644 index 000000000..14f74708a --- /dev/null +++ b/vendor/github.com/howeyc/gopass/LICENSE.txt @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2012 Chris Howey + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE b/vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE new file mode 100644 index 000000000..da23621dc --- /dev/null +++ b/vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE @@ -0,0 +1,384 @@ +Unless otherwise noted, all files in this distribution are released +under the Common Development and Distribution License (CDDL). +Exceptions are noted within the associated source files. + +-------------------------------------------------------------------- + + +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0 + +1. Definitions. + + 1.1. "Contributor" means each individual or entity that creates + or contributes to the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Software, prior Modifications used by a Contributor (if any), + and the Modifications made by that particular Contributor. + + 1.3. "Covered Software" means (a) the Original Software, or (b) + Modifications, or (c) the combination of files containing + Original Software with files containing Modifications, in + each case including portions thereof. + + 1.4. "Executable" means the Covered Software in any form other + than Source Code. + + 1.5. "Initial Developer" means the individual or entity that first + makes Original Software available under this License. + + 1.6. "Larger Work" means a work which combines Covered Software or + portions thereof with code not governed by the terms of this + License. + + 1.7. "License" means this document. + + 1.8. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed + herein. + + 1.9. "Modifications" means the Source Code and Executable form of + any of the following: + + A. Any file that results from an addition to, deletion from or + modification of the contents of a file containing Original + Software or previous Modifications; + + B. Any new file that contains any part of the Original + Software or previous Modifications; or + + C. Any new file that is contributed or otherwise made + available under the terms of this License. + + 1.10. "Original Software" means the Source Code and Executable + form of computer software code that is originally released + under this License. + + 1.11. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, + process, and apparatus claims, in any patent Licensable by + grantor. + + 1.12. "Source Code" means (a) the common form of computer software + code in which modifications are made and (b) associated + documentation included in or with such code. + + 1.13. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms + of, this License. For legal entities, "You" includes any + entity which controls, is controlled by, or is under common + control with You. For purposes of this definition, + "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty + percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and + subject to third party intellectual property claims, the Initial + Developer hereby grants You a world-wide, royalty-free, + non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer, to use, + reproduce, modify, display, perform, sublicense and + distribute the Original Software (or portions thereof), + with or without Modifications, and/or as part of a Larger + Work; and + + (b) under Patent Claims infringed by the making, using or + selling of Original Software, to make, have made, use, + practice, sell, and offer for sale, and/or otherwise + dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are + effective on the date Initial Developer first distributes + or otherwise makes the Original Software available to a + third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: (1) for code that You delete from the Original + Software, or (2) for infringements caused by: (i) the + modification of the Original Software, or (ii) the + combination of the Original Software with other software + or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and + subject to third party intellectual property claims, each + Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor to use, reproduce, + modify, display, perform, sublicense and distribute the + Modifications created by such Contributor (or portions + thereof), either on an unmodified basis, with other + Modifications, as Covered Software and/or as part of a + Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either + alone and/or in combination with its Contributor Version + (or portions of such combination), to make, use, sell, + offer for sale, have made, and/or otherwise dispose of: + (1) Modifications made by that Contributor (or portions + thereof); and (2) the combination of Modifications made by + that Contributor with its Contributor Version (or portions + of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first distributes or + otherwise makes the Modifications available to a third + party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: (1) for any code that Contributor has deleted + from the Contributor Version; (2) for infringements caused + by: (i) third party modifications of Contributor Version, + or (ii) the combination of Modifications made by that + Contributor with other software (except as part of the + Contributor Version) or other devices; or (3) under Patent + Claims infringed by Covered Software in the absence of + Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make + available in Executable form must also be made available in Source + Code form and that Source Code form must be distributed only under + the terms of this License. You must include a copy of this + License with every copy of the Source Code form of the Covered + Software You distribute or otherwise make available. You must + inform recipients of any such Covered Software in Executable form + as to how they can obtain such Covered Software in Source Code + form in a reasonable manner on or through a medium customarily + used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are + governed by the terms of this License. You represent that You + believe Your Modifications are Your original creation(s) and/or + You have sufficient rights to grant the rights conveyed by this + License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that + identifies You as the Contributor of the Modification. You may + not remove or alter any copyright, patent or trademark notices + contained within the Covered Software, or any notices of licensing + or any descriptive text giving attribution to any Contributor or + the Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in + Source Code form that alters or restricts the applicable version + of this License or the recipients' rights hereunder. You may + choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of + Covered Software. However, you may do so only on Your own behalf, + and not on behalf of the Initial Developer or any Contributor. + You must make it absolutely clear that any such warranty, support, + indemnity or liability obligation is offered by You alone, and You + hereby agree to indemnify the Initial Developer and every + Contributor for any liability incurred by the Initial Developer or + such Contributor as a result of warranty, support, indemnity or + liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software + under the terms of this License or under the terms of a license of + Your choice, which may contain terms different from this License, + provided that You are in compliance with the terms of this License + and that the license for the Executable form does not attempt to + limit or alter the recipient's rights in the Source Code form from + the rights set forth in this License. If You distribute the + Covered Software in Executable form under a different license, You + must make it absolutely clear that any terms which differ from + this License are offered by You alone, not by the Initial + Developer or Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred + by the Initial Developer or such Contributor as a result of any + such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with + other code not governed by the terms of this License and + distribute the Larger Work as a single product. In such a case, + You must make sure the requirements of this License are fulfilled + for the Covered Software. + +4. Versions of the License. + + 4.1. New Versions. + + Sun Microsystems, Inc. is the initial license steward and may + publish revised and/or new versions of this License from time to + time. Each version will be given a distinguishing version number. + Except as provided in Section 4.3, no one other than the license + steward has the right to modify this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the + Covered Software available under the terms of the version of the + License under which You originally received the Covered Software. + If the Initial Developer includes a notice in the Original + Software prohibiting it from being distributed or otherwise made + available under any subsequent version of the License, You must + distribute and make the Covered Software available under the terms + of the version of the License under which You originally received + the Covered Software. Otherwise, You may also choose to use, + distribute or otherwise make the Covered Software available under + the terms of any subsequent version of the License published by + the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new + license for Your Original Software, You may create and use a + modified version of this License if You: (a) rename the license + and remove any references to the name of the license steward + (except to note that the license differs from this License); and + (b) otherwise make it clear that the license contains terms which + differ from this License. + +5. DISCLAIMER OF WARRANTY. + + COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" + BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, + INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED + SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR + PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND + PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY + COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE + INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY + NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF + WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS + DISCLAIMER. + +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to + cure such breach within 30 days of becoming aware of the breach. + Provisions which, by their nature, must remain in effect beyond + the termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding + declaratory judgment actions) against Initial Developer or a + Contributor (the Initial Developer or Contributor against whom You + assert such claim is referred to as "Participant") alleging that + the Participant Software (meaning the Contributor Version where + the Participant is a Contributor or the Original Software where + the Participant is the Initial Developer) directly or indirectly + infringes any patent, then any and all rights granted directly or + indirectly to You by such Participant, the Initial Developer (if + the Initial Developer is not the Participant) and all Contributors + under Sections 2.1 and/or 2.2 of this License shall, upon 60 days + notice from Participant terminate prospectively and automatically + at the expiration of such 60 day notice period, unless if within + such 60 day period You withdraw Your claim with respect to the + Participant Software against such Participant either unilaterally + or pursuant to a written agreement with Participant. + + 6.3. In the event of termination under Sections 6.1 or 6.2 above, + all end user licenses that have been validly granted by You or any + distributor hereunder prior to termination (excluding licenses + granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE + INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF + COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE + LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR + CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT + LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK + STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL + INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT + APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO + NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR + CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT + APPLY TO YOU. + +8. U.S. GOVERNMENT END USERS. + + The Covered Software is a "commercial item," as that term is + defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial + computer software" (as that term is defined at 48 + C.F.R. 252.227-7014(a)(1)) and "commercial computer software + documentation" as such terms are used in 48 C.F.R. 12.212 + (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 + C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all + U.S. Government End Users acquire Covered Software with only those + rights set forth herein. This U.S. Government Rights clause is in + lieu of, and supersedes, any other FAR, DFAR, or other clause or + provision that addresses Government rights in computer software + under this License. + +9. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed + by the law of the jurisdiction specified in a notice contained + within the Original Software (except to the extent applicable law, + if any, provides otherwise), excluding such jurisdiction's + conflict-of-law provisions. Any litigation relating to this + License shall be subject to the jurisdiction of the courts located + in the jurisdiction and venue specified in a notice contained + within the Original Software, with the losing party responsible + for costs, including, without limitation, court costs and + reasonable attorneys' fees and expenses. The application of the + United Nations Convention on Contracts for the International Sale + of Goods is expressly excluded. Any law or regulation which + provides that the language of a contract shall be construed + against the drafter shall not apply to this License. You agree + that You alone are responsible for compliance with the United + States export administration regulations (and the export control + laws and regulation of any other countries) when You use, + distribute or otherwise make available any Covered Software. + +10. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or + indirectly, out of its utilization of rights under this License + and You agree to work with Initial Developer and Contributors to + distribute such responsibility on an equitable basis. Nothing + herein is intended or shall be deemed to constitute any admission + of liability. + +-------------------------------------------------------------------- + +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND +DISTRIBUTION LICENSE (CDDL) + +For Covered Software in this distribution, this License shall +be governed by the laws of the State of California (excluding +conflict-of-law provisions). + +Any litigation relating to this License shall be subject to the +jurisdiction of the Federal Courts of the Northern District of +California and the state courts of the State of California, with +venue lying in Santa Clara County, California. diff --git a/vendor/github.com/howeyc/gopass/README.md b/vendor/github.com/howeyc/gopass/README.md new file mode 100644 index 000000000..2d6a4e72c --- /dev/null +++ b/vendor/github.com/howeyc/gopass/README.md @@ -0,0 +1,27 @@ +# getpasswd in Go [![GoDoc](https://godoc.org/github.com/howeyc/gopass?status.svg)](https://godoc.org/github.com/howeyc/gopass) [![Build Status](https://secure.travis-ci.org/howeyc/gopass.png?branch=master)](http://travis-ci.org/howeyc/gopass) + +Retrieve password from user terminal or piped input without echo. + +Verified on BSD, Linux, and Windows. + +Example: +```go +package main + +import "fmt" +import "github.com/howeyc/gopass" + +func main() { + fmt.Printf("Password: ") + + // Silent. For printing *'s use gopass.GetPasswdMasked() + pass, err := gopass.GetPasswd() + if err != nil { + // Handle gopass.ErrInterrupted or getch() read error + } + + // Do something with pass +} +``` + +Caution: Multi-byte characters not supported! diff --git a/vendor/github.com/howeyc/gopass/pass.go b/vendor/github.com/howeyc/gopass/pass.go new file mode 100644 index 000000000..f5bd5a51a --- /dev/null +++ b/vendor/github.com/howeyc/gopass/pass.go @@ -0,0 +1,110 @@ +package gopass + +import ( + "errors" + "fmt" + "io" + "os" +) + +type FdReader interface { + io.Reader + Fd() uintptr +} + +var defaultGetCh = func(r io.Reader) (byte, error) { + buf := make([]byte, 1) + if n, err := r.Read(buf); n == 0 || err != nil { + if err != nil { + return 0, err + } + return 0, io.EOF + } + return buf[0], nil +} + +var ( + maxLength = 512 + ErrInterrupted = errors.New("interrupted") + ErrMaxLengthExceeded = fmt.Errorf("maximum byte limit (%v) exceeded", maxLength) + + // Provide variable so that tests can provide a mock implementation. + getch = defaultGetCh +) + +// getPasswd returns the input read from terminal. +// If prompt is not empty, it will be output as a prompt to the user +// If masked is true, typing will be matched by asterisks on the screen. +// Otherwise, typing will echo nothing. +func getPasswd(prompt string, masked bool, r FdReader, w io.Writer) ([]byte, error) { + var err error + var pass, bs, mask []byte + if masked { + bs = []byte("\b \b") + mask = []byte("*") + } + + if isTerminal(r.Fd()) { + if oldState, err := makeRaw(r.Fd()); err != nil { + return pass, err + } else { + defer func() { + restore(r.Fd(), oldState) + fmt.Fprintln(w) + }() + } + } + + if prompt != "" { + fmt.Fprint(w, prompt) + } + + // Track total bytes read, not just bytes in the password. This ensures any + // errors that might flood the console with nil or -1 bytes infinitely are + // capped. + var counter int + for counter = 0; counter <= maxLength; counter++ { + if v, e := getch(r); e != nil { + err = e + break + } else if v == 127 || v == 8 { + if l := len(pass); l > 0 { + pass = pass[:l-1] + fmt.Fprint(w, string(bs)) + } + } else if v == 13 || v == 10 { + break + } else if v == 3 { + err = ErrInterrupted + break + } else if v != 0 { + pass = append(pass, v) + fmt.Fprint(w, string(mask)) + } + } + + if counter > maxLength { + err = ErrMaxLengthExceeded + } + + return pass, err +} + +// GetPasswd returns the password read from the terminal without echoing input. +// The returned byte array does not include end-of-line characters. +func GetPasswd() ([]byte, error) { + return getPasswd("", false, os.Stdin, os.Stdout) +} + +// GetPasswdMasked returns the password read from the terminal, echoing asterisks. +// The returned byte array does not include end-of-line characters. +func GetPasswdMasked() ([]byte, error) { + return getPasswd("", true, os.Stdin, os.Stdout) +} + +// GetPasswdPrompt prompts the user and returns the password read from the terminal. +// If mask is true, then asterisks are echoed. +// The returned byte array does not include end-of-line characters. +func GetPasswdPrompt(prompt string, mask bool, r FdReader, w io.Writer) ([]byte, error) { + return getPasswd(prompt, mask, r, w) +} diff --git a/vendor/github.com/howeyc/gopass/terminal.go b/vendor/github.com/howeyc/gopass/terminal.go new file mode 100644 index 000000000..083564146 --- /dev/null +++ b/vendor/github.com/howeyc/gopass/terminal.go @@ -0,0 +1,25 @@ +// +build !solaris + +package gopass + +import "golang.org/x/crypto/ssh/terminal" + +type terminalState struct { + state *terminal.State +} + +func isTerminal(fd uintptr) bool { + return terminal.IsTerminal(int(fd)) +} + +func makeRaw(fd uintptr) (*terminalState, error) { + state, err := terminal.MakeRaw(int(fd)) + + return &terminalState{ + state: state, + }, err +} + +func restore(fd uintptr, oldState *terminalState) error { + return terminal.Restore(int(fd), oldState.state) +} diff --git a/vendor/github.com/howeyc/gopass/terminal_solaris.go b/vendor/github.com/howeyc/gopass/terminal_solaris.go new file mode 100644 index 000000000..257e1b4e8 --- /dev/null +++ b/vendor/github.com/howeyc/gopass/terminal_solaris.go @@ -0,0 +1,69 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +// Below is derived from Solaris source, so CDDL license is included. + +package gopass + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +type terminalState struct { + state *unix.Termios +} + +// isTerminal returns true if there is a terminal attached to the given +// file descriptor. +// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c +func isTerminal(fd uintptr) bool { + var termio unix.Termio + err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) + return err == nil +} + +// makeRaw puts the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c +func makeRaw(fd uintptr) (*terminalState, error) { + oldTermiosPtr, err := unix.IoctlGetTermios(int(fd), unix.TCGETS) + if err != nil { + return nil, err + } + oldTermios := *oldTermiosPtr + + newTermios := oldTermios + newTermios.Lflag &^= syscall.ECHO | syscall.ECHOE | syscall.ECHOK | syscall.ECHONL + if err := unix.IoctlSetTermios(int(fd), unix.TCSETS, &newTermios); err != nil { + return nil, err + } + + return &terminalState{ + state: oldTermiosPtr, + }, nil +} + +func restore(fd uintptr, oldState *terminalState) error { + return unix.IoctlSetTermios(int(fd), unix.TCSETS, oldState.state) +} diff --git a/vendor/github.com/imdario/mergo/.travis.yml b/vendor/github.com/imdario/mergo/.travis.yml new file mode 100644 index 000000000..9d91c6339 --- /dev/null +++ b/vendor/github.com/imdario/mergo/.travis.yml @@ -0,0 +1,2 @@ +language: go +install: go get -t diff --git a/vendor/github.com/imdario/mergo/LICENSE b/vendor/github.com/imdario/mergo/LICENSE new file mode 100644 index 000000000..686680298 --- /dev/null +++ b/vendor/github.com/imdario/mergo/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2013 Dario Castañé. All rights reserved. +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/imdario/mergo/README.md b/vendor/github.com/imdario/mergo/README.md new file mode 100644 index 000000000..cdcea0f65 --- /dev/null +++ b/vendor/github.com/imdario/mergo/README.md @@ -0,0 +1,68 @@ +# Mergo + +A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements. + +Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region Marche. + +![Mergo dall'alto](http://www.comune.mergo.an.it/Siti/Mergo/Immagini/Foto/mergo_dall_alto.jpg) + +## Status + +It is ready for production use. It works fine although it may use more of testing. Here some projects in the wild using Mergo: + +- [EagerIO/Stout](https://github.com/EagerIO/Stout) +- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api) +- [russross/canvasassignments](https://github.com/russross/canvasassignments) +- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api) +- [casualjim/exeggutor](https://github.com/casualjim/exeggutor) +- [divshot/gitling](https://github.com/divshot/gitling) +- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl) + +[![Build Status][1]][2] +[![GoDoc](https://godoc.org/github.com/imdario/mergo?status.svg)](https://godoc.org/github.com/imdario/mergo) + +[1]: https://travis-ci.org/imdario/mergo.png +[2]: https://travis-ci.org/imdario/mergo + +## Installation + + go get github.com/imdario/mergo + + // use in your .go code + import ( + "github.com/imdario/mergo" + ) + +## Usage + +You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection). + + if err := mergo.Merge(&dst, src); err != nil { + // ... + } + +Additionally, you can map a map[string]interface{} to a struct (and otherwise, from struct to map), following the same restrictions as in Merge(). Keys are capitalized to find each corresponding exported field. + + if err := mergo.Map(&dst, srcMap); err != nil { + // ... + } + +Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as map[string]interface{}. They will be just assigned as values. + +More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo). + +Note: if test are failing due missing package, please execute: + + go get gopkg.in/yaml.v1 + +## Contact me + +If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario) + +## About + +Written by [Dario Castañé](http://dario.im). + +## License + +[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE). diff --git a/vendor/github.com/imdario/mergo/doc.go b/vendor/github.com/imdario/mergo/doc.go new file mode 100644 index 000000000..6e9aa7baf --- /dev/null +++ b/vendor/github.com/imdario/mergo/doc.go @@ -0,0 +1,44 @@ +// Copyright 2013 Dario Castañé. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package mergo merges same-type structs and maps by setting default values in zero-value fields. + +Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection). + +Usage + +From my own work-in-progress project: + + type networkConfig struct { + Protocol string + Address string + ServerType string `json: "server_type"` + Port uint16 + } + + type FssnConfig struct { + Network networkConfig + } + + var fssnDefault = FssnConfig { + networkConfig { + "tcp", + "127.0.0.1", + "http", + 31560, + }, + } + + // Inside a function [...] + + if err := mergo.Merge(&config, fssnDefault); err != nil { + log.Fatal(err) + } + + // More code [...] + +*/ +package mergo diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/github.com/imdario/mergo/map.go new file mode 100644 index 000000000..44361e88b --- /dev/null +++ b/vendor/github.com/imdario/mergo/map.go @@ -0,0 +1,146 @@ +// Copyright 2014 Dario Castañé. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Based on src/pkg/reflect/deepequal.go from official +// golang's stdlib. + +package mergo + +import ( + "fmt" + "reflect" + "unicode" + "unicode/utf8" +) + +func changeInitialCase(s string, mapper func(rune) rune) string { + if s == "" { + return s + } + r, n := utf8.DecodeRuneInString(s) + return string(mapper(r)) + s[n:] +} + +func isExported(field reflect.StructField) bool { + r, _ := utf8.DecodeRuneInString(field.Name) + return r >= 'A' && r <= 'Z' +} + +// Traverses recursively both values, assigning src's fields values to dst. +// The map argument tracks comparisons that have already been seen, which allows +// short circuiting on recursive types. +func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) { + if dst.CanAddr() { + addr := dst.UnsafeAddr() + h := 17 * addr + seen := visited[h] + typ := dst.Type() + for p := seen; p != nil; p = p.next { + if p.ptr == addr && p.typ == typ { + return nil + } + } + // Remember, remember... + visited[h] = &visit{addr, typ, seen} + } + zeroValue := reflect.Value{} + switch dst.Kind() { + case reflect.Map: + dstMap := dst.Interface().(map[string]interface{}) + for i, n := 0, src.NumField(); i < n; i++ { + srcType := src.Type() + field := srcType.Field(i) + if !isExported(field) { + continue + } + fieldName := field.Name + fieldName = changeInitialCase(fieldName, unicode.ToLower) + if v, ok := dstMap[fieldName]; !ok || isEmptyValue(reflect.ValueOf(v)) { + dstMap[fieldName] = src.Field(i).Interface() + } + } + case reflect.Struct: + srcMap := src.Interface().(map[string]interface{}) + for key := range srcMap { + srcValue := srcMap[key] + fieldName := changeInitialCase(key, unicode.ToUpper) + dstElement := dst.FieldByName(fieldName) + if dstElement == zeroValue { + // We discard it because the field doesn't exist. + continue + } + srcElement := reflect.ValueOf(srcValue) + dstKind := dstElement.Kind() + srcKind := srcElement.Kind() + if srcKind == reflect.Ptr && dstKind != reflect.Ptr { + srcElement = srcElement.Elem() + srcKind = reflect.TypeOf(srcElement.Interface()).Kind() + } else if dstKind == reflect.Ptr { + // Can this work? I guess it can't. + if srcKind != reflect.Ptr && srcElement.CanAddr() { + srcPtr := srcElement.Addr() + srcElement = reflect.ValueOf(srcPtr) + srcKind = reflect.Ptr + } + } + if !srcElement.IsValid() { + continue + } + if srcKind == dstKind { + if err = deepMerge(dstElement, srcElement, visited, depth+1); err != nil { + return + } + } else { + if srcKind == reflect.Map { + if err = deepMap(dstElement, srcElement, visited, depth+1); err != nil { + return + } + } else { + return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind) + } + } + } + } + return +} + +// Map sets fields' values in dst from src. +// src can be a map with string keys or a struct. dst must be the opposite: +// if src is a map, dst must be a valid pointer to struct. If src is a struct, +// dst must be map[string]interface{}. +// It won't merge unexported (private) fields and will do recursively +// any exported field. +// If dst is a map, keys will be src fields' names in lower camel case. +// Missing key in src that doesn't match a field in dst will be skipped. This +// doesn't apply if dst is a map. +// This is separated method from Merge because it is cleaner and it keeps sane +// semantics: merging equal types, mapping different (restricted) types. +func Map(dst, src interface{}) error { + var ( + vDst, vSrc reflect.Value + err error + ) + if vDst, vSrc, err = resolveValues(dst, src); err != nil { + return err + } + // To be friction-less, we redirect equal-type arguments + // to deepMerge. Only because arguments can be anything. + if vSrc.Kind() == vDst.Kind() { + return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0) + } + switch vSrc.Kind() { + case reflect.Struct: + if vDst.Kind() != reflect.Map { + return ErrExpectedMapAsDestination + } + case reflect.Map: + if vDst.Kind() != reflect.Struct { + return ErrExpectedStructAsDestination + } + default: + return ErrNotSupported + } + return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0) +} diff --git a/vendor/github.com/imdario/mergo/merge.go b/vendor/github.com/imdario/mergo/merge.go new file mode 100644 index 000000000..5d328b1fe --- /dev/null +++ b/vendor/github.com/imdario/mergo/merge.go @@ -0,0 +1,99 @@ +// Copyright 2013 Dario Castañé. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Based on src/pkg/reflect/deepequal.go from official +// golang's stdlib. + +package mergo + +import ( + "reflect" +) + +// Traverses recursively both values, assigning src's fields values to dst. +// The map argument tracks comparisons that have already been seen, which allows +// short circuiting on recursive types. +func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) { + if !src.IsValid() { + return + } + if dst.CanAddr() { + addr := dst.UnsafeAddr() + h := 17 * addr + seen := visited[h] + typ := dst.Type() + for p := seen; p != nil; p = p.next { + if p.ptr == addr && p.typ == typ { + return nil + } + } + // Remember, remember... + visited[h] = &visit{addr, typ, seen} + } + switch dst.Kind() { + case reflect.Struct: + for i, n := 0, dst.NumField(); i < n; i++ { + if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1); err != nil { + return + } + } + case reflect.Map: + for _, key := range src.MapKeys() { + srcElement := src.MapIndex(key) + if !srcElement.IsValid() { + continue + } + dstElement := dst.MapIndex(key) + switch reflect.TypeOf(srcElement.Interface()).Kind() { + case reflect.Struct: + fallthrough + case reflect.Map: + if err = deepMerge(dstElement, srcElement, visited, depth+1); err != nil { + return + } + } + if !dstElement.IsValid() { + dst.SetMapIndex(key, srcElement) + } + } + case reflect.Ptr: + fallthrough + case reflect.Interface: + if src.IsNil() { + break + } else if dst.IsNil() { + if dst.CanSet() && isEmptyValue(dst) { + dst.Set(src) + } + } else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1); err != nil { + return + } + default: + if dst.CanSet() && !isEmptyValue(src) { + dst.Set(src) + } + } + return +} + +// Merge sets fields' values in dst from src if they have a zero +// value of their type. +// dst and src must be valid same-type structs and dst must be +// a pointer to struct. +// It won't merge unexported (private) fields and will do recursively +// any exported field. +func Merge(dst, src interface{}) error { + var ( + vDst, vSrc reflect.Value + err error + ) + if vDst, vSrc, err = resolveValues(dst, src); err != nil { + return err + } + if vDst.Type() != vSrc.Type() { + return ErrDifferentArgumentsTypes + } + return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0) +} diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/github.com/imdario/mergo/mergo.go new file mode 100644 index 000000000..f8a0991ec --- /dev/null +++ b/vendor/github.com/imdario/mergo/mergo.go @@ -0,0 +1,90 @@ +// Copyright 2013 Dario Castañé. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Based on src/pkg/reflect/deepequal.go from official +// golang's stdlib. + +package mergo + +import ( + "errors" + "reflect" +) + +// Errors reported by Mergo when it finds invalid arguments. +var ( + ErrNilArguments = errors.New("src and dst must not be nil") + ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type") + ErrNotSupported = errors.New("only structs and maps are supported") + ErrExpectedMapAsDestination = errors.New("dst was expected to be a map") + ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct") +) + +// During deepMerge, must keep track of checks that are +// in progress. The comparison algorithm assumes that all +// checks in progress are true when it reencounters them. +// Visited are stored in a map indexed by 17 * a1 + a2; +type visit struct { + ptr uintptr + typ reflect.Type + next *visit +} + +// From src/pkg/encoding/json. +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + return false +} + +func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) { + if dst == nil || src == nil { + err = ErrNilArguments + return + } + vDst = reflect.ValueOf(dst).Elem() + if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map { + err = ErrNotSupported + return + } + vSrc = reflect.ValueOf(src) + // We check if vSrc is a pointer to dereference it. + if vSrc.Kind() == reflect.Ptr { + vSrc = vSrc.Elem() + } + return +} + +// Traverses recursively both values, assigning src's fields values to dst. +// The map argument tracks comparisons that have already been seen, which allows +// short circuiting on recursive types. +func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) { + if dst.CanAddr() { + addr := dst.UnsafeAddr() + h := 17 * addr + seen := visited[h] + typ := dst.Type() + for p := seen; p != nil; p = p.next { + if p.ptr == addr && p.typ == typ { + return nil + } + } + // Remember, remember... + visited[h] = &visit{addr, typ, seen} + } + return // TODO refactor +} diff --git a/vendor/github.com/imdario/mergo/testdata/license.yml b/vendor/github.com/imdario/mergo/testdata/license.yml new file mode 100644 index 000000000..62fdb61ec --- /dev/null +++ b/vendor/github.com/imdario/mergo/testdata/license.yml @@ -0,0 +1,3 @@ +import: ../../../../fossene/db/schema/thing.yml +fields: + site: string diff --git a/vendor/github.com/inconshreveable/mousetrap/LICENSE b/vendor/github.com/inconshreveable/mousetrap/LICENSE new file mode 100644 index 000000000..5f0d1fb6a --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/LICENSE @@ -0,0 +1,13 @@ +Copyright 2014 Alan Shreve + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/inconshreveable/mousetrap/README.md b/vendor/github.com/inconshreveable/mousetrap/README.md new file mode 100644 index 000000000..7a950d177 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/README.md @@ -0,0 +1,23 @@ +# mousetrap + +mousetrap is a tiny library that answers a single question. + +On a Windows machine, was the process invoked by someone double clicking on +the executable file while browsing in explorer? + +### Motivation + +Windows developers unfamiliar with command line tools will often "double-click" +the executable for a tool. Because most CLI tools print the help and then exit +when invoked without arguments, this is often very frustrating for those users. + +mousetrap provides a way to detect these invocations so that you can provide +more helpful behavior and instructions on how to run the CLI tool. To see what +this looks like, both from an organizational and a technical perspective, see +https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/ + +### The interface + +The library exposes a single interface: + + func StartedByExplorer() (bool) diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_others.go b/vendor/github.com/inconshreveable/mousetrap/trap_others.go new file mode 100644 index 000000000..9d2d8a4ba --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_others.go @@ -0,0 +1,15 @@ +// +build !windows + +package mousetrap + +// StartedByExplorer returns true if the program was invoked by the user +// double-clicking on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +// +// On non-Windows platforms, it always returns false. +func StartedByExplorer() bool { + return false +} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go new file mode 100644 index 000000000..336142a5e --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go @@ -0,0 +1,98 @@ +// +build windows +// +build !go1.4 + +package mousetrap + +import ( + "fmt" + "os" + "syscall" + "unsafe" +) + +const ( + // defined by the Win32 API + th32cs_snapprocess uintptr = 0x2 +) + +var ( + kernel = syscall.MustLoadDLL("kernel32.dll") + CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") + Process32First = kernel.MustFindProc("Process32FirstW") + Process32Next = kernel.MustFindProc("Process32NextW") +) + +// ProcessEntry32 structure defined by the Win32 API +type processEntry32 struct { + dwSize uint32 + cntUsage uint32 + th32ProcessID uint32 + th32DefaultHeapID int + th32ModuleID uint32 + cntThreads uint32 + th32ParentProcessID uint32 + pcPriClassBase int32 + dwFlags uint32 + szExeFile [syscall.MAX_PATH]uint16 +} + +func getProcessEntry(pid int) (pe *processEntry32, err error) { + snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) + if snapshot == uintptr(syscall.InvalidHandle) { + err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) + return + } + defer syscall.CloseHandle(syscall.Handle(snapshot)) + + var processEntry processEntry32 + processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) + ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) + if ok == 0 { + err = fmt.Errorf("Process32First: %v", e1) + return + } + + for { + if processEntry.th32ProcessID == uint32(pid) { + pe = &processEntry + return + } + + ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) + if ok == 0 { + err = fmt.Errorf("Process32Next: %v", e1) + return + } + } +} + +func getppid() (pid int, err error) { + pe, err := getProcessEntry(os.Getpid()) + if err != nil { + return + } + + pid = int(pe.th32ParentProcessID) + return +} + +// StartedByExplorer returns true if the program was invoked by the user double-clicking +// on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +func StartedByExplorer() bool { + ppid, err := getppid() + if err != nil { + return false + } + + pe, err := getProcessEntry(ppid) + if err != nil { + return false + } + + name := syscall.UTF16ToString(pe.szExeFile[:]) + return name == "explorer.exe" +} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go new file mode 100644 index 000000000..9a28e57c3 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go @@ -0,0 +1,46 @@ +// +build windows +// +build go1.4 + +package mousetrap + +import ( + "os" + "syscall" + "unsafe" +) + +func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { + snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) + if err != nil { + return nil, err + } + defer syscall.CloseHandle(snapshot) + var procEntry syscall.ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + if err = syscall.Process32First(snapshot, &procEntry); err != nil { + return nil, err + } + for { + if procEntry.ProcessID == uint32(pid) { + return &procEntry, nil + } + err = syscall.Process32Next(snapshot, &procEntry) + if err != nil { + return nil, err + } + } +} + +// StartedByExplorer returns true if the program was invoked by the user double-clicking +// on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +func StartedByExplorer() bool { + pe, err := getProcessEntry(os.Getppid()) + if err != nil { + return false + } + return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) +} diff --git a/vendor/github.com/json-iterator/go/.codecov.yml b/vendor/github.com/json-iterator/go/.codecov.yml new file mode 100644 index 000000000..955dc0be5 --- /dev/null +++ b/vendor/github.com/json-iterator/go/.codecov.yml @@ -0,0 +1,3 @@ +ignore: + - "output_tests/.*" + diff --git a/vendor/github.com/json-iterator/go/.gitignore b/vendor/github.com/json-iterator/go/.gitignore new file mode 100644 index 000000000..501fcdc9a --- /dev/null +++ b/vendor/github.com/json-iterator/go/.gitignore @@ -0,0 +1,3 @@ +.idea +/coverage.txt +/profile.out diff --git a/vendor/github.com/json-iterator/go/.travis.yml b/vendor/github.com/json-iterator/go/.travis.yml new file mode 100644 index 000000000..945b9c594 --- /dev/null +++ b/vendor/github.com/json-iterator/go/.travis.yml @@ -0,0 +1,13 @@ +language: go + +go: + - 1.8.x + +before_install: + - go get -t -v ./... + +script: + - ./test.sh + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/json-iterator/go/LICENSE b/vendor/github.com/json-iterator/go/LICENSE new file mode 100644 index 000000000..2cf4f5ab2 --- /dev/null +++ b/vendor/github.com/json-iterator/go/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 json-iterator + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/json-iterator/go/README.md b/vendor/github.com/json-iterator/go/README.md new file mode 100644 index 000000000..23a4b57c8 --- /dev/null +++ b/vendor/github.com/json-iterator/go/README.md @@ -0,0 +1,80 @@ +[![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge) +[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/json-iterator/go) +[![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go) +[![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go) +[![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go) +[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/json-iterator/go/master/LICENSE) +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) + +A high-performance 100% compatible drop-in replacement of "encoding/json" + +``` +Go开发者们请加入我们,滴滴出行平台技术部 taowen@didichuxing.com +``` + +# Benchmark + +![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png) + +Source code: https://github.com/json-iterator/go-benchmark/blob/master/src/github.com/json-iterator/go-benchmark/benchmark_medium_payload_test.go + +Raw Result (easyjson requires static code generation) + +| | ns/op | allocation bytes | allocation times | +| --- | --- | --- | --- | +| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op | +| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op | +| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op | +| std encode | 2213 ns/op | 712 B/op | 5 allocs/op | +| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op | +| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op | + +# Usage + +100% compatibility with standard lib + +Replace + +```go +import "encoding/json" +json.Marshal(&data) +``` + +with + +```go +import "github.com/json-iterator/go" +jsoniter.Marshal(&data) +``` + +Replace + +```go +import "encoding/json" +json.Unmarshal(input, &data) +``` + +with + +```go +import "github.com/json-iterator/go" +jsoniter.Unmarshal(input, &data) +``` + +[More documentation](http://jsoniter.com/migrate-from-go-std.html) + +# How to get + +``` +go get github.com/json-iterator/go +``` + +# Contribution Welcomed ! + +Contributors + +* [thockin](https://github.com/thockin) +* [mattn](https://github.com/mattn) +* [cch123](https://github.com/cch123) + +Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) diff --git a/vendor/github.com/json-iterator/go/feature_adapter.go b/vendor/github.com/json-iterator/go/feature_adapter.go new file mode 100644 index 000000000..edb477c4f --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_adapter.go @@ -0,0 +1,127 @@ +package jsoniter + +import ( + "bytes" + "io" +) + +// RawMessage to make replace json with jsoniter +type RawMessage []byte + +// Unmarshal adapts to json/encoding Unmarshal API +// +// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. +// Refer to https://godoc.org/encoding/json#Unmarshal for more information +func Unmarshal(data []byte, v interface{}) error { + return ConfigDefault.Unmarshal(data, v) +} + +func lastNotSpacePos(data []byte) int { + for i := len(data) - 1; i >= 0; i-- { + if data[i] != ' ' && data[i] != '\t' && data[i] != '\r' && data[i] != '\n' { + return i + 1 + } + } + return 0 +} + +// UnmarshalFromString convenient method to read from string instead of []byte +func UnmarshalFromString(str string, v interface{}) error { + return ConfigDefault.UnmarshalFromString(str, v) +} + +// Get quick method to get value from deeply nested JSON structure +func Get(data []byte, path ...interface{}) Any { + return ConfigDefault.Get(data, path...) +} + +// Marshal adapts to json/encoding Marshal API +// +// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API +// Refer to https://godoc.org/encoding/json#Marshal for more information +func Marshal(v interface{}) ([]byte, error) { + return ConfigDefault.Marshal(v) +} + +// MarshalIndent same as json.MarshalIndent. Prefix is not supported. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + return ConfigDefault.MarshalIndent(v, prefix, indent) +} + +// MarshalToString convenient method to write as string instead of []byte +func MarshalToString(v interface{}) (string, error) { + return ConfigDefault.MarshalToString(v) +} + +// NewDecoder adapts to json/stream NewDecoder API. +// +// NewDecoder returns a new decoder that reads from r. +// +// Instead of a json/encoding Decoder, an Decoder is returned +// Refer to https://godoc.org/encoding/json#NewDecoder for more information +func NewDecoder(reader io.Reader) *Decoder { + return ConfigDefault.NewDecoder(reader) +} + +// Decoder reads and decodes JSON values from an input stream. +// Decoder provides identical APIs with json/stream Decoder (Token() and UseNumber() are in progress) +type Decoder struct { + iter *Iterator +} + +// Decode decode JSON into interface{} +func (adapter *Decoder) Decode(obj interface{}) error { + adapter.iter.ReadVal(obj) + err := adapter.iter.Error + if err == io.EOF { + return nil + } + return adapter.iter.Error +} + +// More is there more? +func (adapter *Decoder) More() bool { + return adapter.iter.head != adapter.iter.tail +} + +// Buffered remaining buffer +func (adapter *Decoder) Buffered() io.Reader { + remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail] + return bytes.NewReader(remaining) +} + +// UseNumber for number JSON element, use float64 or json.NumberValue (alias of string) +func (adapter *Decoder) UseNumber() { + origCfg := adapter.iter.cfg.configBeforeFrozen + origCfg.UseNumber = true + adapter.iter.cfg = origCfg.Froze().(*frozenConfig) +} + +// NewEncoder same as json.NewEncoder +func NewEncoder(writer io.Writer) *Encoder { + return ConfigDefault.NewEncoder(writer) +} + +// Encoder same as json.Encoder +type Encoder struct { + stream *Stream +} + +// Encode encode interface{} as JSON to io.Writer +func (adapter *Encoder) Encode(val interface{}) error { + adapter.stream.WriteVal(val) + adapter.stream.Flush() + return adapter.stream.Error +} + +// SetIndent set the indention. Prefix is not supported +func (adapter *Encoder) SetIndent(prefix, indent string) { + adapter.stream.cfg.indentionStep = len(indent) +} + +// SetEscapeHTML escape html by default, set to false to disable +func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) { + config := adapter.stream.cfg.configBeforeFrozen + config.EscapeHTML = escapeHTML + adapter.stream.cfg = config.Froze().(*frozenConfig) +} diff --git a/vendor/github.com/json-iterator/go/feature_any.go b/vendor/github.com/json-iterator/go/feature_any.go new file mode 100644 index 000000000..6733dce4c --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any.go @@ -0,0 +1,242 @@ +package jsoniter + +import ( + "fmt" + "io" + "reflect" +) + +// Any generic object representation. +// The lazy json implementation holds []byte and parse lazily. +type Any interface { + LastError() error + ValueType() ValueType + MustBeValid() Any + ToBool() bool + ToInt() int + ToInt32() int32 + ToInt64() int64 + ToUint() uint + ToUint32() uint32 + ToUint64() uint64 + ToFloat32() float32 + ToFloat64() float64 + ToString() string + ToVal(val interface{}) + Get(path ...interface{}) Any + // TODO: add Set + Size() int + Keys() []string + GetInterface() interface{} + WriteTo(stream *Stream) +} + +type baseAny struct{} + +func (any *baseAny) Get(path ...interface{}) Any { + return &invalidAny{baseAny{}, fmt.Errorf("Get %v from simple value", path)} +} + +func (any *baseAny) Size() int { + return 0 +} + +func (any *baseAny) Keys() []string { + return []string{} +} + +func (any *baseAny) ToVal(obj interface{}) { + panic("not implemented") +} + +// WrapInt32 turn int32 into Any interface +func WrapInt32(val int32) Any { + return &int32Any{baseAny{}, val} +} + +// WrapInt64 turn int64 into Any interface +func WrapInt64(val int64) Any { + return &int64Any{baseAny{}, val} +} + +// WrapUint32 turn uint32 into Any interface +func WrapUint32(val uint32) Any { + return &uint32Any{baseAny{}, val} +} + +// WrapUint64 turn uint64 into Any interface +func WrapUint64(val uint64) Any { + return &uint64Any{baseAny{}, val} +} + +// WrapFloat64 turn float64 into Any interface +func WrapFloat64(val float64) Any { + return &floatAny{baseAny{}, val} +} + +// WrapString turn string into Any interface +func WrapString(val string) Any { + return &stringAny{baseAny{}, val} +} + +// Wrap turn a go object into Any interface +func Wrap(val interface{}) Any { + if val == nil { + return &nilAny{} + } + asAny, isAny := val.(Any) + if isAny { + return asAny + } + typ := reflect.TypeOf(val) + switch typ.Kind() { + case reflect.Slice: + return wrapArray(val) + case reflect.Struct: + return wrapStruct(val) + case reflect.Map: + return wrapMap(val) + case reflect.String: + return WrapString(val.(string)) + case reflect.Int: + return WrapInt64(int64(val.(int))) + case reflect.Int8: + return WrapInt32(int32(val.(int8))) + case reflect.Int16: + return WrapInt32(int32(val.(int16))) + case reflect.Int32: + return WrapInt32(val.(int32)) + case reflect.Int64: + return WrapInt64(val.(int64)) + case reflect.Uint: + return WrapUint64(uint64(val.(uint))) + case reflect.Uint8: + return WrapUint32(uint32(val.(uint8))) + case reflect.Uint16: + return WrapUint32(uint32(val.(uint16))) + case reflect.Uint32: + return WrapUint32(uint32(val.(uint32))) + case reflect.Uint64: + return WrapUint64(val.(uint64)) + case reflect.Float32: + return WrapFloat64(float64(val.(float32))) + case reflect.Float64: + return WrapFloat64(val.(float64)) + case reflect.Bool: + if val.(bool) == true { + return &trueAny{} + } + return &falseAny{} + } + return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", typ)} +} + +// ReadAny read next JSON element as an Any object. It is a better json.RawMessage. +func (iter *Iterator) ReadAny() Any { + return iter.readAny() +} + +func (iter *Iterator) readAny() Any { + c := iter.nextToken() + switch c { + case '"': + iter.unreadByte() + return &stringAny{baseAny{}, iter.ReadString()} + case 'n': + iter.skipThreeBytes('u', 'l', 'l') // null + return &nilAny{} + case 't': + iter.skipThreeBytes('r', 'u', 'e') // true + return &trueAny{} + case 'f': + iter.skipFourBytes('a', 'l', 's', 'e') // false + return &falseAny{} + case '{': + return iter.readObjectAny() + case '[': + return iter.readArrayAny() + case '-': + return iter.readNumberAny(false) + default: + return iter.readNumberAny(true) + } +} + +func (iter *Iterator) readNumberAny(positive bool) Any { + iter.startCapture(iter.head - 1) + iter.skipNumber() + lazyBuf := iter.stopCapture() + return &numberLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} +} + +func (iter *Iterator) readObjectAny() Any { + iter.startCapture(iter.head - 1) + iter.skipObject() + lazyBuf := iter.stopCapture() + return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} +} + +func (iter *Iterator) readArrayAny() Any { + iter.startCapture(iter.head - 1) + iter.skipArray() + lazyBuf := iter.stopCapture() + return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} +} + +func locateObjectField(iter *Iterator, target string) []byte { + var found []byte + iter.ReadObjectCB(func(iter *Iterator, field string) bool { + if field == target { + found = iter.SkipAndReturnBytes() + return false + } + iter.Skip() + return true + }) + return found +} + +func locateArrayElement(iter *Iterator, target int) []byte { + var found []byte + n := 0 + iter.ReadArrayCB(func(iter *Iterator) bool { + if n == target { + found = iter.SkipAndReturnBytes() + return false + } + iter.Skip() + n++ + return true + }) + return found +} + +func locatePath(iter *Iterator, path []interface{}) Any { + for i, pathKeyObj := range path { + switch pathKey := pathKeyObj.(type) { + case string: + valueBytes := locateObjectField(iter, pathKey) + if valueBytes == nil { + return newInvalidAny(path[i:]) + } + iter.ResetBytes(valueBytes) + case int: + valueBytes := locateArrayElement(iter, pathKey) + if valueBytes == nil { + return newInvalidAny(path[i:]) + } + iter.ResetBytes(valueBytes) + case int32: + if '*' == pathKey { + return iter.readAny().Get(path[i:]...) + } + return newInvalidAny(path[i:]) + default: + return newInvalidAny(path[i:]) + } + } + if iter.Error != nil && iter.Error != io.EOF { + return &invalidAny{baseAny{}, iter.Error} + } + return iter.readAny() +} diff --git a/vendor/github.com/json-iterator/go/feature_any_array.go b/vendor/github.com/json-iterator/go/feature_any_array.go new file mode 100644 index 000000000..0449e9aa4 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_array.go @@ -0,0 +1,278 @@ +package jsoniter + +import ( + "reflect" + "unsafe" +) + +type arrayLazyAny struct { + baseAny + cfg *frozenConfig + buf []byte + err error +} + +func (any *arrayLazyAny) ValueType() ValueType { + return ArrayValue +} + +func (any *arrayLazyAny) MustBeValid() Any { + return any +} + +func (any *arrayLazyAny) LastError() error { + return any.err +} + +func (any *arrayLazyAny) ToBool() bool { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.ReadArray() +} + +func (any *arrayLazyAny) ToInt() int { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToInt32() int32 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToInt64() int64 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToUint() uint { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToUint32() uint32 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToUint64() uint64 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToFloat32() float32 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToFloat64() float64 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToString() string { + return *(*string)(unsafe.Pointer(&any.buf)) +} + +func (any *arrayLazyAny) ToVal(val interface{}) { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadVal(val) +} + +func (any *arrayLazyAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case int: + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + valueBytes := locateArrayElement(iter, firstPath) + if valueBytes == nil { + return newInvalidAny(path) + } + iter.ResetBytes(valueBytes) + return locatePath(iter, path[1:]) + case int32: + if '*' == firstPath { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + arr := make([]Any, 0) + iter.ReadArrayCB(func(iter *Iterator) bool { + found := iter.readAny().Get(path[1:]...) + if found.ValueType() != InvalidValue { + arr = append(arr, found) + } + return true + }) + return wrapArray(arr) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *arrayLazyAny) Size() int { + size := 0 + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadArrayCB(func(iter *Iterator) bool { + size++ + iter.Skip() + return true + }) + return size +} + +func (any *arrayLazyAny) WriteTo(stream *Stream) { + stream.Write(any.buf) +} + +func (any *arrayLazyAny) GetInterface() interface{} { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.Read() +} + +type arrayAny struct { + baseAny + val reflect.Value +} + +func wrapArray(val interface{}) *arrayAny { + return &arrayAny{baseAny{}, reflect.ValueOf(val)} +} + +func (any *arrayAny) ValueType() ValueType { + return ArrayValue +} + +func (any *arrayAny) MustBeValid() Any { + return any +} + +func (any *arrayAny) LastError() error { + return nil +} + +func (any *arrayAny) ToBool() bool { + return any.val.Len() != 0 +} + +func (any *arrayAny) ToInt() int { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToInt32() int32 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToInt64() int64 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToUint() uint { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToUint32() uint32 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToUint64() uint64 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToFloat32() float32 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToFloat64() float64 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToString() string { + str, _ := MarshalToString(any.val.Interface()) + return str +} + +func (any *arrayAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case int: + if firstPath < 0 || firstPath >= any.val.Len() { + return newInvalidAny(path) + } + return Wrap(any.val.Index(firstPath).Interface()) + case int32: + if '*' == firstPath { + mappedAll := make([]Any, 0) + for i := 0; i < any.val.Len(); i++ { + mapped := Wrap(any.val.Index(i).Interface()).Get(path[1:]...) + if mapped.ValueType() != InvalidValue { + mappedAll = append(mappedAll, mapped) + } + } + return wrapArray(mappedAll) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *arrayAny) Size() int { + return any.val.Len() +} + +func (any *arrayAny) WriteTo(stream *Stream) { + stream.WriteVal(any.val) +} + +func (any *arrayAny) GetInterface() interface{} { + return any.val.Interface() +} diff --git a/vendor/github.com/json-iterator/go/feature_any_bool.go b/vendor/github.com/json-iterator/go/feature_any_bool.go new file mode 100644 index 000000000..9452324af --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_bool.go @@ -0,0 +1,137 @@ +package jsoniter + +type trueAny struct { + baseAny +} + +func (any *trueAny) LastError() error { + return nil +} + +func (any *trueAny) ToBool() bool { + return true +} + +func (any *trueAny) ToInt() int { + return 1 +} + +func (any *trueAny) ToInt32() int32 { + return 1 +} + +func (any *trueAny) ToInt64() int64 { + return 1 +} + +func (any *trueAny) ToUint() uint { + return 1 +} + +func (any *trueAny) ToUint32() uint32 { + return 1 +} + +func (any *trueAny) ToUint64() uint64 { + return 1 +} + +func (any *trueAny) ToFloat32() float32 { + return 1 +} + +func (any *trueAny) ToFloat64() float64 { + return 1 +} + +func (any *trueAny) ToString() string { + return "true" +} + +func (any *trueAny) WriteTo(stream *Stream) { + stream.WriteTrue() +} + +func (any *trueAny) Parse() *Iterator { + return nil +} + +func (any *trueAny) GetInterface() interface{} { + return true +} + +func (any *trueAny) ValueType() ValueType { + return BoolValue +} + +func (any *trueAny) MustBeValid() Any { + return any +} + +type falseAny struct { + baseAny +} + +func (any *falseAny) LastError() error { + return nil +} + +func (any *falseAny) ToBool() bool { + return false +} + +func (any *falseAny) ToInt() int { + return 0 +} + +func (any *falseAny) ToInt32() int32 { + return 0 +} + +func (any *falseAny) ToInt64() int64 { + return 0 +} + +func (any *falseAny) ToUint() uint { + return 0 +} + +func (any *falseAny) ToUint32() uint32 { + return 0 +} + +func (any *falseAny) ToUint64() uint64 { + return 0 +} + +func (any *falseAny) ToFloat32() float32 { + return 0 +} + +func (any *falseAny) ToFloat64() float64 { + return 0 +} + +func (any *falseAny) ToString() string { + return "false" +} + +func (any *falseAny) WriteTo(stream *Stream) { + stream.WriteFalse() +} + +func (any *falseAny) Parse() *Iterator { + return nil +} + +func (any *falseAny) GetInterface() interface{} { + return false +} + +func (any *falseAny) ValueType() ValueType { + return BoolValue +} + +func (any *falseAny) MustBeValid() Any { + return any +} diff --git a/vendor/github.com/json-iterator/go/feature_any_float.go b/vendor/github.com/json-iterator/go/feature_any_float.go new file mode 100644 index 000000000..35fdb0949 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_float.go @@ -0,0 +1,83 @@ +package jsoniter + +import ( + "strconv" +) + +type floatAny struct { + baseAny + val float64 +} + +func (any *floatAny) Parse() *Iterator { + return nil +} + +func (any *floatAny) ValueType() ValueType { + return NumberValue +} + +func (any *floatAny) MustBeValid() Any { + return any +} + +func (any *floatAny) LastError() error { + return nil +} + +func (any *floatAny) ToBool() bool { + return any.ToFloat64() != 0 +} + +func (any *floatAny) ToInt() int { + return int(any.val) +} + +func (any *floatAny) ToInt32() int32 { + return int32(any.val) +} + +func (any *floatAny) ToInt64() int64 { + return int64(any.val) +} + +func (any *floatAny) ToUint() uint { + if any.val > 0 { + return uint(any.val) + } + return 0 +} + +func (any *floatAny) ToUint32() uint32 { + if any.val > 0 { + return uint32(any.val) + } + return 0 +} + +func (any *floatAny) ToUint64() uint64 { + if any.val > 0 { + return uint64(any.val) + } + return 0 +} + +func (any *floatAny) ToFloat32() float32 { + return float32(any.val) +} + +func (any *floatAny) ToFloat64() float64 { + return any.val +} + +func (any *floatAny) ToString() string { + return strconv.FormatFloat(any.val, 'E', -1, 64) +} + +func (any *floatAny) WriteTo(stream *Stream) { + stream.WriteFloat64(any.val) +} + +func (any *floatAny) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/feature_any_int32.go b/vendor/github.com/json-iterator/go/feature_any_int32.go new file mode 100644 index 000000000..1b56f3991 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_int32.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type int32Any struct { + baseAny + val int32 +} + +func (any *int32Any) LastError() error { + return nil +} + +func (any *int32Any) ValueType() ValueType { + return NumberValue +} + +func (any *int32Any) MustBeValid() Any { + return any +} + +func (any *int32Any) ToBool() bool { + return any.val != 0 +} + +func (any *int32Any) ToInt() int { + return int(any.val) +} + +func (any *int32Any) ToInt32() int32 { + return any.val +} + +func (any *int32Any) ToInt64() int64 { + return int64(any.val) +} + +func (any *int32Any) ToUint() uint { + return uint(any.val) +} + +func (any *int32Any) ToUint32() uint32 { + return uint32(any.val) +} + +func (any *int32Any) ToUint64() uint64 { + return uint64(any.val) +} + +func (any *int32Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *int32Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *int32Any) ToString() string { + return strconv.FormatInt(int64(any.val), 10) +} + +func (any *int32Any) WriteTo(stream *Stream) { + stream.WriteInt32(any.val) +} + +func (any *int32Any) Parse() *Iterator { + return nil +} + +func (any *int32Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/feature_any_int64.go b/vendor/github.com/json-iterator/go/feature_any_int64.go new file mode 100644 index 000000000..c440d72b6 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_int64.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type int64Any struct { + baseAny + val int64 +} + +func (any *int64Any) LastError() error { + return nil +} + +func (any *int64Any) ValueType() ValueType { + return NumberValue +} + +func (any *int64Any) MustBeValid() Any { + return any +} + +func (any *int64Any) ToBool() bool { + return any.val != 0 +} + +func (any *int64Any) ToInt() int { + return int(any.val) +} + +func (any *int64Any) ToInt32() int32 { + return int32(any.val) +} + +func (any *int64Any) ToInt64() int64 { + return any.val +} + +func (any *int64Any) ToUint() uint { + return uint(any.val) +} + +func (any *int64Any) ToUint32() uint32 { + return uint32(any.val) +} + +func (any *int64Any) ToUint64() uint64 { + return uint64(any.val) +} + +func (any *int64Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *int64Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *int64Any) ToString() string { + return strconv.FormatInt(any.val, 10) +} + +func (any *int64Any) WriteTo(stream *Stream) { + stream.WriteInt64(any.val) +} + +func (any *int64Any) Parse() *Iterator { + return nil +} + +func (any *int64Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/feature_any_invalid.go b/vendor/github.com/json-iterator/go/feature_any_invalid.go new file mode 100644 index 000000000..1d859eac3 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_invalid.go @@ -0,0 +1,82 @@ +package jsoniter + +import "fmt" + +type invalidAny struct { + baseAny + err error +} + +func newInvalidAny(path []interface{}) *invalidAny { + return &invalidAny{baseAny{}, fmt.Errorf("%v not found", path)} +} + +func (any *invalidAny) LastError() error { + return any.err +} + +func (any *invalidAny) ValueType() ValueType { + return InvalidValue +} + +func (any *invalidAny) MustBeValid() Any { + panic(any.err) +} + +func (any *invalidAny) ToBool() bool { + return false +} + +func (any *invalidAny) ToInt() int { + return 0 +} + +func (any *invalidAny) ToInt32() int32 { + return 0 +} + +func (any *invalidAny) ToInt64() int64 { + return 0 +} + +func (any *invalidAny) ToUint() uint { + return 0 +} + +func (any *invalidAny) ToUint32() uint32 { + return 0 +} + +func (any *invalidAny) ToUint64() uint64 { + return 0 +} + +func (any *invalidAny) ToFloat32() float32 { + return 0 +} + +func (any *invalidAny) ToFloat64() float64 { + return 0 +} + +func (any *invalidAny) ToString() string { + return "" +} + +func (any *invalidAny) WriteTo(stream *Stream) { +} + +func (any *invalidAny) Get(path ...interface{}) Any { + if any.err == nil { + return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)} + } + return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)} +} + +func (any *invalidAny) Parse() *Iterator { + return nil +} + +func (any *invalidAny) GetInterface() interface{} { + return nil +} diff --git a/vendor/github.com/json-iterator/go/feature_any_nil.go b/vendor/github.com/json-iterator/go/feature_any_nil.go new file mode 100644 index 000000000..d04cb54c1 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_nil.go @@ -0,0 +1,69 @@ +package jsoniter + +type nilAny struct { + baseAny +} + +func (any *nilAny) LastError() error { + return nil +} + +func (any *nilAny) ValueType() ValueType { + return NilValue +} + +func (any *nilAny) MustBeValid() Any { + return any +} + +func (any *nilAny) ToBool() bool { + return false +} + +func (any *nilAny) ToInt() int { + return 0 +} + +func (any *nilAny) ToInt32() int32 { + return 0 +} + +func (any *nilAny) ToInt64() int64 { + return 0 +} + +func (any *nilAny) ToUint() uint { + return 0 +} + +func (any *nilAny) ToUint32() uint32 { + return 0 +} + +func (any *nilAny) ToUint64() uint64 { + return 0 +} + +func (any *nilAny) ToFloat32() float32 { + return 0 +} + +func (any *nilAny) ToFloat64() float64 { + return 0 +} + +func (any *nilAny) ToString() string { + return "" +} + +func (any *nilAny) WriteTo(stream *Stream) { + stream.WriteNil() +} + +func (any *nilAny) Parse() *Iterator { + return nil +} + +func (any *nilAny) GetInterface() interface{} { + return nil +} diff --git a/vendor/github.com/json-iterator/go/feature_any_number.go b/vendor/github.com/json-iterator/go/feature_any_number.go new file mode 100644 index 000000000..4e1c27641 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_number.go @@ -0,0 +1,104 @@ +package jsoniter + +import "unsafe" + +type numberLazyAny struct { + baseAny + cfg *frozenConfig + buf []byte + err error +} + +func (any *numberLazyAny) ValueType() ValueType { + return NumberValue +} + +func (any *numberLazyAny) MustBeValid() Any { + return any +} + +func (any *numberLazyAny) LastError() error { + return any.err +} + +func (any *numberLazyAny) ToBool() bool { + return any.ToFloat64() != 0 +} + +func (any *numberLazyAny) ToInt() int { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadInt() + any.err = iter.Error + return val +} + +func (any *numberLazyAny) ToInt32() int32 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadInt32() + any.err = iter.Error + return val +} + +func (any *numberLazyAny) ToInt64() int64 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadInt64() + any.err = iter.Error + return val +} + +func (any *numberLazyAny) ToUint() uint { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadUint() + any.err = iter.Error + return val +} + +func (any *numberLazyAny) ToUint32() uint32 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadUint32() + any.err = iter.Error + return val +} + +func (any *numberLazyAny) ToUint64() uint64 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadUint64() + any.err = iter.Error + return val +} + +func (any *numberLazyAny) ToFloat32() float32 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadFloat32() + any.err = iter.Error + return val +} + +func (any *numberLazyAny) ToFloat64() float64 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadFloat64() + any.err = iter.Error + return val +} + +func (any *numberLazyAny) ToString() string { + return *(*string)(unsafe.Pointer(&any.buf)) +} + +func (any *numberLazyAny) WriteTo(stream *Stream) { + stream.Write(any.buf) +} + +func (any *numberLazyAny) GetInterface() interface{} { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.Read() +} diff --git a/vendor/github.com/json-iterator/go/feature_any_object.go b/vendor/github.com/json-iterator/go/feature_any_object.go new file mode 100644 index 000000000..c44ef5c98 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_object.go @@ -0,0 +1,374 @@ +package jsoniter + +import ( + "reflect" + "unsafe" +) + +type objectLazyAny struct { + baseAny + cfg *frozenConfig + buf []byte + err error +} + +func (any *objectLazyAny) ValueType() ValueType { + return ObjectValue +} + +func (any *objectLazyAny) MustBeValid() Any { + return any +} + +func (any *objectLazyAny) LastError() error { + return any.err +} + +func (any *objectLazyAny) ToBool() bool { + return true +} + +func (any *objectLazyAny) ToInt() int { + return 0 +} + +func (any *objectLazyAny) ToInt32() int32 { + return 0 +} + +func (any *objectLazyAny) ToInt64() int64 { + return 0 +} + +func (any *objectLazyAny) ToUint() uint { + return 0 +} + +func (any *objectLazyAny) ToUint32() uint32 { + return 0 +} + +func (any *objectLazyAny) ToUint64() uint64 { + return 0 +} + +func (any *objectLazyAny) ToFloat32() float32 { + return 0 +} + +func (any *objectLazyAny) ToFloat64() float64 { + return 0 +} + +func (any *objectLazyAny) ToString() string { + return *(*string)(unsafe.Pointer(&any.buf)) +} + +func (any *objectLazyAny) ToVal(obj interface{}) { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadVal(obj) +} + +func (any *objectLazyAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case string: + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + valueBytes := locateObjectField(iter, firstPath) + if valueBytes == nil { + return newInvalidAny(path) + } + iter.ResetBytes(valueBytes) + return locatePath(iter, path[1:]) + case int32: + if '*' == firstPath { + mappedAll := map[string]Any{} + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadMapCB(func(iter *Iterator, field string) bool { + mapped := locatePath(iter, path[1:]) + if mapped.ValueType() != InvalidValue { + mappedAll[field] = mapped + } + return true + }) + return wrapMap(mappedAll) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *objectLazyAny) Keys() []string { + keys := []string{} + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadMapCB(func(iter *Iterator, field string) bool { + iter.Skip() + keys = append(keys, field) + return true + }) + return keys +} + +func (any *objectLazyAny) Size() int { + size := 0 + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadObjectCB(func(iter *Iterator, field string) bool { + iter.Skip() + size++ + return true + }) + return size +} + +func (any *objectLazyAny) WriteTo(stream *Stream) { + stream.Write(any.buf) +} + +func (any *objectLazyAny) GetInterface() interface{} { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.Read() +} + +type objectAny struct { + baseAny + err error + val reflect.Value +} + +func wrapStruct(val interface{}) *objectAny { + return &objectAny{baseAny{}, nil, reflect.ValueOf(val)} +} + +func (any *objectAny) ValueType() ValueType { + return ObjectValue +} + +func (any *objectAny) MustBeValid() Any { + return any +} + +func (any *objectAny) Parse() *Iterator { + return nil +} + +func (any *objectAny) LastError() error { + return any.err +} + +func (any *objectAny) ToBool() bool { + return any.val.NumField() != 0 +} + +func (any *objectAny) ToInt() int { + return 0 +} + +func (any *objectAny) ToInt32() int32 { + return 0 +} + +func (any *objectAny) ToInt64() int64 { + return 0 +} + +func (any *objectAny) ToUint() uint { + return 0 +} + +func (any *objectAny) ToUint32() uint32 { + return 0 +} + +func (any *objectAny) ToUint64() uint64 { + return 0 +} + +func (any *objectAny) ToFloat32() float32 { + return 0 +} + +func (any *objectAny) ToFloat64() float64 { + return 0 +} + +func (any *objectAny) ToString() string { + str, err := MarshalToString(any.val.Interface()) + any.err = err + return str +} + +func (any *objectAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case string: + field := any.val.FieldByName(firstPath) + if !field.IsValid() { + return newInvalidAny(path) + } + return Wrap(field.Interface()) + case int32: + if '*' == firstPath { + mappedAll := map[string]Any{} + for i := 0; i < any.val.NumField(); i++ { + field := any.val.Field(i) + if field.CanInterface() { + mapped := Wrap(field.Interface()).Get(path[1:]...) + if mapped.ValueType() != InvalidValue { + mappedAll[any.val.Type().Field(i).Name] = mapped + } + } + } + return wrapMap(mappedAll) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *objectAny) Keys() []string { + keys := make([]string, 0, any.val.NumField()) + for i := 0; i < any.val.NumField(); i++ { + keys = append(keys, any.val.Type().Field(i).Name) + } + return keys +} + +func (any *objectAny) Size() int { + return any.val.NumField() +} + +func (any *objectAny) WriteTo(stream *Stream) { + stream.WriteVal(any.val) +} + +func (any *objectAny) GetInterface() interface{} { + return any.val.Interface() +} + +type mapAny struct { + baseAny + err error + val reflect.Value +} + +func wrapMap(val interface{}) *mapAny { + return &mapAny{baseAny{}, nil, reflect.ValueOf(val)} +} + +func (any *mapAny) ValueType() ValueType { + return ObjectValue +} + +func (any *mapAny) MustBeValid() Any { + return any +} + +func (any *mapAny) Parse() *Iterator { + return nil +} + +func (any *mapAny) LastError() error { + return any.err +} + +func (any *mapAny) ToBool() bool { + return true +} + +func (any *mapAny) ToInt() int { + return 0 +} + +func (any *mapAny) ToInt32() int32 { + return 0 +} + +func (any *mapAny) ToInt64() int64 { + return 0 +} + +func (any *mapAny) ToUint() uint { + return 0 +} + +func (any *mapAny) ToUint32() uint32 { + return 0 +} + +func (any *mapAny) ToUint64() uint64 { + return 0 +} + +func (any *mapAny) ToFloat32() float32 { + return 0 +} + +func (any *mapAny) ToFloat64() float64 { + return 0 +} + +func (any *mapAny) ToString() string { + str, err := MarshalToString(any.val.Interface()) + any.err = err + return str +} + +func (any *mapAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case int32: + if '*' == firstPath { + mappedAll := map[string]Any{} + for _, key := range any.val.MapKeys() { + keyAsStr := key.String() + element := Wrap(any.val.MapIndex(key).Interface()) + mapped := element.Get(path[1:]...) + if mapped.ValueType() != InvalidValue { + mappedAll[keyAsStr] = mapped + } + } + return wrapMap(mappedAll) + } + return newInvalidAny(path) + default: + value := any.val.MapIndex(reflect.ValueOf(firstPath)) + if !value.IsValid() { + return newInvalidAny(path) + } + return Wrap(value.Interface()) + } +} + +func (any *mapAny) Keys() []string { + keys := make([]string, 0, any.val.Len()) + for _, key := range any.val.MapKeys() { + keys = append(keys, key.String()) + } + return keys +} + +func (any *mapAny) Size() int { + return any.val.Len() +} + +func (any *mapAny) WriteTo(stream *Stream) { + stream.WriteVal(any.val) +} + +func (any *mapAny) GetInterface() interface{} { + return any.val.Interface() +} diff --git a/vendor/github.com/json-iterator/go/feature_any_string.go b/vendor/github.com/json-iterator/go/feature_any_string.go new file mode 100644 index 000000000..abf060bd5 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_string.go @@ -0,0 +1,166 @@ +package jsoniter + +import ( + "fmt" + "strconv" +) + +type stringAny struct { + baseAny + val string +} + +func (any *stringAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + return &invalidAny{baseAny{}, fmt.Errorf("Get %v from simple value", path)} +} + +func (any *stringAny) Parse() *Iterator { + return nil +} + +func (any *stringAny) ValueType() ValueType { + return StringValue +} + +func (any *stringAny) MustBeValid() Any { + return any +} + +func (any *stringAny) LastError() error { + return nil +} + +func (any *stringAny) ToBool() bool { + str := any.ToString() + if str == "0" { + return false + } + for _, c := range str { + switch c { + case ' ', '\n', '\r', '\t': + default: + return true + } + } + return false +} + +func (any *stringAny) ToInt() int { + return int(any.ToInt64()) + +} + +func (any *stringAny) ToInt32() int32 { + return int32(any.ToInt64()) +} + +func (any *stringAny) ToInt64() int64 { + if any.val == "" { + return 0 + } + + flag := 1 + startPos := 0 + endPos := 0 + if any.val[0] == '+' || any.val[0] == '-' { + startPos = 1 + } + + if any.val[0] == '-' { + flag = -1 + } + + for i := startPos; i < len(any.val); i++ { + if any.val[i] >= '0' && any.val[i] <= '9' { + endPos = i + 1 + } else { + break + } + } + parsed, _ := strconv.ParseInt(any.val[startPos:endPos], 10, 64) + return int64(flag) * parsed +} + +func (any *stringAny) ToUint() uint { + return uint(any.ToUint64()) +} + +func (any *stringAny) ToUint32() uint32 { + return uint32(any.ToUint64()) +} + +func (any *stringAny) ToUint64() uint64 { + if any.val == "" { + return 0 + } + + startPos := 0 + endPos := 0 + + if any.val[0] == '-' { + return 0 + } + if any.val[0] == '+' { + startPos = 1 + } + + for i := startPos; i < len(any.val); i++ { + if any.val[i] >= '0' && any.val[i] <= '9' { + endPos = i + 1 + } else { + break + } + } + parsed, _ := strconv.ParseUint(any.val[startPos:endPos], 10, 64) + return parsed +} + +func (any *stringAny) ToFloat32() float32 { + return float32(any.ToFloat64()) +} + +func (any *stringAny) ToFloat64() float64 { + if len(any.val) == 0 { + return 0 + } + + // first char invalid + if any.val[0] != '+' && any.val[0] != '-' && (any.val[0] > '9' || any.val[0] < '0') { + return 0 + } + + // extract valid num expression from string + // eg 123true => 123, -12.12xxa => -12.12 + endPos := 1 + for i := 1; i < len(any.val); i++ { + if any.val[i] == '.' || any.val[i] == 'e' || any.val[i] == 'E' || any.val[i] == '+' || any.val[i] == '-' { + endPos = i + 1 + continue + } + + // end position is the first char which is not digit + if any.val[i] >= '0' && any.val[i] <= '9' { + endPos = i + 1 + } else { + endPos = i + break + } + } + parsed, _ := strconv.ParseFloat(any.val[:endPos], 64) + return parsed +} + +func (any *stringAny) ToString() string { + return any.val +} + +func (any *stringAny) WriteTo(stream *Stream) { + stream.WriteString(any.val) +} + +func (any *stringAny) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/feature_any_uint32.go b/vendor/github.com/json-iterator/go/feature_any_uint32.go new file mode 100644 index 000000000..656bbd33d --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_uint32.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type uint32Any struct { + baseAny + val uint32 +} + +func (any *uint32Any) LastError() error { + return nil +} + +func (any *uint32Any) ValueType() ValueType { + return NumberValue +} + +func (any *uint32Any) MustBeValid() Any { + return any +} + +func (any *uint32Any) ToBool() bool { + return any.val != 0 +} + +func (any *uint32Any) ToInt() int { + return int(any.val) +} + +func (any *uint32Any) ToInt32() int32 { + return int32(any.val) +} + +func (any *uint32Any) ToInt64() int64 { + return int64(any.val) +} + +func (any *uint32Any) ToUint() uint { + return uint(any.val) +} + +func (any *uint32Any) ToUint32() uint32 { + return any.val +} + +func (any *uint32Any) ToUint64() uint64 { + return uint64(any.val) +} + +func (any *uint32Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *uint32Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *uint32Any) ToString() string { + return strconv.FormatInt(int64(any.val), 10) +} + +func (any *uint32Any) WriteTo(stream *Stream) { + stream.WriteUint32(any.val) +} + +func (any *uint32Any) Parse() *Iterator { + return nil +} + +func (any *uint32Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/feature_any_uint64.go b/vendor/github.com/json-iterator/go/feature_any_uint64.go new file mode 100644 index 000000000..7df2fce33 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_any_uint64.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type uint64Any struct { + baseAny + val uint64 +} + +func (any *uint64Any) LastError() error { + return nil +} + +func (any *uint64Any) ValueType() ValueType { + return NumberValue +} + +func (any *uint64Any) MustBeValid() Any { + return any +} + +func (any *uint64Any) ToBool() bool { + return any.val != 0 +} + +func (any *uint64Any) ToInt() int { + return int(any.val) +} + +func (any *uint64Any) ToInt32() int32 { + return int32(any.val) +} + +func (any *uint64Any) ToInt64() int64 { + return int64(any.val) +} + +func (any *uint64Any) ToUint() uint { + return uint(any.val) +} + +func (any *uint64Any) ToUint32() uint32 { + return uint32(any.val) +} + +func (any *uint64Any) ToUint64() uint64 { + return any.val +} + +func (any *uint64Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *uint64Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *uint64Any) ToString() string { + return strconv.FormatUint(any.val, 10) +} + +func (any *uint64Any) WriteTo(stream *Stream) { + stream.WriteUint64(any.val) +} + +func (any *uint64Any) Parse() *Iterator { + return nil +} + +func (any *uint64Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/feature_config.go b/vendor/github.com/json-iterator/go/feature_config.go new file mode 100644 index 000000000..fc055d504 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_config.go @@ -0,0 +1,312 @@ +package jsoniter + +import ( + "encoding/json" + "errors" + "io" + "reflect" + "sync/atomic" + "unsafe" +) + +// Config customize how the API should behave. +// The API is created from Config by Froze. +type Config struct { + IndentionStep int + MarshalFloatWith6Digits bool + EscapeHTML bool + SortMapKeys bool + UseNumber bool + TagKey string +} + +type frozenConfig struct { + configBeforeFrozen Config + sortMapKeys bool + indentionStep int + decoderCache unsafe.Pointer + encoderCache unsafe.Pointer + extensions []Extension + streamPool chan *Stream + iteratorPool chan *Iterator +} + +// API the public interface of this package. +// Primary Marshal and Unmarshal. +type API interface { + IteratorPool + StreamPool + MarshalToString(v interface{}) (string, error) + Marshal(v interface{}) ([]byte, error) + MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) + UnmarshalFromString(str string, v interface{}) error + Unmarshal(data []byte, v interface{}) error + Get(data []byte, path ...interface{}) Any + NewEncoder(writer io.Writer) *Encoder + NewDecoder(reader io.Reader) *Decoder +} + +// ConfigDefault the default API +var ConfigDefault = Config{ + EscapeHTML: true, +}.Froze() + +// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior +var ConfigCompatibleWithStandardLibrary = Config{ + EscapeHTML: true, + SortMapKeys: true, +}.Froze() + +// ConfigFastest marshals float with only 6 digits precision +var ConfigFastest = Config{ + EscapeHTML: false, + MarshalFloatWith6Digits: true, +}.Froze() + +// Froze forge API from config +func (cfg Config) Froze() API { + // TODO: cache frozen config + frozenConfig := &frozenConfig{ + sortMapKeys: cfg.SortMapKeys, + indentionStep: cfg.IndentionStep, + streamPool: make(chan *Stream, 16), + iteratorPool: make(chan *Iterator, 16), + } + atomic.StorePointer(&frozenConfig.decoderCache, unsafe.Pointer(&map[string]ValDecoder{})) + atomic.StorePointer(&frozenConfig.encoderCache, unsafe.Pointer(&map[string]ValEncoder{})) + if cfg.MarshalFloatWith6Digits { + frozenConfig.marshalFloatWith6Digits() + } + if cfg.EscapeHTML { + frozenConfig.escapeHTML() + } + if cfg.UseNumber { + frozenConfig.useNumber() + } + frozenConfig.configBeforeFrozen = cfg + return frozenConfig +} + +func (cfg *frozenConfig) useNumber() { + cfg.addDecoderToCache(reflect.TypeOf((*interface{})(nil)).Elem(), &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { + if iter.WhatIsNext() == NumberValue { + *((*interface{})(ptr)) = json.Number(iter.readNumberAsString()) + } else { + *((*interface{})(ptr)) = iter.Read() + } + }}) +} +func (cfg *frozenConfig) getTagKey() string { + tagKey := cfg.configBeforeFrozen.TagKey + if tagKey == "" { + return "json" + } + return tagKey +} + +func (cfg *frozenConfig) registerExtension(extension Extension) { + cfg.extensions = append(cfg.extensions, extension) +} + +type lossyFloat32Encoder struct { +} + +func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat32Lossy(*((*float32)(ptr))) +} + +func (encoder *lossyFloat32Encoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float32)(ptr)) == 0 +} + +type lossyFloat64Encoder struct { +} + +func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat64Lossy(*((*float64)(ptr))) +} + +func (encoder *lossyFloat64Encoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float64)(ptr)) == 0 +} + +// EnableLossyFloatMarshalling keeps 10**(-6) precision +// for float variables for better performance. +func (cfg *frozenConfig) marshalFloatWith6Digits() { + // for better performance + cfg.addEncoderToCache(reflect.TypeOf((*float32)(nil)).Elem(), &lossyFloat32Encoder{}) + cfg.addEncoderToCache(reflect.TypeOf((*float64)(nil)).Elem(), &lossyFloat64Encoder{}) +} + +type htmlEscapedStringEncoder struct { +} + +func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + str := *((*string)(ptr)) + stream.WriteStringWithHTMLEscaped(str) +} + +func (encoder *htmlEscapedStringEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*string)(ptr)) == "" +} + +func (cfg *frozenConfig) escapeHTML() { + cfg.addEncoderToCache(reflect.TypeOf((*string)(nil)).Elem(), &htmlEscapedStringEncoder{}) +} + +func (cfg *frozenConfig) addDecoderToCache(cacheKey reflect.Type, decoder ValDecoder) { + done := false + for !done { + ptr := atomic.LoadPointer(&cfg.decoderCache) + cache := *(*map[reflect.Type]ValDecoder)(ptr) + copied := map[reflect.Type]ValDecoder{} + for k, v := range cache { + copied[k] = v + } + copied[cacheKey] = decoder + done = atomic.CompareAndSwapPointer(&cfg.decoderCache, ptr, unsafe.Pointer(&copied)) + } +} + +func (cfg *frozenConfig) addEncoderToCache(cacheKey reflect.Type, encoder ValEncoder) { + done := false + for !done { + ptr := atomic.LoadPointer(&cfg.encoderCache) + cache := *(*map[reflect.Type]ValEncoder)(ptr) + copied := map[reflect.Type]ValEncoder{} + for k, v := range cache { + copied[k] = v + } + copied[cacheKey] = encoder + done = atomic.CompareAndSwapPointer(&cfg.encoderCache, ptr, unsafe.Pointer(&copied)) + } +} + +func (cfg *frozenConfig) getDecoderFromCache(cacheKey reflect.Type) ValDecoder { + ptr := atomic.LoadPointer(&cfg.decoderCache) + cache := *(*map[reflect.Type]ValDecoder)(ptr) + return cache[cacheKey] +} + +func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder { + ptr := atomic.LoadPointer(&cfg.encoderCache) + cache := *(*map[reflect.Type]ValEncoder)(ptr) + return cache[cacheKey] +} + +func (cfg *frozenConfig) cleanDecoders() { + typeDecoders = map[string]ValDecoder{} + fieldDecoders = map[string]ValDecoder{} + *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) +} + +func (cfg *frozenConfig) cleanEncoders() { + typeEncoders = map[string]ValEncoder{} + fieldEncoders = map[string]ValEncoder{} + *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) +} + +func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) { + stream := cfg.BorrowStream(nil) + defer cfg.ReturnStream(stream) + stream.WriteVal(v) + if stream.Error != nil { + return "", stream.Error + } + return string(stream.Buffer()), nil +} + +func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) { + stream := cfg.BorrowStream(nil) + defer cfg.ReturnStream(stream) + stream.WriteVal(v) + if stream.Error != nil { + return nil, stream.Error + } + result := stream.Buffer() + copied := make([]byte, len(result)) + copy(copied, result) + return copied, nil +} + +func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + if prefix != "" { + panic("prefix is not supported") + } + for _, r := range indent { + if r != ' ' { + panic("indent can only be space") + } + } + newCfg := cfg.configBeforeFrozen + newCfg.IndentionStep = len(indent) + return newCfg.Froze().Marshal(v) +} + +func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error { + data := []byte(str) + data = data[:lastNotSpacePos(data)] + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + iter.ReadVal(v) + if iter.head == iter.tail { + iter.loadMore() + } + if iter.Error == io.EOF { + return nil + } + if iter.Error == nil { + iter.ReportError("UnmarshalFromString", "there are bytes left after unmarshal") + } + return iter.Error +} + +func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any { + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + return locatePath(iter, path) +} + +func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error { + data = data[:lastNotSpacePos(data)] + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + typ := reflect.TypeOf(v) + if typ.Kind() != reflect.Ptr { + // return non-pointer error + return errors.New("the second param must be ptr type") + } + iter.ReadVal(v) + if iter.head == iter.tail { + iter.loadMore() + } + if iter.Error == io.EOF { + return nil + } + if iter.Error == nil { + iter.ReportError("Unmarshal", "there are bytes left after unmarshal") + } + return iter.Error +} + +func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder { + stream := NewStream(cfg, writer, 512) + return &Encoder{stream} +} + +func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder { + iter := Parse(cfg, reader, 512) + return &Decoder{iter} +} diff --git a/vendor/github.com/json-iterator/go/feature_iter.go b/vendor/github.com/json-iterator/go/feature_iter.go new file mode 100644 index 000000000..4357d69ba --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_iter.go @@ -0,0 +1,307 @@ +package jsoniter + +import ( + "encoding/json" + "fmt" + "io" +) + +// ValueType the type for JSON element +type ValueType int + +const ( + // InvalidValue invalid JSON element + InvalidValue ValueType = iota + // StringValue JSON element "string" + StringValue + // NumberValue JSON element 100 or 0.10 + NumberValue + // NilValue JSON element null + NilValue + // BoolValue JSON element true or false + BoolValue + // ArrayValue JSON element [] + ArrayValue + // ObjectValue JSON element {} + ObjectValue +) + +var hexDigits []byte +var valueTypes []ValueType + +func init() { + hexDigits = make([]byte, 256) + for i := 0; i < len(hexDigits); i++ { + hexDigits[i] = 255 + } + for i := '0'; i <= '9'; i++ { + hexDigits[i] = byte(i - '0') + } + for i := 'a'; i <= 'f'; i++ { + hexDigits[i] = byte((i - 'a') + 10) + } + for i := 'A'; i <= 'F'; i++ { + hexDigits[i] = byte((i - 'A') + 10) + } + valueTypes = make([]ValueType, 256) + for i := 0; i < len(valueTypes); i++ { + valueTypes[i] = InvalidValue + } + valueTypes['"'] = StringValue + valueTypes['-'] = NumberValue + valueTypes['0'] = NumberValue + valueTypes['1'] = NumberValue + valueTypes['2'] = NumberValue + valueTypes['3'] = NumberValue + valueTypes['4'] = NumberValue + valueTypes['5'] = NumberValue + valueTypes['6'] = NumberValue + valueTypes['7'] = NumberValue + valueTypes['8'] = NumberValue + valueTypes['9'] = NumberValue + valueTypes['t'] = BoolValue + valueTypes['f'] = BoolValue + valueTypes['n'] = NilValue + valueTypes['['] = ArrayValue + valueTypes['{'] = ObjectValue +} + +// Iterator is a io.Reader like object, with JSON specific read functions. +// Error is not returned as return value, but stored as Error member on this iterator instance. +type Iterator struct { + cfg *frozenConfig + reader io.Reader + buf []byte + head int + tail int + captureStartedAt int + captured []byte + Error error +} + +// NewIterator creates an empty Iterator instance +func NewIterator(cfg API) *Iterator { + return &Iterator{ + cfg: cfg.(*frozenConfig), + reader: nil, + buf: nil, + head: 0, + tail: 0, + } +} + +// Parse creates an Iterator instance from io.Reader +func Parse(cfg API, reader io.Reader, bufSize int) *Iterator { + return &Iterator{ + cfg: cfg.(*frozenConfig), + reader: reader, + buf: make([]byte, bufSize), + head: 0, + tail: 0, + } +} + +// ParseBytes creates an Iterator instance from byte array +func ParseBytes(cfg API, input []byte) *Iterator { + return &Iterator{ + cfg: cfg.(*frozenConfig), + reader: nil, + buf: input, + head: 0, + tail: len(input), + } +} + +// ParseString creates an Iterator instance from string +func ParseString(cfg API, input string) *Iterator { + return ParseBytes(cfg, []byte(input)) +} + +// Pool returns a pool can provide more iterator with same configuration +func (iter *Iterator) Pool() IteratorPool { + return iter.cfg +} + +// Reset reuse iterator instance by specifying another reader +func (iter *Iterator) Reset(reader io.Reader) *Iterator { + iter.reader = reader + iter.head = 0 + iter.tail = 0 + return iter +} + +// ResetBytes reuse iterator instance by specifying another byte array as input +func (iter *Iterator) ResetBytes(input []byte) *Iterator { + iter.reader = nil + iter.buf = input + iter.head = 0 + iter.tail = len(input) + return iter +} + +// WhatIsNext gets ValueType of relatively next json element +func (iter *Iterator) WhatIsNext() ValueType { + valueType := valueTypes[iter.nextToken()] + iter.unreadByte() + return valueType +} + +func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\t', '\r': + continue + } + iter.head = i + return false + } + return true +} + +func (iter *Iterator) isObjectEnd() bool { + c := iter.nextToken() + if c == ',' { + return false + } + if c == '}' { + return true + } + iter.ReportError("isObjectEnd", "object ended prematurely") + return true +} + +func (iter *Iterator) nextToken() byte { + // a variation of skip whitespaces, returning the next non-whitespace token + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\t', '\r': + continue + } + iter.head = i + 1 + return c + } + if !iter.loadMore() { + return 0 + } + } +} + +// ReportError record a error in iterator instance with current position. +func (iter *Iterator) ReportError(operation string, msg string) { + if iter.Error != nil { + if iter.Error != io.EOF { + return + } + } + peekStart := iter.head - 10 + if peekStart < 0 { + peekStart = 0 + } + iter.Error = fmt.Errorf("%s: %s, parsing %v ...%s... at %s", operation, msg, iter.head, + string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) +} + +// CurrentBuffer gets current buffer as string for debugging purpose +func (iter *Iterator) CurrentBuffer() string { + peekStart := iter.head - 10 + if peekStart < 0 { + peekStart = 0 + } + return fmt.Sprintf("parsing %v ...|%s|... at %s", iter.head, + string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) +} + +func (iter *Iterator) readByte() (ret byte) { + if iter.head == iter.tail { + if iter.loadMore() { + ret = iter.buf[iter.head] + iter.head++ + return ret + } + return 0 + } + ret = iter.buf[iter.head] + iter.head++ + return ret +} + +func (iter *Iterator) loadMore() bool { + if iter.reader == nil { + if iter.Error == nil { + iter.head = iter.tail + iter.Error = io.EOF + } + return false + } + if iter.captured != nil { + iter.captured = append(iter.captured, + iter.buf[iter.captureStartedAt:iter.tail]...) + iter.captureStartedAt = 0 + } + for { + n, err := iter.reader.Read(iter.buf) + if n == 0 { + if err != nil { + if iter.Error == nil { + iter.Error = err + } + return false + } + } else { + iter.head = 0 + iter.tail = n + return true + } + } +} + +func (iter *Iterator) unreadByte() { + if iter.Error != nil { + return + } + iter.head-- + return +} + +// Read read the next JSON element as generic interface{}. +func (iter *Iterator) Read() interface{} { + valueType := iter.WhatIsNext() + switch valueType { + case StringValue: + return iter.ReadString() + case NumberValue: + if iter.cfg.configBeforeFrozen.UseNumber { + return json.Number(iter.readNumberAsString()) + } + return iter.ReadFloat64() + case NilValue: + iter.skipFourBytes('n', 'u', 'l', 'l') + return nil + case BoolValue: + return iter.ReadBool() + case ArrayValue: + arr := []interface{}{} + iter.ReadArrayCB(func(iter *Iterator) bool { + var elem interface{} + iter.ReadVal(&elem) + arr = append(arr, elem) + return true + }) + return arr + case ObjectValue: + obj := map[string]interface{}{} + iter.ReadMapCB(func(Iter *Iterator, field string) bool { + var elem interface{} + iter.ReadVal(&elem) + obj[field] = elem + return true + }) + return obj + default: + iter.ReportError("Read", fmt.Sprintf("unexpected value type: %v", valueType)) + return nil + } +} diff --git a/vendor/github.com/json-iterator/go/feature_iter_array.go b/vendor/github.com/json-iterator/go/feature_iter_array.go new file mode 100644 index 000000000..cbc3ec8d1 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_iter_array.go @@ -0,0 +1,58 @@ +package jsoniter + +// ReadArray read array element, tells if the array has more element to read. +func (iter *Iterator) ReadArray() (ret bool) { + c := iter.nextToken() + switch c { + case 'n': + iter.skipThreeBytes('u', 'l', 'l') + return false // null + case '[': + c = iter.nextToken() + if c != ']' { + iter.unreadByte() + return true + } + return false + case ']': + return false + case ',': + return true + default: + iter.ReportError("ReadArray", "expect [ or , or ] or n, but found: "+string([]byte{c})) + return + } +} + +// ReadArrayCB read array with callback +func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) { + c := iter.nextToken() + if c == '[' { + c = iter.nextToken() + if c != ']' { + iter.unreadByte() + if !callback(iter) { + return false + } + c = iter.nextToken() + for c == ',' { + if !callback(iter) { + return false + } + c = iter.nextToken() + } + if c != ']' { + iter.ReportError("ReadArrayCB", "expect ] in the end") + return false + } + return true + } + return true + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.ReportError("ReadArrayCB", "expect [ or n, but found: "+string([]byte{c})) + return false +} diff --git a/vendor/github.com/json-iterator/go/feature_iter_float.go b/vendor/github.com/json-iterator/go/feature_iter_float.go new file mode 100644 index 000000000..86f459912 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_iter_float.go @@ -0,0 +1,341 @@ +package jsoniter + +import ( + "io" + "math/big" + "strconv" + "strings" + "unsafe" +) + +var floatDigits []int8 + +const invalidCharForNumber = int8(-1) +const endOfNumber = int8(-2) +const dotInNumber = int8(-3) + +func init() { + floatDigits = make([]int8, 256) + for i := 0; i < len(floatDigits); i++ { + floatDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + floatDigits[i] = i - int8('0') + } + floatDigits[','] = endOfNumber + floatDigits[']'] = endOfNumber + floatDigits['}'] = endOfNumber + floatDigits[' '] = endOfNumber + floatDigits['\t'] = endOfNumber + floatDigits['\n'] = endOfNumber + floatDigits['.'] = dotInNumber +} + +// ReadBigFloat read big.Float +func (iter *Iterator) ReadBigFloat() (ret *big.Float) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return nil + } + prec := 64 + if len(str) > prec { + prec = len(str) + } + val, _, err := big.ParseFloat(str, 10, uint(prec), big.ToZero) + if err != nil { + iter.Error = err + return nil + } + return val +} + +// ReadBigInt read big.Int +func (iter *Iterator) ReadBigInt() (ret *big.Int) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return nil + } + ret = big.NewInt(0) + var success bool + ret, success = ret.SetString(str, 10) + if !success { + iter.ReportError("ReadBigInt", "invalid big int") + return nil + } + return ret +} + +//ReadFloat32 read float32 +func (iter *Iterator) ReadFloat32() (ret float32) { + c := iter.nextToken() + if c == '-' { + return -iter.readPositiveFloat32() + } + iter.unreadByte() + return iter.readPositiveFloat32() +} + +func (iter *Iterator) readPositiveFloat32() (ret float32) { + value := uint64(0) + c := byte(' ') + i := iter.head + // first char + if i == iter.tail { + return iter.readFloat32SlowPath() + } + c = iter.buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat32SlowPath() + case endOfNumber: + iter.ReportError("readFloat32", "empty number") + return + case dotInNumber: + iter.ReportError("readFloat32", "leading dot is invalid") + return + case 0: + if i == iter.tail { + return iter.readFloat32SlowPath() + } + c = iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + iter.ReportError("readFloat32", "leading zero is invalid") + return + } + } + value = uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat32SlowPath() + case endOfNumber: + iter.head = i + return float32(value) + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return iter.readFloat32SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == iter.tail { + return iter.readFloat32SlowPath() + } + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + iter.head = i + return float32(float64(value) / float64(pow10[decimalPlaces])) + } + // too many decimal places + return iter.readFloat32SlowPath() + case invalidCharForNumber: + fallthrough + case dotInNumber: + return iter.readFloat32SlowPath() + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return iter.readFloat32SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) + } + } + return iter.readFloat32SlowPath() +} + +func (iter *Iterator) readNumberAsString() (ret string) { + strBuf := [16]byte{} + str := strBuf[0:0] +load_loop: + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + str = append(str, c) + continue + default: + iter.head = i + break load_loop + } + } + if !iter.loadMore() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + return + } + if len(str) == 0 { + iter.ReportError("readNumberAsString", "invalid number") + } + return *(*string)(unsafe.Pointer(&str)) +} + +func (iter *Iterator) readFloat32SlowPath() (ret float32) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + iter.ReportError("readFloat32SlowPath", errMsg) + return + } + val, err := strconv.ParseFloat(str, 32) + if err != nil { + iter.Error = err + return + } + return float32(val) +} + +// ReadFloat64 read float64 +func (iter *Iterator) ReadFloat64() (ret float64) { + c := iter.nextToken() + if c == '-' { + return -iter.readPositiveFloat64() + } + iter.unreadByte() + return iter.readPositiveFloat64() +} + +func (iter *Iterator) readPositiveFloat64() (ret float64) { + value := uint64(0) + c := byte(' ') + i := iter.head + // first char + if i == iter.tail { + return iter.readFloat64SlowPath() + } + c = iter.buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat64SlowPath() + case endOfNumber: + iter.ReportError("readFloat64", "empty number") + return + case dotInNumber: + iter.ReportError("readFloat64", "leading dot is invalid") + return + case 0: + if i == iter.tail { + return iter.readFloat64SlowPath() + } + c = iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + iter.ReportError("readFloat64", "leading zero is invalid") + return + } + } + value = uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat64SlowPath() + case endOfNumber: + iter.head = i + return float64(value) + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return iter.readFloat64SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == iter.tail { + return iter.readFloat64SlowPath() + } + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + iter.head = i + return float64(value) / float64(pow10[decimalPlaces]) + } + // too many decimal places + return iter.readFloat64SlowPath() + case invalidCharForNumber: + fallthrough + case dotInNumber: + return iter.readFloat64SlowPath() + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return iter.readFloat64SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) + } + } + return iter.readFloat64SlowPath() +} + +func (iter *Iterator) readFloat64SlowPath() (ret float64) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + iter.ReportError("readFloat64SlowPath", errMsg) + return + } + val, err := strconv.ParseFloat(str, 64) + if err != nil { + iter.Error = err + return + } + return val +} + +func validateFloat(str string) string { + // strconv.ParseFloat is not validating `1.` or `1.e1` + if len(str) == 0 { + return "empty number" + } + if str[0] == '-' { + return "-- is not valid" + } + dotPos := strings.IndexByte(str, '.') + if dotPos != -1 { + if dotPos == len(str)-1 { + return "dot can not be last character" + } + switch str[dotPos+1] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + return "missing digit after dot" + } + } + return "" +} diff --git a/vendor/github.com/json-iterator/go/feature_iter_int.go b/vendor/github.com/json-iterator/go/feature_iter_int.go new file mode 100644 index 000000000..886879efd --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_iter_int.go @@ -0,0 +1,258 @@ +package jsoniter + +import ( + "math" + "strconv" +) + +var intDigits []int8 + +const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1 +const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1 + +func init() { + intDigits = make([]int8, 256) + for i := 0; i < len(intDigits); i++ { + intDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + intDigits[i] = i - int8('0') + } +} + +// ReadUint read uint +func (iter *Iterator) ReadUint() uint { + return uint(iter.ReadUint64()) +} + +// ReadInt read int +func (iter *Iterator) ReadInt() int { + return int(iter.ReadInt64()) +} + +// ReadInt8 read int8 +func (iter *Iterator) ReadInt8() (ret int8) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint32(iter.readByte()) + if val > math.MaxInt8+1 { + iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return -int8(val) + } + val := iter.readUint32(c) + if val > math.MaxInt8 { + iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int8(val) +} + +// ReadUint8 read uint8 +func (iter *Iterator) ReadUint8() (ret uint8) { + val := iter.readUint32(iter.nextToken()) + if val > math.MaxUint8 { + iter.ReportError("ReadUint8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return uint8(val) +} + +// ReadInt16 read int16 +func (iter *Iterator) ReadInt16() (ret int16) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint32(iter.readByte()) + if val > math.MaxInt16+1 { + iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return -int16(val) + } + val := iter.readUint32(c) + if val > math.MaxInt16 { + iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int16(val) +} + +// ReadUint16 read uint16 +func (iter *Iterator) ReadUint16() (ret uint16) { + val := iter.readUint32(iter.nextToken()) + if val > math.MaxUint16 { + iter.ReportError("ReadUint16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return uint16(val) +} + +// ReadInt32 read int32 +func (iter *Iterator) ReadInt32() (ret int32) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint32(iter.readByte()) + if val > math.MaxInt32+1 { + iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return -int32(val) + } + val := iter.readUint32(c) + if val > math.MaxInt32 { + iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int32(val) +} + +// ReadUint32 read uint32 +func (iter *Iterator) ReadUint32() (ret uint32) { + return iter.readUint32(iter.nextToken()) +} + +func (iter *Iterator) readUint32(c byte) (ret uint32) { + ind := intDigits[c] + if ind == 0 { + return 0 // single zero + } + if ind == invalidCharForNumber { + iter.ReportError("readUint32", "unexpected character: "+string([]byte{byte(ind)})) + return + } + value := uint32(ind) + if iter.tail-iter.head > 10 { + i := iter.head + ind2 := intDigits[iter.buf[i]] + if ind2 == invalidCharForNumber { + iter.head = i + return value + } + i++ + ind3 := intDigits[iter.buf[i]] + if ind3 == invalidCharForNumber { + iter.head = i + return value*10 + uint32(ind2) + } + //iter.head = i + 1 + //value = value * 100 + uint32(ind2) * 10 + uint32(ind3) + i++ + ind4 := intDigits[iter.buf[i]] + if ind4 == invalidCharForNumber { + iter.head = i + return value*100 + uint32(ind2)*10 + uint32(ind3) + } + i++ + ind5 := intDigits[iter.buf[i]] + if ind5 == invalidCharForNumber { + iter.head = i + return value*1000 + uint32(ind2)*100 + uint32(ind3)*10 + uint32(ind4) + } + i++ + ind6 := intDigits[iter.buf[i]] + if ind6 == invalidCharForNumber { + iter.head = i + return value*10000 + uint32(ind2)*1000 + uint32(ind3)*100 + uint32(ind4)*10 + uint32(ind5) + } + i++ + ind7 := intDigits[iter.buf[i]] + if ind7 == invalidCharForNumber { + iter.head = i + return value*100000 + uint32(ind2)*10000 + uint32(ind3)*1000 + uint32(ind4)*100 + uint32(ind5)*10 + uint32(ind6) + } + i++ + ind8 := intDigits[iter.buf[i]] + if ind8 == invalidCharForNumber { + iter.head = i + return value*1000000 + uint32(ind2)*100000 + uint32(ind3)*10000 + uint32(ind4)*1000 + uint32(ind5)*100 + uint32(ind6)*10 + uint32(ind7) + } + i++ + ind9 := intDigits[iter.buf[i]] + value = value*10000000 + uint32(ind2)*1000000 + uint32(ind3)*100000 + uint32(ind4)*10000 + uint32(ind5)*1000 + uint32(ind6)*100 + uint32(ind7)*10 + uint32(ind8) + iter.head = i + if ind9 == invalidCharForNumber { + return value + } + } + for { + for i := iter.head; i < iter.tail; i++ { + ind = intDigits[iter.buf[i]] + if ind == invalidCharForNumber { + iter.head = i + return value + } + if value > uint32SafeToMultiply10 { + value2 := (value << 3) + (value << 1) + uint32(ind) + if value2 < value { + iter.ReportError("readUint32", "overflow") + return + } + value = value2 + continue + } + value = (value << 3) + (value << 1) + uint32(ind) + } + if !iter.loadMore() { + return value + } + } +} + +// ReadInt64 read int64 +func (iter *Iterator) ReadInt64() (ret int64) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint64(iter.readByte()) + if val > math.MaxInt64+1 { + iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) + return + } + return -int64(val) + } + val := iter.readUint64(c) + if val > math.MaxInt64 { + iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) + return + } + return int64(val) +} + +// ReadUint64 read uint64 +func (iter *Iterator) ReadUint64() uint64 { + return iter.readUint64(iter.nextToken()) +} + +func (iter *Iterator) readUint64(c byte) (ret uint64) { + ind := intDigits[c] + if ind == 0 { + return 0 // single zero + } + if ind == invalidCharForNumber { + iter.ReportError("readUint64", "unexpected character: "+string([]byte{byte(ind)})) + return + } + value := uint64(ind) + for { + for i := iter.head; i < iter.tail; i++ { + ind = intDigits[iter.buf[i]] + if ind == invalidCharForNumber { + iter.head = i + return value + } + if value > uint64SafeToMultiple10 { + value2 := (value << 3) + (value << 1) + uint64(ind) + if value2 < value { + iter.ReportError("readUint64", "overflow") + return + } + value = value2 + continue + } + value = (value << 3) + (value << 1) + uint64(ind) + } + if !iter.loadMore() { + return value + } + } +} diff --git a/vendor/github.com/json-iterator/go/feature_iter_object.go b/vendor/github.com/json-iterator/go/feature_iter_object.go new file mode 100644 index 000000000..3bdb5576e --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_iter_object.go @@ -0,0 +1,212 @@ +package jsoniter + +import ( + "fmt" + "unicode" + "unsafe" +) + +// ReadObject read one field from object. +// If object ended, returns empty string. +// Otherwise, returns the field name. +func (iter *Iterator) ReadObject() (ret string) { + c := iter.nextToken() + switch c { + case 'n': + iter.skipThreeBytes('u', 'l', 'l') + return "" // null + case '{': + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + return string(iter.readObjectFieldAsBytes()) + } + if c == '}' { + return "" // end of object + } + iter.ReportError("ReadObject", `expect " after {`) + return + case ',': + return string(iter.readObjectFieldAsBytes()) + case '}': + return "" // end of object + default: + iter.ReportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c}))) + return + } +} + +func (iter *Iterator) readFieldHash() int32 { + hash := int64(0x811c9dc5) + c := iter.nextToken() + if c == '"' { + for { + for i := iter.head; i < iter.tail; i++ { + // require ascii string and no escape + b := iter.buf[i] + if 'A' <= b && b <= 'Z' { + b += 'a' - 'A' + } + if b == '"' { + iter.head = i + 1 + c = iter.nextToken() + if c != ':' { + iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) + } + return int32(hash) + } + hash ^= int64(b) + hash *= 0x1000193 + } + if !iter.loadMore() { + iter.ReportError("readFieldHash", `incomplete field name`) + return 0 + } + } + } + iter.ReportError("readFieldHash", `expect ", but found `+string([]byte{c})) + return 0 +} + +func calcHash(str string) int32 { + hash := int64(0x811c9dc5) + for _, b := range str { + hash ^= int64(unicode.ToLower(b)) + hash *= 0x1000193 + } + return int32(hash) +} + +// ReadObjectCB read object with callback, the key is ascii only and field name not copied +func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { + c := iter.nextToken() + if c == '{' { + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field := iter.readObjectFieldAsBytes() + if !callback(iter, *(*string)(unsafe.Pointer(&field))) { + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.readObjectFieldAsBytes() + if !callback(iter, *(*string)(unsafe.Pointer(&field))) { + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.ReportError("ReadObjectCB", `object not ended with }`) + return false + } + return true + } + if c == '}' { + return true + } + iter.ReportError("ReadObjectCB", `expect " after }`) + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.ReportError("ReadObjectCB", `expect { or n`) + return false +} + +// ReadMapCB read map with callback, the key can be any string +func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { + c := iter.nextToken() + if c == '{' { + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field := iter.ReadString() + if iter.nextToken() != ':' { + iter.ReportError("ReadMapCB", "expect : after object field") + return false + } + if !callback(iter, field) { + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.ReadString() + if iter.nextToken() != ':' { + iter.ReportError("ReadMapCB", "expect : after object field") + return false + } + if !callback(iter, field) { + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.ReportError("ReadMapCB", `object not ended with }`) + return false + } + return true + } + if c == '}' { + return true + } + iter.ReportError("ReadMapCB", `expect " after }`) + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.ReportError("ReadMapCB", `expect { or n`) + return false +} + +func (iter *Iterator) readObjectStart() bool { + c := iter.nextToken() + if c == '{' { + c = iter.nextToken() + if c == '}' { + return false + } + iter.unreadByte() + return true + } else if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return false + } + iter.ReportError("readObjectStart", "expect { or n") + return false +} + +func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) { + str := iter.ReadStringAsSlice() + if iter.skipWhitespacesWithoutLoadMore() { + if ret == nil { + ret = make([]byte, len(str)) + copy(ret, str) + } + if !iter.loadMore() { + return + } + } + if iter.buf[iter.head] != ':' { + iter.ReportError("readObjectFieldAsBytes", "expect : after object field") + return + } + iter.head++ + if iter.skipWhitespacesWithoutLoadMore() { + if ret == nil { + ret = make([]byte, len(str)) + copy(ret, str) + } + if !iter.loadMore() { + return + } + } + if ret == nil { + return str + } + return ret +} diff --git a/vendor/github.com/json-iterator/go/feature_iter_skip.go b/vendor/github.com/json-iterator/go/feature_iter_skip.go new file mode 100644 index 000000000..b008d98c9 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_iter_skip.go @@ -0,0 +1,127 @@ +package jsoniter + +import "fmt" + +// ReadNil reads a json object as nil and +// returns whether it's a nil or not +func (iter *Iterator) ReadNil() (ret bool) { + c := iter.nextToken() + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') // null + return true + } + iter.unreadByte() + return false +} + +// ReadBool reads a json object as BoolValue +func (iter *Iterator) ReadBool() (ret bool) { + c := iter.nextToken() + if c == 't' { + iter.skipThreeBytes('r', 'u', 'e') + return true + } + if c == 'f' { + iter.skipFourBytes('a', 'l', 's', 'e') + return false + } + iter.ReportError("ReadBool", "expect t or f") + return +} + +// SkipAndReturnBytes skip next JSON element, and return its content as []byte. +// The []byte can be kept, it is a copy of data. +func (iter *Iterator) SkipAndReturnBytes() []byte { + iter.startCapture(iter.head) + iter.Skip() + return iter.stopCapture() +} + +type captureBuffer struct { + startedAt int + captured []byte +} + +func (iter *Iterator) startCapture(captureStartedAt int) { + if iter.captured != nil { + panic("already in capture mode") + } + iter.captureStartedAt = captureStartedAt + iter.captured = make([]byte, 0, 32) +} + +func (iter *Iterator) stopCapture() []byte { + if iter.captured == nil { + panic("not in capture mode") + } + captured := iter.captured + remaining := iter.buf[iter.captureStartedAt:iter.head] + iter.captureStartedAt = -1 + iter.captured = nil + if len(captured) == 0 { + return remaining + } + captured = append(captured, remaining...) + return captured +} + +// Skip skips a json object and positions to relatively the next json object +func (iter *Iterator) Skip() { + c := iter.nextToken() + switch c { + case '"': + iter.skipString() + case 'n': + iter.skipThreeBytes('u', 'l', 'l') // null + case 't': + iter.skipThreeBytes('r', 'u', 'e') // true + case 'f': + iter.skipFourBytes('a', 'l', 's', 'e') // false + case '0': + iter.unreadByte() + iter.ReadFloat32() + case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': + iter.skipNumber() + case '[': + iter.skipArray() + case '{': + iter.skipObject() + default: + iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c)) + return + } +} + +func (iter *Iterator) skipFourBytes(b1, b2, b3, b4 byte) { + if iter.readByte() != b1 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if iter.readByte() != b2 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if iter.readByte() != b3 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if iter.readByte() != b4 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } +} + +func (iter *Iterator) skipThreeBytes(b1, b2, b3 byte) { + if iter.readByte() != b1 { + iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if iter.readByte() != b2 { + iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if iter.readByte() != b3 { + iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } +} diff --git a/vendor/github.com/json-iterator/go/feature_iter_skip_sloppy.go b/vendor/github.com/json-iterator/go/feature_iter_skip_sloppy.go new file mode 100644 index 000000000..047d58a4b --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_iter_skip_sloppy.go @@ -0,0 +1,144 @@ +//+build jsoniter-sloppy + +package jsoniter + +// sloppy but faster implementation, do not validate the input json + +func (iter *Iterator) skipNumber() { + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\r', '\t', ',', '}', ']': + iter.head = i + return + } + } + if !iter.loadMore() { + return + } + } +} + +func (iter *Iterator) skipArray() { + level := 1 + for { + for i := iter.head; i < iter.tail; i++ { + switch iter.buf[i] { + case '"': // If inside string, skip it + iter.head = i + 1 + iter.skipString() + i = iter.head - 1 // it will be i++ soon + case '[': // If open symbol, increase level + level++ + case ']': // If close symbol, increase level + level-- + + // If we have returned to the original level, we're done + if level == 0 { + iter.head = i + 1 + return + } + } + } + if !iter.loadMore() { + iter.ReportError("skipObject", "incomplete array") + return + } + } +} + +func (iter *Iterator) skipObject() { + level := 1 + for { + for i := iter.head; i < iter.tail; i++ { + switch iter.buf[i] { + case '"': // If inside string, skip it + iter.head = i + 1 + iter.skipString() + i = iter.head - 1 // it will be i++ soon + case '{': // If open symbol, increase level + level++ + case '}': // If close symbol, increase level + level-- + + // If we have returned to the original level, we're done + if level == 0 { + iter.head = i + 1 + return + } + } + } + if !iter.loadMore() { + iter.ReportError("skipObject", "incomplete object") + return + } + } +} + +func (iter *Iterator) skipString() { + for { + end, escaped := iter.findStringEnd() + if end == -1 { + if !iter.loadMore() { + iter.ReportError("skipString", "incomplete string") + return + } + if escaped { + iter.head = 1 // skip the first char as last char read is \ + } + } else { + iter.head = end + return + } + } +} + +// adapted from: https://github.com/buger/jsonparser/blob/master/parser.go +// Tries to find the end of string +// Support if string contains escaped quote symbols. +func (iter *Iterator) findStringEnd() (int, bool) { + escaped := false + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + if c == '"' { + if !escaped { + return i + 1, false + } + j := i - 1 + for { + if j < iter.head || iter.buf[j] != '\\' { + // even number of backslashes + // either end of buffer, or " found + return i + 1, true + } + j-- + if j < iter.head || iter.buf[j] != '\\' { + // odd number of backslashes + // it is \" or \\\" + break + } + j-- + } + } else if c == '\\' { + escaped = true + } + } + j := iter.tail - 1 + for { + if j < iter.head || iter.buf[j] != '\\' { + // even number of backslashes + // either end of buffer, or " found + return -1, false // do not end with \ + } + j-- + if j < iter.head || iter.buf[j] != '\\' { + // odd number of backslashes + // it is \" or \\\" + break + } + j-- + + } + return -1, true // end with \ +} diff --git a/vendor/github.com/json-iterator/go/feature_iter_skip_strict.go b/vendor/github.com/json-iterator/go/feature_iter_skip_strict.go new file mode 100644 index 000000000..d26763825 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_iter_skip_strict.go @@ -0,0 +1,89 @@ +//+build !jsoniter-sloppy + +package jsoniter + +import "fmt" + +func (iter *Iterator) skipNumber() { + if !iter.trySkipNumber() { + iter.unreadByte() + iter.ReadFloat32() + } +} + +func (iter *Iterator) trySkipNumber() bool { + dotFound := false + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + case '.': + if dotFound { + iter.ReportError("validateNumber", `more than one dot found in number`) + return true // already failed + } + if i+1 == iter.tail { + return false + } + c = iter.buf[i+1] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + iter.ReportError("validateNumber", `missing digit after dot`) + return true // already failed + } + dotFound = true + default: + switch c { + case ',', ']', '}', ' ', '\t', '\n', '\r': + if iter.head == i { + return false // if - without following digits + } + iter.head = i + return true // must be valid + } + return false // may be invalid + } + } + return false +} + +func (iter *Iterator) skipString() { + if !iter.trySkipString() { + iter.unreadByte() + iter.ReadString() + } +} + +func (iter *Iterator) trySkipString() bool { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + if c == '"' { + iter.head = i + 1 + return true // valid + } else if c == '\\' { + return false + } else if c < ' ' { + iter.ReportError("ReadString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return true // already failed + } + } + return false +} + +func (iter *Iterator) skipObject() { + iter.unreadByte() + iter.ReadObjectCB(func(iter *Iterator, field string) bool { + iter.Skip() + return true + }) +} + +func (iter *Iterator) skipArray() { + iter.unreadByte() + iter.ReadArrayCB(func(iter *Iterator) bool { + iter.Skip() + return true + }) +} diff --git a/vendor/github.com/json-iterator/go/feature_iter_string.go b/vendor/github.com/json-iterator/go/feature_iter_string.go new file mode 100644 index 000000000..b76460046 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_iter_string.go @@ -0,0 +1,215 @@ +package jsoniter + +import ( + "fmt" + "unicode/utf16" +) + +// ReadString read string from iterator +func (iter *Iterator) ReadString() (ret string) { + c := iter.nextToken() + if c == '"' { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + if c == '"' { + ret = string(iter.buf[iter.head:i]) + iter.head = i + 1 + return ret + } else if c == '\\' { + break + } else if c < ' ' { + iter.ReportError("ReadString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return + } + } + return iter.readStringSlowPath() + } else if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return "" + } + iter.ReportError("ReadString", `expects " or n`) + return +} + +func (iter *Iterator) readStringSlowPath() (ret string) { + var str []byte + var c byte + for iter.Error == nil { + c = iter.readByte() + if c == '"' { + return string(str) + } + if c == '\\' { + c = iter.readByte() + str = iter.readEscapedChar(c, str) + } else { + str = append(str, c) + } + } + iter.ReportError("ReadString", "unexpected end of input") + return +} + +func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte { + switch c { + case 'u': + r := iter.readU4() + if utf16.IsSurrogate(r) { + c = iter.readByte() + if iter.Error != nil { + return nil + } + if c != '\\' { + iter.unreadByte() + str = appendRune(str, r) + return str + } + c = iter.readByte() + if iter.Error != nil { + return nil + } + if c != 'u' { + str = appendRune(str, r) + return iter.readEscapedChar(c, str) + } + r2 := iter.readU4() + if iter.Error != nil { + return nil + } + combined := utf16.DecodeRune(r, r2) + if combined == '\uFFFD' { + str = appendRune(str, r) + str = appendRune(str, r2) + } else { + str = appendRune(str, combined) + } + } else { + str = appendRune(str, r) + } + case '"': + str = append(str, '"') + case '\\': + str = append(str, '\\') + case '/': + str = append(str, '/') + case 'b': + str = append(str, '\b') + case 'f': + str = append(str, '\f') + case 'n': + str = append(str, '\n') + case 'r': + str = append(str, '\r') + case 't': + str = append(str, '\t') + default: + iter.ReportError("ReadString", + `invalid escape char after \`) + return nil + } + return str +} + +// ReadStringAsSlice read string from iterator without copying into string form. +// The []byte can not be kept, as it will change after next iterator call. +func (iter *Iterator) ReadStringAsSlice() (ret []byte) { + c := iter.nextToken() + if c == '"' { + for i := iter.head; i < iter.tail; i++ { + // require ascii string and no escape + // for: field name, base64, number + if iter.buf[i] == '"' { + // fast path: reuse the underlying buffer + ret = iter.buf[iter.head:i] + iter.head = i + 1 + return ret + } + } + readLen := iter.tail - iter.head + copied := make([]byte, readLen, readLen*2) + copy(copied, iter.buf[iter.head:iter.tail]) + iter.head = iter.tail + for iter.Error == nil { + c := iter.readByte() + if c == '"' { + return copied + } + copied = append(copied, c) + } + return copied + } + iter.ReportError("ReadString", `expects " or n`) + return +} + +func (iter *Iterator) readU4() (ret rune) { + for i := 0; i < 4; i++ { + c := iter.readByte() + if iter.Error != nil { + return + } + if c >= '0' && c <= '9' { + ret = ret*16 + rune(c-'0') + } else if c >= 'a' && c <= 'f' { + ret = ret*16 + rune(c-'a'+10) + } else if c >= 'A' && c <= 'F' { + ret = ret*16 + rune(c-'A'+10) + } else { + iter.ReportError("readU4", "expects 0~9 or a~f") + return + } + } + return ret +} + +const ( + t1 = 0x00 // 0000 0000 + tx = 0x80 // 1000 0000 + t2 = 0xC0 // 1100 0000 + t3 = 0xE0 // 1110 0000 + t4 = 0xF0 // 1111 0000 + t5 = 0xF8 // 1111 1000 + + maskx = 0x3F // 0011 1111 + mask2 = 0x1F // 0001 1111 + mask3 = 0x0F // 0000 1111 + mask4 = 0x07 // 0000 0111 + + rune1Max = 1<<7 - 1 + rune2Max = 1<<11 - 1 + rune3Max = 1<<16 - 1 + + surrogateMin = 0xD800 + surrogateMax = 0xDFFF + + maxRune = '\U0010FFFF' // Maximum valid Unicode code point. + runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character" +) + +func appendRune(p []byte, r rune) []byte { + // Negative values are erroneous. Making it unsigned addresses the problem. + switch i := uint32(r); { + case i <= rune1Max: + p = append(p, byte(r)) + return p + case i <= rune2Max: + p = append(p, t2|byte(r>>6)) + p = append(p, tx|byte(r)&maskx) + return p + case i > maxRune, surrogateMin <= i && i <= surrogateMax: + r = runeError + fallthrough + case i <= rune3Max: + p = append(p, t3|byte(r>>12)) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + default: + p = append(p, t4|byte(r>>18)) + p = append(p, tx|byte(r>>12)&maskx) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + } +} diff --git a/vendor/github.com/json-iterator/go/feature_json_number.go b/vendor/github.com/json-iterator/go/feature_json_number.go new file mode 100644 index 000000000..0439f6725 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_json_number.go @@ -0,0 +1,15 @@ +package jsoniter + +import "encoding/json" + +type Number string + +func CastJsonNumber(val interface{}) (string, bool) { + switch typedVal := val.(type) { + case json.Number: + return string(typedVal), true + case Number: + return string(typedVal), true + } + return "", false +} diff --git a/vendor/github.com/json-iterator/go/feature_pool.go b/vendor/github.com/json-iterator/go/feature_pool.go new file mode 100644 index 000000000..73962bc6f --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_pool.go @@ -0,0 +1,57 @@ +package jsoniter + +import ( + "io" +) + +// IteratorPool a thread safe pool of iterators with same configuration +type IteratorPool interface { + BorrowIterator(data []byte) *Iterator + ReturnIterator(iter *Iterator) +} + +// StreamPool a thread safe pool of streams with same configuration +type StreamPool interface { + BorrowStream(writer io.Writer) *Stream + ReturnStream(stream *Stream) +} + +func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream { + select { + case stream := <-cfg.streamPool: + stream.Reset(writer) + return stream + default: + return NewStream(cfg, writer, 512) + } +} + +func (cfg *frozenConfig) ReturnStream(stream *Stream) { + stream.Error = nil + select { + case cfg.streamPool <- stream: + return + default: + return + } +} + +func (cfg *frozenConfig) BorrowIterator(data []byte) *Iterator { + select { + case iter := <-cfg.iteratorPool: + iter.ResetBytes(data) + return iter + default: + return ParseBytes(cfg, data) + } +} + +func (cfg *frozenConfig) ReturnIterator(iter *Iterator) { + iter.Error = nil + select { + case cfg.iteratorPool <- iter: + return + default: + return + } +} diff --git a/vendor/github.com/json-iterator/go/feature_reflect.go b/vendor/github.com/json-iterator/go/feature_reflect.go new file mode 100644 index 000000000..05d91b49c --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_reflect.go @@ -0,0 +1,691 @@ +package jsoniter + +import ( + "encoding" + "encoding/json" + "fmt" + "reflect" + "time" + "unsafe" +) + +// ValDecoder is an internal type registered to cache as needed. +// Don't confuse jsoniter.ValDecoder with json.Decoder. +// For json.Decoder's adapter, refer to jsoniter.AdapterDecoder(todo link). +// +// Reflection on type to create decoders, which is then cached +// Reflection on value is avoided as we can, as the reflect.Value itself will allocate, with following exceptions +// 1. create instance of new value, for example *int will need a int to be allocated +// 2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New +// 3. assignment to map, both key and value will be reflect.Value +// For a simple struct binding, it will be reflect.Value free and allocation free +type ValDecoder interface { + Decode(ptr unsafe.Pointer, iter *Iterator) +} + +// ValEncoder is an internal type registered to cache as needed. +// Don't confuse jsoniter.ValEncoder with json.Encoder. +// For json.Encoder's adapter, refer to jsoniter.AdapterEncoder(todo godoc link). +type ValEncoder interface { + IsEmpty(ptr unsafe.Pointer) bool + Encode(ptr unsafe.Pointer, stream *Stream) + EncodeInterface(val interface{}, stream *Stream) +} + +type checkIsEmpty interface { + IsEmpty(ptr unsafe.Pointer) bool +} + +// WriteToStream the default implementation for TypeEncoder method EncodeInterface +func WriteToStream(val interface{}, stream *Stream, encoder ValEncoder) { + e := (*emptyInterface)(unsafe.Pointer(&val)) + if e.word == nil { + stream.WriteNil() + return + } + if reflect.TypeOf(val).Kind() == reflect.Ptr { + encoder.Encode(unsafe.Pointer(&e.word), stream) + } else { + encoder.Encode(e.word, stream) + } +} + +var jsonNumberType reflect.Type +var jsoniterNumberType reflect.Type +var jsonRawMessageType reflect.Type +var jsoniterRawMessageType reflect.Type +var anyType reflect.Type +var marshalerType reflect.Type +var unmarshalerType reflect.Type +var textMarshalerType reflect.Type +var textUnmarshalerType reflect.Type + +func init() { + jsonNumberType = reflect.TypeOf((*json.Number)(nil)).Elem() + jsoniterNumberType = reflect.TypeOf((*Number)(nil)).Elem() + jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem() + jsoniterRawMessageType = reflect.TypeOf((*RawMessage)(nil)).Elem() + anyType = reflect.TypeOf((*Any)(nil)).Elem() + marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() + textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() +} + +type optionalDecoder struct { + valueType reflect.Type + valueDecoder ValDecoder +} + +func (decoder *optionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.ReadNil() { + *((*unsafe.Pointer)(ptr)) = nil + } else { + if *((*unsafe.Pointer)(ptr)) == nil { + //pointer to null, we have to allocate memory to hold the value + value := reflect.New(decoder.valueType) + newPtr := extractInterface(value.Interface()).word + decoder.valueDecoder.Decode(newPtr, iter) + *((*uintptr)(ptr)) = uintptr(newPtr) + } else { + //reuse existing instance + decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) + } + } +} + +type deferenceDecoder struct { + // only to deference a pointer + valueType reflect.Type + valueDecoder ValDecoder +} + +func (decoder *deferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if *((*unsafe.Pointer)(ptr)) == nil { + //pointer to null, we have to allocate memory to hold the value + value := reflect.New(decoder.valueType) + newPtr := extractInterface(value.Interface()).word + decoder.valueDecoder.Decode(newPtr, iter) + *((*uintptr)(ptr)) = uintptr(newPtr) + } else { + //reuse existing instance + decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) + } +} + +type optionalEncoder struct { + valueEncoder ValEncoder +} + +func (encoder *optionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if *((*unsafe.Pointer)(ptr)) == nil { + stream.WriteNil() + } else { + encoder.valueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) + } +} + +func (encoder *optionalEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *optionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { + if *((*unsafe.Pointer)(ptr)) == nil { + return true + } + return false +} + +type placeholderEncoder struct { + cfg *frozenConfig + cacheKey reflect.Type +} + +func (encoder *placeholderEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.getRealEncoder().Encode(ptr, stream) +} + +func (encoder *placeholderEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.getRealEncoder().IsEmpty(ptr) +} + +func (encoder *placeholderEncoder) getRealEncoder() ValEncoder { + for i := 0; i < 30; i++ { + realDecoder := encoder.cfg.getEncoderFromCache(encoder.cacheKey) + _, isPlaceholder := realDecoder.(*placeholderEncoder) + if isPlaceholder { + time.Sleep(time.Second) + } else { + return realDecoder + } + } + panic(fmt.Sprintf("real encoder not found for cache key: %v", encoder.cacheKey)) +} + +type placeholderDecoder struct { + cfg *frozenConfig + cacheKey reflect.Type +} + +func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + for i := 0; i < 30; i++ { + realDecoder := decoder.cfg.getDecoderFromCache(decoder.cacheKey) + _, isPlaceholder := realDecoder.(*placeholderDecoder) + if isPlaceholder { + time.Sleep(time.Second) + } else { + realDecoder.Decode(ptr, iter) + return + } + } + panic(fmt.Sprintf("real decoder not found for cache key: %v", decoder.cacheKey)) +} + +// emptyInterface is the header for an interface{} value. +type emptyInterface struct { + typ unsafe.Pointer + word unsafe.Pointer +} + +// emptyInterface is the header for an interface with method (not interface{}) +type nonEmptyInterface struct { + // see ../runtime/iface.go:/Itab + itab *struct { + ityp unsafe.Pointer // static interface type + typ unsafe.Pointer // dynamic concrete type + link unsafe.Pointer + bad int32 + unused int32 + fun [100000]unsafe.Pointer // method table + } + word unsafe.Pointer +} + +// ReadVal copy the underlying JSON into go interface, same as json.Unmarshal +func (iter *Iterator) ReadVal(obj interface{}) { + typ := reflect.TypeOf(obj) + cacheKey := typ.Elem() + decoder, err := decoderOfType(iter.cfg, cacheKey) + if err != nil { + iter.Error = err + return + } + e := (*emptyInterface)(unsafe.Pointer(&obj)) + decoder.Decode(e.word, iter) +} + +// WriteVal copy the go interface into underlying JSON, same as json.Marshal +func (stream *Stream) WriteVal(val interface{}) { + if nil == val { + stream.WriteNil() + return + } + typ := reflect.TypeOf(val) + cacheKey := typ + encoder, err := encoderOfType(stream.cfg, cacheKey) + if err != nil { + stream.Error = err + return + } + encoder.EncodeInterface(val, stream) +} + +type prefix string + +func (p prefix) addToDecoder(decoder ValDecoder, err error) (ValDecoder, error) { + if err != nil { + return nil, fmt.Errorf("%s: %s", p, err.Error()) + } + return decoder, err +} + +func (p prefix) addToEncoder(encoder ValEncoder, err error) (ValEncoder, error) { + if err != nil { + return nil, fmt.Errorf("%s: %s", p, err.Error()) + } + return encoder, err +} + +func decoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { + cacheKey := typ + decoder := cfg.getDecoderFromCache(cacheKey) + if decoder != nil { + return decoder, nil + } + decoder = getTypeDecoderFromExtension(typ) + if decoder != nil { + cfg.addDecoderToCache(cacheKey, decoder) + return decoder, nil + } + decoder = &placeholderDecoder{cfg: cfg, cacheKey: cacheKey} + cfg.addDecoderToCache(cacheKey, decoder) + decoder, err := createDecoderOfType(cfg, typ) + for _, extension := range extensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + cfg.addDecoderToCache(cacheKey, decoder) + return decoder, err +} + +func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { + typeName := typ.String() + if typ == jsonRawMessageType { + return &jsonRawMessageCodec{}, nil + } + if typ == jsoniterRawMessageType { + return &jsoniterRawMessageCodec{}, nil + } + if typ.AssignableTo(jsonNumberType) { + return &jsonNumberCodec{}, nil + } + if typ.AssignableTo(jsoniterNumberType) { + return &jsoniterNumberCodec{}, nil + } + if typ.Implements(unmarshalerType) { + templateInterface := reflect.New(typ).Elem().Interface() + var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)} + if typ.Kind() == reflect.Ptr { + decoder = &optionalDecoder{typ.Elem(), decoder} + } + return decoder, nil + } + if reflect.PtrTo(typ).Implements(unmarshalerType) { + templateInterface := reflect.New(typ).Interface() + var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)} + return decoder, nil + } + if typ.Implements(textUnmarshalerType) { + templateInterface := reflect.New(typ).Elem().Interface() + var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)} + if typ.Kind() == reflect.Ptr { + decoder = &optionalDecoder{typ.Elem(), decoder} + } + return decoder, nil + } + if reflect.PtrTo(typ).Implements(textUnmarshalerType) { + templateInterface := reflect.New(typ).Interface() + var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)} + return decoder, nil + } + if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 { + sliceDecoder, err := prefix("[slice]").addToDecoder(decoderOfSlice(cfg, typ)) + if err != nil { + return nil, err + } + return &base64Codec{sliceDecoder: sliceDecoder}, nil + } + if typ.Implements(anyType) { + return &anyCodec{}, nil + } + switch typ.Kind() { + case reflect.String: + if typeName != "string" { + return decoderOfType(cfg, reflect.TypeOf((*string)(nil)).Elem()) + } + return &stringCodec{}, nil + case reflect.Int: + if typeName != "int" { + return decoderOfType(cfg, reflect.TypeOf((*int)(nil)).Elem()) + } + return &intCodec{}, nil + case reflect.Int8: + if typeName != "int8" { + return decoderOfType(cfg, reflect.TypeOf((*int8)(nil)).Elem()) + } + return &int8Codec{}, nil + case reflect.Int16: + if typeName != "int16" { + return decoderOfType(cfg, reflect.TypeOf((*int16)(nil)).Elem()) + } + return &int16Codec{}, nil + case reflect.Int32: + if typeName != "int32" { + return decoderOfType(cfg, reflect.TypeOf((*int32)(nil)).Elem()) + } + return &int32Codec{}, nil + case reflect.Int64: + if typeName != "int64" { + return decoderOfType(cfg, reflect.TypeOf((*int64)(nil)).Elem()) + } + return &int64Codec{}, nil + case reflect.Uint: + if typeName != "uint" { + return decoderOfType(cfg, reflect.TypeOf((*uint)(nil)).Elem()) + } + return &uintCodec{}, nil + case reflect.Uint8: + if typeName != "uint8" { + return decoderOfType(cfg, reflect.TypeOf((*uint8)(nil)).Elem()) + } + return &uint8Codec{}, nil + case reflect.Uint16: + if typeName != "uint16" { + return decoderOfType(cfg, reflect.TypeOf((*uint16)(nil)).Elem()) + } + return &uint16Codec{}, nil + case reflect.Uint32: + if typeName != "uint32" { + return decoderOfType(cfg, reflect.TypeOf((*uint32)(nil)).Elem()) + } + return &uint32Codec{}, nil + case reflect.Uintptr: + if typeName != "uintptr" { + return decoderOfType(cfg, reflect.TypeOf((*uintptr)(nil)).Elem()) + } + return &uintptrCodec{}, nil + case reflect.Uint64: + if typeName != "uint64" { + return decoderOfType(cfg, reflect.TypeOf((*uint64)(nil)).Elem()) + } + return &uint64Codec{}, nil + case reflect.Float32: + if typeName != "float32" { + return decoderOfType(cfg, reflect.TypeOf((*float32)(nil)).Elem()) + } + return &float32Codec{}, nil + case reflect.Float64: + if typeName != "float64" { + return decoderOfType(cfg, reflect.TypeOf((*float64)(nil)).Elem()) + } + return &float64Codec{}, nil + case reflect.Bool: + if typeName != "bool" { + return decoderOfType(cfg, reflect.TypeOf((*bool)(nil)).Elem()) + } + return &boolCodec{}, nil + case reflect.Interface: + if typ.NumMethod() == 0 { + return &emptyInterfaceCodec{}, nil + } + return &nonEmptyInterfaceCodec{}, nil + case reflect.Struct: + return prefix(fmt.Sprintf("[%s]", typeName)).addToDecoder(decoderOfStruct(cfg, typ)) + case reflect.Array: + return prefix("[array]").addToDecoder(decoderOfArray(cfg, typ)) + case reflect.Slice: + return prefix("[slice]").addToDecoder(decoderOfSlice(cfg, typ)) + case reflect.Map: + return prefix("[map]").addToDecoder(decoderOfMap(cfg, typ)) + case reflect.Ptr: + return prefix("[optional]").addToDecoder(decoderOfOptional(cfg, typ)) + default: + return nil, fmt.Errorf("unsupported type: %v", typ) + } +} + +func encoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { + cacheKey := typ + encoder := cfg.getEncoderFromCache(cacheKey) + if encoder != nil { + return encoder, nil + } + encoder = getTypeEncoderFromExtension(typ) + if encoder != nil { + cfg.addEncoderToCache(cacheKey, encoder) + return encoder, nil + } + encoder = &placeholderEncoder{cfg: cfg, cacheKey: cacheKey} + cfg.addEncoderToCache(cacheKey, encoder) + encoder, err := createEncoderOfType(cfg, typ) + for _, extension := range extensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + cfg.addEncoderToCache(cacheKey, encoder) + return encoder, err +} + +func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { + if typ == jsonRawMessageType { + return &jsonRawMessageCodec{}, nil + } + if typ == jsoniterRawMessageType { + return &jsoniterRawMessageCodec{}, nil + } + if typ.AssignableTo(jsonNumberType) { + return &jsonNumberCodec{}, nil + } + if typ.AssignableTo(jsoniterNumberType) { + return &jsoniterNumberCodec{}, nil + } + if typ.Implements(marshalerType) { + checkIsEmpty, err := createCheckIsEmpty(typ) + if err != nil { + return nil, err + } + templateInterface := reflect.New(typ).Elem().Interface() + var encoder ValEncoder = &marshalerEncoder{ + templateInterface: extractInterface(templateInterface), + checkIsEmpty: checkIsEmpty, + } + if typ.Kind() == reflect.Ptr { + encoder = &optionalEncoder{encoder} + } + return encoder, nil + } + if typ.Implements(textMarshalerType) { + checkIsEmpty, err := createCheckIsEmpty(typ) + if err != nil { + return nil, err + } + templateInterface := reflect.New(typ).Elem().Interface() + var encoder ValEncoder = &textMarshalerEncoder{ + templateInterface: extractInterface(templateInterface), + checkIsEmpty: checkIsEmpty, + } + if typ.Kind() == reflect.Ptr { + encoder = &optionalEncoder{encoder} + } + return encoder, nil + } + if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 { + return &base64Codec{}, nil + } + if typ.Implements(anyType) { + return &anyCodec{}, nil + } + return createEncoderOfSimpleType(cfg, typ) +} + +func createCheckIsEmpty(typ reflect.Type) (checkIsEmpty, error) { + kind := typ.Kind() + switch kind { + case reflect.String: + return &stringCodec{}, nil + case reflect.Int: + return &intCodec{}, nil + case reflect.Int8: + return &int8Codec{}, nil + case reflect.Int16: + return &int16Codec{}, nil + case reflect.Int32: + return &int32Codec{}, nil + case reflect.Int64: + return &int64Codec{}, nil + case reflect.Uint: + return &uintCodec{}, nil + case reflect.Uint8: + return &uint8Codec{}, nil + case reflect.Uint16: + return &uint16Codec{}, nil + case reflect.Uint32: + return &uint32Codec{}, nil + case reflect.Uintptr: + return &uintptrCodec{}, nil + case reflect.Uint64: + return &uint64Codec{}, nil + case reflect.Float32: + return &float32Codec{}, nil + case reflect.Float64: + return &float64Codec{}, nil + case reflect.Bool: + return &boolCodec{}, nil + case reflect.Interface: + if typ.NumMethod() == 0 { + return &emptyInterfaceCodec{}, nil + } + return &nonEmptyInterfaceCodec{}, nil + case reflect.Struct: + return &structEncoder{}, nil + case reflect.Array: + return &arrayEncoder{}, nil + case reflect.Slice: + return &sliceEncoder{}, nil + case reflect.Map: + return &mapEncoder{}, nil + case reflect.Ptr: + return &optionalEncoder{}, nil + default: + return nil, fmt.Errorf("unsupported type: %v", typ) + } +} + +func createEncoderOfSimpleType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { + typeName := typ.String() + kind := typ.Kind() + switch kind { + case reflect.String: + if typeName != "string" { + return encoderOfType(cfg, reflect.TypeOf((*string)(nil)).Elem()) + } + return &stringCodec{}, nil + case reflect.Int: + if typeName != "int" { + return encoderOfType(cfg, reflect.TypeOf((*int)(nil)).Elem()) + } + return &intCodec{}, nil + case reflect.Int8: + if typeName != "int8" { + return encoderOfType(cfg, reflect.TypeOf((*int8)(nil)).Elem()) + } + return &int8Codec{}, nil + case reflect.Int16: + if typeName != "int16" { + return encoderOfType(cfg, reflect.TypeOf((*int16)(nil)).Elem()) + } + return &int16Codec{}, nil + case reflect.Int32: + if typeName != "int32" { + return encoderOfType(cfg, reflect.TypeOf((*int32)(nil)).Elem()) + } + return &int32Codec{}, nil + case reflect.Int64: + if typeName != "int64" { + return encoderOfType(cfg, reflect.TypeOf((*int64)(nil)).Elem()) + } + return &int64Codec{}, nil + case reflect.Uint: + if typeName != "uint" { + return encoderOfType(cfg, reflect.TypeOf((*uint)(nil)).Elem()) + } + return &uintCodec{}, nil + case reflect.Uint8: + if typeName != "uint8" { + return encoderOfType(cfg, reflect.TypeOf((*uint8)(nil)).Elem()) + } + return &uint8Codec{}, nil + case reflect.Uint16: + if typeName != "uint16" { + return encoderOfType(cfg, reflect.TypeOf((*uint16)(nil)).Elem()) + } + return &uint16Codec{}, nil + case reflect.Uint32: + if typeName != "uint32" { + return encoderOfType(cfg, reflect.TypeOf((*uint32)(nil)).Elem()) + } + return &uint32Codec{}, nil + case reflect.Uintptr: + if typeName != "uintptr" { + return encoderOfType(cfg, reflect.TypeOf((*uintptr)(nil)).Elem()) + } + return &uintptrCodec{}, nil + case reflect.Uint64: + if typeName != "uint64" { + return encoderOfType(cfg, reflect.TypeOf((*uint64)(nil)).Elem()) + } + return &uint64Codec{}, nil + case reflect.Float32: + if typeName != "float32" { + return encoderOfType(cfg, reflect.TypeOf((*float32)(nil)).Elem()) + } + return &float32Codec{}, nil + case reflect.Float64: + if typeName != "float64" { + return encoderOfType(cfg, reflect.TypeOf((*float64)(nil)).Elem()) + } + return &float64Codec{}, nil + case reflect.Bool: + if typeName != "bool" { + return encoderOfType(cfg, reflect.TypeOf((*bool)(nil)).Elem()) + } + return &boolCodec{}, nil + case reflect.Interface: + if typ.NumMethod() == 0 { + return &emptyInterfaceCodec{}, nil + } + return &nonEmptyInterfaceCodec{}, nil + case reflect.Struct: + return prefix(fmt.Sprintf("[%s]", typeName)).addToEncoder(encoderOfStruct(cfg, typ)) + case reflect.Array: + return prefix("[array]").addToEncoder(encoderOfArray(cfg, typ)) + case reflect.Slice: + return prefix("[slice]").addToEncoder(encoderOfSlice(cfg, typ)) + case reflect.Map: + return prefix("[map]").addToEncoder(encoderOfMap(cfg, typ)) + case reflect.Ptr: + return prefix("[optional]").addToEncoder(encoderOfOptional(cfg, typ)) + default: + return nil, fmt.Errorf("unsupported type: %v", typ) + } +} + +func decoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { + elemType := typ.Elem() + decoder, err := decoderOfType(cfg, elemType) + if err != nil { + return nil, err + } + return &optionalDecoder{elemType, decoder}, nil +} + +func encoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { + elemType := typ.Elem() + elemEncoder, err := encoderOfType(cfg, elemType) + if err != nil { + return nil, err + } + encoder := &optionalEncoder{elemEncoder} + if elemType.Kind() == reflect.Map { + encoder = &optionalEncoder{encoder} + } + return encoder, nil +} + +func decoderOfMap(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { + decoder, err := decoderOfType(cfg, typ.Elem()) + if err != nil { + return nil, err + } + mapInterface := reflect.New(typ).Interface() + return &mapDecoder{typ, typ.Key(), typ.Elem(), decoder, extractInterface(mapInterface)}, nil +} + +func extractInterface(val interface{}) emptyInterface { + return *((*emptyInterface)(unsafe.Pointer(&val))) +} + +func encoderOfMap(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { + elemType := typ.Elem() + encoder, err := encoderOfType(cfg, elemType) + if err != nil { + return nil, err + } + mapInterface := reflect.New(typ).Elem().Interface() + if cfg.sortMapKeys { + return &sortKeysMapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil + } + return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil +} diff --git a/vendor/github.com/json-iterator/go/feature_reflect_array.go b/vendor/github.com/json-iterator/go/feature_reflect_array.go new file mode 100644 index 000000000..e23f187b7 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_reflect_array.go @@ -0,0 +1,99 @@ +package jsoniter + +import ( + "fmt" + "io" + "reflect" + "unsafe" +) + +func decoderOfArray(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { + decoder, err := decoderOfType(cfg, typ.Elem()) + if err != nil { + return nil, err + } + return &arrayDecoder{typ, typ.Elem(), decoder}, nil +} + +func encoderOfArray(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { + encoder, err := encoderOfType(cfg, typ.Elem()) + if err != nil { + return nil, err + } + if typ.Elem().Kind() == reflect.Map { + encoder = &optionalEncoder{encoder} + } + return &arrayEncoder{typ, typ.Elem(), encoder}, nil +} + +type arrayEncoder struct { + arrayType reflect.Type + elemType reflect.Type + elemEncoder ValEncoder +} + +func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteArrayStart() + elemPtr := unsafe.Pointer(ptr) + encoder.elemEncoder.Encode(elemPtr, stream) + for i := 1; i < encoder.arrayType.Len(); i++ { + stream.WriteMore() + elemPtr = unsafe.Pointer(uintptr(elemPtr) + encoder.elemType.Size()) + encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream) + } + stream.WriteArrayEnd() + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%v: %s", encoder.arrayType, stream.Error.Error()) + } +} + +func (encoder *arrayEncoder) EncodeInterface(val interface{}, stream *Stream) { + // special optimization for interface{} + e := (*emptyInterface)(unsafe.Pointer(&val)) + if e.word == nil { + stream.WriteArrayStart() + stream.WriteNil() + stream.WriteArrayEnd() + return + } + elemType := encoder.arrayType.Elem() + if encoder.arrayType.Len() == 1 && (elemType.Kind() == reflect.Ptr || elemType.Kind() == reflect.Map) { + ptr := uintptr(e.word) + e.word = unsafe.Pointer(&ptr) + } + if reflect.TypeOf(val).Kind() == reflect.Ptr { + encoder.Encode(unsafe.Pointer(&e.word), stream) + } else { + encoder.Encode(e.word, stream) + } +} + +func (encoder *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type arrayDecoder struct { + arrayType reflect.Type + elemType reflect.Type + elemDecoder ValDecoder +} + +func (decoder *arrayDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.doDecode(ptr, iter) + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.arrayType, iter.Error.Error()) + } +} + +func (decoder *arrayDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { + offset := uintptr(0) + iter.ReadArrayCB(func(iter *Iterator) bool { + if offset < decoder.arrayType.Size() { + decoder.elemDecoder.Decode(unsafe.Pointer(uintptr(ptr)+offset), iter) + offset += decoder.elemType.Size() + } else { + iter.Skip() + } + return true + }) +} diff --git a/vendor/github.com/json-iterator/go/feature_reflect_extension.go b/vendor/github.com/json-iterator/go/feature_reflect_extension.go new file mode 100644 index 000000000..3dd38299d --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_reflect_extension.go @@ -0,0 +1,413 @@ +package jsoniter + +import ( + "fmt" + "reflect" + "sort" + "strings" + "unicode" + "unsafe" +) + +var typeDecoders = map[string]ValDecoder{} +var fieldDecoders = map[string]ValDecoder{} +var typeEncoders = map[string]ValEncoder{} +var fieldEncoders = map[string]ValEncoder{} +var extensions = []Extension{} + +// StructDescriptor describe how should we encode/decode the struct +type StructDescriptor struct { + onePtrEmbedded bool + onePtrOptimization bool + Type reflect.Type + Fields []*Binding +} + +// GetField get one field from the descriptor by its name. +// Can not use map here to keep field orders. +func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding { + for _, binding := range structDescriptor.Fields { + if binding.Field.Name == fieldName { + return binding + } + } + return nil +} + +// Binding describe how should we encode/decode the struct field +type Binding struct { + levels []int + Field *reflect.StructField + FromNames []string + ToNames []string + Encoder ValEncoder + Decoder ValDecoder +} + +// Extension the one for all SPI. Customize encoding/decoding by specifying alternate encoder/decoder. +// Can also rename fields by UpdateStructDescriptor. +type Extension interface { + UpdateStructDescriptor(structDescriptor *StructDescriptor) + CreateDecoder(typ reflect.Type) ValDecoder + CreateEncoder(typ reflect.Type) ValEncoder + DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder + DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder +} + +// DummyExtension embed this type get dummy implementation for all methods of Extension +type DummyExtension struct { +} + +// UpdateStructDescriptor No-op +func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { +} + +// CreateDecoder No-op +func (extension *DummyExtension) CreateDecoder(typ reflect.Type) ValDecoder { + return nil +} + +// CreateEncoder No-op +func (extension *DummyExtension) CreateEncoder(typ reflect.Type) ValEncoder { + return nil +} + +// DecorateDecoder No-op +func (extension *DummyExtension) DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder { + return decoder +} + +// DecorateEncoder No-op +func (extension *DummyExtension) DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder { + return encoder +} + +type funcDecoder struct { + fun DecoderFunc +} + +func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.fun(ptr, iter) +} + +type funcEncoder struct { + fun EncoderFunc + isEmptyFunc func(ptr unsafe.Pointer) bool +} + +func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.fun(ptr, stream) +} + +func (encoder *funcEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool { + if encoder.isEmptyFunc == nil { + return false + } + return encoder.isEmptyFunc(ptr) +} + +// DecoderFunc the function form of TypeDecoder +type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator) + +// EncoderFunc the function form of TypeEncoder +type EncoderFunc func(ptr unsafe.Pointer, stream *Stream) + +// RegisterTypeDecoderFunc register TypeDecoder for a type with function +func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) { + typeDecoders[typ] = &funcDecoder{fun} +} + +// RegisterTypeDecoder register TypeDecoder for a typ +func RegisterTypeDecoder(typ string, decoder ValDecoder) { + typeDecoders[typ] = decoder +} + +// RegisterFieldDecoderFunc register TypeDecoder for a struct field with function +func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) { + RegisterFieldDecoder(typ, field, &funcDecoder{fun}) +} + +// RegisterFieldDecoder register TypeDecoder for a struct field +func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) { + fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder +} + +// RegisterTypeEncoderFunc register TypeEncoder for a type with encode/isEmpty function +func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { + typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc} +} + +// RegisterTypeEncoder register TypeEncoder for a type +func RegisterTypeEncoder(typ string, encoder ValEncoder) { + typeEncoders[typ] = encoder +} + +// RegisterFieldEncoderFunc register TypeEncoder for a struct field with encode/isEmpty function +func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { + RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc}) +} + +// RegisterFieldEncoder register TypeEncoder for a struct field +func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) { + fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder +} + +// RegisterExtension register extension +func RegisterExtension(extension Extension) { + extensions = append(extensions, extension) +} + +func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder { + decoder := _getTypeDecoderFromExtension(typ) + if decoder != nil { + for _, extension := range extensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + } + return decoder +} +func _getTypeDecoderFromExtension(typ reflect.Type) ValDecoder { + for _, extension := range extensions { + decoder := extension.CreateDecoder(typ) + if decoder != nil { + return decoder + } + } + typeName := typ.String() + decoder := typeDecoders[typeName] + if decoder != nil { + return decoder + } + if typ.Kind() == reflect.Ptr { + decoder := typeDecoders[typ.Elem().String()] + if decoder != nil { + return &optionalDecoder{typ.Elem(), decoder} + } + } + return nil +} + +func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder { + encoder := _getTypeEncoderFromExtension(typ) + if encoder != nil { + for _, extension := range extensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + } + return encoder +} + +func _getTypeEncoderFromExtension(typ reflect.Type) ValEncoder { + for _, extension := range extensions { + encoder := extension.CreateEncoder(typ) + if encoder != nil { + return encoder + } + } + typeName := typ.String() + encoder := typeEncoders[typeName] + if encoder != nil { + return encoder + } + if typ.Kind() == reflect.Ptr { + encoder := typeEncoders[typ.Elem().String()] + if encoder != nil { + return &optionalEncoder{encoder} + } + } + return nil +} + +func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, error) { + embeddedBindings := []*Binding{} + bindings := []*Binding{} + for i := 0; i < typ.NumField(); i++ { + field := typ.Field(i) + tag := field.Tag.Get(cfg.getTagKey()) + tagParts := strings.Split(tag, ",") + if tag == "-" { + continue + } + if field.Anonymous && (tag == "" || tagParts[0] == "") { + if field.Type.Kind() == reflect.Struct { + structDescriptor, err := describeStruct(cfg, field.Type) + if err != nil { + return nil, err + } + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &structFieldEncoder{&field, binding.Encoder, omitempty} + binding.Decoder = &structFieldDecoder{&field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } else if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { + structDescriptor, err := describeStruct(cfg, field.Type.Elem()) + if err != nil { + return nil, err + } + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &optionalEncoder{binding.Encoder} + binding.Encoder = &structFieldEncoder{&field, binding.Encoder, omitempty} + binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder} + binding.Decoder = &structFieldDecoder{&field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } + } + fieldNames := calcFieldNames(field.Name, tagParts[0], tag) + fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name) + decoder := fieldDecoders[fieldCacheKey] + if decoder == nil { + var err error + decoder, err = decoderOfType(cfg, field.Type) + if err != nil { + return nil, err + } + } + encoder := fieldEncoders[fieldCacheKey] + if encoder == nil { + var err error + encoder, err = encoderOfType(cfg, field.Type) + if err != nil { + return nil, err + } + // map is stored as pointer in the struct + if field.Type.Kind() == reflect.Map { + encoder = &optionalEncoder{encoder} + } + } + binding := &Binding{ + Field: &field, + FromNames: fieldNames, + ToNames: fieldNames, + Decoder: decoder, + Encoder: encoder, + } + binding.levels = []int{i} + bindings = append(bindings, binding) + } + return createStructDescriptor(cfg, typ, bindings, embeddedBindings), nil +} +func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { + onePtrEmbedded := false + onePtrOptimization := false + if typ.NumField() == 1 { + firstField := typ.Field(0) + switch firstField.Type.Kind() { + case reflect.Ptr: + if firstField.Anonymous && firstField.Type.Elem().Kind() == reflect.Struct { + onePtrEmbedded = true + } + fallthrough + case reflect.Map: + onePtrOptimization = true + case reflect.Struct: + onePtrOptimization = isStructOnePtr(firstField.Type) + } + } + structDescriptor := &StructDescriptor{ + onePtrEmbedded: onePtrEmbedded, + onePtrOptimization: onePtrOptimization, + Type: typ, + Fields: bindings, + } + for _, extension := range extensions { + extension.UpdateStructDescriptor(structDescriptor) + } + processTags(structDescriptor, cfg) + // merge normal & embedded bindings & sort with original order + allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) + sort.Sort(allBindings) + structDescriptor.Fields = allBindings + return structDescriptor +} + +func isStructOnePtr(typ reflect.Type) bool { + if typ.NumField() == 1 { + firstField := typ.Field(0) + switch firstField.Type.Kind() { + case reflect.Ptr: + return true + case reflect.Map: + return true + case reflect.Struct: + return isStructOnePtr(firstField.Type) + } + } + return false +} + +type sortableBindings []*Binding + +func (bindings sortableBindings) Len() int { + return len(bindings) +} + +func (bindings sortableBindings) Less(i, j int) bool { + left := bindings[i].levels + right := bindings[j].levels + k := 0 + for { + if left[k] < right[k] { + return true + } else if left[k] > right[k] { + return false + } + k++ + } +} + +func (bindings sortableBindings) Swap(i, j int) { + bindings[i], bindings[j] = bindings[j], bindings[i] +} + +func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) { + for _, binding := range structDescriptor.Fields { + shouldOmitEmpty := false + tagParts := strings.Split(binding.Field.Tag.Get(cfg.getTagKey()), ",") + for _, tagPart := range tagParts[1:] { + if tagPart == "omitempty" { + shouldOmitEmpty = true + } else if tagPart == "string" { + if binding.Field.Type.Kind() == reflect.String { + binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg} + binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg} + } else { + binding.Decoder = &stringModeNumberDecoder{binding.Decoder} + binding.Encoder = &stringModeNumberEncoder{binding.Encoder} + } + } + } + binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder} + binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty} + } +} + +func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string { + // ignore? + if wholeTag == "-" { + return []string{} + } + // rename? + var fieldNames []string + if tagProvidedFieldName == "" { + fieldNames = []string{originalFieldName} + } else { + fieldNames = []string{tagProvidedFieldName} + } + // private? + isNotExported := unicode.IsLower(rune(originalFieldName[0])) + if isNotExported { + fieldNames = []string{} + } + return fieldNames +} diff --git a/vendor/github.com/json-iterator/go/feature_reflect_map.go b/vendor/github.com/json-iterator/go/feature_reflect_map.go new file mode 100644 index 000000000..005671e01 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_reflect_map.go @@ -0,0 +1,244 @@ +package jsoniter + +import ( + "encoding" + "encoding/json" + "reflect" + "sort" + "strconv" + "unsafe" +) + +type mapDecoder struct { + mapType reflect.Type + keyType reflect.Type + elemType reflect.Type + elemDecoder ValDecoder + mapInterface emptyInterface +} + +func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + // dark magic to cast unsafe.Pointer back to interface{} using reflect.Type + mapInterface := decoder.mapInterface + mapInterface.word = ptr + realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) + realVal := reflect.ValueOf(*realInterface).Elem() + if iter.ReadNil() { + realVal.Set(reflect.Zero(decoder.mapType)) + return + } + if realVal.IsNil() { + realVal.Set(reflect.MakeMap(realVal.Type())) + } + iter.ReadMapCB(func(iter *Iterator, keyStr string) bool { + elem := reflect.New(decoder.elemType) + decoder.elemDecoder.Decode(unsafe.Pointer(elem.Pointer()), iter) + // to put into map, we have to use reflection + keyType := decoder.keyType + // TODO: remove this from loop + switch { + case keyType.Kind() == reflect.String: + realVal.SetMapIndex(reflect.ValueOf(keyStr).Convert(keyType), elem.Elem()) + return true + case keyType.Implements(textUnmarshalerType): + textUnmarshaler := reflect.New(keyType.Elem()).Interface().(encoding.TextUnmarshaler) + err := textUnmarshaler.UnmarshalText([]byte(keyStr)) + if err != nil { + iter.ReportError("read map key as TextUnmarshaler", err.Error()) + return false + } + realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler), elem.Elem()) + return true + case reflect.PtrTo(keyType).Implements(textUnmarshalerType): + textUnmarshaler := reflect.New(keyType).Interface().(encoding.TextUnmarshaler) + err := textUnmarshaler.UnmarshalText([]byte(keyStr)) + if err != nil { + iter.ReportError("read map key as TextUnmarshaler", err.Error()) + return false + } + realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler).Elem(), elem.Elem()) + return true + default: + switch keyType.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(keyStr, 10, 64) + if err != nil || reflect.Zero(keyType).OverflowInt(n) { + iter.ReportError("read map key as int64", "read int64 failed") + return false + } + realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem()) + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(keyStr, 10, 64) + if err != nil || reflect.Zero(keyType).OverflowUint(n) { + iter.ReportError("read map key as uint64", "read uint64 failed") + return false + } + realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem()) + return true + } + } + iter.ReportError("read map key", "unexpected map key type "+keyType.String()) + return true + }) +} + +type mapEncoder struct { + mapType reflect.Type + elemType reflect.Type + elemEncoder ValEncoder + mapInterface emptyInterface +} + +func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + mapInterface := encoder.mapInterface + mapInterface.word = ptr + realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) + realVal := reflect.ValueOf(*realInterface) + stream.WriteObjectStart() + for i, key := range realVal.MapKeys() { + if i != 0 { + stream.WriteMore() + } + encodeMapKey(key, stream) + if stream.indention > 0 { + stream.writeTwoBytes(byte(':'), byte(' ')) + } else { + stream.writeByte(':') + } + val := realVal.MapIndex(key).Interface() + encoder.elemEncoder.EncodeInterface(val, stream) + } + stream.WriteObjectEnd() +} + +func encodeMapKey(key reflect.Value, stream *Stream) { + if key.Kind() == reflect.String { + stream.WriteString(key.String()) + return + } + if tm, ok := key.Interface().(encoding.TextMarshaler); ok { + buf, err := tm.MarshalText() + if err != nil { + stream.Error = err + return + } + stream.writeByte('"') + stream.Write(buf) + stream.writeByte('"') + return + } + switch key.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + stream.writeByte('"') + stream.WriteInt64(key.Int()) + stream.writeByte('"') + return + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + stream.writeByte('"') + stream.WriteUint64(key.Uint()) + stream.writeByte('"') + return + } + stream.Error = &json.UnsupportedTypeError{Type: key.Type()} +} + +func (encoder *mapEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool { + mapInterface := encoder.mapInterface + mapInterface.word = ptr + realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) + realVal := reflect.ValueOf(*realInterface) + return realVal.Len() == 0 +} + +type sortKeysMapEncoder struct { + mapType reflect.Type + elemType reflect.Type + elemEncoder ValEncoder + mapInterface emptyInterface +} + +func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + mapInterface := encoder.mapInterface + mapInterface.word = ptr + realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) + realVal := reflect.ValueOf(*realInterface) + + // Extract and sort the keys. + keys := realVal.MapKeys() + sv := stringValues(make([]reflectWithString, len(keys))) + for i, v := range keys { + sv[i].v = v + if err := sv[i].resolve(); err != nil { + stream.Error = err + return + } + } + sort.Sort(sv) + + stream.WriteObjectStart() + for i, key := range sv { + if i != 0 { + stream.WriteMore() + } + stream.WriteVal(key.s) // might need html escape, so can not WriteString directly + if stream.indention > 0 { + stream.writeTwoBytes(byte(':'), byte(' ')) + } else { + stream.writeByte(':') + } + val := realVal.MapIndex(key.v).Interface() + encoder.elemEncoder.EncodeInterface(val, stream) + } + stream.WriteObjectEnd() +} + +// stringValues is a slice of reflect.Value holding *reflect.StringValue. +// It implements the methods to sort by string. +type stringValues []reflectWithString + +type reflectWithString struct { + v reflect.Value + s string +} + +func (w *reflectWithString) resolve() error { + if w.v.Kind() == reflect.String { + w.s = w.v.String() + return nil + } + if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok { + buf, err := tm.MarshalText() + w.s = string(buf) + return err + } + switch w.v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + w.s = strconv.FormatInt(w.v.Int(), 10) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + w.s = strconv.FormatUint(w.v.Uint(), 10) + return nil + } + return &json.UnsupportedTypeError{Type: w.v.Type()} +} + +func (sv stringValues) Len() int { return len(sv) } +func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } +func (sv stringValues) Less(i, j int) bool { return sv[i].s < sv[j].s } + +func (encoder *sortKeysMapEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool { + mapInterface := encoder.mapInterface + mapInterface.word = ptr + realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) + realVal := reflect.ValueOf(*realInterface) + return realVal.Len() == 0 +} diff --git a/vendor/github.com/json-iterator/go/feature_reflect_native.go b/vendor/github.com/json-iterator/go/feature_reflect_native.go new file mode 100644 index 000000000..b37dab3d8 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_reflect_native.go @@ -0,0 +1,672 @@ +package jsoniter + +import ( + "encoding" + "encoding/base64" + "encoding/json" + "unsafe" +) + +type stringCodec struct { +} + +func (codec *stringCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*string)(ptr)) = iter.ReadString() +} + +func (codec *stringCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + str := *((*string)(ptr)) + stream.WriteString(str) +} + +func (codec *stringCodec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*string)(ptr)) == "" +} + +type intCodec struct { +} + +func (codec *intCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*int)(ptr)) = iter.ReadInt() +} + +func (codec *intCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt(*((*int)(ptr))) +} + +func (codec *intCodec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *intCodec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int)(ptr)) == 0 +} + +type uintptrCodec struct { +} + +func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*uintptr)(ptr)) = uintptr(iter.ReadUint64()) +} + +func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint64(uint64(*((*uintptr)(ptr)))) +} + +func (codec *uintptrCodec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *uintptrCodec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uintptr)(ptr)) == 0 +} + +type int8Codec struct { +} + +func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*int8)(ptr)) = iter.ReadInt8() +} + +func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt8(*((*int8)(ptr))) +} + +func (codec *int8Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *int8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int8)(ptr)) == 0 +} + +type int16Codec struct { +} + +func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*int16)(ptr)) = iter.ReadInt16() +} + +func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt16(*((*int16)(ptr))) +} + +func (codec *int16Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *int16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int16)(ptr)) == 0 +} + +type int32Codec struct { +} + +func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*int32)(ptr)) = iter.ReadInt32() +} + +func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt32(*((*int32)(ptr))) +} + +func (codec *int32Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *int32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int32)(ptr)) == 0 +} + +type int64Codec struct { +} + +func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*int64)(ptr)) = iter.ReadInt64() +} + +func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt64(*((*int64)(ptr))) +} + +func (codec *int64Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int64)(ptr)) == 0 +} + +type uintCodec struct { +} + +func (codec *uintCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*uint)(ptr)) = iter.ReadUint() +} + +func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint(*((*uint)(ptr))) +} + +func (codec *uintCodec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *uintCodec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint)(ptr)) == 0 +} + +type uint8Codec struct { +} + +func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*uint8)(ptr)) = iter.ReadUint8() +} + +func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint8(*((*uint8)(ptr))) +} + +func (codec *uint8Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *uint8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint8)(ptr)) == 0 +} + +type uint16Codec struct { +} + +func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*uint16)(ptr)) = iter.ReadUint16() +} + +func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint16(*((*uint16)(ptr))) +} + +func (codec *uint16Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *uint16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint16)(ptr)) == 0 +} + +type uint32Codec struct { +} + +func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*uint32)(ptr)) = iter.ReadUint32() +} + +func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint32(*((*uint32)(ptr))) +} + +func (codec *uint32Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *uint32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint32)(ptr)) == 0 +} + +type uint64Codec struct { +} + +func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*uint64)(ptr)) = iter.ReadUint64() +} + +func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint64(*((*uint64)(ptr))) +} + +func (codec *uint64Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *uint64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint64)(ptr)) == 0 +} + +type float32Codec struct { +} + +func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*float32)(ptr)) = iter.ReadFloat32() +} + +func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat32(*((*float32)(ptr))) +} + +func (codec *float32Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *float32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float32)(ptr)) == 0 +} + +type float64Codec struct { +} + +func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*float64)(ptr)) = iter.ReadFloat64() +} + +func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat64(*((*float64)(ptr))) +} + +func (codec *float64Codec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *float64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float64)(ptr)) == 0 +} + +type boolCodec struct { +} + +func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*bool)(ptr)) = iter.ReadBool() +} + +func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteBool(*((*bool)(ptr))) +} + +func (codec *boolCodec) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, codec) +} + +func (codec *boolCodec) IsEmpty(ptr unsafe.Pointer) bool { + return !(*((*bool)(ptr))) +} + +type emptyInterfaceCodec struct { +} + +func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*interface{})(ptr)) = iter.Read() +} + +func (codec *emptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteVal(*((*interface{})(ptr))) +} + +func (codec *emptyInterfaceCodec) EncodeInterface(val interface{}, stream *Stream) { + stream.WriteVal(val) +} + +func (codec *emptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool { + return ptr == nil +} + +type nonEmptyInterfaceCodec struct { +} + +func (codec *nonEmptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + nonEmptyInterface := (*nonEmptyInterface)(ptr) + if nonEmptyInterface.itab == nil { + iter.ReportError("read non-empty interface", "do not know which concrete type to decode to") + return + } + var i interface{} + e := (*emptyInterface)(unsafe.Pointer(&i)) + e.typ = nonEmptyInterface.itab.typ + e.word = nonEmptyInterface.word + iter.ReadVal(&i) + nonEmptyInterface.word = e.word +} + +func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + nonEmptyInterface := (*nonEmptyInterface)(ptr) + var i interface{} + e := (*emptyInterface)(unsafe.Pointer(&i)) + e.typ = nonEmptyInterface.itab.typ + e.word = nonEmptyInterface.word + stream.WriteVal(i) +} + +func (codec *nonEmptyInterfaceCodec) EncodeInterface(val interface{}, stream *Stream) { + stream.WriteVal(val) +} + +func (codec *nonEmptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool { + nonEmptyInterface := (*nonEmptyInterface)(ptr) + return nonEmptyInterface.word == nil +} + +type anyCodec struct { +} + +func (codec *anyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*Any)(ptr)) = iter.ReadAny() +} + +func (codec *anyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + (*((*Any)(ptr))).WriteTo(stream) +} + +func (codec *anyCodec) EncodeInterface(val interface{}, stream *Stream) { + (val.(Any)).WriteTo(stream) +} + +func (codec *anyCodec) IsEmpty(ptr unsafe.Pointer) bool { + return (*((*Any)(ptr))).Size() == 0 +} + +type jsonNumberCodec struct { +} + +func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString())) +} + +func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteRaw(string(*((*json.Number)(ptr)))) +} + +func (codec *jsonNumberCodec) EncodeInterface(val interface{}, stream *Stream) { + stream.WriteRaw(string(val.(json.Number))) +} + +func (codec *jsonNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*json.Number)(ptr))) == 0 +} + +type jsoniterNumberCodec struct { +} + +func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*Number)(ptr)) = Number([]byte(iter.readNumberAsString())) +} + +func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteRaw(string(*((*Number)(ptr)))) +} + +func (codec *jsoniterNumberCodec) EncodeInterface(val interface{}, stream *Stream) { + stream.WriteRaw(string(val.(Number))) +} + +func (codec *jsoniterNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*Number)(ptr))) == 0 +} + +type jsonRawMessageCodec struct { +} + +func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes()) +} + +func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteRaw(string(*((*json.RawMessage)(ptr)))) +} + +func (codec *jsonRawMessageCodec) EncodeInterface(val interface{}, stream *Stream) { + stream.WriteRaw(string(val.(json.RawMessage))) +} + +func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*json.RawMessage)(ptr))) == 0 +} + +type jsoniterRawMessageCodec struct { +} + +func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*RawMessage)(ptr)) = RawMessage(iter.SkipAndReturnBytes()) +} + +func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteRaw(string(*((*RawMessage)(ptr)))) +} + +func (codec *jsoniterRawMessageCodec) EncodeInterface(val interface{}, stream *Stream) { + stream.WriteRaw(string(val.(RawMessage))) +} + +func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*RawMessage)(ptr))) == 0 +} + +type base64Codec struct { + sliceDecoder ValDecoder +} + +func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.ReadNil() { + ptrSlice := (*sliceHeader)(ptr) + ptrSlice.Len = 0 + ptrSlice.Cap = 0 + ptrSlice.Data = nil + return + } + switch iter.WhatIsNext() { + case StringValue: + encoding := base64.StdEncoding + src := iter.SkipAndReturnBytes() + src = src[1 : len(src)-1] + decodedLen := encoding.DecodedLen(len(src)) + dst := make([]byte, decodedLen) + len, err := encoding.Decode(dst, src) + if err != nil { + iter.ReportError("decode base64", err.Error()) + } else { + dst = dst[:len] + dstSlice := (*sliceHeader)(unsafe.Pointer(&dst)) + ptrSlice := (*sliceHeader)(ptr) + ptrSlice.Data = dstSlice.Data + ptrSlice.Cap = dstSlice.Cap + ptrSlice.Len = dstSlice.Len + } + case ArrayValue: + codec.sliceDecoder.Decode(ptr, iter) + default: + iter.ReportError("base64Codec", "invalid input") + } +} + +func (codec *base64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + src := *((*[]byte)(ptr)) + if len(src) == 0 { + stream.WriteNil() + return + } + encoding := base64.StdEncoding + stream.writeByte('"') + toGrow := encoding.EncodedLen(len(src)) + stream.ensure(toGrow) + encoding.Encode(stream.buf[stream.n:], src) + stream.n += toGrow + stream.writeByte('"') +} + +func (codec *base64Codec) EncodeInterface(val interface{}, stream *Stream) { + ptr := extractInterface(val).word + src := *((*[]byte)(ptr)) + if len(src) == 0 { + stream.WriteNil() + return + } + encoding := base64.StdEncoding + stream.writeByte('"') + toGrow := encoding.EncodedLen(len(src)) + stream.ensure(toGrow) + encoding.Encode(stream.buf[stream.n:], src) + stream.n += toGrow + stream.writeByte('"') +} + +func (codec *base64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*[]byte)(ptr))) == 0 +} + +type stringModeNumberDecoder struct { + elemDecoder ValDecoder +} + +func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.nextToken() + if c != '"' { + iter.ReportError("stringModeNumberDecoder", `expect "`) + return + } + decoder.elemDecoder.Decode(ptr, iter) + if iter.Error != nil { + return + } + c = iter.readByte() + if c != '"' { + iter.ReportError("stringModeNumberDecoder", `expect "`) + return + } +} + +type stringModeStringDecoder struct { + elemDecoder ValDecoder + cfg *frozenConfig +} + +func (decoder *stringModeStringDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.elemDecoder.Decode(ptr, iter) + str := *((*string)(ptr)) + tempIter := decoder.cfg.BorrowIterator([]byte(str)) + defer decoder.cfg.ReturnIterator(tempIter) + *((*string)(ptr)) = tempIter.ReadString() +} + +type stringModeNumberEncoder struct { + elemEncoder ValEncoder +} + +func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.writeByte('"') + encoder.elemEncoder.Encode(ptr, stream) + stream.writeByte('"') +} + +func (encoder *stringModeNumberEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.elemEncoder.IsEmpty(ptr) +} + +type stringModeStringEncoder struct { + elemEncoder ValEncoder + cfg *frozenConfig +} + +func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + tempStream := encoder.cfg.BorrowStream(nil) + defer encoder.cfg.ReturnStream(tempStream) + encoder.elemEncoder.Encode(ptr, tempStream) + stream.WriteString(string(tempStream.Buffer())) +} + +func (encoder *stringModeStringEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.elemEncoder.IsEmpty(ptr) +} + +type marshalerEncoder struct { + templateInterface emptyInterface + checkIsEmpty checkIsEmpty +} + +func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + templateInterface := encoder.templateInterface + templateInterface.word = ptr + realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) + marshaler := (*realInterface).(json.Marshaler) + bytes, err := marshaler.MarshalJSON() + if err != nil { + stream.Error = err + } else { + stream.Write(bytes) + } +} +func (encoder *marshalerEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type textMarshalerEncoder struct { + templateInterface emptyInterface + checkIsEmpty checkIsEmpty +} + +func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + templateInterface := encoder.templateInterface + templateInterface.word = ptr + realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) + marshaler := (*realInterface).(encoding.TextMarshaler) + bytes, err := marshaler.MarshalText() + if err != nil { + stream.Error = err + } else { + stream.WriteString(string(bytes)) + } +} + +func (encoder *textMarshalerEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type unmarshalerDecoder struct { + templateInterface emptyInterface +} + +func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + templateInterface := decoder.templateInterface + templateInterface.word = ptr + realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) + unmarshaler := (*realInterface).(json.Unmarshaler) + iter.nextToken() + iter.unreadByte() // skip spaces + bytes := iter.SkipAndReturnBytes() + err := unmarshaler.UnmarshalJSON(bytes) + if err != nil { + iter.ReportError("unmarshalerDecoder", err.Error()) + } +} + +type textUnmarshalerDecoder struct { + templateInterface emptyInterface +} + +func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + templateInterface := decoder.templateInterface + templateInterface.word = ptr + realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) + unmarshaler := (*realInterface).(encoding.TextUnmarshaler) + str := iter.ReadString() + err := unmarshaler.UnmarshalText([]byte(str)) + if err != nil { + iter.ReportError("textUnmarshalerDecoder", err.Error()) + } +} diff --git a/vendor/github.com/json-iterator/go/feature_reflect_object.go b/vendor/github.com/json-iterator/go/feature_reflect_object.go new file mode 100644 index 000000000..59b1235c0 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_reflect_object.go @@ -0,0 +1,196 @@ +package jsoniter + +import ( + "fmt" + "io" + "reflect" + "strings" + "unsafe" +) + +func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { + type bindingTo struct { + binding *Binding + toName string + ignored bool + } + orderedBindings := []*bindingTo{} + structDescriptor, err := describeStruct(cfg, typ) + if err != nil { + return nil, err + } + for _, binding := range structDescriptor.Fields { + for _, toName := range binding.ToNames { + new := &bindingTo{ + binding: binding, + toName: toName, + } + for _, old := range orderedBindings { + if old.toName != toName { + continue + } + old.ignored, new.ignored = resolveConflictBinding(cfg, old.binding, new.binding) + } + orderedBindings = append(orderedBindings, new) + } + } + if len(orderedBindings) == 0 { + return &emptyStructEncoder{}, nil + } + finalOrderedFields := []structFieldTo{} + for _, bindingTo := range orderedBindings { + if !bindingTo.ignored { + finalOrderedFields = append(finalOrderedFields, structFieldTo{ + encoder: bindingTo.binding.Encoder.(*structFieldEncoder), + toName: bindingTo.toName, + }) + } + } + return &structEncoder{structDescriptor.onePtrEmbedded, structDescriptor.onePtrOptimization, finalOrderedFields}, nil +} + +func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) { + newTagged := new.Field.Tag.Get(cfg.getTagKey()) != "" + oldTagged := old.Field.Tag.Get(cfg.getTagKey()) != "" + if newTagged { + if oldTagged { + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } else { + return true, false + } + } else { + if oldTagged { + return true, false + } + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } +} + +func decoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { + bindings := map[string]*Binding{} + structDescriptor, err := describeStruct(cfg, typ) + if err != nil { + return nil, err + } + for _, binding := range structDescriptor.Fields { + for _, fromName := range binding.FromNames { + old := bindings[fromName] + if old == nil { + bindings[fromName] = binding + continue + } + ignoreOld, ignoreNew := resolveConflictBinding(cfg, old, binding) + if ignoreOld { + delete(bindings, fromName) + } + if !ignoreNew { + bindings[fromName] = binding + } + } + } + fields := map[string]*structFieldDecoder{} + for k, binding := range bindings { + fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder) + } + return createStructDecoder(typ, fields) +} + +type structFieldEncoder struct { + field *reflect.StructField + fieldEncoder ValEncoder + omitempty bool +} + +func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + fieldPtr := unsafe.Pointer(uintptr(ptr) + encoder.field.Offset) + encoder.fieldEncoder.Encode(fieldPtr, stream) + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%s: %s", encoder.field.Name, stream.Error.Error()) + } +} + +func (encoder *structFieldEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { + fieldPtr := unsafe.Pointer(uintptr(ptr) + encoder.field.Offset) + return encoder.fieldEncoder.IsEmpty(fieldPtr) +} + +type structEncoder struct { + onePtrEmbedded bool + onePtrOptimization bool + fields []structFieldTo +} + +type structFieldTo struct { + encoder *structFieldEncoder + toName string +} + +func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteObjectStart() + isNotFirst := false + for _, field := range encoder.fields { + if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { + continue + } + if isNotFirst { + stream.WriteMore() + } + stream.WriteObjectField(field.toName) + field.encoder.Encode(ptr, stream) + isNotFirst = true + } + stream.WriteObjectEnd() +} + +func (encoder *structEncoder) EncodeInterface(val interface{}, stream *Stream) { + e := (*emptyInterface)(unsafe.Pointer(&val)) + if encoder.onePtrOptimization { + if e.word == nil && encoder.onePtrEmbedded { + stream.WriteObjectStart() + stream.WriteObjectEnd() + return + } + ptr := uintptr(e.word) + e.word = unsafe.Pointer(&ptr) + } + if reflect.TypeOf(val).Kind() == reflect.Ptr { + encoder.Encode(unsafe.Pointer(&e.word), stream) + } else { + encoder.Encode(e.word, stream) + } +} + +func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type emptyStructEncoder struct { +} + +func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteEmptyObject() +} + +func (encoder *emptyStructEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} diff --git a/vendor/github.com/json-iterator/go/feature_reflect_slice.go b/vendor/github.com/json-iterator/go/feature_reflect_slice.go new file mode 100644 index 000000000..7377eec7b --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_reflect_slice.go @@ -0,0 +1,149 @@ +package jsoniter + +import ( + "fmt" + "io" + "reflect" + "unsafe" +) + +func decoderOfSlice(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { + decoder, err := decoderOfType(cfg, typ.Elem()) + if err != nil { + return nil, err + } + return &sliceDecoder{typ, typ.Elem(), decoder}, nil +} + +func encoderOfSlice(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { + encoder, err := encoderOfType(cfg, typ.Elem()) + if err != nil { + return nil, err + } + if typ.Elem().Kind() == reflect.Map { + encoder = &optionalEncoder{encoder} + } + return &sliceEncoder{typ, typ.Elem(), encoder}, nil +} + +type sliceEncoder struct { + sliceType reflect.Type + elemType reflect.Type + elemEncoder ValEncoder +} + +func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + slice := (*sliceHeader)(ptr) + if slice.Data == nil { + stream.WriteNil() + return + } + if slice.Len == 0 { + stream.WriteEmptyArray() + return + } + stream.WriteArrayStart() + elemPtr := unsafe.Pointer(slice.Data) + encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream) + for i := 1; i < slice.Len; i++ { + stream.WriteMore() + elemPtr = unsafe.Pointer(uintptr(elemPtr) + encoder.elemType.Size()) + encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream) + } + stream.WriteArrayEnd() + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error()) + } +} + +func (encoder *sliceEncoder) EncodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + slice := (*sliceHeader)(ptr) + return slice.Len == 0 +} + +type sliceDecoder struct { + sliceType reflect.Type + elemType reflect.Type + elemDecoder ValDecoder +} + +// sliceHeader is a safe version of SliceHeader used within this package. +type sliceHeader struct { + Data unsafe.Pointer + Len int + Cap int +} + +func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.doDecode(ptr, iter) + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error()) + } +} + +func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { + slice := (*sliceHeader)(ptr) + if iter.ReadNil() { + slice.Len = 0 + slice.Cap = 0 + slice.Data = nil + return + } + reuseSlice(slice, decoder.sliceType, 4) + slice.Len = 0 + offset := uintptr(0) + iter.ReadArrayCB(func(iter *Iterator) bool { + growOne(slice, decoder.sliceType, decoder.elemType) + decoder.elemDecoder.Decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter) + offset += decoder.elemType.Size() + return true + }) +} + +// grow grows the slice s so that it can hold extra more values, allocating +// more capacity if needed. It also returns the old and new slice lengths. +func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) { + newLen := slice.Len + 1 + if newLen <= slice.Cap { + slice.Len = newLen + return + } + newCap := slice.Cap + if newCap == 0 { + newCap = 1 + } else { + for newCap < newLen { + if slice.Len < 1024 { + newCap += newCap + } else { + newCap += newCap / 4 + } + } + } + newVal := reflect.MakeSlice(sliceType, newLen, newCap) + dst := unsafe.Pointer(newVal.Pointer()) + // copy old array into new array + originalBytesCount := uintptr(slice.Len) * elementType.Size() + srcPtr := (*[1 << 30]byte)(slice.Data) + dstPtr := (*[1 << 30]byte)(dst) + for i := uintptr(0); i < originalBytesCount; i++ { + dstPtr[i] = srcPtr[i] + } + slice.Data = dst + slice.Len = newLen + slice.Cap = newCap +} + +func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) { + if expectedCap <= slice.Cap { + return + } + newVal := reflect.MakeSlice(sliceType, 0, expectedCap) + dst := unsafe.Pointer(newVal.Pointer()) + slice.Data = dst + slice.Cap = expectedCap +} diff --git a/vendor/github.com/json-iterator/go/feature_reflect_struct_decoder.go b/vendor/github.com/json-iterator/go/feature_reflect_struct_decoder.go new file mode 100644 index 000000000..b3417fd73 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_reflect_struct_decoder.go @@ -0,0 +1,916 @@ +package jsoniter + +import ( + "fmt" + "io" + "reflect" + "strings" + "unsafe" +) + +func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder) (ValDecoder, error) { + knownHash := map[int32]struct{}{ + 0: {}, + } + switch len(fields) { + case 0: + return &skipObjectDecoder{typ}, nil + case 1: + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder}, nil + } + case 2: + var fieldHash1 int32 + var fieldHash2 int32 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + if fieldHash1 == 0 { + fieldHash1 = fieldHash + fieldDecoder1 = fieldDecoder + } else { + fieldHash2 = fieldHash + fieldDecoder2 = fieldDecoder + } + } + return &twoFieldsStructDecoder{typ, fieldHash1, fieldDecoder1, fieldHash2, fieldDecoder2}, nil + case 3: + var fieldName1 int32 + var fieldName2 int32 + var fieldName3 int32 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } + } + return &threeFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil + case 4: + var fieldName1 int32 + var fieldName2 int32 + var fieldName3 int32 + var fieldName4 int32 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } + } + return &fourFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4}, nil + case 5: + var fieldName1 int32 + var fieldName2 int32 + var fieldName3 int32 + var fieldName4 int32 + var fieldName5 int32 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } + } + return &fiveFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil + case 6: + var fieldName1 int32 + var fieldName2 int32 + var fieldName3 int32 + var fieldName4 int32 + var fieldName5 int32 + var fieldName6 int32 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } + } + return &sixFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil + case 7: + var fieldName1 int32 + var fieldName2 int32 + var fieldName3 int32 + var fieldName4 int32 + var fieldName5 int32 + var fieldName6 int32 + var fieldName7 int32 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } + } + return &sevenFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7}, nil + case 8: + var fieldName1 int32 + var fieldName2 int32 + var fieldName3 int32 + var fieldName4 int32 + var fieldName5 int32 + var fieldName6 int32 + var fieldName7 int32 + var fieldName8 int32 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + var fieldDecoder8 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else if fieldName7 == 0 { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } else { + fieldName8 = fieldHash + fieldDecoder8 = fieldDecoder + } + } + return &eightFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil + case 9: + var fieldName1 int32 + var fieldName2 int32 + var fieldName3 int32 + var fieldName4 int32 + var fieldName5 int32 + var fieldName6 int32 + var fieldName7 int32 + var fieldName8 int32 + var fieldName9 int32 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + var fieldDecoder8 *structFieldDecoder + var fieldDecoder9 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else if fieldName7 == 0 { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } else if fieldName8 == 0 { + fieldName8 = fieldHash + fieldDecoder8 = fieldDecoder + } else { + fieldName9 = fieldHash + fieldDecoder9 = fieldDecoder + } + } + return &nineFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil + case 10: + var fieldName1 int32 + var fieldName2 int32 + var fieldName3 int32 + var fieldName4 int32 + var fieldName5 int32 + var fieldName6 int32 + var fieldName7 int32 + var fieldName8 int32 + var fieldName9 int32 + var fieldName10 int32 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + var fieldDecoder8 *structFieldDecoder + var fieldDecoder9 *structFieldDecoder + var fieldDecoder10 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields}, nil + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else if fieldName7 == 0 { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } else if fieldName8 == 0 { + fieldName8 = fieldHash + fieldDecoder8 = fieldDecoder + } else if fieldName9 == 0 { + fieldName9 = fieldHash + fieldDecoder9 = fieldDecoder + } else { + fieldName10 = fieldHash + fieldDecoder10 = fieldDecoder + } + } + return &tenFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9, + fieldName10, fieldDecoder10}, nil + } + return &generalStructDecoder{typ, fields}, nil +} + +type generalStructDecoder struct { + typ reflect.Type + fields map[string]*structFieldDecoder +} + +func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + fieldBytes := iter.readObjectFieldAsBytes() + field := *(*string)(unsafe.Pointer(&fieldBytes)) + fieldDecoder := decoder.fields[strings.ToLower(field)] + if fieldDecoder == nil { + iter.Skip() + } else { + fieldDecoder.Decode(ptr, iter) + } + for iter.nextToken() == ',' { + fieldBytes = iter.readObjectFieldAsBytes() + field = *(*string)(unsafe.Pointer(&fieldBytes)) + fieldDecoder = decoder.fields[strings.ToLower(field)] + if fieldDecoder == nil { + iter.Skip() + } else { + fieldDecoder.Decode(ptr, iter) + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type skipObjectDecoder struct { + typ reflect.Type +} + +func (decoder *skipObjectDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + valueType := iter.WhatIsNext() + if valueType != ObjectValue && valueType != NilValue { + iter.ReportError("skipObjectDecoder", "expect object or null") + return + } + iter.Skip() +} + +type oneFieldStructDecoder struct { + typ reflect.Type + fieldHash int32 + fieldDecoder *structFieldDecoder +} + +func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + if iter.readFieldHash() == decoder.fieldHash { + decoder.fieldDecoder.Decode(ptr, iter) + } else { + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type twoFieldsStructDecoder struct { + typ reflect.Type + fieldHash1 int32 + fieldDecoder1 *structFieldDecoder + fieldHash2 int32 + fieldDecoder2 *structFieldDecoder +} + +func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type threeFieldsStructDecoder struct { + typ reflect.Type + fieldHash1 int32 + fieldDecoder1 *structFieldDecoder + fieldHash2 int32 + fieldDecoder2 *structFieldDecoder + fieldHash3 int32 + fieldDecoder3 *structFieldDecoder +} + +func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type fourFieldsStructDecoder struct { + typ reflect.Type + fieldHash1 int32 + fieldDecoder1 *structFieldDecoder + fieldHash2 int32 + fieldDecoder2 *structFieldDecoder + fieldHash3 int32 + fieldDecoder3 *structFieldDecoder + fieldHash4 int32 + fieldDecoder4 *structFieldDecoder +} + +func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type fiveFieldsStructDecoder struct { + typ reflect.Type + fieldHash1 int32 + fieldDecoder1 *structFieldDecoder + fieldHash2 int32 + fieldDecoder2 *structFieldDecoder + fieldHash3 int32 + fieldDecoder3 *structFieldDecoder + fieldHash4 int32 + fieldDecoder4 *structFieldDecoder + fieldHash5 int32 + fieldDecoder5 *structFieldDecoder +} + +func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type sixFieldsStructDecoder struct { + typ reflect.Type + fieldHash1 int32 + fieldDecoder1 *structFieldDecoder + fieldHash2 int32 + fieldDecoder2 *structFieldDecoder + fieldHash3 int32 + fieldDecoder3 *structFieldDecoder + fieldHash4 int32 + fieldDecoder4 *structFieldDecoder + fieldHash5 int32 + fieldDecoder5 *structFieldDecoder + fieldHash6 int32 + fieldDecoder6 *structFieldDecoder +} + +func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type sevenFieldsStructDecoder struct { + typ reflect.Type + fieldHash1 int32 + fieldDecoder1 *structFieldDecoder + fieldHash2 int32 + fieldDecoder2 *structFieldDecoder + fieldHash3 int32 + fieldDecoder3 *structFieldDecoder + fieldHash4 int32 + fieldDecoder4 *structFieldDecoder + fieldHash5 int32 + fieldDecoder5 *structFieldDecoder + fieldHash6 int32 + fieldDecoder6 *structFieldDecoder + fieldHash7 int32 + fieldDecoder7 *structFieldDecoder +} + +func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type eightFieldsStructDecoder struct { + typ reflect.Type + fieldHash1 int32 + fieldDecoder1 *structFieldDecoder + fieldHash2 int32 + fieldDecoder2 *structFieldDecoder + fieldHash3 int32 + fieldDecoder3 *structFieldDecoder + fieldHash4 int32 + fieldDecoder4 *structFieldDecoder + fieldHash5 int32 + fieldDecoder5 *structFieldDecoder + fieldHash6 int32 + fieldDecoder6 *structFieldDecoder + fieldHash7 int32 + fieldDecoder7 *structFieldDecoder + fieldHash8 int32 + fieldDecoder8 *structFieldDecoder +} + +func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + case decoder.fieldHash8: + decoder.fieldDecoder8.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type nineFieldsStructDecoder struct { + typ reflect.Type + fieldHash1 int32 + fieldDecoder1 *structFieldDecoder + fieldHash2 int32 + fieldDecoder2 *structFieldDecoder + fieldHash3 int32 + fieldDecoder3 *structFieldDecoder + fieldHash4 int32 + fieldDecoder4 *structFieldDecoder + fieldHash5 int32 + fieldDecoder5 *structFieldDecoder + fieldHash6 int32 + fieldDecoder6 *structFieldDecoder + fieldHash7 int32 + fieldDecoder7 *structFieldDecoder + fieldHash8 int32 + fieldDecoder8 *structFieldDecoder + fieldHash9 int32 + fieldDecoder9 *structFieldDecoder +} + +func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + case decoder.fieldHash8: + decoder.fieldDecoder8.Decode(ptr, iter) + case decoder.fieldHash9: + decoder.fieldDecoder9.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type tenFieldsStructDecoder struct { + typ reflect.Type + fieldHash1 int32 + fieldDecoder1 *structFieldDecoder + fieldHash2 int32 + fieldDecoder2 *structFieldDecoder + fieldHash3 int32 + fieldDecoder3 *structFieldDecoder + fieldHash4 int32 + fieldDecoder4 *structFieldDecoder + fieldHash5 int32 + fieldDecoder5 *structFieldDecoder + fieldHash6 int32 + fieldDecoder6 *structFieldDecoder + fieldHash7 int32 + fieldDecoder7 *structFieldDecoder + fieldHash8 int32 + fieldDecoder8 *structFieldDecoder + fieldHash9 int32 + fieldDecoder9 *structFieldDecoder + fieldHash10 int32 + fieldDecoder10 *structFieldDecoder +} + +func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + case decoder.fieldHash8: + decoder.fieldDecoder8.Decode(ptr, iter) + case decoder.fieldHash9: + decoder.fieldDecoder9.Decode(ptr, iter) + case decoder.fieldHash10: + decoder.fieldDecoder10.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) + } +} + +type structFieldDecoder struct { + field *reflect.StructField + fieldDecoder ValDecoder +} + +func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + fieldPtr := unsafe.Pointer(uintptr(ptr) + decoder.field.Offset) + decoder.fieldDecoder.Decode(fieldPtr, iter) + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error()) + } +} diff --git a/vendor/github.com/json-iterator/go/feature_stream.go b/vendor/github.com/json-iterator/go/feature_stream.go new file mode 100644 index 000000000..9c8470a03 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_stream.go @@ -0,0 +1,305 @@ +package jsoniter + +import ( + "io" +) + +// Stream is a io.Writer like object, with JSON specific write functions. +// Error is not returned as return value, but stored as Error member on this stream instance. +type Stream struct { + cfg *frozenConfig + out io.Writer + buf []byte + n int + Error error + indention int +} + +// NewStream create new stream instance. +// cfg can be jsoniter.ConfigDefault. +// out can be nil if write to internal buffer. +// bufSize is the initial size for the internal buffer in bytes. +func NewStream(cfg API, out io.Writer, bufSize int) *Stream { + return &Stream{ + cfg: cfg.(*frozenConfig), + out: out, + buf: make([]byte, bufSize), + n: 0, + Error: nil, + indention: 0, + } +} + +// Pool returns a pool can provide more stream with same configuration +func (stream *Stream) Pool() StreamPool { + return stream.cfg +} + +// Reset reuse this stream instance by assign a new writer +func (stream *Stream) Reset(out io.Writer) { + stream.out = out + stream.n = 0 +} + +// Available returns how many bytes are unused in the buffer. +func (stream *Stream) Available() int { + return len(stream.buf) - stream.n +} + +// Buffered returns the number of bytes that have been written into the current buffer. +func (stream *Stream) Buffered() int { + return stream.n +} + +// Buffer if writer is nil, use this method to take the result +func (stream *Stream) Buffer() []byte { + return stream.buf[:stream.n] +} + +// Write writes the contents of p into the buffer. +// It returns the number of bytes written. +// If nn < len(p), it also returns an error explaining +// why the write is short. +func (stream *Stream) Write(p []byte) (nn int, err error) { + for len(p) > stream.Available() && stream.Error == nil { + if stream.out == nil { + stream.growAtLeast(len(p)) + } else { + var n int + if stream.Buffered() == 0 { + // Large write, empty buffer. + // Write directly from p to avoid copy. + n, stream.Error = stream.out.Write(p) + } else { + n = copy(stream.buf[stream.n:], p) + stream.n += n + stream.Flush() + } + nn += n + p = p[n:] + } + } + if stream.Error != nil { + return nn, stream.Error + } + n := copy(stream.buf[stream.n:], p) + stream.n += n + nn += n + return nn, nil +} + +// WriteByte writes a single byte. +func (stream *Stream) writeByte(c byte) { + if stream.Error != nil { + return + } + if stream.Available() < 1 { + stream.growAtLeast(1) + } + stream.buf[stream.n] = c + stream.n++ +} + +func (stream *Stream) writeTwoBytes(c1 byte, c2 byte) { + if stream.Error != nil { + return + } + if stream.Available() < 2 { + stream.growAtLeast(2) + } + stream.buf[stream.n] = c1 + stream.buf[stream.n+1] = c2 + stream.n += 2 +} + +func (stream *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) { + if stream.Error != nil { + return + } + if stream.Available() < 3 { + stream.growAtLeast(3) + } + stream.buf[stream.n] = c1 + stream.buf[stream.n+1] = c2 + stream.buf[stream.n+2] = c3 + stream.n += 3 +} + +func (stream *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) { + if stream.Error != nil { + return + } + if stream.Available() < 4 { + stream.growAtLeast(4) + } + stream.buf[stream.n] = c1 + stream.buf[stream.n+1] = c2 + stream.buf[stream.n+2] = c3 + stream.buf[stream.n+3] = c4 + stream.n += 4 +} + +func (stream *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) { + if stream.Error != nil { + return + } + if stream.Available() < 5 { + stream.growAtLeast(5) + } + stream.buf[stream.n] = c1 + stream.buf[stream.n+1] = c2 + stream.buf[stream.n+2] = c3 + stream.buf[stream.n+3] = c4 + stream.buf[stream.n+4] = c5 + stream.n += 5 +} + +// Flush writes any buffered data to the underlying io.Writer. +func (stream *Stream) Flush() error { + if stream.out == nil { + return nil + } + if stream.Error != nil { + return stream.Error + } + if stream.n == 0 { + return nil + } + n, err := stream.out.Write(stream.buf[0:stream.n]) + if n < stream.n && err == nil { + err = io.ErrShortWrite + } + if err != nil { + if n > 0 && n < stream.n { + copy(stream.buf[0:stream.n-n], stream.buf[n:stream.n]) + } + stream.n -= n + stream.Error = err + return err + } + stream.n = 0 + return nil +} + +func (stream *Stream) ensure(minimal int) { + available := stream.Available() + if available < minimal { + stream.growAtLeast(minimal) + } +} + +func (stream *Stream) growAtLeast(minimal int) { + if stream.out != nil { + stream.Flush() + } + toGrow := len(stream.buf) + if toGrow < minimal { + toGrow = minimal + } + newBuf := make([]byte, len(stream.buf)+toGrow) + copy(newBuf, stream.Buffer()) + stream.buf = newBuf +} + +// WriteRaw write string out without quotes, just like []byte +func (stream *Stream) WriteRaw(s string) { + stream.ensure(len(s)) + if stream.Error != nil { + return + } + n := copy(stream.buf[stream.n:], s) + stream.n += n +} + +// WriteNil write null to stream +func (stream *Stream) WriteNil() { + stream.writeFourBytes('n', 'u', 'l', 'l') +} + +// WriteTrue write true to stream +func (stream *Stream) WriteTrue() { + stream.writeFourBytes('t', 'r', 'u', 'e') +} + +// WriteFalse write false to stream +func (stream *Stream) WriteFalse() { + stream.writeFiveBytes('f', 'a', 'l', 's', 'e') +} + +// WriteBool write true or false into stream +func (stream *Stream) WriteBool(val bool) { + if val { + stream.WriteTrue() + } else { + stream.WriteFalse() + } +} + +// WriteObjectStart write { with possible indention +func (stream *Stream) WriteObjectStart() { + stream.indention += stream.cfg.indentionStep + stream.writeByte('{') + stream.writeIndention(0) +} + +// WriteObjectField write "field": with possible indention +func (stream *Stream) WriteObjectField(field string) { + stream.WriteString(field) + if stream.indention > 0 { + stream.writeTwoBytes(':', ' ') + } else { + stream.writeByte(':') + } +} + +// WriteObjectEnd write } with possible indention +func (stream *Stream) WriteObjectEnd() { + stream.writeIndention(stream.cfg.indentionStep) + stream.indention -= stream.cfg.indentionStep + stream.writeByte('}') +} + +// WriteEmptyObject write {} +func (stream *Stream) WriteEmptyObject() { + stream.writeByte('{') + stream.writeByte('}') +} + +// WriteMore write , with possible indention +func (stream *Stream) WriteMore() { + stream.writeByte(',') + stream.writeIndention(0) +} + +// WriteArrayStart write [ with possible indention +func (stream *Stream) WriteArrayStart() { + stream.indention += stream.cfg.indentionStep + stream.writeByte('[') + stream.writeIndention(0) +} + +// WriteEmptyArray write [] +func (stream *Stream) WriteEmptyArray() { + stream.writeByte('[') + stream.writeByte(']') +} + +// WriteArrayEnd write ] with possible indention +func (stream *Stream) WriteArrayEnd() { + stream.writeIndention(stream.cfg.indentionStep) + stream.indention -= stream.cfg.indentionStep + stream.writeByte(']') +} + +func (stream *Stream) writeIndention(delta int) { + if stream.indention == 0 { + return + } + stream.writeByte('\n') + toWrite := stream.indention - delta + stream.ensure(toWrite) + for i := 0; i < toWrite && stream.n < len(stream.buf); i++ { + stream.buf[stream.n] = ' ' + stream.n++ + } +} diff --git a/vendor/github.com/json-iterator/go/feature_stream_float.go b/vendor/github.com/json-iterator/go/feature_stream_float.go new file mode 100644 index 000000000..9a404e11d --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_stream_float.go @@ -0,0 +1,96 @@ +package jsoniter + +import ( + "math" + "strconv" +) + +var pow10 []uint64 + +func init() { + pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000} +} + +// WriteFloat32 write float32 to stream +func (stream *Stream) WriteFloat32(val float32) { + abs := math.Abs(float64(val)) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if float32(abs) < 1e-6 || float32(abs) >= 1e21 { + fmt = 'e' + } + } + stream.WriteRaw(strconv.FormatFloat(float64(val), fmt, -1, 32)) +} + +// WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster +func (stream *Stream) WriteFloat32Lossy(val float32) { + if val < 0 { + stream.writeByte('-') + val = -val + } + if val > 0x4ffffff { + stream.WriteFloat32(val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(float64(val)*float64(exp) + 0.5) + stream.WriteUint64(lval / exp) + fval := lval % exp + if fval == 0 { + return + } + stream.writeByte('.') + stream.ensure(10) + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + stream.writeByte('0') + } + stream.WriteUint64(fval) + for stream.buf[stream.n-1] == '0' { + stream.n-- + } +} + +// WriteFloat64 write float64 to stream +func (stream *Stream) WriteFloat64(val float64) { + abs := math.Abs(val) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + stream.WriteRaw(strconv.FormatFloat(float64(val), fmt, -1, 64)) +} + +// WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster +func (stream *Stream) WriteFloat64Lossy(val float64) { + if val < 0 { + stream.writeByte('-') + val = -val + } + if val > 0x4ffffff { + stream.WriteFloat64(val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(val*float64(exp) + 0.5) + stream.WriteUint64(lval / exp) + fval := lval % exp + if fval == 0 { + return + } + stream.writeByte('.') + stream.ensure(10) + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + stream.writeByte('0') + } + stream.WriteUint64(fval) + for stream.buf[stream.n-1] == '0' { + stream.n-- + } +} diff --git a/vendor/github.com/json-iterator/go/feature_stream_int.go b/vendor/github.com/json-iterator/go/feature_stream_int.go new file mode 100644 index 000000000..7cfd522c1 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_stream_int.go @@ -0,0 +1,320 @@ +package jsoniter + +var digits []uint32 + +func init() { + digits = make([]uint32, 1000) + for i := uint32(0); i < 1000; i++ { + digits[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0' + if i < 10 { + digits[i] += 2 << 24 + } else if i < 100 { + digits[i] += 1 << 24 + } + } +} + +func writeFirstBuf(buf []byte, v uint32, n int) int { + start := v >> 24 + if start == 0 { + buf[n] = byte(v >> 16) + n++ + buf[n] = byte(v >> 8) + n++ + } else if start == 1 { + buf[n] = byte(v >> 8) + n++ + } + buf[n] = byte(v) + n++ + return n +} + +func writeBuf(buf []byte, v uint32, n int) { + buf[n] = byte(v >> 16) + buf[n+1] = byte(v >> 8) + buf[n+2] = byte(v) +} + +// WriteUint8 write uint8 to stream +func (stream *Stream) WriteUint8(val uint8) { + stream.ensure(3) + stream.n = writeFirstBuf(stream.buf, digits[val], stream.n) +} + +// WriteInt8 write int8 to stream +func (stream *Stream) WriteInt8(nval int8) { + stream.ensure(4) + n := stream.n + var val uint8 + if nval < 0 { + val = uint8(-nval) + stream.buf[n] = '-' + n++ + } else { + val = uint8(nval) + } + stream.n = writeFirstBuf(stream.buf, digits[val], n) +} + +// WriteUint16 write uint16 to stream +func (stream *Stream) WriteUint16(val uint16) { + stream.ensure(5) + q1 := val / 1000 + if q1 == 0 { + stream.n = writeFirstBuf(stream.buf, digits[val], stream.n) + return + } + r1 := val - q1*1000 + n := writeFirstBuf(stream.buf, digits[q1], stream.n) + writeBuf(stream.buf, digits[r1], n) + stream.n = n + 3 + return +} + +// WriteInt16 write int16 to stream +func (stream *Stream) WriteInt16(nval int16) { + stream.ensure(6) + n := stream.n + var val uint16 + if nval < 0 { + val = uint16(-nval) + stream.buf[n] = '-' + n++ + } else { + val = uint16(nval) + } + q1 := val / 1000 + if q1 == 0 { + stream.n = writeFirstBuf(stream.buf, digits[val], n) + return + } + r1 := val - q1*1000 + n = writeFirstBuf(stream.buf, digits[q1], n) + writeBuf(stream.buf, digits[r1], n) + stream.n = n + 3 + return +} + +// WriteUint32 write uint32 to stream +func (stream *Stream) WriteUint32(val uint32) { + stream.ensure(10) + n := stream.n + q1 := val / 1000 + if q1 == 0 { + stream.n = writeFirstBuf(stream.buf, digits[val], n) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + n := writeFirstBuf(stream.buf, digits[q1], n) + writeBuf(stream.buf, digits[r1], n) + stream.n = n + 3 + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + n = writeFirstBuf(stream.buf, digits[q2], n) + } else { + r3 := q2 - q3*1000 + stream.buf[n] = byte(q3 + '0') + n++ + writeBuf(stream.buf, digits[r3], n) + n += 3 + } + writeBuf(stream.buf, digits[r2], n) + writeBuf(stream.buf, digits[r1], n+3) + stream.n = n + 6 +} + +// WriteInt32 write int32 to stream +func (stream *Stream) WriteInt32(nval int32) { + stream.ensure(11) + n := stream.n + var val uint32 + if nval < 0 { + val = uint32(-nval) + stream.buf[n] = '-' + n++ + } else { + val = uint32(nval) + } + q1 := val / 1000 + if q1 == 0 { + stream.n = writeFirstBuf(stream.buf, digits[val], n) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + n := writeFirstBuf(stream.buf, digits[q1], n) + writeBuf(stream.buf, digits[r1], n) + stream.n = n + 3 + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + n = writeFirstBuf(stream.buf, digits[q2], n) + } else { + r3 := q2 - q3*1000 + stream.buf[n] = byte(q3 + '0') + n++ + writeBuf(stream.buf, digits[r3], n) + n += 3 + } + writeBuf(stream.buf, digits[r2], n) + writeBuf(stream.buf, digits[r1], n+3) + stream.n = n + 6 +} + +// WriteUint64 write uint64 to stream +func (stream *Stream) WriteUint64(val uint64) { + stream.ensure(20) + n := stream.n + q1 := val / 1000 + if q1 == 0 { + stream.n = writeFirstBuf(stream.buf, digits[val], n) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + n := writeFirstBuf(stream.buf, digits[q1], n) + writeBuf(stream.buf, digits[r1], n) + stream.n = n + 3 + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + n = writeFirstBuf(stream.buf, digits[q2], n) + writeBuf(stream.buf, digits[r2], n) + writeBuf(stream.buf, digits[r1], n+3) + stream.n = n + 6 + return + } + r3 := q2 - q3*1000 + q4 := q3 / 1000 + if q4 == 0 { + n = writeFirstBuf(stream.buf, digits[q3], n) + writeBuf(stream.buf, digits[r3], n) + writeBuf(stream.buf, digits[r2], n+3) + writeBuf(stream.buf, digits[r1], n+6) + stream.n = n + 9 + return + } + r4 := q3 - q4*1000 + q5 := q4 / 1000 + if q5 == 0 { + n = writeFirstBuf(stream.buf, digits[q4], n) + writeBuf(stream.buf, digits[r4], n) + writeBuf(stream.buf, digits[r3], n+3) + writeBuf(stream.buf, digits[r2], n+6) + writeBuf(stream.buf, digits[r1], n+9) + stream.n = n + 12 + return + } + r5 := q4 - q5*1000 + q6 := q5 / 1000 + if q6 == 0 { + n = writeFirstBuf(stream.buf, digits[q5], n) + } else { + n = writeFirstBuf(stream.buf, digits[q6], n) + r6 := q5 - q6*1000 + writeBuf(stream.buf, digits[r6], n) + n += 3 + } + writeBuf(stream.buf, digits[r5], n) + writeBuf(stream.buf, digits[r4], n+3) + writeBuf(stream.buf, digits[r3], n+6) + writeBuf(stream.buf, digits[r2], n+9) + writeBuf(stream.buf, digits[r1], n+12) + stream.n = n + 15 +} + +// WriteInt64 write int64 to stream +func (stream *Stream) WriteInt64(nval int64) { + stream.ensure(20) + n := stream.n + var val uint64 + if nval < 0 { + val = uint64(-nval) + stream.buf[n] = '-' + n++ + } else { + val = uint64(nval) + } + q1 := val / 1000 + if q1 == 0 { + stream.n = writeFirstBuf(stream.buf, digits[val], n) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + n := writeFirstBuf(stream.buf, digits[q1], n) + writeBuf(stream.buf, digits[r1], n) + stream.n = n + 3 + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + n = writeFirstBuf(stream.buf, digits[q2], n) + writeBuf(stream.buf, digits[r2], n) + writeBuf(stream.buf, digits[r1], n+3) + stream.n = n + 6 + return + } + r3 := q2 - q3*1000 + q4 := q3 / 1000 + if q4 == 0 { + n = writeFirstBuf(stream.buf, digits[q3], n) + writeBuf(stream.buf, digits[r3], n) + writeBuf(stream.buf, digits[r2], n+3) + writeBuf(stream.buf, digits[r1], n+6) + stream.n = n + 9 + return + } + r4 := q3 - q4*1000 + q5 := q4 / 1000 + if q5 == 0 { + n = writeFirstBuf(stream.buf, digits[q4], n) + writeBuf(stream.buf, digits[r4], n) + writeBuf(stream.buf, digits[r3], n+3) + writeBuf(stream.buf, digits[r2], n+6) + writeBuf(stream.buf, digits[r1], n+9) + stream.n = n + 12 + return + } + r5 := q4 - q5*1000 + q6 := q5 / 1000 + if q6 == 0 { + n = writeFirstBuf(stream.buf, digits[q5], n) + } else { + stream.buf[n] = byte(q6 + '0') + n++ + r6 := q5 - q6*1000 + writeBuf(stream.buf, digits[r6], n) + n += 3 + } + writeBuf(stream.buf, digits[r5], n) + writeBuf(stream.buf, digits[r4], n+3) + writeBuf(stream.buf, digits[r3], n+6) + writeBuf(stream.buf, digits[r2], n+9) + writeBuf(stream.buf, digits[r1], n+12) + stream.n = n + 15 +} + +// WriteInt write int to stream +func (stream *Stream) WriteInt(val int) { + stream.WriteInt64(int64(val)) +} + +// WriteUint write uint to stream +func (stream *Stream) WriteUint(val uint) { + stream.WriteUint64(uint64(val)) +} diff --git a/vendor/github.com/json-iterator/go/feature_stream_string.go b/vendor/github.com/json-iterator/go/feature_stream_string.go new file mode 100644 index 000000000..334282f05 --- /dev/null +++ b/vendor/github.com/json-iterator/go/feature_stream_string.go @@ -0,0 +1,396 @@ +package jsoniter + +import ( + "unicode/utf8" +) + +// htmlSafeSet holds the value true if the ASCII character with the given +// array position can be safely represented inside a JSON string, embedded +// inside of HTML - - - - - - - - -
- - - - -
-
-
- -
- - - -
-
- -
-
- - -
- - -
- -

404 Page not found

- - - - - - -

Error

-

-

-

Woops. Looks like this page doesn't exist.

-

-

Go to homepage

-

- - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - - - diff --git a/docs/Operator-DR-Storage.png b/docs/Operator-DR-Storage.png deleted file mode 100644 index 7bab1bc27c5b0ca9a6711925e0bb0fa8add2a4c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102663 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

`T9 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�fM``TLJ`^;O_1Y3GNy!(73z1yEpFc?(*Ht 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 diff --git a/docs/OperatorReferenceDiagram.png b/docs/OperatorReferenceDiagram.png deleted file mode 100644 index ed2b7164e6781e7d54a99b2b4f5745bcfba6b17c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108235 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%0A&0(+;o(d#kB5jf%dNAAw~rC*-|f~Q{`i?9N_ z=~wQM$s*@D?UK)ftO=O5Nje!WOt;(Jcz3cCWD1-A>>vCmskYnZkqGxNkPZ0Rf);#^ zd>E_tV0#jq4g)g*PDzb0&&=FAI+a}QJ2!l8P@<6TZ~TWG=51S8$ zT9K9By9~wSl?pY+er2s~kHH+RL}%UfKeo}5(?WZc8Mo&zs>=ULADk4=gEZVcKiHcv1luZ z)KG-~{#%pd7l|xd+tOd)y*MPt4!GmRTc5#Bc3eUjQ0qm{sXl2RgLSTL_J zMe=NKsATx`(Z(k3Z=1Dy=_q`^MaJG>t1D764nSkIynJsVm)R3t;*2 z1U}sPw{XAvo}NEu-Lz=D2>7{58^c;a813F2POf+?2YDJ9S6r_xdTe;eV863J4L{2! zZW2=-BG0|(mtu(6A?TCtCm$G7#m%_CQ%|vxsX=+!&FG%AP0KnQ?beX)&2^X#AR{pX%})N(mE3S$$s zE0**O-MRImV8l_d*HxY6@q~+9xQ(y`PNDDF4R7!JReBgFrxgk(b&2G!Q|^Du!wvl=&27slW4<9&C(U27Xhix>>qN-*Pi0L@OxNV|jeJ4I-!~4FN8Foz zA2p|4q{{a%?VnU0?xpDVruO`vg)-Cr@wC`(F7PKG5qUy9wq+)e?ai;!xktTz?IbX_ zwCqQJl1jUOeWIw?TP_>vssdCa0kNyy&L<{S8K=F0Bta^hg?Ul&TNm@sRArr7JCmfp zHJTvZ`gUg=4p&wlCruP=x`~g<=39@aXLj_z_c4rL`5F~=_jKG&g zKWW$U(v521ypNuxR@8JVM|ZCbd>Cd_5!qC7-otH`YN*t`?>excMd=AeU1LFflJp3;^7ur2Prap z0^b*gO5cQ`wWQ7O?^hsdpIvyPYwr4aZ&X$<{&y*3BdyMFEplN&AVzBq_Lu?rhNt=+ zlGTIg=haY0Q_%_OiL3k!JV|_-s(#wQYqYjd(Z3GT3fFQXN`DpWnidUsn>~P%$gNV- z7B@A{jS5yD@3Q{*@q}H9D{E|8G*`jnc?{F6m^7Q~8Fz^)fAaB`3m>zB;UT@|RKEEF z1CmVv<>id$y| zYB9n#9O^4E1M_|??85m8AiDWNR%;_uRB4rXur_#fF|Z=Gdxdj@&Rr(4$=fDPx{>IR zzDvjKnO)2wFIT?)0b73(TFKsnVnl)`L5n9>Ym_0PVX6=8Z*e-af8@kRM4iL#IF>qP zDVSf?vW^8U2!C(6<#ne?1; zReM}rq5}-)^}%jYaq+|O86mPC?Z6F@AOY*BH%X%4r?i#fmve$CM$G-z{$rn@w&q4> zU58)Atgz}8MYXBK@f5Y}y^VbSHq9z)?36X*#7O*vf#8GCfwaBM@k-q1jfQhgYWd!H zqx2Q6bQ4!4Rr}_c7dh!Na>c_l8b&IrUl&uSt{Uh((-&1h*M2Q5q{W~lWvV~=pgx3z zYrcFMS1=jIsEh3}84oo7!kpY_db$#JYr!Vf?rT-|-sy$l(uFA(h)*T48ztAMC8q7T zCr8udYXX8^0{rNeB}*})1U2VRyMG+D?d37Cuj)JV)K-L1eJYY|-mX>Z=BTt=`rBB- zu`=too~TIf%hbe_U&F|bDpvGc@>@Q}dA{HXs!+FO9t(KTzL#E4)?2yVgMB{&3kw~f2II|L8z1Pku&4j}}0cL?t8 zeizC2pZV{ZxpU6U-4A&Jy?gKORjcH!w`#36ouAEbVKExhY&veGLqd+*;$EkP6WuF- zV>5w|ud{T$*(0P7UNp_S3TM!kYN>B3%cvjsF_qD71la-OhFj<*(fP4C8I1{2Osr^r z{AeA^{I>XtwDg*S9N#F$hc}WIjFQYdL$woBqujT>d_KNCTb5lrCtKe!s7Fhm^dAg= z6i&kpQIy3CLQgjir_TEr$^Uw0jtITID7|Ml zgvRH=R?4^i3Y4mq$}5S?!p<&+WV27p%&Tpxg}yW0zYIgdg+6dRb{Dm;k!3D=#!-33x|m%19dzq^hkY2lM1S;In4( zsNMwiqKgfARL@vi7-Mf{bV@R@=n3#=sbqo8P^`|3)-4HzMRw5&X4-76PhgP7smr== z#`oWaTTW=PD^SYj>6aY()S_YyQio6OnAoE!$kofQ6`Sj0n?Wh$VYNXzPvjwX>pmH+ zrRJs*%Ue#T)`M2*#WkE7S&<`e)M#~*WTITEOo}1CswOzA=tEcGdW@>uZWZj6{~afI)^oNzUzJVbP3VsnIMQY1@V*J9vX`Jb2jPJc@0$ z7&rXeLA^xskq&57FOj)E9l0bL;Ktb0+YU=CPND+Y+#TAqa&z+%tVTBJW0DC#ZeBnD zjW`B9!$*$_d(MJ6XM?d9L#$ORd6~O?uZ_L*=BJ`xjzJ!7~!t>2fE7A{E1p`0eF za+^23FopT$c!)BMtlC9)qsiq_*};=ZjjT0^R^ zHz#a-q>4>WSs_i4OSw3RSS@udbA9lKGgHoJTAq%-F?irG5VpLMVL*1}l4#7VS`p6O zpvHhx3IGRpn{0|ZUbuJYcl#3s)Dy*(_^gpp1sYV2YC8T1Qm&?zkEA+CPplPPz>_#~ zG4wy(ea59C5*cj1&VxSPDZvr*}(N^>3co>6hYKmEB169ouqRUqOn@5AJ>EDO0mx<^5T) z31B)jkz%4vMvEC9pQ!Te=Is3DS!b|STh-|)L^3BBP1)i77w*8&?d(hJ;RG7%RDE%@ zqRrd@q63uCrbPFXuH@_42GL48$$AA-=8CmC7024*2G{&`Rc3W6gHg7n!Im54rY6Ix zN4nKJzH{3=#j#a$-tF45Al7l!<hxx6*wF;jc&6NAr{U4uk81 z3A68dD_K4be9v!w%>l^6-b#?qHjL2ixPP*i;+nS}=SQFFYg8$++KQH*son?&xV`d( zJ6m6D^Bd(Zx1yX2UUZ`@|D)xq(VL`a{)T*F(z6t?xZ6&fJ>A_&Atfi)AeTsvkFo+p zX|v5dJzufib6^cl^Vs()_{9^)|{ZU)8r zUR>*W*4!-*U@cT4Ka6t7AS}4YBt1#^wNR{-4dq$vqxuZWmQfeOGn7vj^|R4=a2fhs z3m{SOV@8P6cn2%d4Yjmzop;j!fn-H19Xmc86HBV8(>w!{e7A}LGFP7muQecJPl+H3 z-l5l^^k@2PD8ld!KFL{Nm~_b{YC-R-SN>Xtnk{?-_3sK?C!a#uvVx!8E;@#Puv_k_paG1C5NZHIzl;sJfUe_y6Pf3FVynhNOM z2A|{Z?Q`A5S&HclTKA}SjVf+5Y~)duC=dlL%G97K0IKy12e_S00y3L79$MFZ#3)qC zMUt^*rS+gy{1%J}>Mf=r=szA3{zm6Fsm>XzsHsN^1y%V50u9A&nfhPd!z=MW3nN}Z z<+SBCn0`A}Rss#yMSp$s;~l^9q-}#9YtVN!hv0&5egALLp-Q4rm1MWhfsLcJzY{&t zsH(>Xcf|k4t^fIGxOjN1|2z44 z4*bjsoC(sRii?Q>v%&f(o6mpdGTCR8Mx93NL{5&cmMWQbW*c-?9Af+#zvd`-P($*s znYi_mI=!Wz>JK(ol-O;h_2}SE1^>uy3QUcs#A>qBNu%pmXwTnr(pwW4DTQOJHz@3k zH}@#og~h~55qeN>8y^vdrdhQ$_5#ue0bg=14$MY|B(^=&7BYk~qd&hB4{KMB{6 z0=mNxa*rJQ6pFhbT<`qz|56G5nE){S(s%zY>7+*09=?=BNVI;CO~i2l?D-)1|Evp+ z`DgU;3E>gR1)v~b{a01O-($b~S1-W7s|`H=q&iiJwF>0#%>PTF{>upgCp`Vg&H%`8 z+?fAaZR$`Yr4D?U5!S-^@r=0R>!GS%1q0AvxOifxLzOpyHo9d-N}*Ie+~Iw}5>y_Wfdu@%EiZU&6Kb z3&f&g@c1T=i2s=4riw+8^Q1Fj_YtMMY ztUJw*zjVL9iF+)pkAp_0-=E51p*(+c|2gC5&e6OkYPMEFcJ;1A&A&`q#d@BR8|8|vAD?D#hi^XOr@iOcVO{ZYcu zBem_&pgi?4`?`jMUw%(8x5H`;er%r-h@F1+kE8WO!m!^t+E|S3%wZhe*RU-4qa4(r zS?I49!)A<}8LVm)qZzel|ZA?*}aZiZ!!K4*YeLtKR&j7U2otlXxU+b zh=mN%NBI9`RKAi(RVZz$ROIAfHthb$=IP^HvcAsIYSjF;o|hY7sm5wo`EM5WBO3zV z|5`=euVK^s)3@n<<5-2=Ps@%GIKi+#Smlo|N$z4hS$Dd64+qtn2WlLjI3ao67u1f% z=XcbB zC51U1UJ;~}9LHYQ)L|}J6khcrSP!1n3SV&CdA8Bu8<((&clte!d9-Kb39yNOK#!Nt zB#i})7>BCMd~~P~tAXrP&h{6&Gr6`6tCC3Df$UPP%kSYvr-d%qZMPc2k5g6pBpa+p z`@fEJ|3z&3_E%J1zdBGhxbU{#d0wINHac`5$-&UTv4*F-#K>3A^bM|K-7?{y;eS@o|IVa6L8jzrGQS z^uLLL{s;>S!wRD2i6y5Xzq6vZ6XTLUbti_3z7h?R75)pZ$fz7@MKcq}>MrDM zB$T4Zri;VUaO8Q9@obJ6khqi#p6(nlWBEO@Y(Ye!ro(p)+sA-dJ$BD9(WFS8{Z}|8 z?C89_n<}p7Bn(5>hJ7KR=+=Tp4M(e9_&JubW6Ct33=LK7>`uRt;g{oQli?5hP&m{o zC7|2G_-y3@r)LD`e#M2d{(!#36>KJ&uJAx9oZv9dztJQqpiq2&J)l^0kFis|r)aG$ znMHKLdf?Wue9U_?bM2n7qe;QYwAcFLq;Y?{<}q@gwH>Gyk?Qzeo?RB#g1brRL^Vz< zzI3NoPv~^qV%CM|1oyAgGR*KBqRB5W^p1x2O!pb7CVF6`F_?{!CxW(-(fKO+$p`<$CQ{`w*> zEjMST<6NWFh%>LHJ5G$1ETiDKQ2sv>K-U>{Zas8Q2{{^J=zvl7&bEA6yI&64`pTDi zT5vG1mq+^JLX3{?a9TWy7u2eGW5%&t9u!h8_v=meGm+;VltjGT-8b}RYA*tA*|mA$ zc@ya9_}gTZ?NRy7#94?%Z*O?tEUfv*ZXsc0MLcs+QG;gf`p(-KqoQPNhxWPO5|t{R zkz6foa0B%3X83jCC&8>_;da10^`$TgE}KTxp{GH8oG(v5*aDbM*zCE7Q=a&B%18#M zJ}HjBtwXWqxIB|>6LqmSqo8*HbjC(zLJ*;M6c<}YmIH^R-OnycDqVX&3*VQR>^v-X z(JV|KF1MY`WC#>Q2pWt*8kO3km+@T zl(4emPVhK7BE|$D1*k;)Fwa<>MyS@WWv?qSS6*ziCH=%Az$aIXc{fh^y#ZRSE#2NnJE$ zFAiU}ANk@gr&ARcn_nJW1T_j54eVGpxiQW$^BNif8|4d(&`H-|HR1u4`g}b0$a*hJ zRw8Ap+Yyh5b^j|=95gM{p6QBud7sAP;CdZ#A90!G%c&T9eW;0t@UO)s_uW!W_utWx zpq>V^ms9^Egle?4Ljt@?bxq>~wtMg{XsQ$kGAhY4cxZ&;J=t*kS_~0=})Z{BN!a5c{h?j6f8P zZee~CJD?Y0vi@Z8k2!U#p52p8XIIV?@Pi5Oj|pGR234e$pg*s-QrKiDHX3b|aD3%T zCoZdAq6mICHTpw8QN@W$bP&eMAi!OB!`~#5wo#oZl)l8{-lRy}D(XWLjc{R29-)+I8TXITD-*|X<3aOA@ zy-FD*u9>B*nJwDh-mXVL^3xi-8*EUes#B%%_48x8`m(TdmY<(5A}=q`IJjb;f<{jj z2ksnvS{K!C&b%fRhpV_SLog;exu~yC%xt<55+5J`1`ck#)@p^pc#PysQe6IFOpcJ4 zxIm@GJTN#|ch2s~j)tS-QSRbEO?|M$7k01taKY9kO@UB-_QSDLMr!u*iEU*sB*=ud zF50di1q{4yJO`*#amQ!p@osHhw-Bd{5z-rM=NFVHC@92AtZx()7OG}%$@1`c`N827 zfANMU<>YJ@EfE^7l2=g3&&=dwVPTnRFbK0hSSZq&o+hKD1fz*jrHaGD#~-gSkUZO) zRlJjxWz^l2A|xQl1^4*|1|~`im5iKRRzSe7+I%`4YqrMZ;r@<{j6$xeQ}*OD7lYg| zEv<-rUw?mu8iMh+HK}{cTMe)mHIPxF#9SO%eO7c zYKW}BqV0KNUpzuCKx%0M?dj?5U85H#BqSsyB2oZNCQ0PQ(W6^K#cD2=22Z(e2|e$S02M;G?7URVHWmE(b=v>-}V8WHNkwKH54uJJske zP1t${SmW#BSwKn=oh$OTww2d8*~Yg%ufgi0NO0j;3iU#Haz#*Y7aE>#ASY#k++CkV zjcx(e1@ap0zIDZ#YSG9xB4c5JD5}}T2n3_1J$VLAQl^+*FX&K$AsB-c)6+XB>+D=_ zzc-Urq*Al(eX%&HV$qyew$icn{lHzZf~rZ5!{uCeH%$~TOcP~Q`f%FqP-tE+rEfa& z5-$X#)tV@}ki$QIf#&JYoinnXO=+{a($C}L)bYQB&)jNqSd<6q0u75fMYyqMHRd8LAvo#cW-kYUcBs%er=QCAU^AVgK$|g0yNFcKy1_{ukt$bTr4ksO4&5UwdRLQCQ%@e3v`kRr zxXJPR`qu9hH`pGyT^JpPYmt>4Z^{X0jT{HcDJiFJZzr@x;kEI8z(LH))XHFVJ!PJE z>@~Aij3wou6faOLk#WBl?oVJ8jmj2_NlIgtmdb9QrHj#!BdX~nk86{%)vX0jIwWUF zYgtbJ`2l@9lGI4D<8@P=sed(AkBm{Bih2quuisBq2|E}BX>C`B5Fv@7UrVIu9QKj! z9!vc72MaD|eHDY-QIed))n>D&4G%Y5YMd_iacrxv#qqbuBHQv8N>H2a{yz)IUK8PJ^uDv4ujMH&bqL@x-Iy9&p{n^YHSV-Yh<-f10P0tb3v7>~dva zwBV$)1<8?9l_o5iBp!{1^~d$k9FmHw7xc+jRE_R{-OU(&c5OWO`<=7yu`XCva2(iE zrLCBaY{8n!5l<|qBmO!>&>-4MjQ5y`xq4QYj7X=f>+z=$Jay00+wp z!NH;T3;<8GM+xL>9DLu#k}lFBeXS6OXbGa@+S=M1xYzPvk+&}D^=-xAhxf}e+S=(r zGK^Lue1t?qJ+gZ-utsOw^4Gm59ut?Z5p5TnF1Auint{oos@Wd32L=R`UK73;D~*2c z8~36Um%tDUn55NZDfYuz3E}7%P>j53MfD=2S%j^2$w`xk2zE5ORZDbhX4pDaxUkZ^ zbH^AB)#ApVbY`M#*_l2JZWjBxYV>xsBju9Y{aGqi#s+?5`T1+sEZ}FAb%z8?Rz@0< zRh_+N*n6*YZFy#{Mr)L7UcdQt{-MYSor^%2+O1ywCTzWX<)nLwfgop9ra$)JnV^KR z#<~dQbV4?ct4Y0i%L(?`!J-BN=VdB(JeP)+mR9|}A4Yv2yOJR~5NL!TB}(v$FZ(ug zaNKXCU>*AKu5ue4(`#bXP8i696)H6|&N}qgM^NhZ(kH}x1^iHcVWAv9zb`x{b81!) z3OOUAe2vG3M0;l^DgH{S37728hr!teK;6~dTcFDqqxl>Me^8G7h9^YA9U zd2Q9TMKd-g4e^t<*^KSgBdK=rS(iZ1j@Nl<+_{9waj}F>IUh*{DtJS04J!QY(DI!^ z-^PLPDgoNRcE+h|HiF8o&U#&nhoYBAty!?>^q3qA!PhbT%G3N z`-_*%7HpxYrEjEos7FLZTyIIbr_VPy)O0TMhT{TLuT(7!K{-0xV8jA;C~gX&ITwdWQq^Gf}wQbYnkd(Z}v*9byTQNST{oMiZBxV<&VHvP1O@ zc2FL!QqWm-1Ke*`527O!(-#}7<%nU(KfIqgHZ#f2%)^&qu$W+ukyqGB(J-IzbAwnj z!(FkhCAMjGt=ZZOfc7AFGEamfJ6DFw^?D!2pkmP^kE=C*I?$8c z(?c0a{woZDGCMC|NU9&5O^QROeycYG^ul|@!mjLwA>Uj1qFTE&Iy(*PH=SNV`_^J! zclV>1$UUeZUnRKf=ZuEW?u}O*xMjErTH8&kIT(-SN-N)vE3(?}Dq-Y*c1e7sJaae? zPY1bFnuW)||Gu=eKstV9&x@T_@UeH`W3T2XplYgyZ!+2eqP90(ES_($H<|PKs$8d? z<@~FCs||rmMn(q5?Pfg@JZ3i|Am9}k5(x)~T1H3kI55KOz(5hKeoi9EDnaRph`_A{ zwU`)rGE&kQqXgDSCq5@9rv%0w8MB#MX^3E$@}2b)VMgN5O687a&gZ*%Vwmef6r)WB3Xo#jiiADCsix)F(S`wd&=yDEGvIkwQm(s_tb*G^V zddpy)p0nYF4atK}tuDH$cM$03C<#9e-;DyeG)7A4==|l;W#HT&I5;0PIoQ$crHaMR z)SCf3I|cfDUbXWHlBXF+f^7;!@%<1cLzCIg+EFyNEuHIKvnBns{=##d?@QtNOP?&Q^%KrkI-WcU5fdLXqwggBwG}NX z?%`;~k}T5O6Gs4t#;z1;yE&BRIqvg={(tb)6uj82pH&PPV`agp!$7xT%JVd)b$Om4^qfId($*}yjl!?mq$F;?l^4fGOSYJ1WFlPmC|iDgqyLDj4E@*nHSe z)L#97`TeJ1#LVlZpr9a(IRz=H)GCvS&BLX(z@2wF`@{2g`KjDFZzRCIPk@Z^ z0~S`+3UMg;9(Tfbr*jCUa;1r!=KT0eP|#TSflqJs!{$`CHVf8X#kE~M zELJc1aDiw|4-IDhO5p1^2ppX+Ge`ZwvZnZ%ZA4tCjlXl1Y65Z%L13J&z&QCq9|n`z zTrNnIi9B%Ly-OSW^6Uc=8lDKD=GHJU7*2Rf!;XIIrX zI@n~rCbG7X96h)aJGwUV?c?{P_p8kUNE(>XG(p*_En~v2j5G60F9=N>^ zr=$RjI<)shZrnJ+?si2~213u-QYz?O2Fh|>%e1I5E|6)>xvAP<%6~}FG@pTr!tc`f zC%JjWPd-vpm$c2`{hI#hM35e{8u51CUpGELAySWr4>_Kb$LH6<#Yqo&N#*6u%#3pL z}JSw+>0uzvk>0))VUT<7l9@(U-4JE!n=trsvVX@$6C4>H*8-yMD20If)6p(Ts zTwXth`+*gFHnzkEmmSJ-=hKgzxL>BGrX*aeusZk7PPV=5#;zHuk~!fM$1(SbzADhb zdS72Vf8cN33T~zOu>)7R9bBU2*`FB^|KVjmk5wIv26v~fj3K6NCe$0hbnjN-ws0Qz z?>fov;gIBBXng$fvbUNp-vYj(^W0!B6wgcG1gY7s?IR&4v}YtfAyj5gPR-Vp?_*cG|ANHSPm!yD|Bt!$4 ztJg3Bh@&ssL`NC2#S=SR4w^;X+&J_rUWm(nmVR}4w^=`sFHe5CU0_E*NI3laNNU6S z9R@~k$fpIq#rwOdIvZk(mJ=pkXaud(Z^O)(@W#f*mpd9bIv4x%s@7Y2Q>ILE;#w1h zkkz%dqvarKZKlL{Iy*8eE32gi*rIbFsy?;aw5{tT7-HWt#&pWyY$Sb*mkO>o!G~xE z2;aofjlRO8H@cG<@6Z~NS%67Ay!t#5t(KPj^vG!c+r6ngdt>A>1C^CcqQLU?~~DZ8s;!BY*GSd)7(H2GjIQp zhM+6WD}{+Y*5G&Ai~OHpcNJjb#4&%wL_tS<$Mi4u*4j)ZnJUsZMMe}pvJaK3r;*Fp za;*y#`D{<-S6pGUA@TnG`_17D!2*qxO;&<1f-vr561fNk>PW%l9F8;Vfv)>i{j9@= z91Wc6>$((+?ak`1T?PHs;S?qq-Q^QOmCisx*(3GvK3GfDA|@$$5+my?rjxt@f}3;i z#8T?hpD0r4B!)r$edavOfQTG~7S!(5tt%k?W9LXpSvfE#?Mr%_|CQ}hj_G`3JgIE9 zjEY)s=PcLy-Nk~=+4i^+1@iUzo}j)nG*QJ2bMUW?mCa$g_fhY!QXVcIY9E?!0=|CL z>KV)X_3M|9i%kGY8p#`BVPRCi&qhY1`T6e;D${qM6OgZ^2%;c_16sJ0w6P5>^l&-z zJZj!y>4C~jyJUE&JFA&QH11MV@!e&&OKZNEWCid>wNYtp<5B*WC%d$@bJ(0W#-IE{ zC!`eA{5w&8U!Mrl(on;xP10WK<2gNh)}W@tZH~USriaOF>6w&-IWjUbQ(eXv2RxY* z0S}7s86Gh1Ro%?e>pG1t|IG@5NaKnkf?hs@ubGe1Qzqz5_s0ByTm+uS&{^Vsf*~R* zdR3D0kR*vr!997FJ>UbB@9M60XNNXkY;1h|=mO_>;RG<}1^Vv1|Bg9(hZDqS*7TFHd)5ojF3!6^K ziajJT=m+oie`{umR-7FDeUVaq@_r0%Bq~Xj(+P^v4vziqU@dq*r9ZRv%C*di%j0Iy znCklwLJ1dI81<{3*KLWmLX!58QL#VbQmC`b%Ohc^8s7%BkKBh4@ezl!zaJJj77ExG zEEnU$=%&NP3);QoPt45BJpAE}z%(G6m9Of0)V^6SVHOfpWioj@p<=OY-#|)1VQSw3 z#L&5dOG^5+m#W1J=kBsIIwtn`Dw1$_u_f#~$4S{Y@y$2l4LiqyBIOk}bz2=6@oWxM z5C~*-b-mh{#~F8qNBRRDJ)Mw{kmh2un_&WvyD|?34s2kriQ{1vzv+UDPik>gJZ5KK z#0ynAtB-=@J4$6$;mQ6zXd~p_S&8S%=T|KAv+Ss2Tk-KiUif}5OdLwjen@A-9{8q{ zV3HN#Ef^8vvwYdUhTfiQ)>li_lrrFUXGMSEU%W#S z=#_1xM4@nea#FjVU{ZG**efh4YS3A|he=7fR;8$c%faD|>-{nN04qr`!g&lyYAroMpEHl8R1x_2cC~ueT<3I( zcB*iqgIM;1?R;u^c>;!cW5nX^y7@pd-3$LVT!YGXNEXQ({fc-_x0~a&k*p6$NKuL3 zB^ujAs%C?bmv5+3F&rD8Fvz!Sn=folTjd59`DSUNPW9<`oZCcU?tEO(;+2mcE$%EJ z`E7idjsYz!!A8{XGkJ)3`pI1>z+t8g(jP5XcX;D1ZnCoN_gT9zMEcH#*>UqN29s&3 z$HV=H4<9O>R9?TMiWI~{7s7r$+$0?P)$k*Ph;KE*`)9hiD<{rNc+B5yi&s>Pj8$U| z+oV*a+Vk~Qx_WvbGQkq1u*D>7i{$4U)5J5F($Y?uF+n|Th4RDxwE}l|HmM;iEBovR zzzZy{mv0vz?(I|oKbvWwn@Z;S)VwA!X_w;o+P_h z>0)z8-o^&73&EIz4`OL{svusczLfs(Lf(i|BQ~4N(0FC#dGJT1VrNq(#McsRf%%%7 ztd%quG1>Xi3S&!WSEQQ}V!`uXEmW@<+*b%D^glnz-(laZUto||q|v0QRfL9oEo;19 zVjG*7pj&A?0gPJdM?MrhfD?TmaUy_50my%F;`B}s)5(o%Co2voli7WON7F4`V)MeU zt_b|nS)HM?k8aneT634LH$NwPV*g-n7RgCZ&qD`PyZ&f)iIJfp)DKgp73(^s%V~pC zDw2=1q^}eA5|fRZX8XIO@uzF8@agpjqCA|a{_b|zKEX4P$8-LhLC^k6~ zj2QYqMl3ClWME2BMTLSE4++NP^ySj)=FRPD~j#gb^g%r&wv zFRzq+qxAf&$4{6-q4Z-Z9S;f<{w1$J{Ms>jvF>)IQ6@o7YHoI^I!{=o|l)7OlC7a*`%<2q8r|Nv&u)PZ;+#2&wHjWjMQxjsB66C$knO( zCMEykX{F;!erZdW+rkC+@TH~-)LE{?!oKNkz~rK?EU6 z_tlMm8^I6%CWwhPu^+hda)Uv2>vEgi;v%iZg(k6hI^UFsTa*u{q^b4!flV$K$L(>w zj<;Wl4;|Sv35cWOHv1DmEe>Q0|D*h>A9^YS+Mo0?5dfAAJ|4F-N zk;*4}`#ENoC`wk~&j|>LqZTWOUCwvY$_s<<>+-;87%rdX;`X`e$sp|_)7KXx!akQA zwV@pf(OJBN3Vtgf6)zWpqylfbH>M?q0r??V;9!|K1HKAq$N4!Kov3E=mA|A`>P?Y6G1&p zcX`yKOTYy#LHG61%@q%WLB%vGo$f0Wg%YCNm!xwV0iB~i0Db!71xgN9M-7nO?O?E4jxSz<0 zuM92mn$A~;r1AQv8>N-Vkny>E6C)A`!4`LNVo|9!O&1hlhvXfhUdJC4Kq*A|GW#QW z4E;bElUClXBl*UFn4iwDAi;I=iHRZVXLBT(!XC5G;3;1RT-RsbXXB~W3!>spag~>- z6v#+zp5IUrD>~tStQ3Qa)gmDkRcLQXZMys{ug~PH&HD2--qTNy@iKxv&=n3F$KrMa zrep4Sb%ox-372zj@2gy-UjL(5@F2)n0BHFGpk=0ArnEU(f&=2-?tD!cP<=YrU#|p0 zG5Pi68P|~HYv;|;(a{f`Ihb{H;#q8n!fv;y=R6*s1*6d;2em(C_>PtWG9lrw!l(i# z^ixBQ$QbhN@;l2o)XiP1HiLu(f(Q^SMO*Z!?nlpafrkGr7tS^CG`IU-GP_`-(skmh~h-q@H+t?p0mNS!?p(K|OX zst0%rNB!otaeq&u&F8%IcFwNQ?S5ZvI{h;^o_=ex#e=*i;B5pia1)5#8C@5x%j2%) zyW}5uAACiv9$GAG1a08}OivJs<>%}!-^6_c6eNK>Jlc35Vg9`mhAgG5&{MbZJqUn` z=Hg;2=8@MoD!h|NS8m@Z^{HwtnOg4qOX6v?@bdGQEm?&n2Y={}pcB`z+H?7Kbke{w zJFk*ZHy&bk=aH(qw@no>);1Y103bI$bawku1|Re^21(wv*_IT6>+~aN1$fMHesww|55q8>e6q2D^sm!Y z^Hut%lVoOR(-|IW+V9VGFFo^x9T@z`vLJC79Ar)M+>7-yZ>KhA^^aE4O~21Fh2FQP z&*5X`Wfj!Iu$R4X0-t_vX`R(DO)szhQZRtUBT$YA`+}bl%GtQto~y`uU>YS(?`whVgu&j@y|cZ0WtFLufEgc zdHEvt_DmaMNkXowm;+Nv=yUtX{uY=9nwk@0uxPA4Pws9&5WHN>Nm&kMGvC0WZu%7w ziT~Ui+T~(@<){;9W!&Qq=9%|_>wyb%^1y(T71rwZ7H_v$C_W?YcSw}Ke*;T8)~-Dp zC{(A{*C*(a$40$J;eD86@cJ^EV#NgOT@Q^TPxT3`yzN)#N_F?mq1i(_UG4 zpRcx{P&H_(FkSvY62!DiL{0exqI0cPksxIG>-X{HkX^D#4jeCG7szM)J6D#n6D>N7 ztE$a;1E|E0b6L9atym+JLF#IdGA61UG&W;O{YMU_O+rN|-Q^XM+x$Lw*5_~LrwY5< zrt1!9h{k_|dvBXhg4bh8M5ED!QV)9x`)rR2vp1G%y<(74=kRx{Dzl5d z3X|{VPl7NBA}0dn_jw@ev^^JY;;R-a>JR-0v3Hh9EJ6WCA@<;Cz#sM_JTbl}<6@5Q zdmGArwk>nZq9i~6i)Ystof{|qu3T!9R?Nw|diq+`O6Y8y+#gYY@6{|WgMWC$#Qt0l zYt*M*13x!TbbOfScmpb0b?Jr+94xL8P=A0*KPfq-mTik_SKtx+}(Dpn|uDqnyE7d%;x_l)){=+$n;!*dt z+U@UK>D%4ouTy5o)mW@ORil3IPn{f(yNQ8sopYWwBOoBK{gwSrEns!H8-xN;yef6@ zUnQ9T-B*!%=^6aSO+vA+-=XPVzZ#|jObQ?nBcq~@Zg>xBQBl8%6GcWwmMTlQt&?%! zdxH*zQ|`Bk^P%}Yv+_Q1qg%Qi!DyHq&e82b$WigDnuZ63^zb%so_m`vc=+h4yoqN@ z|0L^w(VAYyghJdg# z`o@nz2waXSgrc!D=C_Xe8n*AC0L%uSrg32cF7G|wh!BYC0O9go5CDYp6(F1?V&RW7 z{F8R<*a!**Nb|4EKnoRvJbuU0FJ0C%lnEVe?I8xZHX0!jv0dZ>$H3x#^BQ`+ZMi;u z`jhqkw#=WEOHIQJNZzq6W`H7DV?1kYvPC2kU+aKm)EbXyj=WFK&F4{$^uBj88e;@| zfc+-9*G%m<8xwo;GHmSdIz42pp5wXgH`fJ7zXF;U_88-9uSF1t_PrK`cV{h&d2*mN$n!$SE``mNtE z!M;a>n2=DbVisr(F)nUeJACNd4XK_H83IS+iW+4)vkC%dJG>=*1m{SKBR^Hp z3=3m8+G8jdT|LQ(5!Q)O!gRI|7YgUx-xhT90cRsZrY1M}3AnW9A(|_6!)8V~kfo?` zHf94UYQeD=*ah8(Uw$bB}zUKK~)h>YjXT z;y@P;e`cUGKQM-LLYBPfJkrYzoliO+y>yuTYa zR2F5_OwE7u0@58!(v^96_*q0mL`YnGts&~>9U`K4zdk-?YpX>weN5Qo?(Y@GhTPmD z6T6MI%Qs{60%t^A_z~RPol;(zSy{9u6BMAlP^w%+KujE!k}?Q#->)GdYj+om8&?}C z8-iT7xT3LCW)FVv4fuZymPn&IrRGM5#TIX@7Z~_82*2b1110c><%MIDzk`f}2xJ^S zaRgrsQN%|}r%gdN1`KB+{|4RfOG9f=@lI}jV6le{ldALwK!BCb6z=D z(>1?6Dw;bUO#zDTr}Y+gJCy`P8V30^&|}nid)!;7UX}l>CU(=%Ph{?B*w)-amlE~8 zIhe~CV06VIf9G=M(POBCxl{ud)J;l?$*IZ*+OBw;Q@nUSzJ=l?=4wGvPx0>o8!z_u z9^Tw36)Dh_)6v>`12(g6wOll71rN{b5e8&gfeI%3(d9~?+X~$NZHb0e_pdMP53RGZ<~Qg{CjYBW|_;R`F_)dI>4M_rlu5m-K3^-wGrD1#y}60lW;@>2G%W^ zYj=-(A89q4je)hEg5uR>t7n(D1x>rma-sQ*_Uf>(kvhqJ@vPBCyf#;>D`A(1Z3x0* zV!BhMT4D*d@RNOYvB7idjn$UVf+h~qT6YXItX^!ucH`4dga&$HYY(>5{3y)RC1{s9 zII3u<#SD_qYRvvFIk_(&+iG4D9*^2v*XC@sba_7&4OP;33=NWL96&|i?j3k=^{Pk) zR6OEi{BC^QdX#RucOeA5fL>xDp_pkmWr~W3??y@Skbpo)frGVp)%N4Vi=hw8%ga(w zywa$Q`mp$dA-WIuZoil@mCTqHTrSkEPxnN{#QGo}lsrD5snuE6z-A@n({YX<_EIi2t*3<*ir*Og)R(q z8$5(UsZvEi0J`bT8>LFacZ!4Y-h+y8o0x1`^GPGjja!#bU-_lmxGtKODWQEbe=3Sh z-LYkvnop))5|=lctyMG2b|r5Y%)!5QyKe#WYV(c5f+cNTeBP3IVH9f#f+4_>3rWTsFd`7TI{Q}A(E9-Xv^_}0_UV$wHp7b2=j{y@v}RQSINil~L?kEkrZl@jA@RRJV&>fMWNO(QFBw<=^b=>Rfqc3f1QGJ;0jzAP_W%c{>#TEP2;@a}*N?%bN~o*k%AwcKI9k60ced?0IEW*s}Z|Y6ls}-#yNrK zm(#{N3_BuK(}08n@-u0AJWmfxv|P-G2mXzNmt^yt5JVnsNa@>!Di=o|<+f6O{z#1l z4v|E{ucnLn-qJMQc$y_KoeQ_KzF;m3hzf$KKXGfj>VWx9K-tEvzxZ5_f|~b`t>`4v3hatF9q*6YFgHc z8}^r77H_aO`oDc?H(ug0nLOGyDLDd^XB4P~=!9`}s5#8HI}Bp|xX3|h!=RC(DK&iK zJR~VC{qEuBlnZsL1xJUt#+?iB^GEO)`r>-P1r(~(z~_ukGw*im{#>#Q2Q1J=vIpl1 zv6yC0H0kQvhQqDjyLY0;LdUNN!g$7G9;=c%RXOVA^pRJiCGI~w2?$T+fASUBX3dxa z)+Saswn|+wA0#NDgb*SgkeRc!etqGntz}OP@9&L9Zy*CQRE_&v19i7Ec{)0}?t|&5 z#yQMBeHhSr{z$?APD^`)!P?pymEInfmew9!kOfVt5E&dGAsv1N{S?&DqNNo7AG*E* ztg7d07ZfB!x>G>9rCZ?8B_Q1(-AboQcXufvNOyN5CEXz1Al-21`1{BA-TT}JmE+mx z%$`}ZX03OfD$fNah)pm+74X{x(A6ch!_#pE&qWKZ|F~7* zuqFY@&ZHi_@1>-rVc~xc{JeG_r%qtj1&3|$yIsth!Lkze!UcFrXmg{)tPz`oRJa2Y zU>WZYy78oC6?-kq(ecO>m6b8MQV;fR&@o1#c}2)}gH|&X){ahERx$y%Be`Pg~zlBb3TzLxGMMm73T)n9QE+I?RiWhjTn8 z%W}MeK=xDi=kdq2*|uwWE7$9K5KU0P}1|pZe0$Xw2Y4k-Npp0>fmwG^J`JfBErPo=Gbq>K+nz)kJ%DUILlb?u@v5mD<>*PYvG zlCTe{xVSh_5f1sz180>j%a*8I!|kqKn&_lBzmctO(@N=HaYrKR*qy5MR7%N+-}XE} zrSfTME%$K6KrUen%XsvuH!!s2n#CH$Q>d2B=(>@Bmd^uGC}bM+pz8;4H>2Lb-K60l ze+5aWXL6ZBFDhpTOLQA)>F5l9w|#zZdJfp6Ki5q|hk1L?hIwfErTf92IKyfg0G83@ z$61r*T<^WH;Tcn$t(O>ld!93~!xTzWGSNlM?OOgEV36Wfy#X6#|EUF#m)#o+4MrTr z025^{2wXiyC=fw04d_X-G(}M5>eZ8Hwl0F7-+aRNKyh#=2fSrWtjhLcp~Jb3&u{HQ z1Hxyhjp=8DD4-C5tI<&hat3a%QKSYEEFne)QylNak#_uQZ1KA^(ro&nNPF3|=K7BzJm$O1#Pw;ZH9t)^Q z%{w!vQ%k;-fnZe5f<%o1C^PZ)fl2NDQsB>Z84ngqH$U4C`dc*Owj=NiFMZ)3nYPr! zMS?Itm-8Y>I&#^20vdTSm(L%je65IvefLsrp>qj{AU;mKW=6Bmu@2oC2SP2c5Ak51Se}} zh7BAXxF?_OTLsAZ{0jq$2QM~jxepG5mKs#6)02JneQGejl zhL8ZYno~TRTk{?wRWAXC?_W;bIeDi( zjXvQ70`#>XX15U}`wR84dd=?Tptub1;r4tcEo>Mhui4pu6cuCvozKuD=<1%y{{Wss zh+N{``bt;%XPyW^C$UeGhBmq4bS zwZQ{i;hPm>pLHAh+jebB?#H= z`g&q|vfOK)i@7Q1lgKpzC~8=Faix^<;*gcqoR}-$0y$BUSWZh6g{A2jlQc4L7Ejl& z+X!iT0G)#I-y>K%&-}wA2QPW0MbSVH)PpbLz2>~@{exYJRDzQg6jG=5zo+14iHxh_ zcsT3J1Zf5qcGJQ4AcMZ(wl%_*%m|bw3IyX{MV@N57{OmIKf-iMqL@weDFJQ(RJ{Kb z*1tjEciwMfMFCm4;NW0$T~Ggo!F9V~>hDzD{^e9zg#bzBeN`kA(yfacHSV$B@p~Yq zEio`t;%#v76yNEI|Hz4*hRT2!cF zW~3$^?(&P9J3X1wot>7&f3?$p!RvAn?u&@Gb1w;?|NL%qgAl>`1wYsg=J|=^!J7gx z?!nfhZ&PDT@~Eq4-ACWDoKdeh3 z`96EGxyw84xWij&RAlP?VHOT~FWW3X*u2$ZJg*XDSKJ=1w?J-9$NPHYZso=zZi?gW z^6ySt_Sj_XP|UNHV-D6M-%GcP`YoOhXSA1#KEfa=)%`wZv5_ZvJsSKdZD-}`DbQ%0 zO6^irh|Ai@B&5q(R-QxO1cfrY;#Ea^&6SNWQzr*OJzn(IAOA+W^d8enHup1giAYiS;sVPPl%s3bC?o=;luHdvq;9Z()g#YT=4S^IfxEF0AR<;tZ9)XTbP z`I#4jTrb!oq5vwA+^$vvHCsG+6LmbOy-~~*lffsru?S@D*XJ!2JkDG;>Muk!8IX0?$=yk@n}K4QeNNBpR0h!-%R2C zs8Q+8$)H~J``0(I_onZEWlM4a4_MnfwH1RUn*K21kL%=KrW*j>3{-~J6bUnoE&&>n$;31Bdt zfQ9Gb1hGF~JRo^*!U#Yr)E6+rHFon7PEMTc!>Q7d`_{bAX}XZW*1kS{GM_YGe}6`; zs-XMZORPV)z>}NJo$ah&?n`TFX(bX5znZhXvl+oAF3u+xWopE zWqXZ6-Fc<;fiozx1g1IlFv{fM2M7|k$;Txfzc4jEPh|!h-NRlTJ|j!LNGS8}HJm!& zaU45povDkI_mG{bs`Y!rTBZ7Bz-pKG5s#(J<}n)AE}Nd7TBR2b^6Irh9q~jst{n~E z^24gk&w@RINtRTl`wD_l7NWqR!2z=3joOisqo^&!+-H10DNC7++6zeJh-Om*ZPSMo znKRqkvsD+aXFTHKrnwev2U;i>E~YPMwBNPIs|5V{Q;g>@Iq?lUUhTB9wPj$7sD&3p zM|s7_il$1}k+dK1Z&3oss%Dd+>q_ezN>CDp^W$U@QqlD-i+AmxQL+ga>j5~BsQ#Fc zt`QMq@-6y*4SyL_LDS$G#eEu@FO7N!hcTpw@_M*P&2S)Be((!$>Q+3-dmQof&eFv)MikOspX8Z}oo9~jZ z^79=|uLGLzE^Y`038zbUwqgS=)r8u?^F;Lke%#(V192W(F>@-??s9Jnyu`y-hJcen&Iw*%rc1 zocvR0wgqc{H1NFs@Gkm2b??c^UG)O+I2j&3@Ua2wOy)0A6r`pKc(=Y`FMS# zE3C!AH0EUYeoHD`XTXt6=K#}GZBChKH#0Eon|mfD`+I7Dn$7n;q$zNE_<`8@xmsnWVb;;M=Un>P~m1b$lLm zg!Jltt;|q`WwkYeenG=s8mOab5CWX;!K(ov-1nhPy09=CKw7Oc?z(ZnG-n3t>vrW?IY+1cUaw)Geqz6PO-Ufk6X_nA2?$Ps zKc)WIXHtfDQ5m38$C>QmJGeWk;~d2Nbe0g+6>z?p%!q~Fhe#B4S>CAv#Q z$gdY0cy44af(yfsEF1iBMj-`ZuP*HjqKrjM%%kj#>O4ekSD|nT(7(;6ij2UqJar*o$IWMhNoG)I3g=Cf{xkQWNo|b1W}n0ou=Qu_QF++uO7SJza|!|>L2zsx!WIgfkoWryA5GL zg7aN)IDd}~58CRgxtDZ3oK|Q5J#%}Vv1ev~ZKuC_&r*Am9okz_oByT!>4%;4c)6pZ z_aDZwG;7yb)heBpUl995wmt+NjZ;=Th)=Kc@VELLV})S_e5@yIy1QLT4JuFh%s!p+ zonF9g%jE7fyP8p_F|;<(Gd!!Ut;rD_MU-zL51xanRzd0~? z(2^8rV!q)i&{6q+D%U8|f#an~=BoGSO_no!U~;--kC{}^rI?HCoLF>^8pc+RK-=U0)1zd zJgNyTS$W5k)FZ{GU;ju^?YZC{@1&#)oa`D!ysN8oxWHc};X;ngXb}RAXlIdfqpB7o zs}j0q$=w`Z13aS(_F{mdHRsnrFgxpC%Xs>)MBMU2ItrK&KtXYAdVLjAv#}nVB*CIUq&B zLK)1Ehq7W8+1yK0=<;E0pY45K_vvhdZr#F?DT((Y>suWE)e1u3X?Id@LN~S|JXb zNGxnpPNvD1$Sl(0hP%NB)gm~LOmsAcl+NK@!vb&-9QXTsi`@$kGaf*NaEq6RKF7!~ zXYfQpEy<(z6*VxxWX$t(o741NJMVM59CES}vS}RWd>h(zLP?iEiBml!1h>yn0*rReOu$=98#@R1$mVOeaUFFU z!lcBA4@GO7ALaDlV(Z<%_o|$~JNbd;cAZ__#AC-v(C?tb)8ezo6}QcS{4=qa*b zGEII58ziVWVgxW3LA?XWHv{x13LymuUBTieU#MuNDwF9pBJIO4!zWp4wAE8E!}Yo7 zi>w;e)lnXg*L30=)ot8n>mfg_MitX0^5B88Q!iPpK~u%7`6|kK1JB8dx{SukQaB^j z>RfjZSZ4Ldc$7TS=Vig4OlyJ&^5Ka7PIn9Wq7PWWFcJ+++A1ubytsu+r@o65WD?vDI6bfn`44`hwoacpfJR_&|mm& z4J#zV>8`m22I_BtYOo&9h@vC|5wP3f+cC}c8QU?N0NFjfi7Nb#x}r~33MN``!G2}i zv~cTL1XIMxfse`LIZ5p|@jkW3gRK$Tf)5X+K8{rEG$=1zKJr0JprPrRiF7Hbf!+q1 zqe)E>DMv=GU?KNNT!f3IN$0>+^4)EGzdTNT@^pS{%eXS>55gB64u_ZAdOUUbTCn7(lb(*exCe!aD)4%bHRI`;-!RbNi+qftkhW*`v^z_PcNWs?q zkNg;BTAbQ6o1wkX+OrL({ZPEsq#1k$pC&h4v^y*E=V}LU__?rmTF7+Y?3T0la}Sda zJY`{7zh|jI$20Dn{Jk-3MQzMxp&_SLNeD$&0#~uKcTR`OEiOlUUHmpc1o)_NMdn;Z zJM+WutbPP5klytB-<=P!Ts<_G8gp7*JrVgZhE;FB3S(REC^~Mu=pkF}bJ| zsmS!tY(WH>q^sConj+VgR<(derf8Xp{r6y5HpVi7?HJK{w~DJ1ususBUE26PoZumk z7aJExBes+GkC*3>8jTisFe;L`e|l3#j;< zesiBT+TEurzi~7)0hQvN01*ex7hvB?--sLquh3>yr20EGF$XuM{$tb=b}TlOtKO!` zFtWJbUrWj4w&@Y$8ScEtUcOmP&6{?uNgui9@abyQ1O9+BQ-iv0cBTGiQbBQ55eQ?3 zM>E_t8%!Bknj6t!RF!<1cI||Hj*B=dh@u$zIscXAdNmdLUULg<;rJG1haBoGD{mi_ zVt=A=22Lz__mwtkyaQxeRJY^f;a*kmviX~%RZ3^;D-1k`wZOK;hs@N6dn4*WjE~UclYP4987e4G%~!U}w5C9alRFmi0_jA(+qGoSsW55M%`gE3f$fSW$}G_Rbv$qZhF1|s>Q6o!6dnoJDUud)9l{yxw=JMrCkHv= zMI0%X7QK()Na`O^c<%BM;`fUqzP(wC6q8EpsLQL;5Wj_$D^~>{S*W{hYz`3J;w=5y zQ=tLw(E@zc(18dsxbjySE{45NHfMrv?E_b!Gxr(;nU|LMN%vbF+Hn2MOIK~5BEysI z&tN}Wl;Pz#OYKJeN66&_3pb9oSK)1=XpkC@!*UUR2tyb!=*V@S)~A*fPiPy!@FFH; z9j&aIIb2)%Dbo)#B@aMyXbx=4bjs1oN`0Tqg9W_}PPUq`bN$j{P3)`dS&MbvhWo^6 zKS03lE@pfmpqH@0PaUJf&S#tZBSHuW2=f;|@J6)`1ME%^vv0SQJV4RTC~uA)#0om2 z$*g?X^av690$NHqJpq8t;EB)1nOxT4HOyQLKX~Et6c8S1`&|OB=_Cw6vpC?(yKVfU3G#nox+IY8V% zn-{sRJwX(k$8DK{KNAURNN3^pbNw)t5M1W$7xC16nj=7g?hUub6kruK4nF?@N= z=i{~de6J8VTe;?d7yED%+K{Q8p>*XQHPMMk13Ykoh#1MBay^t78?`-T%SS6Divy=a zUE3rl7F`q)VtV^te70uwIx``llr#N}YU-xG&coz|eGLSWybDP|K>7#1wf@Cfx{0B+ z!h2xAM1z7R_MdZyRDdwlBi4UYG{=CE&ERF*)FQ(1%@YkKn|V*$(oA){qU@Zk^H83- zLF$qWp*T?9O1|i=sKk53xa0@Y?dKm&sCz%$!)FJVr-(J&1CplVOZ?OYZ!Wk@+`+$Pu>_LjAGbL(rSLT&M_=jtC*_X=*n*(m}cU>8jCgy~1X ztYtSoH0SE2?Bz4Ezg_Qi<)%UK7ki)o{Sxt+_p{$n7Ob?r<{T=6*?`>eIa1OK?PiPY5dDd*4Ng3A^ORMiS23OBLwv$1;yD-7NRKss8 z>|mKY=@jQ(O#|pJ4C{eI(Yw!fd@=#w@A<=qcCZ5qnnOwNaNcVKY1+&ZkOh;2d*z%0=sKJSJ|cqcZlS z#BN7sNG({6pRd$6tX*I&OUZ^jcfo?dA)b4cxo&*_KJcvP+bn3XC4hfet&*Z+*X&3` z@PQ^0k04;|sX=?9e)WxS)%s{M8K{pUraAwx*&F5lnPtlQelx@ndwAEOcU5&^w#3=d z3~J%3-7Eny_peWZqI!t~k3{k0a$)b)OM?ZEyPHR|qn5So{L{zJtwNQli`bYi$;rw6 z{FeBU#L?fvwl9^X=Vc&=e9;(L=9~u=QZ7s#iJ3VM7bb8(NXZrwuqA_*;NJY=Ez2HS-RQlF~ zE?H$J*>`#T09&Q-jncE**u=~FSxif zXIW{V_}+FI-SxpT+Z+|&M((GaE+;nm7WNLWsF)r1c<8HZQ|c|cF7i0xeXZlO zJzJl;NW%oquwGO7!HR^H;>TvUrim^_O7(K3nHN}FO_L>qTG3DFC}3XJ$inG)+z1s9 zP*9vm`)HiejlC||jKg}(-)4STZ!sI&J*PIwRgzlWK_w1Wb{T73TV$*VPTlp zH`ybDf;h0TCU^AnrpX9T??dvI6qoOf{in{iVJpLe`YKrmJQc^kyPg}0t+YN-<}+)# zIlCR|8@LRPuz)~F$yr+QGre1{Pmt+i13P^DopCHWM+|NnvHKhuea;pouyGSDG%+!v z6)~S&QwulM8FgDe=Pk?YiO0aWekT4qy@jMpzq&+hB*_EBNB!Eow}SbMF04;!n1*) zXpvQh6|8OFGa2l!g$8QdOdY{N!i;rqoki-7z8A8YYUne`Qc{c+r{606jy>Z3R#rDr zuOOPiP8e3Z?`pOr^g{MjV{MBWwN}HVHho}|L?Ah`yTES*tyBauq0@+(*7cLD7JLb= zR)^pH{#yEVeow(l zld1Q(^cablDxqKgdmBDe0#3j14kq)Ph3?JJja~jvp4&e&U+j{ETJ@l|e_bkPO${S_ zCka`vr>8H5nlU10;;t1H3ny!GA(T^f(k=XsLs_~6jCkC;7no?4y3aA9^I|b)d>C=| zYL0rNRh+`~UdE|Am%83e)|3v`LS?Gc`_~ZF;k+8ua>aXhK7yV#9WQ*!PRLf~!X1V` zgXQbdOHn1p&m{ATVoXQRn+-KxrgMpsj_1QJIGv1-dMEBRLC8t!BEzQ7=mm~@B39!1 zTckVOHWFn~y3#VJz9z|gZ%c z3DlmZ=c(6t`LDMDi5C!6hNXN7?bll!r!U}mB3EYI+&b&0@Qobtbt(qBK|rSdy<)XrHCoTmH1$i`w*4`)!v&uww-LE& znKK4m_;|IV8(s{s_7`r5VOVbo9EOs}w`ZBgau3E?)(wXenrRF3 z9d9e^z_Th!y6&fIZdo?0aUU8T&|ZHy0Y(7PN|&3eP>NgzzO2qmYMX5O{yx!3$1oN* z$;4^R1?h4*zV30q$>EW0AfL*f*jG(?GU#}!i`VYHaL~w2P1LLE2I7bc%wF2iV96Ru zP>^S&p8(C*COiWUrkSe!{#9KqymkK@7i=?_JGO^%_)El~&k^SvIPpB0$$KZapsMNa zWU4>hHZeLquvS?6X9Zr1s~y`3$pMpTq2@ZtI&;-`+r|POx14H`8X*ShiIw^dnejI z>IUDAXkUVLn*z?Jn(rH6k=^KhE=z+n>E7sKTq`gOAYHAd|+#5ub|kp`Jmv%GP3KVv8{|9wFoaY5wK( z+8^Zyn55cQ2yeK&JUPfKU6_2Rl@Uj`RmJX%pQ9o5iO4@N9tt0}GB`X|uRLhm*SU*P zz(~>Myq)k3p`R*{Sku~!7GfRPZ9Bp|Y;6zw|xJHIJdDfk0PK z&GN462RgZOp8>g_^t?>JOJ6YkFTKwixlUB;L^*Nsq9GLU73j#r`60)C7(Jcy%WfUl zbzQcDlNFH6ina7>E7&u|q(&Y%TohHC-M79`7-Ipbq9O=%em-8Ug)$Dq`p37~44IW5 zXW4su2DQ$fr_$SDhuB{>iTR@wxiH(^y&{I8fV3@td~2HU#*SMUfqp_c+el~gr!)@? zqIkV_!3i(#5KzkMI_ zB-)aduD6CcIdg3$z%2)Du!2E2Xqjs6K=`txxbE@lQvKE!>YgSfR?V90z0Qi@x2j8g zf!YzB1_cG3MF0oj-j&e-5t32zmlmxPE)d4RPUF``M!m6H0*eo%k=g0}*J0!c9<#lVPO`VnPnN`SHR zf+mIXL{&M-uR}5|C`ih9kP_UCA9@Ad0~za@mfS$C{qGg+|6ai$@(=cmd#4&3^|!&f ze;Nd)QYvzWR&Ko#Te#n$6g2iRgp7w54Rn#Pv^Yr02YSu-(A_Op8j;Qw1Ar;559=5# zIl)0vrGE$CEn!GO7MC7t`~*fEQO^%(y=jsp7^VxrHDe51pf@kGqfB9<=#NanHRpe> z;h0t;0r(dE039WQs@9zx42*v)Ir@J-;7!HF4g(zzDzw*8lOsk?V90p_D1n#)|B4A% zcZz1CY}RPB*Dx2oPBzG74ipp=L#zP9NgaVn%~7|;raloV7&7(INpz_M-4*+0+7-|MzI$s~kk~(4~BK$X_g9<$?<`_Il}uXGq7X<+=wH>OQMGsi)j;8WIslD2mzsqtdef$g=I#JO95L{ZE5`mwo)N2AC`cc~>LN zF!5^Cr`FB65CjV`gl}Jcu{-ql=9&Tu^cbiHJH8f8HDKG3=P)MHpZLRGi@qddO*>Hu zyRB^!+)A6O#!wm$_jWfl)1*GaL0|b~%|br+l(q3*0+UKYxZeD>!tA24;<}C(JOWOu zYaAW%!(}$MY6h2Iz@5YVGAZ2$liSfsTtO7NJQ-MD{!GeO)^FG6bO$o8f5jh^x*y*g zXzQ&Uy%TqIDRJbCtb5#D@^Ok%R-=DH#q|T5A!-Xg>WMhe_wLn&XgeCU?+y_cCf1G|lJ}Q3bR@}VoPwc6@kSJ%NSSSKIsNvR z;v!YxKQ)QMTsaxf>v4MY(}r5!!+e^58i4|3dR%R|JQ%jRis($HkW*nN4 z!LwEDtTinGaf(%bmY~TP`;##t@lGzlo9VnoDg8@hqS`wt^#{C3y1I5!j_`Vq-9LD` z*J-&U%Ly|JKGS1ccCwBem4_L8cio$wsF(Vu7n!59q%q3RxN7w%#t=-CJ(5g@07@UD zK_wHh*)7ORa4df}w<&`Y`J9}eqsqqI{^eZlsbu3D_AgI|Sg*^C`Q1unLUF`%acG%~ z--tNyf(K9$E$GQavtTzFOSG*rF_@awC?!MQq0yO``%k(jzMGsU?}E_f62Nf1qFNiz zjDbOfgHJ(Ux3g3xy#^R_i&N|uLqn|WJWbx#>c9&GCEN0bdrc+7cGurGN{Ae{^;P$g z{E?K$Gn)Cf7pTf`QLJByO2`hhw8bp^;lXoNeFsCC1^cz0US{symKJqzC~!N8@OY_f`A{go&cH z4kd4RV|AjQ_!X&e;M2UH_R58{6jxMy$f57@q}!0A z%az`957N>C!m}<2`4yEyQs{>sFB%jd68Bu5S|vte1Kr11dM7_E@YKLB0-N) zrl=3!;$9zuxap9`YMWFQmfVV z__D=Y(r86|c8_EEf}sXD7~53V?Z=_k+g*el^zrJFP$?_XpJXpWPGb7s^W{4+K_*y% z3>Ja;IyBB^txlmEdF0Q3DQrjJcefEQoXT2-aM)~%|I9IRB8!7Uo2h%IjRkjAv$1-)>~bkxJg$32Jux! zI9=jB(JyywcAIbl?5De0YcLqs1;3)+EU=accktJM$Iddo)5(BP=sZDlA>lnRcORQu z)0&dXF+-}vU4B`dKt}F&S{~;NYuaT0_+E#*pf({F!|j!DHZ0L4Rp^)154{Bn%Bp0$ z39M@~*Me5S{u2U7R3E4*vCapkJd}{#YSdS`o94+yvMsE^+ej(KB$wv_=Z9mzN-?jC zgxFT{|I}9P<6g==8OLkI8IfA1&xOMYd&VJBME2m zOF@eR1sjG}W07o?ctieivhaQ%lZqNk2m+P`T}e)Z@-bjdh2`Y8LuEo=1gfxXVSLhV zh)7e4X>l2HmVf^01Y_`Z)_0)%^#Be{P)LkuoxRG@Vf6D#vlK^!N^?Qj2@bpcTVb%y zH^k3=4{Sl(GpPKic_L5p`M#GN@mWgPx{swmimhIqIA)tMrP1W->}zo0V>j6^zk+@h zUlLNHzQOyXT9mX2h#J8jy47w~`B99P!$|B}75i z^LkHMvXK-DkssryCKk-gk#7mk)r}f&j7all6ts8&4tTPJ2Ln#%W~3}2Bl7>D z*&|eAo)%Yg1Y`JQpN7dNg_C40&~dtfgF-hn6j^-PcIC=VA2}xu9sP-NbNzfDfpF$> z<7V2_Ifh#b@W2rXT%I(3XHQ|WMcS<*<%~%&I906QOP=jx24r4RKZSwwi&9>~WVh_; zIm_WR<7AHPD+CTo3jvJV7L1!Z75JMz8H-uOAk+va7D4+L)Gv;H7^*^+vaKKpkN|k& zz0c#SR(_e-yYkHv%Xbc1tGh<>p_C^tvorN(2;yhp$kW}W31lTEP+_>G zdz27G>=@thCi+9-7~8j8igo%Gs3A~3Z{h~n6;7biDX$DKR`s9O4VQZ!^ewrTxp(4V zR3{;rb*;@sbM{0xmh9rcqJRm>vQ~nlhc&oK^1j+QQ_@O=tjA|Gx?l#Jg*7yZ_DP#f zn+cWZibJuA!~_>;IB0Q<+L7Xt-_^q+Yk|I;NTdQrXmv^O z-}uQUR8!)8Zx7rD*$!j72jsTfh>bwgt~GL0B9RGGA)WLfG<6y^{qw#~MT+?$Q#}4!emlqlP7vJSXWnsZM zBH2ay++UDh5%5y;D`}T&*tq^t%%r5u1BAE#AScn?t+kiOFjcrLrR7KEpZOm`H~ivW zYwT$SdB&q>^(~K-mZDRrfd8Hafm;BXT+;&t!(3RU+Olnq{_In|i%$15!z`{%GY*48 z5_O;t*y)S~8}Kh=DaPddCvTpyWCd4I<)W07X)XV1Kn3As0)|DTrbJ6fc*lCou_EIh z?Ynd7-jf-Ta(sSTh0c&5&*>Qv2k`ph1UdEK2lNy9VES!JfoG43I}s}0dr9#|#!cVE zWaA}xJw^mP*%ol)EFd1K&k-$7WAV3NYJZpv2eo#AeOs!+&vMb*aV$4HUks32ek?$5 z-GGEbGDKwP-jVZI@kgfujmiM3)e;1ZV7^~{sF*>gK<`P?=ko2vY8A0oQAlx-%d`SM zdzrhP;h-!aULcJjL30ZJab7ub>`*3yIaYbND5@fI$_af39$55K)`7lh{A%V;0-4H& zjrus-zcsuK=A@Vg$g}9t{13cg?5wnLl=cWt2YLESR~u=xR)QEr_1Q&G z*H_D4<8$NqKB6DpJNiH9TT)uLQyW=u;w^MhF?6MWdgR1;TKeb1f_BhASWng=VQBfb zW1mVaH)^<~om-Fd&A^ACZRE*FX}a}3zggJ;OAS<|LW29Q4sw|9Pv0EoVs7X-xAfp( zjK=?DVElZF>vQYSVf$Swr&9xBy?f{1wFx9I5~UD+O{7k-RWVW`2s`NaO{sB zBI~WLp3*@Q)d}?&we82I3vPnZT5Z3C4Rj?Ep&JVpXA+^0STB9ljmldJoCF~m0l-OL zCz-6vg6Q=;Mj6?nEj?nxO5*HGYjEdVEH_M_Sd8hgI?qZ8LVFssa%#I*@7x;K&bL38 z15UMyF)(QNt&*Wbi&{=o@n`v9PfY04unqJj0yboq)A>TX6Id?e>p7)npeI4QO7}C^ zm`cWGt(-cYAA+|j!menw}w)s%r9&dAcO>Cg|gw~uL{T-AxmvW)jS?*1SrToC}EQo#1sX+K`pw5 ztU4`CWm-1l96(L8|7T;uKbC&G@)qc$ggtwxM|YzD9wy(LEm8d)zjJWY=a7NO!|?5K z91&P*s7krRCEc^u1)h?#OQkmHfvyVxR3Sz7S8P8eon)X2D;n&=c&fk^ZC2b%P=9j)F7L6 za)?3#$-%9n0K+S*x+oxsQ0X2YM-*A3ix#@F*lIe)$R|(DUF}d!AnX0B2#z0HaFw6w z(f7jrKMhGsrB)`|OMN9!N}t(@>WdY3LKczwy+JfH8EHr%SUGDgMp8ONO_|lnZ?1`o z!I`D*NaObmfiE#PD`K>am?9ET{9|~)5+MTwxA=~SDDI|5!dw#xqdvcCM zYRlhogxL^1>sxVfAJ*AE;ie}O)s3YFa-TEVVWj+MQ zy~%jIvGqmfbsX~2{C9h=Q<$i;noq0ID>|?0LpwPc0|5#0`b2!m{zVTk7zPsnZVSYZ z;i`M_jtvm{PapDqu5MJExIK+}!)}x<%I4;(*d^}YaK1Fcqzg~?d73mmz!`S4$ESTj zpz*zGvoJd?a#p91hBJ~1EbHN{ZH69L7VcMGbd$}8yeU?(gj%rE#DM0>t z-yJT+$~j2TNeJ&zvlT6GSifubxmy$_`ja4(7wsUJI{p>r3J0H*a?Elrr%qa^+WVn^ zx*NS3MpY{fZ&boJtC2?CyV8^MCquE*gB;?^3S-s=7bLOBZB~>clHytX*jC+R%AfR% zSDl?IzrN{$s;q+?&;6(GM+8A zEHMgcy+2OtY3Yl>8L-!>znW!fNmDQ)mF~}6d`jJq=wZsVAY?GSbMM4*n3_$K^Kr4uZ8hYOe^Kh$Ov>hx=p`w*m3}& zROtNjmb@UId4JPSCfar@vO7Otx@4GrykT8RzP9fLeZveLAixu7J@Wv;BcAu|?>Itk z6+zwi=2GDTF&E|dwHDeq(OhRKChq-Z&l5w+FT30zs(ZvM76fWKwhpGlOITYN%Ph}) z-62!;#oeYKZLKQno#l6sk~hPr4ZtFR2T)tf?_DDgp?@cT&3IM9)C5BVRz{N!R^Q4z zgE5%fPKj-6xx8ogY~n(KVYP5o6mUMpH|u0KXeDa73T5JnN%2=-(ht4VPuX$uSz95Q zCkG(y)4j%29dVZF{ORHNNW2!~^c&Sc3td^2p%xRyfJp~fNAgm{-ZAFip^qeO7h-0A zb`h+O6MOA`eeIY7R`GWNk}qpjqM3Ji+E9aE_^oovz0hIC^Qw1xCR=#M7y7MjxmmCM z;8KnU1+myn4H${T#c^;%YUszeR8Gm zASW|7_A!C2Q)@|BXg=stF9pf>n~CJ<1pRo^IU&HKEp4^hCHV@>wx# z2JYr~fAz@z%n>&tW4NQOpmBX1^Tud$ijpTYJ#zg_=d8dCGhzrq`QXKo_cJ--rSW

v)JW!g56Xxm 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%0Ams|ps7zF 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 diff --git a/docs/after.png b/docs/after.png deleted file mode 100644 index f38ff044f2696ce7808f63ed4da933d5428bc9ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80617 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 $TFILE && mv $TFILE "$f" - else - echo "Error: Cannot read $f" - fi -done -/bin/rm $TFILE diff --git a/docs/categories/index.html b/docs/categories/index.html deleted file mode 100644 index 1281f4d83..000000000 --- a/docs/categories/index.html +++ /dev/null @@ -1,433 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Categories :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -

- - - - -
-
-
- -
- - - -
-
- -
-
- - -
- - -
- -

Categories

- - - - - - - - - - -
- - -
- - - -
- - - - - - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/categories/index.xml b/docs/categories/index.xml deleted file mode 100644 index c4e7faa15..000000000 --- a/docs/categories/index.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - Categories on Crunchy Data Container Suite Documentation - https://crunchydata.github.io/crunchy-containers/categories/ - Recent content in Categories on Crunchy Data Container Suite Documentation - Hugo -- gohugo.io - en-us - - - - - - \ No newline at end of file diff --git a/docs/categories/page/1/index.html b/docs/categories/page/1/index.html deleted file mode 100644 index 4b7078e51..000000000 --- a/docs/categories/page/1/index.html +++ /dev/null @@ -1 +0,0 @@ -https://crunchydata.github.io/crunchy-containers/categories/ \ No newline at end of file diff --git a/docs/container-specifications/crunchy-backrest-restore/index.html b/docs/container-specifications/crunchy-backrest-restore/index.html deleted file mode 100644 index a40e3a469..000000000 --- a/docs/container-specifications/crunchy-backrest-restore/index.html +++ /dev/null @@ -1,531 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-backrest-restore :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-backrest-restore

- - - - - - - - - -

The crunchy-backrest-restore container executes the pgBackRest utility, allowing FULL and DELTA restore capability. See the pgBackRest guide for more details.

- -

Features

- -

The following features are supported and required by the crunchy-backrest-restore container:

- -
    -
  • Mounted pgbackrest.conf configuration file via the /pgconf volume
  • -
  • Mounted /backrestrepo for access to pgBackRest archives
  • -
- -

Packages

- -

The crunchy-backrest-restore Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • pgBackRest (2.x)
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
STANZANoneMust be set to the desired stanza for restore.
DELTANoneWhen set, will add the --delta option to the restore. The delta option allows pgBackRest to automatically determine which files in the database cluster directory can be preserved and which ones need to be restored from the backup - it also removes files not present in the backup manifest so it will dispose of divergent changes.
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PG_HOSTNAMENoneWhen restoring a backup to a new volume, this volume should be set to the hostname of the PostgreSQL container that will mount the restored volume. Required for full restores to new volumes.
PITR_TARGETNonePostgreSQL timestamp used when restoring up to a point in time. Required for PITR delta restores.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-backup/index.html b/docs/container-specifications/crunchy-backup/index.html deleted file mode 100644 index 591a1f752..000000000 --- a/docs/container-specifications/crunchy-backup/index.html +++ /dev/null @@ -1,571 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-backup :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-backup

- - - - - - - - - -

The crunchy-backup container executes a full backup against another -database container using the standard pg_basebackup utility that is -included with PostgreSQL.

- -

Features

- -

The following features are supported by the crunchy-backup container:

- -
    -
  • Backup and restoration from: pg_basebackup
  • -
- -

Packages

- -

The crunchy-backup Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
BACKUP_LABELcrunchy-backupThe label for the backup.
BACKUP_HOSTNoneName of the database the backup is being performed on.
BACKUP_USERNoneUsername for the PostgreSQL role being used.
BACKUP_PASSNonePassword for the PostgreSQL role being used.
BACKUP_PORT5432Database port used to do the backup.
- -

Optional

- - - - - - - - - - - - - - - - - -
NameDefaultDescription
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- -

Volumes

- - - - - - - - - - - - - - - - - - - - -
NameDescription
/backupVolume used by the pg_basebackup backup tool to store physical backups.
/pgdataVolume used to store the data directory contents for the PostgreSQL database.
- -

Backup Location

- -

Backups are stored in a mounted backup volume location, using the -database host name plus -backups as a sub-directory, then followed by a unique -backup directory based upon a date/timestamp. It is left to the -user to perform database backup archives in this current version -of the container. This backup location is referenced when performing -a database restore.

- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-collect/index.html b/docs/container-specifications/crunchy-collect/index.html deleted file mode 100644 index d5f2bfd1a..000000000 --- a/docs/container-specifications/crunchy-collect/index.html +++ /dev/null @@ -1,516 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-collect :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - -
- -
- - -
- - -
- -

crunchy-collect

- - - - - - - - - -

The crunchy-collect container provides real time metrics about the PostgreSQL database -via an API. These metrics are scrapped and stored by a Prometheus -time-series database and are then graphed and visualized through the open source data -visualizer Grafana.

- -

The crunchy-collect container uses pgMonitor for advanced metric collection. -It is required that the crunchy-postgres container has the PGMONITOR_PASSWORD environment -variable to create the appropriate user (ccp_monitoring) to collect metrics.

- -

Custom queries to collect metrics can be specified by the user. By -mounting a queries.yml file to /conf on the container, additional metrics -can be specified for the API to collect. For an example of a queries.yml file, see -here

- -

Packages

- -

The crunchy-collect Docker image contains the following packages (versions vary depending on PostgreSQL version):

- - - -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - -
NameDefaultDescription
DATA_SOURCE_NAMENoneThe URL for the PostgreSQL server’s data source name. This is required to be in the form of postgresql://. The user should be ccp_monitoring and use the PGMONITOR_PASSWORD value set in the PostgreSQL container.
- -

Optional

- - - - - - - - - - - - - - - - - -
NameDefaultDescription
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-dba/index.html b/docs/container-specifications/crunchy-dba/index.html deleted file mode 100644 index 84b5e30d7..000000000 --- a/docs/container-specifications/crunchy-dba/index.html +++ /dev/null @@ -1,841 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-dba :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- - - - -
- -

crunchy-dba

- - - - - - - - - -

The crunchy-dba container implements a cron scheduler. The purpose -of the crunchy-dba container is to offer a way to perform -simple DBA tasks that occur on some form of schedule such as -backup jobs or running a vacuum on a single PostgreSQL database container.

- -

You can either run the crunchy-dba container as a single pod or include -the container within a database pod.

- -

The crunchy-dba container makes use of a Service Account to perform -the startup of scheduled jobs. The Kubernetes Job type is used to execute -the scheduled jobs with a Restart policy of Never.

- -

Packages

- -

The crunchy-dba Docker image contains the following packages:

- -
    -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

General

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
OSE_PROJECTNoneThe OSE project name to log into.
JOB_HOSTNoneThe PostgreSQL container name the action will be taken against.
VAC_SCHEDULENoneIf set, this will start a vacuum job container. The setting value must be a valid cron expression as described below.
BACKUP_SCHEDULENoneIf set, this will start a backup job container. The setting value must be a valid cron expression as described below.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- -

Vacuum Job

- -

For a vacuum job, you are required to supply the following environment variables:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
JOB_HOSTNoneThe PostgreSQL container name the action will be taken against.
PG_USERNoneUsername for the PostgreSQL role being used.
PG_PASSWORDNonePassword for the PostgreSQL role being used.
PG_DATABASEpostgresDatabase host to connect to.
PG_PORT5432Allows you to override the default value of 5432.
VAC_ANALYZETRUEWhen set to true, adds the ANALYZE parameter to the VACUUM command.
VAC_FULLTRUEhen set to true, adds the FULL parameter to the VACUUM command.
VAC_VERBOSETRUEWhen set to true, adds the VERBOSE parameter to the VACUUM command.
VAC_FREEZEFALSEWhen set to true, adds the FREEZE parameter to the VACUUM command.
VAC_TABLEFALSEWhen set to true, allows you to specify a single table to vacuum. When not specified, the entire database tables are vacuumed.
- -

Backup Job

- -

For a backup job, you are required to supply the following environment variables:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
JOB_HOSTNoneThe PostgreSQL container name the action will be taken against.
PG_USERNoneUsername for the PostgreSQL role being used.
PG_PASSWORDNonePassword for the PostgreSQL role being used.
PG_PORT5432Allows you to override the default value of 5432.
BACKUP_PV_CAPACITYNoneA value like 1Gi is used to define the PV storage capacity.
BACKUP_PV_PATHNoneThe storage path used to build the PV.
BACKUP_PV_HOSTNoneThe storage host used to build the PV.
BACKUP_PVC_STORAGENoneA value like 75M means to allow 75 megabytes for the PVC used in performing the backup.
- -

CRON Expression Format

- -

A cron expression represents a set of times, using 6 space-separated fields.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Field NameMandatory?Allowed ValuesAllowed Special Characters
SecondsYes0-59* / , -
MinutesYes0-59* / , -
HoursYes0-23* / , -
Day of monthYes1-31* / , - ?
MonthYes1-12 or JAN-DEC* / , -
Day of weekYes0-6 or SUN-SAT* / , - ?
- -

Month and Day-of-week field values are case insensitive. “SUN”, “Sun”, and “sun” are equally accepted.

-
- - -

Special Characters

- -

Asterisk

- -

The asterisk indicates that the cron expression will match for all values -of the field; e.g., using an asterisk in the 5th field (month) would -indicate every month.

- -

Slash

- -

Slashes are used to describe increments of ranges. For example 3-5915 in -the 1st field (minutes) would indicate the 3rd minute of the hour and every -15 minutes thereafter. The form “*\/…” is equivalent to the form -“first-last/…”, that is, an increment over the largest possible range of -the field. The form “N/…” is accepted as meaning “N-MAX/…”, that is, -starting at N, use the increment until the end of that specific range. -It does not wrap around.

- -

Comma

- -

Commas are used to separate items of a list. For example, using -“MON,WED,FRI” in the 5th field (day of week) would mean Mondays, -Wednesdays and Fridays.

- -

Hyphen

- -

Hyphens are used to define ranges. For example, 9-17 would indicate every -hour between 9am and 5pm inclusive.

- -

Question mark

- -

Question mark may be used instead of “*” for leaving either day-of-month or -day-of-week blank.

- -

Predefined schedules

- -

You may use one of several pre-defined schedules in place of a cron expression.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EntryDescriptionEquivalent To
@yearly (or @annually)Run once a year, midnight, Jan. 1st0 0 0 1 1 *
@monthlyRun once a month, midnight, first of month0 0 0 1 * *
@weeklyRun once a week, midnight on Sunday0 0 0 * * 0
@daily (or @midnight)Run once a day, midnight0 0 0 * * *
@hourlyRun once an hour, beginning of hour0 0 * * * *
- -

Intervals

- -

You may also schedule a job to execute at fixed intervals. This is -supported by formatting the cron spec like this:

- -
@every <duration>
-
- -

where “duration” is a string accepted by time.ParseDuration -(http://golang.org/pkg/time/#ParseDuration).

- -

For example, “@every 1h30m10s” would indicate a schedule that activates every -1 hour, 30 minutes, 10 seconds.

- -

NOTE: The interval does not take the job runtime into account. For example, -if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes, -it will have only 2 minutes of idle time between each run.

- -

Time zones

- -

All interpretation and scheduling is done in the machines local -time zone (as provided by the Go time package -(http://www.golang.org/pkg/time).

- -

Be aware that jobs scheduled during daylight-savings leap-ahead transitions will not be run.

-
- - - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-grafana/index.html b/docs/container-specifications/crunchy-grafana/index.html deleted file mode 100644 index e436b70c9..000000000 --- a/docs/container-specifications/crunchy-grafana/index.html +++ /dev/null @@ -1,556 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-grafana :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - -
- -
- - -
- - -
- -

crunchy-grafana

- - - - - - - - - -

Visual dashboards are created from the collected and stored data that crunchy-collect and crunchy-prometheus -provide for the crunchy-grafana container, which hosts an open source web-based graphing dashboard called -Grafana.

- -

Grafana is a platform which can then apply the defined metrics and visualize information through various tools. -It is extremely flexible with a powerful query and transformation language, producing beautiful -and easily understandable graphics to analyze and monitor your data.

- -

By default, crunchy-grafana will register the Prometheus datasource within -Grafana and import a pre-made dashboard for PostgreSQL monitoring.

- -

The crunchy-grafana container must be able to reach the crunchy-prometheus container.

- -

Users must specify an administrator username and password to provide basic authentication -for the web frontend. Additionally, the Prometheus hostname and port number are required. If Prometheus uses -basic authentication, users must specify the username and password to access Prometheus via environment variables.

- -

A user may define a custom defaults.ini file and mount to /conf for custom configuration. -For configuration examples, see here.

- -

The following port is exposed by the crunchy-grafana container:

- -
    -
  • crunchy-grafana:3000 - the Grafana web user interface
  • -
- -

Packages

- -

The crunchy-grafana Docker image contains the following packages:

- -
    -
  • Grafana
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
ADMIN_USERNoneSpecifies the administrator user to be used when logging into the web frontend.
ADMIN_PASSNoneSpecifies the administrator password to be used when logging into the web frontend.
PROM_HOSTNoneSpecifies the Prometheus container hostname for auto registering the Prometheus datasource.
PROM_PORTNoneSpecifies the Prometheus container port for auto registering the Prometheus datasource.
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PROM_USER5sSpecifies the Prometheus username, if one is required.
PROM_PASS5sSpecifies the Prometheus password, if one is required.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-pgadmin4/index.html b/docs/container-specifications/crunchy-pgadmin4/index.html deleted file mode 100644 index 6b2525ae0..000000000 --- a/docs/container-specifications/crunchy-pgadmin4/index.html +++ /dev/null @@ -1,544 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-pgadmin4 :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-pgadmin4

- - - - - - - - - -

The crunchy-ppgadmin4 container executes the pgAdmin4 web application.

- -

pgAdmin4 provides a web user interface to PostgreSQL databases. A -sample screenshot is below:

- -

pgAdmin4

- -

Features

- -

The following features are supported by the crunchy-pgadmin4 container:

- -
    -
  • Expose port (5050 by default) which is the web server port.
  • -
  • Mount a certificate and key to the /certs directory and set ENABLE_TLS to true to activate HTTPS mode.
  • -
  • Set username and password for login via environment variables.
  • -
- -

Restrictions

- -
    -
  • An emptyDir, with write access, must be mounted to the /run/httpd directory in OpenShift.
  • -
- -

Packages

- -

The crunchy-pgadmin4 Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • pgAdmin4
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PGADMIN_SETUP_EMAILNoneSet this value to the email address used for pgAdmin4 login.
PGADMIN_SETUP_PASSWORDNoneSet this value to a password used for pgAdmin4 login. This should be a strong password.
SERVER_PORT5050Set this value to a change the port pgAdmin4 listens on.
ENABLE_TLSFALSESet this value to true to enable HTTPS on the pgAdmin4 container. This requires a server.key and server.crt to be mounted on the /certs directory.
- -

Optional

- - - - - - - - - - - - - - - - - -
NameDefaultDescription
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-pgbadger/index.html b/docs/container-specifications/crunchy-pgbadger/index.html deleted file mode 100644 index 379016fc7..000000000 --- a/docs/container-specifications/crunchy-pgbadger/index.html +++ /dev/null @@ -1,521 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-pgbadger :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-pgbadger

- - - - - - - - - -

The crunchy-pgbadger container executes the pgBadger utility, which -generates a PostgreSQL log analysis report using a small HTTP server running on the container. This log -report can be accessed through the URL http://<>:10000/api/badgergenerate.

- -

Features

- -

The following features are supported by the crunchy-pgbadger container:

- -
    -
  • Generate a full report by default
  • -
  • Optional custom options for more advanced use cases (such as incremental reports)
  • -
  • Report persistence on a volume
  • -
- -

Packages

- -

The crunchy-badger Docker image contains the following packages:

- -
    -
  • pgBadger
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - -
NameDefaultDescription
BADGER_TARGETNoneOnly used in standalone mode to specify the name of the container. Also used to find the location of the database log files in /pgdata/$BADGER_TARGET/pg_log/*.log.
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
BADGER_CUSTOM_OPTSNoneFor a list of optional flags, see the official pgBadger documentation.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-pgbouncer/index.html b/docs/container-specifications/crunchy-pgbouncer/index.html deleted file mode 100644 index 4f451c72c..000000000 --- a/docs/container-specifications/crunchy-pgbouncer/index.html +++ /dev/null @@ -1,585 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-pgbouncer :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-pgbouncer

- - - - - - - - - -

pgBouncer is a lightweight connection pooler for PostgreSQL databases.

- -

Features

- -

The following features are supported by the crunchy-pgbouncer container:

- -
    -
  • crunchy-pgbouncer uses auth_query to authenticate users. This requires only the pgbouncer -username and password in users.txt. Automatically generated from environment variables.
  • -
  • Mount a custom users.txt and pgbouncer.ini configurations for advanced usage.
  • -
  • Tune pooling parameters via environment variables.
  • -
  • Connect to the administration database in pgBouncer to view statistics of the target databases.
  • -
- -

Packages

- -

The crunchy-pgbouncer Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • pgBouncer
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Restrictions

- -
    -
  • OpenShift: If custom configurations aren’t being mounted, an emptydir volume is required -to be mounted at /pgconf.
  • -
  • Superusers cannot connect through the connection pooler.
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PGBOUNCER_PASSWORDNoneThe password of the pgBouncer role in PostgreSQL. Must be also set on the primary database.
PG_SERVICENoneThe hostname of the database service.
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
DEFAULT_POOL_SIZE20How many server connections to allow per user/database pair.
MAX_CLIENT_CONN100Maximum number of client connections allowed.
MAX_DB_CONNECTIONSUnlimitedDo not allow more than this many connections per-database.
MIN_POOL_SIZE0Adds more server connections to pool if below this number.
POOL_MODESessionWhen a server connection can be reused by other clients. Possible values: session, transaction and statement.
RESERVE_POOL_SIZE0How many additional connections to allow per pool. 0 disables.
RESERVE_POOL_TIMEOUT5If a client has not been serviced in this many seconds, pgbouncer enables use of additional connections from reserve pool. 0 disables.
QUERY_TIMEOUT0Queries running longer than that are canceled.
IGNORE_STARTUP_PARAMETERSextra_float_digitsSet to ignore particular parameters in startup packets.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-pgdump/index.html b/docs/container-specifications/crunchy-pgdump/index.html deleted file mode 100644 index 3e54c978b..000000000 --- a/docs/container-specifications/crunchy-pgdump/index.html +++ /dev/null @@ -1,582 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-pgdump :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-pgdump

- - - - - - - - - -

The crunchy-pgdump container executes either a pg_dump or pg_dumpall database backup against another -PostgreSQL database.

- -

Packages

- -

The crunchy-pgdump Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PGDUMP_DBNoneName of the database the backup is being performed on.
PGDUMP_HOSTNoneHostname of the database the backup is being performed on.
PGDUMP_PASSNonePassword for the PostgreSQL role being used.
PGDUMP_USERNoneUsername for the PostgreSQL role being used.
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PGDUMP_ALLTRUERun pg_dump instead of pg_dumpall. Set to false to enable pg_dump.
PGDUMP_CUSTOM_OPTSNoneAdvanced options to pass into pg_dump or pg_dumpall.
PGDUMP_FILENAMEdumpName of the file created by the pgdump container.
PGDUMP_PORT5432Port of the PostgreSQL database to connect to.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- -

For a list of advanced options for configuring the PGDUMP_CUSTOM_OPTS variable, see the official documentation:

- -

https://www.postgresql.org/docs/current/static/app-pgdump.html

- -

https://www.postgresql.org/docs/current/static/app-pg-dumpall.html

-
- - -

Volumes

- - - - - - - - - - - - - - - -
NameDescription
/pgdataVolume used to store the data directory contents for the PostgreSQL database.
- -

Dump Location

- -

Backups are stored in a mounted backup volume location, using the -database host name plus -backups as a sub-directory, then followed by a unique -backup directory based upon a date/timestamp. It is left to the -user to perform database backup archives in this current version -of the container. This backup location is referenced when performing -a database restore.

- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-pgpool/index.html b/docs/container-specifications/crunchy-pgpool/index.html deleted file mode 100644 index 371a682f4..000000000 --- a/docs/container-specifications/crunchy-pgpool/index.html +++ /dev/null @@ -1,540 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-pgpool :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-pgpool

- - - - - - - - - -

The crunchy-pgpool container executes the pgPool II -utility. pgPool can be used to provide a smart PostgreSQL-aware proxy to a PostgreSQL cluster, both primary -and replica, so that applications only have to work with a single database connection.

- -

PostgreSQL replicas are read-only whereas a primary is capable of receiving both read and write actions.

- -

The default pgPool examples use a Secret to hold the set of pgPool configuration files used by the examples. -The Secret is mounted into the pgconf volume mount where the container will look to find configuration files. -If you do not specify your own configuration files via a Secret then you can specify environment -variables to the container that it will attempt to use to configure pgPool, although this is not recommended -for production environments.

- -

Features

- -

The following features are supported by the crunchy-postgres container:

- -
    -
  • Basic invocation of pgPool II
  • -
- -

Packages

- -

The crunchy-pgpool Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • pgPool II
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PG_USERNAMENoneUsername for the PostgreSQL role being used.
PG_PASSWORDNonePassword for the PostgreSQL role being used.
PG_PRIMARY_SERVICE_NAMENoneDatabase host to connect to for the primary node.
PG_REPLICA_SERVICE_NAMENoneDatabase host to connect to for the replica node.
- -

Optional

- - - - - - - - - - - - - - - - - -
NameDefaultDescription
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-pgrestore/index.html b/docs/container-specifications/crunchy-pgrestore/index.html deleted file mode 100644 index 64024abf2..000000000 --- a/docs/container-specifications/crunchy-pgrestore/index.html +++ /dev/null @@ -1,579 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-pgrestore :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-pgrestore

- - - - - - - - - -

The restore image provides a means of performing a restore -of a dump from pg_dump or pg_dumpall via psql or pg_restore -to a PostgreSQL container database.

- -

Packages

- -

The crunchy-pgrestore Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PGRESTORE_DBNoneName of the database to connect to.
PGRESTORE_HOSTNoneHostname of the database to connect to.
PGRESTORE_PASSNonePassword for the PostgreSQL role being used.
PGRESTORE_USERNoneUsername for the PostgreSQL role being used.
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PGDUMP_BACKUP_HOSTNoneHostname of the PostgreSQL server that was backed up by pgdump container. Used when restoring a backup to a new host.
PGRESTORE_BACKUP_TIMESTAMPEmptyTimestamp of the backup to restore from.
PGRESTORE_CUSTOM_OPTSEmptyAdvanced options to pass into pg_restore.
PGRESTORE_PORT5432Port of the PostgreSQL database to connect to.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- -

For a list of advanced options for configuring the PGRESTORE_CUSTOM_OPTS variable, see the official documentation.

-
- - -

Volumes

- - - - - - - - - - - - - - - -
NameDescription
/pgdataVolume used to store the data directory contents for the PostgreSQL database.
- -

Dump-file Input Location

- -

As the input files for crunchy-pgrestore, files generated by crunchy-pgdump -are retrieved in a mounted backup volume location, using the -database host name plus -backups as a sub-directory, then followed by a unique -backup directory based upon a date/timestamp. It is left to the -user to restore database dump archives in this current version -of the container.

- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-postgres-gis/index.html b/docs/container-specifications/crunchy-postgres-gis/index.html deleted file mode 100644 index 6ed4e170e..000000000 --- a/docs/container-specifications/crunchy-postgres-gis/index.html +++ /dev/null @@ -1,785 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-postgres-gis :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-postgres-gis

- - - - - - - - - -

PostgreSQL (pronounced “post-gress-Q-L”) is an open source, ACID compliant, relational database management system (RDBMS) developed by a worldwide team of volunteers. The crunchy-postgres-gis container image is unmodified, open source PostgreSQL packaged and maintained by professionals. This image is identical to the crunchy-postgres image except it includes the open source geospatial extension PostGIS for PostgreSQL in addition to the language extension PL/R which allows for writing functions in the R statistical computing language.

- -

Features

- -

The following features are supported by the crunchy-postgres-gis container:

- -
    -
  • Kubernetes and OpenShift secrets
  • -
  • Backup and restoration from various tools: pgbackrest, pg_basebackup and pg_dump/pg_restore.
  • -
  • Custom mounted configuration files (see below)
  • -
  • Async and Sync Replication
  • -
  • PostGIS
  • -
  • PL/R
  • -
- -

Packages

- -

The crunchy-postgres-gis Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • pgBackRest (2.x)
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PG_DATABASENoneSet this value to create an initial database
PG_PRIMARY_PORTNoneSet this value to configure the primary PostgreSQL port. It is recommended to use 5432.
PG_MODENoneSet to primary, replica or set to specify the mode of the database
PG_USERNoneSet this value to specify the username of the general user account
PG_PASSWORDNoneSet this value to specify the password of the user role
PG_PRIMARY_USERNoneSet this value to specify the username of the replication user
PG_PRIMARY_PASSWORDNoneSet this value to specify the password of the replication user
PG_ROOT_PASSWORDNoneSet this value to specify the password of the superuser role
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
ARCHIVE_MODEOffSet this value to on to enable continuous WAL archiving
ARCHIVE_TIMEOUT60Set to a number (in seconds) to configure archive_timeout in postgresql.conf
CHECKSUMSOffEnables data-checksums during initialization of the database. Can only be set during initial database creation.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
ENABLE_SSHDFALSESet this value to true to enable SSHD. See SSHD Documentation for detailed setup instructions
MAX_CONNECTIONS100Sets the max_connections value in postgresql.conf
MAX_WAL_SENDERS6Set this value to configure the max number of WAL senders (replication)
PG_LOCALEUTF-8Set the locale of the database
PG_PRIMARY_HOSTNoneSet this value to specify primary host. Note: only used when PG_MODE != primary
PG_REPLICA_HOSTNoneSet this value to specify the replica host label. Note; used when PG_MODE is set
PGAUDIT_ANALYZENoneSet this to enable pgaudit_analyze
PGBOUNCER_PASSWORDNoneSet this to enable pgBouncer support by creating a special pgbouncer user for authentication through the connection pooler.
PGDATA_PATH_OVERRIDENoneSet this value to override the /pgdata directory name. By default /pgdata uses hostname of the container. In some cases it may be required to override this with a custom name (such as in a Statefulset)
SHARED_BUFFERS128MBSet this value to configure shared_buffers in postgresql.conf
SYNC_REPLICANoneSet this value to specify the names of replicas that should use synchronized replication
TEMP_BUFFERS8MBSet this value to configure temp_buffers in postgresql.conf
WORK_MEM4MBSet this value to configure work_mem in postgresql.conf
XLOGDIRNoneSet this value to configure PostgreSQL to send WAL to the /pgwal volume (by default WAL is stored in /pgdata)
- -

Volumes

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDescription
/backrestrepoVolume used by the pgbackrest backup tool to store physical backups.
/backupVolume used by the pg_basebackup backup tool to store physical backups.
/pgconfVolume used to store custom configuration files mounted to the container.
/pgdataVolume used to store the data directory contents for the PostgreSQL database.
/pgwalVolume used to store Write Ahead Log (WAL) when XLOGDIR environment variable is set to true.
/recoverVolume used for Point In Time Recovery (PITR) during startup of the PostgreSQL database.
/sshdVolume used to store SSHD requirements (sshd_config and server key).
- -

Custom Configuration

- -

The following configuration files can be mounted to the /pgconf volume in the crunchy-postgres container to customize the runtime:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDescription
ca.crtCertificate of the CA used by the server when using SSL authentication
ca.crlRevocation list of the CA used by the server when using SSL authentication
pg_hba.confClient authentication rules for the database
pg_ident.confMapping of external users (such as SSL certs, GSSAPI, LDAP) to database users
pgbackrest.confpgBackRest configurations
postgresql.confPostgreSQL settings
server.keyKey used by the server when using SSL authentication
server.crtCertificate used by the server when using SSL authentication
setup.sqlCustom SQL to execute against the database. Note: only run during the first startup (initialization)
- -

Verifying PL/R

- -

In order to verify the successful initialization of the PL/R extension, the following commands can be run:

-
create extension plr;
-SELECT * FROM plr_environ();
-SELECT load_r_typenames();
-SELECT * FROM r_typenames();
-SELECT plr_array_accum('{23,35}', 42);
-CREATE OR REPLACE FUNCTION plr_array (text, text)
-RETURNS text[]
-AS '$libdir/plr','plr_array'
-LANGUAGE 'c' WITH (isstrict);
-select plr_array('hello','world');
- - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-postgres/index.html b/docs/container-specifications/crunchy-postgres/index.html deleted file mode 100644 index dfe41a12c..000000000 --- a/docs/container-specifications/crunchy-postgres/index.html +++ /dev/null @@ -1,775 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-postgres :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-postgres

- - - - - - - - - -

PostgreSQL (pronounced “post-gress-Q-L”) is an open source, ACID compliant, relational database management system (RDBMS) developed by a worldwide team of volunteers. The crunchy-postgres container image is unmodified, open source PostgreSQL packaged and maintained by professionals.

- -

Features

- -

The following features are supported by the crunchy-postgres container:

- -
    -
  • Kubernetes and OpenShift secrets
  • -
  • Backup and restoration from various tools: pgbackrest, pg_basebackup and pg_dump/pg_restore.
  • -
  • Custom mounted configuration files (see below)
  • -
  • Async and Sync Replication
  • -
- -

Packages

- -

The crunchy-postgres Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • pgBackRest (2.x)
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PG_DATABASENoneSet this value to create an initial database
PG_PRIMARY_PORTNoneSet this value to configure the primary PostgreSQL port. It is recommended to use 5432.
PG_MODENoneSet to primary, replica or set to specify the mode of the database
PG_USERNoneSet this value to specify the username of the general user account
PG_PASSWORDNoneSet this value to specify the password of the user role
PG_PRIMARY_USERNoneSet this value to specify the username of the replication user
PG_PRIMARY_PASSWORDNoneSet this value to specify the password of the replication user
PG_ROOT_PASSWORDNoneSet this value to specify the password of the superuser role
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
ARCHIVE_MODEOffSet this value to on to enable continuous WAL archiving
ARCHIVE_TIMEOUT60Set to a number (in seconds) to configure archive_timeout in postgresql.conf
CHECKSUMStrueEnables data-checksums during initialization of the database. Can only be set during initial database creation. Set to false to disable data checksums.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
ENABLE_SSHDFALSESet this value to true to enable SSHD. See SSHD Documentation for detailed setup instructions
MAX_CONNECTIONS100Sets the max_connections value in postgresql.conf
MAX_WAL_SENDERS6Set this value to configure the max number of WAL senders (replication)
PG_LOCALEUTF-8Set the locale of the database
PG_PRIMARY_HOSTNoneSet this value to specify primary host. Note: only used when PG_MODE != primary
PG_REPLICA_HOSTNoneSet this value to specify the replica host label. Note; used when PG_MODE is set
PGAUDIT_ANALYZENoneSet this to enable pgaudit_analyze
PGBOUNCER_PASSWORDNoneSet this to enable pgBouncer support by creating a special pgbouncer user for authentication through the connection pooler.
PGMONITOR_PASSWORDNoneSet this to enable pgMonitor support by creating a special ccp_monitoring user for collecting metrics from PostgreSQL servers. Required for the crunchy-collect container.
PGDATA_PATH_OVERRIDENoneSet this value to override the /pgdata directory name. By default /pgdata uses hostname of the container. In some cases it may be required to override this with a custom name (such as in a Statefulset)
SHARED_BUFFERS128MBSet this value to configure shared_buffers in postgresql.conf
SYNC_REPLICANoneSet this value to specify the names of replicas that should use synchronized replication
TEMP_BUFFERS8MBSet this value to configure temp_buffers in postgresql.conf
WORK_MEM4MBSet this value to configure work_mem in postgresql.conf
XLOGDIRNoneSet this value to configure PostgreSQL to send WAL to the /pgwal volume (by default WAL is stored in /pgdata)
- -

Volumes

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDescription
/backrestrepoVolume used by the pgbackrest backup tool to store physical backups.
/backupVolume used by the pg_basebackup backup tool to store physical backups.
/pgconfVolume used to store custom configuration files mounted to the container.
/pgdataVolume used to store the data directory contents for the PostgreSQL database.
/pgwalVolume used to store Write Ahead Log (WAL) when XLOGDIR environment variable is set to true.
/recoverVolume used for Point In Time Recovery (PITR) during startup of the PostgreSQL database.
/sshdVolume used to store SSHD requirements (sshd_config and server key).
- -

Custom Configuration

- -

The following configuration files can be mounted to the /pgconf volume in the crunchy-postgres container to customize the runtime:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDescription
ca.crtCertificate of the CA used by the server when using SSL authentication
ca.crlRevocation list of the CA used by the server when using SSL authentication
pg_hba.confClient authentication rules for the database
pg_ident.confMapping of external users (such as SSL certs, GSSAPI, LDAP) to database users
pgbackrest.confpgBackRest configurations
postgresql.confPostgreSQL settings
server.keyKey used by the server when using SSL authentication
server.crtCertificate used by the server when using SSL authentication
setup.sqlCustom SQL to execute against the database. Note: only run during the first startup (initialization)
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-prometheus/index.html b/docs/container-specifications/crunchy-prometheus/index.html deleted file mode 100644 index b8362d3f9..000000000 --- a/docs/container-specifications/crunchy-prometheus/index.html +++ /dev/null @@ -1,535 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-prometheus :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - -
- -
- - -
- - -
- -

crunchy-prometheus

- - - - - - - - - -

Prometheus is a multi-dimensional time series data model with an elastic query language. It is used in collaboration -with Grafana in this metrics suite. Overall, it’s reliable, manageable, and operationally simple for efficiently -storing and analyzing data for large-scale environments. It scraps metrics from exporters such as the ones utilized by the crunchy-collect -container. The crunchy-prometheus container must be able to reach the crunchy-collect container in order to -to scrape metrics.

- -

By default, crunchy-prometheus detects which environment its running on (Docker, Kubernetes, or OpenShift) -and applies a default configuration. If this container is running on Kubernetes or OpenShift, -it will use the Kubernetes API to discover pods with the label "crunchy-collect": "true". -The crunchy-collect container must have this label defined in order to be discovered.

- -

For Docker environments the crunchy-collect hostname must be specified as an environment -variable.

- -

A user may define a custom prometheus.yml file and mount to /conf for custom configuration. -For configuration examples, see here.

- -

The following port is exposed by the crunchy-prometheus container:

- -
    -
  • crunchy-prometheus:9090 - the Prometheus web user interface
  • -
- -

Packages

- -

The crunchy-prometheus Docker image contains the following packages:

- -
    -
  • Prometheus
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - -
NameDefaultDescription
COLLECT_HOSTNoneHostname of Crunchy Collect container. Only required in Docker environments.
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
SCRAPE_INTERVAL5sSet this value to the number of seconds to scrape metrics from exporters.
SCRAPE_TIMEOUT5sSet this value to the number of seconds to timeout when scraping metrics from exporters.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-sim/index.html b/docs/container-specifications/crunchy-sim/index.html deleted file mode 100644 index a222fbe0a..000000000 --- a/docs/container-specifications/crunchy-sim/index.html +++ /dev/null @@ -1,562 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-sim :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-sim

- - - - - - - - - -

The crunchy-sim container is a simple traffic simulator for PostgreSQL.

- -

Features

- -
    -
  • Creates a single connection to PostgreSQL and will execute -queries over a specified interval range.
  • -
  • Queries are specified through a simple YAML file. Each query is a name-value -pair and can span multiple lines by utilizing scalar notation (“|” or “>”) as -defined by the YAML spec.
  • -
  • Queries are randomly chosen for execution.
  • -
- -

Restrictions

- -
    -
  • Only one connection is created for all queries.
  • -
- -

Packages

- -

The crunchy-sim Docker image contains the following packages:

- -
    -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PGSIM_HOSTNoneThe PostgreSQL host address.
PGSIM_PORTNoneThe PostgreSQL host port.
PGSIM_USERNAMENoneThe PostgreSQL username.
PGSIM_PASSWORDNoneThe PostgreSQL password.
PGSIM_DATABASENoneThe database to connect.
PGSIM_INTERVALNoneThe units of the simulation interval. Valid values include: millisecond, second, and minute.
PGSIM_MININTERVALNoneThe minimum interval value.
PGSIM_MAXINTERVALNoneThe maximum interval value.
- -

Optional

- - - - - - - - - - - - - - - - - -
NameDefaultDescription
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-upgrade/index.html b/docs/container-specifications/crunchy-upgrade/index.html deleted file mode 100644 index 9f6d1fd33..000000000 --- a/docs/container-specifications/crunchy-upgrade/index.html +++ /dev/null @@ -1,566 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-upgrade :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - -
- - -
- -

crunchy-upgrade

- - - - - - - - - -

The crunchy-upgrade container contains both the 9.59.6 and 9.610 -PostgreSQL packages in order to perform a pg_upgrade from -9.5 to 9.6 or 9.6 to 10 versions.

- -

Features

- -

The following features are supported by the crunchy-upgrade container:

- -
    -
  • Supports a pg_upgrade of the PostgreSQL database.
  • -
  • Doesn’t alter the old database files.
  • -
  • Creates the new database directory.
  • -
- -

Restrictions

- -
    -
  • Does not currently support a PostGIS upgrade.
  • -
  • Supports upgrades from only 9.5 to 9.6, or 9.6 to 10.
  • -
- -

Packages

- -

The crunchy-upgrade Docker image contains the following packages (versions vary depending on PostgreSQL version):

- -
    -
  • PostgreSQL (10.5, 9.6.10 and 9.5.14)
  • -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
OLD_DATABASE_NAMENoneRefers to the database (pod) name that we want to convert.
NEW_DATABASE_NAMENoneRefers to the database (pod) name that is given to the upgraded database.
OLD_VERSIONNoneThe PostgreSQL version of the old database.
NEW_VERSIONNoneThe PostgreSQL version of the new database.
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
PG_LOCALEDefault localeIf set, the locale you want to create the database with.
CHECKSUMStrueEnables data-checksums during initialization of the database. Can only be set during initial database creation. Set to false to disable data checksums.
XLOGDIRNoneIf set, initdb will use the specified directory for WAL.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- -

Data checksums on the Crunchy PostgreSQL container were enabled by default in version 2.1.0. -When trying to upgrade, it’s required that both the old database and the new database -have the same data checksums setting. Prior to upgrade, check if data_checksums -were enabled on the database by running the following SQL: SHOW data_checksums

-
- - - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-vacuum/index.html b/docs/container-specifications/crunchy-vacuum/index.html deleted file mode 100644 index 824bb7222..000000000 --- a/docs/container-specifications/crunchy-vacuum/index.html +++ /dev/null @@ -1,562 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-vacuum :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - -
- -
- - -
- - -
- -

crunchy-vacuum

- - - - - - - - - -

The crunchy-vacuum container allows you to perform a SQL VACUUM job against a PostgreSQL database container. -You specify a database to vacuum using various environment variables which are listed below. It is possible -to run different vacuum operations either manually or automatically through scheduling.

- -

The crunchy-vacuum image is executed, with the Postgres connection parameters passed to the single-primary -PostgreSQL container. The type of vacuum performed is dictated by the environment variables passed into the job.

- -

More information on the PostgreSQL VACUUM job can be found in the official PostgreSQL documentation.

- -

Packages

- -

The crunchy-vacuum Docker image contains the following packages:

- -
    -
  • CentOS7 - publicly available
  • -
  • RHEL7 - customers only
  • -
- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
JOB_HOSTNoneThe PostgreSQL host the VACUUM should be performed against.
PG_DATABASENoneThe PostgreSQL database the VACUUM should be performed against.
PG_PORT5432Allows you to override the default value of 5432.
PG_USERNoneUsername for the PostgreSQL role being used.
PG_PASSWORDNonePassword for the PostgreSQL role being used.
- -

Optional

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
VAC_FULLTRUEWhen set to true, adds the FULL parameter to the VACUUM command.
VAC_TABLEFALSEWhen set to true, allows you to specify a single table to vacuum. When not specified, the entire database tables are vacuumed.
VAC_ANALYZETRUEWhen set to true, adds the ANALYZE parameter to the VACUUM command.
VAC_VERBOSETRUEWhen set to true, adds the VERBOSE parameter to the VACUUM command.
VAC_FREEZEFALSEWhen set to true, adds the FREEZE parameter to the VACUUM command.
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/crunchy-watch/index.html b/docs/container-specifications/crunchy-watch/index.html deleted file mode 100644 index c0f10590f..000000000 --- a/docs/container-specifications/crunchy-watch/index.html +++ /dev/null @@ -1,605 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -crunchy-watch :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - -
-
- -
-
- - -
- - -
- -

crunchy-watch

- - - - - - - - - -

The crunchy-watch container essentially does a health check -on a primary database container and performs a failover sequence -if the primary is not reached. The watch container has access to a service -account that is used inside the container to issue commands to OpenShift.

- -

In Kubrnetese 1.5, if a policy file is being used for securing down the -Kubernetes cluster, you could possibly need to add a policy to allow -the pg-watcher service account access to the Kubernetes API as mentioned -here.

- -

In Kubernetes 1.6, an equivalent RBAC policy is also possibly required depending -on your authorization/authentication configuration. See this link for details on the new RBAC policy mechanism.

- -

For example, you can grant cluster-admin permissions on the pg-watcher service -account in the my-namespace namespace as follows:

-
kubectl create clusterrolebinding pgwatcher-view-binding --clusterrole=cluster-admin --serviceaccount=my-namespace:pg-watcher
-

A less wide open policy would be applied like this on Kube 1.6 rbac:

-
kubectl create rolebinding my-sa-binding --clusterrole=admin --serviceaccount=demo:pg-watcher --namespace=demo
-

The above kubectl command is only available in Kubernetes 1.6. For prior -Kubernetes releases such as 1.5 and the alpha RBAC, you will need to -specify the role binding in a JSON/YAML file instead of using -the previous command syntax.

-
- - -

The oc/docker/kubectl commands are included into the container from the -host when the container image is built. These commands are used by -the watch logic to interact with the replica containers.

- -

Starting with release 1.7.1, crunchy-watch source code is relocated -to a separate GitHub repository located here.

- -

Environment Variables

- -

Required

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
CRUNCHY_WATCH_HEALTHCHECK_INTERVALNoneThe time to sleep in seconds between checking on the primary.
CRUNCHY_WATCH_FAILOVER_WAIT40sThe time to sleep in seconds between triggering the failover and updating its label.
PG_CONTAINER_NAMENoneIf set, the name of the container to refer to when doing an exec. This is required if you have more than 1 container in your database pod.
CRUNCHY_WATCH_PRIMARYNoneThe primary service name.
CRUNCHY_WATCH_REPLICANoneThe replica service name.
PG_PRIMARY_PORTNoneDatabase port to use when checking the database.
CRUNCHY_WATCH_USERNAMENoneDatabase user account to use when checking the database using pg_isready utility.
CRUNCHY_WATCH_DATABASENoneDatabase to use when checking the database using pg_isready.
REPLICA_TO_TRIGGER_LABELNoneThe pod name of a replica that you want to choose as the new primary in a failover; this will override the normal replica selection.
CRUNCHY_WATCH_PRE_HOOKNonePath to an executable file to run before failover is processed.
CRUNCHY_WATCH_POST_HOOKNonePath to an executable file to run after failover is processed.
- -

Optional

- - - - - - - - - - - - - - - - - -
NameDefaultDescription
CRUNCHY_DEBUGFALSESet this to true to enable debugging in logs. Note: this mode can reveal secrets in logs.
- -

Logic

- -

The watch container will watch the primary. If the primary dies, then -the watcher will:

- -
    -
  • create the trigger file on the replica that will become the new primary
  • -
  • change the labels on the replica to be those of the primary
  • -
  • start watching the new primary in case that falls over next
  • -
  • look for replicas that have the metadata label value of replicatype=trigger to prefer -the failover to. If found, it will use the first replica with that label; if -not found, it will use the first replica it finds.
  • -
- -

Example of looking for the failover replica:

-
oc get pod -l name=pg-replica-rc-dc
-NAME                     READY     STATUS    RESTARTS   AGE
-pg-replica-rc-dc           1/1       Running   2          16m
-pg-replica-rc-dc-1-96qs8   1/1       Running   1          16m
-
-oc get pod -l replicatype=trigger
-NAME             READY     STATUS    RESTARTS   AGE
-pg-replica-rc-dc   1/1       Running   2          16m
- - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/index.html b/docs/container-specifications/index.html deleted file mode 100644 index 26badc8b8..000000000 --- a/docs/container-specifications/index.html +++ /dev/null @@ -1,2256 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Container Specifications :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - -
-
- -
-
- - -
- - -
- -

Container Specifications

- - - - - - - - -
-

Latest Release: 2.1.0 2018-08-13

-
-
-

Introduction

-
-
-

Each of the containers found within the Crunchy Container Suite for PostgreSQL -are described in further detail within their respective pages.

-
-
-

The containers and their relationships to the overall architecture are depicted below:

-
-
-
-containers -
-
-
-
-
-

Containers

-
-
-

The following container images are provided with further information:

-
- -
-
-
-

crunchy-postgres

-
-
-

The crunchy-postgres container executes the Postgres database.

-
-
-

Packages

-
-

The container image is built using either the Crunchy Postgres release -or the community version based upon a flag in the Makefile.

-
-
-

The crunchy-postgres RPMs are available to Crunchy customers only. The -Crunchy release is meant for customers that require enterprise level -support.

-
-
-

The PGDG community RPMs can be used as well by simply commenting out -the Crunchy yum repo within the Dockerfiles and uncommenting -the PGDG yum repo.

-
-
-
-

setup.sql

-
-

The setup.sql script is used to define startup SQL commands that are -executed when the database is first created.

-
-
-
-

Environment Variables

-
-
    -
  • -

    PG_MODE - either primary, replica or set, this value determines whether -the database is set up as a primary or replica instance. In the -case of set, it means the container is started within a StatefulSet -in a Kubernetes cluster.

    -
  • -
  • -

    PG_PRIMARY_USER - the value to use for the user ID created as -primaryuser. The primaryuser has super user privileges.

    -
  • -
  • -

    PG_PRIMARY_PASSWORD - the password for the PG_PRIMARY_USER database user

    -
  • -
  • -

    PG_USER - the value to use for the user ID created as a normal user. -This user is created as part of the setup.sql script upon database -creation and allows users to predefine an application user.

    -
  • -
  • -

    PG_PASSWORD - the password for the PG_USER database user that is created

    -
  • -
  • -

    PG_DATABASE - a database that is created upon database initialization

    -
  • -
  • -

    PG_ROOT_PASSWORD - the PostgreSQL user password set up upon database -initialization

    -
  • -
  • -

    PG_LOCALE - if set, the locale you want to create the database with, if -not set, the default locale is used

    -
  • -
  • -

    SYNC_REPLICA - if set, this value is used to specify the application_name -of a replica that will be used for a synchronous replication

    -
  • -
  • -

    CHECKSUMS - if set, this value is used to enable the --data-checksums -option when initdb is executed at initialization, if not set, the -default is to not enable data checksums

    -
  • -
  • -

    ARCHIVE_MODE - if set to on, will enable continuous WAL archiving -by setting the value within the postgresql.conf file archive_mode -setting, if not set, the default is off

    -
  • -
  • -

    ARCHIVE_TIMEOUT - if set to a number (in seconds) , will specify -the postgresql.conf archive_timeout setting, if not set, the -default value of 60 is used.

    -
  • -
  • -

    PGAUDIT_ANALYZE - if set, will cause the container to also start the -pgaudit_analyze program in the background

    -
  • -
  • -

    PG_PRIMARY_HOST - for when PG_MODE is set, specifies the primary -host for setting the primary label

    -
  • -
  • -

    PG_REPLICA_HOST - for when PG_MODE is set, specifies the replica -host for setting the replica label

    -
  • -
  • -

    PGDATA_PATH_OVERRIDE - if set, will cause the container to use a /pgdata path -name of your choosing rather than the hostname of the container which -is the default. This is useful for a primary in a deployment.

    -
  • -
  • -

    XLOGDIR - if set to true, will cause initdb to include --xlogdir=$PGWAL, this -will cause a symlink to be created from /pgdata/containername/pg_wal (or pg_xlog if you’re running PG 9.5 or 9.6) to /pgwal/containername-wal

    -
  • -
  • -

    TEMP_BUFFERS - default is 8MB, set this value to override this PostgreSQL configuration setting

    -
  • -
  • -

    MAX_CONNECTIONS - default is 100, set this value to override this PostgreSQL configuration setting

    -
  • -
  • -

    SHARED_BUFFERS - default is 128MB, set this value to override this PostgreSQL configuration setting

    -
  • -
  • -

    WORK_MEM - default is 4MB, set this value to override this PostgreSQL configuration setting

    -
  • -
  • -

    MAX_WAL_SENDERS - default is 6, set this value to override this PostgreSQL configuration setting

    -
  • -
  • -

    ENABLE_SSHD- default is false, set this value to true to enable SSHD

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-

Features

-
-

The following features are supported by the crunchy-postgres container:

-
-
-
    -
  • -

    use of OpenShift secrets

    -
  • -
  • -

    ability to restore from a database backup

    -
  • -
  • -

    use of custom pg_hba.conf and postgresql.conf files

    -
  • -
  • -

    ability to override postgresql.conf configuration parameters

    -
  • -
  • -

    ability to override the default setup.sql script

    -
  • -
  • -

    ability to set the database locale

    -
  • -
  • -

    ability to specify a synchronous replica application_name

    -
  • -
  • -

    ability to specify a recovery using PITR and WAL files

    -
  • -
  • -

    ability to enable SSHD

    -
  • -
-
-
-
-

Locale Support

-
-

Adding locale support to the container is accomplished by -running 'yum reinstall glibc_common' within the container, this -increases the size of the container image and can be removed if you -do not require specific locale support.

-
-
-

You can specify the PG_LOCALE env var which is passed to the initdb -command when the initial data files are created, for example:

-
-
-
-
"name": "PG_LOCALE",
-"value": "fr_BE.UTF-8"
-
-
-
-

By default, no locale is specified when the initdb command is executed.

-
-
-
-
-
-

crunchy-postgres-gis

-
-
-

This container is the same as the crunchy-postgres container except -that it includes the following PostgreSQL extensions:

-
-
-
    -
  • -

    postgis

    -
  • -
  • -

    pl/r

    -
  • -
-
-
-

You can test the pl/r extension by running the following commands -for example:

-
-
-
-
create extension plr;
-SELECT * FROM plr_environ();
-SELECT load_r_typenames();
-SELECT * FROM r_typenames();
-SELECT plr_array_accum('{23,35}', 42);
-CREATE OR REPLACE FUNCTION plr_array (text, text)
-RETURNS text[]
-AS '$libdir/plr','plr_array'
-LANGUAGE 'c' WITH (isstrict);
-select plr_array('hello','world');
-
-
-
-
-
-

crunchy-backup

-
-
-

The crunchy-backup container executes a pg_basebackup against another -database container. The backup is a full backup using the standard -utility included with PostgreSQL, pg_basebackup.

-
-
-

Backup Location

-
-

Backups are stored in a mounted backup volume location, using the -database host name plus -backups as a sub-directory, then followed by a unique -backup directory based upon a date/timestamp. It is left to the -user to perform database backup archives in this current version -of the container. This backup location is referenced when performing -a database restore.

-
-
-
-

Dependencies

-
-

The container is meant to be using NFS or a similar network file system -to persist database backups.

-
-
-
-

Environment Variables

-
-
    -
  • -

    BACKUP_LABEL - when set, will set the label of the backup, if not -set the default label used is crunchy-backup

    -
  • -
  • -

    BACKUP_HOST - required, this is the database we will be doing the -backup for

    -
  • -
  • -

    BACKUP_USER - required, this is the database user we will be doing the -backup with

    -
  • -
  • -

    BACKUP_PASS - required, this is the database password we will be doing the -backup with

    -
  • -
  • -

    BACKUP_PORT - required, this is the database port we will be doing the -backup with

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-
-
-

crunchy-pgdump

-
-
-

The crunchy-pgdump container executes either a pg_dump or pg_dumpall against another -Postgres database.

-
-
-

Dump Location

-
-

Dumps are stored in a mounted backup volume location, using the -database host name plus -backups as a sub-directory, then followed by a unique -backup directory based upon a date/timestamp. It is left to the -user to perform database dump archives in this current version -of the container.

-
-
-
-

Dependencies

-
-

The container is meant to be using NFS or a similar network file system -to persist database dumps.

-
-
-
-

Environment Variables

-
-

REQUIRED ARGS

-
-
    -
  • -

    PGDUMP_DB - Database to connect to

    -
  • -
  • -

    PGDUMP_HOST - Hostname of the PostgreSQL database to connect to

    -
  • -
  • -

    PGDUMP_PASS - Password of the PostgreSQL role used by the pgdump container

    -
  • -
  • -

    PGDUMP_USER - PostgreSQL Role used by the pgdump container

    -
  • -
-
-
-
-

OPTIONAL/EXTENDED ARGS

-
-
    -
  • -

    PGDUMP_ALL - Run pg_dump instead of pg_dumpall. Default is true, set to false to use pg_dump

    -
  • -
  • -

    PGDUMP_CUSTOM_OPTS - Advanced options to pass into pg_dump or pg_dumpall. Default is empty

    -
  • -
  • -

    PGDUMP_FILENAME - Name of the file created by the pgdump container. Default is dump

    -
  • -
  • -

    PGDUMP_PORT - Port of the PostgreSQL database to connect to. Default is 5432

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-

Note: For a list of advanced options for configuring the PGDUMP_CUSTOM_OPTS variable, see the official documentation:

-
- -
-
-
-
-
-

crunchy-collect

-
-
-

Description

-
-

Crunchy Collect container provides real time metrics about the PostgreSQL database -via an API. These metrics are scrapped and stored by Crunchy Prometheus time-series -database and visualized by Crunchy Grafana.

-
-
-
-

Requirements

-
-

This container requires TCP access to the PostgreSQL database to run queries for -collecting metrics. The PostgreSQL database to be scrapped is specified by the -DATA_SOURCE_NAME environment variable.

-
-
-

Additionally, custom queries to collect metrics can be specified by the user. By -mounting a queries.yml file to /conf on the container, additionally metrics -can be specified for the API to collect. For an example of a queries.yml file, see -here.

-
-
-
-

Environment Variables

-
-

Required:

-
-
-
    -
  • -

    DATA_SOURCE_NAME - The URL for the PostgreSQL server’s data source name. -This is required to be in the form of postgresql://.

    -
  • -
-
-
-

Optional: - * CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. - Note: this mode can reveal secrets in logs.

-
-
-
-
-
-

crunchy-prometheus

-
-
-

Description

-
-

Prometheus is a multi-dimensional time series data model with an elastic query language. It is used in collaboration -with Grafana in this metrics suite. Overall, it’s reliable, manageable, and operationally simple for efficiently -storing and analyzing data for large-scale environments. It scraps metrics from exporters such as -Crunchy Collect.

-
-
-

The following port is exposed by the crunchy-prometheus container:

-
-
-
    -
  • -

    crunchy-prometheus:9090 - the Prometheus web user interface

    -
  • -
-
-
-
-

Requirements

-
-

The Crunchy Prometheus container must be able to reach the Crunchy Collect container -to scrape metrics.

-
-
-

By default, Crunchy Prometheus detects which environment its running on (Docker, Kube or OCP) -and applies a default configuration. If this container is running on Kube or OCP, -it will use the Kubernetes API to discover pods with the label "crunchy-collect": "true". -Crunchy Collect container must have this label to be discovered.

-
-
-

For Docker environments the Crunchy Collect hostname must be specified as an environment -variable.

-
-
-

A user may define a custom prometheus.yml file and mount to /conf for custom configuration. -For a configuration examples, see here.

-
-
-
-

Environment Variables

-
-

Required:

-
-
-
    -
  • -

    COLLECT_HOST - Hostname of Crunchy Collect container. Only required in Docker -environments.

    -
  • -
-
-
-

Optional:

-
-
-
    -
  • -

    SCRAPE_INTERVAL - default is "5s", set this value to the number of seconds to scrape -metrics from exporters.

    -
  • -
  • -

    SCRAPE_TIMEOUT - default is "5s", set this value to the number of seconds to timeout when scraping -metrics from exporters.

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-
-
-

crunchy-grafana

-
-
-

Description

-
-

Visual dashboards are created from the collected and stored data that crunchy-collect and crunchy-prometheus -provides with the crunchy-grafana container, which hosts a web-based graphing dashboard called Grafana.

-
-
-

Grafana is an open-source platform which can then apply the defined metrics and visualize information through -various tools. It is extremely flexible with a powerful query and transformation language, producing beautiful -and easily understandable graphics to analyze and monitor your data.

-
-
-

By default, Crunchy Grafana will register the Crunchy Prometheus datasource within -Grafana and import a premade dashboard for PostgreSQL monitoring.

-
-
-

The following port is exposed by the crunchy-grafana container:

-
-
-
    -
  • -

    crunchy-grafana:3000 - the Grafana web user interface

    -
  • -
-
-
-
-

Requirements

-
-

The Crunchy Grafana container must be able to reach the Crunchy Prometheus container.

-
-
-

Users must specify an administrator user and password to provide basic authentication -for the web frontend.

-
-
-

Additionally the Prometheus Host and Port are required. If Prometheus uses basic -authentication, users must specify the username and password to access Prometheus -via environment variables.

-
-
-

Users may define a custom defaults.ini file and mount to /conf for custom configuration. -For a configuration examples, see here.

-
-
-
-

Environment Variables

-
-

Required:

-
-
-
    -
  • -

    ADMIN_USER - specifies the administrator user to be used when logging into the -web frontend.

    -
  • -
  • -

    ADMIN_PASS - specifies the administrator password to be used when logging into the -web frontend.

    -
  • -
  • -

    PROM_HOST - specifies the Prometheus container hostname for auto registering the -prometheus datasource.

    -
  • -
  • -

    PROM_PORT - specifies the Prometheus container port for auto registering the -prometheus datasource.

    -
  • -
-
-
-

Optional:

-
-
-
    -
  • -

    PROM_USER - specifies the Prometheus username, if one is required.

    -
  • -
  • -

    PROM_PASS - specifies the Prometheus password, if one is required.

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-
-
-

crunchy-pgbadger

-
-
-

The crunchy-pgbadger container executes the pgbadger utility. A small -http server is running on the container, when a request is made to:

-
-
-
-
http://<<ip address>>:10000/api/badgergenerate
-
-
-
-

Environment Variables

-
-

Optional:

-
-
-
    -
  • -

    BADGER_TARGET - only used in standalone mode to specify the -name of the container, also used to find the location of the -database log files in /pgdata/$BADGER_TARGET/pg_log/*.log

    -
  • -
  • -

    BADGER_CUSTOM_OPTS - no default, set this value to provide custom flags to pgbadger. -For a list of optional flags, see the official pgBadger documentation.

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-

Features

-
-

The following features are supported by the crunchy-pgbadger container:

-
-
-
    -
  • -

    Generate a full report by default

    -
  • -
  • -

    Optional custom options for more advanced use cases (such as incremental reports)

    -
  • -
  • -

    Report persistence on a volume

    -
  • -
-
-
-
-
-
-

crunchy-pgpool

-
-
-

The crunchy-pgpool container executes the pgpool utility. Pgpool can -be used to provide a smart PostgreSQL-aware proxy to a PostgreSQL cluster, -both primary and replica, so that applications can only have to work -with a single database connection.

-
-
-

Postgres replicas are read-only whereas a primary is both read and write -capable.

-
-
-

The default pgpool examples use a Secret to hold the set of pgpool -configuration files used by the examples. The Secret is mounted -into the pgconf volume mount where the container will look to -find configuration files. If you do not specify your own -configuration files via a Secret then you can specify environment -variables to the container that it will attempt to use to -configure pgpool, this is not recommended however for a real -pgpool deployment.

-
-
-

Environment Variables

-
-
    -
  • -

    PG_USERNAME - user to connect to PostgreSQL

    -
  • -
  • -

    PG_PASSWORD - user password to connect to PostgreSQL

    -
  • -
  • -

    PG_PRIMARY_SERVICE_NAME - database host to connect to for the primary node

    -
  • -
  • -

    PG_REPLICA_SERVICE_NAME - database host to connect to for the replica node

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-

Features

-
-

The following features are supported by the crunchy-pgpool container:

-
-
-
    -
  • -

    basic invocation of pgpool

    -
  • -
-
-
-
-
-
-

crunchy-watch

-
-
-

crunchy-watch runs as a pod unto itself -typically. The watch container essentially does a health check -on a primary database container and performs a failover sequence -if the primary is not reached.

-
-
-

The watch container has access to a service account that is used -inside the container to issue commands to OpenShift.

-
-
-

In Kube 1.5, if a policy file is being used for securing down the -Kube cluster, you could possibly need to add a policy to allow -the pg-watcher service account access to the Kube API as mentioned -here: https://kubernetes.io/docs/admin/authorization/abac/#a-quick-note-on-service-accounts

-
-
-

In Kube 1.6, an equivalent RBAC policy is also possibly required depending -on your authorization/authentication configuration. See this -link for details on the new RBAC policy mechanism: -https://kubernetes.io/docs/admin/authorization/rbac/

-
-
-

For example, you can grant cluster-admin permissions on the pg-watcher service -account, in the my-namespace namespace as follows:

-
-
-
-
kubectl create clusterrolebinding pgwatcher-view-binding --clusterrole=cluster-admin --serviceaccount=my-namespace:pg-watcher
-
-
-
-

A less wide open policy would be applied like this on Kube 1.6 rbac:

-
-
-
-
kubectl create rolebinding my-sa-binding --clusterrole=admin --serviceaccount=demo:pg-watcher --namespace=demo
-
-
-
- - - - - -
-
Note
-
-this kubectl command is only available in Kube 1.6, for prior -Kube release such as 1.5 and the alpha RBAC, you will need to -specify the role binding in a JSON/YAML file instead of using -this command syntax above. -
-
-
-

You then reference the SA within the POD spec.

-
-
-

The oc/docker/kubectl commands are included into the container from the -host when the container image is built. These commands are used by -the watch logic to interact with the replica containers.

-
-
-

Starting with release 1.7.1 crunchy-watch source code is relocated -to https://github.com/crunchydata/crunchy-watch

-
-
-

Environment Variables

-
-
    -
  • -

    CRUNCHY_WATCH_HEALTHCHECK_INTERVAL - the time to sleep in seconds between checking on the primary

    -
  • -
  • -

    CRUNCHY_WATCH_FAILOVER_WAIT - the time to sleep in seconds between triggering the failover and updating its label (default is 40 secs)

    -
  • -
  • -

    PG_CONTAINER_NAME - if set, the name of the container to refer to when doing an exec, this is required if you have more than 1 container in your database pod

    -
  • -
  • -

    CRUNCHY_WATCH_PRIMARY - the primary service name

    -
  • -
  • -

    CRUNCHY_WATCH_REPLICA - the replica service name

    -
  • -
  • -

    PG_PRIMARY_PORT - database port to use when checking the database

    -
  • -
  • -

    CRUNCHY_WATCH_USERNAME - database user account to use when checking the database -using pg_isready utility

    -
  • -
  • -

    CRUNCHY_WATCH_DATABASE - database to use when checking the database using pg_isready

    -
  • -
  • -

    REPLICA_TO_TRIGGER_LABEL - the pod name of a replica that you -want to choose as the new primary in a failover; this will override -the normal replica selection

    -
  • -
  • -

    CRUNCHY_WATCH_PRE_HOOK - path to an executable file to run before failover is processed.

    -
  • -
  • -

    CRUNCHY_WATCH_POST_HOOK - path to an executable file to run after failover is processed.

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-

Logic

-
-

The watch container will watch the primary, if the primary dies, then -the watcher will:

-
-
-
    -
  • -

    create the trigger file on the replica that will become the new primary

    -
  • -
  • -

    change the labels on the replica to be those of the primary

    -
  • -
  • -

    start watching the new primary in case that falls over next

    -
  • -
  • -

    look for replicas that have the metadata label value of replicatype=trigger to prefer -the failover to. If found, it will use the first replica with that label; if -not found, it will use the first replica it finds.

    -
  • -
-
-
-

Example of looking for the failover replica:

-
-
-
-
oc get pod -l name=pg-replica-rc-dc
-NAME                     READY     STATUS    RESTARTS   AGE
-pg-replica-rc-dc           1/1       Running   2          16m
-pg-replica-rc-dc-1-96qs8   1/1       Running   1          16m
-
-oc get pod -l replicatype=trigger
-NAME             READY     STATUS    RESTARTS   AGE
-pg-replica-rc-dc   1/1       Running   2          16m
-
-
-
-
-
-
-

crunchy-vacuum

-
-
-

Description

-
-

The crunchy-vacuum container allows you to perform a SQL VACUUM job against a PostgreSQL database container. -You specify a database to vacuum using various environment variables which are listed below. It is possible -to run different vacuum operations either manually or automatically through scheduling.

-
-
-

The crunchy-vacuum image is executed, passed in the Postgres connection parameters to the single-primary -PostgreSQL container. The type of vacuum performed is dictated by the environment variables passed into the job.

-
-
-
-

Environment Variables

-
-

The complete set of environment variables read by the crunchy-vacuum job include:

-
-
-
    -
  • -

    VAC_FULL - when set to true adds the FULL parameter to the VACUUM command

    -
  • -
  • -

    VAC_TABLE - when set, allows you to specify a single table to vacuum, when not specified, the entire database tables are vacuumed

    -
  • -
  • -

    JOB_HOST - required variable is the postgres host we connect to

    -
  • -
  • -

    PG_USER - required variable is the postgres user we connect with

    -
  • -
  • -

    PG_DATABASE - required variable is the postgres database we connect to

    -
  • -
  • -

    PG_PASSWORD - required variable is the postgres user password we connect with

    -
  • -
  • -

    PG_PORT - allows you to override the default value of 5432

    -
  • -
  • -

    VAC_ANALYZE - when set to true adds the ANALYZE parameter to the VACUUM command

    -
  • -
  • -

    VAC_VERBOSE - when set to true adds the VERBOSE parameter to the VACUUM command

    -
  • -
  • -

    VAC_FREEZE - when set to true adds the FREEZE parameter to the VACUUM command

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-
-
-

crunchy-dba

-
-
-

The crunchy-dba container implements a cron scheduler. The purpose -of the crunchy-dba container is to offer a way to perform -simple DBA tasks that occur on some form of schedule such as -backup jobs or running a vacuum on a single Postgres database container.

-
-
-

You can either run the crunchy-dba container as a single pod or include -the container within a database pod.

-
-
-

The crunchy-dba container makes use of a Service Account to perform -the startup of scheduled jobs. The Kube Job type is used to execute -the scheduled jobs with a Restart policy of Never.

-
-
-

Environment Variables

-
-

The following environment variables control the actions -of crunchy-dba:

-
-
-
    -
  • -

    OSE_PROJECT - required, the OSE project name to log into

    -
  • -
  • -

    JOB_HOST - required, the PostgreSQL container name the action will be taken against

    -
  • -
  • -

    VAC_SCHEDULE - if set, this will start a vacuum job container. The -setting value must be a valid cron expression as described below.

    -
  • -
  • -

    BACKUP_SCHEDULE - if set, this will start a backup job container. The -setting value must be a valid cron expression as described below.

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-

For a vacuum job, you are required to supply the following -environment variables:

-
-
-
    -
  • -

    JOB_HOST

    -
  • -
  • -

    PG_USER

    -
  • -
  • -

    PG_PASSWORD

    -
  • -
  • -

    PG_DATABASE - defaults to postgres when not specified

    -
  • -
  • -

    PG_PORT - defaults to 5432 when not specified

    -
  • -
  • -

    VAC_ANALYZE(optional) - defaults to true when not specified

    -
  • -
  • -

    VAC_FULL(optional) - defaults to true when not specified

    -
  • -
  • -

    VAC_VERBOSE(optional) - defaults to true when not specified

    -
  • -
  • -

    VAC_FREEZE(optional) - defaults to false when not specified

    -
  • -
  • -

    VAC_TABLE(optional) - defaults to all tables when not specified, or you can set this value to indicate a single table to vacuum

    -
  • -
-
-
-

For a backup job, you are required to supply the following -environment variables:

-
-
-
    -
  • -

    JOB_HOST

    -
  • -
  • -

    PG_USER - database user used to perform the backup

    -
  • -
  • -

    PG_PASSWORD - database user password used to perform the backup

    -
  • -
  • -

    PG_PORT - port value used when connecting for a backup to the database

    -
  • -
  • -

    BACKUP_PV_CAPACITY - a value like 1Gi is used to define the PV storage capacity

    -
  • -
  • -

    BACKUP_PV_PATH - the storage path used to build the PV

    -
  • -
  • -

    BACKUP_PV_HOST - the storage host used to build the PV

    -
  • -
  • -

    BACKUP_PVC_STORAGE - a value like 75M means to allow 75 megabytes for the PVC used -in performing the backup

    -
  • -
-
-
-
-

CRON Expression Format

-
-

A cron expression represents a set of times, using 6 space-separated fields.

-
- - ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 1. Table Fields
Field nameMandatory?Allowed valuesAllowed special characters

Seconds

Yes

0-59

* / , -

Minutes

Yes

0-59

* / , -

Hours

Yes

0-23

* / , -

Day of month

Yes

1-31

* / , - ?

Month

Yes

1-12 or JAN-DEC

* / , -

Day of week

Yes

0-6 or SUN-SAT

* / , - ?

-
- - - - - -
-
Note
-
-Month and Day-of-week field values are case insensitive. SUN'', Sun'', -and ``sun'' are equally accepted. -
-
-
-

Special Characters

-
-
Asterisk ( * )
-
-

The asterisk indicates that the cron expression will match for all values -of the field; e.g., using an asterisk in the 5th field (month) would -indicate every month.

-
-
-
-
Slash ( / )
-
-

Slashes are used to describe increments of ranges. For example 3-59/15 in -the 1st field (minutes) would indicate the 3rd minute of the hour and every -15 minutes thereafter. The form *\/…​'' is equivalent to the form -first-last/…​'', that is, an increment over the largest possible range of -the field. The form N/…​'' is accepted as meaning N-MAX/…​'', that is, -starting at N, use the increment until the end of that specific range. -It does not wrap around.

-
-
-
-
Comma ( , )
-
-

Commas are used to separate items of a list. For example, using -``MON,WED,FRI'' in the 5th field (day of week) would mean Mondays, -Wednesdays and Fridays.

-
-
-
-
Hyphen ( - )
-
-

Hyphens are used to define ranges. For example, 9-17 would indicate every -hour between 9am and 5pm inclusive.

-
-
-
-
Question mark ( ? )
-
-

Question mark may be used instead of '*' for leaving either day-of-month or -day-of-week blank.

-
-
-
-
-

Predefined schedules

-
-

You may use one of several pre-defined schedules in place of a cron expression.

-
- - ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table 2. Table Predefined Schedules
EntryDescriptionEquivalent To

@yearly (or @annually)

Run once a year, midnight, Jan. 1st

0 0 0 1 1 *

@monthly

Run once a month, midnight, first of month

0 0 0 1 * *

@weekly

Run once a week, midnight on Sunday

0 0 0 * * 0

@daily (or @midnight)

Run once a day, midnight

0 0 0 * * *

@hourly

Run once an hour, beginning of hour

0 0 * * * *

-
-
-

Intervals

-
-

You may also schedule a job to execute at fixed intervals. This is -supported by formatting the cron spec like this:

-
-
-
-
@every <duration>
-
-
-
-

where ``duration'' is a string accepted by time.ParseDuration -(http://golang.org/pkg/time/#ParseDuration).

-
-
-

For example, ``@every 1h30m10s'' would indicate a schedule that activates every -1 hour, 30 minutes, 10 seconds.

-
-
- - - - - -
-
Note
-
-The interval does not take the job runtime into account. For example, -if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes, -it will have only 2 minutes of idle time between each run. -
-
-
-
-

Time zones

-
-

All interpretation and scheduling is done in the machines local -time zone (as provided by the Go time package -(http://www.golang.org/pkg/time). Be aware that jobs scheduled during -daylight-savings leap-ahead transitions will not be run!

-
-
-
-
-
-
-

crunchy-pgbouncer

-
-
-

Crunchy pgBouncer is a lightweight connection pooler for PostgreSQL databases.

-
-
-

Environment Variables

-
-

REQUIRED ARGS

-
-
    -
  • -

    PGBOUNCER_PASSWORD - the password of the pgbouncer role in PostgreSQL. Must be also -set on the primary database.

    -
  • -
  • -

    PG_SERVICE - the hostname of the database service

    -
  • -
-
-
-
-

OPTIONAL/EXTENDED ARGS

-
-
    -
  • -

    DEFAULT_POOL_SIZE - default 20, how many server connections to allow per user/database pair.

    -
  • -
  • -

    MAX_CLIENT_CONN - default 100, maximum number of client connections allowed.

    -
  • -
  • -

    MAX_DB_CONNECTIONS - default unlimited, do not allow more than this many connections per-database.

    -
  • -
  • -

    MIN_POOL_SIZE - default 0 (disabled), adds more server connections to pool if below this number.

    -
  • -
  • -

    POOL_MODE - default session, specifies when a server connection can be reused by other clients. -Possible values: session, transaction and statement.

    -
  • -
  • -

    RESERVE_POOL_SIZE - default 0 (disabled), how many additional connections to allow to a pool.

    -
  • -
  • -

    RESERVE_POOL_TIMEOUT - default 5, if a client has not been serviced in this many seconds, -pgbouncer enables use of additional connections from reserve pool. 0 disables.

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-
-

Features

-
-

The following features are supported by the crunchy-pgbouncer container:

-
-
-
    -
  • -

    Crunchy pgBouncer uses auth_query to authenticate users. This requires only the pgbouncer -username and password in users.txt. Automatically generated from environment variables.

    -
  • -
  • -

    Mount a custom users.txt and pgbouncer.ini configurations for advanced usage.

    -
  • -
  • -

    Tune pooling parameters via environment variables.

    -
  • -
  • -

    Connect to the administration database in pgBouncer to view statistics of the target databases.

    -
  • -
-
-
-
-

Restrictions

-
-
    -
  • -

    OpenShift: If custom configurations aren’t being mounted, an emptydir volume is required -to be mounted at /pgconf.

    -
  • -
  • -

    Superusers cannot connect through the connection pooler.

    -
  • -
-
-
-
-
-
-

crunchy-backrest-restore

-
-
-

The crunchy-backrest-restore container executes the pgbackrest utility, allowing FULL and DELTA restore capability. See the pgbackrest guide for more details. https://github.com/pgbackrest/pgbackrest

-
-
-

Environment Variables

-
-

Required: - * STANZA - desired stanza to restore from. For most cases this should be set to db.

-
-
-

Optional: - * DELTA - when set to true, this will configure pgBackRest to do a delta restore. Delta - restores do not require pgdata directoy to be empty. This will only pull in differences - between pgdata and the backup. - * BACKREST_CUSTOM_OPTS - pass in custom parameters to pgBackRest for advanced use cases (such as - point in time recovery). - * CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. - Note: this mode can reveal secrets in logs.

-
-
-
-

Features

-
-

The following features are supported by the crunchy-backrest-restore container:

-
-
-
    -
  • -

    mount pgbackrest.conf config file via /pgconf volume

    -
  • -
  • -

    mount the /backrestrepo for access to pgbackrest archives

    -
  • -
-
-
-
-

Restrictions

-
-
    -
  • -

    for configuration, has to have pgbackrest.conf files mounted in /pgconf

    -
  • -
  • -

    must have valid pgbackrest archive directory mounted in /backrestrepo

    -
  • -
-
-
-
-
-
-

crunchy-pgadmin4

-
-
-

The crunchy-ppgadmin4 container executes the pgadmin4 web application.

-
-
-

The pgadmin4 project is found at the following location: -https://www.pgadmin.org/

-
-
-

pgadmin4 provides a web user interface to PostgreSQL databases. A -sample screenshot is below:

-
-
-
-pgadmin screenshot -
-
-
-

Environment Variables

-
-
    -
  • -

    PGADMIN_SETUP_EMAIL - required, set this value to the email address -used for pgAdmin4 login.

    -
  • -
  • -

    PGADMIN_SETUP_PASSWORD - required, set this value to a password used -for pgAdmin4 login. This should be a strong password.

    -
  • -
  • -

    SERVER_PORT - default is 5050, set this value to a change the port -pgAdmin4 listens on.

    -
  • -
  • -

    ENABLE_TLS - default is false, set this value to true to enable HTTPS -on the pgAdmin4 container. This requires a server.key and server.crt -to be mounted on the /certs directory.

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-

Features

-
-

The following features are supported by the crunchy-pgadmin4 container:

-
-
-
    -
  • -

    expose port (5050 by default) which is the web server port

    -
  • -
  • -

    mount a certificate and key to the /certs directory and set ENABLE_TLS to true -to activate HTTPS mode.

    -
  • -
  • -

    Set username and password for login via environment variables.

    -
  • -
-
-
-
-

Restrictions

-
-
    -
  • -

    An emptyDir, with write access, must be mounted to the /run/httpd directory in OpenShift.

    -
  • -
-
-
-
-
-
-

crunchy-pgrestore

-
-
-

The restore image provides a means of performing a restore -of a dump from pg_dump or pg_dumpall via psql or pg_restore -to a Postgres container database.

-
-
-

Dump-file Input Location

-
-

As the input files for crunchy-pgrestore, files generated by crunchy-pgdump -are retrieved in a mounted backup volume location, using the -database host name plus -backups as a sub-directory, then followed by a unique -backup directory based upon a date/timestamp. It is left to the -user to restore database dump archives in this current version -of the container.

-
-
-
-

Dependencies

-
-

The container is meant to be using NFS or a similar network file system -to retrieve database dumps to be restored via psql or pg_restore.

-
-
-
-

Environment Variables

-
-

REQUIRED ARGS

-
-
    -
  • -

    PGRESTORE_DB - Database to connect to

    -
  • -
  • -

    PGRESTORE_HOST - Hostname of the PostgreSQL database to connect to

    -
  • -
  • -

    PGRESTORE_PASS - Password of the PostgreSQL role used by the pgdump container

    -
  • -
  • -

    PGRESTORE_USER - PostgreSQL Role used by the pgdump container

    -
  • -
-
-
-
-

OPTIONAL/EXTENDED ARGS

-
-
    -
  • -

    PGDUMP_BACKUP_HOST - Hostname of the PostgreSQL server that was backed up by pgdump container. Used when restoring a backup to a new host.

    -
  • -
  • -

    PGRESTORE_BACKUP_TIMESTAMP - Timestamp of the backup to restore from. Default is empty (restores from latest backup)

    -
  • -
  • -

    PGRESTORE_CUSTOM_OPTS - Advanced options to pass into pg_restore. Default is empty

    -
  • -
  • -

    PGRESTORE_PORT - Port of the PostgreSQL database to connect to. Default is 5432

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-

Note: For a list of advanced options for configuring the PGRESTORE_CUSTOM_OPTS variable, see the official documentation:

-
- -
-
-
-
-
-

crunchy-upgrade

-
-
-

The crunchy-upgrade container contains both the 9.5/9.6 and 9.6/10 -Postgres packages in order to perform a pg_upgrade from -9.5 to 9.6 or 9.6 to 10 versions.

-
-
-

Environment Variables

-
-
    -
  • -

    OLD_DATABASE_NAME - required, refers to the database (pod) name -that we want to convert

    -
  • -
  • -

    NEW_DATABASE_NAME - required, refers to the database (pod) name -that we give to the upgraded database

    -
  • -
  • -

    OLD_VERSION - required, the Postgres version of the old database

    -
  • -
  • -

    NEW_VERSION - required, the Postgres version of the new database

    -
  • -
  • -

    PG_LOCALE - if set, the locale you want to create the database with, if -not set, the default locale is used

    -
  • -
  • -

    CHECKSUMS - if set, this value is used to enable the --data-checksums -option when initdb is executed at initialization, if not set, the -default is to not enable data checksums

    -
  • -
  • -

    XLOGDIR - if set, initdb will use the specified directory for WAL

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-
-

Features

-
-

The following features are supported by the crunchy-upgrade container:

-
-
-
    -
  • -

    supports only a pg_upgrade of the Postgres database

    -
  • -
  • -

    doesn’t alter the old database files

    -
  • -
  • -

    creates the new database directory

    -
  • -
-
-
-
-

Restrictions

-
-
    -
  • -

    does NOT support a postgis upgrade currently

    -
  • -
  • -

    all environment variables are required

    -
  • -
  • -

    supports upgrades from 9.5/9.6 to 10

    -
  • -
-
-
-
-
-
-

crunchy-sim

-
-
-

The crunchy-sim container is a simple traffic simulator for PostgreSQL.

-
-
-

Environment Variables

-
-
    -
  • -

    PGSIM_HOST - required, the PostgreSQL host address

    -
  • -
  • -

    PGSIM_PORT - required, the PostgreSQL host port

    -
  • -
  • -

    PGSIM_USERNAME - required, the PostgreSQL username

    -
  • -
  • -

    PGSIM_PASSWORD - required, the PostgreSQL password

    -
  • -
  • -

    PGSIM_DATABASE - required, the database to connect

    -
  • -
  • -

    PGSIM_INTERVAL - required, The units of the simulation interval

    -
  • -
  • -

    PGSIM_MININTERVAL - required, the minimum interval value

    -
  • -
  • -

    PGSIM_MAXINTERVAL - requited, the maximum interval value

    -
  • -
  • -

    CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. -Note: this mode can reveal secrets in logs.

    -
  • -
-
-
-

Valid values for PGSIM_INTERVAL are as follows:

-
-
-
    -
  • -

    millisecond

    -
  • -
  • -

    second

    -
  • -
  • -

    minute

    -
  • -
-
-
-
-

Features

-
-
    -
  • -

    Creates a single connection to PostgreSQL and will execute -queries over a specified interval range.

    -
  • -
  • -

    Queries are specified through a simple YAML file. Each query is a name-value -pair and can span multiple lines by utilizing scalar notation (|'' or >'') as -defined by the YAML spec.

    -
  • -
  • -

    Queries are randomly chosen for execution.

    -
  • -
-
-
-
-

Restrictions

-
-
    -
  • -

    Only one connection is created for all queries. ->>>>>>> aae224745f5caf481c142b4ccbf3332ab4f45f8e

    -
  • -
-
-
-
-
- - - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/container-specifications/index.xml b/docs/container-specifications/index.xml deleted file mode 100644 index 88559c2d8..000000000 --- a/docs/container-specifications/index.xml +++ /dev/null @@ -1,208 +0,0 @@ - - - - Container Specifications on Crunchy Data Container Suite Documentation - https://crunchydata.github.io/crunchy-containers/container-specifications/ - Recent content in Container Specifications on Crunchy Data Container Suite Documentation - Hugo -- gohugo.io - en-us - Tue, 08 May 2018 08:57:16 -0700 - - - - - - crunchy-postgres - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres/ - Thu, 24 May 2018 09:38:13 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres/ - PostgreSQL (pronounced &ldquo;post-gress-Q-L&rdquo;) is an open source, ACID compliant, relational database management system (RDBMS) developed by a worldwide team of volunteers. The crunchy-postgres container image is unmodified, open source PostgreSQL packaged and maintained by professionals. -Features The following features are supported by the crunchy-postgres container: - Kubernetes and OpenShift secrets Backup and restoration from various tools: pgbackrest, pg_basebackup and pg_dump/pg_restore. Custom mounted configuration files (see below) Async and Sync Replication Packages The crunchy-postgres Docker image contains the following packages (versions vary depending on PostgreSQL version): - - - - crunchy-postgres-gis - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres-gis/ - Thu, 24 May 2018 09:51:16 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres-gis/ - PostgreSQL (pronounced &ldquo;post-gress-Q-L&rdquo;) is an open source, ACID compliant, relational database management system (RDBMS) developed by a worldwide team of volunteers. The crunchy-postgres-gis container image is unmodified, open source PostgreSQL packaged and maintained by professionals. This image is identical to the crunchy-postgres image except it includes the open source geospatial extension PostGIS for PostgreSQL in addition to the language extension PL/R which allows for writing functions in the R statistical computing language. - - - - crunchy-backup - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backup/ - Thu, 24 May 2018 10:06:08 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backup/ - The crunchy-backup container executes a full backup against another database container using the standard pg_basebackup utility that is included with PostgreSQL. -Features The following features are supported by the crunchy-backup container: - Backup and restoration from: pg_basebackup Packages The crunchy-backup Docker image contains the following packages (versions vary depending on PostgreSQL version): - PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description BACKUP_LABEL crunchy-backup The label for the backup. - - - - crunchy-backrest-restore - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backrest-restore/ - Thu, 24 May 2018 12:06:26 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backrest-restore/ - The crunchy-backrest-restore container executes the pgBackRest utility, allowing FULL and DELTA restore capability. See the pgBackRest guide for more details. -Features The following features are supported and required by the crunchy-backrest-restore container: - Mounted pgbackrest.conf configuration file via the /pgconf volume Mounted /backrestrepo for access to pgBackRest archives Packages The crunchy-backrest-restore Docker image contains the following packages (versions vary depending on PostgreSQL version): - PostgreSQL (10.5, 9.6.10 and 9. - - - - crunchy-pgdump - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgdump/ - Thu, 24 May 2018 12:08:16 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgdump/ - The crunchy-pgdump container executes either a pg_dump or pg_dumpall database backup against another PostgreSQL database. -Packages The crunchy-pgdump Docker image contains the following packages (versions vary depending on PostgreSQL version): - PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PGDUMP_DB None Name of the database the backup is being performed on. - - - - crunchy-pgrestore - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgrestore/ - Thu, 24 May 2018 12:05:38 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgrestore/ - The restore image provides a means of performing a restore of a dump from pg_dump or pg_dumpall via psql or pg_restore to a PostgreSQL container database. -Packages The crunchy-pgrestore Docker image contains the following packages (versions vary depending on PostgreSQL version): - PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PGRESTORE_DB None Name of the database to connect to. - - - - crunchy-collect - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-collect/ - Thu, 24 May 2018 10:06:13 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-collect/ - The crunchy-collect container provides real time metrics about the PostgreSQL database via an API. These metrics are scrapped and stored by a Prometheus time-series database and are then graphed and visualized through the open source data visualizer Grafana. -The crunchy-collect container uses pgMonitor for advanced metric collection. It is required that the crunchy-postgres container has the PGMONITOR_PASSWORD environment variable to create the appropriate user (ccp_monitoring) to collect metrics. -Custom queries to collect metrics can be specified by the user. - - - - crunchy-prometheus - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-prometheus/ - Thu, 24 May 2018 10:06:21 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-prometheus/ - Prometheus is a multi-dimensional time series data model with an elastic query language. It is used in collaboration with Grafana in this metrics suite. Overall, it’s reliable, manageable, and operationally simple for efficiently storing and analyzing data for large-scale environments. It scraps metrics from exporters such as the ones utilized by the crunchy-collect container. The crunchy-prometheus container must be able to reach the crunchy-collect container in order to to scrape metrics. - - - - crunchy-grafana - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-grafana/ - Thu, 24 May 2018 10:06:17 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-grafana/ - Visual dashboards are created from the collected and stored data that crunchy-collect and crunchy-prometheus provide for the crunchy-grafana container, which hosts an open source web-based graphing dashboard called Grafana. -Grafana is a platform which can then apply the defined metrics and visualize information through various tools. It is extremely flexible with a powerful query and transformation language, producing beautiful and easily understandable graphics to analyze and monitor your data. - - - - crunchy-pgadmin4 - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgadmin4/ - Thu, 24 May 2018 12:05:42 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgadmin4/ - The crunchy-ppgadmin4 container executes the pgAdmin4 web application. -pgAdmin4 provides a web user interface to PostgreSQL databases. A sample screenshot is below: -Features The following features are supported by the crunchy-pgadmin4 container: - Expose port (5050 by default) which is the web server port. Mount a certificate and key to the /certs directory and set ENABLE_TLS to true to activate HTTPS mode. Set username and password for login via environment variables. - - - - crunchy-watch - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-watch/ - Thu, 24 May 2018 12:06:15 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-watch/ - The crunchy-watch container essentially does a health check on a primary database container and performs a failover sequence if the primary is not reached. The watch container has access to a service account that is used inside the container to issue commands to OpenShift. -In Kubrnetese 1.5, if a policy file is being used for securing down the Kubernetes cluster, you could possibly need to add a policy to allow the pg-watcher service account access to the Kubernetes API as mentioned here. - - - - crunchy-vacuum - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-vacuum/ - Thu, 24 May 2018 12:06:12 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-vacuum/ - The crunchy-vacuum container allows you to perform a SQL VACUUM job against a PostgreSQL database container. You specify a database to vacuum using various environment variables which are listed below. It is possible to run different vacuum operations either manually or automatically through scheduling. -The crunchy-vacuum image is executed, with the Postgres connection parameters passed to the single-primary PostgreSQL container. The type of vacuum performed is dictated by the environment variables passed into the job. - - - - crunchy-upgrade - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-upgrade/ - Thu, 24 May 2018 12:05:31 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-upgrade/ - The crunchy-upgrade container contains both the 9.5&frasl;9.6 and 9.6&frasl;10 PostgreSQL packages in order to perform a pg_upgrade from 9.5 to 9.6 or 9.6 to 10 versions. -Features The following features are supported by the crunchy-upgrade container: - Supports a pg_upgrade of the PostgreSQL database. Doesn&rsquo;t alter the old database files. Creates the new database directory. Restrictions Does not currently support a PostGIS upgrade. Supports upgrades from only 9. - - - - crunchy-sim - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-sim/ - Thu, 24 May 2018 12:05:28 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-sim/ - The crunchy-sim container is a simple traffic simulator for PostgreSQL. -Features Creates a single connection to PostgreSQL and will execute queries over a specified interval range. Queries are specified through a simple YAML file. Each query is a name-value pair and can span multiple lines by utilizing scalar notation (&ldquo;|&rdquo; or &ldquo;&gt;&rdquo;) as defined by the YAML spec. Queries are randomly chosen for execution. Restrictions Only one connection is created for all queries. - - - - crunchy-dba - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-dba/ - Thu, 24 May 2018 12:05:24 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-dba/ - The crunchy-dba container implements a cron scheduler. The purpose of the crunchy-dba container is to offer a way to perform simple DBA tasks that occur on some form of schedule such as backup jobs or running a vacuum on a single PostgreSQL database container. -You can either run the crunchy-dba container as a single pod or include the container within a database pod. -The crunchy-dba container makes use of a Service Account to perform the startup of scheduled jobs. - - - - crunchy-pgbouncer - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbouncer/ - Thu, 24 May 2018 12:05:03 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbouncer/ - pgBouncer is a lightweight connection pooler for PostgreSQL databases. -Features The following features are supported by the crunchy-pgbouncer container: - crunchy-pgbouncer uses auth_query to authenticate users. This requires only the pgbouncer username and password in users.txt. Automatically generated from environment variables. Mount a custom users.txt and pgbouncer.ini configurations for advanced usage. Tune pooling parameters via environment variables. Connect to the administration database in pgBouncer to view statistics of the target databases. - - - - crunchy-pgpool - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgpool/ - Thu, 24 May 2018 12:05:00 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgpool/ - The crunchy-pgpool container executes the pgPool II utility. pgPool can be used to provide a smart PostgreSQL-aware proxy to a PostgreSQL cluster, both primary and replica, so that applications only have to work with a single database connection. -PostgreSQL replicas are read-only whereas a primary is capable of receiving both read and write actions. -The default pgPool examples use a Secret to hold the set of pgPool configuration files used by the examples. - - - - crunchy-pgbadger - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbadger/ - Thu, 24 May 2018 12:04:55 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbadger/ - The crunchy-pgbadger container executes the pgBadger utility, which generates a PostgreSQL log analysis report using a small HTTP server running on the container. This log report can be accessed through the URL http://&lt;&gt;:10000/api/badgergenerate. -Features The following features are supported by the crunchy-pgbadger container: - Generate a full report by default Optional custom options for more advanced use cases (such as incremental reports) Report persistence on a volume Packages The crunchy-badger Docker image contains the following packages: - - - - \ No newline at end of file diff --git a/docs/containers.png b/docs/containers.png deleted file mode 100644 index ff128554dbc324933baa76426d4d98a6bc149310..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 218292 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%0D#v2 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

^pRiyqv5#Z{PVEdy59RIeysd+AGjgjY`; zS^3p@1XtDb>p}xr954TLDD5YWF5jgmCm;L#k}_@?h&hOURw%kgC=z`f>lCD$ZDZ3I ze%c7$du`Z}Zah-F)RnS=qtmS}XG|)GBk`_=S5#N@0=M#P8?{NDxpEqXRWE~jSMxir zcADQOW7ZLRzy1nHG7otA*B`$-z}0P@MO>e8{ zF>olWV4t_3r88Pf8{yg}0eF1W^^9x`>nKQT+?N39N!s1(*7%+{B6;S&46Y7IK6r{i zhbIFsUJ>L{?!|H4$*R|2#ry<@-$U#5)p7dT%g~`!XQBb=s*0Y759Tj-OR=G z0xi6bPvD96&g)`<4Rm2Ek1`WF2^ScPJ-*gC8g=?|pL$no_&@)W!8ZXuAL81`2j`FL zRt3$L%@2RV%wI$Iku6*N3L?Ml^YWtD|9~c>+r)@I7LxYD1=MX@_@tiht1w^Bv?mOC z=lC7y6JGF>`*y4?EzvhqIkK#m24RCRjY9^Qvr}eEw=#_kvNG z>9}XDK0PpV?b<}huJGea+_y*=wI>Z>HIo>(4h{LTScCR{GAw+iHIb74?eM zx`z?7x{)GUyru*%gOXPUpSP&MhpafN%PZ-%zNYUMPTWPn4P@*dm#7jk zSuR_?$^9JST_-Pzy

Xuibqtp(rKjt_-pYEIOU*7U8WX>Zj*?x3}=cn~Yy*)z=p& zT>#ywKlT)*wEO%&w7q9QQ`y=E$~a;J#eyIrAPNG~q=_I!QKXB2fT4~8LArF1ridca zr1v6KqzR$7h;#x3X`!R^9tbsrz+F3xj?VF%@7^DGemFC6@3q%@*YiGaU3<$}UOnPm z=9#A2J771`e4SribZMQ@wN#Ig)HfgI;%n(}cdT}8t0mgEf8e9=n-7`zC>q4waHAF# zMkPzp2$yPmg_Z7kdy6I&N6MECs==}4_qc6&P*0gBo+jMk(ThN78js_;lzfzjLN^uV z)4uO@Ys@|NF4V?$9hxtj%p)X1!WwCwZKiPALl?=K$1__vTBQdPC3&D+6Oj+J_G0jV8jwX&%$Stn> zvuA7vwZ+kz<72(#aw3){36)xX5kWzSej~bi>r!}`)rdrHoVDO3-|m69IZGpKoIw5q z(XZBJCPMI8I~INiweVT&OpcDkBVeGzz6D*H=r^D>bVpE0jB$Vdt=qMenf%pxBU^v7 zQl5-#o&th7aKXE?tioBtbi)lDV5%?$8jM33B32caKbfDBj|wgv(sHrSX7P;~f~6%4 zWTJ_)3!}V^s@{5PnoBy6sEQm7`K;ssv2fVl(&&#>vPu2OoPjS7a}z`k+U;gV$OrSA z6-$hSg%t)Hw$9>ksaqC(F$@&G&I*%C;9-NT?RDYgT5j_KFBw@fWBkYLB=kELi@QBp zS6*r{JIRC}VU5aV8dzMIY52Y2kvXLR;r35RgU`PwSMG?*qFHQCwWT$jA5?T(N3BU2 zIW)_n=#)2TbgK~wR!0}Z)(Xp;6=N@IS~eF(g+^!4(TTikD{>YYK_yu()%;d)vE=9o zVAlWk;huT2WuzByF;CDe2~P~K|0x&1aJuH&fN1Q_2UZngyD3euVZ_|Dfr!7U^Eo0FfMc1 z%fR*4_3vB9(#d6$+iDXje`|H=@eX>WlY+t|g8;d^Kva3g%MLB}bE`9-?>6XpR9;Eu zc>Ce7zJ;6bihHa4PR?zayB`pVqQwifuu`#Nu1vR&RX6|3;KTr}C7qP-yhL^+zBUY( zlNIh@2o!uy*NM0`YbLB99NssV6_GiBaMstjiba{4IG!&;VSkIAs}Q@99KajZA;(XK z{`R7xUEsjecua0w{)6lzF9bDevBS(afA4h=tORn|F|i}*KTXo>ZQ}3kJ`ow?P>C;!3{C2}JvA$X9R7K#qohaTB){=)sy0<=V9I z=mfLdi6ik|CAiXza@-xfF4CJb(Kt5Y4anV`7?Su--?P71^9NuvHFVOyJRz1v1LV->#r(otOl^( zj!s_#oATda>sAdsz2VCQU_;Ig?@YMh8uagSCUggi?PQ4+Z*h(wLs`6zpY%)dc%mXZHn7 z+!C!7CpcJ_>FZ8qdqYO$zpG0tY^fzn73_=LPCTJ!e#E(So)8fPzPaNWWi>)H#+2l% zZl#XYFtqdi4_yY%;cD?0?06V@+Bh9o<#7T`gryh1TF7c-PFKGC;s3h-x}zGmQ(Nv1 z0%&96EOA8gtv7O0cS4}7ByWsBOPWpGJpFExA2*YjhxYI;@lT|;c;dyKRUbbaSESaK zKQ=)`>X7v%~5%XO;+~t)4cm_(3WlI^qRF{q^Rl6?87w z){Zm_fJSwrN7c5QksscD+1Q=R<%Z051XBNAzyj^aChdr%mDll6#rmxz4c`K;SElOm{zaA07r~mBXs5C@UFPNqa(=IV2}CF;0IRA`0K^47LRUxJZN`& zwa2VEkGR2WiQjR)=ylwL$7Tn za+N3`bBMX{nibm8^;`J%Byoh`wzWSRinpIB1KEC0=d7oucWa-KxK({>nx4r?kw|Ra zQudhIgV%wJnY-In{PnKW3LMbX4eBi`KAaob#p66lo0&1uJAvhxdJm|B;MTui>purK zlBpITo&}n&f6c>VY=Z=o1DvkP&u*?I6OaxJBV)>yiv;6<<5D}b1DwsJGk*pS1v?HC zcef=h_HpllV|(<#FA|2xfH@`Ro6A1Re4t`F4Vxn=J#M>$C!~&9@eI0m+Usor42`5K zd^)uk3-DS#`;IQ(VO5Iw42=6cFn{lV9w=^Tq}e0VsoFkv7gL*WzCFKD<*{>!*_&-n zk{IV|IeQv|pO#dtIDfqyxkj)%?6kMk&AOvMfE76MRJU}pLU%I{QV_te0Irs=u!pZq zyXPS|-yz+5?6Y=fPN7kf?zeWLU8C9e2B3aintKje$Lrc%8t0>F=;ahet&ek5lcg zc;MYc_pker?2@(K{e9EQkSc)qjn;Da1`w~1m5_U32(nS(4?n!QnobB1p zZAcbmL%{8w*8g>E@Uzo9lHUD{7mpYK#ij`+JR~Z1C&+5SHz664>HWuk4Agaf&{}d0 z^JHu1{m)C=A7U$aT}rnqkK!k#=EPQCYRgwJ?zX->>Wl?iU+Mhm9ciD)h8*~S=WJC4 zC~KM)vJ_r+0wfuKeF;fQ_sJF$w#1#!wmo*I;kvsO%@cM=0YSoU=aSuAKl5^Urdx3)XiAk2s*)J&ZQH@Pg=3V?L{ zVp#Cc3IaWutOD}w5*0*6eAy6=`-ZI7T<95i4Lr7+rijB_;P3ahXvXJ-nl*bgtAVM2 z5dYs(iI|2jyS{I|;=jP#6Di+V2aWLR?0M1Udf}BVIY*Ie* z8I(*TvkS7NL3>N=78r}nze5XvQ5520>q4OKdXs%*0@i5h|M6s_*{aD){qEVdV%Xeiyc{32=l{k#;>Cd{&%{>|AZFtyy#7 zgntAG>WCnlN#dTLM0>FR?QUANOpxKkjb{w3~Pc=hBE7 z16aDf_|LIrv`9DH@OW(YeQa;HZk46&wjmdgNPl+uNPLPKEV}%BebCrR5$ld{@MrP) zIk%7QwFz0dMl9y%>=|gko#KOW5s>aF1V~fJ$VidNbP!l1SZupw1$^0%v{Jho3_sYw z{aausJ2J9p!dXRabSP`?+0LhBtygaaF{bE*k1rUl5qZMK`|A*kW1p{atWb+lNkckC z_6f=nkUf8mcCw3l?A7AAK6Gd<|aVS-X(1}sqaxi*Yd%Wh_2X4!|2@bSk zi2piD-}g~0K|qTnf=W=LKEPO9YmUzKo7F2<;MR-gsL{#MF1jP}-hw}AocJUOWY2e! zW4?=;J0by;AbcX+r~kH4qV(VdQU8{fvt(bkW4ciM6?#Y&*8V4B@&>kS(L?poD-(m)W zf-JzGevblcDWARWox2G^LAHE!^dg*JGU=l92Ta6r?uR>f20Po<&?w}0H)Q3)P9mLd z-l=ax_11-Qg)=r*F6hFVwF9PL{0Y43#?^yi(o^V_u-!`4oNR5QQdolxEye*#H^8{L z6t?A!N-r8rP2gIFwrr^iD!bQgPm3wvhcD^qBF6i}9@v-Cj^hUNGdD}iir&FC`mcsx z4&)t)$TDei9WJtnDPKT3#;_81IK)92YlBt9R`<@Gw&tZq7#*W;lU>oglRpDY&>pL@ zW(`Vt%Id`{gZ6SXv4r=y$nil%Baw7;V@9X3(fp{AoC)I`-u*IRtwJXn_Lh}EfK~Bk zl*aID5S>>|>uo)6+{{%#<$P!c0(I#sn?lKgf?VzP!~2> z!MkG1S86xl?04MdC$zfm?e6oP4%6@I#pXsN2V@2+C^tqDzk<&tqGL6i&C~BPX}&T0 z=1Y-ZwO3VcwhH?^=IU@~1woO2fB5akMUnb1&F0<{M|~c9ST?dERF9b#4K{X{2UpB; z^$9gQWVF7pu$ovd^E6gWOK$^7O1dasp?G@9w2>mM(U%8pa=-GNewAZhK-}Th6VLG= zo|>BI3c7@na8nEafY!%wA&a;(wsjW>wg#<5+xWTJvIL3bim7jTep$Vk;u%6I7l)=v ze)w4MWzZQWmDaRu*vP7BU5I03$&FRfo9gmOE^-r88==~04)@Zk&@4=8E?jt$Ge=i? zRk(9iXf!SDOu6@(Ht)2A!K*VeaKp+8f|E`htUxDRp_$L^{^x)(7S}@J81@PXJ-?fj zPi*Tjv8c*Z)5>L}e}muS9O__8f+K&^>!1SA^7;3wtI;`aNs(pm!w+~*U7jcf88y@D z9N6=ZTTjC-d<`%V3EP)OEW-HO((0g*u~yWhJs29TP;9`g$JL@IUl;68iv<=S2FsiI zL#71DTMPsO`Xn63ZR|xZ+NO#lBQo)!`8?~p;;s{EI%hjWFDs{4c zjhtFEMM5S`S2Mj$bMo!JriCGt4K^%X=w)5VY}T6rR=S>WvH``?aXqSHwH=B6@iov5CKG$(+1coLXH@5wG%g;94OCn zGAPh(-T>ElG4QcFht#3Nri@!HniKEPu7z_b=kXw!aRVkomteokjlT_Smp_W90yI%F4so{bZZKXKhDzkF(1%z#bLwqh(F6vPue`w3F{rE)oO^ri+mG3Bf^3RuO5ZaxWVCzn6Q1us0od+ zSmv%P^9V1Ax9SKR!a`%0gs**BQij0+HC>;cGfiEn=VhNqGon=OiSt;rGmHycvf=A? zr+wjIel$3`SUI-#+3Gr>yHcWo6=qr~?r)IBWf0)`zOrCibl9BGJomt&(4Avoi@P-r z`+2KSWy!p7$Ba$}wo#%;+lB6%xcKT!Q9g&Y_YYm%YM;wR@+9C}j74!qLd+@1m3HK= zG7kEqihI{Kfe>4MSZX6+ijy@rW;3_0?iT1*n}fp;H1@3qR~7ee+-5APyV zy|Q&-&&HbbX5#5EYXxps8(dg3tvRO+Xg?rMO1yP=6FvuOE8Gj0QFHRuE4K*(v<`MI zpr7LDRocPbqXwLU!)F9)uLLyvE3G-tO@J$fL?=%E_ofVxiZeXi{nkbe;My~cE1+RHr91o z&7*EU&g&ni+{GPCCk^yz_KA<>*<^kW6{MJL*oRn(kRwJlX$Q2 zwJ*X%ISl0wyfu4y&_6%LOmflG%0Let6jeWFPp&*=QM946)J01lQ>ow9CsP<`A|x=& zxM7xQaAyP2Bf^t`8(x1QIp^3;)CdovK^=~(vg8yFf&XyEo=YruDDYZ?#Nz8*{MUn$ z?7Wq$!6WInZlJK%xOd)??DYvdrPu^Dsn;G5j_uUMwC`8-BG=u3jY1}V?b91%{g@0I zItJ=(D=FX$+_@NX^rD4T`O6y{+^D06_45qtvbG7mu6-_j>%A232;5HnmTbs$&nd0? zLWy^_s9A$;Aln}FmAlOo8FZzt-BEKkCbO2b@TK|sEe2O)_TzwC#yK1b;-mi%+3IsE zw>fR4-I|S437cMGJDX#{@~Pu(ao2H^F;>kzJv7W-^Bh)H__V=NTN%}iQ0NNWmq7P| z8E0cSydK+mA@Q$R7B9Q&0C;4`J$D(sKFaf)&Zf^iy-NtRzO-3b5$a@#^FGWq$BBMP zA3 zV6gG43rhb4782#wW3SdFoh0#1%FPP{#csR#F~|8!o1&GIxkdOg^FD1Y$nQrN`Rc={GkW8q>)-a1*`FI`tC z5Bm>w^SC^nPw@(1h-mZ)k^kHfAn(LAHo)DFHGwDE@hEHWTLTsNP7d^#9WS9eVQub{ zJEx{`4);jJc+1N)Y4rM$cJF@z$FIo|`tC3SQ<<^^J_W1)_>|N!<#?yj!waR;VVZi& z1VNu$0oK9CJE-u@npK~nX^Mgz0Tb=jZ9P^pb!xEz)Q606r4<-#)zvcnNWAe=(9AHo zzL;?arqx3;JBoL(q#e0X<~eo0X@#%8@$*hmvW`tg5Vg0iy*$k7gJ!4H+bT(PsPUhD04mA{Z~Y-mJyUZ8fR)98!Pi%AtZ%l`0( zZI6$@*EX;Is2tzIcw=)z*u2Ua%J63wZN9LI5dtpxF+uh%pj$FrIh6&SSc6N}JG8|CihCmk1yFXqkWX*F%1p4u9qh!@UmsB~HHS63TK zX!+VF_Jgp#hMZ!%%f4$(SgN5yQSerLB}8Dn-qys>>N(wHbl-e9F=#j2#er0gxR!E; z?JzTure2QhhVXYqLD&&0GXH{~dF9ohn*X3bsJk_vCH(_yr2!_BHJ@-&eAKng8SR;r z^NH>(s!`rqlLjHonx!4+yM8h{EpdiD{8B?e*^xKC2Zx7=TpNa{sGD(w3;c!O@OsX7 zG?xS^eTI3|J@kT4OraTGHg}0kIS9V--!jq)fU$Q!%CtrLwMJN=dCM_Vx0`J*$){e+ zjAJfPk=H?&QzX86C_BAsFE=4<=q|yU{-MEUQ-17$b~p9I8UqfwHr;!S*WLQ@{UB9g zG%U`UR(Y>{WGx0meNSfcs$pft#f%I@KgLgE!!4QG<$fAP0L(xERfK+s=)2uiX|d-i zfE>`$O^F0Y;=$#X7C)@M)+wn*$EpzWmtkvoE=Q_~(a zOMZzmf^lP;M=PpWL|s`g`o@$K28W5f!Ztic+BpJ7bco6x|JGv_5uh;EYI|qWjJygL z&?4M-Y^>Kgs?D;|G$cw4LqRtoPT`+wm{Gy004uD0YWl&Nu)d}$mzH}C6%*!WZPFIJ z2Ew@(c)`Fa#&QndR9zSd%y7Ndty_9;@4vGyU&CK|DZ`qsCjUiUcm;lO$|%oHU)5G% zYlHYGE#LiRIe${jyOmmUIYv8TH1#cU+tIY`PkeJTQ0H6DLgQ@zD;-7?YMYB{sS?*D z*Q|boKc5aJCnq<1th%ow64r<)Q>jB46P*b=1vUX^>FHMp1wOZ4LEM5S*_;|l(IfG@ zZ#lR2GHQ$BzAFOJkBkZ<9r@IFBTB8L7kLbd%2GE>nUlGlU!jc*C0r_(ca;;u@_aF@ z5+OnKE8&K4tqA_yC{+JIt}th2A+j<~Hz)sCp<7@5!ot8C(2FbKs5Uw!$l3_f6$Pzr zy=CnWnvAB*1J^_4ZDtBw*3t3-s6z9;yoK!bIl88BK}1^rNOF`>tHq*)2!HZ?=V<}8 zgu|UtK^aC1I|+`hjQzb(yDoiAmBk}Aj=8FOvE)9ds$9^OQR(lCpB(|(D*(AEkLq!P` z01OeZiF4r8iTk}_k6kxVVz|aa(p5&1uIdnWE&*3c8ASS44n`bEF3{=_+{}Y=t?IJt zssEEV9W+18=clwBg)?S-8%!tpbsludbRBK~> zz#W6tbC#i52`6lFhZ*HP(cj$$NHxxW>f>yW(DCrU?{F);gxf{?AE$)T)}48K%427$ z%0mt;w#{``EkU(SePnlMgDBxP`W7CZVUMi>=;}1Fy zl<7x>#%AJ^IGyx{re7?u8SW)TNNHGchxK{bM8t(X+jj4i)N27+UcLKm>Ve|xk)XhI z?xbIc*W2@6kRqG3c^Zo;>}j!_B&)r2rS#Us=RZp|wcZb2B8=LAZi;egg1Tj)lB_T( z?XvfTbz_fp<7QrI%b~If0&N#4VYLhn#)1--!~B0dA;cFHuju>ip<>W!klj%(<#V`? zw+d2NL7kMefZAs0W8!o)n$(vB1BT`^wNp;o()BaSB0obkR^8J@K&X|=Iw6qLWT`WBq>KZwtR&p=pvF4j*E@kgXFC?0nHQm zldQ^8qUZhzkn*Tpzy1kU^QJBdt51?wxDm(H2P(JeTkZ)G*0NWC>GV7fVK4pf{9}hE zN7#7BVS5^MW1U}?1E@uwlpN)G`$2@K&xUE9Lh1m^4|~*Z(5C-tlQ<#xy)3^ExIirI zB<1f2&7cv>h0Bky1!4H2+<4Xg8qNJOo-#>P~My2P}Rv6bgDon_x@Zv)j?X ztr7fw&sr-gAgnrqYSib~A-_v={1o7U@!w|effIx`8|4wE9e)ORy)M9M$ z5PeYmU3L2h?R;-Ip+$}!+5U75>QFet_6J#;E6| zD^GNLPKEq`kj_pM$lf;t7ymcai{Hz0Qcr~A{y)nqzaQSR3U?8B z*}f)FG`ZOxp$eJ;{2kq=TIet7fm2ppj`bwYVund1In>@cq=-Hm6S=uE4k=B>l9>gIG5yYie z({p$(Cww`j8CeJFevQ>Qq{o5_c$kMr=c-Ey1hIrYh=uJ0I9A&#a0zfE2fg)@V)mhI zs4dvm$JWp)1m~$7ekpbGh&0Ppv-N7xqk4O+7)LoJKgy6}w$4N{IFJ?8UiWv@K{&Y+ zU%FI9yZ|EHFQAXAm^iCR(*qjyo*V>qK?$h*4d{j#=KxsfT=>8E%#zj}Dr(!_3V@02 zPUm5pp$?Er7D!GHqV$QWu3z~I2k|pzj@yirkdzuADLG8P;ndLMkMc9*7t!VqMrq22 z)Vban{bEhWz!0`Po#N2*-j#JiPk;z({9mUQg^lcpXGm6q`o zzrbUfdInDSM|}z&M6X$>FL7xUr{>4rF&#+qHA*wGd8G5|)hi>hvteJpsrax42U}ge z9v&94YA$uDUdG6-Ab5HCaFk*StJT78QCWCY&SH%UUG`#4K~#k6CFZeHatqlHeDSd? zkDy->)3}VV2bE9l#&cs zoZ5Q#SiOEa*4;Hjym&ocus)(Pc7$7w?GeAIsE+Qs7Yke`j$ml{N80-VB6` z^E$gpENrjL0}rF_)vm|NX6-P}tZTB~3T|U%O~Uuh$HjUTqD?A{;UNab7giKIr|udK zz6@;{f1j`H{i@6DY(QJtk*oM|FI?oiZ?E%p<#e5mZ`=Z|-I*-weD>wHJF%zf7{cy_ ztn}UE()IAan_z4<)eIlAWeE?rbA8{$UlUwZl=ApeG}2uZ+fRkJQ|#+`!ZJF%zVx2| z5_W3q+ucq#b?rMkZ?vVOD6f0a1S`_Nta&t?hrIO=<8aNGXz8KIAwO8C=fA;1*Et{f zrEd~*sc@=Zsjr`3s6kHA#-%ieBgLr8fy?{CtpJ1bqnC?mR^;gNk=R?ens=gQ%L2m^ zUqV5LTn47g(-?HBK}Xj7F(W%++d&3Bg)(jF<2}v1uDnN2K;4im5gt5&vC1Ow7gelQ z;UjAABqXm}4ls>9>VaEw8lIK*|L8{a4L(!E%gfayH8En`U?KhX zT~od78)u)(siE+f{qlE=SMm$P92Y3S=~1yDmE!8=E(MN|wT!XSc>=zg+x_KNd=&pZK{HCYbc_3clMuQRAM&6m1c*5=fS%n9U-p z#YC^o#yhs|7W-b;gE~y|(nstF(T@XfSTG@>sfJHJL$tjR?9f6JpAmN3`_$S#`L-bKp?QaO8H;dIz-bJnxDo>LlM?!%M$ zDQi^T4hHwBG_1_cE$Shg&9rl1<)iDKugz!>vN7Z}NwpRz3jgbG-qo2pcW8{Wvvd;; zcy&ZkXA6_$jTr0^l`jol9}TLX^GV|zfCDt3eQLvCHE-~ye2)b)vdW)QmW-rtXK79P z_XhkiRd(l5_XhIqeT;fk-+i}{4b}XkHjq(#aqX@sI-!v7BcFT5#Lb~ncgZPOu5GI2 zHXr4!&tr)0m4qrkE3Z4OYLyHwm(pObELz$`;PK~hXKcshzgb~1RNC6w!BJ1p4kkQ9k&6&x7 zu7OE{QnSacN5Z9a%3ewD4nu=cTG2vX>{w~gtm1oeAJLu4nZoGgF8Tsegu(&d%M;2= zKyC{He?6g<$HK%{6!J|xVx3f~T+NhJb1hJD#qQizRV&v=P}0D)d>T@SvzlnrMurc( zw7_?ChP#5+rkDU)9?qwVw9 zW48l$hHT7>U9GfY&t$iK?7IujOv3N^9$%A6DoPxyBARk(QX8M>ywde3HOzMSⅅc zY{Q{ckVra}hKtnUVtK`~>; zEaOk(uUV34LvW+Rw6&8Mgy&ML;khTmQ;bHgIyx72M`jQ1lt)?*i4NKlwR9!B;*C>< z5KdR?x9%|K4@pM$2D^Udqj0)*IjwRW)*{#Vc>88^RRi^q{VP5lH)U=gs=i#0vj$~h zJ=+m7L9W{Zhk+zrkII}2EfirBTsU=JAWhM#sfEB2s{e_Pg~ zt8>;~t)DmBvNtV$`>4qaeuwv>7?+P?GPU*qwk*ltE&Q(L!+MQu5gdSh-jw2zMZOqoxdK)JhYSvSGL+$Ok2J|OI9&JpAB!lbZU6UB9brzYS;=tU% z>~6{WLn3f*%hMLmJFXZyU0`<3%;O1jb9}}pZ5#J3R;WLpEALGkI7+{7z-dV9xzmO0 z;SW`7_Wp4Ay@ut7NO7W5l1)Wf&dYOH*wYJxtI=$a_dIn3$b9901)<;Ln%rR*{VFHK zR~OjcIfhijo9=7F1aOW4Liw2=C|{uFrMDgl9=y1=FA*;CO^-%w2%$Qwr!o2BzkGKuElSLP$dakJHlxNNSXh zMPEw`3t90kS&Db>%3rXMw>DGAs^CC`oZ_c;h`6$$b;F_xJtW|J_SRvem{1&2Q%Arq zlP>yW>-nc|A)%ef8|tZ=AY@087xAOa-f8W0wMY!jmfb-x1eMI>F-Ds)2YQ(!!Vhwj zQbizS*gsIO>^LqE!i(2C2fV9}1pNG3c|IP&0FH_P3GIg(EE*2vm5jzYyovBHv3y~A z=8;zeD`TJ>*JNX@SFLfYIG2n^IY#T?-J>&OF7ye-t7Bo&-)6Jg51vu8BUje`Qfy>boJQ49+oIl_)1UNSrn+-YfM79F z$RYozS9kDept7t^`NAoFvjZDcmq?NG>O9pBjN^}3aNcNtM>!IoJ;<~DfKiD{ZhTGz z-+O8W*N7jeqV)wG$e_EF+j)9Ld0=!`^h8Idn9WX+>%5P%kE=La;HB_!hi?t}2*P!w zH`Khc|J)CuR-P8L6S$`o9jA2{^!S+-Yc4odBlxaAo_i4Ncl5fRqmGS+3PN)I-qK)y zaJH1zD{UH8$|ynK{=T-$0v^u1W9P}y8i=Hq^_>r5aRk6lM zo41}*J>e~;mP+~qQ*uL0m*xw<(gg^?FL&Q@GO12N`ATfCHKxes)ks|)EqjOSa(nF@X6e4A2wIlYA&_>Vkzq+rB7{9 z+ZFnkckQ4;kOSG@9E7_vk~AdF>G%MiIpu&Q+I;jhUeQkVHZ1xWxRK|Oeea5q&0wV! zJ%$p zDBzR7PpE+u0s;zHufDE3jh)XVSr@%XoVoH}5#x&ljJ29cQ6nIwxc`}(d6brr{OR+Tfxqif|tig}*3D;8PSD0X7 z@uuZmsYOnLW`{~^$$Z(>r2rAS6E&~dSzD8gn#W640*_n>=4AX!QRJ^`TeHmbDy>Ym zf^kh{6ZZbBd>D(xqjd5GJIVBF8{RZ3L?$ij6=#n9n}Hl8U4Z(@_YU!bY=beBK`}q> z%QbI%7`k4? z_O}g=zo)G0P?ar1`LBDXm&fvV!K)EvIq%+6>kzIbo6AgG{j_yK=CNJRvL1{d78jR! zwI;2ctZP!VXDoifTx@38xUhhSdj@`2fJIPZ?kNMOFh|h4NNV6{owB7>r8LkHcL)D1 zEHbE3ZFC&Uj-LVMDYF71)|us=sV&GtX)hIMRlRbo7KqObh#}vIG@}$c60gy(+or&y~zTnbYGHB|$+#m79u6hljV=mh#88!MxJ+%^t2JzNW?6|JLyYdL_zy^DNLLnue z-#s^)o;zGo=K^H8bdPhM>Xc{@;Vce|$znQnlbC#%q$WlhD0#ZcJQ0wtefF2=Rxz5x zpdXm05$M<`@SSgvq94e2PL5GBEpYDpOF@zl^6(5lwUTUoi<}L=7O%gc_qlO$iC{GLB0^obxMNV;nv5-n;~tjD>cm{yn1#W8Msk|~?o`SU3g4wix6ZcIz&{fk4hF#JH*DkAL^UlfCXBia6gy9g zEsRZu!)a!>6vN5@!3RISz%f(nHEH~cvJTD~!k0PsabxbFW2{HTM~vi+CyUf1^Hc}+?As3;-E%@j7#C6K2 zV4Pb4C$iRGt(Q177x`#HU`>+D8ZH?BR;Q}TqDM%sXE!m``FZ}rT(qmIzJ|Tw;7$X} z8mvd#m>;uqba#YhCRN|Pd>Gv!oUH){4(+0?N{EbFN2mqUhz`1)FqXKj80vC zIbln=+^EvlsK}YT_~?zqnJhbLgi#aAeB^SQVtw>E$*{h^xQF zVs-N<$lpFZ-XN!2ZR^UflCXA91nrkOl?DVpa7{CsyP<%&36_nDx)ov~M_K$J_ufR{ z@vOm=b+L1F%Chesgr=CmJ3cDHj~uLU@3mP7)KV#QCv1veqRsS64*K@ct*@wTIA^Lz zJdK+5+nP7`w{Gf#9d)Ji@_=W<#7+TXGiNVj^jBqX`A1R5Je95h{4Go8L?QtM52|khDzpJ&48%S%$FT{zC%=VDXVq$!N))=y*lEj`jY|? z8L`Sr8zR^A3E=Ysv{xO!unK-V4=iM=dz4CQZ`g5Eno zdZ`Xj^?v{;X#yQ~ng5=!u_s4A_++Itl$+O*0y3JYO{Xl0TZUg0@55XCrd;(U`5)|s z9=_nrd0#qk4)$J0_3MydhLXg4Qu{s~qT7b@hK{A zY!fTUraN#tU}76o7ZltzxSj4?Vu=gz0k1kZtGtDDH~dN}F@TyWIG}%GXV$kla(zs{ zY6^03fOStKS@-k4oNhr$;{t~d(}V6_=399w4?@Kb_t}y%BvuQAnC7x9DaljdDQA&#CGxMx&Junu(r=YIo+ zNH3DQL@I%jwZlk6{eDzlKb1Y)sL*eBPIkv*eUXU%Fk3}m;-Oa0q8=mor6WbjmV>#v zzo&Mb&&1PBwco4vHG7aOC7<47KmVI1`<8De`+YiouI^?jd!h~fO>63N)CWo_FQ0Gx zw1IzE(jqZMX4^NFh1hUL>gS^8y6;C;wmn4anYHf3imPU^=e(8bn{3kL;TLxPY{!6W zE){x?%jy!Clq18f+JX2EpNvPRGoB>#BOQ6aQAI8GuDV%6=R^<=REDWrLN2I=Mza0U z7y>$#jYuWSx4h)akFV67KEWYRttneA#&JQ~$NA(lF>b6oo7yYnw4 zB)IFy6Ygv_~5~(AT za$x9|5VG-%%>1u-Z=nqD{bb3IEhPJIj|M7pk7lF<8`Tn9RJw6vmKnf?I@*&>Fmm+G zYiiavoGE|BQwJs0iXFZYUskl(7W!}pG?YH`EZZqY!zT;YtSVxj$^xXl1aHAPnpScF ztZ4KIMI!hZm}GXX*GzlunmMr;>5s7{&~|I9n}C=rV_ zGdJje$?iS={WgKtmPD?dF)A~DTP+MHHU)r$?8dv_Z5Z6p~A<7)1_};MmVobwiM33;mnbB!>33?csT^& zrI;3+=^Kdw4)hJaA>8y9K;?95+)uLB-yWqE5PqSVqZ74#pzyV<5$LKd1tX#KcWh=+ zY}}tArFspNs)B^P(3LY1J52mnEdrH|bM;)WyqY zs|eTsg+EjTFM5zN{+jh89DUb?3t>@L9!gDWb$54%{pO!*DU+X5)OYk`|%aF{WLobK*}0*Cs+}9s*T`2ZF^vh3@D2asOc*$07Tun9mp; zTO}NQH@F$so$D@S>%X;LjEvjLm-FQVa~Eg;N-lmM95h@3->mwDIb;(N2*m7+;l{9w z6)px00LIhoUNgbtCNg+q3eK#gycRSAywip9wOT}lKFrz825MEeig?LuJXs)vsS5f* z5~ekBJH(GLs@ep6}Bm91H<5 zfELzgp3#Md2JpKv$l0~7TOiP42T5{S!;QtE!NxR`I^`guecP_UTS?8dyV)Qh{D!xDKHq73xglhvmL{mD zDPdT*Nj8ZNCf+#cjijUsLnO zfH&$IC%9eh9~c-5*S7TGb^S&$Rk-!dZz*A_8O~c61RztaviUA$jn{sq5 zXu>`YEf(!^5q3Le7{8h>$-rB+`Dhl!++_%E?E-VVrwsHdl;q))tewyNKrydn6@GGD zI9EDl%?8C?TwCQvP}M*1%@dfv;LAWrvle68fR5}p98)1v*<6V#GMp^%)~Ja70STqY zb3NJ1Ls)lVyuW!+{)B<1JDIEO4a?fke^v3s)wimWmg7palW&6h@?`!AZ8HtW>p`yh;DBxRrOJ<`E zgU+F!fvzH*6ow2pxC(eV`JmHlJD9}G^$4Xi#p#AnYQ^=~#zjxP#m<%kP zjO_otJe~rhs9#<#@ZSY8+)HqWGYEg<`NiV=B9T@{1UWjF1RvDZh2|C$VTp>XU_>&q zBTBz+8p(3%=2nD6bwWOjDir`zVmpxQV{pv;Mjx~|>dt^>&#Bz_UwwmL9H^5{6=-=>@JY3CCM4wlXwdWgOCfJ3f>1qMh!&(WDsNSNid2eLCnBG zupzu{TeiPikG*wAL5gWzX}cr~=DUG}?D;s5|7Fd|t z(Flk7aNUDrOL?a<(peM9#|wA1A583GkvpN=WtiOSY4A=$%NiY!^C$i9^|Bq7XTC@prfM~sTdo_#0TvQE}P82e1Jr$@0+-?*=Q~PcD_4Nb z0omBFpY_8TQ{)3~2rY&f21_>8b|NmzNfw^n2<2g7$}k72DrTorkM$+km^s4E~rC*IxpXO zFz9w=CdX6O=PG{VxCaGrRYxVI)cg~gb%lD=nYHso;Bz)_>E<=_JMn}(jY`*sxhk;O zuWahn=_sXE-#A+%2C~OE5Q^ZP3)|g>@Tbf{q8e?wA zi+PWRh)JKE3q=Ld^DsIXQ$&B@DsMEphD`G@>47={K4uI+@k`zKuS+v%1sY)T&QT^(j}_Ctklv+Gdn* z_3o%mpepUd?tygTz-~Gd2>Am&zUSPRD4)TWWq^@MmJ02f%@{6xO>%rs)6QJWPkva` z%?gzya|h72&DN*lzLMlM8dy98hK@5}@Bx}mT(^e)xR?(V8CS4`83D~B=YB?_rdXca zoNP0kf8SE0EX!5NwLPX(Fw9V0f`%uKm4i=}?MqhE{dg6KhQ8P5hj!}n+sUM>G($9( z^h`y>b%@=Ei2K$5b#ResQjo#uw$@gUuMkgvXqdW_r$BD}_TzS=0$~(lIth;dp^{;~ z7jjsv+s{_eKa4xv)(pXGBRF_`=PG5kY$a`cBNJ{q^i3X487837S#)>|+2dfw@Gb&rrMrYmWi z;XFR4QA<8DVaZqHJqI9Sfu5{Te`)s#E9l6!`__86Py>)J^GCUx{xZoSG|^$hm~+Mro?&#y4ji?UeF!qQ!dcIx{&kz>XR=1As`Vf zZ;Qb)<*)Kc(R2>qPwJC3%YgDa!WGKX=|%N}sV7uFP_NnZuSFnkJ{M5VA($r>OA($GQez0->aUYC! z@H^WsAHO+`<{hHW!)P`WSTIdp0@P>1YIu~ojPOMcc=(b{7G~umJzqmu?-a5^(Qw?@ z`1%qaC4;Z>Xnr3`1d~p+d|trcLtE}A!Gk@%4Vx?py*64=dDT zapzQxyN7KD$03^5g*p1jtRCHSvCM`aj_N8$=zBl3QR$E(Bn-luztbN{=ROmy4Hg8SW~1Lk13cuc^VE9adZPtU$ZWa}Qh%b8Y7D4mSYpU` zZr@obEX05t=(d|uP{_@+cm|a1125cNjVfG5g6m}a+F|Fd=jQPTEN|~hCL|>vi9QY5 z+sk9nw&xb}Pa|?uk5Kh3ub~PUxT}aueP1CLv(B(W&z{+@g$kW*8@b+~EJLS6#x} z_zH4=&ka6+1dI8lviD7Suc#|4ycQ&5dTmC=gCCCVu3|{cDsSrU3UbOgi-@Kp7iziH zf0}RycpYhD5lLj16w0nJB=iBZySUGvLzWX_q}p{5#l+;aNI6yGslUoXFO*#JN$i8z z$5K5*+8|%i&%;zF9|6m*Q)&bzY!c(32F#{%-a9(<^oUb4ZW5eCUmA}5YoD+I-FGMi+BOO|F$=B1Nqr7Olkt@T0zh*|??yRRe zHd#*Meh{CwlLwEL(zu<;&pokIts_0PEzxzHxm?|Hcn{=c)(-#~5_>E;&`At@_h`bSpf#2{AD@5W9ra)0%e$iGSwMZhnF(|N&@H=s@h2A2AJUc#7}Jj%cVnO+{yaePj(9I7%V3{w-Ma?A<7?ih5E3}TAx5!^(c6N z{oC8zYt*=!{q@YK%c!+pHW&HN!x zg!x?SM9)|>_Ky&WZwln0T;#&@`RO~VbMLO18u;4K26i6|ESY6rdI23e0|17V=Db1_ zd|de8KJYCi?~S;&Oo<0=5^FQW={={|t%bnmJ$?YsvX`R{jU+iQq&x)>GBNbk19a>Z z-8}3o?RcQ|&rp0aKp@Su=)NhI&-IZF7di|nw|n7dtJI)~uF(@0+F8ku(`ICFvEDYM zd1iOASf0|fovEZcVQJPK{+KWh3eG(wy9L(1)AKpTt8-wQNzC{~KCjhlrM z0KeJ*Ir%3*bjoMzg7tAo5G{!VIVEp-3BIP_5n-RLd3$G62Vdch6(ib4ksz5ZAVgHgW^hX91 z%^C08zc?%Cgp-nheAUgOfe!`G-_$qU@$P!rTkm%}pIUVV%q!vPDsM<7gZfHFGa8;Y@ktu^oPhZh?bj5sfNq5v#5j^>)2aIPcO9m~^mY&XNYe&n{Sya=0MiqO+&^Nxgv?lJSGbt}e!b_1fa z(*PYBxcbJ$r;RJ#m7*+V+M?h}O3JaG@`33ejjCy?fBi#}F0O3|Rh{8aC;q|2m+dw` zI}|Gize?S-?c@2Qaw~QX;LG>{f&yQD9}}QDNBbM_0R(~gRnK`!Edj@Ft*+j!Tp275 z0a^8aOzQ3U0flS2x!@E$R&&O%1^jF?MG}{jslv63nkq^^ALfxw)38@WZ_Y z4wt#xB%$2V3#cm*?Hu{w>|+clUKlC}-(hGdzB97&wT(E3T5&B3P%X6izQjU|q7%|L zmFJZ$6Vd8_cgtq`Ks^aqf7=?E7R`|SN`IZus{^-ewSk_$e>cx1mq7znl&qes5dq|M zOpq6Wq(jt{u7N8op}6$$>S%-zbpz9;!+1bM8vrjCj36AkqwH4hTK96wwE$#BU3&Zu z>tec^`>PG(97b!!NG-1 z%jdY6BDy|wfmJ?9hjty6f?vIy0}tx{xz|h)Hrs~#bMy$%wJwFe9_r2phJT_@mNydJ z3^JiDSzcNVwOgBm3r>612P3b7?<`>)=V4`Ku+c=I6~rEi(3nlbTJ_F78#&5wd)P0( zF&LaTudL-SWO}pqW3z&>m4>&bSY^4ubX8Vp;X|WOmq|X}WDhi8@JdPvtF|YKjOtvq zFj>c7f7peyW1*4WN7$J7jQVR4=PoDrqsr6d$|m|MOe%Ba$7y=^;xoxL;3=blGaUaj z+~Z#7hf|kX(>?ZlbclS-lzxh~&z7*W$qhQ7vcOP=Tx~9nb{Z&`U;T97nXf$s!?-+(FAWQNNL;K$aN)^r%@Nt^Q7qWV3wb1%MkZwD3j~p&S^-HEugIN8w*W4oSLC_S7oZVCuJm`8|;gD~qmmCSTg)Pt0W(;JDv)DFd z%eh1Fb|b%Qci3*|ZMM|G`?uiCKW&A!tm1(wNO2K~Fnd zu(owOxxb=SGEQ|Qz-_ZoncsTIW+OkRy7A#Q*x-Y7X#2bcX#;UAUi#5hFxA@`w5i^t zLu1_>+p7AVcF?U;t{~UmUi%?u&ka-=2YdGA!%!$ZPa_m?E}StoZQ;af=65uO_l}D_D_F#2m#_yux^u8Bl8jZ zN!sphq|>If7gScGMoMHzHQsi52=#knrL6O45n$qR0GILY4yM%Bx+zi)m{L#qw8G5L zW(W3h-=g$G(2uFJdL^*(FWdo_$)rC5oY`1U1E7sw=oOA_EQcZEJ1`)qauK*NnUuRU z5k0pfwyXy202Q+(EcPK zbL-vbdNbBRV4}U&V0?-7fum3(H(w3Qb;pS{0?|v;{;RMf2 zgS}z}p**W>JFB{$O_ogBrdYu|YE6q#CL438-g;VovMSThc6$GUlkaHPr@FG+U_i-Y z%gTgQ=57Ett9Ri#yQ#z+#UXSj41=$ZVjll*#O`Twxh{B9lmm_ukJGe zO9|*F9}sKJ6!Kv}ZdYe#L9~;erUgG|=%i10xuUX+)a8n&7kd?f<-hns14Mm3x0F2? z`m)f`E$e?$;<%*!4W&62U~CSe*h?0ZsO=Qj!J-$=%TpP>_3x*&^W@ucQ9*B;D@IBBmk8YFQYP5^PwmSEr!3qLRYi9+Xv;=9p!6(}ti|Qw(|E+P4X~$qu z{B3gXvkZTwmJepWv4MW+0RbW6d~0CnkHP>hZ@7RY!t0HOmzm;IU?BskXPbeq3lbG# zB6R2-6tL!EaUh~MY3{SF(P3fx9mXBJV^|{& zq9LGlUeJ1*@poYUP&MSgj(-RQ-^o9KM+1^j=i@xL4T1A@=8Q;x>VTwy?-!}$YMSPI zyaESm;hRNR($y0b`KxR)YsjOtxa%=vkLEm?O3QA=tW1=cY5WGN;RuNOu-h`AoEDJs zg-nzM$KaE4|GpJqcWEA})o411?E+c8nRx8@j>elXUup8 zz{S`fiB7T@hV><21YUp96h=SDR&7n*XFvRV2n#LfKK@1s0+@tRR z-uN3pCCRjH2?+Q~SO&oeOJbW-!Q_B}=4bS|w;djUK zJd^JS*ckj1IgawQodEG~2Heip+92G%?R$nV;O>xbBAuY*LDJUR=2=OJty4X{PPv)} z(o#_=RUo6PrUY=Sal>sR^BH8t_&ZPpq@)HS)Bluy$}TPgRI_kE-LaaNS=xc1v1o2J zK7O4R@?hjIZEh-EOQ(VYMu>vCv@v1pix4$&@G~v3L+dHG<-hGO~}7Ws(u85;JZ`-0%5K^cgA9DDx;l|QQk)4Eaqg&HwMY%0~cf>R^}q_f^yOHeh1kp{mWfq&t9nuhN)O(Q5lIIVgCO!rBwhniAD z;dgghOHQu(=TC(Ed2AHwGk#Hg-yCL>HdDLUf6df|Hd7{F9dL6L@X~ezlMu)`chFds zZl2_g@y0(7Xk?V?GE?md*M!ZTzAe&GKotN_GcYloaL`@?Dron~N&rRLFM~*3JP&s# zNLNSxQpOkIN3;o?HCXvlS&~_Y(L(hZ^S?H5dcsvy=I6>h2~j_DhL)BAOC9Gp6k~Pe zVQ)}CFL<5c8Gv%0Wxa7cd9Ile_$8{*8ioIYax`WCJnZ9TcnyX21R(fRQ~?^IKAPG-O58{W@b|*X{H&jVC|JZPDS1SwzX@h1V9$OA+LtTtJG>tf5FjpPyYorp=W+BB~6r){$; zl42&Mn{erCl}TJMbGswEuRnVF z2Dv3Q?gy8YJZQq!if;@=)(A1+8rMta$kR*W+xgW_rzEn?%}B^M1LyGH=Z^8GAd$Yy z&a8aDQ1ZfjOA1`=VoVG6Kp;k==b8E>Rdv9&E{F0G6Uj*6OvS1fn&5PF2%INyhgYYz zT9ZLV%kjdRYP;YdzMg8EQ9vobQ}$bU;hSC$JjWZ8(>`>8n@#mQM_+pj+_*WnA+<_8 zU0j=Y5nkhZ>sL2Pe(BNDs0LRQxiJcEbh*PN38q=+YLzJ28%5&x1(wQE1K(ektA?os zJy0WpS)p$T$oa*M;3qP;{bV-YJAn6d%|U zmEJhQpw~2qI_+zt1ACl3a6E~>M7eqJ0hD5^muGOYCtWMJMJKH>8{uH7h*fxiUkvX& z#*t##(bSHeHL3L=%&#rUZet703oSKakCSDW`WKvGzBzr>`|_*ts*l|+hZ?4b%OF~1 zg-a)gv0QEQT%6{itN2-$vAJVymi@gaaADsK5yNNmJv*A}Fi{9}XI0bak0p+PB}YXp z=3QQn&rWR2>}Zkr%&0GH_{v68+0v$(bN!T^@O<5eu0Ge)wPds#_R%?Mnf>S_jtki1 zQR%}hWI+S3F7n&Tblw^HtGpM?<@qkas(I5iYJ}6UwPMl|hfk6<5D4p>lcg`ay32V7z!*`onC=XxEEXU=GMnn*a_ z^QPjsgh4EEf~Fz4jmb8p3puHvF(8Mg^X_^7Yrs_&ZuXaxqH zwc#<8n;>cMFgu^h+1}UXT=5xEGub(3!r@`AL#Zv+e9bc7wBiZd*)W>N#xFW!qn(Sx zy*kc5YwYjw_3-Y%xL?31>thuj%NlHtcATu(kKV?*{J=^vhj*f)k;tgR9k1o8P~GNM z2kf_MJL?&AXswU7iPQ@6$45^5UFjK3j^*O!MmLOkl2reCd|OJT(+_H!>{s6D`@}pAhhL}dER1z%FFD0ise#o7C&{VxJ$}vq|9?Xgv5i(Y_0XGcx_;4 z!`V2WW3po=6*8&S63y(DRpSmWR0v5ny?tq6@Hh)B?ienY=SI1!SYFQDKAlO6rOmpX zl3Y;=9_lmG+D=>^kbIoyly|jh2>jU2F6}tT`M;arJS!}zlgs6?wpxU4r+N*4dMjBW z=@_~}vQL!3paVC!_${e^(_Q&3HRBd)vhwM2a;YE`&hNV0mAN{0 z_ufNgjbxL273m)fvS*rlbqH-W|Y_d7+0A90+_2o)%sJ2zhpSn@%z3 zTf3@9=T`Bm;g$Cq6B+PAoBQ8;^>p`m<;0xbl;mu4$nr#|3-Bz9Q!MqSQ7NS1n!5{> zm({}66WGe_1$xY-Chxv-*|E77J(p@`%E=Y;b!s>%vsJ12mYuV|MJjJNUJzbWyz>kg zLVNhb?+H5CM=a*Wk6Eb-uP2Q$&K&G9mz-;lg?E3g8N`Hv=VVO*f-lUtU z{%y}}6aQrXg)k)cQ*Mfjpzq==<6aauNnCt1YZO)XZo*+y(hAmPNE~k<+J;HK$6h~G z{98-&EP0ENWIwqk17UdMk3xb&W=TTB`2uP3C458X3&FPLNFfQlbgcJ7cBY6XD^ji{ zaUlzTgA$As-pR5YV6q2MEIh-WRq zGT&+}NN{cD(dS3(gRYH1}B?MrL91$hLH`+$|5w$E!)k&-AOqtBoCej$f|4%st|er8}BET-duQYP+`I z^1Ed3ancQ!>4ng))v*`B*(p1c(ZRpC0PP@3o^IZ1pTLjd{01XMC8f)WGHgycQvT4| zYN6GY{Sbv~7vXGIcjdNE(nvN?#XkLS48cCV$*9!Ps4t<|M!9&ux;Y^mJI@6UD(86$ z4g-T!sJEirypWZW<7m>3bthWthg&|*b6oYa(=~T$eZ@<`P$gUP#-vJ@OO=X>8`m>j zCu%6T#*t(3;$B+q=2&w}=%ffwZW}o<=G`xKv(^WSSt{|sM>@*nR73Ic-i_oWCvVJ7 z7*vgqOu3c@1hAfkRaHsKk$M{A%cpvJk^_?DzU_m2z5=Eru{#}9Lll+r>FQrFr$dMy z%FsQ?xjD7UkSa!pt}??D08h(8eUmrP<}{hd3^_aq4P-Y^Pp%z95HWfVuqzHXCc)Fi zmMB(J_KnhyQm7zdoJVKtw^UTJ4iAquE%g_Ve=2zl`i{>;lrq~+p5b*eI}S=j)#aRm z161>uahjBgC`qCAc0SAqHpVkyALK1~*_D9wl({;vmW-`76t3K!;wC%1o0cA?wmU(`>sU*=$+pze2S@*sMsQ-td-rG%HV*6cNOO6^NJ%Lu2@m}w zEn2D(zjJ+V_6X$3h4eAQ0l;^C@-R_wWgWuGIh4iUsc&c8QUZ^*J@8GkFnLL&v_>~_ zvRU%#TF83=eM?7hPka8uugSBoP0KH|myStoVq_{NA6~_Kb+Jg^@vi1i&(3=in7U}*PbOjGsnB(WY8nGj?FbcIU+t<3C^LE zxy&tRV#@DndTCVojE+g^&F^!MiaSCbL=_9?FV4M|PsE=3_T{%c6jy>+5Y5;!9xxgL zg=MdPpK(KE>vZFBbAlVqf4wVf| zzyEh>V6dh}&lQ*eTA_g|m5^9jX|B*To~+?}=FnZp^Lf_rguY(PbS8s)%xqb$XVO(f zUH^}z#qc$Hr);UPSw(pP-IRvcrj*sD=+-=EO)r~8XeQ=Oy|d7o*>I`N!t|G}s*=MF zmu|+!SDQ@FpJWezDC1FOM0q*Sc4&i~she5lGy6(78L#LvX|d^7+*NF23B5vUubCe9 zv0nW$$5=!=;jzxQ*wxp=!%?!@l)~6~wc7WMYlTu(X=eLSzq=dsTfRsd?5htlBk31D z%xiHO?c~q%;9SZbP~R4h2e&_s#CYejF-5pcIe5rN#aq%U2YY+CArMWCy28)El^d@y zgH2?(DUJfKi~sM`WqhS6`#^E<)0p{!rJAP$pX??FBk$@)5CEeupWT98o-@;_?&Q?V zMV#x;HRtev<+=^45fyAY`Tb0r_f(9J(o+=xjD#&4H;pw^<#W3Rt$2R|H zE8B*-KXzhmsb(0z6NA3Z2o8GnQnIZ)t2;KR+IFY2Vzq7ZW#$(v<04aWzM0$~p-Ya& zXi`mR@GOG_O2!A>lt6jX3ca$j&laijzS=(A&_Mw3Px3G}W9a+gmctC531eRQZ-n*;9SU9x-0KRqUe7tCv4-I%32xcS zSZ;QVCW@`c79C8_CJ?G3Q`+>R72)XE^B#GFLf0I#@wxjSW==KDTnVn`UO)UloFqHN z1Md%1B^$lyC@H!B=E~V2QJ#c~uN0B-h#%RTp?efv9Uof-<#|~ywUf3s94>{+PMOTT z*01)JE%c2qFWP*DkaftC``8aGR1f=#SRMH;iT5Ypr&-0gyy0>IlI%u$ab*-59LUlR z6M&B=wR4J&=XU-R8Uz3h1{yS^JbDHJG^GCq4UvVFrO?jKV&eVgq5F6fj-+`nA%lL- zZRgDthmI!NPq-XBE$ZWoO<_)tbFjwAmTBJAxRw;1{g^INY2WyK_;PWMajp1}jGi)O zw)VT*Q{>&H*+C9d{{86SwPVJXZsI-o8G_UALEu-?OteFDmnw z8F~YE0v9GB(eHW{{bJqwLK*??b8`-xh=SeCAU!76wR4innIPjK9hescA|_0S76EaMT_5UiWRTWl zJoPmILSJ83pXAYbwj_&c@>;eXL=6^Y;?n6?{9G;t&iZI{DI~o$pi_+1O|XD6SQmiw3A*U|Xz zEm#@QT5$iHGWgSPt)Xi{O28aJxjT3IntCDrC{u)I6O|tFWLz7h5bU1*jqL0ukbY{Y zMOsQ{#_O#Ys25AM!kz}f_>gUoma6{%a&O&x|Gt*A0SAN2gtw3TJ8V}`G^msPKp%%pEC>vAyPajQS*zn`M-@((x)e8 zgL@!*?10+f|E|Fd%+p`Co8HpSSjoVHTu)Z&ofIf&s z`UeE`imu6nBT8`~|ES84`ZwQ#mhJqdO0ZNO0R0Ppf&Ll6SAPq&?B*xX=!|ei5X!vn zn*V=77!VCw`W@s&1Uvp6+DfT(f0uh&!uMB@ZHM&TRusEW2=uA_e;cK#IUw6a&A-dz zf9di+DX9OlAV}O(5H#85z=Q0-u0pa)SXl_oU6sxEH1>_0^dPS^zwA+?nnhpyU+>HI zh$|r7N((aQOg$}HL6DxB;9xoNDx`L9=ym0+DoaS-@T?h@Tfd|azQb$6)x*9f;SHUa z#@#SB{ywOYSY7h28T)A_;&gMZw6tf>4oA%S|83Xcgq0ic_Gw5;Rrf7ISMoM7@~tMd zj5t8A(G zN4JU@O>Kfk{OY1Eey8CNIy8MQh|!ygpVgC`8UQvxxBO0>=)dg6-?pO`6j4xD(Xm!$ z^P7^}LDE1$*^InV5yA93mkQafua0a!(Ie-%g1XpZSuap^Wt2cU7AZY4&vP4eI-28b z%EAi8>9Ik-U$~*a?`G^`VP1~(4l9%t`ai2d2T+gF;Du_f>Q6V9dhMM{D|?YH)n5N35Ok=lglUNFH#P#Y{EE$d+E-Qkk%XFHm|vj=jw zEFp7j_Git_2|!3d{hSI&w9!Y?avq>&sS1ZS7Rg(suQh+;T|=AN!`GDSpwtEnbC=xO ze27%Y0>_hQ-j5A_aJc^p5`6QbTM>&OXTz~~r*s{5nos1~evp)<@7N%(hgH!^1t+->+ zfFsK*OvwZP>JD`THF_W1qvye!j4)5@45Vi}L>&oEex{DDNd^NB+;CWHTB|{k*r8q& zdUMLgXf0~=wY*d3Sh+C5NF#oPo9j*39Uj-YZ@%@_y7=aD%R?;*qlI}p-njL-QP<|H zWYjQ=tBhwRwo+paxJT)24N0=X9tD23zpSV@xP_5cc()7_g$AaBQzu~{tIK$imPnwL zY0)a6Fq`q;*?5zkZYTvMV%8D^YO7WQ+l$?LjOkDMAWP-m_GyBO{fBsP$l|`;LDb=| zCB?!UnXc3M{CV+rh*O^(EU9T{cap0qJHZnb22CDocsi#hN5hRk}3 zIu_Y`(!>r62X?(Z*YsK`Fz~eSCFOu?cl4ZZ>oc)lyQizb#ENkWJ{S-b6kr~ZOsQYC zMlU?66cM#`pIP;Wj)sqNM2J?3dd*~4N%3>#OT^1{hWWL9=_q($v+RrJ3vUg2K&mZF zwNa3+ptpL_f@Sz)uZT6mb!)we%Of_r@6P#{9c2;6@(rQW68(R~G)v0bmTYIH&r~uHi*{8z(4|zVQ*~dY4){vwrlB=_7J6Ksb>CmRYSGno z-Ll(tWg>fOM*^BVSbpG-z09u-1>O;^`m+5))vOFAZE?GW3zx46D|2t+I(tR&dOcmI za~|>0v)TDGK1n$uzLzWf&)qrh+pgo{@FB%ZLGJ>R5nK=Wk_?PGL^USsAZnpO@gJxA zn-9wn%joFPD`nP5h||Po0SX*EV&sOtN?-0h)16Sg<#PP=bEthywp>2p3iujyurMx{d1s7%jhOAh{3-87RWPR$}iGwq=G10Pxw zbqn5K+1OzG!-oHS-CVcST(T|up=45xvw9HGFO!H5GvQb4X41TTTg%XDE8bFLIWj0# z=e(2Kt!0Yl2=`8H3VOMsPnS1E2! zf6Cr+bjc=#t$7KZer{zH<~ACU&VJ{j>s%1QSK6BA4Tf)QkQevyG z7nhH}Vn5jI&LYl#O3Pe!nUf>$#gnRAoLt+LIjc>k*BO}IlNZ#7>O}H64XcOB_N5zX zWt+*$%$DgXH_0i>mU(Y+K~I55=W&ao9dQ{#{C> zKXyfUaXj!KO6Uk)`h=tEMSCqS!D|WIT*YH{0?`-Z)-~iW$qtLIi8t*{UzSxq7;Q7H z9JSYS?d1UvLOTQO7N=%$VnWm>9h|Dv6(VQqu|np%)B&x85yiCgLlLHDIu4fc&(UA- zUJ7PD7|_IZfh9OtQ*HWNe!(Zh{KqRsB65-}(At*sx83~j6i%WKpEr>iVdOuaeyc#N z{AGH(=5S8$RQ?6lK$!~v)N>y8-NkBkJyZhlz#xze7u`CY=SlE?oNmZ0v*YD1eLEJ< zEt$hOCTn8ePcjDOhf{5HYpD*ii=isT*k=b$pVL{^Gj#2SR@mUx97)nNbYX+QEo|UG z%M(3-uAr9O$d@knKEf9)t6kMuT3<2p8@V&8>J-6@SPtHIKL%w{4`5l^d(t6xwn<*+ z=406cmzBxSwraP(PX@%S9!k!VUe2IVp8)wrq> z`p&Owr$71&B4y0Z6b^hk$dfzexnnI_(C0@*Hp(3TI&I53($eyod3Mg%Yfoq)D^J?XLwhnu6Q3peyq~gW7EHRg;|Kwf8(Up^fE$3&|wa+(WxZG zD3r{bgQ(f0dKCe<+=5p~V#*JLJ%}5c8VT=_-294J~DscX;1$}s}PE_`xG0$h?vYKpMGjPzphJGhc;dmBQE7DLq50W|MJd7!_@kg%@ z$JXN>wvmz-)e|IlaP?d+IwYaz`EpON)m3`iH^A$aPs~`MjzMZCG&jBy4lI8w7*5&Z zI!uR7>^8WGj?txq6^5T=v^u74N+I~7b2K+)S{fUP2VaI85jYV7Eix4s?`O4h4BdCX$;0cRw6O3#=MWxe?(}*cVd%D$+SB41Q z07_}h`7Pj%!1#;<<73VMsyf+oMP(_0!vH3(!XQr_9UX#yucfEKRWXnJf^FI zBsQp9ce}keQanmp8Xfjkq`UUh6M)09rpN}f| zBK49;I?u^ONZiVY>!A zy6BD@oAnt)EM#U6dTCL&tgE3CLgfP|;FeJuLIdYVFi!KRrW?;!_uLhLFFAlaaDFJ& z^`yP_R-%+uikys$phJ5`?KSPc*ll$?baka-5B?Yg5CsWk4 zIx9R+RC$?`S7ck^-cPVwll;YF<)zz^ONx8FJK*Ns+fGkL)s|IU==bhHyc65}R_mZ! z=X&GZz2=*57*J_E;oSfD+N!#o8*e8+Ds~XXH6oiv*P3d|-xH>Wcw__0RS`Gyi=>P0 ztsoNQJf20r;5c{u;j6ovZ+eU0Bv1CMUYR9U-8soYL9s*&bp(aB$iS6l&4K-tXp1c0 zh^+jmupBAEJ3FxN=@SifN8Ip@nC_3r%Pm{KMbPcH_I<4}9M~)f^h9&V{5~tWT%q~f zgb*)+f)$z=EV6A$A|HKz)M*;a%nY|IT$^l(ZeNF&E=c*@CPybVz!RTfr@VCmYqB2# z6^PO&@ah#in%~qj_{I6dG(&v_N|%d~1tPYw0t{qT6_10~no+M8-^O!*IADT-tM(qz zZ9kmSjn8}dT7?Jq2)9|`+V2-mS)n8DRvw#7Tdsn|M6R`<(Ef3fGVhB;&Sz+x;MyiV zvQQJL9JqCaOCD&~0}QCT8={AN<-D?w+i3?KvdWUll6avXAFYtmD*PIG$ooEUZ~Kmb zgSwGZ`L^oC3^Pabp8qn-^S`%!w#o6A*dEX0|9lhJpOmq90q-Kw*%Yk?EJVO&7ZrRId6h%_2;iCh4}ojZ9;gn<$Y>XI_;uM{!0a?b-MAM1crrOqxM*Zy)C7 z5b8d$a_647Kv;aGTQ0Rls$IC}fI&O7br>!xnjSxPm3z_!dDUoVd9+ zyJ6KDD6&b8D#>$|#zJ3J-mxJNj!9b+^+`kc!RJRAECe2F6YhvCrX(#d4@nyuA?{=v z3AK(@pC0KUDxTokHzv7blFkOrqS101zJe7{>gqXmPcLUY(mxpk=y*mJSj(tzcR-R` z3YPb01c#MI*(R&0b)=TrYOk0um0#!^ze#eoWmCP<&70HpG5f3d66=Xq3TvEv2US$m zAG=+syq0jxB-m(wYKqrbSM%Za$Ybw*lucI`JTI_*_~Z2SK(vJ!A@O3HeJ_`QPWch$ zC`pqqoTXPO-$E9cPez?j!$gk{UD=AHZw5e3(Y@m7bK=S8r2gGGvfbT%>oIj z^=dRAOtD|xlM_NdKXT&~>;fBCdLr8^h5iS8CpRuSM457j#+P_*gfAYaz<#KdvGOD%VS^Y%Q- zH$*sRPO(XHhdUmxYKfH;>|r`%u(;z zdEtkI^lsk&;(ArlZ z_jUTWam1R`%708v7nL;A)Na9}XMfapXpdM3>@kW;i~aaqqv>O?(g){ZE`=PJWvZs% zJEH?HInEjMNYpK*NSre|CL}P^Z?qx{D9Kr#ZSKX0N1C94!_1jHzWQDLs+%&-S}=hX zWy|_WF?F|dHpkOpU&hykpZm)vAgdg%h;4!rt@>GqXY2gGcfVpR(7&=*@@?XG+fi&T zg#iWwN(0o%f)naK&^e! zMR=r!mJU2dJ0MZ-I1p9tmIHsBd!>6SG&a8>f=B6E*4xJ zF_Odnn1^}HffcHDAw3srK0=2e`@U~ct#r;o@ z)(9A_n1YW~-0N2@zrqRNlGJc;!3M+642Noh*>@p3lFPa|Vb(OXJy!)h=pnVZhQgY{H zm{W-We@^7BbC>!eK0dcUnfkHFz^s*Hlq`H&d;;9uz~R3KcR1hc^l;9=${aik)toqvzg48h!t6 z)%actuy;RvjI8?dL4HA5pX-l*k)Z!^#`Fv&mq?=>bzT*W2cjA_AwJ|G%u7Gq?Vmn< zATRTLRNDPyu^T*QMH=$^>akv1sT5gb%d^-*m6PASQu&5>bNGCQWlqPl{TCqdVn^S% zdzCH?V}1h()1O6$CUj~2@@>FN%kKYee~25`tVe;VN&Srq*M7;1c~6rBf5H*Gyqquk zOQbHsJ;9?dkmHKL`N(Fx%ll8IK-4Q2!H-n$uUs2nMO z6NA80OBsLTV`HZ{2w|r!smy0U_HC%>-<^|fz6EKC#1!^(-bFg@C68OfVzmZGIXN_~bu_MP z;;g?%z%PX*#s$^mtmemE3#PwG9pIMcuT!-B0A)tcG>H~u5JMh32uRN!FN)@Z3UVAt zjP2fcn@{#=jMH37L5Ts=ytq#y8}p z-M=8q=U}h(buNLWAX6G8l=aW7cm;b|>spkH#4M`rg?W7cEcB4P3SU7;*j1P3w>2*Y8-IxRg)( zLgtC|L*hmOBGK=d8E&7YeIYvkkhpe$NbEc1gSP{J{UCbr?33TM0Du0+23kX)r&WaR z8`hRa+z=bSl)UgDX8P=)vxeNLv&O*^o+#_@;jP`R`QEJd5sZq0%XKAe zh6OpGUeX3p``(bv$uX8(BGKYy{Kl#)_JSengGi5ODpN_zXCvhkU%X)iA$5Q2y0rSp z(%Dy4)xxL^4#t+Pf`E4Z;IGCUXGA;{Q`$$qU37|VA~i`KUfz5(lkM~h)6Wx)sgb)_ zex821FLK|qeaoH=ec~R(hxI2_1-WL_@?0~QnjjpHd0$JL!{mlnm(T9UxXTA&*WnXi zZByHBX3Fo&)d{@k)@1#~D0$=w^iIw&|4yk(Ue$V|*+!Sl_bIFy_NsL0Hek-n*Y6c? zEfv}$sNmz%$W8mi7h8mH;nTgQN|W_koa9clwNF=0W7<60Lc%@TR>D0Rbv~*4=z>qV zfWV-7{qnG?+z?+6_|&dHN~f_$5O4{Zu8muGwPRFZibDEULPaARW0niSCmFBX3d1tA z?0(o9Ns}I>Exq6qJ{ri&U;F=2b{$YrB}?0YiXw`DqLM_CWC0O@0Te+pC{eNsh)9y0 zgNTtZxs?Lui4A1zAj#$A7pM{vhjySl*k}F#1QO5ry9ps#y58>?OZKyK>Fvgklnmo zRTei{VK3a|JT$;E>}nsjO^AyN9a5wi({P}94(_yc;c6h91di}3!+&vv=n?U?*AL;C z)6)_x+NFKovW?7UtiT_C*Ugj7k9sv}=Fc^WJEB(<^$0vISP4FVnF82wn|hZ-5U?C* zxLwme4j{}IaO2z`fs`b!+TJK;1<~05kq}&1=3#s{a=|hJcch|_#t1xzf=|}@47j-N zP06E540z0e@ed<7Ti{+EoCHaS&k{ZfzYuvMWGBIM3_ok)nMCFtFv>C7=UNS&prL#- zUTK^p)Lz(>+W^7|^3vE=ch#FX27T8uvJ-1xE-C5U=idrhk#u9L<=p>M zwgc{Avg3`UA)Y6gozrdJ%S!PjP2N1cyu>P#*W24KTz0Xw;PS6gm6-Kb71wzX zR}Hj%hLv2~TlFT>hnt!;yfKEK6;r+GFpzHKMlD3f06nphNWa)@Bbgma+;M2yO+5CbrzgP)C~&!0lk~vy8#oil^kP(YMe% zB3E)fJ?|RodEedJRn>2?fi@Q>fIo9BD7-gi{Up5Py7WXg`57R|kWJGwG1W_8i!KFE zSiLg?J2wBBJ#2GQmZf_8O{Kb*^bk2ih)fNePGO4tQ2#~D7*IJcnF8+gCy}iEv6C;X z_6)=3)sD-IFLh1KCtF*&`@J+E^8t6J3!4-RLN6y|=X;oCdgK>qN|2W{zFS;Mo{{?> z7k`y}Ky#`xYx~6D>xpREk_CA%KUCvgW|>cQ0v%7zG~Rusz%9iZ`N7K)GO^IVcIVcV zfk90oF&t)j-Yv{w`pL+nR4^TwNI%F#zPsBX&|xDf#CLng8eGpMccu}txl-WQ{4RG4 zE4{l5ENI>3J!?xUr1tCSl>Yla?vT5n0A3RQA^ft2)CJCz%N@^vRVFRE?4d8w@2G#m zxkP?+{`zKRhBD+(BHa6AS4vYSh#4s56Vzo}U zd+We8ccSx$GtQPDu_r>c_SigiNh06~wjK;YKCehB z^CILx7Q_0~P}pwBKp7uE!ch?PS|4O8^K_Owx=?SA-7P6k)AQMbqI$K}aM1F5N%Ow| z$uO=R=Wr35>56^_#!zNxzKKYh*w4|Mz@Fz{>0!~#rkRA`Q+Gd~_SS-lw9Y#a%~&HJ zY7YS*^DBn>AMk2elkm|9kp*^tDL@B1ap4Q$deiY+K$kvdD7P3Q(+OAEUqTPwZMfZN z@qp`y>P;?iIX#8c?8(0ma^$<$`sFLM+-{B!Id0ZB;A46tzjZsNzTWCJh=UYwVkt_5+&#Wy&p?CE+3q zAU*NJQ?7V(GXGhdr@i^)y}{R}WKjHDsr zR}M4_osaR>DN@Bh?0p3Z57@Rwi}x@)Ej-gf<~Bf{}7-Cp4_yB0DJ}*TiJ^=x6t`0fQ&ml?-xT4(klfA zT#v8;C(N0PPD*etirRDC%sdIs;qKqZS6-CcfQs7#&%izKe+gz|)D|m&W;@YWT(TFw z)(HGhsM+u^uPU;N6&HKS?`Kn(jZFyjlj_Z6g`qx*5D?v)EDieHmn|V~~ z;hA(=O2dZvBnCJ@mj4GBmVlwZ&+vINL>w*VClo&ITA-aKg>>APU#&~+0RWSQ<7?t` z7|EUwgkmTaNt5(f4~|_2mqrbFx$eXrovRlDshvGfWNA}9kCT>`24M&XYCTRh1MICy zuictcll;~q4k~!2-WHeUgI-}qUed1Qmf(=UCu`egosAaxAJb*snIP04oIm-j#10PV z0A0Klls)3T^Vb!`WFNsOdLE`0JHB+^keGT4giwVoJRsl+HwMK<_$T5FnFe!=8VtkE zSnEhJ-hP?RQw zN|==;xNYaB1~AF4$|}TC-Cq+7t;$j;Lur&4w0ZVJ2~U3zd6p{ixC|l1SSo@Hg3D+x zP6{V#pbHjkqM(?6=XJDSa2{-P{haIi&fGE(D&*mN2iv8la2pz; zYZpLWOQ`rrhgu-BD5QIBFf`;M=jw5!9}WU+SpeFGt7tXI5T@j5ju3lPvM{7tEe7 zZ_tqC%vkZj4gSrIoh4B_A%x0ci^!iq5$dMmK#s<0nz76z1mi5+yIWOI*ccGCMi_4- zkvZ`cx2+^lr0|$-&n0qO;hJe|NR6vnmj6OoIT(7KT zd(_@$=j&ylRe%$29~Vd&aZR`JdBo1d&@?lA4e~|vI2kC}+F*a;K13&3bGQ^c8HS;z zBG?ng;~me4IF074drPzX!Q4PKM?_Tjb+#%bW1Kdx70ni1f<=J+P$F^w`*XvIQ2$yi z0@dxh7Wr#zP-TMWS6Q*Jc~!=RpFfbiklbPbn|~RHguFI>4jfQ(fOl_LAO5qxm8Zqr z11z60EOC$3#sa2dq4`!!XyW$07XOkWbK)@vsW*-~`mK?xqQs>NCR~+kf8OTQNIHY* zc6C;UqopOg$%Uyl;7oxlIs?(U{>6Y2BtHf~zV)JeEiVE@83mRWTqOeR$=s|=Rnd|K?Yr|V zb^bc~wlLhU%Ib0xzPz@r2`fVg{`Ox;Cpaf(h)xdSY_ zHnR=nC%j6Z#rf&wnj3|I`GrOX*dA7~Iw#+CToYZm?)E?q&t$AJMC7fys zNh8-(CCn{4$BITotp3jz71{EPg;f%B&;JE9y6 ziTN3Zgq^n(kBoN9w{Eu0>^fk`WvAl%s0o=g-RnN~if+b)`LGn}lA`V-XOo4uv}z2v$W7X~$ryYI+`aliAn<8E z4iMib44NNwv=begtBh`yg;DT5wyj@E?j~fi9xH5?{L?V8>r>GJ>mYwG*I)16w{Y8! zg3#`?gxE&uO{WRYTH*>lhk!+{5wcJMo<|#;?&@Y12X_8R$SP49*AxUX?jE*wSk!=n znBR0@>=Xb!k0L?o(zg$SQI5k6ko=xQ^6Ni=VCP$7HL&s4(aha>9SYvF+}(LB)DWNM zZv7J*4J*{4>6F?HD?7Lx74*s0Age9SpN}?}4V6$)QMKK%~&IS1B z4rh=b^vW}d(_P#ypAQGv>uM0-BA2^fy;;u(UO)KzH$dV5hO)zx0ATaYS9@E9%Vo+V zWqxS0_T^c-LQu%YC`TzZ+tk`3wyZIvHCaSdRc8Dk|1W+R$L+Ga-p*+{JGKLomy&)I z*!<%4N`YgLhn!mpvc--FBh5d1Dy4zp zw;&GW*5+Zz!?OFJMhlEM`!%?Bxn>yw&+#yq; zysr_cWqc8NpErd(sV#3oH{IPSAHdp)Nt^~%-M^(tM9B~hE9u}INm5%070k?JNI|0u z*>#cX;zC7CV1J`A0S6v%v{tqCXw*U160%Kru+jD7}uM9{MU@C2%20Va@agPAr zXixs&jr(sozqdEf?k%Go_Zq$Muh%?P9Ria{^!{A?C+THMc-?bVAp(1rm&XCzeLSMO z=@de%L66!pAL!cMMH9~hL|t9i@ZY3$;0Q=x*{j#Aye)arm`68PnYr^icu(kFcY&S& zc5ZwH!d1VMRbdn#1%a3h4Z9sd?oLth+$7jmtS~Gy_qKjM)@Cb z`r(NjvD(Wc$dk5SNW-q>&ZuyV^Yl(7I2uGPd4fwYzX(TK0c&A_Pv`)SZ2#-pKH5Ic zWc_ZQ0BW;Ve@YlFUf;{Uu=xE9XkXbX?>l8$376u5R9LtQ?tBqg8GtW-{r#OiRggRn z&W-V-7{o(q(AIw+ND)DWbDXE&s{>N0rPwWrU2uJmj}5h@WNPKnck6p+lS7Z&4%$mE zviOy9lrIQ_rA;Du)b#HWc)w%Vd+;+ax`ArM_d7PRN=2?Q_^+D*>IoVm|Ce_!?Ce_X4yheaf7 zfGe6a7KIoPARf%?y{%OTwwC6vgPRTO*R)=`!gS`7r?hoG?peiR9|ZiYscn&5O{b;csF&Ex0qks*4a z@mvL`9DaJ*{{PreAZ`#a?5$~smih^v94wOE1+Y2!05FEe0VsCJ8&bpm`<`_3+B{=g z3782;HfezAHaa`o2Cynb#&8V`f?Xv6-Cei$_0L;@#!@sZK$}6t0&E45&XjYoG;p}S z$M_0o(TGlI+;2KO;`~qYNd)|_z))8$78(^b4Ak&fBd=1!Bmt!fn3Da`{0R6b#j&w^ zb7kC0%x(xW+JGbiBHuHBzpqoke$XuSChjA_3rZK4V`wS^_pHB^tJqRZ$!3R5*9r9l3xKf09BR-L}J>N{u&{c^rt||n42ncqx8-T}Z1;Ts; z;L=nW=Pw%vEWo}H4*ZQg-}1b@V>2E`W57tkkHf1QU4cv{m3js8?)|N)4q@5CAvGq<%=@`qF_Xz_&xy zw0kJQBH##y9t8;4U&3nsHGY%5@iUzJi|v{PmnDJ@7k}V5LHdProF3L`4DGAOS6o_j z0s347^{jsu{Fuo`jils;_x-%vP5V&}jd?wq zAm{_PJS+wZxvK&<0m0k-2P2`d9++14+cjan*xJABlI&8*Pbex!~ z-MO=hI?CLmGh4~!sX9_Z&6FADv?>LD)32-9&V_yKJQ5lPerYNvG+!>!!Qr%=K~?YY zTLlYzF!Z0ICCtn?(b?E?w&$x*a}v>W)m_>R6z|FDCf(!Et>TohZh@h>vcjJce2&1K zw}n(3!QV+6tEp8g*x6&{RjfS*ray^VTU=xN5c~KzoWVJ6`TX?9x0sq9Z*cl*@oF1; zP1_?hI)PcFY=y66Xf2WEd!crYQxO*gZH{z%{Rtr+#{AwCC)*noK6Vb0FnvnrS{Dy zxI2`r_;-E!4U(w5g7gXZ@Gq_*Owm~RZYt}Lk^M>h>MYoj%LQdL{yj1x zrCz`^-d6i0qx1Gc%X$39Ay71IL=P&qo-Er3Yr^z>lzFmwUSTCI?zAoOWHO57l>gwI z#H5%2Oie^_pZ%<=1auYW)jBiL^77wmZnrcP`}O2F?Q2QD|~48rcN<-^V6v z5R`I8SxIL68FGV`778b)M`r9!PHq#w@1P>%UA5n80e+z$jI64oInvIinIkaQKKAR8 zX;1MqP9(2?J&P&_PC4Q8muPi{u%LMfjz%G`g!1;1r5gb+>w@lU*cDKc1x$CVGzrj3 z8cnkiT*A6;sJAne@M=6*77}DRuLIya3vg2a!bdfg{X|BI&l~hDxQQcN$O)FvZ z1lQ4x9c1~9O`2PjWPaHp58Ch=ClH_oP2VK{absiD^iQxk@aRUGK-4uwse5q@Hcrp| z)amycq_S)xIV?VaI_tNRaMn3og6vvP8rxaf+FF$4vWHf#%6)ayvjGwmpYP1TJRd>P0I37EwNWjJH;Hfb%t{PRL?8sDQWzEblLnHV-m_Ahl!8`tK%p=4*?} z>}*|&N(}ymH^5?lfa#l8E^tt@4QOk_2etKP$g3}fRXvP%RE6lt(q?ji|oK-^a+%j#cYl zv%ei{0Sj9yAbX{lTl=;M9scDT-yL$fw-1}et*lejmIEYd)ESrkVK~?^el)n8n1-6exDoi4j~^q?cKHTLD+qFPwd|CJ%a%I2L==7nO{&pWw!oy#t?ao6;J~=jXr- zgTM2@FSNA#T$3R*$a^H1=rWL#Or%Uks0nZH=ux%EJ}c|xYxy3`n$nzPflPIpLAV## z(++=-Sh6iflVz=_LCJ{lC6Jfs1;7E6KcztKP{Nek#f$oB>%T+AY*J|a>af|_a97C< zVTfG#7xcuTEDee-kJ50lHP&`n!k3-1z$vXn@mY_`bUJt0l3qT+z%2MNC2!YMU~s>_ zoT`Y1XBA21eV8!1D-e{YZ-5F6mv0u-j0|VX&1J(6ut!OTbv*;2l>op*jV>UYS^}BC z>(nqJsB8Ie*nn(LcT8@ab8>2oXWXU*vHib7Ak3<<(*m#nDXY#^ph9|jDOGpz8o@N; zrdD1@(P<)nppUxYy5y;qBE3gbCl@j#SU_tOrDv#PZD zpdn^1yHGf*E4k<<_Dj}C`YvTB#Z2WjD1R5=JhiM0tmuh7VkDRHcFoEQD*#0HUGH98 zP7Pyc+_Nahs}TtaZGVZYl_ay*(D=!lU7V9cyPswlD!LTHbg{h~F6|sHv7T12O*OOY zPUc7@bSzW5S&M+lDaJP_bSTV!w|$4`txv*W zOb{Yz~}h4b>vo%IDQ z6wyMu>$5)@Lc5-5XtfCCoH3KXas3jP*-@5YdZqg-JByjIG%v8EH{er5vCePnM*ze-qqiRkd!cL2c>EK;@Aqe^Jpb48~a`T;? z()^qb+f3lE_7#E)e!G_=YbC(6HeIbtVjZh2gtmBY`pU@Cbwii=MvYrjBPyllt$YSjnf`hMu+F>sMwfk0TC;3F%+b zGcXo@sm+>uB(S2a;syZS7-Y40RAWauI z+Wgt2e8`63{*7C}$SNtC+Kt+luAaBVg>^lF``xB})h#Q?azmf=WQ+1{J^W+jTa*CT zGvFt~8+v>+UJFO()THt}y^EA>^>4_%*L^YY!vuYeHcQSp!_tz9o4)a*W&zLmwT>hc zOY+FvtToYc@_O{_BlBqnLoB%@vBCC*|Kk90ViO8ML`xhS{W?L9wQouSP=zHsgmZ0E zu2e#8Q-({p4(GZ9s<|ST%5#Q`f%&*5?GAh_7SuifJZ|HH*^>CpNPofa<7F;jK;XOk zE7tK>{ZdUp?+A$qCVw)$Df-Bh@ro_|>>G&i4^C*Yl*^_YFbFdQ`$C=EGw))y~NqItM0mJ7=-P(Y{ljrpvJS zyw}Jv{n1lR+lZBqb-V3uo+=O@$&CS0V`#O>M zI^5KN60m8B+$T834Uqg#AT;ly0GuwMjei3b3p#%!6Hg${y#&FHTjid=J?#&I97%4) zKUhq33Wr)I^}z`DIsYS+42BEQJNd8po7nCTUz6cfUck0bX(?QJC@wHpFA`euBqHld zPI&0uf@`s}hY-f;-2PZMa3keQ|K5+@~0UgJ2xB;ztzL|W>z#*Mt z(JL~OMQRDFWU}*600U|Y!IW{;djZUYD=xc^;NY1rd@h(1CdK{Euc7+d&=t)p&@~vb zO2*+wv3z9{{V^D7A_Q?~6d;n(a}~GC)5H!uJ2}H8^@jeT=S!u1+DDhh$tm{dzS@_q z93$S@{>=S{I6hnck4+qGj`zgoa}TT0ms4vE%SeiP+VqtI8pdkIUR~y0;KkE~gG&ol%WaYCFu;^o+=$y*hsN*n#4Qo-(AiqFK2kPJ2`d1TE8+82I+kiJ14Ijr5<$ zins29mpVVZpJ-{0s)Ue5WojmG0u_-pV(UBiHA*OYSLN%;2yh->7l#Z<72vHNSO1pf zd387~qWjB7sE}S5v|U^gG3vA+-U4}wYV>A?p_|RAX~e06Uj(vpNtw!Pw@z5^7pC-4 z{RZm`|9umxj&)tT;Pfi-&z&K>H|_{*0>Mav+R+QSAkheoWKbUXWlG2|H=eq90s(HV z@zJZ#S#83c(|$@EWoGi*wzN&ruXIwx7m^+bYuI{6F&6n5=?hQ;RP)Ya4{U)KAg%w6 zY_?W5a7C&u#v>~g8nsZ)av1XZLPo|sHXsM6oMn6vDP{t;UN2yCceCGsDi<1R*z@l{ z07I0@opp8R)(E3SZp7*0BE`kKC9`6->V%7d6rr2F&SR-0ryZL@t>!?LZZ>WpEW(JX zb)L37P4<9`2_znsS8Hbl&g@f&0<5#M6Y&2en$Ax%m8~Y(3VpW{OsoNY46^V!0nVTT z45DK=fp@K_VFv9PKDR)=d~>OyKXhIPxCC|1IQODlG%3>%rmI$b`TH2X z{K^mbFuD9fbANf7`~f*yXphW)MoO{m(^B%OfWz26^Y6GuejrYQL+6?vk8=xm@bsto z@yl8bz#hBX3v-PRGP*qgGU5k`Mnk={UmRyi-e|z`MVGXAs50mU{*{SaO-?eQbGZBZ zUUsqD*pGsky!O>#b7uOm{7P%Cv2Ibc;4GYa)0zB2lqTCu% zrisLvixFkGJlDxK`vf@Ukr6LQ8?4D^xJrN1240{IxW8xv#Q2Nkp7tc%yf7nX<2ECq z)}DF}B)>C2r_3IO&~JIgg?GT?KCl+&*SCbp8)sI^QYwmat4WzmSgJSVc3j3m)s3TS z+=0crd+$62-bw!VBzAoF0=Z{qz*<$w^?p%Adj{A%-Z`LbY(vI%f*UB_%Ps3c`EuC^ z#_2ZX?q$E=5X&1b9Oj5=#>zDJEfOEwJmh7+QgL9K0Mh?EmfOw{{6!Fc$91we2wONk zP7{H`1E~8&81P_6;-J!vyS>!vhH=&US}C4$GNeom=bdBvTHDfpe~XFKeWM!XzvpNt zDkYxbkpf**Hpi^!F`$ba;)=n;=T`xByWHpDteCl8L<3U)VMaq4-!)h0ww;*{$k708 zlwfrbHBy!6PIK?A8&nvj3zH2GI79Jr@%n8_J7MsOjLS-WTj~qQTOA5 zXAZp+R0t(9Lkr3kjiDB=Vvy#wu>$3Lr3V+BNtt3Ot8>zF4Jz0$u$6%IPzI(jbOALb*=zKLHuU3%e{$g|UO4XZfelDnm9L4;by-S<_cvT~xEI}6^q z`n9UCCBN0RHJq1gZ_wIVNDE7VGW-9NGN+YWUolqZ>oEoLU$L+82i3zZm?Jh{nq8`I zlcK{nti%m;bu*~P5pL5QA|4x`*S|6_;U<23xV>CQrFx}%xgn6&vAWU{wLjZ_Fx!0` z_usOnV763IIb6m&ZkyJ6DErt%$&WGMogk|@qVh|hixIp1!@H^BV^b{&nN?Y`-;yQ* zg@^9uOnPsRGnN|}78?T)3k}Wl2>$QWkYOus{Vydj=4ju-&tBN5Dxr|Jg5t!YeFP zUS%-oWk3*r4eDRk>9i#U#NEw%xZcgMNj34TM^(5abzvPs6TQL2;2E z925wEW;>{w#BXnoDqxPOBl4BhClFiMyHce5{=;3`&-ngJwE?09T$I_b8=gnhw3FMP zn;}Qg75gu3jY-8VBCj#)oZ~xSRN$@PL>5pHVN?-hc$W-e^k<>|=NDpAeX;GJTN-6I zG4OsJ9SsC`DzPH_`$0+l(#}6s^nkg;ezax>?2J2e6%7Le+%ky+J>7Ia&R1E^#8ZiQ z>Reb*HR`J{{?zXKx`h+YX9HTxzwkNHtCJzhSfL2)z0b}4?W|lA<^odRYnTt9;_lpU z>k5@hL2F2-=tyv!3*!gHbF(5tY2Ocm#=k$+FhK$tB-{p-T<-$ zTf5uuPkIu*bctZ065H>f#J0#0mKGrkEWEGsYsX)%1Oidg2cJX6vEL0GXuhO&#brA2 z_Hm{=(!oWWswiy)&qn^#ECK z$g)#Y03D~Q&Q1f>QhYCc({@F|DWtytZa~Yxp^u;?bn^Z#qy#2Ppo}b+S~gtd0qEgC zVL>0rZ{2{Z&NT)2DXYyPy*Tm|k}h{Y7m?gZIyJ);cr#ZNC@w6<2p6%JhuabjC$fF9 zpwo8`R;GdDOEQQ~TA+sD+2IqUf4eb2sTu4+kLe_8LF;K^!0|um!R!VM3f})!oBQq! z=v-3~Em7oBeNuhwj8qmT^sal`%uelHe`fn;q!Wmc!SN}w4UUa$phN+*!2K4uBgUWB ztbqC+AFjJMFYOzJ|E|CLx-dd4z^@aPxDxlEZt+xyD61a3 zmiezv-K%vsrR3soFu@AznQWh2ty8gl!~fvIXC{H52nw=*(ECRveOTM1VKKoY2lz>z zxp{gohRw%>@boed;-3sHbkD5x@kCzh4wx^)zQfMBhr7k97_>?-QAyb)Rr> zhJ9<&Zx?cr>0O^Lx$N3&jqDjt0xEdP<3M-ACRp>iPk49+;jUJ>bYqvZ0`XhvNqB(#_?D@fiF@;-^d}0_!^arwZFa8t zrkxg~2$|Y)OV1r<9_{(!D`D~A5?fw$?7=|7tC4i?Q>H{W=86UU~x-s^E6e*f)A4E^e{ zV8!!B^Txj5)N!c(te1OdA=X@iI?h?+OA<~<`dl~_QtfVP=&x5VOWF(i}iGbJn6 zG1Obk0delUR|xn=6g5;|_#AYOU=C6B9IQNX=unLJ9oC+^Jgn!;*(pfB6@UA5aLu&z zG|!xx4zjNJ^z$~)HnGj}oZ|OcoJ9*}=%8DN*J~vCs}hlpcw}bc>k(Xuv`Nu&LXvqm%`oVaU_n}7_oC7+g+l_c7sgDtn3 z@HW08gSaJ4iiTlxf|@K6Xp%oozZoy{92kxU|j8JzS^vW@pNI8L^eNk1e z*hss2Y{dD5=gUV2a(#Vno{Pep8O*pvs0-udUWbtxa|8 zdy9|feba_1Lxg0eoec*W;_z7VI#H9N$(6C6~v?b`DNZHbfDkS->Hh zbb+k&GM~SM9h-QKp^scH`IwKNV8zj$kAO>5CGEt@kj9{86Nf@tp5N=GEn}Iqk(mU) zr{XTb7|6OJQC->Yd@uds+z_I&J6Lf&p^y}jO^P_+#bkK~)-)`=NOJWc2}%BsRayL5 zpAiu@v8Wa%7q&UdD{8V{#%_}0n%zkldOI2F+l#9@NBgWYt-D^)tVge}XS0$bE{tt$ zDtc>1%b#i^3-MuItnlCD`3NZyu`=6#IGlQq)!C0O}ez#xa>VM!wlf*21-WMyfJ_vFe%hD_;217`?1Ro9fDG zMI9kru__tjGm5V%USd>X)yju(_*{ib`@)CwmOHzfaf>Ufn@qb(<=cpRZ&KH&v47`p z+%PmDfNAQd;Au^2xkp$&N_H`jl7Mn>N;VUO_sHXGW^|gM1ICc1=IMYkmJd@JM5 zy1Y-HA`^IC2*3o`9J%soV2n0$-<}C@I950-(+w{dspZ)w7Opk(mO9D0CtIU(&==Vn zY9r}y9lsMgef=$EI{{a=8z-oDkGtB}OeuE8BBdB5U3K14M}*7C>%?#y72SC{t;Z@5>{XHXEK?&_hZV#hYQ-L9;SoGh zjj`hG3vXY>r4$!yrKcf9xR+e?FK4f*smJNsWOsCxsN}er4=48ZxgAH1Q8JP$dMan< zCxTmu+AhYp(7Bbmjukaxz8HEQ#_2Ds|Y5mJe+aCRxJpI%a`wE_#+WE{mT{tVCOt@dXcg!gQX3 zq59TrBmEqQc)9SS-*=eKB6XgmE}xL3$NcB;>a!75?0oXrFP}VCarARx!b~P?jGk_? zqQ~x-+DwE(pEF80-z*R1$AXNB{{QajHFDxzW(mnZtgmov3RC(YvE zjm((hr!?K9OoFZxy;_^SQ%QTDq^GvG^?K{f572gtdn&b4?i8pk*dLQt`Nvvi7^v;qeYPKFu2G zY%2I~+~+ai5H3z2!8E2iO-6I5P0aVKx>q>y*?I(WDznTIvB3JKXy|Wjx=6Bnv(h`Z^bEUK5p~&`-%7C zt`cFUZ4p!FEzu694#LGDN{z+K;X53LmrYaFcesYF7VHNu-i}%SveWvia6HAku1q%J z8>M;NtZ92-Sw6iuvU=JI8yW{AfG+nhq|N?)+YFmiL(*sD70 z_g3@BZnqZ*B>D{B0S(MsDd_2avi<2XLsuXeYcUpT-6n*5}1R1}{7 z>@fr^ykG3~9Gm)ioMmbL1 z6z#LMVQ0o~SJu(d-SqUB$TbR5Ia8}DO9M@lO?+n<;d=GBr22x-td7CNM%i4aY2$7Q zYOG*Z_H9S8tm&n$obR&WRJwPZdS_sRFz>1!BUUQ458JJ`A{+t(nijtar5A4VOASs; zziR1TbVv`K4>{>}QIG!Mac<3A^dL{y%wvUj353tfkrTf7?mjYV)6awNiaX}mtP<&g z;7uxIB9-dcQkLu0XqxZN$K$Ub%C|4a7G^y$91_`aOIyemaImUDIn;)mjn|cee#cW}5X@~B!%yO^JePm8A1fj= z_X~cB{g8ILk+E-UVk+S~LwztG1+1WUtLjkc@$n{43fL_gNbzDpJYqawKZ1e)NW*D> zQ)WUW23aS`r>GXiv}#sL92tM|9zRf*bVzC_G~BMKd8C*F*TP2Ni8DNYC1G)6W6Pj% zIuH`t^>rmA`;D3Axlxm^$VcIqU4j&CoRi&F z-8iNG@v(PZeq+bG_xTx7j*ef_Ws#vV(L<_YgNpZ8C$?qyXQIDXja-O&Qs7wso!VTG zA*A!U4@u+GR7RZmk9$c9yzQYT-!E%NDraSxhe;jI&+xK~XnKBX4R$3H*hBrJU#G7h zVioL%pZ=uwNpmraM;-n!W5hgyQT>Q&|8;*YRqvcRv*(oQiIj%fgy8aFdp6Ii!=t)u zH*BmDT@xo=RNm&P5bl4RHO@AbY*a&9kYJ7^Rx`}zUgT;sc#SeiGi9yEG1PyMj45r< z1bn-U8`qGK?O+rr~P|8t&y$r`D!<(V7>zeX$GuP}K1C z7*;mienj#N?BLYIj19xL*NOU3InSHyHpVf@I1{NM(!?-&)UnC6mRqjlRV!_axAbFG z*d|7BsuPQ-M06g~AM(g5@fDoxV%Y~R16Q1=8MKvhL}Px+m&uD4aE7(Jcf|Fdf|C@HB7)!w zss=h}&S#v7{H%9Vw=MDCvHcTu;k4M6{sb91$4`UzRCrW%((M%{KEEM}sYlv8|Drp| zzY-K`e$+Qj^Q%K2JUv2`z}z){ZN=rsXvn>OW4Ub9n`pjE-<^yeN_>oVxolJF?c%#04ho?7s z(KsLPlX3dz%{E?JFnr>#Ms#X8?nFCJYy#-8pSPSuz9ea*Oh zk>SQ+&^7VNF>?gBctKstt`Bqnax+I}HijePBHiy%cQ*-!1AwWhAi<~!bcy?fcCJGs z<~n19EW)ajHz#Bh#p%Esn}TK^`UddW-X}&?Z5*mX36U+kO?KF!(s`V*)}FOWIQ%DT zweFNDJ{Vd1va`L)@zMR>YCvTi+IVH{KTZgJq${Rd-Re&WYM+i0gmWxd$K2>TTa3z7p;N?u|8~C1lZ=~OSGsi*%@X5rtlchG z)8lU4LBjeO*j!9>W~Ju>EA2hY*4xAC4bomDs%a=UZ3S+I#PE~a9B^GYYMjzKC!$d( zLd{^9Gw=Dqw|;slsdk#NvS}DzgNAY2w=zkT{^UwT8)ks)>b?cc#8i*y7;oZ*!j>~v zt{+xoyb!Io7=W@&)YEDYd6>OI1*6$93tYFqYJ<(49CpMc+Sjwq>oD*Q(wr1hCqV!7kP6}5ChaRU^pW9jCp!7Unv&h8fBga2KgAgZ)>eZK>HZtLP zJwnfPoaIMugU$0|_ki6WJ^cv-AMVwixIM=n@=$Y8|Lw@}OP4Pzvs0<*JN6vV8GV0@ z#1Gbh3rR|cpG;(3DXXynxj&b7N!g;)@Bj?#mAFtnd7JpP&4shS1L*3>y zly-%_Y2&4~6k;kMVz;ZewBv-NJC$+h46K{}bM~T{yYi;B&MI-o%}r@Sc`@L$+zw}& ztqx1`J;F@Cg?6TKNxsfeOSQ3p5gnamuld-ipIK{{Tts&WH@Dmlfh(xAJ6{WCbz*(Z z*su#>(-sbx!~)dl#q&K6^u*ivV+_X&+*Id}U3&7?^BIe*AnZzFkls;P4!&Q9M z1=}jE9Fnf-2D`@i<2nV{aG3WZbFb5C!0Zi)E4i<>O#52}!C^y6h9|waBaTUguMt$5 zV#U);*7VM7V#-fX5WA3kT!!ANk)4%X)dODoyGwAU&DYteiL|)BNm)L+5ZOerK zWTdVENuRnO=&ZGhyu9oZIs3-cAxobM2F!TgqrAC-ckkGDbK5yT8B}D$4{O>~mZY48 zW#`LSAHm?x!jjlcH1oDr-lg8cVSe(jn>@-{E*^<_dw#uVDv7H4SV6$s?c)gB3qL;< zC#pBim`OLFrQ^6dR~$P#EVAHd6J4b%*78PF5`mKI=I%uEqo@>R>)kT1Z~eZ$|6U`CNnuZK)+VW}X7%Pe*<&UhSoPX>6-V>MJtfLCQO;fh*pIDg4bf)`jKg&ji1m-4wQfV(uhaiKaD5NTkuNIc${)?RK`o(p>P1<>-Q z#um8_>qe2ZM&4m7x|OV#CisJdTchNz^5fmbIb80{E|60%*vUR=mfC%`mGxFbB7_JRaLeJ~?qepG)O2PL3(3UQa!#ZDG{Si!DfKV~N(%32 z6lK&eXIgcv^%9>wz7Z2_*EI94%Q=zqvzf?7rB9%si8)g2XPwn7rj09 zjpjedUu>9OtwCS;$xUbZ9JQZZ;Vnm3j&IPDsQMhw87}AY#*dxpcN_(pY&wi4TV4}B zy{ro_A@TEgtWg}%XQLrG6dt`&WqlkW)EZ8^AaV{yzjqr)%ct6Aq9tCKYjZqS<6QsD zmHw&&y{+kNpB+4Bmd;?Ac8h0-8{Pi8zNd6F`ns&~!IWdt()nC?a zb;@Lr7G~VJoEKfF%h1n2N-ggxD}D6n7$v-@PrH*m9F17?`+kFhOtCq`hvfe_dk=W3 z-~NBRQc6oHNmlj>AqfX1vdP|5NVe>KB$0XS5su1A#>tLjBqD?|GmkBMJ2;&4yWZ4& ze?Ir8?)&@ydptbyi1WVQ*Xw%C=WAStnA>^J#67XAoG8vt6TMFVWFbr62A8w}G=-Of z=grujB6%2Xoc4ReSUpo)yT*{!1OJ4JP&W_7|CN>hwPOD*kS z4UQp)#c4y}oXr+P#RliR^?JCV0b8n3J>aY|(B`?dir7!>kMx!wsXNE=L|MPGOc;FQ z{Ji7%3v%n8hlWuhy@$Wd9ck;OB@$zCn&|dACG+z8{fRG<3Qh7oa(16X=O5Y+P{@yc zm8fb~$#0H{?b1#@td)IuhAoXL+ParH=u`bXo&vRNIQaxeF8aS6Q z5TXOJ)NbQ$6l_U zhXD`F=}mS}cabzREkee$iI+3WN|V;bmK_{uoe}2a1|Uo1WXP}(hh7e*xqa9dG5yiwUO?CF;Oq&sK+obaKEdG>zFViID2mS!|Wb~L3SY;EK2y)n=f@~Y`faj%n>ax2GMR6TO$L(GvPPCy`AoYWg1aAyU*Ka+2$o9jpSlckpeNmH_y;~A(Aov zHNF$YUTAH+)$N{T#LxctLd@s4U6v-6PNALMi!pKXNs~_@s3EO*h}%V}tG!P*ankJV z8zG|_ep*EH%`^?o%q&zvRqaLsO&9aIl#V|7`E@-SO{G(x-_A^)JfaRKL7o7}{&yn* z%^Qf^6@S`k#gL}ys#{rE+OG{UWUO;zZz~+atc7wTt0ZR_deX!r!e7`2#9StlPjh2S zFO@+**yy|-sd|4m8ao=UnstS4{zB;fK1cbJTH((KkqtQk>4R4sWDOVtAZy z7+R+Db}|}7!FR5qjAtZBtwj9+kkgb%oGuPhK!Zx~cjV!6Qua%wzt;0L5 z({)o#LQ8PVv#=VYIx*ZwXK?8UNP;!5r1^yRtR>rB2nVGVav*0F?--ygQprQww`bRWFK;nSFH>!4W3zwmVb_v7jI2ZO9r`wUGKc<* zHiMIwF-SFCC(IMa$|~wHH=Vd&brf160e>j;o;x;ZkX5zBGH@l}>S@kQbVRiEm!0K6(bnu9v+#K}PK$>w z3amqg;k2%=QO?`9ks$?+DV|9(GK0>z)M=t8p9<31S$3m#^VCSSRr8h0$&B0kDWa^y zyqseWr}hjG#Jsxy;yDvMNCH*VcK$xKlv!3%@RC$Jyd9adKbrh!pxovpK zE0yWf;Qr+sdb+-lHx6BMf{+y6D*vGltor|okt*Y$RZpy}Nry$9dd zrgZ9`DxHmZpQ4THj$U*r^BW^lMIA$$wns=GTu)7r`rxV7oBZF-f)?yxpG1kRoO^iXs2iXlU`YF=Z_4}pA9IlV?=690Kl_KZ6^rm)~$ zCl_>9!q!|t?{?i0(}z_22z?j4;Y^a`r%}@aeow`1++216g$B59_LZ5pf*K!&_6F}N zrGerG`5L&GO#Rxr%<9_ll;DZwl~bx^mA9O)7t1@a(Hop9Y^>*Gj(#UTDkgvsT$3@_ zx?-IAzGl;~bq#-fCp3lC@mDPXk+0d4r^6%}@5VM?@?CJD=E-Sb^A)_g^yTz6(P!om z9xO;{7}$y3uF4W~*Q9iCT1@T%iMCGXQ|vgb#WAQbMiSHo`NGTACVEzqGdpKLlyRn( zHzEKJbJ!bVW#8#B%ZQo+biwp zxj5R5UVP@xbY8L5?Hqh&-Fn1t9+Y65QleYz2y~m%djgVaeO!YR7-{|W)jacJ~m=V2CG~*zcaRQl_QoW{C7pu~%nj;ogWoe?XRB9D| z^YZ1GSC+(`GCLQ4;hd*^S>q42lf)nRi<{M>yN?&N1Q<8P_fyIK0I0a(qI!zA&oBv; z9jrm=SG~fY#-XWn$7?oA%bQ;iAAIsd!9_lXVJF&pF?w>4lNpNB^i(~(>T))7Q|>IS z$r3*x3zcM|J}u95sl!M)>_PeP^mXut$TW4fsTw}>lPTd1LSL2DUZR<_wxXn#1|E9?e{kP4OT#sfC`Zw%oC=p8nnu3~*@f?_ zX}icCKXy#g%)J&(t%*7T^l#kSrMq;zoZhpUXJNARNA~KA9nI8B$VJv*K#Ta_IrRpy zDe$k-ItZY;P3QGC; z;`q-R-lWk|{P8bGKzS6<>S{Na4xjstqIYvo;c%th+T@48v+P&irUVN#lq8av;|E@$ zr*zyx70(88!WFmHu(2nhm18(PRPdNyT!zrMeF}{uJ-3^}q+lrDro_Qgk$Whgqe?Xut zu^T|;CRYVRDpzYr!IWcMv|zmQhedF{M!a5lX;AU&%AC=bY4dbg_Bi{o{Tlhl zL6~jMs}w(>t`P;*O4(%|fyJ5M2XTs0W9+71oRTWjz}9+g&ca**K%Q;Kcisi~R>S8M zQV3`F7-M=hs~@(rR2y`LBJ@tNyu05Q)=cFT&H9yEQt=$zT9eQk=&eN6+3u3ZpZICC z?G~D}nzZ#-Rvr&BKOw#KPouqMP%8_t0}%*k&MVmcu476V0>{2|%4};)dx<@xjd1K3 z^w71fPHXRt!W4GZ0sJnmI2c-7QBko;8y^7QJUW=E)%vQMVegE8R^R>?sf3_y-X2gr z48^PkfMpgd79v+5cqzG%!j^671K(lgC6d1_t%)+sm3gdJYSYC%bCxf~s;@|vvKi{& zS?J)L`U+aaD#)tWweA6!<_M(5KcJkbvI}I*-M|30V8dFO>5IwDi497lIoR-fN7eS4xYDeu!1t zpWY>>ujBk1JL^}~XdmAFO%%0bHh8ot9ybi7RrDbQxe4D@4T=JXDYm(Mr^Ks+hDq=r z*0$(C!T)GXyjV(k%Y1+7#8L6hCk*ww{nfjP&i4`FRt270_NFHZ^B8>YK$Vvsb~?u4 z2k1M2l*hmM4!GS42mT2cJ)BrL*Ay=zqz~XCx_*tC)fQ}k(@(BGsjmvUP~D5wTx1Wp z)%@i(CVd5mTyIB=fw@&zjH>ise|zKn7!lq}7JA3p-VBUh@%JYl%+xS^xz7Z1s1FLi z5*f3l3mnFemxHDMgkE7>K%9`ZDFC!d5MYMc!;mL%vEmvim#lU_0z!u;)2rf#4gm`D zdWp4=SL4@F){z5@2pB`6pl$3f4l56O_nZ?D;jW$%GgdY>v5JY;8^Nz1P?c71wb(kQ zD7ihwgNF5(&Eo1qtG~cco54y{$R}w|J;=lQ9jFG-dsIl-k7sR8apN5DN3*vfos;4V zboQse(j|yW(B`u-LiAzO#Ia>nT8}wiN*bCjFX4$(+n~`}YqSUGQ=*^xbaS$%6u{dc zz4VWS1f~LyLQn~S?y6Ev-^b`x8p!yof0obV7z<=aC*m7hra#pw$s)p z9`9EM?TjX3&`yy6wdo8OzRQPkROsWl|7}(%zH1%(R_GTBq7~US-GzFyQ za;4R43eN&VEeMQ8dOrf-PM3N9wz30m!@9S^tWc34kTU*89*DMjVRg~F{T-o@473_-$q60x2DvP; zzj0r1wic=hDe5sE$chYaZ&!62kB}~s_w)lDs?d*VMMdgJ*HMyQvxVzC0F@I1dl}_gRG>kLC|wxp0X7Vj@%`hJL0&v7q^w3B_)PXO zEt)m_fStgm^$xc&^Dw&lieL4@6B^~`<-9V>JZ1Rx>PFA{#@p;f6LTi0`egofy!swE?* z{5GY-a<(9Jt~@j|8XKr-CP)VD z9Igu@Znu6qz`z`Al6OoIT(-G6*0~00yZ5)Mvtl2|rv=&EKP(BDLhv`p24OS6C7KsI z)n+>lm}Jkrs;&bvvkC|2rwk}s?KFkVt!J!Ev8?WuIYzIRFD7l}K(+<1{+353|q1spJe#0(=EgT3taC5=^&?$!A(pa(*dj@d~89@0d`Xzwp z{rQApJc09)vQBH8(!3xw3B3tNdVd(FLuX&5XnCgM0UseqD&wgE%bfbjG7lP?XF!Y) zgMt+DZw_&CN)PO3G|p%i3U*F<=Nw0h?j;mJg@2RK-EC=LosWW5dGyid*$yp3h$4(5 zlV3Q&d$ov9&}%B|BhHrT0Gk42k23s$bR7OE9h-44Tw<18S+>%Ft8Dfg(+Dfsdc!xF z7ZL`M*6@MxaDJx|l zW?=-}a~So7kZO$i+*V3k*oEugrlqX#G{S|-NIZwP!>7Rn|AnZMtshf*h{hk^19H{!eZ0DcE6ckB-1Kyc5fVBSVQE}Cc#mkT%vRMd1`dX3w1Aak3g@ws} zTMe)lAdIJ{u56=IK7R!bO|}YT62}E^$I*RG5f+c2vxQkC23)ANlgzvD9ZdT8KnE!c zM{oiahxWZemi(1a(&**yUfz;_(0~`JT|wQd(ExW&^~;juNUm?uZ{z4+f=E{b_)|8e=F#=rg0R7-*#dhHQVMr#`B;ZF_e#Y6dKrU^5V8E7=fguRne(D&vcI-VD_LMz8IQ>FOPYO z-#QEsEKS0m?tFlJ*t0S6-=olEn=N`leN5EwL!4<&SAg+Bkj5Gn)P8UKz-qkok`tn9}rK&r-otq0 znhs?LC;Bg}jXXBZ%7Vp~giqJN+#yFbw0_lc@q#%oV@|P00;t1I!|$#Zcw@}Bx;T?T z$5BlM99zeDYl(?+9M?uXkzzQ%SBR0gNZR}%9Sj8$I^a_QsfEYgF7eUd-Aj@7qb+7UBr-|LPuC3T>VKMvK2ELuNOsUH}`jR6HrK1)|m1Mr)Z zwOZAYuct^w3|$E8%B&`{5%eV9Hy9RE(9E@rV}54}URJ;tVh@W`M{r5|k1x}(QcodA z-_}N6EX(q6PdbNcBOF*A0c~F3t`~6jz|r3Oy2tiQW5qJ^n!>Jop8-z9`HMCvyQ$2s z$fW%OmL}TC8&}Dp>IkS+iqZkwPz}ZTR_~4@>EIdYw2G05t?}(#^ok1)ZT@_1+x2S3 z`TW^FsjCt)BU4|cd&ct>8?08pVk*D0fFu7Vs@NJ7HwE|E0%E=Y7770r00}WW-4UB_ zcRC&^ZsL0jF0`ktM8VMOOfAati^7DNs;rEmyYfmJG#!w{EUFSP+mscH`1&nA?v zi}JZ{RXI-wpBYVAGb(2#2S;;+lj}ZkcK4;W*8673C6m0O+k4_9053=$)2=*ce+uFW2|5R5fh=D$4_j5>W7Gy? z=3}UgOEgSDD_Te21h>R7o!wY>(X9pl3uPNI2?z`9DA?)Uf9#axu<~b$-W}o+uY!3a>dQA9|gXYFeu%Abh4(yq`Pu3wQ~mnhvgZ}fRR91 zJ1B8SHiyn_uS_s|D9rUS*c;%Z|J)m(W|OPu)^||tbn9T$^l_J*p#<7J^d9x>e)3pO zwqpj)W%9=7BcOy_c>w{>4k-;la>Hs?WrMFiA2#PsHG&&wmrc}W_dNsKOK7T6)3RFa zoJV7wlvA!(Tqh8{Klp2;yvgyOw&vUBEqzJ^@a=(@aYTV7+qJ-bYHq)uhbu%ubJ=8F z=`&QauDmcrr&ZsNy?r{RK=T>ekj;hIPBBVAsrREmy^T zs6dhE-Ue@G{8EshG$ML=Q=%DEz55ebfyy6O9z5)hhM$5QqWR8^}>(37F8tS9vkm_35YC!|ZTE4SN%a6W`d<4sy8(Ridz5nZxfeWjQO|JS| z^+zGvMA$qNnf$c&vqSBK1N9F-=w-W53xLBwSro)!1k^2Zme(99J8Mb@P~6ZX z;POidc&dJ32yEd$`5ubUDG>zK)jY_H2a3|z6#b89w^h9d&j#Vk$8#_(y(4WkoKT;* zVWRRGa07;6;Ph(t^!mZ^Lm(pE`}%zTrpcXeD*y_3-VlV&Zb!HZY7=O| zwl!yT8|su|qjx;!Jyx3IM8;XE5T9Lo=)$Ee6DeYyaLgdm(pgJ8kpiUH|4x~IPCu#= zxiyZSCH<^?oi@U#YJi?#h(qS|d&pfc-T;N4DRG3tRWDPz+GEK2|3*&$y_3Q5JF$GU z^7y5&U+>rC>;M^vI-apv{AMYckT?TRvG)~(wMBE;)itfC(T>+n+Y`*-E;%W@MJU+X z%9~*!OBU1JtcqsFzW+k$=)johAz|JtiKGpC1^434Dd7N%fxMz-peVnGA>s-ig%K2G z#0noJPr#|}o?AA*BG{6-QhACCs)sCa#68|Z46;HWHd!5suK?BcWQ>ANMtLh?>zfDO z%f3RO+H8kn%o0-)Ff=G|F1t5jlVsNP|pXO~HjfU*QdbWuyE6a}n zy)R4AF{RZpOZ553zb#DFdDtQX&KWUsw%3u3MI40b)sLcUFT0XO0cutt3AW8Dy`DE% zpr((SO(RF6R{Jm~!oh*GyA3_b9%Cy_`GxLvO5mb3sVfp@2lKRdv|_z>vKtAwO3>xKTW=VcJV#zHZ-GiNAAOL4+vlEyQO=sx)kK$x-d#F(Z;e(f zu(U#u6Z55d#$|h2Zx*&Tn$0&awNwih_z}2@~vV;j7^k2}g+P^19Yl)Dp?9}iB7e{EyDeXs@rqI{b zz=dW*r6pbXy<9Eq`#-$kiJDaqgt$#4dm9BNLwbhg({+41j3x05&%}tC?}~22&0BeC zCWBfB1liM;omN{#x13tg=2A)0Db_KV?&QdFtXRxY+k!=Pnfx*Oy16xPXRVnboVquz zp51M&cMX1HDN)?15wwgs8W9_OvfOU1-_D(Pi9Vh$e!zjvZ`p}MjDghl#-k|fDm4Bj%;lvr zm|l?SwE*S_s$QIy_hyVax;<`-6uyUEfUPJ5Ck27IqF2g&fruOibK;=sb)>pz0VrEPQ(TDM6wRlx)K7EcI~?(CiD-^+Zwo?I_;))$<@W`>3EiYPq$zO-rJkcMGG_bH!GA zw44WVqTX^B9Pl1O{-463YUc}q>s$E3Tm52Qwzuyh#a;blqQNC}?_;aR1y$XaLOik4 z7y6y1j>hELb9gIaO&{MnuL?gfIWn=l{-9Yp4AE#U?4*OM02-o>&J8!t++g`lK9_E` zN`dknGzoZdQ)Zxj>9?BtS$RYZgRj#BO;;(j221=P{h(iQqe|&C;ycp|It`lG zb5m9AVuUk55t)5_n!1wuwzjF5{av08!xUG?wQLrvE*@dK;N?VIJx>w+s-0O8gp04;x+#;m$i3mR*pgOmtb8t_pehEN+|VEX3O`|K#mY9lmBeGm37T2`^PWmQPscqyYwz z^iVQ*&-IDtP2?1a?wcUE$4HF7K703|D-lm9N+6Wg8u1V=Vy}XO-3I$kn{2^~7aE|t z=S9aLmPc;SuA0@S%DD~$~td5KXifrkE;YFi{2eMM(Zmze3lgc(jH-w%6 z9!cP;Oc{(=6hEh)cmEYXg_Dsc|Hl)%w*bs)!eM~cVsPai-xSDoBD`llI`Q~$+w^a? zpEg_u{F3w`IEMTiUY-w7naQBl$m=qvvomK;UW1F{bX8Jo;NClAAW$Bp^%IMRH*!An zCX$|dl%fn?He6xl!CfzPoH0*v<1VNnG%}p3Tf=`i?#r5R+;?iHgUaS}%j4Ti>c8Pt z2j3~sgDRJcftSSWDZh&;z??Q=kt7^F??7LpqmicBCwai7q#X@C3wiWXAzKGUp^N27 zClpqw`Z<7%C--={C70uK4uaS&+n-7K7Wyd`T78AMa3mi!F<4SEt51>TRT!^3aDW;xe$s6%U@O zTiJ$}e|@_qGHPSf7*)8{}-h!P6bGiS8 zk^*gJ=VIF}Fxv!_gFT);?E>cLXhb<_${Vnayw3$intL&ZN$mucF=eGqmG4w88p}UK zylMp>6MU79)%-f-C=S?o<5q+q!GqNHCwz_^Q1`6Sa5u=E%#H-mC&6J$rrssHb6zC%`Qn%rK5x#zL#oqFcV!r_3#m ze~t|=WJ;LED^-Fflf39;#Z#)$577cqPRbQ7vVGeR)9UaL$g+a#Z+%=G`c)iMrZm#|5Ws1SW9PgNV@3tEE0|fKLmPpA`0j} zHIFZ=uCK>%v9IJt4VUq<36O8}fdv2I*o7!VqSj*lpDbN4vJ%ScX0@s!wDT>qu!>u+ zX0;nksmcVs-rzsWz|68lW}-d9`i!{BEnRsloYT1#P~y-B7Xr6{`NfXCd_9`2K zD;3=ogSCK`VPQd_3>M!a%#1Y8b&I(`MrgHBys|xAzXPI?(*pzP%7-Sb?rT#Cu<1MTdg z*7=kp?c0OIZ&@^DXv$b(V#oA)1j`EENG+*busdHcdGy|8D*(2=z#aeo?~;Wgm`bVQR@E#u>MQ9vu85JLeh)6MbJQn!3tSj%hhaSAZtI z`?=-`Ma=d^)#+ViO^#^B)Pfck5n>a)8%~71K@T^spKcjLE7Z?r`@}A&YUWxM$(B&D zNHsmCq%C97ljCa7oafid@H8_naL6+CkjJt=c)KfNlu%IFS>8@VfxDj3;8%Mb30f97 zUXY!`nAM3PRiE`p1pgG|W+2E-@y=wTQ)IB*2UDGv0FT`x)Caihouz@UbTQn8YDx6Yt$w zwkxVx(}BPEID6Qf5W?J^#GvXdXdOSnKQLhAwBFKNDiQ&zR?$ql$O2Wf*Jcl%DF!no zD8A_F*HX(34pSslSfdTX2Zgp)*=tHnq-RpQk6O3?h&|6PP-L7iAD@0a-N9=LcxUal zF*Y$hA+m~D>+glZ)E{X4h_P~$8Eg6gOT~o+<37bb6zHCqLhfjS(wYLRt1yT&@2@NE zvl4uivSxLe#y~E#A4A!V59ZxtlC80Ct4#v)f}j8n$2a?&0*EDdMi^>isO|jOjB!$$ zzNwSY-_dUw>D_KBo=>hyTWGe{RhTDjS6TAStPMhBeH;TrRC;x)Omxe$<>K?raVMjT= zHP&@kV4>EkxYE!2_+*BrwDp{tr6zOZr=af^BHZb?g6-A-X=)}F)0nT1r%xTtq~kIw zs1lvXUvREb+ZCHKyk8Xl)8wz#lm}&MtXYXU-P$UpgHb7PIs@!?Uo}-P`wg4#%GZNw zfZDQwXC$7Rt=4QM0s_EcPB(3+Hc#jR+rD%iP{4ZLE9melG)3_j1qSspV=VhOjLn>k zY&srTz{A5NC}7EcO)q|E-&t&t9BAGUT{woE7H0%qezNnmj7o?rDY{#Z3Kp>$=PuLG z%BL_qFJVVjv*-ooqI5V7z=8H_&hJpBq;QyaKEcsq(< z_?Y3Tb({A9In`6ThILi+pCs<+yO}x&tSz6tJ z!r5Eat^r>;G;3^D9CPE9%vDsi$1R-aEwF_vOeh*KX}g4wN4SZdxXzWaaddhqby%l> zG4`9s38^JVOE~|9U(MCUQc++sqvRZCkn?Mtja-gb8Odi}41=v(%)x8{WNzy9k%WbzcVlPUDvBNjxE01x)5gXgfn zy)|xY(s?khzi3adem&CW$SJxI(x(+sR8LdmU}|`zO@G1my6+S;j_FECk4lM$U8^u( zXzCZ;a$DVp^EUZn8G~Cl90k79k&4p?hRL%Wn$X8=f!SDKBESQblN4@%fyFly)Wkv1 zq&8c(6iA9ELh>Lrr(e{{4gV$o2V5nVcBZs28Z*XwrqocmBa0KLwH}nybk#uL)k^UL zw#GA?+q0}#PO>k(!I(!sjPgrbgaovoFlL#Aau?1_v-!C6>xA9lHJbkEmblZkke{ zC3U|!bD0vZ6j;89QAq6RpJ=A6aZoRb)(x9zf5~vy-}yTokN7%%c*9h+ph`__!Lk(2 z3hMETn5@_RE?xgTCc>h1DLHdEp)n}eFl66SUWxA2Tvmt?*7<244c76JmYZ;_=*puLxtEuWJd`-mr1NPTr!4`-ury^0x_yK^ z=gxJukLk~sJ^U#Lk4S&^<&8FcLw}(VYw6-$!s=;I= zbi4)zg$me`kwKC5lvJ7`>J!&5RrxDd@=XxaEjnRPRq7HP*Pcdnqpna+Ymi1PbXCTn zoj3C{+HNQaiP(w_Pxrdr+!;|Z&lT{X+N`u^gKqcsVKDr7*yPGp>^F%rKN`f-I zhe6J6FTwp#pLckxxO_^Wzd=q;QgVEw6+aO)IpC~T>ob_CN0ezq_hB%p9L_r|D=GQu zA`$XgJ~J_F3e_mH>9h4UHA8M1sU6*`uIqbi^}a%Sg<*MZ2OrXsxvjIv`3A{)0X z`Dp24x^<&Uowb~0rEjoDWgS^|p~Uzbs>prn7r0`aopXJ*KFQnDX?x?K=I2rMt%`3CUeseY?E*t}}Z4;@kdSmXWyw z_wY|D6>{A)^QaL43IVX@83{7=Q--ng1Drz{M5D8(8eiR$s2`PH88TDEyxHnU@sOri zXxZrF#)>z*yK-T1+0~W1cl7$McXVk)r6%0(>w5(=V&ob$jJnkn$ua$$`}25R`2EX0 zW2ZjH&sZKl1xkpY7gQ=T_`hl|+U$2Y6&)*g8`Iv8N~~Bfx3Rl+rlmS%(!iiA{nznE zT0$w_y`=DXtq<$jvk{7A^E)TB8?$f}L`X?V^$^}+or`+QQyRw0<|Ky$n9tD0+;r5v z6Z!0-pI&stW>KS88Z(*lgyF%?VuYY{gBJDf@qs4#BW<>-um@g?H|6E!V4+)n+_ zhzd!AniQ^NMssp)EW4wW^qt&ZR(#K64kv|PQ1bdj$tur1=FA17ldfcERe0-t%gpfS+w^4w?Lq*T&!MA-{hPpD?Iy^bz2A8Ji{l=}bUS?!oNluJ3^#hLJV2CvzIT%WS{ zmm-1~GwF}kOOgM3J|#q(dTLegxaW+Os4q-j5c{{*oKx$#NY z3&i3m26_2(Q&>Xm^7!lBehI0#4g^XGBlhylU-m%p-}WFm9=pHft9RV`?=J_C(#4_| ztMr)%_WfHF?;_Q(JkYvtE*gI*yt?T|ezuHxpT2A%&2c>PYHCsQx1TsW*M=g$c*C*u zWh1kgA}^1i{K?6OTWcN4^FxCW{f5i`>*g6s$M^ZN8|}LMdf;&bO$jMM=yeJP6vG@@ z2oqTd52oPhtL%qRg%AFFTJcYG{P&}_f21PDyY*~~y?(T@589;$bcqPQqQfr**iW}J zqg~+8UcaCDKM}P?w|esv&&gUBK+7m;S~tlZ@9HE`56#KR$>-gJy@h6<7O~Bs>*fk( zC*$!W=Y}vE=S4j9{CD(_FrDpz_Ia3k#pT?b6lN1%_Z+ z)16KmwQzJ)_r|ZLP;Hc&rFeBORPRAm?`-~W&lBJ_C}#p48mSMzFT_>vq|ZO~Q6JFI z(z4trv-O(Qi&V;-$In79cwqM9AGOs^1sKI0xzCB(sVI~(|09Ry#`pDD$T5oTIp<*?IpCkxviwHw!4oe!OjY^B95|- z=MVc`qf?ey4JL6Lf940<`S||Yk@^Yjlfw4za7|iIdY!)s(UhRHoTpVo_ zMfl;Z=q!qRF*kE57DIb6mTH5h#gK|R2K*akgs11|npf%lMjMeLel8*fr_`9NoD!KL zD#}FI=nS{Q5DL`AwhGi?LTuvZRM8^3wf4Ak_se#dqgGIeg)qY81T)Tk`e9J)s!S@ITn= zOz;_SHM(h2!E+h&W>HYT8mM0edwHc@Y!6wcEnUts9buX71wFdFT)01g@W`^r79-YD z<S>{-SZu;`Hm!d>@NqL&=_CKS)3mThxM4c$&~h|d z05_CdI%I)0Itrbo_Mdc)G7y_bmQ$T@IM?ItjhahFgzX-I+sHedZZ;sBLm&*70fhf`3-X(=TI^g%GP2q1` zC@yWZ(A={ z<4dS%b_=PgaD{6Pm|<|!+5B;QFP&= ze)Mv+CtIM4cyyo(Pvcf6vk+lOnr|I1&A02V`w;&kR#1Es{lyS`8*FMvuF^I4pGf&E z0>?=XmAUE+?JgChiS4Klq1Uo12;VYSZn>*)r%{;V7gHKPf)SdZl=D7A-|5X-6RFB5 zIrn9UEu2|OGpklrcr*A`MtQRbr@+~@s@}7J?~F1VVCf($vAu|52Bt;(=|SZJe&W4) z%lDMO^#C%&tA%3JP^9)F`=8u%<7zIQbd5~r-7B{EaF?Xq^H(iE%byMyvXEyZ^z65n zyPyLGhQPVrXAguCH2!bCf}~C3bb}Ve_%%MPz2Fu1m?7l1%A+{008yka7i5P!?{3M^mKiZx8 zYEgl--l3=|v7%iMMaeXt==X1gG&Q!Adc8KU+4V2eQ303m|FDBgVU@3XhccB~d-0Vl z4DHzQMxB=YnVPA#@BiPPqoh=k**i3kOD%z;0-vvGh*5r{&L(cFw#ANge6VhSTZMEH zA=Lu?n64@Iib=*h^k*a$T2onYu;7uj)6+s%zRh|eGcz19rG5&E|7*q!sgctTCVS#Lu-qi%}V8xzf!qCmd+_9MPk^wBi_{ilUv+8MvQBn7u^;@<}nTouhDoH1qZ9`Obl(rvgwO z7acfe_L=rT_me-#%e(eqtqEx^9?B9B#@{jBMj3s_@3Owm?HI?UG!tfpt#8oozL{W_ z|3M54bQhd<+(&#i=`8zhr`y* z61Ilr`>{j}977NB+vz*^f3(@lcaYRRezW#!%$~mT5%xYGk02c(-#L+QSm-JnzLhvD z?@f465MS1tAx6K+6XMjcQ04{n0|0ti62k9x}P*MGAQOrqtc%{ue@Q53>qArU29z6 z+qEV>g{53A&G8J&ydx~4m!{y9NK9z|V48QZExxEr{bDJqhDXgo&E8cxVZ<02TQfHw zLZ=3^j*L%?%8EDQSb=%p?h*?`jR=Kp^Sath`6n)V!Gi%;qrQF|s`E9RH zCM%{yv)QN7hizYbmt6W2%eOd8uaK9mPSbbX;$(Q;GS`|JK)qWsXR&Q9{kSiL92Qd` zN*1In3+pt0U+w=S{Z(E3oF*wJH^EJ!&+#@=^sR=_7}2S>h?qd}*e!?o>(@+(Sy!v1 zJQOyroN_KXby2f}+N$HUk7iNs$rtsz9z}?3iQVo=67z4?)vwvwzw)yMe)sA8fv?D6 zE~=jr;yzVQ|D~iR=3v|Rk-_q*Dzb@Y+J4(y+xsWm)$>Y#iia=yUf%-@oZ@lo-WB zSdJMCs1@iCCqADERIL@2KIP{S=k6c=;{4eLt%|2Cw9xw74pAdbF}Ld9INvPDFmt2w zeDSJj=F4R>Bsnb3|7wfovE)R+*C^pBpUnGL3lv0$%{|2|gj1VK6(13+ldD8u3bfgD zYZc>BQ<)!A7mf3uQZNtyu1nhxjd!jmzfHMU)c&sPpP`xx^5LE0>SKf6H}A|10R^vi z(zS1_eImQvZtfJZXy7BY@~rzef%T%F{?s-vwv(HP&wqKty4A<5N`rxu=~@gWtn(zZ zrXx2g#T}7s#cIPGX|$Z_Gh0(T)m`2;TDY@}iukY&<2Okww`X62N(QpcbcKeegY!;S zTq4$6r^9?$&4C*N!(j1&AG>jpR$2<*ppxN!`r`ikl0$a6r)yI|j$t`1gn1rwfuZ!T zSjGf*yN2mzy0+yNYn=1hZ!^5Z=GBc@u}GvACbFE-c*R!vRAVUih!q_%BLj9L7e};G zm>H0^@Hu{GF}o0Q*PQ7l^MdiquWndx_+(DsGcT}+)Xyav+eHlSHhki2dUxM9v=RjoXGC5R zbzgPQcz}`ynL4R!Mr6Tlg3yGtN&Ch;tG)7H01cIeJKG^W&uNyW`b&eKYa)P&@QHf7 zgSnJ+b+|XdD|kurjat(+PRSA(M-HrB5e^$Yp_65AOoR*?jX=gPbF~`?3@5mls+~9r z%XUDy{vwDEAP67VKpy-=D+h_C=8{5SkI4szfrI@@iqfPbB3-&8 zpmd~5jYc0a$p4=(ms^wz_PcIM0_zNVPO8Dt^sbNStj*YUy^1EmOxPx_BZWr|aqifv0V zpp_ehaQKRoY(Is^#pB%_qxapP5v6)&ZkVM)zL30qNFxf23=VwoCCd8hf0h4^LmUM| z$wp0xgTl9hxxoACI#kF%*W)#RW4oz)eSnA?h{3IHZ$^DvKZbKw#tsrY129;o~)V=QbFuUY0NQ&S$fk=@@k{IuaP#JkLeON zr}m?np*~7f-mk~BT+cx%0i#TL0C(~}U}F^fNLUW1gT*NEhSJRnP(VC>H&^JpAlcuC zl&IRxmTl&rIWVvklQ`0#g>;cWeAWhwP|T^Q4zp}Dy|v>Rb@up*h=_7gwQ0TDv&9Wm z#=CEH!^pg(*p{h3Y z{s{7yLmgMdgF8FM&Gb*u8o}$7tYn|ZIVU~xk6orlR=kL$86Lc5CSB+HB27f_w2GoC zxeEJ+wa)t(yMPEgB~DxUrH|Ihns9X6bmC#5YD`>Qo{H}5n$zznG&NwaC~w|$J*Ic; zVy1L$nEsBST;}T!!a5#5MJ^gtVU|~0fGerir46GO1EDTA2Ct}DRTYfxP8ChO+;mIySLGIGHd{lm^&zZD zPqUSG&o*P2e>CcEh-Yh+HuO0n1s!fT5A+y?VhgO9&imK3IZs}VRE%3$u(e0VL=SIe zEy0-1Ybtvg45nTI)oKWYb7~VV@}xN+SF4w!G*4XVq?;|tSLf$Al#yBZ$Phku^0jk9uOH`kXxO=TQD7^U$NfMS(ji)!NNk(9I(Ssm~H*rajve zlo70@$8z4H_RD>Zj?4NuW8dt7ns4t1KFH`{PqdAWMsE_L^Oj2faP|*8q@fTI`z*e* zi#;p%ZbOm9aLazy7*G^)NF$@mR<3~EhT%1hik-HbE{8*=u=^`E!Azrcu1e-d&@psJ*K4ms3wl3F=GBc|NVPO&F zkZQHs7yUT|X~{GLi@E#gGb>)Y1%g;y%+hkZvZlO!&w=W(*tsQ?-EMYDMsS9XvK-<} z9?E`qD71KP2C1Qb(vDgbh{6q;`;3X7ILg;-=J1!P8I8<%5&qYRHOE8%t9kUdEUfdQ z6JRa)Yl#cr71Op$5go04Es;tq^Y%EK%Y#x5*S=J_?nYK<-gO$w(K=jfxAD+TabSu@ zU{om-)s5E#vh9)1vuauzOqJ;pZr@?f1i0Nu^qYJ=>sRRdee`-hJX>?-o+; z43tfyxvMdj^^F#LrKF0p&y$iPmg~qQ@6SRQ+q>)y&Cj|LH1l*}1y(yZP_!}m(?4F? zDvHEJ{xlqPi`7w9sCimvS4UUnukpHA>_CNn^oP0BLnpo}6%m(sx{|ia@pjwAw|$QU zkK}XJWz{IjN*UJfx?XG8UXa5EV4m?Cy~1B zUuLlC40@C6c}r-Ih9aY9GBMFtEfF6j8M4#$+#3v>n7vJsV)dd1WsNfD=|%aJ-C?se z62j#q9A~fPH{jMkx7{K+&}`e;@&@83dp~^3)p_ya^(Xnv7lOBLarIiOZs2E{=}LdC zV%UYD*En9JFQ#E?U|i=S?_1x`DBUHLPvp=Ix6s8r@UeL>$Wr=1s)cxoTEMrr6WPHp z%USv@aY<727PB8YKwgddp0v{~OTW5KXZm&-G0oTPPKAx)=cBBJ(}(dM_#J^;@ff#1 zokIq24kO=0D-5-G@;u+3&CcT6af{;a;!%+FisB{2sQ$9g^qR559$KkHB$4hwi6@o^ z$1;4S7zK;JRuF?Nzh@|+Fdp@C31OTY@KLCtuZ?Ey;ETdaIZs>(OZ`LO+<$o;v~e_Q z&0!azyM1YWKB2=mE!EI{n0Q(bw{JrHwa4>|sien#te)_AhX~p})ML{Gu}H8yuNJjq z(pc41i5mH$LxflllVa$J?^@RRU9@O}5*^Yq7Go6W6Fa+eMI6|n$T;Jz+6k&=JB;C= za!OloXJyfnVSKC7o>Ry#fRf~#7s+>h;i#mShq=L$%rGqr7gp2+(xqP*M0|+-H5$Ec z-DnSDgY%DfP5?9gpK4Qv8jM)LessQ~;J8SE-ibcaVPm3R#4Mpa(|3k`+|nW4Al+-B z8$?ZN`nP%X$y$=^mD|vd{IIl%xP@V8BZHprNQ{3rx8G~^8-Ft(=At0P(@ z(vvr-!86YF)O)lSFqE-7X;GFnd47^pU$}*2l=$4uf$sO0hkEW0E;DxB%zgUV znIM6lL|yu`en%lt-5L^1dXTDU0?*S#yfj9a+Ny9M>X{Dg3=|W25i2gk zi3`A7HoaAzey9hpdrYbWAvEr(W{K&iTclOG=b(6arPFrl+KT4f5R~77J$uWcZXRNr z+G1bEYHN9vn60a@fmE6QQ?ho;uf_r^AfoTDbb- zkFXg#oeCx4k<2Xv(o$+XG0c_f@6TFo*q1c{va! z;tbeM%-%5!zwMB;q#)O9ht#E(LLx-RYj#B!6Bjm3FD0~*YTSqL#OGXKixsSt?Jhr) zZ730JIn;?AKl(MmY9jHC+w7Km#67PJ?S)M*ZMykU*s5!L7S?e9-%{JVpYM!Yf`A-m zyI{np1iypHkGb-og&%w3*0@a>ot1*V6Rby5kUePoa9=NdWNT*zP!4uF#z;%tjV4tbOiBJ617zSqywVp9CVCpVmhOZC+Wf|k8Ws`oGJ15^fw;Lg5-s_bD;68 z)nH$p=(~3nfI5|=p81pXLrKbtE{^xX9I*5+Up}zqh~h=2O5^1-HD7;6ko9otU~iwI zQ1-xw_vTbJLUY2_2O0d9-$#qRDJjr5M7m;SnHx#d5=$++*vU9QCI1Gh)WER8z@H-T z#KohcLvtFMTY3UG&ubn?HfqwJ*DKWV9+RTaMi%%#)6RTXI9Fvi+_)i&OVF!&)|$6Z zYcr`l(TqIx<@i3Se=EcS<@SZEiWT3Rr+Lf(KD&&`9TR{7F6R?Dai&FQ^H9(5)=?WS zfm0rOE=3r-)5B*eRwXyznqlC|4m8yVy`*;M*+0tR*4jp(T$T3pXvftCrMF8~&gcvi zFq$>o*rHBbDQ^(ftu0nj-_S^NlJ&H>_(4MMlP0=UpVca(FpGVKFKs@Z8nyo(VC6)l zN<|`M#>Fo@>5v@1WZh1PcYXrZcQWZA22X6)>zwKuf@_>Ey091Y)oyeh*!03!Kc%%V!oaiB7A`s~BrIq>{l=k?h}rY3%D*DDQr@MSYG|`v=gks|#T&fwM7qhvt`z~LJdFaEkwh`47h*8M9 zYKUG-Q?`b-Rs?=|z{CzjXED?t>Acxy*P%F7{q5lvy}I^)}ob2tBXd zY`DQ!fQ=ddmhrCTUbd%I-WJ5tsl{Mo``3}eFKx* ztU_;dsIu$|^zU-gO|D%o5fLIVMJ~&Gb@jl}b*r};zC^R5wKMLtPy!B{#_f6DEkujD zZRidGA2Qrvz{Pw_s;&F)Rs_n&O-V7{{<^Bha=bbBJGji-)!F4f{v5Ct=ku&Do0>i< zM;4He?zSV#F}3K>;~Q0%(34t{jtPSGC@+9S`i;{Gd5G#s&# ziCju4IQgvD%wn_6gW0>zq#5(3HGR(lB!V;U#I6v6(De@qmgxci*wU#`f<39svJ;d{ ziwzz0V=3a&>M!s^s;wRB@u|G4A1HT?*q~*(DxR7Gqld@ zzt}B#@}pGvk2sJa1KK<}(EmMb!wGXK4GI zaEp!)UpCq?de?7g6s>rZd93!X%@9*$#G;5j+fD`>v`~@SI**I82{C>S>bnuMi~n2@ zXhs^}B4Eda&jCc+-*)GWbq((h6bPzKZ!0vm1z_-tNOcbSGG4|I<(sj_Yet%;4pBnf z$6wz24xg`rM*Rl^mFQzCm~9yI=8t1e?g!lhOaGxBE`)-f7^BR4?{sY~OANgr2oU?4 z-@a?r-IIvlp&spy^<+Y*{^Hp6C(jui>NTBxuTqc~+nGhZLqqYF=(?3=hJzRhP0d&< zuv>X0>VOy*b1~jDu|VOmJY{#cD+|#2i%fL>`j)zW4)@{DWg^NckN>cm5_%>cYo=-0 z?h6W4@mk48B?YN1H!+d!JNx>s|I$QKgT4F#1R{5s;I}))ggmg9pOMkI$T#9`F^b2s zvbr94M)8I=bLH9v9vV6w({#x6vp68_A~@BI9*Fo^P#!HgcGY%v2iC` zJT1@y;%nUsbz-zh=7c3w;=+7v?1jBsueV+cv&J_7BoJ~5eu`ooKi&W##(4`4s#N8e zm)dR)^k?!8h7G;hIoX|0#_z9XFzUgoL21x-B-`jbT#Z$!uKKMtk;37Ra^~Aqpq#Ir z^CAW81g-|9+ti7jN%{p~B8hejIA5H%)6%FoKrwvyq{2qGio*Hnm*X}Fgug$$o#x#P zmVPJ+XU!D*G*IgG-lEPmLD49e#10& z4d=_&J4ZV`x16=;g%{bvQ}ItH7f^LhOhkI|c>d0cPS@%RxUg2H#mPfBSc z!%l#luijQcRTU9ziMh1=?dR+PY$QOT)zuMSf2{YwgXll3WRYaW^aTGFy8HE}3kB5W zx!!wk2C!LBM#g@}k-4VaL+XYf9Lnf9eP*}{mh?z=XRyT2g0MtOxgW#7gMawakV`8_ znQ=LJd7}a-apgP({(vG6ym;XQuI{u@R9(D%Lq}fE4ZKs9NU8EB0JI41yVl45U;!Wj zH2)3)qEsU@?rfw`n}!=P9aq{q`zUWUC9;k-CH6&Ad87wHu8!rmH082NsRELYjq6AwrT!@FVo?h3f_+%v$H!n{be?-1S+{AmO&+Y zup=~OqwmK6m&lmt+$r^rPxH=qCqd!+EZsYGt2Y)TvIl{Dq?qs_yV!0KZjANQQHi=T#hu#Z{ZyE_i*1 z`ydxQ>k~SQC4E;E5>hl&KFTuF4DW1+ZYVPs*DAIJIAd=*yWWuTLRfmU0qeh-8+d=mcJ_LuA~NQpj1C2 zjXRy|DvoS>W&f-b+wr*)zC?QYj!nA{HNX|bAy|F&1VfsJ0{3~ShvC=KPPYZ79dki$ zQlsgL*FtuVXt}@0qAV-PQL9<|tze#Q=1v}dCsqrEHq8UIc+|uwI;zcFs}_mOsuEor zV!$&+$W3IuQ+ucUqFVp%ryMtv{fZK0$;Q=zLWr{gfIwJGbnD!Kf`CF_=ZAsVLSrhA zDqN&sm&hNwmbdst_|6A@sb6$`aEqk~8RBn>Op8?1&z^%x?VJ^q^jBjw(amAfSN0O3 z@)XBaEARHQ3`dwHwd2D~(NkT1jl-^1a!|!Jkpb*4<>`i^oYiZB;&863GtJLh#tloF zwEAnY`qJbv6LDOf$P>{cbzCIk2vTRjmRwgQ_UIF8`rAjmw~iJ!W4Yai&evs(<i?aN-8PIQ?oeRqV`8lF};Pjrsk=La_;EdE*dS{J@cp<~(!ng>4p_hbnkvP_#sr9p{ zZ+Wizo97UMlL5;|0Q6K*JH!(5_!b1k7i;SqLCd#u1K zBEgMpGEyQ!w&bztZ{XtNYs4n_0t6=EA9fa|T$uGuSvj%fi?VX<<{!|Cr5k;@ z45~U%%q7#pGN&cshEvE(?WXXM{9_Z!x|l~q$jmmilp1tA)9-1geCzVl4c`Y_9&v#T z2q$>?Fy^}l)}Z9FEvQ*-ZJ1=r*RIP&W%m`;EQxxCo>!$*kl3s#;c(LBqSZP^sT+ZH1bb!poRF62Ni#1hlU z!l>7!1ZcFJDHhf~eG*#vty(Z;X~C?jSb{c~X`}m>;mu7ly38dE zKL*Tbj;CgDwZqKir-OfVY$;p<#Y`>VV!j^%x%@d^k5tF(jO>_jBRF?8o!RgQr5BjwFA2@|zin%~ko$s*4SPI}CaY4lI_W0^Y0mWjYVubrq}SW-UDR-*I}KKwS0C%cBf z)Q3hwCh7vQ@pd<5*ZR*F#sBbl>@DA$ugYK@n>phvn;}*r(2mO`C060}Hi*QgWMkboL+Z96z zK`#8C43Jf!M;Tnx%12x=^Hizg1nnrIS!H6T&84}Lo;C68zEP`D+SaT8ur)_R_q1sy zZf1|htOLH>cT+1M_(ro)IjTY`RgULU8aSX4{v%)UUA=u7A%HbF==UiZ5UC!Yg$Kq()S& z`}tNGYV5tN$_B*!HPW?VdX2e~dusVK7mpdYZT*ANS0NNil{Q57Bt$XkFZVw;*?Eky z!y6$StS3yBswX`rLhE5F1Xt(g?lPrLGAX#=_qkle)(@3uIwy^R=@OWJjU>4n#p%PK zQ&ru-Se_xija42oHzy^&Yf)|Fti_rj{A{cIpU@Vq;QF6$+J*onF!m;JV9Ami3;&2M zc%JO>EguFZ0|AkR9T3^KLcS~tmLiLT_6t83x}QsrxdJirJEW3#B~hRb7akp>qx>Du zBbN%gheAt?gG_o(yai4kQRcMUcYmg@?g(Y?JhOY#Qw3SR{xz)AGTG zG;h#kGtr>|ks=aU(xAdBUZvE4zJbj&TY0o%-y`s=ruorhC*Vl;CtL12Rjo&$Q&CS# zi&&Ptr)L!hB+>o`Ul9j?@KA4@@kUjwiMtzY($$KE3Fig6#?(wtXL4mckuA%i7oX|y z;H$P%L!_Y2zMT!z^hXUBz+slRMf;4{-)LoD3QShz$j&V0!Box|R=LjYT=->JqepOi z#YX8?^3Zu+3h*_~aI-Jl_(A4HygUSDw{Vpc6i@qk(j*q!LrhMT z=~)=nc)@`*uS)d)Bv#IZ{gu>h56#=8A^Y{(OCnO1{;X$H%*39Ja4gI+AD#kI^oTt> zCag44>*@4g?Nqf5(F2!{jR+#nUIkH8Zl53>gQ-lAs1@~Qa}z8OIe;$`eQ)iC(&t8% z9!*f?_^xl~#FwM<#@}+L_Un_|+Cm@2%zO?hE9kG*GT}DRINKhDV!PrE3pcgAC$b-X zq%R8iuKZ|s9rP#^>#5XIu1`e9zVW~74-W~XpL|!K@25{Ao`{vRpfoRD79#tTKd3fS z1>&?}{fBH|xR{^C*CrPvSR2OzTnIEuH&X?T5k=mzT^kuCktTgt)fI0^T&IyNmn)v3 zHdoznU=I^B|Kz^`=LaE}#5hi}h;tvT`DSs)t!4b8S zmE^g9A5PJ zxBdhc&62io>n+o{Q=Iz6P{fvpm=7FOxt_Nr^K)D}AzEzg?;XUqWtw=(V>T~?_tEZU z-;l(fyuAt`-!nHX0tH0qEoObBUL6y&>B%95w)D?5nrX`WDX-Jnx4iE4{qsTJ_o z9rl-d;v;)CtawI-pnS_y?IeF7Z`-0BXz_fxta+iE zXJzARgkTiR4piHBC8kzbh93!9C)JGEMh7gtdN6_SbT-heL##KR%hr;}Xr{k2; zhoA2PE`C+UbT5K41CM_Gz$Wk8g0_U{BVRKoX~UG6lfzr(Yi|;wRF!T?@H|`o@KTrm zw@Yb?%H}yY2{xE15eJqXR?eyRX@;&RpM?bd_qGIIv+o%j7sKYC9yG!i(qeBr-dekI z^q#YfY*bs;kqj07A%p1B*IA%)y7QKOtvFsLK~;$@HvFM5OT_W1)7ES_NRekj+tYAD`p6h56C8{wh#yknfQmVga`STM?OE~>P%QeZMYJILif$2eaj=$?yd|dO zHQI>hjTX zc>_}Ny_Oxs@jtSnqw`~AZISD|OW zbM#<%@b7Jg|KY>`ry|t<-^i%)v9D|47aMif@!S0MIwlbsNk%>%3o9dTmPREQmPxy5 z`3+#e>&bIZVHO(Z-cm?PC*bSlRo5>xJE?IDcxnFX>Qn95q8D2B zeOF;4etr0|^f#RP`2$39J0~=@oye~;LrS0V+t$g!?r2ze@$`cxqUgCfRatLaML+yN z-prDZ1grZt>uUKE_Z#lYOY13-JW%<3pEFxqLL+`Fs`B7R$L&`>sfmXuzysf%;>|aW zfw~q}2qEG8gg3k1ExfA>-TLJ;9VL=MGh)=8JFvJa6O)ol`JQ-@ygA0U*ex9SSND1v z>RN)=<3y6mpo#QeuVfZ}Ja~Zdoy~~va>b&IhaqWad|?$$4UHqunasQ7$dz=EuXvd( z>A7#Zt}rs5$4zJsuNhZ04VRI9d(z4_EJi5(m;?fO)|5h{A5jRsnY&hkmaRaPm7^0mp*+lj(VphTL39XoLasA(AZBlJa6vR6RHG8 zKNc2R_)V5B{?w@0sk1rK7j(``qsrD!{xV)m9{;Nk$F3Vs?sIh zm$%W6qD)QZ#+M7P_`tgFJ5V4JQvl$=ws^|}!oEt@dlzKvBav62w9?Idp_ zoz^#G`7unsEk8;HU_C7%8!hC=eUfw@Q~aP?=v||`NCT+Ti^~-Ad5CH&>N-kUa7BA) z^uK-`ofF5Q<>WLe4a4aDp4Q{0js#m{Gc#-cgTh%01Jlr%f#|B%b?Sl(UHJBQwI>n- z(SrEI{D^EzjL7%cM56~wE?US1XMZ8#!~s!!Rq19LzvYf&4d^qxBoWt+-Wv46WhSc? z_YLf9CHcvwR42gg>p{1n_t=id(g`!o6D6}n|=BH>s0<)R+DEB~QHfDdEoI`7jsz1Z^jgI!72z4DH}kYnh2fTW!bXOs(?6 zX>aIn?@SGw3a_JrLiydBr0Q6a1_;7+uL5H_sHh#|3sa+H;puYY%A=>V<_9A%Lf=PlEZOO5j^o6=+XzSVL>u^Xw{$JwMn|A0xOg=?XmDkjc~E<5n2;gyR&WS z3-@u~!Z}n0z4IlcPj&cfz>yz_-VHj%aCjo4@T`rGrc?<3b$9T%#fkSe2)rk)wy%}5p7&m_e7K!W2UGN*lcWv7w}{qrU>a*6h$;FW8!p`7zS z9iIru2CjozZ0NMqthJzI^ASBh%+t2TiP|chc9u)Ru zOQ|;)7_Xg+wIeVJWyyrjbWcCX=~#DG4Rak?WQ^t3VGn7^UTurB*ddJ)U1E6BI-%dA zUewripf&X7LVr4rwWqbBumu~NZS^rleQ=rBI?zMT?I3Gk)95#lTt`OwusX>42>VwT z|Gbu-OneyANOmMO5*%+jR13rE{kMoK^)bbf!y;d5L6a_#Vf@Q(LdwpXDfO=&+*V)O zj_ZsBjz5jOMoRj;INCU}<%KPp+m;3GEJ<(k?m<}IOP;?J(T8U0+3LU`nPj=0>1C?C*A9)>I_^?I z&P9@>);h4%f*gKLAc_5THtvE*)s1nK#4o}KQJc@-2&)BT%0T!dlqbwLm;=V{I5;B zfQ?V904J3;)*lFuLVMrhO7p?jppvK|N273?ai;aQgxNz7z&-zebcJkQDn+YlB*_5|#4q%SE zBiH|NshKtYnHD~N8Y51haNhPFoEovhMQO-BFSruZ4GeWM&`WdUI zNU)oknF)%Cfy%`bEd3w<-Cp-+F#pMvgh2n?B^KIaU~djRq1m27^QXQZYEXg%u$Gah zvu3579nkTpBmnHVBeT0KC+<(GKY8j@`U0&-zTEdg`F)fdQX_=B=08{f z*eViD(qr@(KSaSm%q$L7ED(_{>V) zY|&rs+V<=6oPDvLfl4|GaV+K4FK(Ud&z+geO^bz+R^wKC$h$pNv?e1cvBnje;Tq>$ zV26a9w%2X+8&Q(~OZOnWV5Ep0DOBcaYK3;+t~w1@+QmsNf2Qgi9lc&uR5ZD^l~rD@?d9b) zy*$z61b{x5E?x{j%csMUvC1J2|31SEGZs zq@GnyPR?oa+i}VlGw+49Pc#K(=VHj^?sx}X-8rUIcwS}#e)e{Tg^0q1$JtRK=!CmD z83~F}j`vm7t{!D*UZpvI{peB6(|;UMxGz7WaPG*vuUt@NIyuc=%nlW^6}F-0gyShY zob%F7?b1SffOBd&VWh{fR<^J~O%yi5Ha9m{W{;9EsI-l_Zcrva+mpsGWZ4;>o8~9+ zFb#*TM#l~e=un0TfpeJWWI|+E#=)3{4@$XRaLBW7#ZzwsI9XW(Gmc0dVm`enzLDY- z!eO2=U_uA^9RG09pUEl(96AbtfFn&$FhqOK`mEulWpsAj5GbwTIqFckN|;aB;c*S zuz^DkEK&`$?}M}Q06OZD`_gE{=%_K6gVP=CJ_XjVxbQ*g9YI0CtPdX)=NA?#gG8uc zzP=6T&YxGhdpD5s&)M!2UJdDuf#A^L(HduVe*PZOFlWyHgAVdapi@YFiR>sTfuu%D~^wkPs`Ad z2dv~OX$RLakf$BwdOgi^_L4!>lZ0g1689k3;ZzV6C%TO6o;a;&DoDWRr=M2t0gf!IRf4nKA-AugP^ie5m>I$p zq9ufZv$wam%yHrl1#grr;i~NYp>HV_{H}r_IZn{uhz4#*w>g9XLogeKZ_P5yEiEyw zJ^kbJ*)wM}qtui94;_AO(n5boLtg%*!f}tox0yeU`QEF!o9p9un{qgw+4EAenu+Oq z%2NEs!ozQ>Ih#Nb3IzufLmxhAYfmVP5YB7IzdKozD zfvo;nXu$2qh!v5!@&;u{&cvz-w&C!ZGf#y@jT;L(VNo*30`J<5U=sv2v zeR$fJvPc)t{sMmKv}!)Gm}jliJBb$@e+HhRwHocm%ipjb*@L=<2KR4kZT-O*c#^&v zNVY@6Mr_a8YOX9%sS)^@_hD!Mu|%fZ8TXHW(J`*iYtUzAWesh9Gn>>tieIIFRhw%R zHstCHfe>97sMJ+fDH?T?;|Ceo;&`3P50W0uFbitXJ9ZzlgsNKw8r;6tBa0J}x_Idl zw@U2w2;dv-Xr%%RTEdv(*i~W`&CRnA<jxhD*(YfZTF&nKhp|)Wb=S;oc~XqGM&1 zKm~TV$JAikzI%dupLK&W1(cUAY;HSmpJ6}Z{2rf=_j?u`eCzUBkE!l#l{?8@p5U@@ zrmmP4@;)u8dN82h{IELY^nWN6CKq-JF+C}u7zxOc*JER*ZSC!mdD^*NCw~uRk~N*} zO5#NOtc3`RiP_QKdJOOC>MC=_sBd*ZNvwc$!sT`pIEZ=|Ncy3xlA*tOG}h-U=7Gsf zr_c1x=>c|i!u$tO6Y}!kdOwlwzZI-5YL)y;*fjLRE<3(?Pz&ADjKh?H zNzdCN)>7J~)=E0hQUovn(gy}ytYLZx7mp;1!V;eheSC(JxM~ez0-udReL>iWa2STr zC5Dd9$;r_SyLRu06gk23P9A?jfZ3% z^72=JyT?S=z|7{30{ZVQ*2+Kv{N5ePZ9R8@XVJ+!nh91i!=B)jM4%B6Ac36Vtn}#D zXE_azkxe}&jt+l%dhJX1>5nxv2BP+(T>SOR&u3~F#q0qfB&Qvm>wZrv74U9X3RkEF z^-@a0Gq6#XY^6i4sC~4G6|P5cvHQBTK;vSiHZPH1EPk1_t!XU^Q48l`E8 zt^wQc8h`1?=w?G)z*)#k_H|icN;rb%2WkGe;Ad1su`CzaDY2p~aZV%l5u6_Cqbcez zcAcKzbbwLy+h?zpNd?N0=k=SDZ(}hs92|EWcb4kTgm44qiCt-YKTz!h&HR(Rrv|2( zg4Hl7!EIO#RR{_}J^ln(S$lK?|I~$3uO2r0CteGY9UB}IqEPwRx8>?3vQ2lUCw4_a z+zCgb`iq}_4cW(%Q;ppAjo|)LD?Ne*3HGop$z<=*%tFf~6YaY2(;#q%Lp_=mh#lpq^qV0sI8#0DxGfG*K6>Tnkdyr9@OP#p-{h)P8)x;k19cU;k;xCE#&qz zz1(M;cFd7v2(#3C@*&9Wo5TKiYTzf5O)~cgJR~hGO>smg z_I+LP^nuB`X&!IdHCs52^`!!qnXMaboZV?-&|>7GQEpng27saR#qMa$;$E%;7H3hC z*Z}y46W?ERj+B&?)e*arggZXKoWuh83@Grv(5bKVHEoz$h+hFg6XZ{o7*YG zU1PNuAT_rjc1>-fp|w>}+;KbrAHXuwsdTGrot9?73fscQ)2oB ziyLnZtDuDS`Llq>kgq9rV#jYCy6tg?;{P8;n)m_(7>gO4r?}l+N}!vOk)fL2P(9|Q z(w!`xDXkNXUj^aDDj2|+(A-hpBf|@W!Ax5c%?_u=6}$0@$ZX(z7qeal2ZyfR!AN^f zmK$5BmoKO*t3O~0a4y~19MSrj_3|+XCoU?mqhZARH-M;?{YiAZmui}v+X)V8FddL? z*!~98J-{)DqQt!WysA^L;9l!&-<6;+Fo4Op#z`U7pX90iz@aUY-3jO|_R*b+T%gF& zz`w;ecRBY+bIOu;%Uf1v;{$SoTi1AhkCq_2e^T2~I}2>?#O6%8Ud!%_kJ>+}$5j_) z8oh8EZPC#_>=&aVz16*Gfx@h}OecF;obtZG4h8?5OEvX<47|(jPtF^&u$jv#RbLzZ z(~d%ZW80@sl6P?DZUODUUby1pNZfYyT=`C~#?sK01bo`*4585qn<$&z`rXxz)rAtc zVW{}Mqf*teV!W=Tr*nR8T6g5-TOJUau6lBaLlZixnCyC`8@#@81FOfOei2G}`ic1C zZ}F{dRYoJ;#{tvCG^$XME%aE;*^knLaV{DKeiJVNdAFQr#6-r|ci-GOC~1;Bh9JI# zJ$gZj>OP;KWt0jBiDdt|?w!>R{>q?Zy#_hi*$K_P$>Pq_AmGk&`y}cWt zwNO@n7b~U#M4R}uE%lhisid;SfFgG-r*0qLUcS7(1xLnbB>fQw8ITw91OJrALR$ej&?8ynhF*i#gFKZkAa6 zW?sTYBiC;#nzE{^&iY|aA?lptM<9>>bhj6pv{m6!10N_BZuvGCh$=y_O=90b!O&w14rDbeC!FwXc3%y&Gyys`DM9D5t%OZa5+2T08 zs})3`35HAoYmV)kUd!X@@+I7YuPhpGG-NeYgMgv7Zl#sI-)EzFM6Ncs@6p6QX;A{> z>)-!4xSkAQ!ay6y%H4b7cKsI?8v{(2!SPA81VM$%moHaPAL$+b`SYi;j!v{-RYqoJ zc8S9;n~$L+1L$5M1WZ<`&U@Hn?TuBjWDX z_U)Ur@vn}<@R<;ZuJ zS_3dIsA<`^WrI{*{e7n;v0}P_LKI2|pJLPKb*)mKpfgXeZUkac$B|7QX+oxreueCf zwz#M`dmEfkaPY;k)Or^c(kC{wutrP@Za~`i6a#o5$kz}ihh2Lw!K0AdxAw&?($vQ^ z!AdkngpvV4PL9^OYXH+5vy5tw;jIihEKp$#B+n*j2!yIHqXnJ1QISqp%cCOCf*{~Z@~y^337@fZsR_yT8mB~dGaAs$tdBjs zK1|Sqzw`*p!Xzd;Q8LM&WFWtB-XP~6OExvt%>pv^pQO~Bn10tHb=YvMkRo_D!&6d< zj^F@sGn3!nj!-?jXh`w&5$l54$+S6oC2AA95Rf^eD(rXpi6~3q6q@z zD+1u-ke4T#1NzhS&Vtok4%knZH^#*QWp0ZZduAjAr0T8fbNw+tObiVZ@i&# zU)pFZtf145-&0g`jRrjFMR4%MM5OdataGmslreT}ht@?S?pkvm#WAE$(Nmm#>VD9^ zoBJNDrC?a~p3fTP;^Ml0*u6(;?VYfws4eZ`$JQf5LtGj%TUmm$AlX>j1@1s`7q8rJ zoYMTS>6HC9@*!Px!k4lt6-j-2*R(_?CH}sDDw;vyY z7}QtSv`^Kq&7?cm=6(-2{X1aa{n?!b+s|`@B0-d#^*?E3VQY!*Yyyh&#y)Kx^Le?^ zA5p!T_bRC&0u_9`yxPs9+8Wa5FH=@k5^!WUl&9li7eijQ7SMwonoA(9S39v#tg`N} zd>!+C^Qx{>OS&ZYD-en-s(g4?G8x#hDnH5C@v&{zB-%rqkl$$cb8eX)$%0NH@j>(+smDHn z5!ZATZ{NKeU?epyFDF=~YBrm;9+9Hng0^{f1cWT~OAGohC{dL5TY$l!n+mCM>t%~4 z2L3$+@I>>BGTym7!idwb^)t9(qh zQ+CnKQ{Yid!`4&=%7}dfo^k}?i}&wPEa008=z?BxFXA^4QN{o1*j#XzEK=KwY!H;> z_hfiXO!mt~a9oSOH7)6p$3=R2`Vk68BLh1G1-KD{PlQ+m^dkuaGn}0Y5D9hPysr%a z=bYZ`4itan@j-t>?iMfV6xy}+6O*5u>pN9CTZA+B&1}(O56QYz)3gl%2j)7Gu zBi%Ps#Acn#2ZBSLF4Ncu_fwH+lSr373Bum=iRUSt(=AYcgmlBvl>1O7$gPwrUU2Nx z`iAR)1j?XdAzHBKO5ws@vGn9kZ~PN>bA3a@{5_7^*w}0W0j_ad3(cBNjRASm_IW(0 zSgj+#+xD{2a+aE?$d&TLMUI$4C z9W*V`e|Dlw2I9z51mZ4+JobYXtP4KcU~RwC#O-AvRH|t*CdY>9IQ9wtT|l z)GBeqXthm@voh$}=`&PwW@$@j5MQr&F7{vXeDWw1@Ab9qC|ai@Oze(3C;JrU=x=Nj z5{)-@huA?pA04w}YcV0lIn$ta&%)BSRCQ-JKq}(XJ@5Cwo$1Xz;jH6|n7Yr&u@r%c zV+tRtp!0O-*EHDdQZlG1(W_#r<5Ej8sm3#)9Lxls$X$O4h$S}!e6SRQi15UF}TKfRvo6d(Dm{J#BJoxm$wq>BGs zFQ+)|hY&DPxuQa6k1|jSJqwz6eq+~i>fw==s@skPSCR);`tow+C}doUl2>~X24;>( zv3&d}1NkV{6&Rqs=ykxM)u%l*POu7v)>Eq4kc*!$E{}rE68tz*U=XN&@&UMB!2QRA zB#G=GtE&!!CUh@_^Lf$m=pPR>1f{N%Cn_%Il@kuE>~#aWpay%#0@cIE-o?VJA(Wp5o8<@T=+ zgNP^~2r7bjW?VWk%QjT8g=>4L(SGV74!QvP_8HQ7j}W1ST<;f z*k^CW|1~2g-bo!xkqk;164KJa$Gen%rKmO%fX#nR&Xt;-?%EtFo*wYje|>*(wH}=t z$@i4iDbYqr4eHjq*rflB%7P^E1H9y{YU2-BhaMu}QmM^4R^<#oMtkB{IyN?z0Tl;e zeBGQSgN>@2i)J6+6z!{kx-&GNI}12yb*>jqT6bNppk}rIXLTh7TZzJEpuK-4eJ z2u8K#xbYpYzCU?o)~-T^s^{xhVyC^vZ)5%a)Bvjo3=Nt{Xy-zn6uzG0H_%w!qb?Bg ze)pGYPdRTh)SQpe{Gbk7c4BY?)UDA z4wP7o#5YfXUAS*h!&ox}m)#!j8vOw?sBUav+9)O|Ohon37Jsw?Ya0cIsi>%oH+U0ks;a28H3r_7os)Ay*)%$E=2vTT zDSu$Ue;LRZ5Fw+lU|Y-NV7hPDgP1a%$ayo-IP>p1cQ%f5Yh($Y5N3vdit5PDPgovq z`r)A058x%U#!BnDt$y<>$ZetsxQFILyBZNcR!*u6Vz+YL_pbUW?*)qt|T4@c-X z?>9d}^X82E;wiQ^bKc_tXr|j#D1%9`Cr2=jtdjkmzB+$hc_>}gri-|HV}Z^&;kuQV z)k@8JJ(;_{UVSS~qV+yTUZ!p4`PaYR<5@9evA$5YbG*iiBZ4-Jbx-C`Kv)D^Tl5wA z5fZ&($X(A_1GU`1Ywv<|e%=00t*0Eub=kNu0$#%|r{g0v(Q=gkG5azkwF=xg;<}RLEOUKbv6B1+0}Ia-ALn~91OQ}^ zlS%uGy~A*?3sFriEx;+EeSF;JF2@AB$nsi|R5FR(E~=aR$K+WPI^tzv7h|-@qCJWG zRj$8({t24vo~N%X-pq_CWc=NP^~w+Lsdm(LO6TCUO~2lvmU~5(V;pAI*25HJV(t@wFh;R2(1m7zt)N(J zaf1M`Rr_VYo|0O4R_rzK?!+n&QD?K+cmG7N1cXgi!G(CgN#sczNc0y)1R=NoB%Wh; zuGtsPq80x*PwQT=8uK+?`FVHl}jq&+wC+Tz-pBM0NK*%okD zdB!$obB1{Y9?>sY<0HEJV3*9{^6Ur&)^-#CORb?pc|OJ`Q~aFl>_rqNv!w2NvDaeM z;CDA8g$nrNz3nq@&RX)yo%eQ^>mMJOp9p+mFsv9{`f!((Xz`W z=l3e5*hdmF=7AUX;?avKNL}lht%0d+ncnMOy)`dhvZUT?zmD7^|L7jxxngaGY(&1` zFVNqvhGT8OJ3jW z=0)@RGYmy7Ehb8@i^336o^Fmt9_vZoIAO2a2ag_E;FHadx-7O5Ac2Nt87hN9){5RY zVJ}5&zWL+EydW$Y)6qJ7^cA4%QrBWG9tdxx6Ofm(maUpRP5KP|X+VYp$fn0A_o-#9 znLXIs3XrpXub2_r_J5kkVri~;k#LiTvYR98c` z(8X}W+)uWn!RYPCueEP{ajwq)qV`K#_#-O zs@YUge;PhM4HRPsUx5Jf3)~;Gda^-?N~fHol6R7}tMsBfu0VrT8}-DSxQ87`ee2Zo z@j*6Xn$bhhhQ`{o7G|V?)5CH0>r18L_L1n}7X2ev_7a+2wIqX;K9U_h2uTn`zzpkddCG11@&x4VAICebmy&i4lC) zOkY44HpAbgI$KClebknoGgZm<^fp?vJup7BcdU{!IZLZ>SIABH*S@^GEx=%)`YzD6Hu^SEzUEiqpvB{2(M~r&C zI^P2;LKd2`W1+lU`npPPE!nz$Ipo1CMHS1S<2r2AYl5-pA$k(4Vj0rfJY?( zuK_(1eaC^h(Rk1eI8{&PRT7=iBTsB8!RJl|S2w}vo;qn!g2IoHa{x~(Uy|)&G`$Lf zsIZ62zgLu&NtwH}8nR10NIp(r3LqBZzH(8!s$Ke+McI@=9#eIKacwGgMoB&1RJiT+ zVLqD6{5e?DCc zfrf^r6|7Afs*UPp*Up8*W49*Cq(wx0#NNC)gViQ`o|#F?$V3^mgoRe#LIpsy+51Tw zzQ-V^AR-TRDI+T8c0aM_-MN9Y0h$Q3=kHsN>XY1I`*4|qu2VB6?6jOrHD_1P2vvt} zWiP31J`~u@?jhU8b&}48&(#lBXpubU>JdG)(lJv>jLvGmC+;7kn`b&zwRDG5xtsbxK%NQ1| zXF$RP(%7kfQUV}hlu9kfsAXkk(Q^X-TBAnR4PO*kw$FHA5TXsRvXCE-N`^3hG_Zoc z01a)^H)#ZGt!YK}sHUt!#92cKx%MU;Rf%PtH*978no)Qqc46AWkj^73(;l6Jz}$Y@ zbSNzLE2kbTh2bQ%4V7E? zb6=){!2lk=9mGIXp%4XX{&v9cFM&dPydl!5EIV7uX=j?nVmLPfU-&{n*L{l%C7|G!rXL$tj@U5pR=nl%1znaJIj_D$|*Jblc>RSs2K(~#C=Kk*F z=oNq!l|uiZ5lhjZW>lGuYD@^&yRBytP>uuy+(yp&;-emBx7-=`ZA2clI%sGfC{ucL zz9Hk-B?FEyU?xU)A_EOM+P6o5QS}6s32=Ueti36CyJPH9ME;DsY|D$2!=7=Qv?tVf zmFJ7{8A6U5-GabF{Hp8My*~K;C8%?{KA|gkWI(?A!tHcdU!&MKv>M2SIP`yiB*40l zm4tG7piAHYND)d9wls5nRhE{X-iC6LZ{J>KXJ?b`jh=vFIV(Fm5>&}3@1X(B8WEc= z^A6&=7WJ@wpkiqUizg1NekSwv2`WTzSq!%V{b9?6Ju1+np{0yMVY|C?qR1+Mcvo<3 zRZ9Enzi$C}02-Pb;FZ5^`XG%jXcM;S_0%U)2a#u$id#Hy?-7JPb}nSfro8NK1=i-^ zQ@{Gpu;fm`u<$D}lDAQQg0db!8h-(FmFwW#Ya6*_h=#7~(!)3)w(|gGO=M&wb&eVw zr9hOFmyeZA;BEs7UZa)nB$UVtiA34~@`!-stwc0BgY z^BBdY0c|4ZSdDubibN1xLFEUuIyxsEN{5+RrU3-KvUx&bsk*bqa~Yue0CV$_5)j-F zk5dI*-Sq8wt=?{Ywp( zv;P4SoT~x`0R##APa5ihZ5T0>n&Z;w@LxhVV5Dr>!v|e98a-$ez$MGZfEt|CL zDv>QAeuI)H2Zn{=wJuC0t>2f2P{C`C<2_F2{P$C?FT{(Ai~od%p8J0`YTmx>q)Q2L z*;UZx*i1Zhoz|E#s()T^@WDG(s$JO9@0{ZY|D#HQ(NT3&35qHK0B2=rY>d*ErUPAH_e z`MURFvsS1z>q;(bhl^rhn;xhGz;EAeLi^8V<#U295eX2UMS{LN$>)34b?3sM3QKzT z{7mm#Y6?nWX?}uy1km}Lkjo?BXo?C7PbSK2Vu5(4?fdKC#hR1pFDNMm>gxfDyR!Ot z+yY33;jPkaH8emS9BVd^fhtZwj%x=r+7ci$B7hwzg4Afr?+F$n3iVSm5PG881MpWU zhF2zmTQ);Jg%zbcLnq*SE9l<@TT;F0tMiAS(h#Ze_VcR z6b1uzs~}04L|!2(D{9QrIZ>h_+Vf*T?0$~Y`7v1e2LXti^@C9JzXldUoIeh`looz1 z)~GPJeZV#vY>VUay@uw`A!b4#PP{W7*H3Sbv=;`*=|v+7(gKhV5nUdBNL3r#MX9E< z=hpa)U?U zNg*tNL{~1;Q89-JFO+Xb%Gioh5F}9pZ^BjEs=Z48KP!QWECI)=?qdJf!*-`itkZ|T4iZk${(nyx&W+@sO8?1=KuzRX zy;r5Uz+@2wa2n5f6#fd-q`_Z?u}~27AV16~_5a5x5mU7}gT!$~Kt1^X8fEX0!L=hj z%6J(Fcf}fQhqgEL&KOW)Zl@HldR-ujP5Ms~;MIri&en^jH$#IrHR!%VQJ5i`cVUy{ zhA%1N1bkQw_cL%tcI}e$vsh2C|1S0C)QVogqnnVong5BEavGE}5|cTDu81A*-RtlZ zIsS4ZTi`|`S^(VzRFT8~cD9Rzp3JVv{QD6=l4cJiX&@koGyV_j4#M9}NK&BEU#3G2 zOhwlijd%F(LW&AED3x&dM@#@sm%P)v^w@VK~$5r>ryL$8hzuxMz1+R>l&9uXmz`~T$@!xZOF*??3Sg)m(Y$!U(FpVjHN%wVkDPv zr4#ZrcxW4NYxnAE)orbQ-kdbg8qyK}Y?TZDvN_Ma<@n9~`N~YZ^oU`@91c26b~k)E z#q$eLMM#_^xue4Xh44=l_^*>wezCD5mB$8W?AM9BW8M1nyAsOO=CY?o5Qj>K#v02W z?%;Zk&Hx@PNU+u8U6eY9h1`+w{yut7@`nSCrc(Why3uD)*4T1tPEn!O^%uVE*TdSC z&#ue%ewGVOJw2!udi;6hOwRqIeJ*;i`roEt7{3rYZ0osk^?#6$aJ2(tqIPV$w z8oY}CviO=Y_2LNvbb0%GL)+**IQwz|Sdb1U7Te|u;%Gt9xp|GM^tbMUtJY6e^iJNb ze7gxbdQQAc_Cn#6JZb`z>g+}4b&bBw?6?zu#<>k_BeCtW*1vuH9r*PWt?NhcOiukv z!0MuH^O{{UQ1|ZvV#pyZx=OL}A)nHF<1Q!rj7FLm{^d6Y2C~Uw=*Q}u$2fNNMHJKi$Y{BB^eOo!q_2(t z*=)rp@64oJmL7-h3gS*PuJ6d>t@ z_c;w6#6m2Ygl&A!3QC5kXOWwc9!B0X)#P9E%u%iqH(3pn*C3VAjRY(}xD3Z1jRz{F zq5o-5ZCfNafDC}rvm$-)9Ee7eP4z4+vT6A|GuARbS~Od)Ko|@1WQ#aBX|4VC2ohKW z@lr{r=Ro8m%a>cTFv4^V+t4zqh$FOuZXKPfB5;(9QWf2%|vk>R}pbd%8^ zU`u5auPVNQ`L83nxR|gqvf2d%<$tp<`x zz-BGSY|>_vXQ5aGHsrR#XpeM zmztQ60SmXZC8^j4i_4Pxb?48Rd!nizi{h`XM$Ye7innCdosw*vBd(RZFv|>PkH`E{ z`DQC#w)4BC6_qQf(q>3_h(tEhrb)P2C!OdKnr?iqo)poD=Cy^~kEEf37F$lLutZzc zI`dhBAd<_HKrAG)) zBiB?Kd=EdBxFMpH3h^MEGXx#0=Z8kRG^w+E^Q=SS#?8oTojAgjf_JkXHZdWS{8^S8 zpF@@yB2{L*Eae_1v;=o>z3vZYlYpuuJy3SUU6>5pj8_V`_cz>WkNWuWLr+|}21k%! zIJ~)(yKVF{(+o4b zI-(nutW#nGSohPrZhm%k#U&*w-LW9`{3^`wHaYadW5B4qJj?s0s}4-=olR}ka9-|R zT`eu3hzmz$!CYaKN0HOzf%bN)ENB@tZHIRvwxX;+N z=X;>6EMY>KWiLW>;2Wuon+>YHMl zc9M-}{AM7o8fh78c}_iy8>4)Ga9UeTTU9+s=0o}14R*9Dv{QGYbriIy^QqmU{JcAc zA1-XMy&_oD_X}q~N`I%;3|!aADTzHE0`Gh3N=ih})!50AQnmUK!nc&_=hI086a{ga zS00D^{i(=~4!5$t`Pd{1J|_9c@I#5prtZE=_*<4SQs!o5k+ojeEV#n7fEzF!+w+5L zAG{@du3@#G2G8v>_AkSi!^8LouFE)jX6yxiTUhU|FyV0L7;sKsmUqT(x^Wd)TwDc^ zG#|_$m@Ey3j8jtjmd0~Gnv+@#8f?e2>rF$2{W%q**w>Kbacr(C4`W(rb39F%P2kQ5 z3gdQx;*9dpRGF;7Dd(2fxlY8@O#w;}L~vx#dp_}9hHjpmj1vxq={lW-a*+3rkd2nzb_oNKe9OW>HkD8!Sc3TWY>5i7NVp`% zho2N}y4K{Qzc}7MQC72Xp;QWAHT`na;GJEJJA5M|SM1~@>3eNY2t&+{@PpIGYb!?- z{l7eC7$S!jkCTtmW5Pe_sN^3fjPG}f@91#*w79xsyF9aGhzenmB+}FRRxLl4j~SDK zNbmBnrj8+PC>D&2c>bF2774~&J*2@UaDuBGz4tkE}v>$bCX(j$|!7&S13 zoD{hDiY)S(m0%ujcF^nY=;#Ut>+6}VzP+P#>uawJL)`6vu|6u2JH9)@RoCYN{4{LN zWliPDY$TWuBcrwG$CgB2DJ?wRcuI(kmA{o!B*mx7Njq^F56Y88l6C0e@z{Aoo?s+_ zjZ4?FUO3ni@zD)qqf-n0la`gAr?v{bCeh-ro@D z)YY;qv6xl3mp6LP)V?Bws{N(s^jL$-j1Ysm&GcIiW6`92!DtM0=@W8d{~s!KoE7g@ zp@W&&iZXiPy29$Bv1a0(4rQLE(?*WR3eR_?Qk0jUxn5W{S5hQ7Qy#prLiR%S)Hde| z$B7oQg{xz!+xGmPzgslUsK}8RxQCzb< zyI%VnXdd2qyhXMG#trv_fc6eQjQcVz_pZ>WYSw=j zGxH~v*I_Vnbor{$(cxzrTHMkX)kwmWuZ(y0aA;gbQy&agP03hqeD>MrXP`&S8Yex# z_mDS$C8e>+N1T47kyKBnGqQs9+og*$=B(oitI=VqSYhyNxTSTT9%Wx$Q%t_igwDc( z@9t=E7X-^&$(E$Scf4l6CpBWtrbA7{Qk=gDDe=C0cak}N#y?grW~Wiw2O+3pYz>n zgj-mU#Vu=v_;t=?QQ__gyWB`a72_=B%9I~rIgw=+Wi+@Rf?!xkV%%YUGB2*nD$?kO zi;^P0Zv+PGJ%R2?Mp{FKL}YIyPp8BAs^J4%pzA4 zt4{i}uMCvNhVOsYC6j|idS?o%I9obo2^c$RKNl>m9@UzKPS=HbSPfa%ybGFO^{y3} zt;I-=372xlHywHuU%P!p@!_Jntx3ldVbf6uW#4i7x=3`k5$VX;iC(FnB(HSOx^}Ll z(lC0ha3ANE`6|inT@9=S^Bj)5!aNVWt=3Gx@HUu8!%5;rgYJe)haW$kT~jL`Xt2QD zk{PF6vqo<`)v+R?QY-7xhvIUqyQkU3>YogdWMOOsr#`0EHvc)|!TQEiSKO}4i0<+4 zJkG(we4%NGBqPX9sy=6&eSx3WpLUB-DgLbm7|!8nT8jTp#^&Wj%vMSq+m2U4G}4^? z-loOw9Za8??owdJ>8n$MBZ5e_1^TXRKw;SYid?c_K&kFvY|#UW2o;BhB*m%Dv(NIy zf6Ls{#Ca0{&(9Xa#=%KXD-gq;Vqu8-{o5|f!YX?BfJ;$Po&FQ8uO3^}e*D35ov})w zrL=5Jc{wi%Pi}02(c}!2NxCK>-C>xJo)Hy|L9WBv6^nKjgs!6Q0}pmNgA zwVTSEoW^Av-99*Qp-r3;MxEe9)b4t6X5Mb3WxoFdo@qTn$F)*J*^?bErXy@~n6W-CFi$>S#-~CaGU_rzEvb~YiKiT`_ZdX_TS zV!bo(zq`ES^wBZhGasLfP1O}`&i~6Wz`1~;bLEeslY=0PXK{)WbJb2Z!g)C>d^1>g z`ueBjft-LSPccqVD36)Wyj{9P`r7hw@A(4<^{IOfRRlb?N&^Gu&6YnuZ{8ga4@32} zx&y01K%}LGnW`uVi7C3iW$f=B4q|#J?62Q zS0|>qh5XK}(AUON3lD9=36hYjez`05$}FxF6gz8nT~XDgSKUT*$CcmD!o5#0gi&=TMUcjtv=jpSoV&rWg^sL8(~6ZwXE#g9`rwd8LxZ zs_TnfWJaB;>ZQVJt5)4W^?Ce+>r6k<->yYYj{6|HW>7G3X*!3{$@Pw8MTo%Mk%X02 z>W9nfE5y#{u{+BfXKxi8p3ppwP|!cExH4FiJUN5;V|Ssy ziM7~$yV%^KnM0*|z)tLDWq&$g>oLCW=XMbCfZ@2@!raRiK5P}+RR1JJoJF_c^z?MR zlr?K>72ZP3?f5#QouO=}OG|jb0XNq<%u#akOeBl!lsU9P=#i-K%HCup?0Pq!@4z~D zot<5nND$t2F@}XGH6Q7Hx@3`18Fg|& zLpzkiPx5ZnC%^B_w#yQ}Ny#^oRqI7?Ya96R8}7IXaqCCgUEUOGbk^1Vm>~DmcR{bza_!~4 z$D~~1?T|40+mFC56GjW)A*^-B*v0=;IU7;}^_Bg28!>Wiirw{OS%!if)cnCQNG_*a zJuAOI1=Ctt#5_o{jw#geJC^GEO%IJb)5~q_mb@?Lemak;jwCjEzy;`j-kHYkG@=#k zkk=fyd>CCjhDhz8RcF3Vp+^t>64a-!*kM72Lno3Q(X0*U<&7>%MV7Hhg7EEdTFYEE zEI;oY0Aij>1(g)G7;CFO|jsFgm#0w=iz;oA5H>ihPZv~$Eeye?Ac#O zmMu!!RS$Kkh$?*B@*#Y0SE22fkggM{e@3>>2OfDuJm^r7;eyme^l|3?7WYf~KE6Ik zo-}D57B<7YMw)xWym=}^MBD)J{W^4$KNCLo3+{^T(k&GcGAR;Rb~~Q2p1c9iRy1X1 zeX{d~Aaz+`h5{cE!5s{$G42KzD6QnukCeTmfa4tNswvrsLmzIgC_-;tGFBKz?{S6mjjB2AXy)>{+UEegSEz2`TQ+qpKj1aDlpUV7>+Iqu8A7vk0ES=9VQESncb zO$m|@mHmZNf8Q{ud+Qp?%FxOZ6&m*`lBa+aY9w1?shvX87m>W8aKQHJbnM3kvdO!3 zP+V|g2U^lJz(%i*rCmc(SleyquWH1qrDuwL=j`F`;VBM1hP`)L5?zgsy{;#;=}S&~ zRT{_009)8$&xaf*lJFc#bom_nP5C%!l?fTa9nhQw0Z z-6$fB<-Z&}ltwJkpKb=z>!EpVns^z`L%FepTrN*%i^S4oepYhkgM97pdH(krj!z#jsni+%;m1k~E}3Ya$KK zstfzywItL{Z7D`YFVBshkdl@u#IS@FUyaWvew&%xwiaeVQkZuZ^^KwlGWX=D4Bx7f z8|Co;EoEH6m7$K=BXzYPmSL8fExzTEE^~^hU_XYbt?0<;(q3sBXj|f^V5354E?znB zibJpH;#Ot{WRSNd*}|Rp{$HIa63LT3{q@C-WPYw`hv2d2zs}?Knn!wNje<#S0H~^c zU^HacV8E!OM1g7CDG*EY`vVcr&mo17p{Gx#D2_~ApUU4Q#oRx@TY=?Krmle-+=a|4 zIEclh_B;p1d{x6APp%%*cT^uGI|EDOyUU{tOA^hQf}Mq{tkvxmV5e3#K8&Nm#0a-$ zEf}q^)u{+if@!n5wrpvuF2{>HCfjrhXrbJ%Z$u;ut}#+LwpGGUQ~%ws{=fj6y{m)t z3|GikgPhRj!ji%{AYrT2H{+yNwf=`a$4oo`qQMtZzWK(q;-nlO>lRcfibc)yLPyL61DAPi8s~AM^WEFt$yYwqhVq@bk-HAGT>#I>s;pG zT;JQB=9!G6mol^Qqp3#M-pY@!aOUIPD%q66Yx`{qm&IzRi9F82)Uq+cY4=w)t%}YM zm)kCG)Aa+=bpsqB0$RgX>|WcBq}(0ZEDz^Od{@9WIe@V5TkZ?>pbPV05HUA;3*?eR z9xb~}MGqaVQN*1bz0Im{=yJHc$_MPI6B`Ly;elMbFN0mn+A@vM)+ zYNSqmGSfT{W)C0kS_2fy_uZO8(Bm$#b#MN zg?49sQ)9Y(Nk%XXhYhnD=Q@GlGmDw=*@E!)I?ioZTbV z-W>n-2qtZ-*(w@!Vf{fAoQbP#;~ue8p{G756feL1K~BT?;YEOobF4X==CVFy+=QoR zdKn-I&E6)SiF**{`vQ$xkp2l)9F{P5%kkdsA2mstLo?5IZSj0xyVq8z5$t|E;Z~!! z@NExPbBJAx$h^wC1##b=1{=QsQr$zPu4WEu&@679jhN|Uj{%Ers#!k9+^{Sl6nars z+vhr7edSc4O;}Z;&&(L*G0r;QPu+$eC)Kq( z-pxse+N_Q|732F?Px@PLa5q1Rly=3{?}!%acs^W!k?aY{7#JzsKavoe`M{gAXL6fO z9Wp$)Bo)aqHKKj*#c@u-j@Mzyy>$y1h0|LLrP`Kt_Ofs%<2(+E>p1I_)Q(>p@$T}> z6Gpd>D|hgW$EmDVtF=<>7kJ}s##sh8zTOsN!>bn}S-pB>N;V^p;m{TDd|bk9cq944 zS#`s063y*M-U5LPm22_|Z^tc7_zrX46i-JR2xE}XlOPYIU zo}?^qy>DdWIFBf{qX1_KNvMQoZ|zobG7_qOX?h|(gD!utfiFC3<{7%W2%FYh=)+5- z5XsFaW+1_J88%FCLU+8zZ5D6yT6B`x%6FdvMV}dBI1hJJIFGgefCm#xA6DGy!kMjA zs<~aB#`byH(|0rrJ%2!J%Bga{)K}5wpjQ}IV=`c8>sPr3MeL4|c*X!x)ngW-4!ZZp zrCQUc-6Ts3oPvFcTrC$G%we)i9635}M4Dc=?y7H18sfSTkzgd}^G*!fgbsyT#CEp5 z#lV@$EYrOD^bV@ATlHyY0dKDLkPQ!1X<>SvBLHGV5st$tq6PVbSQ}CU31(Vl>f{aO z-!ANwiRbh;4M_;2+8uXW=}CNze*Rh^ZrHd9X(0K7EXM<6dGzQe#8Jay&*jZhp@)^D zXn0^!#C)l5$j(be1FhJ>(yXe@o3yvNI<9rPZk)OL@70D|GII5hT7SsSy$KS85=}?J z4=n?6@RzOyKUx+FIR&X-piu=7d2{7s<(Fdxo;v9q__KgaolM@z?5-9q%BUg`xJVReCK;7wzyX5B78ZCr|HGZI<}NfsZO$co37 z{JKQ7ilqOx)`OQ!gcw~Oc{xY@)3Th-E=qut zZ1G-^@JaF|hNpbHb!P4q4<8ZN?>xW=*H?4?2GNT&KZ_fTJZRsD$s}!vU>$q0d)rwD zz2~a~C0yU7vkJ+HiwWs!d7@cl;TKl_?)h<_NA5@It-L=bTQPI;lB9g$(N;t)7Jkcx zk3FI42l||Zw=wksIy`xmLsL$Pu1}{=1FUya{kn^qE@wiDnjEQBf7 zbY+N_YI^EDX9PkSu-|6Kez4N}54Xv8b3;m}Ape&OXWmB4aXWL|{fD&R^F_T4KQ{D< zPx+kO67t+W^W6qJWnF$hk<;=D3V7k@#K6@m zCXZkj{$73Uo;#emT?KJ>-x{|&*zRN4w0fvUp0AQ8!VnMJeHDOB5#`*gUddnv;dF_k5CHK{1d&0@$3$;53VSv zJ~sp?B#p}jZ4kkgkB=D$ovcFy)+>g*=sk0o6@X!!Zs;zcN)tZVvGqx2y^&m6#|ZGJ zcPmetYY8S_&bW?ok4)xpN0&)iOx3YQLj|H!3bAc6&IxwOaG~a4gX{rUH6|ofz~OAr z3QMVKL-&O87S_^X^r!YGS663w>=mtvK?t6CfnXvnyszK8*=sF^rrx62kb)U5{vbUJGMhipUsA2&)JT#~0GIByJEw_|Z zYR_w`FB*AZ{rvqIviWn0hm|M;LDugjziMRjaMXt>Cy&cq;d%nEX`5VM zh5GaAt7)2FZc(;}XZ(Czw)X{6zcrk=R|(iQ6m#%29hNw67Wrm^^9DU{z9yqbmsdH{ zTsecx}x=s%}8^X^y- zn#aDfzb3D(75$_}%h&IMcjoJmiQQTCy#fo;m8yI)QaaAwPfHM(p7GcsXP?Gc*Z4Yr zLU$#U`=C2K<{+r4@Pu$5&Qdl`J_w;4QN4RpcjckfULCZ=O~zyI)`@}8gKDJz9`McWAmq@G2>lkZX8&#|G*2Bw`%^am#x7jo~}1q6GT<7<{jL}aTdsMx4yp3Y~j&y~$!45PK_u zxXR43_ocMLlb3`N^uFrol|EFT?qJej-oo~!efL>{O0jjx-cy1xtL7wIYN>K#-&3$> z#npJ61_%iAb%Jx{hutJ|RBL`XPeToxu=B=8`Ikp%GqIE9;Zr76Ur)rl<<=6IW{iXh z^z={p8=Ra2zxrHhA{iN#-|FV??_;Z|jxa<)9e;oPPKC&Z38|cV?5n8ebWv&h_pRXWt>l=6hZuJd}E0EP#|)!VSzdS%t&pMAnEQ{nQZuLFPPFmt+CRjBO; zz4pn@qkyDW{cH@&(~rOUm_TtHybMV1Lk{Xa z;rI+sv6GR(d%$d>LzwJMwE6m=(mC(nwtRigaq89L@98+=Kw%&dXY47awC?C38OB1I`kzp`c zpHpY}3`P}ui~OEFkp*|14cRG%|2Rmjm^IU@ zU%!PZzX9bkDl{^$1s@fh9Kl|xb()_Hz4H*_ueQ563bzwSn$~AnlXod6KQ^)$k!dTP zjWau9lULjA{Bcf$*`pnbOn#>kZZ0bg=Rd#oz;Z&k+Gl1z)kn)DxC;05BBKvGC}V!; zhvtZruDH8<$-1jj*7;kjH4+BBIPCb+NUiWHdSkZp&>f`Q1yo$%(S5Bcc9MY=8FSYy z(}aU$9y=R>(M5_B&0@Xb$_%GGEi2Y$Rj!hpEQ3`tE3Yn>>%^*Wx*w*|9gh#qIzFy&3woUPken)||xM_e6~&ZjT8;jYs<%;b`lJtcgaMOiu@N?G$<7f2?MBz*7= z?TN&R_F#q-!HkpENz9}1BC}mG!;()mThQjyWX^m;v$pulkl_-CtaL|2%!Q|1`v&_y zAE(8K^KcqPoZ74wYt7JOs2qkX^tmK1i!Ma7P%aB-HXYXOh!mm?PX((WTAR1 zqQWO9J2|y^TC%c7ZtqLaD;}6PA0P!{zSCjK+Zbx?c9xFDEqctzz_Q@7Y{bH`EE>fz zKO6RrGWM5)mggB=O7pp_UhTm6?Ax)EJ4(Ius{qY3%t>pLEfTRMR$b^~5YYhO4w~gfN=F)Q>qYR6^<}_f&!~?agyw3Y=HsLNh zPc?y*&8TLN?_x?>-Xqs?TQ;pP7FM_7J?8in>L0C8@a$+MCc8S2ZY7(b1I@ zIfEm-XXe^|2VbXDGnXSJHFO4#xww{&S9EoC&Cjn%8uAo<;U^jGWi=ElUZ@v8d4#zDWM^^2OyTpDTWV zRM2n*92sw^cW#N3Y!)W$Xf!Q0cr{%l)v>j((ck{!I^*+u^Z~@H{waKV7or>wQZK3g zKF(vG6~yHdCmg>mUH#djmdwN*V=k)bl-EDAJZcTbmU~{jwbqC+W_fNk=Kgwv2$HW6 z4#{>spe!@mero^1*|g|aaaWDqJ*{5?Jy1_8!9**17jXJvp6#{;UH4RL(d-(l`7^bN z7x|`TH8!UvRi*kp1+U%DL^1?3Mm%I&yfsxxgN(zgZRkUbUb~m3&c-$HRnKVOw6CS) zIa+V5V8Sll9y#!PxX-)+Rk5;BE8w{_cgZ;a##B6YJyDHc`Owsi8=MX0tUSa1T%Azo zo!d@rt|Lp$)154Kp&6)f{!zIq*HOl$r4&m^+z!GZeDCV2m80ZPx38~ZE9`uSEKl+> zgmcojxWjL5t8!zeYx#(rS(0LFO;sgcaVI-E>JL3ECIrQ;D3tl~r zrN#&1xNJG;&bv^{6wYF-8J?sX4D+#Cs&p|6wx?L!Ut1o;7>%h7Y;O$t44xcsjtmak zzfS7j*gr|Y>OibmuZqoh$H#Lgz(0uV4phciJ7(~O%Tj)oY74ul70MC5)pjDYc)*kJ z$CE=;cgZXYIopszabb!nS)a``V%kTl)RJH1=_2L0wSMtDQmD7DalbljD?t`Zt$f8v z)*6=|XWhR3f|Wz-!Z0OPU1LhbBllj@=&9DDH)QvZY8Sa(F2ma9Bjck2r$64PjSx`{ z>=CZEd+SvWJw1=SUsxz1;TXMLr0E)}SO4xMx|glX!>>Q>jehp8r?$u*Xy-=U(Ck#F zkcq7i+z=bAwR>lF)JtR0Y2$ts%J3!l?Fb{=c2v{|eU!0?(AG`k7|y`C$D)OG$nh14 z`hhD`=#XK}Z)K6Ipg}m3N`cp|7k-+q^in7TZGZV=CdFVMhHGcDPwVUEAzvnr0~g+w zVuvR@TP6QemoIrC^_o`lGTX_+#tujM+;NB06;46{PvcK`Sh2ank?>s%qHR&l>JPtk z8HLIsqb}rA&Ck!P#w*4ZnN69>aHo|Rl}FS~n4ZhD0GFQCR)M;U4{nIIn`SIfzKvyY zS-#tx;!CW?k>8mFT`~;OBE(j$f=B#XasK&@^hnLvQ+tKDM?*wTiIChgQSpTG7jCU8 zbiyDlUq*9|(lxU@9Il)?82f}ksbq_|Go0t*3b&D_Nqa%5qexlvOC`A8*2Tq?Oo!U5 zIoc(O&BSR$Zd5t3wB5fYelOsXpKXtJN8mEdOE0Qj5Z4hAE8U(mq^_2fF)LMHto~O% z=EY79hku`4Q{mT|npoEy?!XQ?tNEhx(al&hSV0Nt(W3Z~zi+}?m+z<5#f*%o{oh&u zEhIVDLx>KOOIYbp=A3JH&ljJS3(FvBctz=F=8p=yzx>ZN=O#zw600I~>IW2_Jl0;a zjyiwYoMJT{b`&UE^Mj%o$%XiSf932~oo(21-uC0mlDH6eDEc%Vm@}6%w}Ggw-1>*t zktZTbk`oaX-Rz+(7}>A}>3Wtv?jS@ZV+K-YdeeWvV47btE_hFncd?13c3DVea%{W%d{R?Z zD%tR&4;8)Md^7Xi<7_Ts7TkMtV4KQnz~1Yo{lQ-CSF^e~Sp_Bh9JXx1elR*)JzNv9 zOuWpd1Z!{4Y&+oJLBSScA~fJ`FS1jSoF5U*pR{6IZ;a^= z?_tW07d&-~6;4^Mh7`%j3T_{ix9{?IY7JV_%j5k#o;rk|ACQh)!PS-{H{WG*SSooH zl(@R2%Z(VodWF`@3l%s>QV?-L$qyhk5&5%x)9+0p4{A7AnricJHLNs4xG3$t@(RDL zY1a>w{9e-Lasc#AA9iw%UCykT8{Tm4!*!0N2?KKT4c-{!#fpMr%7AVC!6LGJiyCoI zvQ_DNFq~E$fgRz>QReYe;u!;h+Rx$Yc11g*`ztiR^3GnBn1o2XTdc(+a8=e`0yqfV~_=G{5nByOv;l-vA z!<<9Cf_Q@4n-^cMN|x zNV4}@vpn;ebIrXciMDgcD;=KohUBWG*Ct&lsOfuMlDQMbtG9e}*ms{x0^z+7w7>C2 zzhO`Lg(6MvjA_h<=RTjh+FnZ)oA+f}-Sb1PO_*M@`RVWvRpnNjp-3AiVxn8rb;9o! z0)o8*$!||J_Zj=ES9af)&Qj&IlB^lkRjieiAEDxRzyxPNUTq5eu<7R!i z4>5&(uwo9qf=I~(Pk}~BF1iq*ZYZ|j@ud^#$3SXc4_ zVcBQ6EK$yzzK2O%^wJ=-(+0ruX3{vM$A=2{lKmjg&L&XJlw(WAcQSusx3-J(Yb=RE zc$cN0tSvAQca7dTy08!REV}mX=HTaeW)Ct#6kaxt%mjUDQK$%{@Ad{*2$==IbBLFBlc3J?ALnXpqsD{Ra20xZLFAS-6^`T1vW1!jFaD zXk~*&hSPg-@;lQIXS}|FYi+oEuBGkbNJ0ok0&fDv4O?-XJWnbqZigcIlC>5V;l)4I zTZdTt!WUJdv()=MSGO3*an8-T9Adb9A?Fr^rhtQV#}~xLe9HLFXF>8NFDA9}&xR6- ze40SFTHJZrmCnI@{{@*2d_}k;?)&NN&5t4hp<^SD_OXe~qqWjeRlUlG+adbp(hsJu z`nMV+I0#MIG|t3Bp`M?agL5<_olVVV4I*t^9eY07C5<@QwIOFYzbdkg%+xA=uxt>^f{+%^iuW1R{xZ>`$V``=%vE}$xBD*FkCM|WmgaTm zqw0;zwX(p};gft5?;GOV6n@LB5Puy4;W1mgn!SH}Uy^T@-)r>V36nH0E7#)4(Yn&7 za~66K@r6Y<)BKHH{=qT}!}rVcC9YoZbUV|&Yq8$M8=CnN*GrS7k?49zS@FX=tyKYR z2i*#Kl+yfID~`b;-hc(k4p@x9%g*C50=*d6aavSmjCr0o+UMhU=JWY-us4i++8C^0 zKm#fT%BVerDmqhO{Bo+@WUG`*RJ1^Q**^<^tSb{{!4cB)Nt@TX=< zzIC`~P3$rBNw0ZldXikh+y8i)--EzfY<`wCN-OTzXfkczh+TGNxt(OoqHK02R1QlQ z)aN~G2Jyb?Y>KyPc4^(V%98R|R+HUk3A0gjeFo*qvG=tY#V5XME*WSy@${{aeQKLYkY?-xar{j+;3K$Zt4L%vMH(7s?)`>JEZ% zMNH;~#PJHT`L9gGg7Ct8o@t0NRI>_ldUAF@v})PB@r5zRtx1%i=JV2H+a*;VcUln? zvzygdCO2YeQEwh=JW5<5euVGKtOt8~P6CdQ@L0#OGgQdBTI)0ugvILehLhUn{8ZQ} z&KueVbDNSiM~>7LzG%lNo0y3mSmNLIm6$mE!wurPXT;O!CwuVdn{k}mkS1dBrlz^f zy%x0LTF9Vrj5vc-dA%93QMt3htfnNS!p2R}#9ZH`%gub19Szr*Qktp`UzFVrcYI-V z|K#a+n=ywS0bX4}619ZUwitw`=E zl@N9HR~j0cMrOtZA2+;=cKD4ZSRM@5m*+auvUL8Qvn1M0(Zk+Iw>RZ4FVd6Rm3mb- z_v)KskHp1Q{*R^``QK9G_HLb_|EmvQhFu3AwI25_|77skx}I-7b*1#2G*2Zx-AFyp z*;sWxX{`~JkiPPnG|rkd2W@&AbWK`=Mj>ub(=@*mdi6)eDYKzUZd8xT>1={g)=E5w z?wAXrTCAS7+*>w?T(h81&}G^>^iji5U;q8!pgzcPi<_F1l16IiBHklN6}y4b@thR? zECS>GsnRlg@31@T4{J$v5W%&<4pg&3o*sym9x;lSsl+$m^T(G?p@dyxO)O8+137k+ z$8T{iTgURDT6TMvbF(xjY^4rwa{EeXwAFVNJiStV)*kyDHR0K!CD59D&U&?L%>D$xzJaMZ8O%LL`3(Fm+M zEZOn9pBQDgrrO0x;Bzj7@L1nC4QXnNuLk4@%2)BUtLQ$%vuG%&s%8+t|{yttRWEe^~@Y> zL4@`vAdad>-EPKjqmsrleCI4arYfotZO1AyE+}=R7Vq!JT2s`Y+1egx3v=IHnM+a^ z^5d57%p5WyX!1D}Ot{O{(9|Dr0gZe>n0Chb7SFN;i+UM(cdn6qs@)BD1>3#{jV795 z>_PokH2>mIY4Z|NoU#*kmM9N$qbXMBBxK0-_ zTW}d@dRv>7j?P|lP8n5@-a}sQMiaK1s-^j8QR87D&W&#yZ=1%floHDm6D9CHN*S9-eMrT1G;HwOxA9cVk_Q_pb4bkDVc1vCB$xL{glgZ1<};^B1ArPO3eENJlZc>|Dl| zS@9R+BY$|fy~S|ohbigH6+C#S*Rr9HmXIIC_N>kK3XB%W6>g!!3ShG1OnB_hfg4?R zzHgKx3#{P%%qc#_PFTV)afEilQ?XL!C{$o0La3Px^XFvyrB{;o=xz~&g0no`>0Nal z)v785Z~5z0rRyUuz{up3nweNqjf--XOGd+R6Q_5ev$ktveWoJABBE+c5z_^=m=L{z zvS*sO;|Tk$+}uuPA;oAy%!}YCzfqTMy%krYP=s#4lNs;x9sB*ZbgeA=w{UIzxL8xk z3geOI#$!in;+;W8ni=G@Fu$KgTOX^o(rCJ!e`xAn|~G1fum6n4`B-!4WvHZ-;& zZeKtsmWx4d2xO1HO``W2PDB?}SsNIjo`yRctJajM8P!ZZv1pzOnto81DG`>I9#p|w zHwDE6ges>{zLSHDh)p>G?xr6d6mxysCQ9S=OG5Ij)KEkR!I*KAy{njJDSRcv3^XB} zhj0Aqv@H^Y3bQ5(Jul@&nN?%R*y|AtK3o^Co_ zMlzQxLDR)a(~@@hgG&J(XJGOhez1e9AYsv>9OA@oI_o`Zk%U}JFm9^Sz@a@1m0i^q zI#X+n*4pO z;SJwx1hX8>VrrSnmR2M78EGfRjWE?f#dsGNoYCT2H*}C{Yn=N?ZFOl&jd|;|U5@>o zXK^ijL0Td(xb(@46DIxUADTS|!?p*q6(nlFxAHB8*shnJKOr0B`$2MQIhb#W^})OH z9;j6inc=6D;;YEv^=9{qIsK1Xqrp}}<@mNvJl<1Bmp33TwE2m3M$4xBE~!Sq#d%4` zG-=4Qf{j$?qaF%1aP{bRy_MS6b{#&^dZu)m4Zman)oesmQ}3wxtZnE))KyY*ofILl z-s&b_6Pd3oZ3|H-)L0e7!)aHNh=U=&3iY8%oP~DSTn&_!H;YRBWrhYC%+H!5iolpO zbA)(N4a5s^LveJZV5;}5i<477VH7cY%*n*O)J)dPd16zzriNgwto;1Sm2@8bZt$C7 zSCsKuQ{ZMY!OBfUJ%Ze_xeQGhDtMfquivSml&kHv{c_o&^lM(m)xMyF8pWTywMqOJ zH1Dr};J4_Ud${WqL%&{NbSgJDt2PI(Ah3U#yBB-W$T2fDt|2>mX}@rHw&G*By{YoV z1qTJ@F`a^rHVI|=hB4+9F-Ex|_g*K{k~0mc+~T4K(=2R@o_6)&jsafAYu_A_{;aAC zuZg>)=A3_RJ;KJmd`ToA?x1N9mhvb+XXbLw%&A+8H;5uk=wRr5Q&1Yl{1at0=(5+H z9x!sniB>7TkFZJV?E>5#@v>IXbhKZpuinK0!ELrCo-FCACK8Z*mQhYKGhVxu-hEf* z;BB7BdkVrfY+0TzJFnl{%3LA9`ZSZ!(1td?t@Ob;ceczx`#X;{Ud-uVd=bvG&OM3t zl5O{deItgSA{mG!opST9*vLSZu3u8x5U4-cjh>v_r!=4=74#rE9|H9R6? zjKkk2aGkv?kUr}#N$nYFok-_naD$n9zRRxQz>+-LV#Frt^WHyRuxGGLa$H`qWk1>(H+wdY z@gRzaLGBgvY)dkZFOFBbEt8P@p;_LH z?4){ilQZ{unOFn23D~a=N$i>j-)ES$%VyFF9?e?N_UxWHvsyLm+D;BH++|rg?Rl9! zH_wbB#w=&rO3y9nK0PSHrrJe$Q)R_rYz#74bdfo3bc->w{Rf_}c>)=d(Focgmuzt*c0 z^1*=yjmDJe1p8h+NIa=CB}|kdB`To(4qf(_=qJ`aM21eN82U8#r0yxs2!_YM!sss9 z7k)Y{uPz}7Ur(2f_L%g6BnHlWkrtWek?s{&R~YT8eO(n}>|%Y^-cEm1p*1zLPO#WV z*Q~Q`TfKKSDftEBow&AEr?SLHjS@!9`)`I%AqK}QA+%28h!4W)+dWttlBlV1*OM`i z9o#kL#fC|^W^p2dF)ccHdlM(j+YwHfQ*w^2|Kq05jTaDcO@^DjsjPkNPKm{@Qp4=p z%Ra6cf723UlB+VcbmZL@`rbPcnY?o>&Niylvq(HWq<6AYZ;n@MtI=d#Bd{Wu`5q8> zY-zk1pMXgIU*da)R;>DA{qk?J&Bp&QlGV($&9c)qc>8s2`pK)8SIsBQN^00tw33{& zp9fA@k$u@qMBm;~GbNshbPSs>!&e=qggJf72xp^3?VGG%bvu$e5cH% zV=j)k^rT?blaZJ8Y}l6AK)9pjhUnuLBMt)M``^xDMHd6R7UHwSqDwxnvv9S{JPdtm zneOT+h?OJh(8L{c5S%e1N>Y$#GfQ!uM%W+@t#|!VO^GP1uKKdnZaIGE(EBW{uKsst zuQH#MZx+V&tZEg!-^a`9Uu^DvS*9!te%R2zoin4}^arWNLT7!F$GiE_XUf|PO7}Ur z(TZVj%rmii|EAZ3YM%+tiL<@6`L+$1>(U|%q|1lvisQzwZ&!?juF$`|+llzrRla+V zTUc}6Um+VZCu+Yjc9YXN$&jCAACwzGAX&@H%Z4WCqI*c|oF|5! ziw3bLr_6(le;3PoDn4-`xoDh2U;L7>t#3WPUWx~z2@T!cPVpqqmp6Zsx;FT5HYfxw z&2~wmX`v=ZT=N!@wJ*}XnA=Uttc~Ba&!|@H7PFX8>0pgnVxZBVq)ipeAYe*fl=V-uvsFfeQ*87P(BAZ1<8HP{wrso z)|xNZrgmhu=%uJjFvzjdYLKF~wmsi1IetIn<(_g$e2$v3T&p&;!kX~Tn?%kcO@H{( zMYd^d|D~M7RRO<@cb1K0vsGB^#@Qw;#KQ(H+Z+g$cFWSfarv7326V**S-)wNygY!s ze(-LbqIT~&>6&qZ2on_sCTUTHXu{^+Ym3y^Jc;SkRzffjYrOk3D|lCi5y9uihj9yj zO>LtIMpV4FjB;yYz$JpKbjITb-G!jm2r?gM#A_w3UqIZMW5s-M-;;|tev3)&{PuX5 zI+Qeb!V>A}-GJed2DDG_UEhO0SaphBD0fvq3WjmL51ojByn^dhswh>yhBCh2Xn4|1 z`pzRP;IbdpF&71-U(S+dSgrk6foZe7-JIwf2Uo(k;&W#d?#VH+3-{J@d*k+_z6@#& zwzpLnxoA0m`@mIXpHwV-!B~*pYDP{_#yZ2NSzkfU{cZD0pnCoOZ0g&e zCPkHl51$kjopqZ3@z-VJV`7;Z-8r~xy2ko-E@M z*H3nP2rRxW61{40?VFHIx&VmO*Gk7;@SRia*%Ucq0X(J^AMs_Mb6_)z}YgQ@$^1&C& z$2y(cFJ%de-@EU9W;;1Rv&(}4X>9O{QfnfEX53LEzmo-x)GJ%(HaUT^c@Yp6GX%~SzVv`#)6RhU zFTtkK^>0uDln2b^9n9>`LS&2+u3PJp$Tv==)e2^=MHtGJTp6;P@Bad^{i;x&GRahx z*QE5rIm)f&9!W!f{dM4_V7o{LQu5QWJkcQMt*!^1w{!d`8zzN(Cz6f$--^v63-~2SLsJmV1}?IF$=;yw_->yw7{Dlk@58mtbep zdj3*ZL-bFRKT`>2YB}p13by2Lhr|r+248_NL}%WNDNB?Gpl*Y5Cmvf!Zz+5ES)_SR zifQbkKME#|s%B!uXFVTTiYJ41Ff!w|;~qADu$9pRdvW&+`mVZZ{%6Xm_G1Jk1YERC zbD%>HWeyp|How`_TaYmsdv!a#r-krVfNbMr@hp8S?As4lpTmhqJF?e9vB;DBF30JH zZ}d!Z@e7cO8w!kLLy_TQEtuD}8&Gg~g>PPjpk|TNg){1ZaAHAtQo3Ks{eSU^V939z zIHCIS;%uh%t9Sih$hmZpO4NTRl^;zV$UsNScqWpe zH{g=k{VG}qvDRylMq=lCy7QJ91vu_5!?hTVgt_Zzr%?f8op9i*%BzI~ahB_;*JfWU z<$QQw0go0C+u!%LF-og@|K_z)YpbgQ16^StvJQj}Wm43WZt{%^C-G!Tw?40wZZq12 z{LOkyE*T%vOe)O>JvSspD*(JVbz&5G&SNz?l30)reV#NioKv$z>&Qtb)2R(Bs={sh zB_9Tyng9G@h)+Sh`a`#(B7?<@f)E_isJRm= z5JAlgq&)k!uV(K)4d>yEh>`qX*ZMZE^WbBrpKb7L8)7La{?qZwJKeWOF4wla-BTWE zvo^P4&Z*FN*T1?`c{0*Yn)oPL+$OZ64v)#cf^D{+Su%y zvapzNi&m(}c#eEWJQp!C)IaPGE|hs2-Q#~OG510TD7q~O28`~v;gr2>l(H`*hyc#? z2jA%Y{|J2#)^1pF}CFs2h7Nqj6OpLq*3Iyvsqe!iPz4vw?+Md9bqr(TN`1KOYQ3~sH;JQAhs{~}7u zwI*L&@&T-53Xw5Unju?&gN8dN|Fw&kEKKkk**i|BmK$|1m+qzV2HDl<%||*t?V=Bb z?DUm?T`3hXOt4XEsh%wCxRdv@_CZYN=MwR<2S)lBD{6I;e`mkHrDkYinKLM!82h~RW>Rs(DBS5yuWSdF5_LA|()-HPJ*+1; z=H-p|KnwXF0iM=egrBFs6XhXnH4qcI9rkHOVWS2ZEOnXZkCrJW-;wk>FF^ce^N`LTuncrI!@j6YbJ7?cv zcvNIz4<*x2oF&A*=vxYaeX@O}qO=}hu^xcjBa<29JChzQTz0-Ox1NJ*zbef3XRYAG zK_tG4l2c1*0E(fms47KoO;9{W5v)t&&#W(B1JX#p(^+uFDsuU^ZjKS}f=<22Q-MnN zTOxqA^ByMRXz2-s5f_x`M2`v*AjAfwi89J@6)Q0KmcRE|kTupjM)N0!Dl!(gtvcZb z!^%bPYV!->pc&|p@ z2G-dukNKWG|5R72Fm_>_di%cb6fZ%nIJUo8I^S0G52?CF+J73?K zigGzKDt~mP0KAW2aP?}Q*){KslOe}jZ|rAY1ZGCxHT{)TF*Wy83;2)7EpWgEtH2mK z6AKX;m@GI1-L;v*z1a+Gtz+rS*s3r2Jp_STRx4E$Dk>M{a_++cN-S#`Cl9&J$E=Sd z0M`zj-rW4P{j)Fo#uO&9AF{3OVVR`ksP2`hzxFoodpm~@$j(gKD9bgtM4}aVDYCKpIRGCcnYj5ef zfWH^;hM&ywoVEeE{x6A`0f_)NwM2fg-ZVwo?K^>YOW!M1#QQ;o4?WdVfTP-LT%|=F z>=?n%pBj34B#+$hKpu@V^-qSVX#9h|lRtM810jZ7i@cze8CX5uLRkfgiT5Emb5bps zJCGa;ZStFv=p%6uNc)piYr%H)^?5*G&b305B^+aH=W^dsjWdr~F03Kc;LvPj?#evc zUxf$T38uRXO0dh|_vAvW_Y6QnJ%m%v5CaxUe`KM`q5wIH>u-@xXRmX>>#Z`fvM@mk zIp7XmQnfq?tFe+Eld!o1wLkcFv_>c%{Bo7!Rw`MC!leM?|L8*P_jK!mRRDUrOzafg zprJ-F?q=YU)5(4q9eMRQbrJx&cgX$j#+d{L)XWZa>V z?_gyFvK+ImyU+$+n)b54%Y#^DG6ieRNyG#}oeT&qlIb8Z7Nuf$KyE6?JF7QOgL3Cc zFPjxd!T@kY3wjn2sL$8USBy%31QJ$HT85SRFEnCyQP~%wfUj#5f~45A(X% zq&J}EIj@~AgY>05+X$-|!x1|LHh!mys-O&r3dX)WUKiAsve*J!c?tYGAujCJj9L2{ zBGSADUMOWOnm2Qbx)d!qDBNlco>ObxtP!d=1y&cCajro_CyA&g4|@d4svgM@#kmF% zZB@N&G6&}kw3sCc*|psZo)X(QAB(^qj0|SENCypUdV{DOVb{&0)-oh=_@Qn4^6lWU zb6Lo(Tr>y#EB%qU27$Patmb5QCfa`)ckTQ8(=<<)hW%$x_F5s@i1m$|(Qu$XXXRG< zOH@ND095U+>{Z+I*5{bzPFCF5`b3AsNsw2G_~kgt{I1<;&b$DxEu8C~BFEJyQ}OH% zXVIUMey8fO)uCZE%wV>^ICN@Z=QvK*x)eS7+)-W;33T}vpZPd)APZi9cxU%M#@{Ne z>{>jPFFSMt6s{KC$;WZCYJiVF;n~7E&!;C(9BG= zuSYJT2UiC!d}NkmMn^U&1_qeY=4IU_E3%}t(_2=%l= zTGRVL9ZcbFBgxnH*_gPgr$AyuRM;GW`8B$y`irQ*hE|P9wTilq=``=Jb3)_; zjLFwLQ9QPPaPGpOZ|V^2a-}J^U-+Od`L}v~up28&T*OkLj5f)l;ZU1)h~pv8=1i1s zbpXz0xnGr! zi~<3SqIt^ad%))8#AdIdqBso=Enhz+cD<^`#pF9qc@x;Q)RC;cL=Su>rfoz54s39o z;PDj!jActn7`Z3AI*~2nbr(vp`J>UHp&kz|36jmBDf|O-@X^t%mTLjvOjnW?3E)h~ z!H>XRi@5`=2!Ns+%(uMNpDPu%5cjb3fl)^SrJ`cJ5Co=R9js zzd*#tlQ}MXXGZGKW!njM<&!anKM#WLfCn%acLTYB$LMcbudW)*XRJ0Kq^kTz4GJ;f z$t?A8^kys}z_$^%u-Dy*Z`d1(U6Nw}47g*&6-@*^S(Y#ul~^81g^uFdHm}m^+8qh4 z(sp0Ep*${p@gv?k0D7O^YwMe8ImX{2`ZmY#>OqqlU`Fz=7(nq8if49p;lqq>zilx` zt$9U4U)r}F?sc9^2m8HmoA_aF`O|$>1)gWk<0mOzT^#s-U*Q=>PEt_Hm z;Kqldgj)nl1X+g2IRHDERn6B+V5|q-_4CB6s8CkY-kMhj9OH(_f_Y;M)*_BL`n}Gb zTfx+aWcmhhLe4>Bj~`Vn3;70)*8|fAcYKgZWq{Z~(1P0+c9;wJ z*UbZ^9uwxrJz6w(1~h893W(jt@|800jwpp_;e$051eK~k>e%sKxy|u`Sq|g$6P(A= z%s;CbV&3}Nom{Po;xbouWGgwZ>Ki>F^7 zMVhC4zUwa|tPYB%c1(9b%kAEN4;bY2xX+8}QlI{s3KMm6QQ)SpJelODT~;=zTT81t zZnCwq_h@`X4)&0(9|Ywl1uYuT?*#70AV9U0d5czqEBle7*iwaC2V%HvMRAvjR)hT! zF`9QXlMP&u-Tgd*x`B9b$cUqiu8k;ojFv?N#M!5hzwCH>h0OB??R%c2)uq8!!51^C z1^6&6P8lVBk-pNNQ@FO@qppCD!00C_DhK7}Ih{Q?vn?LxB9pldPwqL`OKXuMH=|zy z7|)XmJV;nTHuB&Xr@I$ER8(;-fOg`?*N*md3XAI6)a$p}dZ^P%|LJ!N%F+w!EdaOg zAbWS=WNS)GQPi6;{rk-vPiL#Y)FI;DB!TzFI7}g)lv+(q=Cqtv41lJB5h8)#Da*5rw-nvs6ej#E}*m+>h9+;Zy_2;6t>KHit!y?ugO`t#Rc z`~9XT56XIQ$d!~YG^g0?2kWz_TOryUQw3=&*zPaOOxy&B(g55?VKPj~U*xvO<=eKi z#?4y;i!y-<1Y!tGJCzgZXFjA9)z?k*L;fWdEfR-un_fPW;nROMCtg;f$H5o3kL5W03J-VGFM!-i3y;9^ug+0RT&_f}bnT2uP_tjacHrkF;Zuj5mI&`XP|w!7L^ZvT&pX~h zpdUB_-&Emt4wPYO=nQpN-Y+0C4yLW{+Hj6 zj!ceq`lTjx7;;CRnD~S{!%lM95>PD zJt7Q@puj3@zXa3@b%Rl`LjpVTi*OJ$^-e2j_o4be4-DlfFjoGs^7D~ynuw$3k$P)d zbR=jYumQEK{tqCjA!A&U;lg=Y)*<;GB9)M{G>=01poh7BS7n4S$>%5w5nwYf8w8$rK|LFwieEmbtm?K`(fWfQKTbX0}=3;puhw5X9gfhQoN_x75Y*}~5v_M}h?IelpSBv>kJYIL%x7xsaEI;%y2_>{)7iywP^eyyzh5zkZKk^6H@q>d+I#Ux ze3FOe%h8b0+=V`cNB~A()1qZOw}Z0?$g(QTVG$^QZ5%_CV8k!u zaPlHF37`8AkO?>Rq^19qQ7SDeFQYc^I8Waa;BtHIk2kHw=mDRj?*%M;YdrZJI8@M) z^a!LZnS_KkPFk(mwetsnA}8P_OMhT>SD`b40ij;t5zb=|=C_F~fsZ3?FU#VGKAV9F2EAzXW zL63d^#4q-OV-y)#5QEx&-vIAy084roU|H{_iri@zaf_6NftQV3e9hpHDbPV3^xWWy zy$1@FL%Ro^uFHVrHpYjPBUfc}N-S-Jru^=UK=v&T7oSst0Nw`e;B_BHzPg~aag&-3 zwt0lT?=*oHI4XRHr`!&$$e%b@4CDf6xe|<>Vm4)c{wJ9O9!T+w5Y$^!;d~OOXmWd^ z6Lz@GOqFW_931YXX40aNgo2q1U;TE;d{<7bH!Dc7-m;9!0WLv#^OF z&{cTHilxp=I~u3te0X6N1odSZXe*GA*FP9W9cU(@>@OK^#vScN#Fzzu1B2|_sPecQVgtYnw@H9 zm|pWiHApj+#y#A~1gA{P%6e0e(SDymrVB3nv?oOb*Fq*#F|L7Wcg4yt&jnhYyRn-E zX7#y%VVVe6*S<{YhEU4h8W98*P#v#1Y4YIcE?avzf-OSyCkC*_uh%K-r6oIc@_3hQ z-Li8(fel%4aQ{sxU*~~YglPU~UAgs$McTUwnBA$>(8Y#|@YZ+u@my*g*!U$qElE%l z?{$>7;+5M8bSI~JBeMfOzih47X=4S=0~Nn6xe zgTDU$!B&6Xs80i2YZ;6r^t6;DO$Wn){t~x?{zJ^Q{uDJg+x{zH8+2cPeDO8H(^1cg zVpLIT#)u-^7A+8S>g`{4mzpW#t3jIdjxQ}Et+kymEidog6yxkFudb6VGKnExg6GNQ~(CVruD5uhJPXXq?^=0|aIAj7CI3R%| zK>h{)(CCtnzdw!{xf5AgZDMV`8d&^#{vK!`^C3<7H&!Hu9V~{8f?1;Xn)|4E%F};D zk0E@PB`BtY;x!H3aJl*5c3ctlNl3xKX;2>kJTA&|LhtLZ#O7;WZLJ9j6NW5plC;^X(@; z(wWeagB1(Xhg0&)uPnC!Zu9+O4xgOn*6XPHuzlmPy)ri56j-%ruPoL)_QB@411cNR z#7+IsvN@en0hrToG(cbg58aS%WtyB{2n#i1V`Ix^KHoK5kejP~xXy8C({v(q zy9&1S{JcVcZ-!*259A0a0%MO%vmm2tW_LCe2r#OXxW_@G`FAfsMs2nGs^`>?Qb{Ix zO)E?>D8>V?zUll+nk>;GEjvo*<+ol}&iF58`MWF)=F5cad{|Uf5vyNXULNE)SUWit zxR}*}KFE2=J_yFON>{iZneM-g-Cf3w^||{_=T4~TNt)f26_R4f9Co{U0`V)GnZf-0 z8un|OF(Xv(MDG6(*&9QJItY?`Go=j#jLZ55a@FKTxD#Ie_&Japge$M5noFT&GqG0^ zV|eWi3yBEgFcr7z!$37L_vm6b+l^O12IUF}7w=0MdQkrW z;(fX<}NZ$3GU3cBEJf}8Vf)Q-0zbLbZbD3 znl%kF{idm*v9*xlQ9^aPxocgS2*mB?-Gz(>;MccWvSs}Vnbo+XT<@O}Owgi!Yz&ITXRkULi7lq4a9 z^+(u|fj{Nj4x%sv4v_3eRe$U=0d#epu$^F_8K|ezmmZe^#S{<%zaNB2 zPl2#ynnEwsGe{-aRJBkC^G=5yLh%?RX7lq8pR&H)1M;eCYdCGt&zzU{EVG8v$b?2+ zpgkGrUNu^Te3NPq|6&;nyaDd=AnT;*Sl;V3r}9q1#t3V4HZri(^cS`N?Z|*=ygGnY z`Rwm_Qazn2b>G!yQe1Hp@IXS-rVeGh7CDlrt58gPn#l`*b}&JjYUzMcniv@+8JC;o1Fv=DQ7Jaa)H zAO8Nm$g(R-slfMcU9^g;G29`&rKlI6@7lbrv9NhnB+qJyv8-<3M;FTiAiBB zt0eUrW{rO3)Jp=@30b#T0MHonM#&dqCVj zPkC>zZAydxJOwk_%Q`ylWl4K?;8Gkd{(~Oi&zl2Leln~BB=x`1Db;__?GV4+4ST@U za6rKWV3$8OcejQObhXE$QtMw+%}ZCF_?CJjAi8Dn9X)^lT4C#!72*<%fx0~4foOiv z`bC=LqMAE6({b+_eGNHd#t}t@{0CrUG&1iOFfk_s7R2c@4$|zW;nk(3x?J#8@nktip{bm`2ZpuZYuF58j$-LS*fxP8(CxK; zcz8Jf^qCqH?-llz2&Tt#I=%7rqU{3<^0&5p@ZT$yStZ?vmq$t&Sy@X}qnY?*WXu34K6v;rH9R~#n_2vMcsK(S zQ^Dn14!qzakOSzuxs{EUnda{71WJQKSiW2|hhvva$ z-R|dtN zZ5AunxN&B=XqO3XkihNal^`b4TkzHPUAJb22blHWtP%+>$Pm$1}t?17PCeviO zP7mJxH&M5JNvR4N0hfNkHBI6X;f-fXdu+YtMj`4B0TiL35h1P5_5dX(1c9&3=rpj) z>v?%L->Z{Gy6B#0w2XKmtBECUHtX` zsxEvRSi83*Sl?5gCBmC?Ce_Z9FOK!RU)+Ke8jbi(0F`O~LaV=3R$XLB4tKnDWU^WRYW&ca(M}Zlr=pTyv6}l?6?}7q1R-^#H<{DkexV!5f zVknslwa!ZCllNXbzA+eh#+m=<){baj7JWjP>5_$)K*fFnFiVe94iOam_i~e!$y7 z|5XKLr*Ww*;0>v$w>4LI#X6-REJJXFb(>qBUNXlLL$(kvi|CHC?7?e*I21i6R z9R0+fuM(nh5?=UIK+H{BVo-mwB2aGIFHruca+{k=!Mk07*esSQKu6I+wOYW9AF)us zo}OamV7hU&emeqOX#`wwsqM?n|1K-dZGZtHRD*@1hpzuHI(#=1Yi;`P@blug{|Z0R zO9pFY)XE1<%beAsGBlZ7{x9%>lVpH^Ui=Tl!z_b54^ZQ$y5P-Kn4dnJ7hwjDp0vHpx z=;Ze&-|kWY?*B0NmSI({UE3(?gRUitE|id579AqpDk4e?NS7cW-AsC_h$yK@2?BzI zgmgDj(vp(~K{_Urt_geGQ`dUxJ@)s#$FYBGes~}g?)!=n=Qzh0*M-lNPL87{swM_S zRofl7L+lY{D#X|-%cY{ysN3!P>LvkRLtPxfGudiymC>8+zj$`BqSz~UTDn`21R0^F z;54+X(a1}15Iyn7ukRh>Xx?tH*ICha(9u@to3GJ_(<+lY7K(>bZK|reZNv}fqwZt~ zABa9(SkvF;8}mXpuB#k_2NAjaPH+RCPfwA`ERF)CdGeI1S%|p|b@Yi1TV-D+7`1St z+q2WR$n`A*JYR}`p0u8MjUBeq_S9K$NRyY~Lmu)Zf-vUcs9sW;%W8C(m%UsvobU)D zqVc3tQ?#KYB1eeM9Jpn0Fj-6$HI$wzW}c)$2HovDm)AF=dd9UTZ_*l;ml%22PZ#%O zXrauzE01Ir&yl!=cX!5u(XTc*RsZv06@U3;?koT5+`4B@ZE(gCra?qRC4)%YlcBuf zn{&jJeR~IDgb^8Bdtpf0yc|RHq_WgKv3#E4d^wJ-1@{QdQJQ&~)$TRVpkB_{%W9|p z{OdU;gy%?8wf?n2@hhwjO2~-TXMSl)w?3@~h~4rq_PS@Jc&#~Q2j$YR)rL)f1wtwi zUF-Sj!>)a!3;p>c$*Bj^ACMPNy|j=x$OJJDpQ`y~3rEC~gS!OQN9rBw(rUs)27Wz* z_UALWU;q7#Ipbf?2xuG;8&n@n=v-Li@P7{8ptr{kv;NSnqGoxb38spCsS~zHw87t5 z$q-swiHJ@WM7;CPb!Q?PH{N&4f@3f_HN$_$_t9d)-xjz5W`fP>Jznb1L|8R2OHeTm zo5PG>`cOxBBo(RmufKormj|aHkrbdz+twbAL1?Gm`CofshRsMe8j9f5I^u&VT=IB3fffl?+5SY3F=}9760mK~gq}JuWqyjyfLhpII z>Dgj7b7|;E^|hTp*77M<%L@(tha^z-_Vy+L)s*&Mkpe<$ia0NRYY3z%aN97iZ)h+F zM#wKHs4w6G4-y^V&M`I>PJFNgptP>-PyS!=f?Af|=U?%Hz6Z`HH#ax*?c0xEzTAot zK`B7M0OxWhmzI{wRnfu}Y~QHA^HqqY;H(PseFPTma&pDT4~TDHTv%+y*I#O8glyT9hZ_)=EI{Zc>@XdW zo0qq-GZSY4G=ZO=pR$tDYfJtiHq$!o9O@j8j@KSp@JcBuDTE(ZGBiwpUw4AYo{yJz z7SdJM@b(Br@Z^O%y>O_55)AE0{Q5$L0!K?J;E;cT1S6RB(U?*jGLozdZj8(Ei3dz& z7^8{gTR#C1(F$~O93iTH{V6rI6R4+xhqcEmfNVT@<_trw{|Hxk@xdVTfL^fuz@(3_ zuLW+R-p}8^8-CGgWBx%mmjnnv$929lP8+nLuFOOR*_CFyQV+HL*=3{Q-*x$Ju8{X* zFUnDAReNnKdE7JeXHbu{!}j(IBJ&pB&q*S6O+?#g5l>_A4OU-OQ!^EfU(iR`k)ubC z>bN}|qB}=L^~r~Xl9hu)9!^LbHUYzFKy~emG5tv*s`n6aA%WK$3q=hIfe46(B)Xax z4=n4(=J2NXQ%&V1$c-`&Y^5)&;qh7-&ArdiaRLxpAYTjw(^LKpGHR-7YRQR-SK8k3 zn11EF6HF(f226vhoLm6hQyUr?`RT`xM@dOZESE1!YHDf<10!PZ;P606>BGc?VOTgE zY+kMd14~Oyz3=H+VLe)&iU@FJr5+z2Us^_ns;g^>jI8Vf9i5D4&yG$_PtSjgmqfzV zJ9l1mb#;Zlf1goTce}p6o`sR|4!pOgKgY;-aYss8nvI3!p0Tm9+sgRUxuQS7SWW(# zHTBp?WtNYAIP|~lQ3%C_QAw{4=B#RVb?`@dQFDDxPnQ+28C3Gbq ztJE>|(&fv1Ui;hXZXEDkfpH5(SZL_%@<>_om+Jr{+B+y**K4k5_Z_s)RlBS>R)PW3tVu9AVOyFDZ&MHV(5`=Fd&o%cnohWU<&Le8*Yw~*>@%0Lsk_8 zPgP4Rt*=jQlCnZRsi5Ei2>33h>L4jeHo_c!$=i*iF_0!jKAJx@KE7ss4xToCy;aiJ znm#H#yaB3SuQB(I;rTxd6=>r%2LeeWXpPj>BUstkHnPxoStNS_>KhQjDbIB6ni7<1 zz}uqW(;Z_3MiZ?NVzQN+Ti7v7jrWNY9z(Jc5)x9kZ$Iu$dw}Q$$S%%*U^y08#igMl z#dNjLT{Jf37bPUBj#Tu$dGiKIXf2Ob+3fOy^P{qFmDJ@q)7IQ<2sU9B13@(xyS>(E zAs(w;Fot#G{n5BSUULj|lm#>jAxCqSe}I5KBf(&?u(0qzMdf32vkc@)()06GVfk5^ znU$=qGfC-$6EiZ{jUPQ?2AkE?)FdM(r>dj#-q6sH7v6sJ@R=<7RZx(cvT_K_6^7=0 z5v`9b3y}#Do>fb)udmM{DH))R^@=BJKHdMwi(1yHZ){`}5Wraf5nZkWH92A6y+D%@ zJ8|t=_Sn{+fBtzRT|G+;mJZTja&hADJgz|3Pdl!Ut*w{WTxa1ik-l)5s)!3NS?U!J zs+w4FXns0M z;#ob0n~q>d2ga&W50;B=N_c^=t*)-Fw~JuQ*R9_}<^mJWp`8!Uj1l+L0$iJuK^tPe&!1KFrOz zI@le*>x5+Kz7;XX@tTE%bLyt$=kp@oqoAO7d)til^XJdt;U0hlBA?xR%XoUefL6fz zJ-^jp;)@qA9*QDOHbg{{gwR-T8b;6snzN_-V`FOz^Tmh6X?x`%pMU_3{s%_I?&0B# zTHiAZkV^@xszO&$3Xn30w-P&p4y#4_x>-j>M?1}ay9khBdH}D6XuOMpj7u1xsC+2fslYYR ztgfxme6yefp+R1KfZyX3Jx17jE<(ag4^$#!EGC3eJ}ME(m;lggp#0F}PdN+OkF;;! zlv1!Wp)4xkicNO&ApkX?pO-4JpE`+1fU=4>7rkT6n$!gblro^%IEg!oiorm?XCNc` z^Un`sA>aQ^Nz^wsHX0glDk_3Q2479iz>qaN`#6xAFYQ0|AjlLk>*K`2!ougz zott#babEq=B%`Qk8gb=}oP$H&0UnFCfFCK0jYURM;dd9Zk`*OkIlW;yZ4j+O-IEv+ z{4v#Tx^u1UR)`}a=W*hApEBt?($W@Vm7Wca!um~sn)tx~P*!q*lfXd9?Wwp_WK*A1 z65d`zFXomAN(1`*&Hf=jJG)#N3OoI*lrpiTL=(PM146u8mus`g_jtiywE&9)P*pg zQvLP>_k}@7(K7S!sHmhUIF%0Ff^!k)y1`+(a8JiqUO)sb8vL+0*Yntn9h~b$UjBuI zgQ{)Xioz=o3dv9KUE)`{te00sS6o$91=W6^K!Vm}8LUI6r%mXD9q%IUWFL=@p%7yN z>46Vb){!`asFpCGhhXjiMOl`tKoas3;5g1tdpAJD3q1FniU08rjaU*W@KpwZnd>Hp z5&bb8{~VC&4T9~3joi{cwZFgC@jzGC%47Hvex^B$ZLriS{g$L;Ol6!(vfO=5&3AL% zq{#a`2o>a_cTG)Gkc4DQeP7X-SM-q1jsd4$`KPa6@3uHhK$=4xKA-CbYRBcs&v$)* zdJk@HZUz4*Zk>zmTvi9-u(X7OLyc5_JE9SmF+j+S=cYz{jXP@WK z1=-V%pE!}8o&9Zlg3B)W{Q2|D%*0rS6dzkou?C+1artoJ%n? zGrJEixz?4(YLIuN#G!HB43LQ^(VEigb%F}T=jEwjs}3uT?VnI$l98P9N$MlNGg*`K%D?3T#zS%fmV4r6p|Ih#JAc3i2aO=lzXtux zV4z-_{zH3)_c~vD2_w(ku37EZ{Pz^Ht4eEjBvhPN{er@1!B*MjH zVserLH4d9F>kk{=eC-S|QAcNIXFOPJ-;O0Ahv`qr$qn0)w}#okqDS$V2G#D6QBX7} z5O(=m9bwcaQBhI6_CM~H)ptT<*|GhF1GiWXNmb{W9&q`+gM;R~jwgV-1iicvguG!3 z_1A_OR}>cu7UbtsG047jPfkjbg8d_%Y0Ee3cAROa>rNrCj4p)o`QkTK2fMOhS&OvK zLsmTjFj64bAX$fkmDT531zK23xAoaKbKUenz<^>tD*gg6c6bQFe_pU!V z`N$-mz$DrUljwo^?}0p1k8h$PpZM7zM?o_TvOQ6S|2<{nSO zUDP3LT5QjG{rar4;!&dNM(#6LGk*g$x0TTM+DVdR;ktOSW;^nxC=U*Y3m2&&#L{}u z1p$=uZODa=9G!js`?;R3E<+DHco>)fzK37_QRc7&*e+QS4KDWVn$m-Ak`I8x8z_xmp%__M znwE8htGeMAxcGho>(fv(*=+sY z0dN?UMZdsFX->qHz&Ce->8()hfE)+cg8{N!gDtc(Ml{I1AL=1SOmkq1!7&B~pQ{s5 zR#m+Mu}YZ(yNJlpy4e|`Y6l=HA8(Z~2I4cSUFLkD-`2($QfEs-V;NQSXO<&Iky?)N zv=%LbV6diG&Xs!GMe+eaX%trp^TDfqqX?#mH+np{A&z@x+9#nYDEv$j)MW z!DM4_v^f3{Xwm}L4OJvd6e8Z<-ho_S$i}`F+f6RE zSA>UCbW4D%t@eSzsSpPDm(ax3AVSkfJP~tGMkZGTldKTa%;f}~T8|H=6y-+^D=cRE zJ5HXDL+M6nF;HOIY;QyS~L;g<>yc1^2{;QAI|xkX%7K8zU7 z03T=LaU^{E&hBW)#>)5FWHbB-5XxOR{qNq|O$ zA~O)(TkST2J2R4@5k8M(9&;R2yu33D@+6_z;VkBd)}FqMpsS=2yI<@_%*=uuzC)pr z2XVGkg;1DZ=F<*Qz$8g_oj^!xc#>>F$aGzt@hnyW zT-JzC5mbkCOMnk%urK^>+7i<>ieF7IKTK(H=_E+s^!(v|+;ozDHtolDfdfOKWP6{G!qmm~k{qK( z`)FsPC$jkmyD4`*I}Desc^`XVe$eYtLU?b=TtwsU_>HhyLB8oc5Bz%Lp>P19_V}9R z@^FbWNepld4V3z?Y!dVHdzOcRE{dIF0Fya>t5xzh8qXSy~v)A<6`f&xq4B~|}Lx{&Q=!Z~ZkwPd-r^L|X zd)W3Jh!reR%K*to{$q6)=tNznf!=%lWI>+W}GB}#kGfMugt*)5Y~S#uFYga zpmSUWz>kK;V-qy@WM%V2w)kyEEq5D_5RKP&$k$hQ5~{aD@T5In7C{S;2_WQ1 zuVrF=HsFeipR?Os)a1-KMl@dgmzHJ<06)>-X?O*8*m(xf$eP@tAoND`Y^pdp*Hazx zHEzhSc}^zLL66X*KUr)Jg7^FSu@mpq>?O$%T?|-oe~5=V;RZ^*S2jNY6XLzrzPChzHf0k|8UCE;sH3(VA@y4E6Lp@(}&A z^34J!YbeGYG@Tzm2@vnr1!H+)A|9R`b0>FvtQ4Z#hO z!5yfl0LBV5cl%CztQb;ocP)e7Q7o73OTQX}`o`AcD4hRS$D^__^0$UA4tz1e`m{p~ z?Sa3@m;Wzm-JgB1Pnufi*m=*Fd0!;|zMC=N^Pg7!=lo|%4 zHY)#q78?PBdiR>zJbHAc%q8R@65L(7bcwwY@Y##5)=xr|}S-rk9m#VLp(C73-vS)hz4x=T2O5qf(9U3Y@jrKWtxrE zTBkn1N>cP6AzFC|af~gp&c&3Fy*=@3LyB*fvyqdNpZx7N+fsK3cO+9$M;f3|4W~>B zOMU%3VKHdt+#dqHAB}*pgoFgzgZ8m8eeiM0z_cK+dKB=78o0Xs{e9Z@j}T+SJ-PCb zpJSx#`|HI>2w%)(D#DU$ByeFKwk_I@f#{kJa%kFbxCVl<2WseQRJpFr)jOqYQ;KW5 za4|Dqt2B@u<^e%apzJ!_=|HFDNriRlFW*r?$N4-hPDW zTIjz$Rt<7?IST9#!A0?_Y#LEs?M( zjR3Mu`NCCJuSi}nol;2Grv*d73~lcK-vWOwifgCO2KdDJA5Cu|C1LMY<5=%UUTXXO z8O}$?kdcy0uLr83KLH-sioIM@Qv+;d;l37OD|G)3DT6BG%0MjLpznkBz~jsF-yuE2 zE8cLnLk4Ot8Ra6!ZN)h>vTp#+3)n;NRrxA9Lgfg@n11}%7*k%B@1c?`(EfKk`rhv; z=S$WC#9K4JHAOLOpwGlb9uzy2RA#-JyY+J)=fnzsqKcL?GP_~&YLF%hJHe*%#8Zl|7q}+n7 z5M91znN8Ve18GAry1=Nh3JMmF`KKeyla3B;8H?-9%7a}CtN!epkdebz&Hw}5+}cXJ zvIUpX0Ha$i8j1*){%V4q1Rvi6Si0~y9FWy&Qc^xR?pMXqaKkz@Ph4toFb2meBQNi? zO|4J6HH1cg$o?$V(4zbNELmZ}T{_euX1#GDdw%b|Jf%H?J>u_Ta|mSfi;7mC4O6qn zkCn{L(}2G1!PcvRdjkRhX~J-Ib#0)0)>LgjQTIFYe+bXGJkSVF2RZ<$>QnRF9(IU= ziGqS5BOT*@ZFl%f#~bX zeB*lKWHxfB<;6N0Liet~Dl27Q9H11bfq?;}D@o7gNFNydo=^9Yl(Vvm$^$(;YmcXq zqHWM!6BZJZfE4?~r^np5E?>TkK&R?`Hb!@VyDYGuk_m*e=o^$KaZ9CZoze_* z)lZM%IU7Rai!p^!M7g>%I zb4T*tizpozFdvYfwDHinT>BQv(jNnS=i2uP{-qkt#bZ!ucnKA2$4t%9R+`WdB;CMu z_S`KGrqdDtv^ckkYL zSK_adEQ0g{)*VBr&+3+dJz&m2GgNJDZL22hAOJW|N!gegtM?kFtVP3b3H9U}RajRb z#IE!3oY?pDG#*wI@*IhO1VQ7-w$H;`FR_f`9XJOw4CZvQ1g9@_KY|M%r9uFH@tg0Z z*`p#;Q&ULw1EeCkKarGx(m#FrG)l-J+0e)cn7Blv#-P;P+^+3sd1Z(@Xbht3hKw*$ z)sB>||M{oEx2!|>+juZ$y2Z8+HG;a;3EOaaI(`%($%)vqt}hGl@-p-BIo&7|_kHog ze5BL~GLJmsj3G~_pwJ)bIRR!`fBQfoiuWEkA@75vGx}6p=#rsSsDbF$eI7WXZ@iyy z?c#Hf*Sf}A1Luo56^jnnGqnp;{?*smArb_CejkWRNStkcp`+SuiR3oowdi93m_L=Q+?&BtZzYKY*lKul>sGYQT0G+-Eix z5luhUpcJqNuBN%Y9ZCN4eaJEX4?SDFqUZqhL{ehnV`%50<}>ekGTH(d)Y#NCJt@h@ zZtNA55%=ppiFxDLw@v&I&~Uhb^ZT5=0L1dIH%`BX19<+a+Y|F73l-gigJ~eekAY4_ zii04Q(BFM#i>=>FRY@@iIYzSI;(Loc@J?nC5$zO(7-g`O(!jTCLkX{i$QP!OASd$c?0@D(}w@^8?w+X-7^pE&7)!$?Dv(1*%0r|XJQKlo zvWbf70C~jFHzV%3>*%>Vmm&S`BC=i8* zG!&hPvmDeMG&HiI6hXwGY$h3M8QA#w)sW_v8#k&y=pPD?riJ4s;Rr+*LLJ%oo#CA?rFoDoWo2TT*_p6| zERml365k|cuKZOf1VG*ZJu-zhW0~*Y(*~FP_I-(9E`_G!V;R8GJb7xrQ4E*9eT4K3 z(i;YNl1r=)T*;k0leR8o3&DGXwM#869o!b2o`>=tq|Zp^-n~vga<=mTlemo<%GVdD z|IGvh>}Ab)Ks_DDtB;UVQl^)dYJuTz&_^St zwAz6Cj1!iihgaWDdOWnzQG4WK{>61squ+Mn_3@NW<)`W#zltBhHc<>Gl=^OOxmcC`V9^A!%P3aG%%513aPey|ERxo z>m}2V-HtPK;#uXyakc*fK$i2X6+E~`D}U*-j2t0`4HpUC17%madGjeGYm(r!3Pjq# zq0{xPeiSfX?9YJ;%`OB$L8oNuhYvU4mw65(dw) zbh#&jdj%VTk|QKFI238O*x1;R!ku4+0Le*#LkXZ{{U5XzEHO1Yj%tgA;*VRRa2ppW z|Je>WW*O2uFPS*A&tYE`ab=IIhXB#`C(*szH&uZIngR0TEn=K9r#J}W4;~yTs5^Fo zlo^rYzRyTtX3`dw1n_-lZ;yt{h?E~Ly}bMQ6BdVl*jJGj*V(9$0^ng&d<7i{zq zNoofgkFgf0be$GV1OERLc_%)8T)5l|z!$ZcTRv0-r$9mz(j&~E7~r1z0Q>PmS{JET z1>fqn)+PXr{5NxcW9D}{a6$sbG4h#Oo#O&GU-u}}m z8bY1jk?I1ftyfJhd;cO{cHuAP6J{I=ew^gua48fpr-!p|33ZlFXdXU|i3|W~_%{it zFIJRm7;5zVdtNV%2Q&N0;npLv3HqOu!~f;qNe*V3-HR*H(sD}KnWPSaInn>xXNrDg zkpG7Ts8bpobeiAiixD2{XTzu}Z#ky4z9_Yjk$s6-4O_^+eo^1pDrjs{xt{ncQ=LWA zs$%{l<8rdC^Qjq4nt$Y}7+;kd%(jmS&(KMkvOuve%@T+4jr65{6bXyO9ITJ=>Dn=i z4qEba2-!**lPd=26^`Kc1bX<)^>-CGG!I@)a|CpTOfAIHD@IS^din~)JTpCG_mZmO zCX?3S!Ok(^Svo0o$JA9Va5^#yVt4`BaCE{H8}cG@-CRM=^qDG;DPa!%=u~g=qF%Rj zh>3BZehNT#wF0a#B@#(F05RBv_#KSlFcahC(xfPkDii;-7g{GOc9$!uJn)vr3 z6~btT6)0Dg@ZQlMV{AOPmSyv)%s~BX zfCkmaalOMhm$VVwhP91KLSCcJ?6wP>!YM-NNV0xT>}+`bKg}S;q&W8l08<2;gQz-p z#EViAzgaP+lR2Ch#o3JMGu#vUHu?94QhXOxdp|RoSM+9vRmjGk7(DQLuRy0GgxiTb zk;U#-dD*0QXMZO6Fr&vMb;7T!uif5d-!)aLS?EEUw=~!KAj?{;GgrPugC}~dxgzaR zisw__@6SdYsvONtB|3UbhX<8n#%A30TzB#Fev5jIBhE!{Z7|1uF-{5mi%pmpQ$Zcj zk!$yp)(`x@+X%+))R84C_o`N#oo5jAL8;neXE(|Wpsp=<=#Hw&>~ zp$~2_d-y1K!z0UU4$k z(|WIR|8betg5R!38~ajvVO71G{Y&}6p2N{Q74f@~wcHzC@B6eBdj>~mmA<_%N@-gj z`@yt6aFOTA+Rk#kn!Zh*XF~2K?4^^U8Hu|@F#m%XKkS;#%)IIzI!;n64r8aUo1$e? zU{NCZH2>?t=7yE}BIoblh*>|kE-ri)1*P=TCRUV{T zPLD}DpjmI_{pXXhq-D>Q|F=%z(Q(Zc z(cM>*L7^uG^|l31FQLbTEAWN(q;(=3Zj6Vz-#iBBMBkpU_upLOD)UaM&-~aMgBQmR z`W*`*R%kEfp1Ur>VFt#IcEVDN+Q`=-Qn&#c`S|kZ7 z^26#9Io(a^+6{krcu+|bq<3Glo^MIvrJW1s)w!T7OmjJZ!Khopi+SaiFP1CKmlkyI z|8D2~fAYu*lU{3F==t<02H$meW%kwh`~ox77bXgyw%wH>tL(5x@@FjhI zZ@g0xfn`y?HzKxxS=wn&#G9g|uvs?h6Rni!K*@ogX%}s`Tf>9~E!)coO0-KMP$ydd zjy7O!8>p%#NV6q->4`qNdf88^GQyM8IJ$&2eq89QqxslsN?FeRASYcpN>SfQ9*qfy z$YOLeX`NuJ?{V=U$N8SlnDC_A(N>vVG6(K0o2EtDXY{sTO$)IIb4u8@edjip4bt?& zdiDlQwG7THw>k8`TF15qs8^0y^@wmZv{veOcUaBajPzChgDGodu`+mreJkJQb8mY} z+^oU9&NW?8Z`1bP)dG>Qawh$~RnAWtpAWZQpFQ_4W?6&-0k0TC`d{%F0f?Zex8lP5 zV~v?*?wt4c;4*gK4VPzjA>HK@-TfU-{T&;{qothacj*t~O63zeAD_Hh!o+z_vb

DqaEg4oSL8;RQ^9IJE7yJVX`Iq4oJxYin$qSM0`0Q{L%1HsX%@^5e2PzD@Q` z#id5ICttXqKh@YfRk$|QUo89uHy86}FEb#OjXG{W_MuaUnjtNXy1JzX-J9YsIdUR? z?TG^X83v6~#I<7P3$u1;G5@f-(@s*1W73Z_MqZVmhG@&LCkNREKl@HUv^N)YwMQfv z%Tz}~SSVit%8^BE_n(kB`x)mA5KzACq?cRCV{T-b!u6S5M)h|uwb6=5;Iq;SN>K(zuX6>Jz3Yi=HtRU5L})O_(b> zGJ3Cu#~){2v*zXh@6S5q%sw;cqWNa^q`#^v@7pism-wV!h_38@EwC8XLPEcRsWI2b zZjljg+=SQci!AfB&)h2KUG8|mSsD@Y#>QXDX!2z2Nmiv&m8(x>9)x05=AN1qNHr+a z3uI>A)q!ObzEu16Rr+P&oyZ(+KKjr1%?#pXT4;JGXfR(les_`{sbu1I-Rt??DG4nW zwLey2#FNEA`%3X}Z@uH?$hWT>BGhtMdR+1^?vy9(sotkl-fmtjGNO~a;<)(OTc!xB zYUUbvG|Bw|eB#@}VLEa$Ru_YPe1$vNsO|L0e{81mzV;Z+%pa=W+)x}naNc!FscgKx zT3Bi%z&JM6>b?*)xiJ)X`THs@Zccm6S^8E}2T!)*gEq15qSctD=U?cW8bd>uADDf( zQ@|lM->y+dtDc>tne?=R_4K03_ziDr#robDDwWBnGIR@ym7AlsZYA9z#^j&)MKf%9 zT}O*Y$cjbW?)RPu$(r(6YFf)FOp^8t!tlf|NA8t$3+!wJh4(deq$o=ZlX1@ABL}sj z$bXZo+*&=(_u`zxXquq<#KyCk3JNh#cRIM#AUA`M0Xu`k9^K=U3c`H)mSbR)I;}Ij zZE?BD<)=hM#LdLdJ=B}8fJo-a;_6y)haeX3Vm6El_4jgKt(3jv#ZIwt=UL%cdO}zJ zt;u9+r@)a;gVxX45yN5JR282tMP$+KJ?`H?_2r%nDKiKMteNI_r6v4A97-kc z8C}~2y|+neE2lAAL!IRvo5Fhil>?ieJ|~2&h$Y}S%9NmdUN)}UwZ1#aG70C>Mt&Sb z&NVhHKdzg?Ptj4w&dfyY2>H#s^{5r~?iAdZS>HOdsoz7AiuK%67}`slr^*u>Ge8f{ zyssLtqfPrbNqxcJR8&0m_vCQ?MzXZQ*xijbv$!@Bx>t!F$$9TZdcPN^`NtgUxtUMn z9Z|gfm7BNB=5q#93lDZ8EGwux$VDl?Q?u`^3Clr3l;B___sgrjfI2=Mlm77ONG+}l z34OnER&_{r*OvEaBh1Ud)RtYG-RKamt2j=NbGN-Cq$Don&6uB*E=SnrQ61S_A`GR% zo)}vUyI4?Q>K8R;_Q-fT<`TwxEa+sJU&m>&=Svh`8(Z38 z>$P&PI%k&k@kZcVxQ_aWdsAMbaq@4Exm+mNS6rET)G7ydBIVo6M9hK|DamBD$w&@p z%S7H|>RazsR@P{IJJ2Itzk=37e^qN1Ba3Dg4q`D7Q77xhau@JM?+-JcCq=Q2GsjVU zN=s6)N)dL-xGe5)ip);CvnO{m)nax3?x7{CWm5O=1$4GTl@~$;G_9A+M=cKDy)_eUqUwaQ^-F56tX=;$d(Wx zW1}26*b)m3@OZ#Jf5w=dPT09^xJMYzHxm@zG@&=Hlw^cy@UzWL9OzvvZ*w(w<*cxr zWp>d+QQ$+QI%J%#EuZZTri;?%9Hr>}+b?IRi z?Ufx6y%BsTQzt(zr7-t1UT|7IOwWN=kKJVy%h!*>KtAi@BVhHRrsZGFa>W0%J{sXy zEjCaaF<5LDsILN>p2cZ{2_ zz*abZFn=goU{g_WY$iFX$$qKT;%grJ1E~g6A!lv6GQ&-&m^jaQQyzQ#i?lB1qa32V zD&>w)`E}-M2j;e7vmJ|)k)@8+l$j4E)M3bVXv=d;t$5>Za+bqeTrFR}{?D}{oOSqf ztyX-Yaxa|ge^R_0cG!dv21t+8A*@S4FnDW?Eo!=x^uj!W5P^i&O3G zQSE!^(K($t$MCajG|8wSQHr}1XM=Tf&W z%J0IwR5<(HZo`M>J+>xS)t)(VxoMKGxVmFxqd<`UZQ;jHVOn}l5~yVB67dbZ=PSF@ z3SqheZO-qzS`wq_M8c+(GvHdQ%&9@XZB)bo5})0A$@SBiH#Hn}7j;vJSGqfMYv#O6 zTM1l>`*H%4IX9>zH*@QvPrJOQSmIsFuO$ZbVkyZ{Cm~CXWJXz820nWi$otjB1jkrB z^<<`Za@FPO5IOH(?1k64624OrL&9=iIAvC8b)oZ{9UVIx(nnO_j(RsA?8_UvyKDFd zU$3ehx*|DMHz$4|*mPYd+MKmnRarS9WW=~>3u~WYe{ugI9nq7imfM})t}JWHkVr5% zzMvSemfVQfVRtdvjSY}Wq~)S037c3fV>D^^kZ~u$$JVpBm>gWtmF|{(E;8fM=D#yI zVl8Q{86H%(+`34uIc&}*9i$Uy8~VpmQme^O``bCEzY_7f&)N^Orb|WcC zeUz=8#K#=!KbOBd7$_DqF=@PyaS)37t^>zM2%(fwSK11GDA%m%W!02;AfEA-^3TQ8 z+$G+;*h|q~`R9F_l4J``lJBl3ItIKHhH9)fiQ~!k4##vEw7wm6Pb~cAX*X-|cy&Q) zIZG&uaYy>8=BT#3``v<}>*X`$-hR4e$#+#WUl=JT7Jh2Uq4k?JnD1a8PEII)cUZM# zP-cY_rwln5g>2Po&N}2+l3Hb<^ZSW<_CcMXjoWZX{j(XAS9rM(&Qih#&($tWZ?t=+ zW{bK=S;wrIqt;Z`nnJX@s^~@_-e2W$jDF2p&;n_skMG2M;FUwMZ*RQzNBja=Sgd0z z#x)~K#s@UC#yvQuPN#jgP;=5sBjuabVBhiTLTx&lV4pclIH5U+&B{zlDMf4Z&Wnx& zp|AfQR$9J%LpOcWlWEL79nZfm6t2VS(!NFQ5k-gOAhrqTwXeKR(l?0Hq2+SWY~_5f z^(j_Hhfk_0E379j5AR-Kl_RVu|K>-~k(|wwdkKnCL*gT3 z*VG$a;7lvvcqAQcs>NLNXo_6et5VFBRqk--ZO20qe#t+=`n{}u3=wHA__VYEN1##Z z^XktYbvK8?kJUFZkf2hA#RIaOL<4R39-95L4l*m(@VdM0Td36Kt=fj%EDnCtlE)X5 zF5RnSL1gXZ!o=FH9vofF@u0)Ov;l4<2-0D2;Gks8VzLHwp3^;@-1m--hf-t3afmO^ zB6db$Wp-3E6CIwh6hAjHSFtoMlqWJ{8C;U`ETzRR*H5wm%@D!bjVWo`{!YD^vH*$a zvmwa&-9#>TohkaW=CsOneS+%4F8Np%c}Hp8=2YRGa=*N>8AFya(rD$6J<;vV{poR> z=8ZUur}#mo+e0SW237oty9xOi-N*Xy?Roo(KpCm-ABL#>wy6s3<{@1PSCNcJ^X|CI zOa1u~Qv;P=*Uop?dYtT~7pStW{6M@J3f&7+mo5G&S9Tc^-0eKeO!Wu**b6OETgt2< z`zq|z0m8C&YF^%x6hqcc_0LTE?fji(eSF=foiZr0#^>~S3)p2{pZaqK$0->Zq_6T@ zsolq^X`d7z|8(taX)v8=OxE|imdkYVCsJg>)X9XEmk;!mNut(RTvEwD#WV5$W zE9`dVqcQVQllyJGiTYXlwx>6{og$$y_8y^2N%V>Z$s#5*wc<;O|E+r}j=KxEP4C={ zd|jd!?LrjQMZI@S4oh55q@Wlg-Jg!^tWj20FYjOQAz#Wn449)kdwu_p8rH6oRN_sI zXd}uOJzKB6*s?}g8haLg!Lm%tcFA`U*SV0BLQHZ%xjKsDeyBl+qx|N_N5lIGjRlFK zaUo+9=S5K_1>*yhcBAwoxtr}4nC5zRm!K)N?n2&&XESt8CFFW%iYfI@ z>^1g?I7{ocX&Y;5TN!_?xqVBzxf|WrihH-<(BbGIGF>X=?iJ{Uo!U0-Coj0Pc(6Ts zkn@hrinPI>xMQ#4xU6_70U$xr5NYy!qLG}yFq3A4~~2}j%>=_b{tQab>5W686J|wb|a-vh5fDEk-N3e_a-WfCX*0y;I*!1 zj4w=DuNhKq0fzWjcCmI6P4_uVJ7C%=hHv&bgVel|O1l}NU#2^D>k(&NIXndGI|r#d zk{)N{=>^2qTcj$miM8wIpDNuCNS%lsY7Y!wZ5E-+D&V44?cAK6JNg|jhV=+4YvI;^ z+&~70xOU!dXe^_%X<=0|s=`NZNimHLZNC2UwlV&aM=fsci<5{|qp3Nn%{C_Q?qGl1 zzShb&HS%zj`L`rX%frRS^LO{$?zLz%<4_c$7N#t$sN!Cb4#netnSJWz4uq!cw8r(%R|9ADZzn8 zfHIA*x^`AoTXr>)oLpr}B^rGHxNLE1fis$vpb^o;cOYQkL-l)fG3{H+vbewq+jsbKr zx5C8vO-@shjmB5A8gdcJ#G zh~X3o6#K=ww>V4ov{H_j+Tlqdj5FvRY@z#&HV^AJLN=M?3`{-%+Gh^=gp}$^pY>#&;BS~vjW^7?y4~5+qtsq$+n56yP~rj_XisP z3Y{xS&s`@kI{ft5Oa4evRiau?UMQdzLv&g67p&U9t7HXO({I)x@-cLf#_|ZR&-m_muFV()& zFwF0YpVXuHlK8@pr%#5er==yC+B3DK>I$%gzfKB-bAklh-yT&%^k{i*;i=%j1%pvbe+g7i*obR^QG1PIbXj}U4g;aU6O+&kXqzR$h$<@Lij zNV3m4d#}CL+WV~i`zw~wvevbP7pWh~sh*5{*3qngsc`(sIaA1n&3GU5f9oAwJNhyw z{n_cKRflt1@EVLW4lh+y8I;$~C0O}jR&Db?+~Xs{ia|;VLf`K^yzQ5lY}Jb{)5)&I zBDMR$iwznJPrAXDeZ;!fD>$>GhMzQb!Wd25)VY*iwS+U@%2|zV*EOy&Ei%On?ZJA{ z&1X4`vg!=CoSgkXwk0*HB?LO}Iq1j^T)o+J95?rQ$9J7sIGiKI}7ZW=21? z1w_#U5>@Q?kOEKbD&%Lj72Iy36l*06yte|iyhRUkb-`9;Ytzkqg{q`L?ISuGs`fo< z*|#%udg*NiZ-VEi9Y#+12C=Iv=PK@L2Og>Mie^~QUA>=~hT;~VrPj=)Ja^7Gb7n5J z_xh=>hwZ+DCd)7RMy)PhD8ftG&{9Gg38{*F7w}iFhBNrT?2U$2#vcht>K)PaPnm=V zm=PuCD~u@`-Tns_!LQ9fyaH+e>0o; zT|=tBQip6C*m_-We+tgRyCDW8ZPLPnPz$RL*(z+j+L&TVoA2;B@m<`fPj+l1Hno21 z%Gjd^v7;9@AI@8H>Re_SXw$`LqJ9f9d93|1i%~BKv@GhB5nz~j%%4qW9i~{4F z!R}T@^5~H6Tp`}aDeF?I;CV?Cpn{(F&w_8q1Ab`Ru z&9kv;>6uw8*#4N4`>jh|{+2`XF|#b~KwlG!3OZ?HahQo{vuhPc<#@vEvT=uin>Wp5 z`S_y6V{*F;E+a6|`kMHJqP-UEo0Zbe^?kF*q;Iv4ow2xR{D9Wvp*Ukyq{KHCXJI+A zP^fLoo(-{P^)clW;u!k$WxY)lOx#5%MAf5quy>@H^o_`HzGuxN_x^&sLWxNI@E31n zb5Cl!UAfVo`)YQ+*>HQWqS2?kDx+l9?1#FI+#bK}Z#PW5BbRGsrAV4RWiw0vB^6(1 z=Js22^ZkxoukZ}s#4anb$5%4DvwpuwRVDWgB|IndaB;o#j*R(7&Yb19;ujN+Wj+x9 z<>B4b-^YvHw+a4m*wt$HwSBPt;x2b5^O5aDDDRNQ#D&O$NL{|pq=`|tgN}rwwre`M zqwT7>ovr#=f-?y!L6AYE@)JEIOxLbz0-!bLf)C2(u%D?h(DtAa426GP{h{ zuKvda#hSLm^Ch_{_om*~OvY?GuO-oEg0zbF+e(+`IclUzizcHMA=?`gDtp~_on6>L z9cRSL$mfnG5-OM9e8;O@X0LJUaYk6)o1A={gdzR!S`? zrh@Q-N}fMoe}WP{RDG#eqb$iwNvrsexeiY0)vWKSgjCr9nzo%NjTSYnoG%P*0xi*uhFV)w10Xk@q~6*baA)0Ly@f*&8XDv%tH45zx;7=HHf z9C*f_x3SV(2vQrPGnzeYsRViQ-fIL?$|q0O}Ka%bjzdZ{4izR_EL~>y`L?@Nx`Q=#S2|*`f(Q;2&khU-7)<_-U0^ ztA0XKw|NP!|H3l?qmVfz9lIC`Gf+c_mo7(N@i2m!|~yb%|zDrHaOBOhR#(nznG? z(he_Mr8voHWm_>VYJf{9d+8-(dy!UGtEjWM$ujYc<6?c!od$C~-EZ=*Q(mtu+^{l~ zIc&MQ=)iD+8nXH)x;{r_Tf5W zZo}iQNQ*8JX9pT%Db8)L?KkxC&LqEQp&|_>ugY^6>O!>|rwQ!(H+`BGmW`8<{q=uT z@4Ct&Yt=23p1itwhpTSx%69BCdQVJ7i{5AFu@9DdR_b+}1BxIUW3H-IsT1w$qrp)1 zVh5fe(N0lcJ7?d1sI*SVv3SFhxlZo8BtIenUlHab`6B}>s}p+jt&+@+FLwR)OIik2 z6L^XQE^g95KxxzE{b#6|GTMXU%I5B63BR}}cF%f!q+jZvQ)19_*)dPD*B7Wf4<0>W zRzBS~q+3!qtvHw~W`6H>5|x}p4%eWK=H0QhGCH*7OtH(tl99FjNwW^q!H(BX6SplY zn9T!AkzzW*4lZ#W3bm%|F1GY4^PI9<@vi^nEgGD8sB2lJn_Tz!Fn18syUYd>kui2X z=pQ>0lx=xWsfXw4y%sY~t;xTp7dAqybdqv?otBnggt4|TWu1yU{6Z@UIny;Ol1 zZ{lmQwSxQHRP9D)G`fxwKz;;X=NxRKrIfV)9v?kBa;eUPBjLP;vZ<2NokCilv2Ug% zR`H~lDeu-_>d#HbSVTp-L-F{Z@0jMXQp0O-N*t?6uaZQihCV9=pN>%Q`EX8_WEG*W zPW})Q$@Jn)@9{Y3w~CVBP3GPQZ`ulT3(Ttb+r_qy_geU6A1rh-T15emF*g@kcE`er zHMf^L>+5Z?d~#fSjgT2kskyY->+gyp7$@1(acvp0{ zOPEH*CB9B^a@GDY+dfn7x#bkDb=xPVNc)O^#41+*3-6d;&~>3$t&-KG?$oDvp-89Y z6F*QcU! zn=<6wucxi6Rg!Zjbm|s~D?eU{EE1xxA|?q+W>jbGZ;9m){|Kcwa7(-m&B#!*4U9Dz z&xjRNc9QxVBcyO3@xsZc5`_o)f>F}jHxg(R(;e{AD(h7%FUi4M%d*yB)$x46g9>Rf zp2r|lwo*5A&CQWd8?VvWNlAZVDK=*4&|OnJbiKEX#$e+Z29>*-Cc?P=s1q@|4sWOH z|1c!wUy0k7I(t02sZ1f)L@812vPaJN85UDl(ay4)*Y1YI;iA}MzukJ$ae2RJZHx+^ z|0=;aDBM`B(<+z7x}Ihgl$V-!IJqKR)8$=-fYLR|d1aSOrFi#rEY7vHV2kDgri--e*0YtTMEr=b!Jk8TqusUW1r9G3vOzvb*}dnQ&fCG zx>3dU@U!0HA0Vp!?3;*?p~OFp! zP1)jfLqh@6BIja*B05_pv24Z$(^F z_!}mWbRhg(?&!upbRFm3q!A`~5mP zt*I~;tK!+&5whyX))jU85E7d$#M&f!*peg6L_ubXsUCl9-|Q^YKf9+;Cs!hUzq5z! zR*8rHxFo5MDZB>1=Y^Y9cU(*{>5v$I>r!p1cd@8-rcm5EJMh<-e0#=?E{B{GhN1aN zZpC5j&h`}2I|4BY-+MsGB{AWb52+Kw6z8KY3*q8vY9a|cYI39Zw>Xr4NAA1!`Y&Zo z46Ll_08l|tNvfJFR+74M`XNLN5>oUq*J2NY~B~U}v_@E3ye-_@L!Y*v!DFZ`x{if@!FIHWidp@zn69+pt zPDI!dB2}hKZNs0mN&QioG;!&uU=ux$$$r#{9nn$#ubkDIeT$FnEgi(bOA+iBrr&mA_et&&5ykX1|Y;1iXT(K?rHXtvpkf4qMtIcfbjB4n0E z=+Jqi5pQv_4q6gQockHJ>ZLQ?DFeEn$1c5#iyIdZJ6kBn5;)%0bL+id*&R{6?!PfS zRkCM&li-D8=M$3xy>PRA8B4v-RPlHx&(}>CTn^%E12}TvuXK1XIC6t$xm7A$r-JO`W4IDp{i*3p;56}v2MEW zforU(!t0RA$Wr{zCQHeX%H9>Mj_9HDXmZ9h^nRz;xvs9?X`_WAw@os?pe$|)V^%boi*Xt;Lp*~%gF zpnpyW^TX&(2bbGdaVcA%f{mliN5`97bnOk9#I1u{BKZ#I8b<4uOqHp!DN<*R<$1UM zuYRh%f{HNcad7rwW4XRSh5lB5zz9cLd9Rc0Uw zy2?D}(RH!-#ufa=l9HzU7 z<g88 z(v&$b9KL-rD2Mb$Pg*Oy?ih<15S=I$qz;$(*DGP~RLrHn97x2L)^&~obIZ(+c+ZK5 zSkiH^qd!!e6Bo^rr0i>n``IedlKlwe4!#vVNyf>;JaNe-xp<1uMDqyyNS~SX(Nh!V@6(Rh zE|?|N=zGmb`EGCcU|}3tR<|SA$Kc<#{}$Ox6#Jrpx)Zv52*e_O!A zb?FSHWad`-_f2xjb}MAEPOYMQl~|#p2=bq3GT$5k=F?wRs)!AyZn>Bt)pkbubr6Yv zg$*_rsx54YXlFMgP+|8yG|9rHzA~vRool$n6G}xrZA2n{7v4rrUPbUFN1Vsp8>sSz zeQOaQ@#jh0*tl^cpRuz@?QS^CniuN@|0vG}(i~S7Fq&nyLh02b0<7$+ktY;SNTrqA zibUeIHg5m(KH~DB?h3UAhurfeZn(O+@nfwa{a;&p_q`4L8p}Ykx+#u)3mgmQx+c6z z>nc{bs6Jd*>6;s7!lCl->?;?5;qUjEf+>&XvLQegXxnxOWMi$p8^Xkc?jGGqEu6a} zy!2{11KelTE_hgkxKx`3bJ&YK{>#U91a`WR`v5`zr$lS_PWQtIfmax@vY|8KCpBXZT~V4tgk4rE0MM@e^o8d4^CCpkP~@~PSuKwa9oPS9 zkk{f~0IxHG8+ldpC*8L(?O>8ekb=}rOE`ZIk1hl-$oXetdO{v>W*8pbI-}J5Ut0wo zA=~0v)aAlFRZ~@fB7_fuc&6kfn*7|E5*pIM6i^y!Mq=U3n5IY|Ydiu~t=5ocK16oee|tQo*C4hUL% z&127&b?x<~!b?4C5`7_Lsk)2>wb~>^-mlS0nWGr3 z*1MuF^z-ZUKI~Y(IzXyylP?`$oB6R$zzR$B1?cw8Z|aVn&O-;p>#(sc=HwyX^JeH= zKq%VKy8-Eq8KCzFRmp9J$NsKOdF1jW#jt3~p2jCNj;@+*Hbk?t)}CS5nzrrE$Qwq#IwNb( zv8!_TK-Y7qUA7Z;_Ser?o(-|J!LZS5G&D4>zyCunue=@(wDTL^6yaz9lVtqq<~~U- zuFb~~7r;Oth#7nL?$uc41H1YTm}@o|ACXxt8rMd8ErusGgYHg1(1v%k9YR8`OO=8T ze|>|Q7JYBof-drS>U!p{+#h1kTq7DsYp^B@-tfmCm!nU=&tEoMfv)!a1pEJRAJCSy ziOH+^qvDfz7K@bwj4Ep3EGTtEB9QRSBQV^v*KEBGy&m!G3t0+ZGGRK3cVxx9A>psC7rA+o~xIuyHN6cAJYot0|YC zWQyszDL)4idft$wUN{oxL6B!*z`Q!d7=ucPJfQ!OWaI~cgV?n8BU=LCHclI8XiBZXp-y_ZmY%*E(h93% zafGK!HMGKs$Fo&wx@$HB(0r(;f+AOx9E2SmmUp zO}tBf=A1D$j?*O>SSq!4d(Z*>j^i@fu{cL2Bv|mc6>YP=P)k%AiDxB!&|%k>llM0- z`)=irl{Q+x3l=Ne5AIf#$T#Fq*DXLANstJZGk>@n6v#d z2A~V?*X`saBiRvSn$KeTKd*iXyE;e@^%b00VYP4U4FbIEq52F2Emj@>hAYx_bktsl z;HoC(>r>B2bD+I|NY1A0=AHIoBy(oxsB;HbKcF>G*rN>rC9Tk(MqyZ3?y>br#zOplrTsDa(qsZvfBHM8DuvKBbLT zZs47X_S?+@Lvo?@ZNaLu?3|sOCymRXz$hus=W@gKW~5l4`>Y|E=sB{la$%~A;e(Hl zk5AOHfO5-Y;7@e1v>+qhjw=p)QA z0l()#%2N+CV-?Mi%))L_En@TTAm!deS_lCY9Q;#Lk_@Cs;4G`Xk+XDc0%QyzTKWro zA|fLAh4oL_m8W+ud}SY8T#mp5f&c!xEBFIQ3<~-s0Fdwl#b@>aOt9_7bt2}n($Y^r zTurflLv2RI!r=2zumhlf zhObL$Vg#H(aCdK;k33cq_4MgZIFL|KzXA8>SOXat(=2nW109^1G-Gzn3{Oh9nI&*| zelNdT!Rt}on3$iB$1Q#0IY3+k%;X}kITEJpG7k*M*C!HW>bRuI{yhd~Y3+uvho3ay7flOcry^jd{OfNy{BNjOZqug~FRA(VqY>n#1R>9%ovpYm2tB%Mc!ZjJdY(*{8$0^$ z5D;jNwl5nlx(VkW&}UjcejEXsV4{{f)GMr)<}p-7V^*vFWvp8lw~FZwS>P6~FAz5dWx-~U6*SCXL;hw3Nw}(J@K_?S^WaAk z{aujnk||+f0JIzQv4@pFu4W!3aygzeBmTZO31gX+2$%K?UjU!+_PyDnd;uc?3f&*( z%H~S_dftgvhbtgX=gFRFZK2WZ zy~TI?MY}7L5CRO;=^WW(3U-~zm?MHY0&7QZYzdSCInFSE&9f&;O!dMcdZmE7gUB`v z&so9yC_*13)sPAw;^#pg7BiELaC60svRc~=$c&R@c-{vfs!UxgO#hi$W6lL0mFY*L zhcaEqF9W&$9Ox%hR4V+#S}=o~$@Up~dLL?Y)4;@{kunqvU^^1|y-6X!?OWN}w!lK* z@Tjn@MC}Fev_2eWTv~Q^)BNo$+UAY-0sKfRDJeOOi%24Ro&mNR3rM49<20ceW`%Nd zG%~vakGokmsO2Lcmplbb8$TXKzD~Ydo}_PdZ6TTfY1RA zbShxPKrW60qRkqWD)wEPYBLQQ1_L^GkWWr^bx8Z>fDpO!U4YgiuVkm+ zE6|1zk$5;EV!G!JPd#f*H%y)DKu+t(wg`f2xqN!Fs?U#77y`P5L!gP6I}0jXs4u{q zM$TNq&G+0vU*59u{tUDgsd^UfY?~mInLg#>@|_10at3iV2#>BGWfDOq4*|8YIT^Gk z3Je4pAdt0)OdRVFs2G;b_i{HSVg6MdGuump6_u4PAf|Vi*F`%U#<>)lWR*+#JT;L{ zMu0Zs82MOehdrB5ZUGOG0(86g3u^+Wajw9E*XZj5aTiE(Z@#!9giZiFTD0pbN&tp^ zebIN%&GZoL5JGJ8$B&7yO~5CN`+u8YniP2nbe%9AB~0J_(N%C8KyUU0e@SPbyi%Jr z{pvfOq2Z)BT}YDHdUbC++^*`7n*Uc?xn%#Vhq6MsGhJaBB zgGh-fmM$=Z*@~1hK{hKdpTjoMfAFfP6 zIRo?(3;aev&|9BsL{o&!Kp%Alb3OwY$$vFzE-qP2e|yjjI@i|L7TN&_-Rs-SFJmm{ zp1=+YLR2CdSy0#&sb21Eg+oWGSz=t5a(k6VD;3D3_M6Ap~gYP75HqhXi%p>`gPka zpyn|MNWkq51F)G-P*9FN3Ere%d}S6E4uknMfcWclqq@}a>ovkLE=!kz=PVDN5L6wL zfgTEXByIG#F3h0d#t|}SCL`B^BBV0YtnD;0!G^gvk`Q5Z;gG;b1)8@hCgllRpjeVo zAPQa~1w9(9L@1-P`aTqJSt)p9f=-fF+(+nQD^?%e%4dl$w_@S#Z2+`Uyo1AJNo4`> zI!8dFwpq$&l6%#iBZg((?e0;H&M*t7sWgtRec3`HG7I=v{i6FeUfxkq1LYGIRv^F@ z4w}q2QKEBc3kWeae*XMYb-w32P$05i=CC~{%XxWiMR!T{10A&0PpT{#-O|j=3=5v- zpt3S-bl63yEWAg;C;xStKrjL|R5!V^!6I`Z!z$FwmhHE69p2lYQ8?c@raK zQKknu-%PwP`xFcqD6KUDg;h>g_E|<5t7iHNH1XiYK~D)3j6`2ad_ zKzb(k$T - - - Crunchy Data Container Suite Documentation - - - - - -Contributing :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - -
-
- -
-
- - -
- - -
- -

Contributing

- - - - - - - - -
-

Latest Release: 2.1.0 2018-08-13

-
-
-

Getting Started

-
-
-

Welcome! Thank you for your interest in contributing. Before submitting a new issue -or pull request to the Crunchy -Container Suite project on GitHub, please review any open or closed issues here -in addition to any existing open pull requests.

-
-
-
-
-

Documentation

-
-
-

The documentation website (located at https://crunchydata.github.io/crunchy-containers/) is generated using Hugo and -GitHub Pages.

-
-
-
-
-

Hosting Hugo Locally (Optional)

-
-
-

If you would like to build the documentation locally, view the -official Installing Hugo guide to set up Hugo locally. You can then start the server by -running the following commands -

-
-
-
-
cd $CCPROOT/hugo/
-vi config.toml
-hugo server
-
-
-
-

When you edit config.toml, you’ll set baseURL = "/". This will make the local version of the Hugo server accessible by default from -localhost:1313. Once you’ve run hugo server, that will let you interactively make changes to the documentation as desired and view the updates -in real-time.

-
-
- - - - - -
-
Note
-
-Please make sure to revert baseURL back to its original value of https://crunchydata.github.io/crunchy-containers if you choose -to run the server locally. -
-
-
-
-
-

Contributing to the Documentation

-
-
-

When you’re ready to commit a change, please view and run the script located at $CCPROOT/generate-docs.sh which will automatically generate a new -set of webpages using Hugo that will update the live website after the change has been committed to the repository.

-
-
-
- - - - - -
- -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/contributing/index.xml b/docs/contributing/index.xml deleted file mode 100644 index e67ba93c1..000000000 --- a/docs/contributing/index.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - Contributing on Crunchy Data Container Suite Documentation - https://crunchydata.github.io/crunchy-containers/contributing/ - Recent content in Contributing on Crunchy Data Container Suite Documentation - Hugo -- gohugo.io - en-us - Tue, 08 May 2018 08:57:09 -0700 - - - - - - \ No newline at end of file diff --git a/docs/crunchy_logo.png b/docs/crunchy_logo.png deleted file mode 100644 index a3769acd5d7e8e8fbd7c57e525a8950afedf17d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 205471 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

0v>B1YT0OzBo3U?+;BhCI9(| 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%0Ap?W^y9>p#!6Po5;OZCC!YRbE>f?pSYNnC* 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 z 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

V@o}7c@BMqY?q@&6_@ZnZf+7Yl zqkI7Xn`0tlk7uV$neAjygJogdxJSN-RUf}coJO>9Wrp;dZ(fo6xnF=W{%JzOoB#o7 z^hv@PS{K3$AM$a6!rIVfnRxb1CT0eRdW;VAXwtV0-_yf^4>Tb*D`2)P{;EO0?3W48 z^D=Q%DwtJyKuR#wNhcg{Q1SZW5VoA@Ej*F2|JWxYptiTR&Dxj73znA!Q{G+w=uOAV z0dG4Acy5gLyALd|%tNESJmKg|4v)lu+07u%qpDxzDWjXDSTHwT4S5cep2pn7f{!wA z%Jy0^({Z4EvQhTuezHuw;c{yM6OQ@ZB>J7}kbK#Z=PavE8&sA~)s-h78gxisqYS}K zp8Lcy`$Q4DGgdp#2*>?x>A7)lu4&U?B-7t$PqH)fi#{`nR=&^ai4(r6wHm%;&&~1| zm?WF}qsUsD17LbGU8E;WaN`G`J!;ba&(P6zzDw!P7FGn*W^4nshhWsnvh@dK)=sgS z+FE?6!GT{~lGzSpXrt_uZ>q~y!Icx9%H$W}LdXyL5Z}0UwOuQy)8dU>`ju0)$|(no zzF4B2UbbsNi8qgjg|XGykG)SCHyk&b`_>+Lp|DK9$;|51ZSBn*--n7N;VKi}+4cqo z9Pin4c=liNjA4K3kH8{~z)CBvG_bYQd>BT5Ctx5sG!7d5hLv{MiR%X00FozltjB?7 z<@Rd1{Haz3Czj(7NFTUjJ3FF7F+ks#7iw&;`jl`50g>r+?rIr~M_Sye{ z@Y$_D%as^F#ldist;{IDSnjNTeblHCa~zDXv(7pru|LNrI5|L@&0aTNgJjbW949@d zPoEwxy5PJp{^5sgGQ%F(h-O7I5f-v*Lc}g)1`|;hH^nM)QhD^zWe9A!V2T0kU3%EC zaM-uL6;@nnMSDH1=s4Kdz+N#UF8KpJC9Hm#g15$8eZ^%MpI5_5!&m+9t1rBGMY-I0 z^)u6^J#Dh);(+)U#y>W3U+j~14&u3_y_%KoSTJ0WeBec#OVp7xF~Rm@vbZt#_N@6~ zXbL2g;Y|z!|%NRT`I=ajWK=E{%D*FGZ5{e z!Gz)9t9*>YU`}heNP;iBX<=+(Vcr@@X@9;@B7hN&jn&!SY-Dy2HfPokOfTU~PGkLn zJOHIWBRun7Or-*re(^5MCfuSS>0C2|qus=q&$+Gc6G7>`Ljk)m=T!A&@BS{@VnTux zPa*2L(z#DC!z)`z-kYiJY-T*X?U^yGDK2iLxkow{kWzmj3`~MY>>Q4m(ICBv;(`3m zA~|M{;}X(sBu$-u@@6u;TC<6KF3UuqEPn+jPts!*%+TY!X>J`62HRsNKXT}T%@}JY z&r*Mp$wJaz`;IaPK=1w-uQS*27-RQ`rs4TGgzR zAAAg~Q21mh-oGi}vwSoi7pVP1p>=ti&`?{}T?3%R^!PPHy6qyPFMy1Jw0LwqbhO_T zzW34bX48A{&_AK^9&FUU>e6Z}t+rvIsd^?(!>xJ#+W?c!_<*!qzd+}M#~I~H=|a2c>+>#FEZ?yXe%k@DYnOu`1zE4CL2e zZ#{1KndtF|L+I#if2O@F?6&d9_3y87&AL=Aln!ZXY931b7;mhiHd}9gv)NQgafd(9D z<+qqbM^d|p;xP$K;0#`J$#D3$jtuLrvkoRRe8CHOk-F6>-ynlzoN&17Pj`h;qc;v8 z{pd&U88m3gZ|=VPn0eZ_;fW`nSaSU1kN*S{83#al$tH)~7Bh%ta}~N}hdWwlt9aZ- z#^3r;WQLHO-)c2qEjFet9!wTjVEE(?O~~4UWsm-xeqYOkvN!|3wiPg;!9juvjcsOB z0GLo7L&dZfn^iAA-p_A76;daN4U$ZLt2E5MA#%YnfwNfgNsl+HvH)RzlI-d@>f(A ze6s$a&SHjUeFy3c#I|AqHqlfbSWRt0xPKx8iDr=o;Bk}Evhl47AThC$hkT|)xfz|| z2_W2zivyv~w%>;FQ}A|}{vF2;)y~!KO2p3 z14U1?mAyThTbIDfkNp9?4*r7Lyrx?v|>duhk|qI{sPd>O5fMks~M6YwNx?Zv6PqLd6~& z+?#*W>1NO#4t)8>k2j{jft48-gvpbh3tN6>oBIbeH(&JpOV9u5jyvv{X(O&R)>xyp z+EL!PQmB3bqV|KFVe#IG3Owas3V95LPkB901sBvNJSwvP!H0y8ef;Bi?1aAtGYI^z z4c=L|WH}F@F;VaoRlZ*Kt2^yjU3%y;XRf{W>ZfAj;C1Jis|@Y9#%r%nzoetH^RsLN zrQ8-P`weZ31F3406>-u+%}qOfvOzwWbD$@e;)Y5pn^N$Ye^$Z4sNpMtMvShS#m8d- zq|bRmyw>?Cfy!7z*uA3o`;d7j5N1)*jTS>onVh zC~G7uc$qNqu*{UTZv^!I(M*=zo~!RAdmH_r*$psbb^e9w6<%%H(Y7BRQCp@qNvya+ ze==bfFr80!P4aV!ua6F4OgQ=9=Y$hB?r!t@-Eq@A+*W5WCdpTpGd+q|iXRDy=SO7} zS?2=9u8v#7_cnXauFjyR{Sz9DLVxPD2n-)SeBE)Oa8gsD@KqX78#tybMeY2w6PHBz z;2gEVYqfeqwX^fsXI^+=3i%t;SGWJ_@GtK0#k1ad>&+d@_(jH6Wq>~oIHd+Tb$8@tB#4tq6gTib6sI@%5yJ$m#^6AX>|S-<=4y9X4j z#j(w;%`Mn#Bl-h)9EhU;y}V9wqUD_#Gs4X`-BiV@i2J^M>~}BSdY7Gky?miC%e@z# ze)?$+lJDgQZ-cq9T&6*`>ZgMT>fetX`F^rIiqXEQ`&SSw<-#hNIOW01*)kq}ActqpP#udF4O&tslBux?#3H<9w6X3#S%-R(Il4q$(LyCB~hcX#l%%V zThth15~JxwP4qLd#4ch1E4_#X=_m>U(zf05KhHb!&YgR97Z!vC;vLvCGjE@FX3jk` zXU+_OLdWuAxqJqHYYHMGlt*SKgJ2m@AmK;~I0q1NA+$8ndd&c=$-;HR(Kq~a#V9a4 zd)0SZppcGf9~`~UuPvbi={O(q3i7^!EP>&ou&{j+N4WT&v?>5;2F?24919kN$U|P` z3Q8F?29g_urpop-?HhUGNsW+g$cxm23Uqq4jI@m*Fvq5y@q`Nv6Zn(*R3 zHMQA+G9ZroN=TieVB+1%2U1WD&q#gB{lyv^UNZBOV`JJ%*^T7^`d{lq+e*AXr4F3| z(k_^G?S@H_fs233Pv9mFGSMmpbLE3Q-edh&2n(N>C zH@*Qs9Y@?-@lEO?&>GsL^&&7_d|5HmnJnvwhw8Jy`GbHPcc53d#su@}cJB^gw4PN4 ziJ1=l5vJ8Cg!wcwjSVZYXV9++{cjGO$}NSG2in{NIKHxMK;ORKPnl>WRy}-;13no< z29|KpC_y?iQq1BnVQ=y)v-#Ym6|-l5cV-Kd8U6e8Id00klb>7h*)mLK;6Y2}S*e8^ z17z~k1)jLE|G^{7wKv>ojyn2i`Gn8zcafKgj9f0C#l9Oi^-+eRMfpjSCXVUawe#2Sx##YqzIDope_hjLh89EP8FS{0$8o7A zK<>{0%rL9swtS3-Q-9Wxf9#EbI5+gXO z#xbhgFm-IEA^Vlxci(-zCNrS3Y|6Chmp=XEQx9G9@!#T!faa_K%YkfHRNCdcpA%tiFbS^f!ofo*&5s&;4DOP>v0x zjH!?}sB9s`sI290|J5gy$v+7$q51f#2hu1` z(qRUGO+24LlOzQ(z0=0fRFHIF`s)1 z{LZ7K$6t{=CnI39Hj|FPX7DP5dgZ%zbFsN@+<~Ep&z}xE5^bR!E*2j%O)YYY4lGMj)7T*9CrWC=k7804qwO5B`tgD zx}F~J^`jLLlcUuoXj~-E*!}s6jqz;`SuGoFq}|O0fd|MS>B+qu57{`0DEnueP=Xym zbhu1o)F8x?WgNm>T0yi-@r=1T4DSog^)K}=GCGm?22L6X`Y^C^Z!DrJ=p;DQA$b4@ z)4wEEGv{-EH@ST$5&hpBw1)nh%UCMgX66A*Wb9G5YSp7rBKb=U1bfQP zJMLtD@WV^Yl81%@Bj6>RYXZwc z1Kb}KNx4}*2UA-m&kF|LqN(;KBg&3eCHTko^8zg)QOWk@m@G3uS=*;z_d z9+X~U!oz`>GPY5C+31ew;QPy_jcQLA(+n}4W#pf;i?RGE0DVJ}60bC6jVl~w^AWoe z{h$M6fKLp!q~1QH708%kYC8;2o351DILy zK`f?=BnSagi0S)mcCyLWKI4$3s4YC8^+R2n4&yM*deS;2oM~+V!P{) zMRwD6_h$eR9IOFNHSo zz%G6I^vWa>7h!;RI(p;QexiZewg0jMHk0O{5cFAm8S#f?W5bW%`|!iXaie)cN?DZr zCO-ST3Zv=)6y$YC=XbL4@WjtgFo|HgZ?~N}_V^QUg2@rse6uT_qY2Mo?}(HsOP87Y z`udd(nTCI6>+7!{Hf-3OxXv}@-yA>wU>qrWFKq9~RSr@vvBU0_fr$K0Z@J#%mq)O}bO<E&AttTNMTAZ zc@nS>GRiMCwW%dG)52Bd70C)@D4TX`r6)X0Gov)h)7CLxQ>jg1dBU{V1R_u8+KB*M z0fZiDrCHZ<2tS!A4?zanDlaBfah4La4$nOt@`+Ut@e{lyJpykSy2~n#7`w7btT?Zq zx{D}WCIIrg_GD^bJpEq;>mzu7aSUK%`r<)$#d*Eal*hC}5CS2HNXadT_K$K1(#3vt! z6dXy(1|Dw0%FRzPRYvwELD~_ajz^DrwSa;yu>qID5xSzx^GWMs4X9G) z_Kn+c!~U7T$ggFPv@=c9T4u@!X@v{`&r2i%^YS)3aj~g+{XaOKbOUUjhl)@=jMXMF z$g1_arB09wZ55dE1@z4&AAB%rrss#rWDoHycNo+TS6m?|qH!6q5sZu*R@a(*@`X@L zDZMd0&>hthTbL{Lrft;eRv4>H+Kbv00Hiuye$8vslzHRF+6EbG+m371_D8ss!4W90 zWF4Xi=IAz7l#iZ5-VL#r){O1eO|J}p`ZwBo1u}&$2K;Ab@{-MTP?uxl{=gtg^w8tJMz5J6t`{oi! zzE$BynC(P|c6@gqVT8Re3_l&I++lzjaoFMJfP)S)+xO}vpOkPwTVGd?%@Ol6aYK0_ zn@{|wAW(|! zdgAd%cEhI`y*h5a_5E|^%xTpIqph`pbmPX2Ydpl5AI|SrnLg_^oWu&+a`T<3Fvtvgs}0PQ>jR+9Z#=4%MD&fwrjGE< zg5#5Do$t2gm}$YQ!zjXMCoX82HLr09*K|BqT8+i12)i$q!WQiTsb^HC)^~AZm3Caf zp`@M;Y2I@g6eh8bh%Ktkt~GBC!Q|+1^1!I}uyfHwwp9;Pi=+W-#^PBX0XrP`WQY>e z3q)&4sSb^mJd~+0#!9Dnv6UGnHdTOrwTmW%=_YwG+#0HM+9oX2@vp;dEaj-IA{m-N ztZKc#94^im`Z52>uT6H_qfM%OggpU3c@RszQ?J4_fqYzMm=Dt&V5G{nHTnA6%*79W z)!cCszMKC%frAsaN7$nFQCz&tgsB}G$6>+)pstuCJ`8X7+8){7cJ)e7_K=3@P<|X2 z;`zCW$-ZqqOsv=EqRoje!Pdb8MfDWar^4g07ah_9$bGwZ?$PQ`q`jC8ow#GaT1-fC zGd3I4{pdvUYnnV^Ixb^ljtx71hu@N4LOgq8)6kqvAuLRLNATTdbOyFc zYmdRfUUFXx?-i=0h*yD#6|QlB!ixcH23r4wN$>2>x$Quk$1Jf3q`6W!rEb7|^fZ zq3B~5=kn3f*u*m_1I4h@$?tr8V2Zn)+{oO(JD;D2&$)l{!Q9z@hh=Ws(wM=0`*vNG zPaMB=k@+TeT0B(chl5eBHsD?hNt_(gq0?44{`7FO&%XPb>LEi+w{39@D<(LwSHw!F z8-=0h<2W*Q!s5k?Cyw)&${zp#KmbWZK~xwqVjZ5`n)++6KamRgCK06_u zPFj$TLD&Q?S-B8XUS45pSJ%FpNt*8rud4c>fNfn0^_IHtz6VeFY0b6Qzy8WAm8({+ zgwN7q)6rl4iaGk2W88@*l;_)q6)vU)6A#u@P|;A3z;>NzKpn`6jMcTP&8x4zYF>Qd z1v7E{c=K&c;#9P2S6GoE1-0VCHsv2mg9(eG$qQNsU+Tn(NO0|0?9R6ELugesz1A}k3d;xS#I|fr+BgcpGB^@x+hO}Af`im3 zTJs4F{AH1Hw^VR(6o^!rH_jypXK0DvV%zLWGkkdho3)PBke2e^hmJ6wSN`T=wkM8- zTgy{Kr+%bh=gV*pfSO}ho0>N+!w=MRsEaOk^#(}eZQPg3mEGqlH}D6u@xT>;$@CGX zWA6)rx;c(sw>PsKm)ZqK6XOV4r!R(HV^;h_3g>f8 z=FFJVW}s{I+=fT83fShQu4C;W)E3rR*uFiSa^#V@r6Md<8J|D2K`;o zyuy@Dh=Pm4mA)l@WeMo8uRhv+fBQ+4wlggsVo53-{JyO_oc>O!=zvr~8$E8wJdC5a zuD~jd?fqvVwA1@v%M)1AERJ+8@V729hafiyzs1}$EhxJZA@=2E!s$`jzRo?7wJFnx z{n4U3z6g6~sHaL38tREHH0Hh$>1?)pBAHBQQ>krSF``s1w>+Q8tiW-meDnXg2I=eK znjQM|*%JfDA7EJbjYJ}B3YrS@U%bBOJLS_r%f*Ht+i@y{ri`{|5%^JIX${r1~$ zgH-^7@vL<8>byA#eYhV^M~SfA0`39OfIm)P$mW|s_QdLo%F6y`=6H_XF{B^VWazVPOo)3(Ey_=aRMbsAPXMBIA<_F+{< zxmmVs+3JzcJvaG*zx}1+v*pW=Os7(R%Ow&&`v4nws@B&hz23W>>2Qi!w)_liMLM9O zq5|_EI5IYw;cAKVu?pq=Nt34BvnrMN`+frluK9a#73$*o^XD(wp?B}|;PIE>^R5Dh zk94r!h?NS%_uki>{Qth`eJS_MK#o)!FH(<4;6En__}9=-|8P2;IBUo{+C}jz^Z6b> z|HYlxKK0n+XU_a!hWrBZGZ0P&RpWTp@0@z7v=f{#V{huvFYQTfqfImh<>5b_P!P1E z<#D*2R9d|FQ!{?tIP=VtPn!4MeaEa^zTE7w*WNhM1`{Scmew^sTShC_woy^y^+1Vl zyW$RF_(S9}>Q}LWw&6cln`BIGfQ7a4TAt(+iCrqs@~bimWMJfylJI!J0_2evpm~Bh zDI@uO7e`%+wsa3@{Yp7p-50^MfQmz2+5+OD_N8=f7}vc1J#?z$i#|0`^;!noUIAr8 zhvAI$ncCC3gibom!ZR z8S;jB)#1c7jljIV3Hm+sXs11O|<5t^kU`wSBYRcpqnA z8ZY$__rL)BGT-;ufJh>JGDu4s08<_?j}t;lv%$l)fq+&5^4hP2A3!ycJPP9ki|iXg z7-*D-8Ri8h0)w=}IdCB&yp8X%Hy-qnx#rb}@L+$D*vgBP&)LZG;J@!bG?spq5aJZ3 zcnFCS-P{C}l}R3zV~)PWr=(a6B=yIcyAmfmSbnj6$AQJE%l+bH`9N>0Mip2e)2O9(qfy+vCCI{_B$M%`9}5NfsM8 z6L4$49{X?X&W%Qs802$5i6u*xnAflp;OQryNWK5wyTkEG$5Um=xwB_WyCdD!+iYvTbJ}U9 zefxH@8pO(m9{iKZ5o@PvvaxG6GN}UD_;3B9exgC3k-bvjAF%--mI8xp&$A)-8!9}6dDgCDzoX7(q`Gj7Xh;Z}-$y<-?wnARIY?&V5Vut2E8j`lrQjxUH z5FfM=wh2BYw()Z!295_q@9p^gNZ1GRSbO#6Iym#%j+vCeawwlmr{I`u!)s=%?)VLC zMF`jn{l+VYd{GS5AXHivD|z5a!a+q_`%vwW7|Ll+lludKt~_EdXQ-GIsrBOlNC1|@ao&k+>p#^B*-Pp5^Z+&mH5iDpuB6?t zZo)c`<>NFY)jl9;Q-=o6!vuorx4Gcz@U|gK6O%HA zvM5{cN0JtSxB%|us+>S{TPCCYU+}Q_J-ngXN}iv>I-qG{r?b)9OamP(G+)b38TsHQ z=VdAznF5~|`NP45hh)s-FVnc%@asi~-p9vB7YCKAZdKvqhB{+?tsf z)6W2)KwrOz@`+{mPJa_efyc-y?f!s3XVa=Nfuj^*PCLrpCjw{TX%XzO_BewCTriF}U6Jt-7AHOb{PSkyv(K7^ zA6hrDelXi0?c&SF9cKpP^pr;Nt!<+!Npw)L1|aAU!o^3l#}PBnKTcwBRSx}wBWvrj zjk%d<6SFV@HxH=kQ9k>$ifdK8T_R(aM@wy?9S8KQUV$*rAU%%;F#slDhqFKn6FLVV zZ$7cTqD%3X=z+8yKqrDa*J`(&#kLnM8gaf2puPC^qXgQ9G{2GKno&DK!*5NZtc(4A zIHphS6T2Nw+AY$dsm;;xZDcP0ocUp&wd{p}he_dAABKK$iWN^2LR*|kHUeUu?u13m z8#qHF5!5d>*UZ(?714$;%D^9*S*rpk1LRh&G7$TuORG(6pA6yZAmWrhtY1rMuQdZ# znxBro%H$G{I5sD=81}@xfDE+{IcmW@Vh|%UP#vU!nQz_ zUY{$Fe~a$yQQh8dwKGuYaRDq$=A$06d_zS#RYF3T`at`>(ouIvONIy)n9a;X`J0?1 zC-O>{jpqTj8Q#k!xLC8SJ54hoXu11 z9`2S7#TQJiYR3igb zIkOV+GE8QC4A}0V{}L?g4ua2c!-^Nt60Vsm4E*rOOZIDJa}Ll!IdHCzd+&MUg z6(_#vWCnylqwHyM;K2vk$tXI2?T}7(P17|?t5Wd5;lHdJL7C>EpwB-2lzHW)moSm> zp}=LOgouh{uZ;ZaRBU<5mPF84{xizf(Z=#n4(?D>W)k{ z^J!x?GZ$iBYcLHj=NhAT(&_xdL4$Yu1ahnpYjNwZ@04XskNQtJF0;XjQE5{45amWw zY)8Z?og^H<&s74+xAFOWKZ8|5_;buoUMbr0JRnt!dJXO)(g;}R(gd4n15!%11>z8- z&9qTdxN6K03`+luWlX#JeKTC&@@?0dY|8=rShg^bz9=XII!$B!YLksd6`@hJe zMPlStln0R6A;qVKtc8O?cu2# zRZ8IN6bRoof#m&1gSJ0at9Ha?DgCwkzi58)+PzqUc`;VuDAZMt>S63qB2UQxSA7Z! zW2I#rC9X49kAB7c?*Z?IBX!`Lp@T~vbYXuhvMr7y1MNYOGE*UB zDUax(UVw>e>+sM?SyMCmcUU%j9DY-==LHSG#h1_7=D^-OwOau`&qO?E!5CAXqY1&v zCUQWgdD_8c*NOZcaj9Q~d}%^sGp=QPB5-(=Nd6q{c`#=qIiT_(Oe;_ucXPcxpcg6f zY+ zd)A3gQ33tj+;Qt|yP1yIFJmjL;MivCZA?3SQoy(H7(8R4Nn#gFa_oZD8>iy!`HG76 z9mY+ZJaq!*SGYpt!$dx{Fqh0_%cAIGY#bVaryFE)W&6;6 z4ZePz&-{QIK9hm9Iv#j#Y6{zS!Q{=ulc!Gm?Su&vZXG&w=xmkMT>K!8cI#W&|Iq8N zxyDSuH%CWd!_6a)IvV$8JgrhEcdx!60Yb7hZh% z!bkq~uS-Wh`%Fdcs#S8*h*f9{)`&74a`+ME%f}vTCmMYFa|L(yc^xj#RXhC5XVK!t z=7o{Zn}c^ZJRRr zM;s=Fmee;kyoAq;UdQRD&sA3soCq3ctTKL%_+ISoa`hOTw8Kh)Sdomhs!&agrC+fC zq*DZS6UILVjcv{iDEgVLzJztIHEVf`?RZMj=IH@xAJPz9J3-n#7g~U88)Cg{ACBA> z2pQ&!+RjES>eXYugo%vbV8A%Qem0=GV5gYpj1zlkyKB21M_b9`;5I{meRGGCUvU$e zXwnVquz!XKgaFko((EPl3;SA_7aM4Y<9F-^0>2T@$r$h77>;-iyw6@b=4KPsqaCFO+Pznlp8A}88E7=4i+H(b zQXtYK(Y%s#wMn|XCnm|;xVC-%Y9<5J89j^t1?UR`g=g?0hPjfk+y(1 ztRsPI9U?;-ZBM?v6R1pq5Cs8S2r*h|H^8bMCM2yfaZV=T5`4mC!@SZum}Emd(#$$C zD*#s^34q#WLsn1RhKWy?k2GDjdJC&G_Ac!C*cAj)=>k zEd6a4F-{+4B=Nl4SU=JvGOw%3FH&5Z(AYd{JHlkfg%}*&fTr5sA9YGw*&$r}FETxZ z$qk8(oWuwrPSO_c2hgMuxfrH77ReKiAOmZUurPn6JXL@Pf+Cp?rzDX6F$l)vqk#L$ zG7V3^vtYreUQUpJjIvRqM(_RD<4@KsS@P*o@4fe)Y~r{8lNeaaZ|Z96FbSDOj2Cct z=#b|S*iF;Aqc0v+M5ISEK(9_%x-D*%~W6x?qI|_POW;(+|M_ z^$_~FmYY^Yxm8KLp3mm#0>bKuvF=-!MpD^A0+hF#tI8i$&hW!E|VGh1L)d~Z5T8`&0v`VdTBVwOHqUJ za#Ay&?`oE0D#0)vf2FX+c>t4?(c5*^L>t6LXB^+;i^;AmHe>Bo9$!{xJo`v4|3`COD^9JF zegHn|^|C2Plosm|lN_C=cXrYifrWAiY~#QIH0@BcyiK&DnKDVe6Q>O7XTlH^Y;$YA z(ru!fOd+Gn)L6x+pEU-LusQxvgtBOS+y0-JD@I+4w(=1tynbQAKcM^nOqK8e=kqvlbH? z>5fu<_oB)wWSP{jBy_sO7p}ZTesMIEVWNf1l|oy3pgXE)sjVhyi>{8OZK6(!?umh2 z+Fo4sT1=SHHlX#dZHRgPX`Y;pwrFCJaL@@mZBjbMVF+b~Y1Qv&gwO)rPE&R%uO|dl(_#Gp zMzDbB3o`S9Kei91qr1Ijm@y4F`02WKEJpD11aob$%YCeU7Hni znU)6492+$NgoQ!)98LwW!2`|#8VANjJV43Bg#wY+q#qatFcoQ4LRKJKaAfDG+2mK^ z9`piMD?EXtOU7Vj#oM8ov2?p3g9aUN^wCG3i2?s{ix({}pO4QHxG#b1Pe2_(z~>&; z=AyFlEqq4a#MiA_ZI+@CA1zp5CXRheiqm=PuBKPd?M=V_{mt%!2AN%U-o^Cnxt$Ey z%gf3zq|akDhIq9T-^4R;;-GeQ9adsYG-I&(^qsfgHnV2V#J*V>`CKBE!rlp3N96EWQT z0w<#M!lc6;jg5)(u;S!dkdMhE^3$-FN(USod!UILz770fe%`Y8zWbSd_uF44b@-`^ z)|ZtF#jwM-5dgW$0sEJHhRKZ6@p((DCo}Sk7Im8P@h4Z^ci-Q>|KI};bok`sg?7b+ zE4P+|lNa54_B7}J;0IQH(EI;$XYM$w<8&>}TPq$AG88Qfq zZrUhB(MPNgX}nY^wmO4ZHqHAqV6M&hdX@5!8NroJV#(v!)+kktWNAW!{@4-&+dz1K zkhTzOBibfdKDGe{_AO0Yh;2{#aECHQe2)10PnMf59rwX^ieEKR_9VPT+Fp+D%ewCv zeA`9BmjgB`+}{jfgP2Ynkqk%^CbWXIZ>ci%)A1egBSO-e3t3eT=|z;2$GoU>1}R-g zqrQ|_>B+bWf<7#3-Fja+pDElHvS6T;%h3=gklvBucpC$|Ja0H&RW!u#Q}v(G*Rxei_2H!o1QtR^b;OT!aS~Z6Bm(2xX8a z%nKeDfiw1kL8ow00G!HZ9MB3{X#f`-1u`I``a-*e#-fERej%;!shl{$M$V_Pe^0hy zrb(pm`MEnplBQ@G)PC#q08Rvg_B+Yq683XTK_ZuOJj`j5vDUStG6}SuZ2i-w?11MK z^hJwH6B?UYjqgxdc^aDWjcB-Nu6AHa6J-Lz*{TCO$;KPC^Z|LFA9NB>@;6yJo9!g} z#@~sQXzddhAOpLTE@|bbP52n44s#eE!K68`_iempAK4g1uXpc0Z_%1gRl%na?Z&_L z);B+1y!gmes;nF4aT-^wT6yoBSu@|q#`id>G%)~b+dFo(MGv*l*`lBH(a)X8${MLVqEz-Jg{w}FGqZoBVlw(s4?zTL;e z$Y-B@X6ECK|Mcn84ObR$Wyb2&*s2tUaNwN4pV)vr2K=KlCUe=GISXD>pM>$~(W5)z zVBOzg)yRSMn1BeK=O?X%0p*Z#F$RFe(pd0By9p`giNl3^g}Bd9cEakEop2oOIq2N@ zi~u`jB$MsAPX#yMBz^z>{V_p=6Hc&?h6L!~gbC|a+nL0Gvz+*>WnnJUc)^e%)&I5( zYrlTH?BfA1O?mh3M;?Coh$rv~NF!F($YcXqsZR=q$3@s(jukcMV4`8C9e1+(X3!4M z&5Q=$_izmCvoqUMp782Ds+1s;Lp{Z_p{kDdIQh z7%8jM;cU0g1z!E2CipxEm6otnSpxEhg6tnkT8g(o53o+PJuv2<-bYv*;^RT-J)C@a zt&}&t%}-w59|J@*Bs?Vf;3gm>PdM{2d;(ifN2!ju_iv3p$i0wu#1F&aAgn~^tw3kQ z46&|cr%`OHh$K+IrV(qpiJinL($UAVfZk(nI=tBxfR3XO@lBeBBDoX_`xrz%F2sj^ z6$Hyb0{%IA@@&cwmcyrMUl6n`0jP;zL)?0$olj(vCG?HL5qmqFeQGbWOk*;7jbU}e zjqv+XnAP9G4lc+T=u&wi1URBKggAw3tTY_3q{{l5Onr^1$)9Fw*1lhrvKHwgQ1xl7 zggzfr9>Q6qy!*{oKE@60uuFFqZ+8OTAQ_U{!aLu1*`x>v5I6{4p4sYXz^I1++<5I$E9 z0+m+#vX|Q&vzO8~iJJYEn5$p84-bpic!g@en&<6z6bffn%c9Kjyuis2_(N$mR(*67 zSMlbsnNT*m>x*`>iMoSvX+k6P#wJczR#pzdZ_+Jj!@d>UKEVbH<6QgZAWa6fK_}oK zjHiHrW;upuD=}c43G_U$trBjY1&t?5Ym?v!LO_EZ!*3o;`aGV4f3m0&5M&9DBmlz4jXR5;nVBgtE1` zNoS89Jvwwur+elSiT;UPv^NAF16!)FvjN^TLuuH_o6*X*?y?Cb=s3__g}of6O_^*a zPaKcqy3?jx_a1nYUk+T(EL*nBEXN;x%{>}qpo>pgB+#jVV^5I`{P8Q;bM2hj&2OSL zDnBaKX=>LyFsMF8R%VE2oO@t%Shv<|6wd#UPdtF4i%8E#95W<<1un_eB>6_r%PBaC zj^xKCo|sI=L!ro`JPVVAz;J;8{_`*-ISBxNF3RQ`{@;-5A)_pE?bliJ<{dS9)a$>x z@2`IuFczQW@N*SxCab1;0d}$>XHNOnx6D5K?jw^KQhyvU6s(albN>$d|DEaYnE!k5 zALfnMU&rT*4Unw^s-SRm2I~e=xIt_h$Jw2RQ&YZl~xJ zfeEKNO!hpU%VzGWs(SauD8fcin=CXeFuC*!Oh|T?!KT<@%jZpU<&{PtzH=B?F3AzD zd2z4G5WiKKv&N-A(u#LQ@mPfuV80=L%WPHu zXOC}9LVY2$QaD?7=^jo%5e;CP_cTZlrtsG2-B>g&*`YoUZDd+~C}nZwXpVNR_VO8o z{zK4M?!*GHdITBhP(1<<`4q60_>RLCm@8iTDSo8?jB;?PWYeH!WEqjO*E|d5({aWIKAdouc8gFtEerFiTVX09#0kv% z2QNcPVUu`(brRN#)EzBx^&2-TtkXE3(2@`JDk0VeLwe%1omgUNI zh{uA%Ma@x}A}_{AT9wVT1gDb`al+r?P{HwR#3*a-$B)_tcsAPx0|r|z7Ea4e)naSR zh9bNx6G^1Jj6?b$qkQTwqEtSfUGau;lqvh@rI7oJmM%?bY(6!fz-dj_;LUkA`BH;+ zNn3UeTHCcWVhqS!`D+@8afT!4O~&lF z4`i5OWh1pl`NX#>oOIGj{PBFVHN@C2VHI{soB>+?J%_)W2K4Pa1bZ5sh-c=nVIaQ~ z<>-LbcX$GQu+HR5Z{8cYq63Gwh));cvj`6CSx!D9aNmT23_#^3YI&elp9QBd%VA$ohkIlfop!r=Namo_gX*^XS758Ey{CNfNB)vA-Rp z*K)JsC?sUS&uxFlgt~vbh!)0F%OX~E{=a>}YBp2nOepX=v+UKHt?yf=A)i02C zlZSj3$LFQ^wyblJEm~d$YF=Z7YaGHg&6vyn^Z9DitB#xBeyHT7cuVpC`#Hxmwp}-G zxx*=q#v~5YmYFw3d*fq&D!OSnIRbZ`P12T8ZZ3SIEz5A%WDmv0@L@iN61j?x;}p&t zXFi9C_C$@j;)r#7!%Uf84$I<{6u}5bh{M7>?kN&*@7XLvXe$lWypIKFO;?!Y)^V=0 zh}VjfYaAZW2c*r?$MKrKdDH{u%0rLFrzhXClMk+KDqh+~&~Q|*#!45@6Rt3B&Xmnv zZ+`sh%jSmt7AVV_<7RY*GFxI+ogtp0iu#&EX0mut!E7RaL%pp;g)%g)v165}2@G;_ z6jlmt?g0*r`DD%@^}>7FTB;(B*SyA78U^~4BowbPfnmD2d~>jtcoeR&@Vb6k1Z%;r z=5!Ipp#5Oo?(&v*LtSq=@I7p1 z=ChfLX3n4gzS1`rC(`9-V6c3d>{a0ibl}dcsHO_8w(#{1OOU3Wc7=u`6n#r zD9Ck`l&is|xe}uXHiJF?!i&t_d+jBAW@uUI0}WUa#7|gOV@1Ye4cW{uhF4d=p}5T= zE*rhb)E~Ooq@uoJ58ESyZ6JlTO|fA#g|&nuEx(seBzv0r%n*>3CN$JnTT;v_cl}=4 z1#Q=MU=g;xgk>UL+K>W+Jnu#F>)?JOq`y#!3rtEEaxl$H7Cb@!@^%!#lwSp|A@+9C z7Ad5&8_L9fRSq;)Yh`NxYG!=$%o-#%gQ9H6QBhte0SIb)6FiX)sQwp_<70YL1XpcE zs*n|R_>L))#XqJE+TyOzW=@qW}NiI4OZw_;A zdGmXGigqHbDW|Cte34wj_cIu-wrf#+xdPfyj?e+;>45YwrjfC$5=WblvLluCiyD_E zG&YZ#Pbae3^RXfzDT8h85Nx=brk$>nb3lgQ%E>rF^UPUuXSHf&!^SKoY?dwtyYgek zjOpI7W0yhLS8hnEJUuv<$?lcU<|eJIUHScuX#-`?pFf{(P5!jYF1!3+rmpV0=Wlcu#_C!U@J7BL=I}8fRBhAgyH}L6O~7K4AiOa%8QE$|j4Zm6vi{ zkf{=}0c#X8nJb4@557}zYlX>(T72-qO!H4nWQ@UHY&c=XPLR+(wOwNx=bT2}lvg!u zm^lyfEBp16O+7siNVy_|6IYn9$<)`@KZNP+yQ{0KU!j=IF4W*b{mMfpq0qy`pEQu= z<`RDRNdo;F2IdKJ=n!T75YY3X0GrxE_6eZlPX48^C3%1^&iO0OdX#E)v9J4P;6lej zx&$NAYdi9I(jaJiVp`>fgJ$6+5`nxT#|c$>m8~>kEKDHua-0Ed-;#8B${-EP8pecU zwHEe*!DhXQtIR{|@rjtIz=d%WTOC~O3u##n4j$St)q2HL1NNh&db-qrwSsaw9@y8j2}%2$4h`}tpe*(pcs zg`%`P-k?C7sB%Q1eu0w?iAKDMjZ*((u6pHh09rBG4<5dCj|Zp5w`JAAwxnsL@wUW; zxO_g1?aSP1S)~;jDoE*+AMg;*wEBr8(jIc?P^Hl39?<%u;^xxQlwAF3yA~q>^Y(r0xW9{37OIcmn!*Xj{d3~L-v;-n3jA??h+zc=K z3-jkM=E){>gND+ChI(QX#(n$ZEYT>jPmu}Q$rUI+G8~@D8}=zUR`irPv*%1#^x9%< zyqVl#hXcyf=|vrtwtf5d`PHkVD3hw+Dxb}!()lvmV|1>OtEgh>L}O#8ii%F@F57l4 z`()w5{!^w*>v+p8xAcE!`g?u8^rfQ)jGHj2+aZS>+$EVvciO5`XR~z4lKWGiCePk` z#NI1a@5YYbefQlJ(DADQefqp;qU6u<*}@U}c3yP5`$BVRKd=sI+yftGC6?gXrGEA5}?Zjjvx&s633hu|@<&u$g3;9x)xPj^FjG{b=^yUWrwBOZzLA8@p08p%* z*x&=zSlp`0MPn#~s(YW=0sjeDyJE3a}^YZz2k3aF`tq=a=ALqO> z>IHndgELj+$HqC(>DRJwWn32=n|t=T=bG($Y-cAMoP97|R$y?Skx?T@nFs#9WZ^fO$g+Qje~INE*=QVn;3!+Xjh97Y`2Q+nmbMcBMR;SNf1acz}@h$e2o0 z5MrMcM8SfvZ7WRy8}LD<=*6nKY{M!OWiBx{9=ZWeX9(=kq{hwJL0E_vn?k}(kfuFq zM|cmQDa3hueZtZ!USrCTc0$1V1_<#>4V_VeT9L{;Q4EUHyoI*zTG{R&X7;L6Fu`?< zd`{OKm$olwiYE~paPj&B0>L@Tglryj9hRHFVQxI=BhTMlLPV&*fIvYiSK>gQk`lxq z8=Y&$g8Vg=#M$+RGc6Vr7b9%AXt_Nj5-QT$K|1uOT&`0{R!XK8Ob|9OZWaF9;Y~ji5|$1dy2yg3>VT-VH0}7T~K?NrJbY|KIRE@A(TP5 z(kOm&iMc`W6)*o0pQ0TJlla|wp##Fxd zM4aS{m@iFeYzDPnmQN1CcXK`b+jH8)1}irvZMp0RXx;hzhq+AjKXVq$ZgDb$`!+=7 z<+~-b`91LUKvk4T^}xWot1(MD;Fl4x4YhR*82#oGsa$?rB(Nbt28%wRf`?(SBk{#8 z_i3F3(cj{TQB=;iFx+9XUzDqZ{qmUSvUz~E{-)_ZB9Jpo95ty560eHNxY#? znI(%q{d*MU&KWqOdX-bzrqKuU=1uL@tJm=rWn~v)GU7V;FXg?-^7%}`tfD#qm;+}C z`TPgjM0DD$IkVRKCV$+dN&8?5;$Ex*sF2kMs5e#R2jUP)U0!~W7aKeWY#`44DZTI# zga6iMH|YU;IjLb$4u*`C2_Y>8OlFjo^HY$w>e`iG2t6F-t}#Gn`rhCD;f8-b^x%0s z%2qb$bjF4gC@O>#J7wi%IG*)FGjPyAOlI(SR%aXd(%7$L0gl-H%b)&aM!)z1op1Lr zQ2|c2lv(|QqEasX+_P6N^WD?WFb5uV5T5^dii`d3Tle9>XC>H2wDFOKZ0#?HRSkPt z#cuX-GMZ@jBw%HuTBI?_B`}@17)-MY=Z`DX^kW$K*-0`r0Ehzsel$dt(wn&l*v4hD z5B19W4(nIuse*PPc+jA4cskM(&cJrTw6+gzFY-_ZM98Oi2jwBZhdCksZJbk}@<^*n z9jZvL*j*qIy>WUk0tV2AZ1x&+^P%hbsR@N3P@nigjd3vI#22oRu2=+%Ihq%Hh0r1> zE2nv(Zu^V8)r1|ik$>tx7Krv~VA2&&Kw&zh(ezqlF42HcuQTui^-9*^Nu&BSP5Ij1 zBuxZmwlbWJ$?2;`U5Fs4%q1%%qA^nknX38XO zm?+@c&vV81`l#6NZZHGo~@#8?xi_#J z3}P$NQby!`eFSClI7ct6%H!xl8ucIhDAPEU0KYYNn6uBe54(VVkwa-hV>76Ie2}m| zc44!YNP||Rf($zY8Zk~Xxo*~ixs#M4j3-T+)E%=B-^6JU-@!m}=Ug(^0eb}C%su649TzB1#S3UpCQy0&hJ6l#(P@D#_!)NHj96s|%m{ZR<%N%gP0kWqB?Gck;ObVyR zy!FPL=C{B8m6<w#5Kn`TlNRMzb#eHSN0}2(KH2ofVkg3~nB-vD%5cI- zVyx0JVk?=c zz(v%ltJzeqLko@4i7yn*g77wt6$AppM6-y`?J11J<07_6Qz{ zNgD8Ll6t*vCrJbRR zxq2-UMFjsekTxLDd!C>JTnLx8MFQdxkzMsVFe5eDsso|YslK=z6-JqssUSl^#A#b5 zY*U7s5i8A=FXA(|=yo+%%n|#UV#4`W{1d>`7sLl-q$v23I7RZg*5&Q$jMq%N{Q6Dg zi<1AYOKC!5GpJ8&J+Xh$4~#Zg-yztBWisRKC8-tvXwKxZVy{Xk{!-b-D)aRdPd0n*y{Gs(gSJn7Jf%e@)-sKwaXNR+uwes7 z79?%FR837y;;5sJ>R4XBRgWmj4#f=LP)wxtZOCS?+q1g*-SyJk-Yhh=5#9iBLIY3t z&aV>tH0#$%*9Qdwkbn(_IF}YOX+*Zp2$spW{Fm`|bCBVHpcJ++53mwl{klFP1@LVF zIEM}r_N|yD#FY)mHzJS)X>Chhw&K7dZ`Ke~zP%t0@WSKrN+YtJO`cYe6ykJ)$AdHx zz_@Qlrr|MD(diOnYB+ja&!DU-+v(EsOBNR;Q(rJvoG$}S0DMyholH{a(QdsrH&++l zR#$GdpR~&7Y1We9{{?M3Uq}8{~N+2FV?UUGo*6Z3(_Ip!S|5Xh155uN? zPM_+aL|1n*kVjTfft`-j+e3Q)<`qcZhg0}IGuL>Fxn$H^=JpYbo7$=0`Geler!FU) z5&f%q6+qv3m=FbdB?{u@+ccQ2D_5B$?PqZEZN~8ur*M@Y&=WLN-s2oF(?gUfj0+JT4Ask-v?B-#*QWs zD}n{>XoLi5wTF48L$o)>8wDce(O3j+UYC08#a13&DjTe0(L^DzaJ0Jsu^GY<1n$zz z=0hOIZFhnCJ< z`k4YWo-k`xmuTgxyDG}d_o}U}Mfc(4hm*k{O!?79>~0=jI&e0PEA={r9T28WeSMvI z>X9dL!o>Y%+0v!5ks|jX5ZT~u#9jxx4jg1Iz$XNlNWok2ELVWkVwvantE#Hjx|%`l zZ>t!acs|{~PoGm0$<$vlVbED76X+iX`o@)?4;kW)d~STcvGLn8Km2g5lNsaR9^WsK zi|)q&eJ31s>isDb4uM}oKU>APIum?e%mEYN*4K_k4Cfg4cZQ-?#6H&p-3Tb@+q>TUPLGjtj1R6_pV%?rp&p6#w&` z?_yFN`t2|OFk7adbu+pvl1ak#Ox9&a6@i^}F=r4cS zv~Sl=J~`nrwe$gx+RbJ%pEfo&+_7Rs`j-bBuq*de*=XUl2@@(irYd&M=CcDaIXM(R zN_*o;qY?!uOXK8)igp!d#mW`s_!R7$>$P7;4OWy~frsW?_RF>q>Kw%4BV43jk>?Mh z_IDvBfuom*7lwd`Y1Un`tRou2nLu7BB&Ew1<^ip1n$5HZt#i#Ymd4=794*@bgS4fV zWLXm7cOn!bZAe7nBKHEul;{n|pdGShaE- zM_#AP1{+g}2jbX059=@&)%F%VkMNlfPF8pdL>_DLZx zUBm;W35`wM5Xz!xSNwcz;~T29-LNxT12OPik#yE${Cl`D@eFDu`#t`3K8XxrD$ zp&dXw4e=n-0c}AZhJxVXAU}m;fEIqd(A<0X-R6x~#|W(+l_>*cFk!%G`rrhK3og9S zY_sjQGRWirwV|Q@mg>QS|5K2=d8KB}oA+2{pUQJEZpIQZ!=pHgZzOPnxGtZc*jQJ0 z;@povUh8DWgbC9tliBP;>2#`!t7EJHSBK(nr11meB#Vy)>*|Vd^{eG|J`-M~HTFye ze4!pWIpqW@Ly#rTPiCk-{V|b>&;PZmx@zg#YKxN@So!cf)PF~;JSf;kM%u@VwlyR% zQDR0Mez-aJf(z_K117y_2Ulji_ul*FSHJj$dH0>S<X?^4R{$fYE-IguUKp{m_Q{!SFKn`#%AtIi=#dptRLj*UD_5>GJA``x06+jqL_t*KWX_Xn*r>=4q>|Q`;#E#`|jb3E;vsv&_d}B0*u&(H)&23gjWLlB<1=)Dk-x zgcadEQy`eM0UUiCr%gPIm2;<>I}iWZ5q^#czLG&4ML0dG&b|T-WP3ybro2)l;Dsb8 zUxBjiQnW$*8uML~_Tbuy*en-oV~{MapVkxs%waoFpL*Rz!UKT{C%*%098k47dHW%6 znafArfaQ9(+PyT$8TJbmuCc4LqJBgk;FW~guuX7fTa-B4T=BwV=4SJPpu-FOAiRv3 zaP^@u?-Mc!(9(%1T6cuw&!I`#G~^b^WVW}R<&2ld$B$Wt9E5kS6S&gc4>4(+xE zv^1fiu4#*ybs}wsiJ)$Le*!E_hwVb@(-|42!}hAO_1RCzm6)=%-2g@~O^`sGrd>=~ z9v|Wyqu5Ef3ewntng}Fqpr2XKD;ayC82&ZOZ%H=EHJAGXewV(5`#~q`N3~JQ9mZ0C z;xfqU43<9(@jP*GdZv*N^mm)vj@+c5^oN#i4rvZaN?{Xv0IM!`!3KudtP{bvaZLb* zwkreCyqPm=!Gb1B!FhTK?i;7bVA=H-85}c>KOMwUe0cNm187wRAu^eP@3Lmhc;8(6 z)2q#EqhGO~o!~Q)!ax&ZL0eW{fzM3NF+1(JBL=PbgcEQ1u`*$#$#uI;bZy3$+4E-q z1NZIQyl>P8&PDLUJlv4JjmeCeYb(avZ@=9yk;pxa4K0UbAT7QTzmrjK_U-|~de}-7 z|I0)ItH~MQ=`9WI6B`w-^{IKpg}Mfkc*`njCZ$~v=n&N8^`Rc+_|k^PMc5MKA=0lY zR904gm6I8e*;(i)jAigjk$_AM{Oo4v@Zs_~5?4`h1rLci@ik`j7*q4(tIT`vOt+I6 zl)*ppiwq}}@)0;m(4j*|bN2Zcm`g9a-1O_)m#3AWnn=$*EmL5R>aeNlb=z*;_1LNn zIGOSO`|p=enl$auNmHiXuuZq_k45#3<5TJ6NbLJ@Wip-KA3p4hdP>z{byPh*pW%uW z){Fen+tw#ZOaR?9Wy+L3QlNFc)K!d!pm(sOG2m2RYYde4UzjG|(O6rYkDVw*^FcP1 z?hYA0beK}KC3rxqU+Pga=r@{=w+TTI4+3cqF7|m8TEw_MsBncTkMvCe2C`HyWjGu= zwolWcaovQG7Jtg3G>ipK1k&8ksj>b6vwY<#Ydv8C9IX!CKHA{^$V{~!=kkOzgm5vF zd(%mjz(ch zN1pW!*@nCES<*}RfpB_QQ88OYAHZS{GeJ7E(c2U7%U(@MEL%<7X0Cj)n`Mq&g%5Js zUy5WnJwopE(jh`eAYuF?pGz7{pfn%mqMV>p9f%oJA7c^aWCMlqNkOY7^a1l+MC!QBp&*)@?@)T!P*!D+Vgu7VV6=jPN zaUMZ9oD|0CQ8;6j$)xftE%U^a4k7e`g=~J;pN$xc2hyi7XbQ?hGf^h7A4y*hEoV>+ zrIE@H$}c`}c@c+az+CQiQ~&W=Pg@M6e<6~k35`u#%@ID)7*;eWbOShn(Kgqi@#z95 zGj!dgw|duIcijmaiXP0tv*=W8(_J#)s~xziNfQvCXqDLpdT{9no|%7)2jCUg;GP^OPLX~= zSz3_+pS!`ZFe}VvoIEF5CN2OHddLyEz=d`Qht?zc@Fy#8qTEB()jNOaBsLrE(5KIE z91-&yPG*EQ*&DR76w1bSF{rBA{NSRC&DJ*ls&>$>mp=1m=44Sx^Rzk>rF7 zHZSd;%}19BZe1^2LLEi;v2+jS^pF2@!qjK9#HWFyVe-cd(?P6h!f7v;QJdt+=HlnD zl)4nQ7!QQ?$aI+3LMSY33({7Uz{Q@9a$3RxE_z(7WXc=n6(;mC+eE(8qq>xiG9-A;F2)2*JL;Ufwd$itv=s7LY+pm_^*bjqYa#H4Gr?to8|e1jR8 ztFfeXwI67xZjF^z<7Uk81tO2~Y0P_OB0UuC^7|@6V!rKGS&WrFOp{P##$tgJ=HT*D zM1>I<3;Ad!R#s%BE{PJEjy_~l8$x!`;dqpn%P;e0uaK;iZbJ{m>qP3s=@%R>j2Wa( zT_&t|#VK7pFSGd)v8D-M?d*B;o>^NN#*Le{W4kEv7(Sgi*lz#||L~tqD$uXu zW2p}(kuV1O6X~J}2Z0Gt;C50%94{;)*YSx6c^e}ryqIx<9l31-R1@%9QqfBc54NbS ztNW-dmAVzW)H0>=@y@+_Z;z!Mzr)N`FO@58f)o_bfU-+@kz^a$dDq>{C0I$(vu95k z%u74Li6hTE{j|CLXSbNomMz0#0Dke)f?6k+`?ORI9cHe(@g}p+K6}f)Euv3UMg|iM z)c00neeURC)zyDh-1@|$N006_dD^tEPMSLPFCCKUQK_ti2GJmfisuB4n+=q$TvG0 ze9|S<$E}I&+qtbxD)AFjGYX@~QrP@G;49qrr+7Wb3m|y#NX)hr;}?2`xmal!>mTV9 zu4%<7T=R<8P7~sZlMvHI7*`~5zl>b=J+%FAnOjF(WH`CEAwxE2H$75YwJ&L&W~sf@ zt7(lxTjI1Ku1(XZR|YME&ADrUV|_Tc3$ocVk)XA+3aGD8UXfm8#GW|N<<(Y=32x4w z7T8+^-!ft}9#HPWsqL0T<;P=U71pE>&S!DB*oOjhbz5Y9XnypCyVqm|(3V zM`H7uX$H@iAo_>T$&LQSVayY!v8I`4-_g9rA%C1lX*dzBbZnap@v=ytir+NYr$Si3 ztNbC_O5XI>6{}vsW1tOuqJnw%IiZQ8W0Guhm6dPB409Pmot4`e`u z=pd+Q+)6^yV{nU2CI0iD|Hx-1<=9kFgCD?>5)&9(b?#!mbLwfPQzz~p$caeV9JDUV z=k7+j$qEvcvpL2yKKyX}fPVe{7$u@hIq<|D4Uc>1#UD{W+(2oXa!v{LD~>)Tx8JI^-mV(8-NYm`H8qJ9?c2 z@j4uw$F%ae)9mV%f81@i-DV44GndNB%8G10|4V!?F+@+!v2968SKx5vPeswOnN0Q@Snbq1T~?mv zstcaX!j&cTKmDh=gUYbB!&c%Lw4Vtr`3M&jFvzDd`V3B^lHB2SK&Vf|#N-gKx`=05f^T##zk#AvwYQj#(Gi$MA115NV&;ez zwV5|;NjF2Jc6wTH%8LaIL{nuQ&{l6T=Z!kt{02ukGLSB$6`+GFJ`U4-7^@t0Q;3sv z_5(a9;`b!q$@^0E#%)%(loQP2axJU#ztuOyT>e~NbITEPo2V-RHoOPAL*%MN(>9~^ zr7<;2-(f=QjmaQQ6lrp~#n?RZ-zFCoCV`>C&zpp4@-T!jO>1l^3fGq4aXIK6XlKV` zpx>*>vx_&|CkpbJV!5QeibuKPWi95|bh&$vU2QHM`4`x?zZju*YOI!pc}cV1ArzHU z0JvzmnUv*szcs%()ZSl6QVQM!r3nr1indSS&F?X2!71Ni*>HolYkz297aBZ=+i?r= z=x{VvXY9s}7Yl=}I2H1)uM}ZKniZME9vL4k{K!20#DAnedA-W#G&f?fdi*!OZU*D1 zOzxY(z#}_xROZ;Ks=;H5|ZGp zUTjeOB;@tiUpIH(^-EK`3a88INhabbO0_{{Gv>s|(O>zBIsMGDP5Tb^6ccUZTv@{M zW50|$8yoAd!pR}){D}$cF_BK63|%KgIkRU9M+D{b4YK-zM;)_RQbnu>l!5xJS81#B zzMw2lZ6}l1>FUqQDeyO7lBT?(d`Oh2`w;|PO=+zTzc^u;xn$&1IGzs^8ZM}z8WSuw zD}mCHfB`XoG~+?}U3syw6^fhxUvtq@ubN*RJv&Zb%5Nqf;1@#p7R*mnOS@wu1l+Yj z+mHi$6|Qwn6ziW4OJUnkI>CcL=}9XLj1dS|oQ2qYn5JCvsa=xy082?3@@5ZD$qn^* zU~7E9M7dv^+YX(iqBc&9a?_Nx1^xunehpe?#+zM$O=6cgyil+1K3-JMEWDOQ@f)g0 zl&i8r-_c*8-+Wq$9bVvWlH~LFn4c(J^86K;p?(x2wswUPofAquzU>D##C3W*l@GDL zBx=M&a5BBOsc7JH#Pu?0)Gd#M4-N=@Ks8~WB2~V(g}_z>ep++s3;0Yn(c9$RY8ow* z%A^=6nwAwYak3d<03#juyGoUBXEL=1AXl2yrcX9@_yh{t%YfC^Q`k08J-)3lt@moC zS*gvn7knoRy7{JOy9><^H}I-9s$JJ`>BvENQPNA=7J0)mwIoa1ZqdCLjD$BG6160y zZQ=RV|2CQSm*O+YoeO1kg$?VJR;dqseG))8VyV+0&)>#O!#Gpl;r}dA=^FO{=hsSM z6L_F^@80b&2(nAh*~qoywqOgJcZkC3jIvxde})XQ952&0Zz(11m;}?zO^<^w4sgf4 z`IebCd$vqa*iHs@t}jsp-&F6o^UmhTBae1(tpNlcCwt&GH2)~%Y=EZ@XKWirGZrkE zj|Y!GVFk=hvu7`yy(ZNYCQRsp8RoxNl$9UAL9Yb$5o+4|9>}UnYv?WDk|A{aM0~Yr_5Rp!TlS=@Th;Y8DOf2NG*?D#Kb$8U)=Z6ic8gvPc z*KP4z^d0;48-{VM-Sa_ZYfL?XeojF2=+z4=GcGeb@3gaBnE?{6%y{>mcg#J%`IT9* z{IkMj2IVNfwo8d|nhAcWzIO7-<{YfdXy2i|tdt-rCk;56f%aO5)f87(R}a2uT_-ap zOqjaogh^9=5hc?Tl8Myq<*Bj*Ag`PodUDfJ>af!l_6oHUSYO21J{3AaDGIUBX_=ff zmR04_SNQbgyvdU%?@{1tZK~m)_>r{Bg4BN!Q-S-VG6u~vjt9jNF6e-UNq!feO!dcG z#~VtYp2VHEIpsN{fuNtC>3u+}Q`=!!-8%$_|Pr~DuX>)yX~e=$DdJdwur3Wn=N zWH{yIvK2VKukTBiYn6vW=lpXqt^D3_=1zx)GnV#b1`MoWZw@Bfro-%PC>v7oARX&X zx#I}$s`h=8AkETB)hgzxVV~N7cA6<}GxeJJ$&ZG%bkj+MBj+P;UrFOJ<4Js`OyY=x z0OB0)Wv{z@(k;pK-Q9i{s@<2Vuen^;&AOL+%NK@sICCaW2$jmmg;V~7J&3B98PA+x zSlxFKH^%@#zi!+H(z%FSmiU`bwY%a{cjKX~oJVB{bGYiDNzHBcNFPtSF!zBBr)X9< zSYMJ6;0g^UhMN&*`=s{swqd*QU}ojK&qPc-M|?3nJ8!uh+%M(hufQZ?+?XZ$~ zsJp)nc@rJ0@{5H5+AY7k-*YhT5=`FIeWJPEZeCO~(tjcAC-=|eP^ZV<8R6V;&btS{ zJXDWXLuqh@MngE3U8S{D+8L_?wvk5f(9CsnvQDnL!D_|0B*IL@6Z4%g5Zi%+BPI=& zK(B#q1mM2t0&H-`3xxLo-3M?&o&UJ<0!#1lcR1?~eo@6ctK=T={sY5^kzD#8O`$G4 zCC6siwW(D3@0!Z?XuC^LqO`Tq`p0cLbZp&OtN(s8;Fz>9}#@ zW=mWjr;SF87}i}Yejm^2R}q<;(UemkUp*SR>Z;*{lTQwKeI@k|uEgNyf6qDl`(f_m zk7Gimt!}T&$%JFFMf=w;a3qC4HFR zfZ~^cHrQa}?OR$)Clv~%9We>FBKt63X{oTS6iLPwNtqdE?P^hvcq37hu?B8!^3YSTk&>4V#4r!_@$z{ku z0D8mcPdof6hn#F^6fU{pK=aV>YByJ3ou7;Uk1n6`yA?vQeKov0we-V)Jz_#fPc^I% zW`{{T+oRXs)UxexSf)Oq=G3Xqpeh=>q1}OQ=tI5m2#=Fp6Lo=E$@?5ZUZyC2f-O=2 z_`6p7VxZesy5{3Y+B2buUE8bGYq2!?kKwHMEu~jWWWa)_5(b`bo9tyJk3n8GoYQ%p zSODP7xr~4Pm1+gNs{=by8?X#x8rm539G`3@5s59OVqq~lyE9pTk#3xnLoW5YEp9{7 zMT=PEOq{9)i+^AC z3ZK7uU0@$IiotAYMu4GL6QaO!Z*7$8Ck+W3Xsz!GC4!uz|H@p2KyzdgPHraa`QHfD zX{Hf~o^>R@4q`>;0eLDG?!wo&_{D^lWV8IpopH+z*5Dg(i4+CxozXcfl-sXzuEBi4 z2=w0{-34v=kAZNo*b|Chgu^X9@Z^u6c<-`aY}c}&=;+0A;b9NZa9w$EWe(LF`!=n#Bq^IW^oHboo+L&?dxUj=}|DRq3 zpgz)ZWd{bK&!ZDPEgSw#PngVjwJ*~-nSl)=&uuNYe4?w%f7f|CS-UAF40nVp=8Qe! z#Mt*1*VqVTmhlT7rEb9_Xodo{Pc4FUO76zJGGp>0IRPT9f;ga1 zZ21iKN7)mbke2ycjK5MsJJWT+Kd6eOfDPh3wrU5*fQ-r8H^-$o>5sG%f;h>q$p+N- z-gn=7*P1jbJSJg_ayn=4&T#zie~L}$b^>`^(41ediYYLrR!aSePc$HEp)Dzy@2ZoL zNE|FyE9jcVZ-(P#dvpM09|`&B}B;VRs@--{a{B7q<&){LRWj%~n{+Qr}k z8cs0=U;z{Wi4S;O0-;p>TX=cM&L}N>LW4YPHk~MgWlO|)zaWA-l}LmN>rS6=gk^Zr z`?6S-(}{(cT#j<%rC{%W1TkjS$}^#R{*M8F023GwVuEfe-qU~C#Vqr@R^m>-nGbF| zK*<-k3IM{GJU%MpBsh4vk!eq*e|}p{sujblx3p*=oZCkmndn;H2b`waPxmqL@MgS- zNji*?@>AafEa6yYC0CSH-5!!G$+e&7?l2ekvQr`T3fP4#MRU2zV)?LLbCmm1W$Ko2= zq?CM=oAdeKIhUCWNOUN$T;t?S%S!0WpG57noOH0flp^5$fc?p@8?~X=*)UFI#nd-x z6YwNqN^l26aKD~qQ|3eRGlL}qo9tFKqm!&eJg^FJVi60!(N^wb-i~f<^1<6Q^I7eW zy6#8#yIBYqhckERbFAWG|5J1RA{$K0I0BXBmOBw2mDoNGl&mA8W7h{)Fv$8fY4HEK z?rQaMH}f59ul;^J{oaZ1jdDrH*X&X2#A*>A$05{7@VDe}0I8+HCyNJ$at32R6Z1#tW)9BCxfD2;~`RIT{x3|2Bc zhza6TyE^CZy!qyvpEG7LCNtJucipkD>eKRp;;lcZPi1vZ4h&y$#c=e*6u z`oq-}zy0lR!(Z>X9g`7wV5t6QMl!=;wfL$BKnEXsXgC0$1Ll4ma#;j%Wd>sZuUe(& zqg!mT=^{;L{No@07(HXgeU}tVE&tcn*19huSLUh={+*F*Yd5)*$CYr}CVPP;G0ObM zr0bDD!j-WQ%aICg%{I?smf|Kl&{GsL^r_(p)B6cttklweHD-Js(2~YxMl%OSL>nEi zIutWkVs3{((LceQmv9dB3dP~L37iv-zh#@q`yYBfW^!9-tDTA2!uM*>qBtQweBWI6 zMU*+{XUquG6Dh)2MlgG;i_dT@OBQ)@di;>->&qUbRbp38tehs5ork#{0^ub20J}aG=^N{eK`7uovT$wq?ym4_mp}FEWCm>uweHwnEYi*_ zhODMocsvNplE*|j;fPj%Ou`qGZ)@ql22L@lXBsyW98W(e@H8!MCE*}SXl$CtZv2V19f=H z{3#R<2`AmLs$&N8r4#`^Zc6Qp_ z!idlFIzxmHAeVYIC0%RQmZ=@-n;&@$=rEIAd!q5U5We7tAqX8z^#}}3Xw+k|OiJsm zv(88H2j?X3y78vfq?$_(QO@Lu54>HdyvS zGiC6LANYa>ewSAs>*(q{si)NO-YvG+>|0xIx#e8q7d2s1hn8Zk_BF^}DcNdva$v6m z!uXofs;jLYK7Z;L!#3MypHqcP{2c4FY16}%zxcWOnwcB>6%CQwap2F%3)=meBaR4% ze&i$QdfY=J4(J#`ewG!nf3T~kXMgPX@%uOO1DlTypE`Z!SBDH;{??YZ@+Yw}qn)24 z<`;UTSH8pv2gZ;8VpL(2+=~H^lMr=(rI#cT-C%~K5COc}*k}mne;xEWD^q?6*Dzj9 zI^fYqA8l_C_(m1Z(${*QuI|vv{9!v?B0Cl*>KIKNwWu}$x z2ScIfw~=@uXBR0nDqg3~RI#F9UiNE(jO4??eq8N&5EBsmgcT7nC7GzEGI_GPWaRb8 z8s%D<6C1_S^5{!H2otW3ud^Ad-?BobGd|IV1@b5JOYLS(s!S`1CydE+D=LQg+g!p@ z<94#Q10tx2TF*E3pqSCCNAlhKAakI zuz6i}vBK1xN9d9{W6Hf&Jsp#hvo)#V-Q4|7b(#S?+!R-y*X1h#MyI0HdEd06Set2` zr?=d7IWCuza7~4aw&D}6+v21laO7cX@WFsCPdHQ(4a>$uUcPo%YS}1MU;8gs2h%c& zKxz-@^R{B4*K3zFB(mK5Z|VRM)$eCBG1=ih3XT)=hQnc&laY8P&tq+Xo?)b(R%Z4$ zTk7qZ+Kj##y?k_D=J*XVnEH&s;Dkn>;aPIX4K~=IZM{*WzEms}e}t|%v`@*_$vNP{ z28s6-d%8~py+$M5mD)r+@gAdBP1MJ6Vj>R?4Wb0VNvMcVMbP-5tB9|gJT_-`m^Squ z4ML*;3UXdPSgVDdciB~+X~p1B1Jp>s>#G*p+uE@lp!zO{y`A!@Q)he>D`8I8Q+?iK zEHv^_CK@qOGkR`&jfm zfE5T|Y3(V$XYA&ie|M`*w|X-1E=J*%QKR;Q{d>yxWBRyT!k8Cw&%-zlAG}rOvl5K`AKWs8SJN#wfMs#*yPc}UnMvd{dlwz)iASxo6 zs~z(Ao6myNF4AUr=OLaGQ=U{OA!%{MK4Aow@fyY#hPHj_rI)aQ++wC``AY1Tid7nM z)pUbV5@otG8zPu+J8~RANe1zZn_vW^piM$sHVxI{#bM%aR+Fs%l+)qZKj+R{zK$RE zM z>-SRUc&^Tb~Nh>y|@@fGWViWTTZ?ryt6#%nIxJ&Ba15X(8ZVDF35D{r_X)KOp??Tx+d&Rl9nw z#P=D#hQD#G8nCg0^6woFPu6KUNa6qpPn93S53NJ=B@WQsHEr6qSg~p;lTZ{cK0)6OSnp1-JzRhh&*^q6feIa}Li*6-7o0R^i$2v2^C;b9OxKN-i;)_+SonOMtutwZU~KKTsSAcXs_Gs2s6=X8e&OaqoZAspLhF4l~H0iEC`IwOhl3?N%j z_PkGJZvi>Hot1dL23Kx4z89LURVru!rk zocNnd_X}jidGc7;Pg(~L<_kt(a6)6jm@HAq`fIJVXR%bi2~Vo`i$ghx_s*(Lj`{+B zuQZu46OW7zdHC_iXVRd*;8l}yD18@u6AaT+Xa0TEjgRb20`d!mI&h(A@C7(?a&nJ@ zDRjx^_qSiKyz=g`c(r8gMjO55F9Xy%J3otwtu5q)8>RjN(~z^RS6FGKaP+Yg zu`**DZTjhbi{#wD1FuGfYp=OR`>VvhMhDz6x~RU5{!|Hj?Z1Ec(0~1x`f_ zK(N~6;jUWc!+6c)emAAJ9DAIM*l@#5FD{nL-+{hWI5DCGmD2AaXRdMvpjlQ;Z5z4c zS?x`Wo7xFHV$J#kX_$CTQWkX!7QvAoxWq@jsE`iRIBjBH+!I!NVcGPf=oFEY_W0ql zqQXWzYv#9;rMmmHKyEzUnA9k??iRXRE)Nrbw@%`JI~Gp7b_AZZUy4Ef=k%k#Ikwh@ za^2&V;$Uszb<&EaDe#i%M9dA(Yo=EFK{$Wsr*dqsQ<4yNFI3rCw-xaoq`KzgbBBd%CO76 zSm~LEix4xjo@k$!EoWUv6T;(?lXC!Asg1}%%dA}OS{}NvcLN{IT5^-!R?msfeM)T# zAZf(Mei&W~g;(agxHrt5Hq$K6efmaZrmo5Fj!oY5#TyJcD1|>yd7LmbDhLF%y~&qc#d-!{gwM_ zS=r|HF?RrSq}&J9GeGWB1{U8yI@xeZCgp7)`vJ{iB%&|6*P!4y(GFxMY52fOgA*D{ zuRY2eth4T^g;M!f_(QNBm)AEW`|+SbSB7A{R;$b`cXxjfgTs4>!T_nXT&4D13}mKB|mewJcGcRB>*t5Di zYCDV@v)Repjot1oPh?QlCZk5Jfv3=ivn<8bE&b79zGkxGN?4h3;z?nL9d^WT!1y&2 zI1o8BFt3GQ{`~Ur)ZBk*a>H>cXWzy@ZYH|(Zo7rUKKUu}`eX)UgAb7qe{Zc)IC!fq zwwNJ;g`8&0n6XJ~+j75ZU#{&it{maPcF>{B8ij*H`obhU`z!#_^yn^V_%B^UAZ5EN z1R&%;Pw^U!^~lxOzNE|PqpGM=?Jaw_A+IKG9_y@CzU8tPEC24!_}+Q(?BodB!uy>I z>U9}o-4~JNJiW{o8x1^Xae6DHn(39z?en(+G#L$&=%yc%&ZIwY6VL?@eL z<=-ec@A;!{G8i+g9_3m`)-OW?i=F2|cS6lpO*C0wQ>)|UW-wu;*#jJWirDF9p z*ni<5HUv z=Cq6nCN!$^v1|C7NG@BfnJyPaywiA|!bT&KAyWP_>6O>k3k zn@QGOZ-zNO&)rADJbAex2j1&W_eOcGa6PWAxXU|fo!?clo?r_pO9yb?Cpbx0Y8j3{ zT4#kLuUqMjOc=z!g$Q`t`2E=H-fj)`COvFp#}l>e??6okHC5dQfz7xa=H=W6hmj{Q z4>aGJTvgTm@Z5dyw)ML33voz3gODr52UDLB7@W}PGdyn&xz0N4tn|)NqkfE~yWhYM zo1q%ux+vaoIG|yUq|C}3C}D!&{#vDS&_CzS{U`C0@Q(5HnfGF4M)|OA`~ZwYEOz`j z(AHp^giH|}g`ym3BZ_C*!B4Gr;?tx5d%^kPk%u3`xFjwqZm>}-QU3btZxAOlXft(E z35%W}lLJY7v0=?ns9t^d-P7OWsDHQo-h1y|1A7wu7^^cj;>1x*ageJr+KKVzKgJ6i zIwB%5XG|1Bi%mnjfZ5wZeBeome5`mMpdgb$SOM)7KY1FuI_A&&aiv(;af{KLo-ls= zW)CG9OQ6tMD|{9CX489VO0bC__0 zFMFQ*=(7D{VD5AY2l<>VDwIDMUg|k6>0IW8j+dbFwR#)znrXUj+$Q;eiu;iA493Z? zYHj^+_+9-lNmJcyfonI}$Ub6r3TAcs)=c9ter7j>7s6QwXDe6;>LWGi03BuP$aoy) zpl1C}PgzU*cYJZ!rI^&X4)-!BTSz~3dufj+hc)+m_l0zM+4)HCyiSwovVJF=G39z) z&cgC1U!IDf{aq{fTyAsT%Ij_}jEl-~{@@VM&D*E#BTt%Z$vk$AU$GE390$A-J zQ&NLuVq;sVT^vd>mnHUk|0hY_|D$ZgKt>R|kd)a$3VvF*v%Bl|N>|sV3*lHa@J0L0 z3&-Awy?MH^%$Q5~eIr!%so?6RFZunOl?wC&bd#=aK*NHz8&5+l1cy(BFe+4@8wTVHOWxonEcLmMyt)jso7nB3(xH9jdmp)Wn>of zM)3>O6qhEb$I4@qqg|IK$`&COSK>FqaW`Lze!6omrlBm8GrQTh-7eSXIT@Y4%1MpF z;rN^L_wa)~f7&4P?NmADhC}g`=6!hL(u0+VcAGK>?N6*~`6FT7%8Zss=gZ6bv0lJi zrj;KAt`2HW)+F_AU;u9mu9#uJb2=}mPMmkjoTgbxKhh{y8yxh=UMw>h1v^i|BywC_>L_3(4R0P&tcioLkwc5`Lh2nVaz2Ns2 z&+QL}x~;)%fD24z3I;`|KJxhEchR27lOJq*$6B4=z*i8C=O9;uVqEpgaS`bEt2#Sz zV9<@gJi%`dA9P6<2;$c!3gPOjt_uHm`OmacBi;NYpiu_DXtKhJD}_}?jF3)fNd)@juftW)u%eZiYHnFd&T`L);1Xl-pfL|?{$uW^7&pQGOj zFWZ4Q-h}X9aR7z2VZ9ARYz~4pR@D;XH$WsX+8AF6(^hNHqag>Xse(-mmfYn9Dma1!?y3<7Lyrq@*omK8ur6hOkmtIb!wP; zH}(+39v?~y8&2jQ`^NekY!Hr|Fd?kC!U}w?B;r8aiqE!UWybxrYT-j$Zn^2bQNV&{ z?jtj8M(w+ph&zmvd6?|6=7AFSVYl5_{TfhCnEfW#Bn%xi+gOa(lfl@&>6(Z{HNuoY zV~S#%nGmvqCbgreyq?Je9al+J_}+e{=d`W1+G<{u`xeemzVf@U#_-ESYx^e=NC={h zOlGrUgR+?#@n)0!GM}7Hu`#?eiG(nU#YwcN^WExVaVUP|o`KQ$cH#INPr?tiCAxY@ zt}N}-F_YgLs_>!QwyjoW)cgrcrr6`?AoUT%z*AOKuvu5UjKJv~9)k!{03;iC&T3^o zp6;I(E;-;;7u#pfIhPhFp-ldu_I|4NF;3#Bi=Etc87jh^j(C)tpX!~x*FVF=8^45= z6qf-TZ)jvmI#>Xs`$wERE|>rSQMfaq%qmapL#39LQTbjt`S$$-KTEtU)1*n&F!3g= z(tvG>&q9>vzPP_0Pv%Ubft+e>SQu8`2#`AkUlu2RjVC-mx~?j>iDmcCbASX!JvN5f zZ+xWZN~}&lAddRdFLO1G4CLG{n(m*xwYdE{**AyH7^^8AIv~>X+>4VwpIQ7vc-`rQ?@V`+`zdE)M<>qT@AM=y8dvbs2jNcPPZ$wU; z=$vsd?=1rP{96ji4keT3S8myY%`9PIrwShU!dWs)m;89&SC{asn zIvHLx07lw4(B(=6wD$uTtWW6boWCn3GkzN-ChjF#*l@!QN8m@?=ky1HlI3rloLU*5 zWX?D!0@DD8UK~Dz%r7zUHZX;wocb22}qjplHPgfb5Bp@7h}hcy_KYI zIq`{HvGzas3d!SWOY=>}N4wPzp~Y;E`m7>fjW!vAy3mAYNidv@HDUOEH3z|^)&oMV z_=j-J4M&8-Zf#Hafm}Fd^7>)o&1YjN^<@0`-&S98@l`I2n_}lV9AUg-=c;?O*!Kq@AJ2#Iv>SdFapBsgEuC2Cd&`&XYWV4zhqYBF3@TDC5Iys`3Ms~ zKrD+UlQGbW-iEOe%@5k18Jhb|xcely`RK5WZLrvT1bX@9(mUZGbm0+LZ_PEw;O2fk zCJDx2a-vSiPN@qKxjHMVTwRMdlQCiNzqM**w@2p8IS>;W*Ug}(lGEOd) z+x~z(DfZC@pyCO z@F$`11UkMJ5chA$2JFN_t_Fopt~y|}5lBvkaGwr5tzUV_koHN%a?2m4&7650zDTix zvka8{?rGEZFBM8(#bC2Q`;%XE1vL#sqr>(13zvC-dWv5Rf$D4~www9+c8Xl2H@ zEyrQ--5vd)FDlV1mN^D1h5PUOXZYKle~GV}un$C({N}{N^23IO&rLWwyz5=>s;{a5 zFIQ#&|F3Fy?IYvIZ!tvzdpY3~x*usRly1g89siI0D%lEJ*=#YFUe`@IEUQn_6l+_W zM?dqF*G*PKyCpoJC`%IQJfX}RDX%rG&Jr}n62(jv`O2W_>g;@?($n?kHUf2>&H4BD znhjsS08eoPf>QHaWGt)hc@wj63YH=0oF6$YVMvxW&`<_fhZIU{W6*nH7~YA!HE!O$ zUpIS<*7kn>)a}E^5jjcYWJ@1~Vz?OB)Z=){Q0J9O6W*IV!7{wpmD@dp=!)+38)DVQ zPw}eQ`h8gO?}M6f{r|&6{uMux-j|DyQI1-j(V{I%v;NEtk0g#(L_uy09 z^Qu25bzI76002M$Nkl8 zO(}JaLy-Ep4J30NwABY(q9GD{Wncvc2aL04&ko=I*0;j-zric^z~Hl-Mvq*iUI)_a zC}OKduCl;9O?>3S!I%bl(nU!~r1wJw0~(rx*)D9@h_9+_h~q4Lk>d8LQ>PyRe^)1E zf2VuynYndqx%DD^<)s~84{0zb4U_?;?~JkBQjAE-nmOuKkpU(e8~BPB1b}%AbJ^N& z0*LwZJAU0+3A>HmV)QBR9y8_%id@?19q)JtmQ)r#;d(exP{FGpt76}j<4!m!jNfW2 zJh1AP-HL(wGE4EF`+xI|H-y(;!=8Fv^^=8!D|I-4KjNqfVY}_Omn`W54L1?R#L2Tg zU6oIc8#nq6w;|7Ozy1DUSmE;xtorydCQepQ*93@YD|N}PoQY+|-w(ewSVxKz5-3<* z_L{6T2?3nsnlI8tX3z;P-grH5Pa68d{xM_bOnkO>w&{rYc+HSCDwO_e?FZw>kAH|F zmuNbBk6+-2*cJNWLini^s~W@Mc-4eHnX5EaFC>vcgWL(Dgg2p-vi4D65*mSad&} ztU3SoK2O1?UG_DP8uesRh|L0%BN*0g7LjD;rFXV;$?I$)E?zu zJteo5B8iul88wsD&kp{_ez0JEvih*&K zoo=j|#A<%M6YM04&BFc$8UJ9`X9NbukIX(z9Jojf2uBo3Ef?dd?4}y9uw(X;YykUM zrC9yM+K#5X!kAcxIvH9m{Zk))C7@2$!#w8`f^Pw~9wjYB?Sf#W0FSqq$-}qe&aKb|_+m)|ow6(T#^}{s0 zr1ODmuDv{u? z^O8Oaiy~BJ5wf^4g{zld#YD~>fB8$8boy!GZ-4!3SYd?~6BFe{dt_|fE2O*g&hGBc z^GxCr&d@2V#V?{EAB>Y45KkY}E_9wpZz^G*;6_6d=Mlp2qH$W}qDv=}Z!-7<4`D*b z_yB(JUKd_?&kbS14F`t9uN^_eGEF;8D&r~Qrq~DKEZkgg!%~{_LaDH&CSNp>Nyp4? z`Do>2Bxb(l)`S#gkLG7=N(F4W~ZjrSMg^F-S-J`R#fZCiv=&)1ge zBv`cvpUJg}0Gj7+$R7g;Mq90}Nifz0AkfOFb7HR;HV%a$TSdfDJ|BMtH?-X!H(J=h zSkorjk=tfAOX0&di-8$xXQs$r8CLg)EbgQGBfA}*(>u&_;+n2qK$6?dF(YnqQ?26? zOxQlG2^#X6ISo1-mVoR(ZWnVB_(35|q(Rd4imzQ&3s;9Dt{oGB|7Pc7CVvWlqkfKi z+G=q!!+iI?>ap;47To+->{v!2mEC`bq0W_?JzWoCvJ9VD?;}YD@E&v4T`$>^ZrABL zM3~W<58h7X?e8Stbb=*juWZUJd^@i}e)m3>H|z5`oxzht`EpUNy`aiA*% zB|ZWM(;Gzqj}`~hn~A_?BS$Vjzg)f?_o*Fy@J2Zr6xqFobuK}#hU(3&g>c0Ek3Kg0 zQ38>$uLM?hw0sSn_CRc^SoT4`2Gh=;=it%6Q~e%@_&>scBOg~~aMA)RAi^&%zdYPC z&FDlC<3U-J zAs_MN3Ip2p0sA60%szhBz4zUW)hWLn(%SmljW*ioIb&O@*^C)8R;$#)6<9s6DVG0B zm;7c-a^E~gprCJg(g2uH(Zgp)f``8+>v$3XO9H|X3$Dt*M8L!af>Zp zboOPM7Yf`vqfFb_Hmj|%MmX{0FNDoD+f=WexXrXFx~a4J0Za7duXxqu*=L^7;9j=V zRXi1_U~q8I!3T$faj@U0?~$cKmUXzt=EOZ8QvbN6^OOt@(Rc2WN| zZU#g321<01Zo;js;&F3dBL&VGjbL)39-n43X)Ig~IpuKmL!sD?AJn@e-yIVP|HS0N z9}w^x!*X4>hBFs&^Gn&Wn5T(1Y=Ixzd*Q~oBjSMN#4W?r4>;LEAJpEtGXQu$ah%gB zR?SXAhR4uz3Qjz(gLb>@OdrMZt0q0&e?q4@83Xt?`OJwrDW7Usj_RU=tRN-(Vl~kU zhm*TTIv#zcdEIA(p~da-bap2VXhaJh%1DX!7%b&LN>3)=^*SHxnhYp^Dm=H%A5r_I zqn2vk()uL6q5K^B$_U)NV5b>IQ`0q**-c~IcF_`Gcx615@dvqjI0`oryHr#6@Q-0) zY%Rqu+2aPf-JS#PZS1}giEKwW@XtF(zrTjNuv4K`H4Cd_09p~~b z7rm7iCp-Iqr^AHF-#`d|B&B&S~d@Dh2LV*_=Irw zo{RB?rd-D|E_3x%amZ=-QF0Xg!&4Ug)}?!jixuRv!;q)=c^qhS3Z(HfR)jO5kYZK% z)}pPz0}uHrwl{qVM)^qWYoupNwzJ|umIq3rfsBvahFmrS>>w5tGXf0h^bNEbexSJ5 zU@sqJ`lliZk5Dnsg4)POK{l zb6$_%L)R3m)qC-Y&}T%ygio04SssJwi`rUSM{6=e@ikjnmdUU@2DaX=3D;y0=+z`( zRBM3F{g$ls!v;Ug@B@*rWpwp)-H7K{U)XYs(bJlwEwd_Lm4fBFux+?U#yab+hflMf zm?ksamu7?1mW&0worejp+y8u<`kv@4Mr_~l_&n=JKK5~e{Z%YYxD|?6tkd)5abreb zEM#`VM8-02Mow9#bh1U_2_c_Jabg>`l5Cw_Y9!9SUVb(}SlYGc!5XZI$ zEUxijCDv&-C!t<__0@3y{r87ke}7Au@{hlV7jTWWwY7)OeD26_!292?eKgd!$>;2_ zh5GpFO~<^BUyK>E+3iFx)pXt-zY9m-@HHs?rf;cHj{yu*=QayuCr&YB$?jh5GoKo8 z9z$*2kqc2EK}vn-?RcX?sfbEwqwVQ%^o>(6h`bd~#_kH`>XX>;=jCwG zAul)RSd_|9S1ccjD~t@~!aFb^-2rO%#uU`18lZAu#{C)i^g2)OyPVIRqs{IM7!rzb z3gF3sgjo^?vVN(I=}(}Vk5@%X?&)LTksk22ci!mPk+q5)?9Im~ls z>nrCMSSH+fBHp9FN%3Xd)6YC+9wW)kb?1V~!@AkxD6W(!7Fuz~{03eR`g`Cc-O^6o zm6u`vWAcZuo~YeSX)3#&GP-V2!aIm~&~o)p5tDd)H~+kS{_NN#o_`##=M=g>UBB_U zeU^JwiW@2xf3ql|Sb+U_9}s`ArY^RO4Vn`QQ6 z{pjnr!bHaR@HcYD_<9(xd9$a%H}g+8D<`v27d!!CLHtI`aK*nr{|H06u56-Quu3+U z>3L3NViOH<($~~x&g*$Dqrb{-3+<)3UZ*{&Y=!2!+w5@Xf5j04FsH4u(~U-5#jNgT zCt3%1?zEmed@%1V0)rD8y+!2>U>mHn-ofao6XL+iuPkSZbq(li)jJEForgW})Km4z z417_eR4jiDgSIwb9iUE5HYUH=V-4p_9*VJ+kN_0JYx7V`ON3B@ArL$1|{kEe=KMQ{R#d&K96G=lc znQ=*LTkHP#OlY)Ewy+onp2%XX6ds*KmtrZOEuM6d16CsSKl)ymrHF_IIs;Z4JYDJT z{>n?wKmXI6citI}_hTxR4#j>dD{%n6`WkD76HY!QY`pQtuo15qWwD@z=4}j&{KvA6 zmU6iF-h0F2kIg~j)!$s>ii&q)^UtFv9vARM624j@c^II`S^P%+%DAzk&usSm?z^YI zw^}HEyRD^VYuePq!2rY0_*x&$W6gFVE)r$Z0BW$8D5;KZBudo{fikN}2Wl+SrxJXu zVQ}@#v(JRT+;K;^{ZD@m4?J)`RwH+5mBz{|j|fK{du-TY#~oGYYN(VXG+L)uz`8o0 zm|yGuCVa?<67`ZVjA;LUc(!9qXlebg`Z8LNftjHAnd;njx6ph@#(CXyAy6SNVO-ws zGIh0D-SH&CvMhUwJOuZybur7gE_gnG!5=noDb5b9!=J(D0G|w%+FY#WcpAh{V(^1S zZnX|f3Sj4cC@2vFlQ7u5r$N->R+3BxozC%KlG1un z?LfVbBb}Hdjn1eq%ANMSJ@3ZXY`zSZ3ngL!F#vd9$fQSF;s8uMD5wme_aR>Y<(7A1 zQ2iaO==m_7Y%a!Y54plcEdOAySHrP4K7_%?mYVpYeKa!fySXTbCm(=JWii7S_)u!a zL|f&I@bRnn4L>>P`CP;jD-Y{BArxCTPlHw6Vw!AEeX|$1x0Cxszj;ru^gMxUYWkb9 zldE& z5?-K8CRy^NI!a-Lsr5!#kTMHA?MR z?C{Ody3RJ?=xa_7=e~bN?oPj#kGggFP?&!#CSQ)jwLUVwqD4pHg!_?JeZ(M_e2z3tWbcb>%_`VublL`90&Gi4twYelT5>j zam~y0SAIDW>M9zaszwtr1N4l0zaDY9d9*+G&CBi!bEjpFim}A_j~IQB{ms^(*Ge#)ayJ(V_jn>KCMuGmN7tKeQLS24yVf>Gvw|09hu_YJ9HsV@hkcp5$$lN+Nu zJ3BvtQO_&WXUx27`n~u52@@=TZ|N#NGHc6Oj~-IMrz#gC-F^3iBWs0@i?C7Z`#G6G zJ;^88hm-r^a`i{dDsHP2nL8Q?laIdRpAU>98TZP-s$=}a*ExQLr_@-PFy@~wzQ6J< zw%B6myjNb?n=u$ZeE8fGPCj|%O*Y=Ry%Pg7udR4UF;Rh6m^v>SJ9c!#R~+!=8#MQjBQY;G342nk#IKkz zUbMpd67vQdSoc5HuE1|ljoziv>DYc7+<>ET*R%`mSsuuNXhc@%U9_+<=*#nO5R z)_TY>5CmS6T1Lk=_d>B7pQmL=`I=NwlVn9a$VcbVvT&^gvB?W5U&u)!U4Ld{?z7u1 z5xvk7u6qK^AuV}5C2}u#?gYr`V-H^4IB%byX3#fTgnZf{HNEJPRD(D81%&gs`3qz3 z&9bLny*R8sY!?jL57Dx7(&X~EB5xRkwEJ_sv8J_D+ywC{`=#)-xW zlV@oqk+-Gn0bVxJKBHyk@nTtc7LY`f5%Tq>Qp>x;@Y)6Vl<~*IWlMM>oBPs~iW9X8 z%Hy5eklR)_P^HvX&eveS9Gr!Tq$eWrVw_!G7KX&Fm|F0hF6qq*PRHDD5lP50D)7^% zM_u=2{9*eg{z%}rvN@zan%Urf&@C?$E%Gb~juV~n6Wz>bC_}^=={Oj)2Lp*@Q48np z_eZQ0Iv*=ePS7h=?hE;8S8kL0m%~U;8<;$gwK_lRyl0cY+DQq8(zW!UGy?jyl z&K|EjdB5ZbUr`FH4&OHvJHLci54V=jyuYNB`Pbk#2vpCUZmxT~iUg+|&#xWzbpJA( zv)7H`+@x#~3J@Z>rq|Vb&PJe~yj@gH1gL>vQ6{I!x6Bgk^LSC`!pgZlq)|+B;J-oH zee>Ke95s=*6XQW&yx!zj4(6+ngQ?F53{GhD8JCsgdWY}axtf3FtQ*Qa2j=1;f&A#gH}ezufbFlNAt4Gf;y zFE<@MI!rwAq_FO~qvU6bk*SfH&_f&estQ(O-L}fgD_!8WEwlWR1LoofUkA*YJdd?{y&0}pI+5|^FqfN1On$0cL3Akd2_N~HH}mpcEldQn zKlt^hAJ4icDdHv!S>knl=4%cYOBMri6Q2^wPUB#{3gL-%3U0^-UJxZ+#^805qd#G9 zkza+@*S_lF-cl~vZe*s zK7eSr&$#b2D)*(gdj5BS_`JV{-84V^MwEY6eBNhuzf zVhr&NUSXLrZAN(S&O5~k4eB7?Qa)M1GE*8%#tO!XV6ylm8(DCBNoO*}i?UB1FxJ(c zs`h!He5~A92Ls@BK&Mz@6$}H>1G=YMTAzOcW1gq*C5dQ^!m-C47uLY1Z8^CS1xcxu<2`^jFiw~RoL8yTzOwe(YtIM4vQHcYPPpOI z_>sj=(ybi#vS0vk*!7xz6wx}u9Ik651u?>NSYCEs=AK-R*GbRR4EH*7r-_uY?(n3~ zep%X*}lDTXGT#jIwj3ifFcB0>)aeK&<%gRZ;+)V3o9ZouJ0@`_J=q?@`&O2lY z^@*&FsKfQSzl3>Om=A8N@VI#{YC3P9IhfQq6&Em8nsDC>i)*tDxh>5$xbEI`a>A&Gx_i}&#+ ze<_^1_aAz5cadO6UB5d1zMYJ~91B~x+i;^z9(xLN+jdS?DER{Xdl3Abn&9E?}yccFeKZ$GaeQ3K<+{+1nvl&mt6x41j>t3c1FEeLq#`ji_ zly&*l8h+SRz7Q_n|4~Q1an5%3w$7;C9)jHV46R~L<8})%05+O<0*0(=e)VR*$CLK< z<_GZ&e7(d-z7DVx&Gbvm?a%#_xr^Wnd9&xq1I)_-W6t1&#v(Sws8OTVz_9MrhW?j# zRJ(z2kY&R^y#HNK7>KWm3$+|yvq0xmN5`;7o!jVASx8;jQi0A)x-{q}IY{{AnEPhT z!9ExKgr-tmbgcW;WFnm=5u4q*i4f=)9r&n^Pug#|{<^U3d$z^kwFOZ8Fmu0=M}ML; z8+K9%4kscGb@MGv1Q1O!CX_W%;53d9jqygx(1Y3a9{zxH`CvqBTCkF1EqqFIEy_=c zal>pnUt#nW1F|=lYvgJNGCDhHjE*9`ot%y+(W0RCHX4@sNl)yvaQXasuT9)`+ijQ5 zd(+haCer%rufJ-or)PNQ{CWGo*4g>=^ck~u;tC4)+x_!)@;v$*gM$rE^oddq@VP$( zSH0}E=bqu<4;_LyS^og3R;cuJO=&F`KfB51<6fe<*pzi;4Di2pcgQEeDx?f+;Pj__P8ZFs!9Pysw zh17%>gHtr-F306NKdE}NBj?U}9p232G{om+rxPE2Hhcp-gXO&9u@mW2Xi+X=FjDE6 z8VWrh2^a1EWKR0#%lv_Eli5iZrBSy5JeLwVlf{of(8*Th4Kl>=#;5c4xdH=~Z82y# zL3^aQK9`v!m~O`>xD^ObG0P0;!9AkXvIhq7r-1VGX0|0(KX13^@!H804EFY|4_q@l z)DfU9+3EIXG&xR&(Pt#yqxi)izJ5}zUWa&Hk4eUJ@f7bKyw>r?BMvT^AF=YNP^uh? zLDDDDm)6&cn1&TfS({5|R`<5>Tt?+5vy&iBy5aNEp;Ub&r&zQy2eB3pWxd441&NM& zji$G@ciR5UFM8i&;mGSw3&rY>VFo7uVQ+77biW!CYB`rH=LmGMsC+j`;v_yVVQ~KVr$~dan2_m&~b$lQ>nZi__xFI zjfXG^dQ0dDSA~|ISz!eBO`5dxBD^aY#VqvvxtmtS#?qTY$9{+zzp6D__r`$LBDBGM zpnw!>E9XMpHIGG(Yc4xYgU=w+hR>bnhE?}{X1U;Mg(@AA_u%>7gw(MQII z^jVxpPIxa5{D>M%jS(1}&}fXuLTja3?HD|{SuZ_FwtgyxhRz8HaQMF^O6l`e%P+tD zlk?`sb@#`I|z^xYcv-e+$tpT{2urd$@v$p`U6zl4zv1;SD;?ub`068b<|?(#%1 zlXzKWjN)XG28`yS54iay4Q|S4(iAqUL^%-=;f??-$*fOA2_}-r2@~RgTIR5g%sew8 z(gVpAEnFGj)z$s=O84mh-geu8|up(P4V=; zrdVff!B3aI_WEmK){N?66k}U$wZuQtCc*^G(LhrVCSN z&fKF?tDVu(+B&8iU!16NQULuTsx||f>~Pl&Z2dx3)!P_E1`$lO>~Bo0pvbo2L=2&` z=giSW;NSjwXPEQIBN$&`K@aen*daM>V!tz`oVeL__dUXdV~@dWHSL;Iqfqa&PVcc| zU**IIUbA@syJvjskV6)4zZaOW0#YAG1y(*9ia9&k27-^J@FUd1mlqsKB zHyGt-=*Vw$`{hO zvJnN9DFe==SY$Fe5vg_opSOL6e#2t5!cUOD8-JL#!%`-Y=eCd=b%Aio+uvdIfkx5} zPfkai2JWR3!so90OSo{~o1A2c=e5Fhn$R$F+>IDNvrX~K>~tSQ1dHSgfTUwNm!+ln zr6IWCd=MStgZQlQKd?^&R`3<3U=<2Bhi!Q|y!gsX;T&lYxeW@I;XU5sA;Q|9=$;;&YrhTW?8DjS#Y=qFzy&_;H=TDI z)V@^UFpAD&N*oex@?;>d_FG>0*Dph1t$ncv#fS7dh5Bg3baQ&%Cb7Z_<7 zBPNeq9)pO9I4{4Ie6@Ms3QvbkLQ6X~jK=Rd>SWMeC#$s6b8ojCFI;33e`;g00-4t- zjtPJ7rKDKe0Qe0;OZ5o!|9^$&I;Z1r6Mj%&aphYx;w8Ag?W?0q{ZCKo+8x;Oo#U~s$oB3o^(4caska2(U4z+L=KEZUucuZ(4BFA zJomnn%tygolb=qvuyz~>-mK9i=)Lg6;_Swx?G8+?Jb;dyt=FEtFbL!s?BQ&^J_* zV(R~?xlKKlBC^P6M`||!yiP)ozT=~9#MJqt`DhuwR)WbtescA}2Oq#h#vj97fBS2A z?%B9kFE;?CPbsl$c*lnjUS~V*v`aYRs3WyU2sZ|mzIaMDil3(2^?)4i*1kG+?3gE# z?EWsCxA!Gs!gYA3xaBPT2*f97IQmeekjr@UtrtVhuXt@3Ug2)y%fwkjMjZ}U<31-%1JVuNraI`7dB;QDd&+;35x`dOZGXR%WT#OJlT~{ zU|GD(aiITUG3%(dq_;&crZ>ENe4`^5cN$w?* zDz)1}q4POhA0z6kG$2`Kz!&DS%j0TVlV287##VGXW&DIAHa=-oEN_iBb+*Q2S2u1{ zFKVV@TBUhOhl{_Z+7Td*5?!&_A@5WQPkk8SQtHTx#f-( z4yWd_{M!R_Tx$k_aWgG12uxhz~W`` zoHP4TOb9#^hAclc9C74PVS^1ez$+N>mlpd5Ry_1z4~iqU++vGAVHL;@=(RVrwzPZ^ z@f+%|{wS_>g$ieiHQ^b7+E(Voc2Qrj_Ed8u+B%+n7Msb2=bw8%T=lD8h5!D_SHfwh zej(g=-L>IGY;ucLB09uRHa{rK$a{#$&~jilk*dgL^fBSis?R`PpnAnM{}X zNuTkhvI_xi8Bgnay6+C1wGW2#54w+ROEl@SGkwZvGZQMZCl>3DdEIH4Bav79JYm4` zX3}~4-3hj@;9@}Lc2JPp;yGbRDPF1wRPPJ1+R&byOf2E^q^&LA0CTRuiQjs@#*hbK z!{0POYES`nZf}DY1kb1B1NMYM96v zqStu%q?v;?rXjr~71zWhV(8?o1gz#lwxwa3arnf#WB& z*|+0L3U)qBR)n?C|2KzSyW!XslP-tiN9f@w<5jCNHufxUkLzN6(2hjjrU{vDY_v~V zRF`7yHW-Zh+5ZSuZg}@gRoLfs`ss8DMp+buB$&|?#>tFo*9va2XwoR&5~d*9zm6+vV}=%}}EiLvtDQTA}gAZ|n7|yRKY5(`Ft7 z!XF(5Bgp#`%ieH;InM6?!VjK$i$Hy3+8cHd#=+W1{DI#ug@PT7KiJeM0cGw#;Mhkk zap;ZZ`KPZpYSaXRFyP^zhpC#7pa^#6T!x71Aa-sIm?E#rB@EKIAH-#sToQi%)1PRi zhU8>=HL#*R4s&~{4rL7vsf%#sIFZ)q6P^IUA{_^5x8chVS6p!g{=Q)8KAwClF~gy~ zLo6;XBk40zO)!v&B60X2Fvfw{_>Uyf50+wCGR0 zkbB68dHlI2$%79(s10Hd{J_ECJ=<@WUPJPj;kA+zT8hQr-7{mx7qRN@hSs*$Z9DK~ zpXS%K6lX>$>+7<`+L<~@lc#zQp}B@LdeX69a*vgJ@4GKta`DCC^T!__F23M`Fk>oK zvqGL$WN<=GvdLi5nNyy+L;TXtW?PI2$ATZ9w$*DUvd49b)cO`!6(7L3+5@lfybcwo z@4ffl_@y=g(*^roh#!AP!Qs~tFf%XN!O&7m zeb_)-h33g^^qdB*^hJ#GVG&G07vxI*EuaOCxP zWn(EMzRO>!U7{}`XqMh>avP~Lx5@3b-0u%E&3W=X=QUaEkNk1YC)fUjnJZE>f$H~X zm*G6jU3Xq~x*SKmC&C@)wph-4L3igfxHtUBsoz}g@|n91(<>BVJe=qGn}xTk98)eN3k~+(Y(deMSI?jPB#IA@Yghf z=i=lKZR$-iVNHime8>;l4ZK+0FXk?f2%`~<;z*w#ycRGy;Rh!&HSveZKZo)9;I$%K zAw$V^c-?c?kGif;=u%ENQ^uF%(N5Aio;j2A5O0Yf$*bZseBCF6|J~> zfJ$&=dR2Eit|VSS(_*yruAfUV88=XEbL&;1=}{<%GFFKkWyigpv8;YgnFtau`= zAB5py_F(EW0{&~ZPon>1WUae<2MnAxiUSsQt}NlA)S!x;QAdUY2*cslQlWU(`lCjD zd&Gzl!&X{lmA_%YRZRo2T%7lB$Z@=MqRvSWE}NhGuesrjZ+;W6fBX{9(CT#R^twUN zjLa67PgtJ(8u6UyoP@HPc|gLa-oN_4UxXk1@M8S-igszhX}ocgz?H%(%2Ac_G93g1 z7i~4e4DSQj`b0wXDap$1q;Sc1>WGXXs4HyHBQs10Gx-{Ih)$-u9ONnzXfObzja3}n zQvw6%`Pe<<%=Ok=&%VcNJ`Lck)>GXJn|3Z2eUAN@q4Y?~bOHp7zO&2;wdvEQgr zJ$&%sL$qo^GJr(?sC9LBf4kb<`Dc7~=C?yy+rJLU%kwKHY**4nN%e^$LQ-F_vUHnD zaYVzct-T_uXr{FxGSs(BE*WLF*OfgVLzun=*y(h7Plt@CmTH8qA`M;M{&nZw@^4U95WeDX_rEp z*K!m7z}==cls*_B8!VSf0+3{{kafSDHsOtqbtbVIPpT6Rm~aGIa@sskG$_bE&^j-1 z$tKE3#Icy;gfcucF53^4ABPJLc#}_;sgH@m>@e}E?r7yeIw|X(k}t-LaqECdd|e|{ zzKB`t7c?16Thsk1bH+?hb|*SO9Or%#;4m_%YygLQo&+wT0zXSzs~(M`JNg5;?vGSJ zF?GBC<}zvYY6@u#Nq(0hzMRSFkh@UP8eB3AB{m6Yw82>u-sNYsq+t>WrzF>Dm=m6e zVx6`y89L@7GMFPGnSh)Kr2Ov6m%@enU*?#%l)JqW0@u<@J zCB@9iS+h|#LoV%e8}qVM8m*U=8@=;8Y#`?Hi$37+K2B!^ryqu+?T&Z9NaJ{i4Swc? zk?J!IPH6NQ9`>_B_9V!9B0HD{Q5epo&IUn*`3(`(*dJ>x*eLR(<=WcrIPvJCcYE@w zr(eetYprtNLI_8025ZhVDGA5{$IH0!VAN^dGqj_&$eNa zdRj)pc%;Fe!E%|3o2e68Hbj$HSAtBpNwTN|JQ-V^jwQD@LP2Mg&LDnND3|}_FM)|6 z$?$gdkhmyOItxUx{qTy#jLkRS@9cJ>Tu<~32mNn|AALo?eCC;F z!-^}e7(R3O;bF*fSPji3nMj;8=;`U^lZlr~E$zRp#MuE2QzK?jCI4m~uigGmYY*NCTpg(vTuRXp`6V4zi_|HLwEIK2+|XJ zqVA4an?>aSvYw}gYA<*NC4-Yb9R_EeNpQllvJj5U^Q(W5({=U^;1so7pd%l931BRjyPE|TwS5|i%ZSy31P-(!S;`Z?=ZK-u#tfcrx z`2XyE34k3%wRUy)y>}-2Le|LwK|r>I-CuD5;VCEt6d$~&B0hNv=u@6-0%04KKnR=S z0t8&1`dktPSybE*cb~Eb!X}HduL)$Gxl8x|eW&X5t$SxCgfN-hNvdXUSJkO=PMveA zy1MIhb#>=&+yzL9`yu}J0jsbC?NZ2(ikbuE08D;7FgTb?3dn~w=;LUF-jX)ZD-S_a zT!*as+X_I|40rf`xkC|ot5B3$ zr1*IiOgMarm9GVpyio`bH^)~L8Q<{nzx4Cw%7b6~3SE&=4psz}T|}ZBu3m{XqcE3e zlp`|T0^teBKwWe!q)54LfQ!sd&K$0J;yU~WJXhYbk*Al+oySbLpF~>Vz-kcRUM;I< z>j>8WHv_Gs+iR9&`t<2z(9QOim8Zguy~|GaWs-y(CqnsTTTeubme(&6twM3;9k<^x z^YoKXN_X934>NP-ECc?soSjdPd7|^B6!OB?A_4vye@^o@J=dHO2~194=Vr|Kgy_T zD?ckY%Bh$ZiY^vk81g_KI1q&nidxk@5^{1`2E;)SBMG+1#ywH0S@k~D+4>V$tAQCY zV#QWiORy(Dx0>76wUydQZ7BA3N)xtf)hhGBqmD8YCQJ}#0a+4`S65bm#WZ|AcrNqg zEq0Z5vHd##WUdg|gVwM0FlNZxj%ina4o5=evvsh9!BTHAcC7i}kw==h?Ypn}!FRuF zZvNFTWhF_z_lvE@l1^{sD}O-_|RNhpWPDR9d{N_ZoPa&U{z z-gD1A`{|RMc?BCTan-@sn`3_bC{{CG4)5ffWoa*KlM~q)O8PuINRt=>2T-2SNv4i~ zJ|IE(I51&ElQKylE zkvPjPLciV*Up?7J`nSrdIw`8&1-u}J_l|X16*;)rRL+;uQFNu zCENs+?0zk%Q}tr46oE3TD0!NATE>J+GZtKjC|!&|1hEs~?)sba6;y|BG3_x2IUy*Q zOIjYt6Nd-#)^Z1`%VF7BT%?7E5L((Cp9Ki2zsokja4!scd|nSvY4o;BTF*mnSo zS;o(&=0T8AB876WMNCS_6X4gBZk7>De0_x6opg56s4VMzIH{v!<@Ue*)jaa>!{*(y zXPeoF9x6}n`4tH6l^{HM9^%gr`GgQWtj-PxXi7s8NpnDE28fcvK<(owUnyl>&{br1 z1AA642ij^zOvKN<{sne!PTS?uvW<|BJ6P$EbBEHNyctTu=4l0(C zA+q`acJTCYDzhKb?w(G_($O#by^hJ5PPm5Yh9Yy=zzJCKf!tvmon+RV43&liY( zn+dMA8JRdSGTK}()C6mL5=Y>y2-Ffq*wdujbWEOX{`-Vao9%bp(R_Wum1Z@ZF}jBh z$!rH?WmX_=`Z;#|cyrj{hl^v2pKFyO;pz7+p>8-7@k&^^(tYF77oT6huLCr28{o`> z_uOrcy5>+bv@{ovnPaWeXhZe^KQv`+5rDnHn`w!xFpZUv?dS8z%l*nddLPWDBdt%P z{ltg)G)y;_F>kv;FJ+EcWz<;eW(Emr=UW=4#g* z<^zzH>wzm2H2{l}v(3k@|C71ukiX?*{gL2a8XvoUj)^LJLH@}izuH#$i+D~(M!9K` zabW3Zxz4~5JREYEL-g^Lzr$&HOt#v4bT%dMJFDLzS9B8#AE-IGETDb#2Yktw^b%|U?3+u zc(addoed|4gDXC=4MF5`5TOGT|9m0L`O9BgX8!kE|6|U=7bJf9 z%U_z6D^|*DGT1u=;@LmeCX;6Hwi9J5I47@?ce;?L;3AekW(DTqp+rQosFD^w1WHjZ zJnnx1P&}|Ap5z@0Gn|O>6`%XCiR8ue=bNYT8C=?%^;?EO7BWC`ep(}9IB)O*&~zYq zHBpP!3|Y32>K!2ZQDUneR7FPZBK^Y3FCglVa@#(5Bq2`>dg{lvwC!v0#e_K;IjL2h zsa#(Z8Y#8N+7HC;s8`z2$&_;-T!aVTTu9P8rI4!1Bq}lo9dwX6<`e%V{ZgDQuKHYI zUtgqSy!IuaoD~vUpVWZ7)QJq@7zV9W$}7^yeE#ik$3$o_hHoAAqM0=8lbDpB3}sis zqqBA`avOSR4KOv3SKe3BNA=UhZ_YRK&~nzT^((9a*8>Wkmsh-AKw8vmOnlzh@=0A< zz6KwTnLXgn3>8du*SzY|0B^`xOvPi)Pb;6-5`P7K%EYH&Vzfr=)KCX1%f)dO=XqCY zL%tznWtCS?Fqus7Dc56e82Va7?UnYbLzcixbv6ch+&VYa-x~qd(4SxK)XPDNvo@Am z){N`J$&mSG{)&@V*aKioILO((UhV|oY||gF$#Ih5SLe&7a37Y-$b>7)fZk+d%_9FR z$ktHoG4hf<+t?NQIP0n@X&UNWM?%u&_2mf*Z02XLjVtjPc^2ZJyAQ){H4;gQ!rdA&-pe$yn2^sm=OJr8-kTO)EF%n_*fO;sy%@hem@r8ZsEJ zghwG=6o{X3VcTU{s*x>35`HZB*MSj|1}xBUj;R z>rq#qP_M#?OTps(0L%fqg5w` z<*4?uD9ToGb0Q(HuMVMXwolmA5tbK@sGo3hg#tq5m(jN*WjLl-@l?U4p6@*1op?R! zKgD^Ke{ChFx72*yXxWP|ntPWlY3%c&7^HTBOFwXWl9EnGyl%f>x1D$H->1a6QUjFW zQ|SeVUX024;ZW#dne0f_)ID!CD@;>X(Q-T~cXU2&o_1xb8sT}F1NNFHW8x|yvo23Z z8$&ZM;o~)!PpkNrki?S84=O`5Pa<$Km}M_x!hVuj^E~#;c<(=Qx`9qmY?alon>JB+ z4;{QRrD;-M!RsAg@$Q>p(hKc*>TwZyU0&VC*kn<05$-j<`^vJCyOK2cNzrFR{= z$7p2n>_p7bH1}uCH`lMMIk{6DvQRw64JVJ|uMx`y*G?2=5-Bh{q0A?z8yb(@}GtHT&ea77U zi(igD7ZU$&UoHY9q#htjgiS}A#Bd;5^_ z+$>Ytkp_nCtiBLi)1HlqB0qsKQxCL+SOegEj|@f0V~0aBpNA`F(-AIM+E2+3e?kHT zO*?=@76u%6Xyl{Fj-T)nKCXX&ny<(lg4d$iX+n{!jSZg9t2T zR(6NyGIU0k%asT4I?H(;(cn&AdFV~1(zQR{4Zj)|!S45bGm#DCY~{zArp8Q5V>J4^CRYEYCYel4m`nb#%m6JOMjgrWvG8Uv>v;Ld)wVTz)tRt;@5H+y+SV zixAcF%_gcHXs(=niTUP7Hr^MG#Ac9JWK{h;`2lJOimx47^QvzHazA8NFP)D`-_0^P z(z<-MdAmB96{lGqfrC)t+V0$YG>%R(AH9A*pKZUSJFz#?(ylo;7k&uOe7$ZmS2^;u z_FvUQ3M`(Fo8vR#g6QV8nc}OCMAPx61O?d8Gza;2dJOt*6Q-*+#^X>>Zqf-YI9(VM)gg0B~KQe1&MCDjgErg+N3 zp>6Q!%Go#IHKc#VdHZ)$!0U7jlu7#@^O_d}pPW_PO3JnGd>*>%S z8;fac??)01gflSGv;bP@ptAcSDNN($GReFCmG>1Nsm0PnX!W{}vmEAy&{l=0w# z;xj8eB;g7}v^EQbJv92T&gfEU6z=4A$tU;P$Cp)mx~Cn(^8wIy-rNb0^Vd%8 z04`fE_UMEc@&q;G=}C}RT*qlf72b+pugIpf4(56%1l%iVs1I=F^Fi0y1h8Uc_xf0h zC*3z(^Fwpf4cD6~)25jjTfffiG;^leX4`E|N5^D?Ni`fCMfuF7Y$giFfW)X1yDZ5B zRctKv*t+U%VXG!ooEiKw4D{i<6m*u@FOOhzRlL%}FKw(`vBErzy*`#Kxknr>Pd)J@ zKIi#7R>BY$D@?E-2w(phH*UNgW3*1H3BKBve!Ht}SjN|gvLyQ0t+(F#9c&2s0_AGe z5J%Z;`SOV92nD5yVd-3Fmlim*&=^TNJ+$A8p^y_8`-$sMv=M{aOfmu>D~m@Arq#BB z>*{Z?G3lKB6|T5SOBCsb%8zx3JhnjPU|iI_WmjE6wTgzLO~Vv;TY4D;Rm{I+Ql zr-;>m7e+W-vY8K}PDLFEU|3&A($V1Ee;Z%uf8DtG5`w>yZg+?4no5qQL?F8(U?=!Q26;cET+ZWy&t2yhU^_%EQC%DAu_=8RprHyGc zYz=J$uM(jrHBr4wARn46aEO7!zOTck;D2~g@?@KgnZo;i@e(0WHlpPdeHkZr<_=6J z^tr22F=jxl;jCO7d>E^%XTIUqGg+XQeF|{|wl?=&ShK&A;G)&Bp&-R3+)B5ayxjh& zl&>;q;zdA*(eJ6RhkL}}LH)GQwV(=b+&xq!!QmLSfH2AGkR1YpiA%YiO1!uep_#k^ z5#=T1Y4;A^C~_y&$)EW9OQ=)K5qg%tyv@EJdy6D$e>*b4=`QQFy%>>D?Wym3SMmcK zMfFTAGf|Yt0V(t2UQOkcl55J-cK(db!W*G!m_*bM4kw`#z7W%kqqB)}Yr_CTvXmAb zBhtm$)HR)HPkSE5vK;1id0X9YrDw%b6`8|dL0YRbE$Jy?t(yOd*=jBNsEZryG~L8s z3>;J==A<#0`@M9Y9$Wq49Rdp-cNDF#C11J*QM8Q#E!qFbMO%piL7*{Vtop4Iz2J*$ zz@5%f=puOqlFSGj+!)B&tbV*IE7YT2ldcJpkv+~hH$Fh{x$No9(eaP;-Xj9$){@cq$RXFpC&~7DIjbKQW)G;TE(~y};E}2p;cYEsRhE1~FW~XKk;UkT~ zcy)Z30@B5^F^9ZqRCA^zm%5b3x6N$?=+)9jk|S9Z0FBU$(gqpkrJBL^7ol;cTLChj zoHbR`VGZ`l)rSvU-?!a>p{r!>ig>N(y$Q`U%evI@C7`Jj^MU6VNBW4xz8SimXfbZ} z@paHj6jvWbu9)9#drwADIOW^eNL`~hUe4(pTI@L2K~s`bK|OLP47{|g1kmpEX0~y7 zaF)XqR1%ByJH+r4(#}XwkqvXhh-`bTk8Rgyo|aFkDN}J@(6%PS5BIO`HzkX=JF58F zL`R?gCgW=k{97*Tqu8s;Kz--SANxxu{J@lpuSyHLQdCmk)Uwl=O^J0J3H#OD7)u+f zwKBq}_lN?7_E;Kkn?_PeJ12dgS5Pz5kJL++!l^+5@V$$%iS1`7BK$2`%3EM zPD^Q0(PO`fJrYE#y*mA^&aA*zO6q=@sc|#aj?iw2>7txPbs1Rxz9&jD^v)q^)UeY~ z2el_wRZlnexJi~dKa-k#eeXd+4_Fbs8CL}7)KBeAMcMxN>ezcB8cvjoz!HDl$p?Fi zH}RCv{oA8AE#NRU$!%azFaPI9>v*tMV#ej&4n3ZYq#;?~&!9nGXi`(~ysGjZ-75{I zxJ^ojW?ICA3r2#%oWW#43Njr7%5>*&{;{OijNh zL9UPAcJ2oUr+{{JU4hBxjkS{*(vYU%iX5SVyfx_@(~E;#4%=tuV$@bRo|i1rjAgjy zc^x@oZZ6JE^ws<{akk4MRvUU`n2v`lO_2;!)5ytHyUc%!13QF^B-F%GvzQ4%z|+%DpIL=|sjnxKSQ6hh9YPahSk0Y(o}g_Q_%$2Yo`kpm z1Xac;D9mZo=|WCBHq7`tatn1`!8KUi*(|Gyo|K^IxdTm}CiZ!K&8?_3u+%R{;wM5l zP7Z9yd?_tpy&tT7&UqWgM8AK}oZhnW`sN<|bQlXVqTo0^CGCL*#CmwCOmWr6QltRw zC%><15-jz5VOVEc;mZ(Q!32g3s0);bfU_V8^K&!>5*o;aj3bL68~Y;!LR)ii<3rH( zPbf$M`fIQ)8eOngPy2i4neex+RdoKjtb%cNovbQq_qQcez8!y?4S;p(e(6{9Dob$@ z#rlTqrYl$F6LUR%R}jM-opAD^Jmb`U@CcESJH?UXxyZ z6piXF#0x)!#17OshY= z)1>Mk+uQWP{SQ*Fn@_1)F!YBDfK!vyqhZ$ZH?%nBmDA`Qb&N3j_~Pe5(_RvRn2o&A ze8pl+cSmaYiR+nydmm5B=aY};@Cp*lj=k*pV~K6nB~T2rEX=^37>;DnJ%=WjI#ZIh zABbi=xb(_(I&rB23lmh?3C&ZqhP7`?O+97Xx2n3dJtS`so+!z7)r^#Ta^eOdJ$l5EIM!65A`ji)Y zBg6>#d4j|QPw<~y@}R8`tQ8>Bg1qvMGOl;OP8 z*t$geTNYxeB4}@qe*hX{RHrG5BgH@lSgOFs32HwWs7-~h=^lfpvvPFIVbDnfuZ`Q7 zRMb#k{0M?>gu{jJ%@_E5Nl+MT>6vX^EJnq9D`ih^;mIXejS%CV=I~6zLj8DQXE?#3 zhr#Uq3UbEe)Sw^H7t`t(3u>tr_~rP=dvTt=duCE|4nWtZU~jp3 zIM^MJ&wyYT$K{&3I$2rGJOk}ZY!`=2)2N>Rs{XI8x)G+1R|6@XU5Kacp-tV>zb|uC`;W-Bqr8r%p;y$NYnCv=V$g42(O8_RXJ>+R2?q9L=`;2i=z%cDBOWHelDV?y(Q(d6PHb{sw5|#QdVy z*N;uGcA5NhZ{`F_@}Bin)a8n)<1|#EJw3D%*tn9mx!U!0&NTjAlZUI0g6?!MQDd62 z36?;@c&;q4;YSg=wuC_O7@`14FxZNS`FbKGM0!KE5(#3N5AA>j3jgH3CP552{MxM;j!XvRv#et zO|!Hptj>UjV|1T&P6gTO)Bs;`TfNzJvcAS~AV~h=q!+G<&=$Kx8TYj+UIAyH(<*&J zm6`V58LK61yToE_HIT0oSuKo6;t6|6r2UpsX2TzAb*$P?-u-*^N-z!7gAoJj7B(Zx z5;1{zXFW>+qkP2B(DtPaR&30iRZ-;JQJS87pAj!DprBkEN4}&1YGye+PpB!s)(Lhv z{d^Rddaa!M}}*>p+bT<^|T+e1#^A;(>rgicZsRB2IWK8kDkAL8cG#axXF zu$BHJxT>8>VSz~OT*r1jYx-Qcq;{>% z$Cv(c;y%B+V2$Ky3IedT>yM!xMtk7`@VoWU#5L3HrsOU9(3u-r&7mLS!B674WdH(t z;hUHz*F$%x1pq7|i|^BH=_D)24-Qa3YAn#tA4!L1BLAF7)Zf_fXs@f;o1B;)E2BsAj|as~n3WvH%ZvEEZrJ#9zx^BTB#`c_{VgQXJ!pI9_O-wIhGTul7k zS(9TEiM9t3b)xy~$tD~GP?KCutKiD*vC~TLrOP?NEm}?6iWI+i;>Vn0#j- z>T$$eR;^kZ&6LAbFkDDB>Cm@@T3!8sq3J$hD zfuT?HtWg6(Iz=h|H1r$w!?6yGqf=!f+WW5LE~?`c?-*#?HjrAMwG2W3SJR!2e}c9) zQPGStW-o^%fqE_E&-W2aZA7?kcbrOxB*pm(_H8}*Vvn0C zG_>D_I^qs8F!fls*PIV$E;ytr9-q;0IGLdS7+v&Qj+Kfo-afHOzHR3}*LvMr_sG0c zl?6J-Src?sS9ftVeVeGKMQkjX`nNcJ+m^&MbFC+|&9&2)W`tnR#&{zvKqwVpY5hZ;$Ioo;XCTor$OY; z3-n;YuS?Uhh1rABI1DSlm&k6>nCl;b?0=&7VY9Q)k?#GIqseP`!lWJS4g~Y zdM*j+kpy)@ykz4aV2%ulY1jV7n6nZZl9~dmKf_R(P(m6|Bcjns3MNq4sM6#8Z>)z{ zWm^_pm9KcSj%k3^09!u(a^aH*5^t#9#6tMB@`8IunqOS5f8o@<`|^eQu3wq^uP*UB z+}11Q&9?h+L#?qjwg`M0qbN-Ewz@3je2HYZv*w-qe9pt?cUjom&#ZVX1w)WcEtlTR zU-=ac6@=D{3Y(=vHvYwO4646wm~4~p3dHYIYfI}^_Lb*kN4>GV3nv93PPx=u^cET3 z=O>QVVmvqZKk;hyw^#^S13KR2V!}3CkPF(`?&otv{5!miqBkL|vL_cB99bhij)d8d zpB{|I&aNKMC@WWX)v>VWn~dW;+?~V|wO+!Znm$-IV`kXkNV~awx2@aeS_NwE*xo@E zOVQoq%pH1G-S^!>UteNf0)4wxRc7$V=OCzs-T!LE3$(68UTSts=T`g~UF z?a_LC`vOsXwL5j0TiJ29B(K+z?N%Y1+`Ur+E&Nb(>isU;jB9T(b zH629cyj~ez*;tTCesPZ(kfj%Dy~**J*1vzfG4y>|-R!;+Joy4lG z7FN;J{LM72Q4uHZB1wMp%*m4=L5yc&TA##s3{?9TW(Gbs8%m1w%dtit)y0Cpxo(qF zQLEJidn-G=jw$RZEmnnRhA3q7iQn5CoezWVJyi#wu8Y?4YV(kfE_byG&lGvDbkN7? zdJLOv{<-tcOz}Y$8rnOABRFtLejExcU5d80`BBF-^K0-ot|H{zAkJFn#WHhYhBQEH zA+pg2*+Zm3%XZub9*j1x6PXXhLK^Rq+eg7jhf<^1xt_-t`s8;f#+|%;L}tGo?{m2K8y1Bq7Qw-aImJ0R+&^1`WT@yly5wZ961j(s-3W4; zNEsP^cm*V8@#BLwh90*qUL*TEPTr6Bhzru|C>^dR6Hpv@R|h77n0wyNuCS9-)sm*t zi%wLZa~1_jFvdFPq8bC|tP8Hdcf|Mb0F8On3_;ce?iol>6)Z4zusHZ57Vy|MVCrb5=>YZbiYfKebn4`Y2y=W3>JkJ1-V3 zD@~>0cMSxHyr_pPJC*z_>X-#9Dkr!RJ?XG`oEm~~$L%k6Sdy-|+3A66wo;x`5HFO3 z*Xpp zHeUdCcu>0&)_@{CV_^6=I8OlX%D64miY{Vw{=;8;K@6`kC&BD*#Cmuy#oE?Ig4ODKX~7#*$S z_-0A+Y93Hj6H>hQPO|wi-6CH5S>V3#4HM&fty+x?H4-ye$q^ZsZbKfFx2=aCxim?b zB;O9iJp9C3u-u-e8x;mk1-xg!?m^=8VEb1pv3T2nZj}mV|_{s2< z$M6}pmn;rCJ1a;c|5d<2zI~jqKWx-oov=ZQDEFKb7iRGKvw)$kckSV|7%jXZ$mm7C z2AsCGiujz+%k-FRF|6Ru03#wF??^PQDQUQ4F9${YaT=B1zIHw23}?2X`64d;x)F*l zUA&npyVsXn>=H7N=EZw6^2ws7kk2P>U?f0)i1FnVCV)FDvM1|IvknH*!rHBJjA*tp zV%bdeUm1l<*Yw8AZz%c68$|fy-+d70&f zBf$glRkd*6oMAI?tAkX}0?@th`7Z#PYD;(YE563Tv~Kw_C<0=tGKNp8PVTn%=fq=i zN)gYr+I;lXUr^VK@7pZ4*s9T%uA~6M#uCp%#3qY2p=P)*#9drMZSJ8avl`dJ0ItNi zo~ab?d_|ljSV_!q&K5lz52j@AAnyjdMCB#?Y2WALXHpQd07$9ua31Snv6(I)t{H~$ z>5}_5j+L+uMJ61n>lqQx@kR{L@~ZVB!W~k4hsv5#JIILHmT(h3qjw7kBm`!!%b#EqDt&>Y{*B9ib0HswFc6 zV=rrID0Wdhdi!l9BD3WKRfE}CTmle#JB-+^P!Yi)D2DNd4e50(rscY+%+qA_6i)o4 zH9-$wQ*M~4%Lz)ZBI6*23_aq_--Du9+hVoZ%X6_Me6F|Q2gcg%EXpEGSR>$so$Qe> zRKk9Gv7fZ54BGu23f+|>hK}Un^M!T3PuJGPJR2B_-%3iA8!2<@GMX>MG2yS4HW_8B*Gd!x$3eG{5#)a=3< zLqIlS*E>?P_zN!_+mz+pP$jdoV+E^%it?>PG(Ho#2%GBFNHmO|bcDMlx&N&-eVEx) z=lGZK&{=+>sEA*;l*p-BV&n00$Y=M+q=FVFG>g@jmyMPlbCQ5lR@dDKA-hi=K3TzJ zN$!wDr~qE%<9czXvbD zC$FrIXkK#S*|K~!sMT@178tFdu~n`j9uJDyG3L}D*;9S^=jOB-nM5Yx{g z8lOp}h~R}SV$2vc;&P;5NulcnmDu5H>d2)DXmfqQ)bD{q!IF#;M!CrT8>v13E3mDU zC*x6Ep#{E+{?Qk;I^pa%0PzoruU03JCykqpsS(o61REHJIDo zTM=3P9#M#0{2RWRCRj8%F`flvXwQ1n8f0FU>@1rq7`$n+`yMPk%se$$BWbox{w3r! zJ`)B3h;UXoobMoipTHIdsrcNr0^xQ00f}HJbUL$tXgf3H(kxpQU#3~%QO|11{I5Ap zq}-~YVB5=SA=cBEF9&Ng2=rS)?EEvSdUU$$sgLvPC-NCc)_QaO&UNd_{k#fjHaQmU z1KU|I%HCcj&A&6-Q-mq}DrHyJmarri)$xPqtQ`o+g?;Rw7{F;|1!OVQ8=%i3fKQ6e zQN-*2NxQqT-h3}4=Ak9AGlpCNAKD7qMukoMRk)4O)fYouNX9QMZERSHG=j(VC2AD1 z>c-x2+@=>E_C-WF``|2GxgU7R`hdH;?~BT}7bCS+y7x0AJw7_h&c#(zItxvc#;9Kl zVx*uoGNvHiH-DuT3~;m1y!5x;Q}m>BPL!S_#cx)w3|qre0O<*8lKq)ax2Cej459}> z5EqB+`EscQ({r>+2R6Gi)gBkPu+?6_m}hug(?3h7SY}sF-QB^Y2%?}Mb2&X*lUl-( zL^iFG5y69&mEJ;@5>R5@l^ER>P*J3&LR1<*hoR!c4DqlvD=C~Dx!^>XWBv{5?u;GB zFaRu#OxO{K&3LRLC`iJKi6a>p4`PYng!u7AtT(niN$TZ{r5-Vv18>MUm_|6R(5?|u z+_WII{mm+}bBs{B1r~Uv>CnY=^uVO~)_DsCVjw&3q$SFpsf# ztaFQ%k2RZhfX~+7(Sz`zd`Px?gd+AeTtC<07<|IJJ96w_N`u+x=SEY7=MTg;kzoV! znuIwzDJ^}2UQ~S3C{~%;P7-m!h0xOnR(LDb$d?5S*$4GTtNnBD32H-aE5Y`|j#m;E zoQFqJ`3-0&F^7U!U{#+Z`#_<{Cf}L#TB7@c1P33&SWHe}bEotxO zGxd~nzCO3}h4Iqv$WXjgU^&$vfJa-g6?=OuD~b)%9Z7B{dudvlb?Uq%5lVqPI$0zu z)Y4Qoyz6R`VXPLHtC^X%i|ud+e#cSAA8CK~mMsp;mamVq55u8fin1zU$d&|;?FIz= zPf@+&Xgz+erfLFMw43fgm6x^>!>=m-l7^t5?rv%>saM>?Ck?k4+Q7Kft0;O+l`QBQ zpViP4_Gz&;Wtb62S6?R#6LE}D4L3)8O~IIy)qr1$LL(TvhZt=vKgd2gWsdq57Bo4Fc|ZRbcLhz7^Z zeLL#+O0&1ZmpTC5_fT;>jCM^V?qm_$!x9&pERkNAOaok2|2D7U1?=sp!M1`tCoZyT zo5F*hYuQ$9FK)+h5v^!gxPveg#;^G_KD&P;Tj{%c*xyJqq!P|b6tdNZHi+;bsJDZp z;i=RxS;#YR%$FH%neChg+2QiH22C7YiU0huz%H##^Tl&>s^|5AiNU0SOaC_(SR8|p z^z8!7*AwwA%-`U#JgcUcxfGnBNyLpz8T0clzEQY}NDy@-xVY`N$VJ*=Z)KRw$;~30 zrZ|b06XnT*M^(qNzgdA;(og6FKK$tkZ3(OmoB0 zHCyJJl$JBo=76{R`VT1cZBj$#t?&vLQh7nMsHI(?hb| z{6*E5Z=jy{JLXop7tZz_0KWwF(01}8-AJPhz9PLf?r4cidH3Ya=Dsx=%yyLhcWSSE z*L$iOEK%xwOb$u4_vl_K3kn z{*jmV6mlrT4t>ezS&kr4XX)1$xb&Hf!VughyNHqPmm(xmj%OW{*RSciYJeIy!J5nAkmtFcy zyb8u^!}n-?BH1J{&i1d6{FpCBqJ`bxnLI8N0*`S~_AIZI7bi2@EMW^ha~75$A0?ue z%fu4fC&t)oj){`?$7?#kaQ7$)11&kGa{}k(RupuOXt7YjCQxV%r@OuDGW%Nlu-7s0 z>0xl!R?JVYXp(@((;00C@6c^}&b*bk8yjcf&w-@XA^9oM>?pl6%6c?z=2kXU#H9HJ;(}+Pi z6z2lcTjb@7B&^P7B&uWQFc(85dXJe;i{y%5y(>w-s{86s_>$~E?|&Bvc)c&Z^xshA zPHhw5hMS(lm0KM}eh0^J)^G|4b(;(`2$8nC-_{V8`^-mP?z;w+rR5Yi6;t_p*)!M2 zd+vl*d63$D(5gybX}=ik&J-6+BWZ5b9b5D*a{f?6h}8*yO7F8)AWA0>0sP1slV@2lb|Ed5`;}JRwj+{1Gr0Xy0B+3O z>HJ5;BP+v=u8Bm70SE3_4(y4lZ5{%S6*1yxZa;8IYwU}SSQ{a^d_uOw)f%iQZb)is z?AdRB0nz!C(-CgTwiAH#s0i^P4Hg2tv68S!KYa2|zq4hn+{_-#_d|(?k&cXP?nt%%pd0v&ebuOqk~?o zi+ooGwX}A=;I|=ItMtwXROJcZJ2>?~Bf@+z%gp=K84iS0YE*lVopv}bthpdkjze=* z$BggQSADZ_bR<7LF_4UrLIlTt03k+hWlby!Q`y<+u!0PGaT<-Y<(!q; z0ML@!=x#&oACznGphLjoQ+EhyCESwU?Ih-ijaBBib=O}Hf2cms2Q?muV3`|ag=G8l zNdDZyIpfA`EYc-dp0W*NCpS*Oj^ynngzDMP4y+YFG86%Gvh`|b z@{rYZvTkc&ayEb9(mj@IesLrGR>|3-&ham#3Impf$zJc|f~^K=80_8Nef~hZtY~<3 z%z4{`GrI$kpjv+hz8UfPrHL+oj)gFy9Uq)0y6;La_x1_8o0*e2oMCmHw~l;~x&={p$cMc^B zL+ZcDo>drDBID0ANUqbspOP4wMwboMjXzdTkR5#spFk7<7Sq2PuXglL*KxHZ?!S^r z4M-LqGsM31LH)nNXad=`>4>ha^E1ZkA3mYZ50Iix!jzxlh4e41)daoD1U~kyo!$ZBCEa_n}y1 zi;W!MKy{d#%z`16G@b&^LP_z{cRSu#`0iuZmdlN1A+-~T8vF>F52?xBS_*XGAtD$E zH#RIvaJNEoMTu3WkW5FX0B+(Eajb!iw+AEtO6^`fM@^PN#<6yUXH7@K;42AhhQrn^ zQ=Gn=P(PWOp5@oG!PQS5{TYu8{DeY+P(;9w|NR?7$rw{FZP$^Pj``avCwmUrVzsx2Fz-OYWefUV(YPq3(*P!n*y=etcVeQ@HAxeS(Q5f5sE!T$a7! zy$sEb49hk+#(4qL?I(9S0IFu%HoFEvPmB{>@!hSDg*kfz0vFO`l_s61?1n(gFyiUvXnf$kAJi4X}4VS2mX+-7E~J)Uz_QV zYo1WZL0|c{DoSQq=rB5lV`_R?SFsEu`TxL~yE(i8spOIx3o5wkoE%1n-$o5^gv708 zS+td&;0%mp023d_+gW8(nKAGVLB4(IUnG-f0Qzo$id8}J<=LCiS|3&XVj)H42>6q??;jPbu0Cet!f{ZD(GolG^p8^ZtHrYE9UVKZKU zKN0Rbebi)~O1aq_1E)1(*vz+K=0wAc61cq*jY|BI1`gy(G5GFkk=XxhA2O3*gGEgf zZKm_&{>x?mm)q{u$!oabjvPxlC8YjaC(~w9u~6|vSQ1WDj5!<;<$If25IM?!Km9)+ zOH1*y?{(OlfGPfeYKRu1SbF&iHvVGd)+*(I4RR}|FWTH-C1;-q*Z+7WGA;0eHW?3x zL3S6E$A9nPa~~nF{?VFp!x?xJ%(qP#jQdeY9m1l-#BO#hu{;camDt00{%aMZ#3qP) zt!>{14&O(ddHH-UMg>!YFDr92nK7QRk@W|41-1MN(Tdete+1dRTvjto<9;;P1CjgX zt49RhZi{RM_*{iJqd<82gc~1Pe-IsM4oi2wn|hlIjHf zgk#?O1k8{ym#)_ZYU#OOmkPbL^i@j7`?6>Ua#vDF#68)Q)1K;AFV-2t70+Z*41kLK zC;C82bu+`t)VY_NoA<0D-aA_0U}nE^ildrtawe04D}rHgRmMUAjeoihm`aFk$Vxte zs&c;3$14R{m)*szvkIGvj&Ni=Q=gNct;-wW=g@cezM=S)B{qpDI5X)=J--W z&j9ji7t}u%qCV1!TWhxP!rTh3|CQx^e5Ke}Q2ne*rSLtvP|{JkD!m1aFv5?Cc@Z`? zC@1&*z0ql_{}++-AbM@zz`xuCID^b~*f|0XOR(?m=deXioPgwws%D-y$*Svu(fll$ z&H$8ilegGQU4E(s?XaUe(}WBGJt?u0H~Wk;2(Ws0pOjBp>0qNA^+S#B+Kf{MqB{Lt zM@=_dd@PFQ_*@6b=6%#3&Fm*Qz75YJtp(NHQfdtnQv7lE54+kpl1#h-)+yWi6ZUJ# zED`G=1oyhPjDMp|iN?-QfgTt7Vb|g{e$$uH>9Id-%;1y41ftvY4p^nPPEU(ddf8nS z4m9A38h%tkKosWnQ5Idkq=>V@eY3d&}YA1xhet|rgo0A;|pDfvYX(xNSE9{7(Pn_s| z@|8IDt}A8=HyS`K=NhGmD6txj`DBK5y<~O5DGN5Xi*D)X=S=ug?!xAiN~C)B25~xo z2^b)ORb=7by@+M`v9+vdSwBynsW_Np%?TB_l(})0W(uI4UUKNrR@PWz2Q<8~8ZY6d z;N=cp=M5M*%`-dUO9?i>^)4R=j%7Qtx!}ue62AKK%lAcGK zGfFm^x$_XQN1|{i5tefBYL3O&DPmi;S=|r&9T@0j@W9GduQxs zw&-_xx}3~1?KSmTCa^g8*e1wzrpr_3C|5Bj+VxF}=ex;0=9RsPa9JE~tZDSzBB_pZ zR$nI3l2*o!IP5yo6Ncd34@6(fEsYz~_2k=w8|Jp%In_^3luF}TnCRkt2OM1|A=Z%H z*{K8G-4o?LQZjXHFV$;4y`{N`u)oA{JVZqm5D>Tj-XW*S4O<{?0PlVXGfw4X2K+7F zlr7kOq0V-DH8ki-N`WeLC5QU>>N|X|V{5L|MuRc`jX=Vriv;)TAL7o*>|OOQmRZ<{ zVI!+zGSfQYN?l#PwUW^AMnku9i4) z-LDIxZwTe!i7Zq=B)in?PN{dz@|S?~T9?WgVAEoi*dbTwW1C*1)&Ph`58aMMJ4m<) zRp-98A!uQvCiNh;K7rl%|6u_{PjlI}ZwAi)k|?jXmx>zGXWT1IIg3jWQ$|0d&51>( z*8&UDFt9uXBW?u2A{!3cM)1$#_aXce9G(a?c9i0Q8wK}D3G;EaGFWW4kH?`69lRk+ zD-#(v^#vU!yiE06&Kc@CEt``H-96sv#`fV>*;QS zZGUfu&?y;qZr_jyJmfhawrK`3){gKk+P)lk0X_fC=JuW< z&m}aGAC{xD=t4h!ZFF|M=+5-kmclZ1UiKTGiAsJ#7{sh5@;oaO4SfVfViFx%Na0s9 z@$xP(<1O2^+kfO_L7BNW_O{(HW$DXAZH}Cf^DiYs$L{=&`Cv;ybGU#!*%5zh4>H&r zMq2IRc|YtzHub6fJ;g=$$z(3W(^*(=AwTlG+fJ_a()(nk7~|NAe&|%X z9Nc5C^6E}#Wo4llbGO1#i#8&SGj zW#M9Ya1@z|?v3LZ$zmR5DuLT8Eg%|6k`PO9qdOrU0=Xj z`@FUAd5qq&DpLMx49OcJ>Ad@ObnmwWL*AV7+G&SVuFWsa&*TkKb_5PyLNo2Ypv1~ITZfqRK|xzX zdI#TW{&G0XTSc1?u4=u9A`hu1%xiN_8gjg4!rcGRBCYX6ZuJmxOmTN}vtz405Ivwv z{i(BFy?*K<(G;;FeHI@5!wy@du2)zGg1dfcG{|mfytW}n-whCL&f*{{Z9P_`W#-ZN1*t~j}N+t5l^3L4!nLezfJ5n%}5J1U|w|^u5?>cUzgcp z$9z-}5x5>quX9G$Ul>y^E!LZeJagd#n7H%-KJg)+k zJUe_e_>hz>p+?TEO;v9w1v=-Ldpbn|f(Jl9gd6J@N3?ZGr=`cw>@HR@?(F9>2SFE1 z27RIV|2x3XQ$+k%7Y`9a15J_Hj0>@G%eBk9}1QF@*8;&Z%e|}sqwOed@q4gb~mPI zzTnFN>$4d1BquLFTC~l{ZRZgcNR{*eca- zmLneGGv5X5c@|VNJI40k#Fl-pT1$-@ZB?DNny-`DK1XJlxV6K!9jfM>k%@7)C6+^Fuv9tSL+G3j zNB#D9LiDf5KJtLQ1>(^*9p}K2wR6tOhe6kuhGXlDL9!JI0+n65Y zjrFi~k|I%*9B6+`IY+RGU1^&DV{*3mDub@t#G8@EA;r$39mF-n^FOo!c@ZB5OWRVAuDj{QP8OY= z3MjD(^Z1~-nkW0><{yWF%Kq-!8BezI%{ATtTK;APRPvp+V3-T%u~|BLHaZ7?6tBHq zG0znBOWLyCq8HM&H&#;|zx2x{SiV1A(YDqYs~%U#M$Gp=DCxoznbMIGK;&%blc`Q2H?#+ z$OIUSO(2bI=+k>Q(45$nveal#-nFlVXUM&UxsS&6slfGz@hU{W)WA;vT-O1Jod`g` zA_x499<=Bkcqo)t4mv~Ge@YjQp=g`kGRhY|QQC1^a@t|)Rqa;!2D7qsd@X)l28J)( z4)4}4Jb!4)h)o$H_tPsUO3XD3x@F4E@3i(P;e8{-S{I*mQJ$1x$f#_A(?8edw_+zB z8DgBdO=C`8PNSB-xKPPI>j~f{ZDEfp zu=wwR3ZmWMLEGToH9Y!|3Z!}>8`dQ#hip6^zO3K4g0G+m6PHGinAFwEM0Ii6X;#ImpBqw{U-qC9>(+H=+P{`fO*b@L zS`w}}Vls4!dAYM5Qorh4+m5vYh%B@t{L)N4JdKagN#)ji{8sf(RKp}Q=g!D25twMG zMT;Yg3Dy*Vug&oV|E9nh(|0e-(zAw?%@YYbp&g6R>tt>|V4l(E2bkhVHzK?LTrTl& ztg?vb;o%^dL}&YtjXE)fH0bA<9v=!u^1S=QZ)6d_FVB{^@duiT326=Z#EaCI!(GIioS2UnRPeomYsOp?gr#GYVBgR*~VEnxAn^)lfDDb*b zFto_uS|Y{iedp3nO0sdX9laaSF{GBfv$Z$C&G>!x`vZ+j6cMbq0qNL(9vb&&ToA?O zx!t+Y0VM~_br24l_#M{wy~Uf_Tj2n4M$l(IwfnYMP>90&dW;&CP|)U7uu0}&%Zccf z(14%t8+{XzqJvD#)$X#lpRM#zr6SGuA?>BR6cxTfgXg9sG=(hhNo@SQt|pBsCe9Mi z8{X_(uVL1)La&?s*yHn>^9aJ_`A=w{N`ur&NjUY9#r4YapwlIStb*ihu>7}Zn?bZl%9?Bgxar@Jm-L{wu zkw8DOYi&E#h${s0IxbgybSHM5WEJbn`vr2Xv?imjS-=a80!4sc9{_5AbCf1a@3!fB_S_A=ntqP{<3vB||)SaPIwYWU{}YC@H2 z7qJoa(7>?}Uj%E%_rgAX_`-#^EIQ(d9;-C)VhY|kvHptsIm$6oT&DAr2M@76=yT%>wvzmyEDnUM#ntcGMPB8CrQ$EQ72Y$~ma>eO>syN2NobKDqPc zSG+LwR`2Ej%hFmoi?Q4hkHctN9=N-;PA<4?n@`GUO@yO%{YJyz79O>i;M zCSZd|BO&JO3xTWu>_m(!G&qS0VRN$phJ;Fi7T|Jj8K-4T z!FVELxE){W<2T_PXE@$i$13rv)k^)od@aJ9KWEO1pY1&R6ga-Wz!iEN!<07}+O(^i z^$^BCNz-vFlYkwMx$;W9Zy!Q`S)j7C*oD~-zC`3~ZLOZ$-@E~?`W!XnKnQxFw^3tpGu_c$^$<6TzUs$>+Hnlkmjy-mroEfUy zrI%j1repHNld*ziA-2@;>hR?Nc7yGh<@lCjHA`H=gQ+8xpC6|QFrbXctMs%n|5+e~ zs0T5D@+UA^72W46K7Jj8H630#8LTZA;Nkw%B?PkRo@$J z2X7g4hqaC(pStX_w&71dJ-kpD(qWQxFGx20{w3y$MTGBQe14FGR63BNt!-@8-SPARl~y%KRkK;>v!4*t5+t%%L9)E)@7vGqzLzo z;$hcmgS}RXL3v^0l1Xv(1I~#FE_V~R+hOMqoN>kuWi0p3{qpo20UuHAfzN;b^L*;D z-r-Z9`c&H%TWm2347RGK=`JQs#^MRVXuKCc2EsfIco$aSJcAv-@2pmbJki!xUgn;* ztaqL3LMZRv4j(?ER*SdA)8#$!VE3W9bI-XEw6t1}0GZlxmEWpRGjGH*%IU=<{Vre+ z^*~$;08eCwj2bm+SXZq!qYxE#$4yl2_lf!DEloSHgDyxOuGnROd1#Sl# z8vQGNHq9b@^0cs+O6}H4F-Hr+;$$9ltTG zxHP17XAVbkEvMl)?(ivK9KX8zk7h8e@!kjxwxo_{;?tj3_Rzj5fvU42ZBbUbmUZa}oSXX>67zS;SQ(&s9xrX;z6J z9zA-<)2E)g;rooQ56+pPX|}htj60;Z z0HWZUU#smf=d8{nusMo&Hh6vEfWR05nQBgExOraez)XX;6c(a5XhRJB!Dz3@Tp{d}oGWVBC@!cy| zu3Y9`=je^qy1?48f5q198@%Up-NE(~?Kh0`0y|FN{$=s2xnA@o$h^+ZM_~6OCrs%0 z+Uiy2*1qrvFBHn}N(#kosug~P&&rzPyH2isor-9hvg1B#c_po!iTk8=`YdeD*CmdH z6XdkhI#16^wYR}JGD&Pjn;_u46T3+o2Wu-BP0lgajm_m!vmaKpjfWGsaTN+&D_Mf` zRK7@5KUYaCI_e2aUi@jD=mgbnFy4eiaA<78jT=-878pniaFFH|0oOP?hPr`N2WiF} zU!{;~zAC}|D!wW?@BueTqj4MFkyH(CV$*3^5^tY9zjS6)Xq$zb=t;O)gg+unx7{JV z57Pb8m++J{!*__l6Urgk^wG4c>Sn^2sA+`PIxkeAZc=i*PNucJAEH zwO)Kl24}|pU~wI0e(kgk?lfU9zL?|Yjb!fIRVuT#v^(qpmkteMb^zM9GVW6XiIjvq zV>&o$W(g)+Z^cGduX=O6IdeL9$1dA%#&z>uxKDTkZkWbI29F_d7aQS)Q(G4=v~1*r z_1BU@`Pph3{Svf4#oYb3=bd-nTA!>?fprOU=FFLxCdt$&OD3buwt@&dVNx;+Hv>DO zca16*3Q;wyE-A>NnNmyKgb(|44qyDV>uFZRxvUg9Fgl z-du<{ae~bdBD4oy)3rA_uo<>f?5ftH-<^Ku**~t8mO+c>W?1GFb%X1`iRJqH_>o z3>5qILW{eu^$?Ha&Y5R__UlOQPNz0GNHsh-b|MI~tj`5HbuoRPgo)q?fL^sjTeW3;BS8#>4^$cZkU$nt#(%f8Jvz_d+_gw_KF z*2+}PgJ+!6`3EdYzqJ}w7tj0r=Xu>}Xe8{H@o~JXKM$`nV*J6GA*FVLs=Bz2phdQU zfM@IEsvJ0%j5!cyI?!HYxC@F!W1f2^n6&rl(yC**1J93=do4+@651mTgt7 zWz+GZ%Z#MhJ`Q|RTzBZqpu@74;B_J?Wj+^Q(pKR*yjZH3(#kSrJqo`DTR8%Q^SZrS zO{PUrc~Z?JQ!t`z2P@2iy=URggsnhSEVdO)R<6*ycbU>@eAZcK&BU{W_rtFLj(eZ2 z5_~2EuS2|W`@Q%67C5iUfli*MpMLuIBx!pSlKY{{z7z55&;a<7D*7;li6E2=HE1x7 zJ-pw7tljNHhTnR|S-1|T=H|I`JO4snuO`3?T*A%CWVzE}AGBt4{Q~`xH-HG*PiRd( zLP4H;O!P}|ue1GPZOm|fL}#7d`F=RwpuHVLtYnUg8Op{ibzoXDyfP=IT&aF<-np;s zq0hW|osZx;b7dip&%xaw_-jSI)GKzx0YY%^4V>fKB&%2N0?B?w5jCKFfq|mx$61Q?#Q4ozP7E5g${c-ceH4(T_Kp&CU#08U# zRGCgV;fyImM;1R}YSBlEZ3&-%hy#Ha7T(11Vk8$4d*I}1+oVvKlT|C9IOD8y7FNsA z+zT$~d`$T@$GG0@jvJkJEYB2E*>cDw3G!zGc5JA}!3EZ6W9nd0*)}XAskGBD*kGN< ze@==qN!u5bw2y=3-uQ&sSWd|Jl#VjV4K4HT#=#ju>H`Aqtl|zh7e0(nsDC(3OApUE z^Rr(o6|&30cb!+S05`5w(hq^xJD|!qOfx2+#!+~ZItKCR_EI~18E8K~WkgJEU3%!6 zHF3j^vZtMS=D%RFFt<=j;E<7}rBDN0NS~&UI>8O=#LngKj*EpO(AML@a{?HTL_7wa zh5e?$CgG0j>_1WZOn;CjD?NJN;4!FQASR?(^P)`Tu{$Y4ldyc247` z^irO))`=(Bu)FJ%q7|%K@B6R^XRJdoaow$y#JjN>(pqIHY6jZH7m|JBxVSIuy!6bo z&bcYAMHgby+;5JS9s)N3AQrx+gkFr;73Vq`2K(0Vp)qb$>BI5yc&5{pbA?VQnVTaaA-rEe`!(}BA|6VVDh(pTqu1Ud;HJF$5v+W9N?ru z&qLv^x_Od#?2C|d7fjN3Nio^MIr{=uCftGYt4oP&T$rB=9?d!@u>oMR^=)^(3Fpai za1f(!N7M0D2DujDA-l6XEC4&P?=)LW@|d@xu!KDZcE+l_ojHj#mF%TCXPvzS1dGaD ztG|aQ^Uetr?OL}nQn0mNA82RVTq0_q?Le?A^4o+c><@LBEE2~;6mTWYD+Zi%h3;By zuh_&Ng${27DV(5YRN?=#_a^XqRn^`9Gv3UBFi$FoS`~*nYpWJt?WKm$UNdldC38`R%)t&el5A=KM zIIRBT7WpVI&Ak8T-EMv=_wDX>PnfPmRQf7B$*pkRi7b~fXz1t7R}nC!!q z>0V6jPJ>jcdLcuhdIdNS3$isxf_70e?E&pBD*udFGa8uDz)sMBy3lIJZi6oMZG;z1 zHjQ`TCc-DgpnpAwjWG%W_-5JIz8`-OUz0`w7oxh z?t9*|m?va^%Ao6DP282odla`!Hp@UJJtDzq@~XuNCe6Du$Xvo^=KpctdG9^*gCBhV zmn^~1g-PbZc(Sa%&c_HE#F7xd@u=!CxkY9;t-_)s_w0_zCR2I-;H+7*cxQUshROf` zM0f9|i+zPUSq)A)U1Seqpu9g7K=E>gf!^uW2<~uh0TtC&{Tg z*=$n>n2fTmM4uiq)9LhIM}1o5gK8;LLckYW8{+$8qtN%XF0EwL;?ML>U0=C!;fKY9>G=zyJywjbjH%)9nz+IXW=>)2LE?F5hrNy_B9Y{P`$nflhs#okG_g}{buz1 z$J?`WNl(Hm|M;i|!-Z(RyzyuZm2=sNEm!WM?qRU(Qq4y`pUTs?Sc`s1#+A zXu5oqlG0#UWU%@Y3un}sy{L!3Oa1-bPCxsXbIy79`5*r9`RqR1eslKOs}8RJ;71>6 zw3{4w*x=Q9ZXCcx+Y-80`(!vBtTA$D0_h>cICp0e+9t5IS##fd#u=;Lbn(Tjc-1Le zXbbm7Je4<tw=0!)l*Q$-UVbg@=xapB%2XUkFKrX{ zv&%m4frl;gHZHVFi&zw2$rj6F=)3ljAd;~dhX@1y&{f=1CZb7Y7urtRe|34ZRrD{v z*J{^aMW1-Z?2*R%xnH)qFgGj9=FoCOHVK_910(*X*Fj-)-Uet7fA_mTaLD=Rzvqs@ z*vH0K@AO_pS-g~~! z0@&edzf?v=IhoVzsCa2H-tTj-n~WV_sqm^{DT7FQKRsBWt#CO~ibT6iPk_Qinfgaf zR^zhE8g*YYW<~=u8ko_*qtgIAmVd&_8&F&ERwts~g2pud3b(>j+@oVWz1$Bx@W2RI zwDq2?^$bR^^@L87K6MI)(;zug!v;R$=mvWG(jk42*~ljeKUk+w>#4f(_(ZTGCt>zS zCu&b^g==Mtu3PC3_~1N@jb6FIIcuXloiHb#DzQjVOzSCKirDb zPaPnWOg)93@`*o_$OUJe^PUg$>djx!8NWhwq&L@>NI9O+LC}wIxS27(P^&N37_2B$MM&%O*_|IWr z@@^(kFVjMXJta!m1W4&i;~<5(z-?*3L;aMj>~47-gR`5K+jjIa=Y%d~)4iyCp=HN1Nlb&ygsU3nS7HpwFFN+aX?q+ZECWlLho$6fZ= zW9>$^V2_#P(o_7&oqnb(!y*WYFBbRK$T)&S0osz!MEO%3u=gRd?qzjZ<&)}T!Iyd= z`HDaB;osW?9EwSG$86koe;F-aKHwf_M)ZXh=bUr4&J`MhF{St1b65Q)FE)OeMcO}v zEIZJ=Z!wICrx6G|fm3n(44c9#;dWohPrPtyGN~Uy`*Dtuok4+nH10EK16mD*%a3^_c6TXsWGI3e4;yhksYyJ)Q&+p@H>OM5QGz)eQ87&b@ zn1n+fU4=#d_*MPMZFmff1r*&5^J0dg9rD-ADbA`jnzB2Tciu z@iH}~xjSJ^TJZZ^BOA3d^l#L^6_^^(W@Kwq6j#*)h`SO5oG8s7<7(v#^ym;*QAR>!fu4bN___HWYZqcU0T z7UL;C(i*nuNw&iH*`K@#lg2cRIS*R3>P!}|s)mPe6&fK^VSB908uAfl^`+bKRrV^m zUC2GNps@=T=8Pya8u+i$fOW0vIA}oCII9EGWHH>=hjh&@-8tWHK;fG`@)6RcD-W z-jjw!hd-}RFd#9EuB$2?b%N31xgJaYuJbb9Y52s-X-IDMnBtnRrNfR#^}{e~I-8=_ z9QiB*9R^UfdEE{JpGx^jnO>ICLE@?Sqz?}ZouqOn&T%;A^kiud#vGqqdG33EcN~bJ z02ZS7+6&tV;A6j}Bk_cANn7#wO@1rGOuIM6R-An{?|U~sN)%^Yq`_d4N%`%GQ=Z>( z#~ru+I#{>c_9e?s!7uUFGMCeLEH=QR&6)eoe3GOgWiTZedgTcpZ=(3vd>z6kdL$GhN}QzT3@MZ}nC)34Dp3CK}#I zlWfY3&)H}HH*{pSk(GQnln&l_oHn-UM|O&Hx?(r<-M;~%wHmu04&e zqXTW_7k!gMG?Ux(sQ8q|e#d2(P46|RbIv*M6kaR&95?hc zy67qw?xnZM8o8ho%9Moxo;o&_Q->urylWI!XoV)6d#qh z(kWk|>y%I73bQ!HC%@&faubilPvvL%9H-%{b2#=SX2sd(9oZgfUe9KXeLB&QlD&*w~yyt62K%(13=F>pqovq3`6k zI+yCC;#4-fx|vzf*wssTM!p#hJRTbGp|FNrY4Bqf?X!3C-jSp@rLqnNV2@K9JO82i zeHwK=_B7tkH{k$-cOdc$w=hd-@@KpOQs3Jv@EaX4<5?sdG*wX z@2Eey)y_|aR&3Z5L(yI+{`7i=snDCpS*HZWgduFpN|;e7;uN4Tr57F1H8~APHtAuY z9Lly&KdW<|K=Y0E#E=eBghaz>2H){vM%vPrI&3 zXqQ=^RfLJnvSlj|$nwVjW;^}M_`DxPS-}nY6SJrp436S`D^nji{ ze~L=<%5o6>lt~Wz$qIg=X$c7H7mLGA&97&ib=J#S$i51i^VJ8aUIl%Z&*iS_UH4}x zpVtw`>3J<};#<-RObI3!J&$bV#RKc zyd@mA`Zn#PNLekvCs!`*1n6$+HKuNFR-AqAakTkYqqRle7biSPnbJu?Q+R;s7*jff zEw{%>9y8dHPJV@Jw+3%Ky_NGh-cQiLxWw|L3kx)(D8?45jGpoEvJoGF2)%`^X3-Zr zconJMdRM*C{wo$WURb5OGu^GRd{6Ces4i$oUMb5|U>IF)LKJL2UgeQqzIpepw@x}f z+7X<+yn7e*e4Q)R>$cGWhv70E8ajb8j9MUP%rlR=c}SHfI@JRO{S32oEE=lwUhhRh z0vRcbGk*%J(%RMBGYcBKT8YlcGoyk30u3-NwMJAOtT)hQr)K?y8dGa@HF!|x=RZ~% zYMUPiylWS%1pu5AZ|eYTFaS;q^G-nxzd_~VY139ch0`l5Utsr+#KV+U8GVrGc|E_x z_B`I{xPH>$WbrAdoONJTd`PgBMEOe`$}hjsmk#BZEq?a%FyZpJ#6PeaE${qP7V0RW zH{llo_#9fh)@Xm6f%YqPPKNUiUa}>N%Uso);YqlN9@3R?dcG2GiCwQoFlc)M2QpqV z)svfMlRiAjY;sDkNjBGo%U|G=KE#(fIETHS&S2%4ntb};CF#?2>*+LU=FEqIEx_!F zM_qd9*k!KDZ@LtZLhe!~(}#E$_!1V=oznTh(+44*PIOG)Nk%KrM8owqj1Wp$0{=W#g- zJxIr-8`OuFjTX8n|7|X4JmKIcFJU*&xp1pn9^;$pLBa$Rs~6(s^(5i6_=K;5#gZux zKf@R4R9?xAZr-bjU{yyu)9vTUxW26ZNY~*U~6Y(o52lu(1HXV)@FIdWB+AbJ9uY?7`&bSX&GWc@tLWlXwV}g}W|HC-N8V z3gN=SFYq}gVJ^e%)yjVV4gu=Tn>UyArgtmDgx&NaED28$mt+>b2s7HsCmxZ%Nat9! zn*h}hesU82D^{%7k8ibH!9BF67J-6p@b&uc_^oUb9ud!zv?$ESRjx2R`>yTzc7nv;x4&MF?`pLAg1$Zw0~wfw1MTq#{w@124cc{nFWJK}zk zjgC(GO3w0?=e`OBUk2^jHZfP3Cw}Fr$)tWHQy53@2d{2pe0E7_rE2^msl3wsfSq0{h-RcR9Se*RU@I#I54#sfbubPYq>rTjAs8oN|+&ImK3 zf&VHE(45k!#vnnR1Ff$4t)sAxO+ntV_#lLM<$1h}Si{RPxb2;o<5W1k0`VpGGA-fy zOES5f@|PW?$vi~g;!{4$n)0gyViLcI@4~+^#9zFa_vBg72s#iKHIK#}yd9IUdRT-j zsk;e}eB`!bNqj}mwykE_xPhh^?Y7&ZGkD5aJfU|=;u8bM7^DR(#W_X|HuZ!Bb zZJoD{zQkST&pKn>uD*6rn32vbLFF}<606cn4lAcB77KT}kw%2vT@5!(Mx%&>iD;Us z&~b4hue}z+R_5k`t@f-FQ|fV+4{QurBA48t;#U=}T@tm~xLXndGwktmV(;o&WcfgRjP-$5ej>N7C3|v%VzkPml((;)dp z*pjT1sB0U+?E@gNpwwZZL8EW=$ar`-fXvX(Y_4~^6CP;1aN+Jt*gF3P?P^gj=o|K^ zBPIt_!XNRnb%>?fE~_tm%2aKc%1m*_Tl`Jl6ePF)6t5`$^cn}&NF#4vz8Tdrn`l!T9q^ynASF-uqN?FfSy#j93Z*ZjgsYzO2=e^#o zSoYE^f?T`gVNw`=a~Y1nLI#1*fBK1r{2nGp^19PJ(i@Zev89SZ>TLI zd`xjlZZwqB@(Zuiv+$HgVOkI%@((#-^w6|OT;%t(PRns;cU*eur4xQpiCvP1uvg$J zJ)yT(gT%wKIv(dQR!%Q)C|tVtepq$FYH)$UWH00~k^{1c7j0CNR_ISp=gU=|V(_Y0 zRcXz>ZJ~l=KPbzVek%QI8K-z9a9Xx_TC42|tM_s~(zniJOUv@*=R9qY(~kQnodd+r zelYcgV(5uK;ZaAzAGmmRu)~>1gRfKWIE*6a%U<@fM?k|vq=d;8=EZ^%gQL_>DabGOMGnRj7(WW;F14X@ISzw#_{{5jDv1 zv@ybDE8H7vHNR?fYuVO^Mh4zpeJn8ZRDlN~@2ot^{>+7_fF;$@b{X)wx{A`Z7eF8l1Wg+XREGSVKYwMRxc%$)c{Q?$GjPV`AH zzvA_CJQ`%B@F0rKP|yZB`r?Fq=wTyYYZ-WDK*>*M3n(eiwE+}^5+g>Iki+>AuCBEr zAFl*xAT!1w^KJ&IKhcvXo+|uW=`?YxVpk^}^vouW*&?aQKqEinWDfHap7DmExcHjT zo=^1T6^)=<)sqiEb28Ria$8z1N)ta1GaYX3Y;FxrXg4ag{Q{44od^|W;JWc((K8cR z@oPe@CyV+*hlZG*UU*9UCR-(s;Sw*=D}JESfU#D8>oNwtiPM0^u7syjo#&qP zRjJ#?!{w8TWJFi@6m?=V6N@kPyS)>$Uhfb3-TV(3r=CpM2YDj=P2%rY-Bi5|OtPgi zCd(6Ukr#ai@=R3QALh)1y?k*@G9)7q@>HoEB? z3|=*zMqqM1d6;PF=`Z%-du`hKmSDRxZSGZ8{Ok`tFqDb=6K`1#mAXZOl+x30$Ca1I z4rB7fR|xzbFhU}hc*&Lyf`QzcprOe7Nj0v|IGuAdYW3!sc7LRNUan5Vg95wrQJC&W zEi`ee^{=QSYkIx>dM2aS;{F!-*Q*^CZoRPab6K_b-R|0cKf}rz~dz9@*jBp?w;K5_CG-VxP|-pK7A!dZH@5C zsD!A8G|M%s+nhW)0^-&PeT;sZ{K^!3NiVnf$`Sn4)`q*#t5K(1oC4|1;R_8}PFva> z_#~+&t)MyHc5hhPRN>@Ke%XOV)Fe0He?*`12kmD4)pyRl?Tsv#yaI{dO!yDA5T*Of zu_><+GI9mZL|=U%^+SDCU;0;HtDoy@aPb8?M#^Z1V1g;V20ii8f8uZ9_4-2ZYg{&3 zFDnZprgZ$Nj?&gl_yrif(uUqv(Kh^s>&X}t@>#iBkjkT^t$OOZ>OVxj+o-=kh0ooj z-zxcxKlnpe0`8a`f6&!p18w7BjV+^pB>hil`q@8omXdF-O*$||kQitp7!GquA$FSbTA1-rowLO@I+0!1aDw}cnbE+E24*zy=ro`Q6U~M?X*zow-RPp`wlsr2 zVtMhNzx@|17+t;m%#~Z{j@9*V$7kK?l9&C&T4C<8Zi4l?hK+XqxmLLR9`HWt;hiEb2KnK~= zPCMp1!@mXi_hlvcLM zBt453b&oIJXkc`wCoZqtd7aD#&C28Qh)ft8;2W6;)xD!hem9mfL6kt)-HI;DCbBTHo>3*9%{tvat#9MApw7yP#WBu*za;Wg9A zj5Oj}alveTJ9807IwmERzn< zCw|KM?rvvv+&k{n!4vpQ@`2jYZn%=(45r#mk&m!M-TE9Rd@QDZxZkY*@6{JxaCa5` z^5ti-lb~~2v))*2G8-A{Ye|Qg002M$Nkl<)THvYdLRZK zfUPk1vuMN4y52R-di@`@KA>chNro>FtLp#wqZfVfE)Pl9M*n~D>CwGyqHgpDVqLF^ zzW8V&-tTpP)bBNpxa_iz+*wJj#ejQHJ@u^b<*okTaSuHc3`KN-n-Iwn#`?x??+cXG z=UB8_1dcs$@6Bp#XLM8cg-9n`k3Z_%xHfSVi6DcdMpOROHky7c34xK$;t8x6i!ue$ zA7=TWZc@5~4m$Yd&^=P0*Vb+a(Jo|2w5<$Lz<&=TDW=?HhZi3q+)4)c>;XV9=PwLjykKV~`bt@9V`{>k!y67T3xw%chlb0|5K|8B`h6(&Lb<(^UBad!P7j{X(J~<`g zEi8&$ndo>Pu1sX;$m!m#o&hn{w<1Au6y=ae7k{p11%fA-jQ<#| zvp7)>E=i^ARo#eg)E7nI=b64O@=U z(`=sPi;S5LxO6`p)PCUf3xQB+sLI*@yQrdx^57&8n4?nBDgIzg}N7)5Ybkkyn)fhIP%EPA9v6}|L6Wjvvn4AQYhR&+jJ!PMLOxsCM;TfYBrxl z{eBgRKNDGG&ziOSzDz(4wgo-qtr)|Izv!bBM-nC@%&xQLmtJ(yq>C9!ddVf1+=F$` z;>C-5q#P_h&zhq^TJ#?Tx$U(3UuS8dp|W$|gJoq7Ic zmtFKPikPlJ9Dn5`VNgDk(+D_IZHr~u8J8?uC%qQ;SI|uNR^U-^ z=tuVnZO&dBHu99JVpJs?T#Od@rDJD2g7GC{ie=C^7hY){&w6EJ%iueuUp<)P^rkacom_E~dE6)l|;~9SV$uIc=gZyZHyuJzT)y59wp4vm( zWKH*?W3(!A$uGL#)PNNGj?R|shXcT-@Gzm-!lK{JDknah`Dq4@Kb+TS_%`aHdKiH@$oL4U_@l-tKbqY=>F4?2M;3viir!GJ?*nT&+$Z zXHow{c5KB(U7`(^@7u%d_)7BI(cgYXr&2zlyP#q8Q@r#|eg4b)?!BYj$u>+Fzxs~# z>({=IwBOKzR<$gu^x_^d8h1@G1J!p$d53K{$!oZU6ZvHbU)vpR ze78zxD)$XH+%QVr{_93Pdo4S9uBM!R!X|`)*FUQHkxgeeHB5g==L7Xxh!UQ{R=Rp^ z+MnN?H*XZV^XJ10T9tB#PC+x3jr`Iz{lQPSwi{omVjXtxw%fdaLcXu*Op&;6q8`Z~ zGKr@3FSY!Iv**u$`7oVfKP{S!*Ut(aqbdBtopd$K$8mTX`jv^~W20C7u3?@hEnogL znzGl&jz*Uw$p99UMVJzAAU-51VZMVoX}On#wK+*^f?pevrb zuem=sOCvjiyc5n7@4f4;Ti88wmCC8WRbWf{3CzNq>QHgdgkFj~2@myOpD|{kd4vZE zEd1BMa_Z^JFXvU1DaT2LusFbTpy_CcHV+xlo%HGbP~i6R(jdUU-cqHtv)uGj8-rie zE5j(gpbN#t&*G&Yg>%l(ym=j#o89Q?#W0=1A9)fj(J`8-{!ZB02H{=6p0J|s0&>lW zFr$GP4Lpt-p!4fkqYBTWF-{#=3|=hU!cu1!ZtHXiqd&0*xH?!+Lmd8SoN271p^izh z4Jhb@nat^l#DqpeL&ISFyn|IfU|7cywxvRIAHFlY<+*r>Ps)a^oolw{z*L9 z(d2aX#jF2$bnB-7#Wv@^N?R5^Uy{XW$gMxo)Svh#43KYhv-$xO0#1REhpe8zprHvN zVWL%pCEE4?C=u9(wPcl^oaJw{0d@sj6{lfOe54b08r-`n?@l=p2)0*Tdf~q@i1~sh z5TOI$PJr7xYG!QhURHZ;5?I5`QeJmCUBjNrvq+=5=Jh4za&qvOalIuyPVmG` zJSjFF{PP#`M>)uEw4opIsoqepwyoNyOuD)^N)WWf%jv=qDYJlO3vH$-^YeCC(x!(g$R-}oeY z$t{uv9>Ta|2X~hwg7v&{FbNaJgjFt4-7Punj_`V-4Y zJc}Ax_DVffuhMz6?s_rPaQ$j$h_&4&Te`1Q231_d5iniW^<~RWdvmK@{|jcTPqW3L zR4!0=tD|2aj3h) zlJey|Z64T_RizznEfApet9hl#UzD_dLwNOH@+q(*hfkXF=bd!Y8BYp2vh#j@pH`zW z+b1EF`Xt%oFX1j}XZ=>IBjDR*F24BUhiGF?)$S0cKQp)2{sg9uXN?v?pBvm`IY=lm4!Y-W-n)Yqgp=cqTdjk?e>D9V>pDV+W!_9 z;hySC;FS!hLWgD)ZGE%X5&?qDa?K6pBXB^ML2p;z0JT6$zoId-pt0T6awfx!24*xc ztN}gUvjG|nwGY%Zpu=q)nm4ZA!6=M|n4iaoof=?k=+&_M&uNkdztc@L=>*)bK`d#L zpE=c}9TI#=8vLA|8vc^D^NCJaJN4*P@9%X-f1gRuH-=>n|5aCAwVsV7bh!Py6y~_9 zn7!i(oW&&AbfAf1f8U@rkN=%{p-D{T0JBwr*`{ z=K&9HTt?a9Hf%;S={@m56fk=_=}3cF%}MxsgxwzOqR6-EKtNlJs_{C}klC_jmTHZ* zAGwZ2E9uAas{RChk8@15Is?dQ?UMObJ^ygG-~WeV!AJCkKk+f!{H}l3S8`|hi!`CD z!q%P#lUcaz=V=|U!thsk;B-AEo}y(>-TE1y=VO~}*581g^JN0zdYHA#aqm>?d=|qT zWs+!>GKgp8Cw;=07yD^B#v9V^WqF6NnhdE7tiC6HR(ET)Cv(*21Uq}i(;p6@UgVV5 zmf>*ubx0rO|As<;@C+PoBMXD?kPpFhZpJU!!8Pzs{zSARY;<$&`&91xZ6I3Fq0vNF zLECjEe~zr}9g;P84%@vt$EPBw)n{aI{bL*d@RwK$9avd!o$#w8(jE14k7cKw_WF}g zJ^jl}e0V(}e}=w7qWqG}$`O7pV}*~^k&>Tn8PD^-zw%0Zt)hU>djSWN>xDM?De8uB zi&o@!x5)%utyHru>c^ce8zybn3kJ#2>vX=#Wbi@nGej@?tb|>76MxBKJ2diquSO$# zPL&piS}YQd(68xH@=G7-XYq-i!f3em#(rLv&i1&6U*8+f%Xu0)9iydoBkEe%ro+Hy zTi_lrr8`WVwZ0W46WsSd_REVL7-j+x1p!@roUZFIcNk7B- zl3)7geXWBygX0-PWD2j&{n}j1kK%#OUt9l$%zn>#S%$v6e06_B`6`|6pR%m1-%NOv z&hjcfICL%!J2hU^Y&HJoq?1lNssJ#7W5I$2yYZ^f?BF%f*NJXw7Yh2p6Fk)ajT4aE zIYC*@_Og&G^drA?QoRp^G3m+gN7d6}K?54vJftm=UWP`qluO~J@1SY&I=`7$PIgXF z&QO`rz>EfVWeqT)@eWG8ln?Ygz};m78-7n$O{)&Ze@YWHuq_eFi!eErR(~|!N*sA< zyC;1jN*a6R#EQWfXfmq&`VU%Zf|_X3d2IOj$3OnFZ55pc+03;+r*y(n&^0>V@fe?= zn{1_JfU)OP^r6PA8jy*$xvkT3Uh?Z#c8d5>#B@zFYd)WI9p+j`pY-7RaJqq8dX}3B zZoilJ|7p7Pm5u}Ze#N0>W9pe5zta+*=$M12>8_R^a?(jBjn|8^Rdk`W=8vIi!lt*OQ9X?v}5bcn$TE24IfU{P6E;8-sl>90fAWrgEXcb|kOL{Ej zP=Gz~)1YoW`=Kvm5dQkkSoVTmXY>`kzkfVuMt%)2f6sxI;|6^!2-reX=s>g_x8GmF zYerUbDxO3Wo>@U%#3(O`Qyxo?KX?>22{ce-!mDrWUc%0WL!H^qxgK!90Z&0Qhu9z+ zUg8@+aWJ6IsJ6|Ej#7(cbBokKSV^YCKrr-Zs z?6&iOsju_{DxV*jW(u0)+x9|#loRc0lifW76GEg{?Y45A+LjE({fmgri{5q0DKD5B z<&MTKq{$+$DJ*nXVjK>aU)Ygl+6(90rF*#UO8V7$Eqe0HsH}7kVBPK^Q(u|iX)&5} ztwcja9AA~b(<7X6f&PBS9((Mfsi?BJ03@dqZBh6|*Y8oMP|!~4nS4t>8#~?3)vTVs zvD3(2K;?ZUD=x>-wtf{5Upn;A`2)Mtp1tSZ)U|EyvJS|A=Fs zele9C)wuPqdCewv8r@@IVqkQgcF1P;N#bSc8nqW!X$-qL^>!VH^d8;obZ<)MP#RXJ zCmt$G*JIeh%VYvXA(JIn+Cfb6>od5ReOm3tRkSZh%QKOoFQ3Owtyv|nxQDDhC2SHs zgqJ&&XRSU^CKJ)$(J;mwe8tY?a_&*L6c!le_MgEMO8oTkc1}sbJJAU}ma>wfh!ahI zM#FTh=LdF?Rj5sqIn9;yvp#fT6@1P)VGgq~(jFNEc>6(lU3~;NF zwU*Z-i*QS%I8SbAG|_gi5mL`%`4tv1a`|6v+;(`UscYG|8$lbv35!N@P|%hP^&V!a zGiVy{RXjOawQ9|_Uq8(Hf6Y|mEJ%r{A4Vs-{A5h#@VE~i7O>D$OmYRD4z{zjmK=9r zO<97h>mYoS(5nRVRJ!rNL+fAE=_mFw5r_s2rLS~yz=DX{8 z&z+~Zbp{%~Q^IsT096R|#R};@-=9hHArM|0#5oC*XEUU}uXod>gKZ2?N73k4&q8e}Z&LXfdYd=y52 z?E>Lt-8F005HLN{9o@91Hf!$feAe|hVlm1NGgS6O-nCPBZ4k)Bb|K%j(UbZ+f)jxK z^{*(%M8nEA5{W2v$m*2E3pY>g`q{7e8p7MJy!>Og6iMCjpQ~0KdE>3O9>$phmyH_~ z>5UV+FNGC71YJ8@RQFl%GEDI09@ZypStzkl>JTr`^&dpLsMu0q{ch@ch%#lTZCKmZ(KRTpg#OwA;*a6Lis2xoE)6IXX_lD2ZOkiET3>3CK@{YLST#Zoa;uE%4uZ zV9!PW=#k|WL@zeHP7+#*BdvCq{`m2?;<=N0wVWjUX^maNH?#fZKfYWsQ7g}VI=R!6?N?3B|kWRdZP zPkiDN4@CY)Z*PEA+c2rDOf;1P{7Wq6!tdo`Ma7!Uba_)_*_r^os@z2-3t>H8_mJuW zi~WyGhdwlWjyB;nsNgK>5&@P#w;ADCZPCcWg}Xz0(gz?M3M#D|L2t)|#C5=u$RI2W z77vaK=SN5NYo4PozVgbC4WIw<1Nz*X`1(i_dw5K72yz@0?Z2@~YKfW^wlN0+{{MT$ z@S)Iy$Oe2j^Z8H~9M`&flMLp8mbJ5<-1xv-=aTSxsdlqWX|#CDs~+#1HEYhlqJ^2*D{?}F>F zn_;$YFcCE}iIyy6PVz<|eGqFrv?9X6`BN7D7+hd8hdTfSfU8CvTu+uUv$!9+_#eBJ|} zaND@(=sg2IPiGTB2j=`O&Ms*%34O!Bz}*L=hZDO-DW)`Z8h7ypg!`GOaZ)_pR;BMW zddi)!JAL>ufnfkSxcWZCg{L}nxIPd|qS}N|eU=;3Vt5QQPi}bc()+O@Vgd)B1JmmY z&*JrqBr85J3TEmh<${oxWjZ-~UA^1;rA18h!efsOydT_U%52zekS;wVgYgm%{-ihY z&_o>>4kY;Bf<>#fnenaf1R$=+Tht*Df}YfpoED&0N_e{SpPY3vyqFQBYZEPID3aX> z`RqCKIc{EqGwHzpe4qiJl94ktVYpbt;ZRt^Z`(!(R4!e13X`?^Z&;m6LdcRavgUFf z$tm6GzM$lujrZ>?nhOI{9~-I;Dx-dhkaQJB181v41SuV#71d(Z`>(p{id!O0)n2tq zXARt34JzFX1O472$e5-my9Z#Nu*5`#0O}jMWbvgWQo5KB+|Gf9#JdbpH;NSCl}M6b zwn|0+(j9f@iL?cm*Bb35C!KWa7kRe#B^EaRqsY6xjz<0zXf`^$CQ%xg$%w!14YNH! zPgwi)-dz^I9T(bxM^vvQgO#m_VN zRjbC;7qtIW)nzS|$^Hv|r~EvkdOp71d9>)VxndrUpger~z}V=?iEKvel? zCqy#Aw5_^Q)u}3j)d%rH4ylp`LKsH+-E7K!m-eZ{ z!6GGI^-+uF^P;y=a?x$p2w*#$J2 zhl{XYy>dok=EfFn#8eT%S6-E0H0lwpGE_?8RdQi$H0Q9w_wi-Rmfd;96;~8v1Z8Q= zZnU^Jo9PT25-Zd#u`&Yki6rdm#K zMK$16^QtgwWUWzkFy{AYYkd8pMf|2p$Wf~%)vn|F^WU&UDIChBgy{~-2uM~(B zSTqDEIuRo;T#1iaf`Ab`fv^ro?&+BgWW1M$IxJ`yr$pTKkW^z~;%U+n$YRBm11muA zH2|`uj^4XD4X6_+Bb?MHom)i4$K1AU___?Qn$!-_;9N%KrGKAzdj1HLFAWkFFnfL5 z2}_rbG6(vzVlI0C=wQQATXFeD(qp|S|e zr3*+@7rbgEox@8X1ZJ}HxuKmIPIMYq@e*L0FyWMLY%+swaTOX?rjn0WDfZs`R-u}< z;T(o<<;~_&r|FcGxk|+1Qj}ov;2I3s;8_aHpmH0uCmo4^epXbjd&yw2go}z91z=sxHjpgc}d znW+7eA5+x-Bp2KWg(i!0GCa|KHlH+ncGhp4%+tKDQwOhO(PqtLi&vIu{6%|D4sGbD zk3tN0nBJsEIWV&1vd=BnYOi|NyO!-n$k2qWI$o}dZYyR7>3wmN7D6UXqFI!e@sSR! zP9J*02`6X_r=^HTZ5o_AS>t<=+}lZ(g1OPQ$r~=$vX@9O_4Xqbj7i|>6fd1rO;VTf zuyB>1Dbv%6ij^%6x%phGzIt%oRaaepOO=k?b^u_%wpVVYhbkxncWuANBK zsbA*V=yvbk;i>a|jlL#>qRT~ejft_ci}}rkD%qVv*Ld*Q*l4k!(b&?zr#C0Ri-QiI zp~Wi^Dau>|L%^_Om-2YHf29GPu#=0AP^@Hu_k^VI4-NXUSdRtx1Yvrbe)UJQVwi-9=R$6Q8RYth2s*=cxi3xBuOgy#0iW5p7 z;QX9vpKB33Su8tLt68xy7jl&MzVmbD=#B|373?=pJaOsUNi(gv9Ce>_LHbYYv!5l3 zLHxZxE6Z9XY~k8nm1TQ(S}nc)dA|j2h!%$)$>6va9`fI7Pv#jpcQ&eLB6`2l+(to9xhDCo8;kJKW>=t$b8Y>WJVb ze-bUFE=ZaV$gH*5$HXA}BHkM_hPvOq4wbANVZvzWaoZhIXOXyFEadXQti|GPOZ}oA z3W$*ODA`0KjL}nl3SQXssS&+P+S9rTc1g)+gqqR7j0Sd|2Kww*r8Tk1MD+TpF}BV~ zt*f=R(dg0&TZ^kn8I3%7qI2^e#}XU9(&Y`egZ9uw!h*ERpwq2SxaBU&1!5)*9MoA>O_Z9#*zxcL4mP{G zNr5Z8T5gt3Wm(CtFg^6uV#om9R0U8n|A}#8nzpMRRK?JEcve53zZGQKxh#U!Sa*jQ z#r9dqLW_govu}=1z3mY6leK4M>@2ZK5E)9WhCw7uS1^)10MJe$28b06Y@3f#u>Is0 zcC0(^rE4N2f<{EDkt5k6?K*dU=z+ze(%6$l;Z!Drp^O;ZLC@eR+GCi<+9wacz4tzQ zPy5`5l+`SKR|UbT_SzXFs_^9BoW_KU)l-jCxavM>i-B5|9MIQhn3p6|;zY;?2N$Gk4p!PguI_`YjtD`G0S`@y1CPKaDmQ zUKQZI=l($&=f*wlaUlo1C0CdPuF-6spnr+!@SOE5+YNr2OeNjo6}vS zGm_*EqVV<7bQ(H9kwsU1e)PPQalqo%UQloL=PHx7W z>FWjqOe!AetffupA|v%e{1h4BQ{9vw9hCL5HosmU(LJhj9%`3=>hcFqIC0tcSzLRD zpUVr{mlDb@ ztEmm$?F-uM&(LABRbxmKk0>i^pV_6bwb8G>dRWb7Zh9+yU)J>D5(8J26XPVkrn(-wrqqvmyDDDjLQ#&G?yY=W+d*tZAH_*NqZ&#?} z^_E8M7!L~|@AQq2)mLX(%7*%_-{bY1tfAL)rnR6UwrSD$BkZ8~%g$KmLzpo) zzibk&MADaGkSAfOK(f$?uVD2c7T}SAvE!>p=FB;Qw8cU^8^pS;wi-y)HEG5rGG10Z z&d;?Ww+yLF2l;IG@BAxz--{=1ML%Mw5}p_%7iDbhK`0%uM%Hd~?0hmUPQswG^#=#4 zkYu)eme>`TBre-h24tqURDXlku4bz6l^?LBwJPI^!$N@6WfOl1_`Af0u{N@!Rs zdE_)*D$*v2MlpgFI+jbkWtluCVK{;(|>>mSiiRL z?YzvHGe??dx3}xnv!{Aj)N6$%@DhU@;IBwCJ*H$^&w}7u2C4g5X4Ah2ru@cF9+ia$ z3K#O}>2G1|&JpU!SWNhpMD#*QxQqKybBF$qsl(+>RZyIsBg({Jt2_%ziBF*tZJpPE z9J)oCK_1$^ykyCVU*y^;bS`uaAC(BH#Q{nZ3FMM$yYH>q)gOn~%tgKu|v~gYsXUOE-q`E(&97Hp@4R@uI8GmE>VA}ex z#M3t1)*F~gaIj*-zEm=h(b_POOG!mtmtWc&Y|H4ZzCaWD$EF&~CrXl9fRk0|P1zMU zYzWi+uT4(ytjcj3&e>)t!4)PO{ zpLYE5OK)Ocz8v=(*;zE-7GwoaKQrNhc~J)hBpJgLSn;3-)xT!mXfnHBdgSMi{EM64 zdb1jN#tD7SkZSa`aA|sqGAmf%u=)`6l*`*KJ{__^zQ@Gm*>1YWqU?-^;RrmzwE$}6 zNZ+-w*mg(~om$E}HTH^U(M~I?^kym(J<%|w6)N_$mO!a@Ni(ycu}c=~j8HQgcziWr zTiNvTs0}Jj5Jo!>*C9BEP8lGg|GrBc@>(;Gn?|<;Y!*;l}ecIFRt8eQa zPtfVrhw&J};`kKjdegu=O{zU$npY;6UGKEi;X+rPDT8Z~g@36RIwVCgCDKC7)YSWI zp(L&8HsOm5L05z$%5dj-`+ck4*Q~ALHSQ@4?@Z65qf^(PQaQ>rZW2=~$mlpDl@ePR zxRfJ|%k0!*tS1dvD(Z%fEl5<<2a8L(!X1?CUC%t$0uWu-F9er*`&GzJ(ZbFW>X34Nu>OG!D2Gg>CFCIt2TBrABx~fwvAP-T$SGM zE9I@`clU6)czRt~Xz2RA#*^*mqUYW~<$rAMJ*5 z;1b7HNXJs4@1P=Ys`OSLCC4Uk%!_VD49EZ`}MH79n1$$(`pTe<&DQK{hE!EKN66 zIz^p{Hjzkn2R*&sY+Z@QPdx6pr623{w%jz;f`I64-MY0=Z?>5yNv7be8X%dxOqEVJ zWfX4mZ>#UJ)P8B?-TPyAozW2yOz<$bdpw-;8PU&kvXPNj6Yw_{IKc(nOK9g0?UUZ> z7!(VfRyd^$7T?#Qo%#3Tkk$!ET9CCk=tFY4?x8BTV!4Qx?1-b6@N*dY`5i`JJ1^85 z`%;hBW6_u9HA2w+qyA3(jeEh<063z=&Eu88llpzvKpmS8+RPKKaQjzf0afKJK`8y_6F!PKNsbL)p$z-7nh)@l3d3DCym}+~zY}Tv8MZ z5R&ty3%;`V%Sijpl!4EUbN-3%0Cf5(LSkCEK_HPZ{i>Z(Uy8k3O1e`mUX7c}y|tGf z1gU(*$*}|qm)o&b;`9bgmaXOfEXQ%IXyh&FjVPn#G@PEpHg}TI+ga5i?H=`hbf*gU z--y`Eg2sQN!kB?Fqk;clYk+oD4JlU>!>=w;wfj)Rsuo=q4Kl|DjCFi)G5yJ(Q!TG+ z)|BqaTrpS^e}h2pVZ##vO#?~8%td(ZeMjtRkS`CYakt+|Bsid_zNl$P^5^cJxjN9X#I+x4Czu{?}J5_P8M zLuL5(x!C&8T$pt?6CB>g-Z50`x0g#|YrL&!CuDZR4VOK9+;JzoFVE^XlEAk3M?x=t z(RcY=u1Z-X^(&oC3_OFS7Y0ssF;bkf@gfxXnca8a^T@?Zmb~YNYpxl1x;i#CkGWxw zSH9o?je<<#YqX#g;bF%UVb_3P#n8AGUcZkdL+HizCxS}tWg}WPa8;y5M0$?8&+Hyi z;+cA&`ru?%BaXBYWBJupUUocdaECK zWbOGAEix%x7#_neWPM_`DzDgt9>vSc%x$H2{<>eln$>n_fs=aP%WBP@PF(hTDj{(Z z;U9VkJ87$4(@vVg+<4JNn~y!=g!gfq{v|2xv)o2PG9>Iu9P|nn`1rHT4u37s~P z_SzCYo`gS#eUsO=n{$q2B6;4m*IxDSo@o5F*Bhy~8<{?xko4peca^KV0)g@x0!ybR zXgsw^L+*z9FL^2Qz*r25lqNeK+0k@a+nU#BHEPZG9CzGt|Hf+^<968{cftvO$SWl0 z+QF0LR$CMOlV}^gB!i(QfX@bJoGtxD#ZP5;%HPvLRJPg9MYiOsWAYa5nwVg$eW14j z|D?M_J>|q#^0N^WV*2;WDysG;sWg5OUm1^f#)&;~B}j#t9xS1u6u_F;3dwVQ?!k|mo>f%+RA}asB9lgB$5KOiG*8H0IdphK2Fno6V7Z zb?!;L+9f8Ew`#&4w#tW6|MlqTp~Y*3$fV}SU+pBnHJRy5REnT+BC7nj?g9tQ8wLEsRYsZG4jQ(_fFH7No8C%1 zPcazX(e)V}<#)}v_xM&mjyKQZ@u-_ zYTXc22TMZNt+I%QvN?`I|MKfE&o^#sVpM<|a`1UQk?84?m>729FZsB;)V-B=F`gJA zIjMJal%q3D3{6zbVZ7u?au`qN?POB;z*!I~dDBJMgKErYKPhc=IcNSneG% zHrz_Yjh}e=Pv}homoB*-Po`k z*f>*1+te9MH(Jd%werS4uz>QrgYvI~mp?@mU#Ja~g#d+|vgNl_MR>ZWEGpuar;1Z) zO1ep16}n!PNJ2{a4o4dtI}B+q}|Z#b#Eg2cdotm6YrhQJ)3v>e5ENX7JMP1e>2s#M>u3;$;}-) z=~+vbaFPoX6I4^mRnWuXvbv63b}{rh1abPB)PTA6>Z`xX*Ox9;3PWeuJc;~9PZ~1X zPFD%#*Tlr^#Mc;Eo|KPp7GG?l$R~bZ%hrLvXY&7+0RTfD=acv;F7cJ^?vi$-MHRD# z$V}?J=9;V5vhZ+|eRdm?eouON1-;;7Wk(vxK=pVDqlB*=bIg*{c)jF#{GPOU@sejB zd;F5iIrHT@@-FaxH*l8aMtV8n-)~_S3=}cB=a!rZ5ctL|b7pJR`gN z=9^a)3mPl{Y2mA(g*IV#Q_Y|97Bop?@-vW0sdrUtW{1YETCy{8&1m3p)IcN8_$nt2 zH4U}~Th)bNh1*IqjjHU_PU9x6o|IOntdAjP8vo*z6Ll4K02g-P3tW1{BK(p?gV*VP zdXt1q4Efo6v~ZxqF?k6WZ4ILfry zChGO|5AR>3^0ecxylvXyEmR&_Kv8tKh_*O7VL6~l7@XXlZ1ZqYry5Ve?Mbe1dIn2k z2Xx}ngBHVQv`V~6WXXe$=mUU3>Rb*z9HlQGqm7-YM4q*`(Gr$#}^>k_KW@-beOF-Q@&EqlwBdV9{i{)qU+6DwC3IfX$M zI9%6G&D>e`zyNJcWR$p42Cm;qD#c@ro?bSt$DDJ{lB=54z+OIc;vxQV}# zENRr<%h!cCbhvgNuR%3@rvZdS%;+ZK<}qqk*Q_59vsCv~9|!B8usAlA3s154pl)CJ zj$@Dg&(BAVFz zPf@?-(n+qQJ8Zv?X+y!U7@9N5_N;oVajD)=K(4i{OYFrf3x8Sk&{-;Wa4EOwJ!}|!v9;OCuIhkMa#N;k z>Bj=(Q5utT;gL(1&cFG}D|fgrbZUdwv3~!+cB3_)d(f*4f_d#$I?3YzOs5?^o?+?m~@+V)&7e#EONarBTNc~1(TQ90~#AyH&@zaIKGhZ_M>DnTq z{MJ{=4UrgRI=wVWwndZ4IcON8!G$LAGNPd@sSk9FiN3h#^$6ZgZP#kIR=*KB8G|j* zR9%-+zC;V7J}6s?ZFQjHW?M7)*}fCAPRFgAJs% zlP5cS=aO}vCM&UUB@#&tbC~2dyNqzs*7JLYS(zRaE@6^MmOJE0Didf1JiN+N-=RsK z5ocY3!w3`Bf|Eu0;*&2zd7%i5c(PeM8(+pwue@sVarohfpK-_`hyD<~ypMw;4$#Cw zcW}@S8CB-eo!LICbVWH!BkKATe{+#mw!Zjdp8|Yxz196Ayca8M(V`w-2+X$R>^)cc z%aF6k<6)u&8}Y7)?$m{+5?91)IGz?R6lQtdVR9KE$0d$V+cO(n5hWK#_Hdu?OyjZy zMb#tyq$6*CN=%j}3E65<_9-ffW6}DW0_CAMpthjy4d`nF3tt-`c_-+<+sm?Vuy^{W zJXPJH-9eCUL61?o=sw8y{)4q^$m)Y=7Qp547BnXOQQ4qQI@KByCwY}x#>-D- z$AVp}wQswhA4BlD7CC&;R(1=6lIWPn3)N-RVwcl2fX2`2;V`91{d#TWo$oyE9Nzi* z48&#$ujH}%1;5Z;g5ffGXwW2SeJ|nhLqG*GVN{Aj{?x}CeT(428(LZS&o^(_@V5%t zwqf;zzSLz8xs?lD8(S{2Wz0qvW~?k}?9hX7)-!nB(Ayc6rF0^)g-FIn`f@B5ucB9Y z)u0a7V#x7!K1iSP&SQ`L1wF!tK+P*8 z4$vSNIFJWCIiuR)PGA1sztNbZ^Dk^c1I$0;%Sfb)Ob%Z3TyFf~Rupc@NnM;fZ_Adw z2-&F%8XQe@Sd3eQA>JSG~jm1i9&XB~)IY-i&ZU1{#)L9Nun!*cx;~_zP_)y`c4n{pn@PxhwEo{`7f}(9N)S%A? zvZCRs!ye9SX@@%U;WXi=BYlK{k@h?cV2E-FTj@h@-U)lzncMW_ovJ!!>oZeNtwC4F ztKpQqf-h#K3T#WCu6QxfV2;A}^VwTAZ}w=90E4#w$K*UeMqx z7x~y&uU~Jw{zK=gAx4g%}VJOMa>4hiu@s+Q_Io$yn&jbUPy+_c=hZ{A`6$vgOt-3I2+7Yvia z_;X2s+=4%!pqmbZHSE;jckMCnIOZGOT9+j@=cDXAo5lQ5O4WZS0-4hjQh%+rk z0MWL^Jaio204lR@?3ZYmRN<%Z26><-CCXjx0T zc6X>hE9-giks{US>%(D{4AXLc>QmQ#;poMS4{SEu7g3GVJsfR?>c8-YoFZ9u>kJG@ zLue5^e2;q>Xjh$^Jbf{z^B=8N)$T`QU+@%N5E%JVUuyFR?b5kTx$7)} z8fVdGJi^wWqMdR0Nd~OsD)Ol;6eeBhI#99zO>{HiWcj@BA$Lz-Loj*0%it>X|#jR#|SXQcUD;ZXmW&i*{07*naRO@v2 zA>~g6i({pJSg*B*bg3986*5-HrUi|Bch>a|B-x!xyR!`K#&c1&jSWkh(a)D5RXiFc z@rCHk9Ate*nL_yUCVRx1Y)zBfqT(KPUp2KBOZ?%S?JCq~!FOS^-Hp*Mtcw}ZW;8IP zfgRL9kB=NQb9)aO3T3mZ_Ew!w8R8v^*!ZMC1A@v(T@jCwVGzn|@*4bTAmEdkl9eMI z#EGvOP$r(#1!>+xmu$*7QRcxg4VD-fPC2+XyuxfWCuLnkSh{JZW&E{PM`nYHfn^L7 zG(@W6bbmG8zEHyqhK^ciZd>BSl85emMl#Dc`=FzsB?nJt>zqCw^t4r+F>zk!sjarQ zq_hN3I%8Zu%iyzEjNp*dCW9HBJqgDcNCy3|3pJQSm{UghiVr2p-n zuuLTNyqkcGTHN_w;aqzmO@Etc!BWOA9 zR41rS`tuSF4#GGU%1BqWum8;T8n7-o`sic6$h+!i!0puxW(Nj}&c|gedCKpYs`Q3K z^h6BIPrmK8+n!9i+g|dLmvnEx{VshZ%UmH}8Rl~G`ie~s7?Ad<ROv8UJN$m$@7W&NnC&Z^|zCG=~3@|=bv@^*;%|U_gcM%GSw@ICNeCo(8Rf9T?J)s zRT$zAT(oGP-yq<7!wKwR1X#nUCYN;O^1Ib#5-P7~6jo@* zGV0D|QHaloR+kjRHZL&H@=wEJ7AJ5I~2^>9xOoAo}~r0vTTFY zFp3CA_Y@EJ#r0zkE@@loRkM%|uU!fi4aDy%o<}{<+f@`X zBgc#eW;C$l8sNE}O^62vU;fm<=VxkB-5*?RfJIBcdEiLHh~4=%tZ37H2ZgXq)RkyZ zQg#yM(~{|;VHLck!I=-xqVsUsp$r-CY#3-HK7_qIL5a58tY5!An>A;Cmu)i8a@?XnsC$)%NK-!iX`0TH%kAb> z@7JHB!DPth1cK*)D&e1EbDf{jy0^+K%X_o*o!@eRqu9vry0H*~q8@qv9Y1QM&ZB*b zTaWiEe8n^HI|l&|TpEnqp))CJd#q1?`ue|Hym;{~oMifX#&&1I_hlR`S=TmnVW__H z;|N0j;1YU>vMg;N&*v%r(@A-oc4-`a^y2$fzGb-#$wb1a4=NWeu#9y&=ks}#Z&7PD zHnWxv7fb+*FLRgLMm_-wNe@?Or_t#2H`h1MXR7V{o%7o4Ua$V}oH?5|{_JN1g|qkG zd+U?H+h55-{0VH{W9R66UzGMTD$B1dS8v0MdINCoz}Cn}rUim&PZlR&ze7RjZw&rj z-o0m0IF*ZGQkeuvwGkGx}mG8?c}xS$TpT~_i{IW z>Qi5T!ICB4e&*KB>*ySoqw!Zzr`TPn#Wt^}qU^lkm*jPBA!k`m9v*cxU&zAPlL#AF z(9m`bJCYbXc*u5YA(JS@eWLq;+MQA;W_!(zH{S5cqmDZ2m-R;T3dB1Ey$D9)@`-xTGLQD8`YFj`jGKHsHzk0 z^9JRu%CX&s&x7BmWd-Sh(kk++6o&6V>0a$8M;BesiPblgd@~L3nATGwBW*G(pACK8 zi#M!dC!F5$8SS!=v}seN>~!<4U0WNSHEZLR!ybIFz9xuZvomg7UtEdasZQFob#Fgv z@hy#3eetj!q-U9`E<8-T*Lc#==ohbvH-K^9*!_1vK_h9;?Cu%dIu((k%C8oGEj!~IMJ(G++KCb;pI`KSl)fpPTPUAX? zaJOAQa#!j5t5Xd=3AHPmnFWnqxpZe_o6*4Iqyai(j;b#Qc;2Xb$E*Q?Ots^1f0^DA zJk}S+IMzuF;jw|Q_b2vLLSu;-#OOe>?J*2TYzytM%s%nfAjGK!eS=c=JL6d0w`57P zwzX3Xkc8hms!E3l5ua<910S9gjiWVD0E4~`o#MT8{48jA9$A4?c{FHcsAxJ7Z#v~R zpZWYZ28g#$MDx*yt(k&^*BN20)~CQ;hQ**zgYFnaOhI;%sKX9BEdTj0Zs&=*1_UKd z(~Xm$Z`Al^^f?cPI57pC9K zd9aJmLE+Fq-}4y0q7DWx8))gF^Q2F+g7#!KXKHdrU->j_e0g{svTd)XC&x4yz3GJe zY4)`*vas=Yd@bS~@H`$tUo3gcfurhjS$D%-+CDLpUWD1hYkVrQUOc5^5$zsI-yoHA zEB7BUu4<)`T&CdrKXb!%Uzv^^|9#TL4!e-Y@0-w->&N4we1%t$b3zIxC^mtqJ>t=fm zqv&t!wX`Ip#kj$;4caAr3xTOmsCT?=6`dPzyzy_}_O`dZw$W&Rs@ZD(_TU7~+YIL% z_onQ)XVHK}l$<82bm8}(8Z!=C{UPI$3vasV)1MKq?KWzQ(~eH%_4@B^$zXX$97wG& z49s@3W6|L*dtK3JNNT4uD6i_Sp`om_a9bPw%>UQkcYw=PUFXi3nOoG6Fp>}*<6v6> zL$HlWoFKXZQ&bV6I(f14Z1WQPrSg&&C$2B;i^)rzXUE_|7l@(?h$1k}My3c+i~tz{ z5(xDx-7+)hy#HTouQO-n&b^v@B_WX3mhPN=c3I`$>+F8^`O%MdYCW^lM)CtjKr^7J zdM?chEcj2cP#dUDbeQeo`9kA~$3LAk?CII`cH59)FW`B>L_)9=P~mfH&k%X2t+Pyd zN4vsv6Xia|FQ#B3p=J_UQw;pK6i1(EDdaz(6OzoY%+!WdHumepmKjT(@rU_&-aUYy zUQX*D?G~yIOhVhY{Mjtzr!={dXHRx%M|n?H(sgqL9D!Yn09z9sY%3pW7*LN|<;+mV z%RR2<-;u%QKsCZFxqQ2ujTajPl~HBlimu3nieDQ{>l`Qf5hF&(=fJkdk6R0|a{=eZ zv7yyQB+EnjDt*O8(_vMn&mItWB|t(fzNnl^my%R5Bqw&}Q#^OL90!F{ckUg? z*}+F46m2MD$|Z{6nKWI(J)R{Dnm&NZf&srSfv;STr)^cA{b1XvT^SzX8G}8D%~f&( z+8tn6@X$~U$gjsD`eb3Kj>;p9etK<-aejtP z{OL2p@-+<8bPNf0A@mLOY=Qy$F)_XZH1Rs3*&7Lj=S#{^v1B~|R4!w}I*=>$eDwlz zYDvglM$HA z`ni@{t=&{OHVnQ2l zEYXg2_9W%|?cT1?37cPQ7v~sfG?gChh5FUjM@C~$z3y-aW={pi^>PFpfdL@E)r>;5 z;g_7Kz&TWBJ+52o)UWq!i*YXigf8n@6v;`j3Uaon=Z@tHMF*`$Gt1_`h! zuE??dHW>|nW!9`qp5p?mb{Z&mtxG!q3d3heK~{P3N6 zJVuGB>)n=-N^TGPsU7>0uIp z@A_lSkaH=4ZpFaI_w-wsUUnnHepM%E;du{{{ zh{0{$<}whavQaMdKGSD1ic2fwsE9K!a-$44&2MyS>kS;di0EX}%$c7%=*AnbS!KN5 z>sRPTouPWw2Cd#U*@*z1Kw`g_VV2$XgPrb8)saSLXI=4%(S~AF#9^b_c{kbgs^vpJ zpIbT&M>~*<$8FiNg}XEc^qLH+laJ`(npN7MDzrIx5}TH~A3?A)@*`e*DMopM~?X@d*1uwK|2jM_A(Hp-|w8|wEfdrVJpJqpuyJp+A zt?4T#On~R~Zdg3qfY$nFp-NGGR*6o^l z&->jijnJM4qif^{I081qtd%O75>%ktP=v;*;l0ivzZ>X*eG3~%{-dL8(!pa$kWD*$ zde2ojgy->n^QI<#@kIpe9;m)@LOg_Cplv+TE8-;$Ug79Ve+=R|3&W`&m63V+qGxHK z9*T?yHPE})b8B`l*CCO_UBI<)n{ zdOkRS5UcDNS^M&5bO4tK`D%tfGv$knajw_ks$QRg-p`(W z&DtA(`qOWeddgGKsg;#+;?d``804{duF}DuZa3bxZQIKze|cq~A+D)Dia9ZW+ZR(# zvj!^r?o7{J+YR+=U_Uf)No%_IR40JmO&vHP3qhXmuY3`o>P5LZFhuzthyw2Q>c#eC zhwUEC{Ecx6&nmGoeDwKU2^*?=4}N=`8pmHh|N0F#T=&y|#z&UV!+>X%4OA#kuQJJo zWienu*E!&U5trg*&p|I8t*kS&up45B#t>Y=#uVD`V{!(EX@fs`G~mODQq*_%#+AZh z*l2keub6=Sa1xh4j@sws7hint((AAN$=9#D?#FlUl*x>MPl^F#5?pW-3Ugi9|K{)zjlW zY4Z8TbjZbF*JMg>pdOrq(~>JEe}P7|&FmxPY4w9$gKQ=vCr#0s-m`GwLL9nY@9-6Q z)5YvCU_|-FK0~}=Wc=$X?P>QrR2l7QV7NYxfFm$C1o(a+JM!9D)GG&pHTR+Nl@1~N z8pjIw-ErWD-G4zgyK(@=4r=CJ24z+GqVDeQrW);H@gSa#nH~x%gWx(0s{Elp<1`*` zFE@4*CQQJl1V|U;3+aQriXj^-jkhZr!z6AU-Zi`_xy#+%PnXI#hXF+)bVMejl_|rj zyzEGgDHdD)qOsJwCKMYIIN+C0?@~@{)KhFiISL+%D^_V(wpha10f$32NkjfpUZ8I_ zlZKfMA?-juXL!K{7axy-{ba6Cie4EyEN|nT)r;yN>W-_gz8a_1*E*Scsh2lPGx&{m zkUt-laRS~BII~UCla3j#ic!^;SZ0=v&j(iH8rmq%#b`%od50!DZoc{Y#o+%v;YnG* z&v+}&K`w@ecw#Io@JW*5ijML|V(aP%IjjQl!owxAH%7&#&m)0$T_rtWwsB&CxOJxwbGP2dl zNx3C0vCkaL*(57TcK6*s-HO*Fmdh?TVox5Ka?RQoc`;rFzH$5qQ>R{d^gwv+NLrZ5 zLD+RL7VNJYxBrCeFSy`>kL(D&Y~CnpITia3j^<9q8tm(Bk+xx&GmblSI6am&Y z=AYe5Cxw+Q{#awPqSY|@Mm$r$D^5FXBy7Em82(ik! z0*&ViP)y}E+QwJpOm)(Z6c*$!n>Ou&DWcF$`k6lc(u1c@pLsS1wDly5T}8gjk?uZ_ zMmk_1@*x9pVR%(;>A39JU<xMy!xXZ42B{j(twb?iAtrB@#c3^5P*Uu=%QOS$Q@LXC0kSF6ftR zT_iTWor%L@_vOHWx)TfjnP2z?{u&qXiOY{! zlFzmpk1SvM>0p;{Rw~`A<>p=biE*}aJr4Dzmao{#*sT$Z- zZF$h{fIrZWK9J8R|AIOJ2jlKMH*MO?N!W$S*IDXZWej%ah;0<2!t^96+&g2&jQEqZ9p6H`sta78S!GA%vo=T1#|5?6#c_dqr>qwzf)Jj=IM)IaS!C6De*?c;Y5(ig6 z{sJ1ers~N94rtBeR0A9gipGR`QB!%@RtTp2h>1B#+s`W}k}gg<&}?yX1uq6bKITv9 zk``qKHwnW%qj7*nOG}BJ&89km(DB}46#X`NNN!<+vdiEheugsz^aGY{VEKb-)28Ka zx#gBQ2p+UM6RV%YqUdwET=yS>`VpHpbsh;~vi&wCI=mwnmxqbnaKZ%&i>PK}f~&z1 zGBFGj20J#Pfe`@D#o$Dhf(yR%g>n>o@8wU1f9-3zJpTIZK%k>Eq%-RI2h1a!CLJh} zCtX1ps#zIJpoX#xu<8R@Do+d_KIAdUQ1=rh*anWTfl@xnMcF`0MGQZU!H-- zRa#kzh{2jp!3L$wOh3fYrAUfx4gPhdfy-H&V`Chz9GQ!Lg$X&VszUl8vlf!375T;H zAvLa80Yy3IPUPzHO*h^2d@aS^cRHwvFXLVYYvUvp$cZ&51|cJnfz`tnIN^X4HJ?a@ zh=&!5(eYRcUIe;dMq71DZ;sm!!6S>;nsi5CnwqS|sSI+qLv2}Z%O!P_bx4oTc$Q&P z9T*6WBrtSrPf+nezhKvab_kJ*4gL?GI(_=c#j|Jg{F(u|sWWFDkA?V|=mex~n>;?L z4oWWQFriRrnS%l5Q^58POmWtGImqS}nNg4Ouqzlz zHfkXLN=trmQYyd0gSW|xMr5`dSb&^Z9HO+cVLgL`rA|TH{X={P_X?c1GN=P+DJLgi z*RS9FDO7`B!6B<>mn-pqA^1y-GlzC?4A0NubHE)?5MzIQdiS3&$#EIV=SSV$(T#WB zd1LK_uw`y=<>JMrj?VM*1)fp&R6K!)**C+?_WAtgBb*GB{|<2dG$vcFy!F;wmuvohe(?&`v}d2c z5M=%da_i)0uQCK*B+$|$E%>Mw!;lt>VrYMI*YwRL;oKlQ*HVc3a8Ao~DIRcJ=Be2sDV8xtu>Alpop)o-kHi)Qf_wVZNx$4=Lk@AAE%)UubFLHUjx4bVDO0jf%EfDKBe;kfh)3$B<(^n?I4!=;3P4 zgeZ@;3`x<~5-|l|O*rTdCMVjKKmUANumu%F=!*bypXE)#I4K0n9{IJe)tIg34ZoNK zngmJz0WOX4F)2u@X*MbdTa)~(Le8|eIPoABbWVQ)W-PfMQ8dP~ZgIs~GcpEQk2dIgi{ z%OgtVV^QYc88c?gUHo!I8oM2joKsUMOu}}8nK0~A@Vue=L)}^Jb8d%1^U>_Af<9EM z>ZSUqQfgC5uZox6$5GVYJg1$T@~+vl*H4>q!Ot)PnJAK`^4IE;K1+ya>w?4oM#ILw z3NP!)-X)h26NCLr@mb=NWIH;;K?CKAOp2A!W|Y_jen=1#1aEY;6l>~4WNQhNUE{DZ z>e?yOW*l2?DO`0YUY}t8W*z9v$YZOAw4;=#mxF8!Mnbj?w06`T9DwvX%(1Prt-PhB za}&;coi+ti5k^aBN(R+=s-rC>4Mj|3P<7Q zpIckwKb`w#eH zy`gw6B>NQV?`z^h;nwwUz4c^v#}$d3d+xa-TH4!>&n*>DotK^La4 z$PUi05gwv%9*mOACB-@&oGOR8^FoD9;4U zi|rps5^zRR_SCJtBz3fdNYwHTB>kHVo89h3AI6;{;0QPZJB9$~Zu9(th*jElMWv{% zkJgmZm1GzkD@OQ6p+=p?RcCdqSXrgo*h;VH%}6+7=r916O4t14YiXpiMnjjcl(>qM z4ouMSML0zxT@7Mh=2Oo2B?}2dM~#uJ&>;w1!$B95WZjl6QDNk0ymG>Z7p*y0xTuS8 z5O0uP^iy8Y9r5vYCNwIm~&`jQ!4%0UHD1q&x!;p>47oAC;+y zQ@O7|=l#N|Q>XKN_Ip78fn0lG-H<5i?C8i@Ps~{=9Rr`h{Vb$98J(UX z)S0rX(8wKd6}t?6l9O^E7xXx=YW8sFwk@|Yype<2t=PIN6NVO_4pIx8%IDBx%k9adt{(A!0Lep)a{79DUIhHlq4l6=d|DN`=^ zZn>PFd*_|oAN)n zL&np!ED!@aqA7_9ZCpr0bk*lnmUt1JFBX3XA-Atvw_(|oDKj2IlKHUAS1>@^*40() z&T+GNM|mg)GN@}RhoXOZ0+t6)KjualXR!NxpnJguv@oR=$uv$ScBS%7x`srovHl z`IITsUYaxKmVam@C4$v|J@EY1@4$e}=Q3AV1V=wBLF2ufIvQyh|SZ zV4`^#HZvN=ZP;;hWztig3fum7tdydfp1sD>_H~^yefrthrFAK{mQx0;L&BAr7{*J` znfIIuLp}T4oH?_5y>hayvaY8!KV(f(j6OolB)8EOa!Q-+nmRxMB{3-C1M^K_SjN|{ zDEm81&Xs=53Lb=Z`m{JM&7U)8&g&tgT!0I{B9T9rXJ;U}^2^AY)`N@*a)dU`$czDQ z7X#~yb5Z$?$y29e7ff^;HmBWp`|UTbv_v~{#Y8)L3uwo|U+R7mgN!l|BtX#LaFQ$H zm@Y2$eaLq+@}QsclS;09F=)yc)3j`vQ~MNEn`QwpoOX^_lnv^WV{v!Gh!I`SO_@6V zXNa1QJy$$5w-ff*&D3afa5e~5UW%0o$nr_FL!Zu-;$zSUJCqZeI02hGi^8{B;`Hnn z<~{DX&to!f!*K57lC}$BHGK}==kxo6<`ozQUx9C5twEEpVan7Q9YE(zw11$N><_-< z@P6B9v}Y5jAHNJ$W;;tJ;?%yVYqgzK+cTRES3LU3^_HvA6*l>c$y2BPzm`JFSEYOi z7M!%%xYGIfLGW|8|7}*ROn03$XhlL3o zR+~E%J3%lJkKS-hy9O=xHqiW>VIWJ-gtEmdnNwqRvvcThhy1D8z9YgAg(fM z-9tPBQ(`Cl0xh7)@5iXFNF#O~be1Ht8woz<3(vZwMp~uAasf|FU}2NSfqjU$+k$tX z1GC#?cE*l?Bk&$WATFV^9ianf12mH_RIF*O&Tv+gtVGR)ij%htwaQr1Fh9~tI1_~X z^lEt+mvL;EOG!TML~%t36);}eMHhuMGIB}dRnxMB29A|F-!;I7+zjbHy<^4{aoz^r znS`{)L**tvWD}kU(f>*Zx}yzg=R^bkthZRh1CYMThEXOOQvH!ch?8(|h*Mo~4?j8< zc#96vGi4Tnk}MZ^0+e2(%Tky0i!xZ-f$)T#fDQ@Kw^UhINU z8fh8uHf+7MMpE<%Gr-m3SE1|6#>q2|BZ*7Y(DLlwUgNphFqO=80vXE%fQP zd&I#S`RH_^9R4>>Kksuuiw+MK>xznz5F!(j0zD}&(q#l3!Xz966L_1lbIn-$i$P01 zs*zSLP+Q;VRDugn}l=APLV-zyx5_iNVXdVzFm4 zzKMhL@S@Ss4}%4KxqvRvWd~XDV;E>+;uto$P15Yd9}H6P>D>%LmSJ$IiWXq{A`Qxg z9o$~!Xi49VYoU-lj3(&bA`aohUT7@`GBzEoTqrj%lyHQxa!1IwU{4=I=zKiqF9L52 z_*?LbLv$=A`6i$41QXU85nH-#BTPp>mLolew6q zIubMVSK%m&KgPt_VtmH=p6*J|Q^i%QR?l6!RLYvRy>#g^OaMn0pc4EdY(jU_k+kV) zvIN>a>cFll1WNqpKd^xeI?XHzM+7+3|0R@VdI{IN( z#0k$)Qwtzz-Z~Ge?nhD2EH35?XJFT)+LomW?HX^Tb|GKG3|^Lnr0itzO$jiwLanJ*wY@=z{;CJMa9m6|2laXnigv4om zr#UgiFXt-60r$XTJpVKb!+tR;i9kH)^U!X#84QOLT1+HiN<;cR8ZG!5KlbrpbI)N0 z>E00C*9CLbm9LkQ=mhM_I)Uv91qrpY=7HYQo(KK2&yC=VRFngfjlyigQOJH2s}WTQ z;=)T?!RaSTkH1nb;Wnj@d%-}ti#H@eyTSuWuRG@GqaL_z_UsVa`vN@qH9c$rfez$H zyy${I4KtpI3Z<$tQFG>zKv5!{EyEGbZ5k==?g)R;XC2hEbCV$|lgfh`v{0e(E+|UKF z2cYxFPM;ye`7Sa%R>0k&?>Qe3OQg0b6 z2p7S23{v2ITg}WX2l6p^i=)hpqp)-#Ats)>@VQ!@<>m5s^*E z1brpWVuiR;Gi>WcarKJrMJ5lHP=TCVDv^PEZ)UpZa?~Mai`;b>U@s*Lm^p-k=;Ydfv&ON^N^BT_J zeOLnOez4Nlan9t)-@x4BEyz)ne9WuaHFcn6S%pUkQ`=N~koYLV2Bzph!3z2*HXKBt z0GTISK1NUr6BBGn!@43(HV6;+${9l<2Y9EF23bVSI{kzV~As;p7-zq2c5!hUC5X1i&H8XM zVHkF2V8ZgIJMOscnQU_UQ6CNG7VosKf_&ITCdt6>gQ%-N2w6VYmdkI-9eillc?TVW zFHj{LVcX*h#oTyIe&97fJm0hv>IP?JC0COZ@is`Kjp6LX4LC@&ufZRPRbGbRU=?&l z9+8T?giH9z#B<=MgJ{@GKKd}8yAK0H!GLst-MUgKdM=wC^Lk%|+#f1)BAfCfojfNY zk?d;9@Mb*Ii44>^<0LH5U@++Hhw__-iJ{4(dg3dmOqudi$Z-o^RjWOZDMO<#FKU~% zbRs1r5`1M+!Jb!Ps%4H+pw5^C>s6=q#iLO;Y`GJ*{B6`QzXyIp((*_XQwq3%i^xQO zaFSkdk{EPE__7*Y+Hyb5$AyZM**!;jgV z$dM@vg(6)wC_0nKEFa`Wcs=?%{k{x`6`xb?m$0iET88T zw~UMyCOVLq$rSu1kEKibWoV>f;82q;r4?*h$g4)$wwGRkLf^o|Wv!7{35pMW0M312 zM`WO5bnVJi=I51v_40)_}+4vK}g@y!X=pel`8VqOihekMb zLf z$_if6jvxf9;}DFUpoW7KbZ+q#lBfsiY9>}h3&YfO;C=8D4wi>tTHjFRay=N6)pRsD zC^+k^DOVKH{7HvN=nqMGPrqD4JnSjI-+tH?ItaG~?-7j}HM+=-pYRPd z*by)%{3t^vj2I*w<--RHs1h?Uxb=A|5TQZDM%T`zI1O*0CU zRzqR8*cPoa8h(ZoceW5&-19x}{lJv+A1rtU2C$W?en@NlSq52L$xm=#nJ`gOxdUz$ z!yCEwVsTzqPtOmF`QjI3^|Xqe&`tRuvxp)@af7SI;Wy;rRqDE65B2=AHkQVb9&ITX z)vTPR@jK+U}|(iBJApri8~CsuuCZi+m<@+Ag+i?nIKT?4(ZKqnbnx^%D=3vjOTy} z$N0_1D{w1#-^gJg{!*Njlr9p8ZH9!VAL$x>;UDzp&MbNBD1$rkL7H_P9qV7s@Y>BANhyyY`IV_ zI$F7eQ$7(elimWDjx;j&)RoD3wh5|(nzJuZ^>Q*}9GiB@$L9ulYxpBSaS@iJ4JW^W zZmLg)r{!lt2__BZ4YY-b5K`J~53w-v(56iruSw&!aS&)y`4hA~FKdqee))NK z?sk!!wF!d`*+9cl$`yHP^k8}sRwa}PjzE_ai&8%#jpZ>~*t*2sF*UE!WqIx{|DZZ~ zyGvN->j*dk?@h+nTk7R&2NEx7R94EyFrgj%BEN)jvAel}UQ168N8>G7`lg4` zXU9(leHpnC)`E^ERslWWFTqB zzIqv`LSxPZ%j(mIh-|u?a+xF#A-5IdX-(DA)z01-~cxJCo7MXC-4>i zrf&!rS|N(P&oGe#c~aR~ z4^qY;hs2A&7E7if4f#`lTDOT1JK+bfY@~7szaW?B5#*=bCM*4PQa0>i?`Frc!Jy!8 zQ8v$I>q?WEb%S9jGH3OJpK+WlpdE?+xTZQXFViz!<|^rsM=&8qaLB(6E8BlEZ{F-T z>LEG&@Wb(m(j*+@8R`|}6FPw|X;B7|(d-%{Ns~S0X>u?>{!BL7kfb$wxMDX%XHU8G zAH=9$CcDQN@p;rSI2S-|nskgNuObimke|^;T8XnO!n3+S*I(7|jKjpqw=pUCGACIi zZ=g-OM!TwO(9L+J{RVxW(){F$INmFN#jsSyynQagYY+J^VqxNe&wlpYzv9_O2;8m% zEveJ0G!+B6r>vAa{MF#SgRh*JV5QQt|5z%OZ<2O6!%J|Yo`RR@9O|49u5l)#U6B^V zRUZu_R&=HZi1J46#Rkhs%~?X&*@<&eBAMVfInult-bO>pBG6=*$Q9`G-u{?Q>D9@K zyyg&c3Oj!-OAU&hEryhJ7f2$ zysCrYs#sRjRr6M9GfdMdeaL`K7v;ajWJbf+!6b3r57?{hK~BS2a73i=<&|>s59vf# z^0qKuK{t&jE#6xi^0c%ezXmB?@aT0G594>I+wG0e?o{4+I|7ct&Ow0hB}&DJ3Xqkl z`K=PQhQcaXOJi3{Z}+@r|7zkxTuR$2-3)KENSiip+*s2XbGHIISi16HGV)r-E6W#+ zUmgoJO|7`}^b|PxA%n@3W{}Bf$`>s%ata2pG3;lkP2P9Hxic`0kqmoynB z*P5^@c7_|}F_{KVdu0D1eM+B&SL!j!m~ zAcJ4VZ+z`qi9J12!u91&lam#!ATj<(_Erym|9pYUXK8WvP=> z_%qD#Bi@q6Y^b@<6E~6pG=UMY4|1nGK)+rdOM}FW>ouVP`qrBbD4_gSMd8E6<@GsBxKReqclN_l3(1D>^d?D(qmK;>==HEA?>q@V~TaqEnBzQvugRX^^C<;^ViT!%5i)p&ZJn_NWRXEo%=$D z_NqMk%;-JngmUJ+(NF7D#@S!6g=!kB|El?zmhqtu|G$go&3m+wOcvJC(()YiT_L;$ zldvnTj;Gi}2$Qt+{_xB(9deVK~MlgH2!VZJznAN9)I*FOiQZ?-(D zGK9P$kJ&M0;DM9Uoa~F&dA0OQp0K> z*Lm~qSOELOVbPW6`D{Q5kyH2vodiGHvFRv!s(p!0lv%=h>yXA<8m5!8LIPg6XBy5X zKu65&m9LyP?@pd))|A8CG5VQ2@2Dz66{}1+Fy7KohVaLH*}s}Jj0^JBq^S#I9&GK{ z?&3;Q3hl&1gX-k%ME*|75pV?d5Cp8kq&hP5%PT5EwnC^*Rm)JRrfGN|VkNDn(mWx~ zg0l2&c3m1IOMojIJcgmZ-7;y?Brea0>+I~rZaUddt->KR%P&itH0T0t4xpRbil5JS zGi}{Y0M$E7pMJ`34vl-UT<+=bODD(@UxU?S>6J03&`7U_pixv6>v>8l@&-y6d%lg; zjhYFcYVKSPgXg&zG)+c_^a;b5SCg8w=&Cd|w}i9YgpbKti-F#S^dYUKSNcgecC7T8 z&_DyrXcHmjK}zIH`9vNjq93%wwXk_J4rCaFTeWHxK1iU0Zj-wnS0l@Kixb{KRLjS7 z49{NmMtyqeZ;Y~G z^w+18_#iLk#MxB-kU{q?$Rqw z;(}h(PI5?I$*Qzctu@S0FnvXrT#SXP+~*f8nAh}VhEgl@LvJQpDla`EPmslUNqCSq z_46Ko_PnL?g)mE(z0yy|Jb0Gil3maS35!Ah_=Luwq4SK6fFocCVBo6_C@MtG?58US ztT<)WJUa^>W{%mxz@NsepZB_gtrc!|CB_;O&4cu8Z-rO&$~gX^YTukaTnUFvVzL3B zf(-FO1G3q@(KdP-E-MV|s5dpx!>$5(J;i7UP3W$?6d&W8rlG9Z)qx`|8m&|tyg95K z{|xl5VZ&?mNW*v-PF1?Kt0PROCyEnSVqSSWCEkZ;(V}^ewzT9=Lx=b;!Be(R3mwR8 z{G{vxjxy7q>Z|1^va>LR)Yxm5E|sL*U~(Z#xj%ndcCloi zT`Qv+8zEl6v#N94>)FB=Q_yKmWILYBAr^Y^Y#O@DUr@vOgvdh!qE&%fiF{mF}i zm+`7!yha94v=P`0`AYo}>_X)P-(cTXkEndL_HKFW?ZyTwkm=UVo11%8P34Ynz{L6E zHo!Akj5l=_y@T9_fnC$|h}W=O!wHR(Pd@X5`FzX2Vgxoi-3b()YvX0K%u&qaxTr=_Lzo&L%S>2WNW;%#|NrfPZdc}5!ae=IGoJ8eRP^6{0O z`Sa&~Gp>~Isr7h1=u4wUne30eO(qMID>0}`CvsYyf;hQH{u*2v&VXF)=b<}0xBdY5 z{Wa|Bb)H8iL+CmiW;W8ax=-6vaQa zF9)jUVAA`9#$ZtMJdS`PP=f#}Mecx*%26WFFz9`#FeOeq{A@I`X)PTBHGd}F(q*qw zStBj!&@s-gnvR3w-W`5)*5!2tO`DZV`PS13oqOz_DE0X|h%gR6J$UB?jf6~0WaTxP z*nn6gpOqJUK)*OFORIq&S<8Qk&cw~q@FD@}TH|BaYMAO|;f9%Ak#$Q09=(EiI{3nc z^Z!pzPuK6^6Y2j7T({cdK$TbH#?^S44Ay8$xHX_?B+Zc?cB(vv(!*TT1HE==pyPqV zE_E9)(`Fs-8KhV9BL%|H2)Cnb20d73|50_Q;+@rn@#LG;OZ*aMd5IAxTzX?=x*!kE z1T4?Sfc~5X3+D3`6ZxcWR?lYqz)0-euwWkZ>s2uqz5z3#8}~lXq8WagMqdSzXB$7Y z{On$zITnh=BX6&XyafvuEJLYbg}w4iuBfZ4Vy|VPw9MbkmCv6T1b?+`?#D{)^o0xO zUf$nlaDxDSULfzHVZ(-=hT^*%ax70J4juhk*@B&bzsgW&4|p!J;VQGT4&i+L?5o3v z4`0=%K!c0`ee?&dj1(i1f~X=B`SHbIG=CTV_7=&_bCU%*OZS=j18$xg38>vy&RBY@sg9%216n zOj*w(`9VGN_<{w;or}TnG}zBCj0XED z)Q`OD_3Z1uJ}og~7#**$oeoUW{2dl)o-jVVVsfPm{ef?yFYw#gVe|J$_jbr86A!g? zYvr=I^cv)@mr>e~R2DgW@?PjT8Iw9QfkCfVn6mN>)X!Z>(C6QJdU7WM({IBr(r1No zT7Rux#%w!o`Y?_9vo@RcYdmbe18w}ZcilDjmjjiT>A@rIYm1Db?9|_P9gUn?#?(vx zw5+$6kMV(TdPN_jbIX=epF4ad;cocpwK}pJWN?;_fFtn!M_?N&>W!$>S!;6-A2ia6 zP*qF2`Mor?3R7pus{`EL`KmOuj|N2Q(u9S#lKK%s7EET!DDIkSG1jpZzVh=R>9FV2QY9>WVIHzwus!{F5y z7Ms9k6)?t*7J_JHS6gnxq$&muc9Rv+T+Pg;NK8ERp6 zt&3w`(Ob$qEen)GC%#JZ3dWL4V7EV6yLR0#mo8n}Yj;Xu+|&j7zlIlc*JC#bg)o6K zUJGWF*rtqKU>AMizFod3#`UntwV=VznLXnvK^BPPrSOqehuT zv+##<$&aM?9C*{!l#PVc{!m9&pDY&)e3E=VdKF{)$MB3@T`F}gfgSalfUTuaz2m?X z2UDKa)m1tdc6c%1{wT`)V9=CDqiWk(yzBjDBYI_>j!A(xA?EXVtnj6m+}uTr7UGk} z19zARdf}|I&iX7SHU13LFM|#5OZtWp2fwt<{v6|h6DE6Vx1~>-ba{JA%bM>3$4?-h zz*7Mw1s>whgvm3&d%8?GZV=Fi43>e7$Jg zh=*YUdN>myc^-dv0GHeEz4zWF?Yiu$u4t?7tenM#IJ-tKfpxSbhO8K zHgiWpmk*eg8NQGUNrUXEF<6+1$a^|ot8w8O8Vmcs?)1~oz@%n!6&70-bD~I+H}O-c zba&vbQk-ulUzQ4tvV1}iWlZHW!WPGS^Vg@#giAKw8ww~9IF#$-t*!69LqV%jis1g^ z2si?cz`zms^rz1rJ!D7^wvpn<0dpLdHM4G)O_%i>okrI_(xJhKDwRU#z4tDx`6MYx zoORZu@ugDBfi*HRq90mlSbNa8Ki_PJ6%FD+SaceX?Rc^+w1&3vu`5_p-cl*wasT~` zUZg0^x|2^n>yTnGJ{v0+=b%%30va6dBH?ETS*PpF1qc1;cn0$?)NAFX2$drgrXB391j}($>?H99byDEyA+_ zpR{~J9Qgv%75z+LrEE?)<*eU8)$*}iKKeM`BRT@0egr0UATYG;-F&YYcE>Nx;Vc6< zWQM&(Z(%(i&sOvtI@^z8W$YQ)+Dj?nUF5-J%y66o^9h&?pUq<-!$e#U2D?_+2cJ)l zBrrQe0XRYwgQ?(Bg5+yqE-#|wp2n2Vlh9`wI`q#n<*sy;83#ii0e<}CrAXF`UmxX~ zZ_6*oBvf~=^zX3%=vc(-hsR-J`=gjZI0_RQ#{&C_(03S2hI+H2Du(h98$t-}34_!K ztK!jPD4*p$J@Io7J}85_9oF#VlTZF2=Dm)_aQG9bCoplBdb3aCm_)icYZs@UdioWpORwTYk{B4W2$=?g2<0gEGLr0rH2dkE2{$2)VXu1*{gj)XXMs*Mt4~C2!Ir1YJBHQ({y}>TZ7tprul!?;q zF`PJYdh7oCZ$LX-I35@s3)}roJ=j{A`P# z!{GYqX8Ss%n024|%x8|ob9D^J9}9lRfzNLM<^AC2jzN32IBP+fSnix9Ed6)cpNH)q4VgZMX6h*5a}=J*-+-+9qwmoMxnYa6sosuIt99!{ zO`}vS7yhv*p!*V#`pM9t?X#O{f2U8M-ioib0oz;~XjI8Js+)U@R}JYay@lJgnnQeQ z<1Md0@W6sKby2(hw!a!-w+rV2I0BAM)Mj4-+0ZNHmYZXY@Al#stgSAw!bQNYg#oPWnLP>MO0uyLIc<(fE+a!EMFD zzA%a+Y-2p^Du(#dF+|)(JUc7!oNUGyh`M)lr%qq;cz6{74h}jxI@-ItyGOugFdS*dh!0(9fMWhb1l#BRD#z~|sNF5_U+1g}*jXlKyEs-=o2&7K zvF_!|m&=5%p^X9JhcIw^2t&DX$gjatfAYsFQ>|C^ldka_nEaT80o1m*98JSC`B|u3 zPblQ`BM~M!NJMgz9_wbgDrx=A(hlL4R&V26PkhYc2N&ZtxA(n^FbUH>x^48RZMhQK z;b?pT^9J~!GTLPxRvx{9J^_F#Vkcht71W>W(H8ZD-DNvfdG-lLj2MB}3EN@2@wj|G zhl!0CyVVMmg{F)?NCA_Cc!f2Je!Y3~=C_6n8M1A6*3D%dpR=%nuu!gwF@0F1E9HhCUrQ(S`yw%dRM`VZ~~iU6N>caDG~;0QPZ zj({UjhX8im48v<7bFsRA5OJYj0|B&wix@`R3ll3hCzfIQTA=h z)*Z=~Z46l_-DQc1J6lrux-BzE*6d5jHnJ2kmO%^#W8c0*p6B)a1J7^wFW2?Ub$wpv zoa=qI>vPWMgbenu!tPu9B{IU%qx9FXYX@_#u>XxLtz9<^h=occD;S6*FYp--(bJV2|Z zxsKK0Cg+uO4mE1xk#&`?>tkNs+dH_EYIYP4!-$&v2W#0d=Et+vCh(gM9rX6FNlu~` zsRIG-@e97UKKsJS=5vUWN?qPE7Ku=R&78>!XH9Z)%|RT4LpjIR0CuuZ9}M6Lyh5pL>_O*h^+RfIB3Yg(4!v@h%;o z_kVnKt>3GW39m@(MKf(;u66qcDM2#ca!IRvZ7NC-4ORVqH<^~^Ad?#WQ96W z=Q$h>*Grt+i}|amP0E2!c)ZQkKnKF;&Dn1MdQj)v1WO4I=*<<|p%wVPq_w1T z(0cYHy6^c+ptnAUPB3mA$i+io+|=z2_I#Y{ErFmU8Mw~HT2f~-zkptyk5^un++g8Y zmRB!=n1fl~BQY8+*GS4)m|V8%v}zuQr_p!!&Tw4toE6kW(HRy;p5PTN@q|$pMAFrMi2ifqg9*T|1okb{!`oq0rM&Ix z@v&1(jutj=7@OpS#kl#1%^v)!tRPPUapoGs&Myige5s&BQn$^cFWspF+neBEm*Gr~fBgNYn9idjvm;tv)d5U?HRLMVI-9_H&VYwRlZ!=zl1*`{PHgoxW$7?=IFzEY7DZ) z4YGn3m$(A$EbBM*8UpWA+gfx^;Uh$k(6TbGG<;hSX3eCFu~~U+rDx4PbCIoC=}JP; z+pzf9(L|cC$uw&DbWLsDZGQ?Z7!Ku?M!rA=gWsJKNrTR9iLl)#UW*Pj4=GiMx3c#P zyjhtVk`9^T34<$cH6eq7h4qmrpvLZeu90w<%RUpyH`MXHeO0!THiB6!wQsgaM68!l zW>R}Xj5}*nDKYO{>e0kAp0hO-?S7Bqw^&|$uA({w(iD}3kq9^!zkxfZ_c1ly%Zy zXQJ2x0z%DuTjhn{{dxG6XI~YsJ62j`S5Yj?2JNNUU`zwKb2>q@_D#*VjqmTwU&qun zD*Q}KD(UX4n0GAz&MnHM{Rbs{5EtCNI*Pg-jPY2xj2a&M4S_czfWD-s_V`o^W4g`Zogw1 zu7(y(1BZWI6=||O;8s%;Pv5eU!Gxr5v8l*BRvo|I$XCd#x&HN<-Q_V{d_%GJ6Q`wM z>YQeMjuI(XjNKgsm~$saa+GD~h<({kI7Yw{&^tz8qApB{ zkCcFCVgK7Darcg9UZ*XVHc`5ljX$YtE{wW5vAd0-m4+VeZBHlUN-vLsX>(+B%=p6D zHzW#k z9k%7SiK;_o29aQ|ez|SW&HU+25tYLRMo{7Nhu|95?lvV2{U_^U{r&nPXks)Ab7riL zX8m7#euVuu1|gxwoc<3M9*hr&EeqBMt?>nRzBr;4{U|UL3>AK-wxvHByB07u(u&{d z#}CIT+Ado4nUq{?g16USIv|;c|9ls>whF#r{A9-9R53T<0Q@t)oU;Dc0Sa`8d60WU zU%B3rv{e+uhm7;Lob=8<{wS@$J5!w?`F<4rtXQlpTjABmJg>12&cT}2I-yX3y#-P3B4$uZ2A3O;?s}=F7JI) zc8Zfea!c$um4Zir_4q6dv1(@UtyHs=qqJIKCiTmyMk^^0tYAR4{|dCHPG|bS!tqMc zDWqzm8=|>Ja+07&D*nao-hpRilt+?YS?C5dHH(1W7Mxu{Wbf%8kE{6+XmH2CRZ@SoAklbM=xG>7KJ<2>Fu&33JzIDLCToj2eZ&{co zD;XsaTd*!la5mKHKv$My2P!bWVOft(J#9+qQBiQfH~8My9=kEu2{zmoSqRL9e)f8**Yn@(W@dkyv{3opcUu(NtjHRVQW5nS&-8G zbs~JWie##MV}e_aVMUw)T1#ny;rDi1;<)E{llKj*WvUJxT#oA8N#NowG*|WS^>=%^oqfX+O}%$*P}43ze`o~ca4BumZ8Sp5CYW514sRm< zMIWXO>qB~(ol~-v_RM2}=G2TuIpN76tt}waP=*?*LpJ6ZlaE%qA58{dJW{w3!KkYy zAjSi^zo^Tk@dv*U2f%p6V@;IHW6AKPzt~*2Sw3~Ex7d2Ml(b%O3~n1BZQnD?BCGht zDJ3R4NC>Q@D2Sws>LcIk3UDi?Be=pw39EXXxfGFPfmUUM>0=9f904i;FNNRTNk~wg zddgJPD&8x*drn%J<3Cxc5$|%miiQeudWv$ITrwzqT8>)GbAFU*T$KuEnPh&-(b5hN zM7W@9w&K`UW5kHu7f{v_)v(ibX{X};fz(yys!wZQoi2rqNPd?;m{eDM-O`mz>oji| z$Iv+Q%a>#4gbsGJ)C`ux zNmwh#MVSKq;{}AHpP1e!BVvC2bDAiV?E&~7Du8tXLjCML(bU7rbF#_2lUYIo^4lfd z!Lpy!QG2u>zb9SpeIN#0ZD|HKXyW?X7YW=ID?gTw5dU2-PVV05wi^ zfENWx)J|3KKmm18i-sAkB^ue1rmu46%Xy$UV&gN_GvAK;Tgk@2AdJVOiw}nfPn}yZ zAeP-O+jDd?kL0@pq~@kCNtSheE>Vw9Rqp+A8+OuZA1FbY`U~ns&(PK6#M&0k!X5iT zrEz^W{gGDzXdU(2j~~aRCn4Xzw|^z^FBtwe7XKFv|36?LqMtV$F+WQxCchRdqs?-l OqcgZ+qFbzujQlTLt`^Mz diff --git a/docs/css/auto-complete.css b/docs/css/auto-complete.css deleted file mode 100644 index c144cd389..000000000 --- a/docs/css/auto-complete.css +++ /dev/null @@ -1,49 +0,0 @@ -.autocomplete-suggestions { - text-align: left; - cursor: default; - border: 1px solid #ccc; - border-top: 0; - background: #fff; - box-shadow: 1px 2px 6px; - transition: left 0.1s ease-in-out; - - /* core styles should not be changed */ - position: absolute; - display: none; - z-index: 9999; - max-height: 70vh; - width: 265px; - overflow: hidden; - overflow-y: hidden; - box-sizing: border-box; - -} -.autocomplete-suggestion { - position: relative; - cursor: pointer; - padding: 7px; - line-height: 23px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - color: #333; -} - -.autocomplete-suggestion b { - font-weight: normal; - color: #1f8dd6; -} - -.autocomplete-suggestion.selected { - background: #333; - color: #fff; -} - -.autocomplete-suggestion:hover { - background: #444; - color: #fff; -} - -.autocomplete-suggestion > .context { - font-size: 12px; -} diff --git a/docs/css/bootstrap.min.css b/docs/css/bootstrap.min.css deleted file mode 100644 index f1468a525..000000000 --- a/docs/css/bootstrap.min.css +++ /dev/null @@ -1,1884 +0,0 @@ -@font-face { - font-family: 'Glyphicons Halflings'; - src: url('../fonts/glyphicons-halflings-regular.eot'); - src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); -} -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.glyphicon-asterisk:before { - content: "\2a"; -} -.glyphicon-plus:before { - content: "\2b"; -} -.glyphicon-euro:before, -.glyphicon-eur:before { - content: "\20ac"; -} -.glyphicon-minus:before { - content: "\2212"; -} -.glyphicon-cloud:before { - content: "\2601"; -} -.glyphicon-envelope:before { - content: "\2709"; -} -.glyphicon-pencil:before { - content: "\270f"; -} -.glyphicon-glass:before { - content: "\e001"; -} -.glyphicon-music:before { - content: "\e002"; -} -.glyphicon-search:before { - content: "\e003"; -} -.glyphicon-heart:before { - content: "\e005"; -} -.glyphicon-star:before { - content: "\e006"; -} -.glyphicon-star-empty:before { - content: "\e007"; -} -.glyphicon-user:before { - content: "\e008"; -} -.glyphicon-film:before { - content: "\e009"; -} -.glyphicon-th-large:before { - content: "\e010"; -} -.glyphicon-th:before { - content: "\e011"; -} -.glyphicon-th-list:before { - content: "\e012"; -} -.glyphicon-ok:before { - content: "\e013"; -} -.glyphicon-remove:before { - content: "\e014"; -} -.glyphicon-zoom-in:before { - content: "\e015"; -} -.glyphicon-zoom-out:before { - content: "\e016"; -} -.glyphicon-off:before { - content: "\e017"; -} -.glyphicon-signal:before { - content: "\e018"; -} -.glyphicon-cog:before { - content: "\e019"; -} -.glyphicon-trash:before { - content: "\e020"; -} -.glyphicon-home:before { - content: "\e021"; -} -.glyphicon-file:before { - content: "\e022"; -} -.glyphicon-time:before { - content: "\e023"; -} -.glyphicon-road:before { - content: "\e024"; -} -.glyphicon-download-alt:before { - content: "\e025"; -} -.glyphicon-download:before { - content: "\e026"; -} -.glyphicon-upload:before { - content: "\e027"; -} -.glyphicon-inbox:before { - content: "\e028"; -} -.glyphicon-play-circle:before { - content: "\e029"; -} -.glyphicon-repeat:before { - content: "\e030"; -} -.glyphicon-refresh:before { - content: "\e031"; -} -.glyphicon-list-alt:before { - content: "\e032"; -} -.glyphicon-lock:before { - content: "\e033"; -} -.glyphicon-flag:before { - content: "\e034"; -} -.glyphicon-headphones:before { - content: "\e035"; -} -.glyphicon-volume-off:before { - content: "\e036"; -} -.glyphicon-volume-down:before { - content: "\e037"; -} -.glyphicon-volume-up:before { - content: "\e038"; -} -.glyphicon-qrcode:before { - content: "\e039"; -} -.glyphicon-barcode:before { - content: "\e040"; -} -.glyphicon-tag:before { - content: "\e041"; -} -.glyphicon-tags:before { - content: "\e042"; -} -.glyphicon-book:before { - content: "\e043"; -} -.glyphicon-bookmark:before { - content: "\e044"; -} -.glyphicon-print:before { - content: "\e045"; -} -.glyphicon-camera:before { - content: "\e046"; -} -.glyphicon-font:before { - content: "\e047"; -} -.glyphicon-bold:before { - content: "\e048"; -} -.glyphicon-italic:before { - content: "\e049"; -} -.glyphicon-text-height:before { - content: "\e050"; -} -.glyphicon-text-width:before { - content: "\e051"; -} -.glyphicon-align-left:before { - content: "\e052"; -} -.glyphicon-align-center:before { - content: "\e053"; -} -.glyphicon-align-right:before { - content: "\e054"; -} -.glyphicon-align-justify:before { - content: "\e055"; -} -.glyphicon-list:before { - content: "\e056"; -} -.glyphicon-indent-left:before { - content: "\e057"; -} -.glyphicon-indent-right:before { - content: "\e058"; -} -.glyphicon-facetime-video:before { - content: "\e059"; -} -.glyphicon-picture:before { - content: "\e060"; -} -.glyphicon-map-marker:before { - content: "\e062"; -} -.glyphicon-adjust:before { - content: "\e063"; -} -.glyphicon-tint:before { - content: "\e064"; -} -.glyphicon-edit:before { - content: "\e065"; -} -.glyphicon-share:before { - content: "\e066"; -} -.glyphicon-check:before { - content: "\e067"; -} -.glyphicon-move:before { - content: "\e068"; -} -.glyphicon-step-backward:before { - content: "\e069"; -} -.glyphicon-fast-backward:before { - content: "\e070"; -} -.glyphicon-backward:before { - content: "\e071"; -} -.glyphicon-play:before { - content: "\e072"; -} -.glyphicon-pause:before { - content: "\e073"; -} -.glyphicon-stop:before { - content: "\e074"; -} -.glyphicon-forward:before { - content: "\e075"; -} -.glyphicon-fast-forward:before { - content: "\e076"; -} -.glyphicon-step-forward:before { - content: "\e077"; -} -.glyphicon-eject:before { - content: "\e078"; -} -.glyphicon-chevron-left:before { - content: "\e079"; -} -.glyphicon-chevron-right:before { - content: "\e080"; -} -.glyphicon-plus-sign:before { - content: "\e081"; -} -.glyphicon-minus-sign:before { - content: "\e082"; -} -.glyphicon-remove-sign:before { - content: "\e083"; -} -.glyphicon-ok-sign:before { - content: "\e084"; -} -.glyphicon-question-sign:before { - content: "\e085"; -} -.glyphicon-info-sign:before { - content: "\e086"; -} -.glyphicon-screenshot:before { - content: "\e087"; -} -.glyphicon-remove-circle:before { - content: "\e088"; -} -.glyphicon-ok-circle:before { - content: "\e089"; -} -.glyphicon-ban-circle:before { - content: "\e090"; -} -.glyphicon-arrow-left:before { - content: "\e091"; -} -.glyphicon-arrow-right:before { - content: "\e092"; -} -.glyphicon-arrow-up:before { - content: "\e093"; -} -.glyphicon-arrow-down:before { - content: "\e094"; -} -.glyphicon-share-alt:before { - content: "\e095"; -} -.glyphicon-resize-full:before { - content: "\e096"; -} -.glyphicon-resize-small:before { - content: "\e097"; -} -.glyphicon-exclamation-sign:before { - content: "\e101"; -} -.glyphicon-gift:before { - content: "\e102"; -} -.glyphicon-leaf:before { - content: "\e103"; -} -.glyphicon-fire:before { - content: "\e104"; -} -.glyphicon-eye-open:before { - content: "\e105"; -} -.glyphicon-eye-close:before { - content: "\e106"; -} -.glyphicon-warning-sign:before { - content: "\e107"; -} -.glyphicon-plane:before { - content: "\e108"; -} -.glyphicon-calendar:before { - content: "\e109"; -} -.glyphicon-random:before { - content: "\e110"; -} -.glyphicon-comment:before { - content: "\e111"; -} -.glyphicon-magnet:before { - content: "\e112"; -} -.glyphicon-chevron-up:before { - content: "\e113"; -} -.glyphicon-chevron-down:before { - content: "\e114"; -} -.glyphicon-retweet:before { - content: "\e115"; -} -.glyphicon-shopping-cart:before { - content: "\e116"; -} -.glyphicon-folder-close:before { - content: "\e117"; -} -.glyphicon-folder-open:before { - content: "\e118"; -} -.glyphicon-resize-vertical:before { - content: "\e119"; -} -.glyphicon-resize-horizontal:before { - content: "\e120"; -} -.glyphicon-hdd:before { - content: "\e121"; -} -.glyphicon-bullhorn:before { - content: "\e122"; -} -.glyphicon-bell:before { - content: "\e123"; -} -.glyphicon-certificate:before { - content: "\e124"; -} -.glyphicon-thumbs-up:before { - content: "\e125"; -} -.glyphicon-thumbs-down:before { - content: "\e126"; -} -.glyphicon-hand-right:before { - content: "\e127"; -} -.glyphicon-hand-left:before { - content: "\e128"; -} -.glyphicon-hand-up:before { - content: "\e129"; -} -.glyphicon-hand-down:before { - content: "\e130"; -} -.glyphicon-circle-arrow-right:before { - content: "\e131"; -} -.glyphicon-circle-arrow-left:before { - content: "\e132"; -} -.glyphicon-circle-arrow-up:before { - content: "\e133"; -} -.glyphicon-circle-arrow-down:before { - content: "\e134"; -} -.glyphicon-globe:before { - content: "\e135"; -} -.glyphicon-wrench:before { - content: "\e136"; -} -.glyphicon-tasks:before { - content: "\e137"; -} -.glyphicon-filter:before { - content: "\e138"; -} -.glyphicon-briefcase:before { - content: "\e139"; -} -.glyphicon-fullscreen:before { - content: "\e140"; -} -.glyphicon-dashboard:before { - content: "\e141"; -} -.glyphicon-paperclip:before { - content: "\e142"; -} -.glyphicon-heart-empty:before { - content: "\e143"; -} -.glyphicon-link:before { - content: "\e144"; -} -.glyphicon-phone:before { - content: "\e145"; -} -.glyphicon-pushpin:before { - content: "\e146"; -} -.glyphicon-usd:before { - content: "\e148"; -} -.glyphicon-gbp:before { - content: "\e149"; -} -.glyphicon-sort:before { - content: "\e150"; -} -.glyphicon-sort-by-alphabet:before { - content: "\e151"; -} -.glyphicon-sort-by-alphabet-alt:before { - content: "\e152"; -} -.glyphicon-sort-by-order:before { - content: "\e153"; -} -.glyphicon-sort-by-order-alt:before { - content: "\e154"; -} -.glyphicon-sort-by-attributes:before { - content: "\e155"; -} -.glyphicon-sort-by-attributes-alt:before { - content: "\e156"; -} -.glyphicon-unchecked:before { - content: "\e157"; -} -.glyphicon-expand:before { - content: "\e158"; -} -.glyphicon-collapse-down:before { - content: "\e159"; -} -.glyphicon-collapse-up:before { - content: "\e160"; -} -.glyphicon-log-in:before { - content: "\e161"; -} -.glyphicon-flash:before { - content: "\e162"; -} -.glyphicon-log-out:before { - content: "\e163"; -} -.glyphicon-new-window:before { - content: "\e164"; -} -.glyphicon-record:before { - content: "\e165"; -} -.glyphicon-save:before { - content: "\e166"; -} -.glyphicon-open:before { - content: "\e167"; -} -.glyphicon-saved:before { - content: "\e168"; -} -.glyphicon-import:before { - content: "\e169"; -} -.glyphicon-export:before { - content: "\e170"; -} -.glyphicon-send:before { - content: "\e171"; -} -.glyphicon-floppy-disk:before { - content: "\e172"; -} -.glyphicon-floppy-saved:before { - content: "\e173"; -} -.glyphicon-floppy-remove:before { - content: "\e174"; -} -.glyphicon-floppy-save:before { - content: "\e175"; -} -.glyphicon-floppy-open:before { - content: "\e176"; -} -.glyphicon-credit-card:before { - content: "\e177"; -} -.glyphicon-transfer:before { - content: "\e178"; -} -.glyphicon-cutlery:before { - content: "\e179"; -} -.glyphicon-header:before { - content: "\e180"; -} -.glyphicon-compressed:before { - content: "\e181"; -} -.glyphicon-earphone:before { - content: "\e182"; -} -.glyphicon-phone-alt:before { - content: "\e183"; -} -.glyphicon-tower:before { - content: "\e184"; -} -.glyphicon-stats:before { - content: "\e185"; -} -.glyphicon-sd-video:before { - content: "\e186"; -} -.glyphicon-hd-video:before { - content: "\e187"; -} -.glyphicon-subtitles:before { - content: "\e188"; -} -.glyphicon-sound-stereo:before { - content: "\e189"; -} -.glyphicon-sound-dolby:before { - content: "\e190"; -} -.glyphicon-sound-5-1:before { - content: "\e191"; -} -.glyphicon-sound-6-1:before { - content: "\e192"; -} -.glyphicon-sound-7-1:before { - content: "\e193"; -} -.glyphicon-copyright-mark:before { - content: "\e194"; -} -.glyphicon-registration-mark:before { - content: "\e195"; -} -.glyphicon-cloud-download:before { - content: "\e197"; -} -.glyphicon-cloud-upload:before { - content: "\e198"; -} -.glyphicon-tree-conifer:before { - content: "\e199"; -} -.glyphicon-tree-deciduous:before { - content: "\e200"; -} -.glyphicon-cd:before { - content: "\e201"; -} -.glyphicon-save-file:before { - content: "\e202"; -} -.glyphicon-open-file:before { - content: "\e203"; -} -.glyphicon-level-up:before { - content: "\e204"; -} -.glyphicon-copy:before { - content: "\e205"; -} -.glyphicon-paste:before { - content: "\e206"; -} -.glyphicon-alert:before { - content: "\e209"; -} -.glyphicon-equalizer:before { - content: "\e210"; -} -.glyphicon-king:before { - content: "\e211"; -} -.glyphicon-queen:before { - content: "\e212"; -} -.glyphicon-pawn:before { - content: "\e213"; -} -.glyphicon-bishop:before { - content: "\e214"; -} -.glyphicon-knight:before { - content: "\e215"; -} -.glyphicon-baby-formula:before { - content: "\e216"; -} -.glyphicon-tent:before { - content: "\26fa"; -} -.glyphicon-blackboard:before { - content: "\e218"; -} -.glyphicon-bed:before { - content: "\e219"; -} -.glyphicon-apple:before { - content: "\f8ff"; -} -.glyphicon-erase:before { - content: "\e221"; -} -.glyphicon-hourglass:before { - content: "\231b"; -} -.glyphicon-lamp:before { - content: "\e223"; -} -.glyphicon-duplicate:before { - content: "\e224"; -} -.glyphicon-piggy-bank:before { - content: "\e225"; -} -.glyphicon-scissors:before { - content: "\e226"; -} -.glyphicon-bitcoin:before { - content: "\e227"; -} -.glyphicon-btc:before { - content: "\e227"; -} -.glyphicon-xbt:before { - content: "\e227"; -} -.glyphicon-yen:before { - content: "\00a5"; -} -.glyphicon-jpy:before { - content: "\00a5"; -} -.glyphicon-ruble:before { - content: "\20bd"; -} -.glyphicon-rub:before { - content: "\20bd"; -} -.glyphicon-scale:before { - content: "\e230"; -} -.glyphicon-ice-lolly:before { - content: "\e231"; -} -.glyphicon-ice-lolly-tasted:before { - content: "\e232"; -} -.glyphicon-education:before { - content: "\e233"; -} -.glyphicon-option-horizontal:before { - content: "\e234"; -} -.glyphicon-option-vertical:before { - content: "\e235"; -} -.glyphicon-menu-hamburger:before { - content: "\e236"; -} -.glyphicon-modal-window:before { - content: "\e237"; -} -.glyphicon-oil:before { - content: "\e238"; -} -.glyphicon-grain:before { - content: "\e239"; -} -.glyphicon-sunglasses:before { - content: "\e240"; -} -.glyphicon-text-size:before { - content: "\e241"; -} -.glyphicon-text-color:before { - content: "\e242"; -} -.glyphicon-text-background:before { - content: "\e243"; -} -.glyphicon-object-align-top:before { - content: "\e244"; -} -.glyphicon-object-align-bottom:before { - content: "\e245"; -} -.glyphicon-object-align-horizontal:before { - content: "\e246"; -} -.glyphicon-object-align-left:before { - content: "\e247"; -} -.glyphicon-object-align-vertical:before { - content: "\e248"; -} -.glyphicon-object-align-right:before { - content: "\e249"; -} -.glyphicon-triangle-right:before { - content: "\e250"; -} -.glyphicon-triangle-left:before { - content: "\e251"; -} -.glyphicon-triangle-bottom:before { - content: "\e252"; -} -.glyphicon-triangle-top:before { - content: "\e253"; -} -.glyphicon-console:before { - content: "\e254"; -} -.glyphicon-superscript:before { - content: "\e255"; -} -.glyphicon-subscript:before { - content: "\e256"; -} -.glyphicon-menu-left:before { - content: "\e257"; -} -.glyphicon-menu-right:before { - content: "\e258"; -} -.glyphicon-menu-down:before { - content: "\e259"; -} -.glyphicon-menu-up:before { - content: "\e260"; -} - - -/*ALERTS*/ -.alert { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px; -} -.alert h4 { - margin-top: 0; - color: inherit; -} -.alert .alert-link { - font-weight: bold; -} -.alert > p, -.alert > ul { - margin-bottom: 0; -} -.alert > p + p { - margin-top: 5px; -} -.alert-dismissable, -.alert-dismissible { - padding-right: 35px; -} -.alert-dismissable .close, -.alert-dismissible .close { - position: relative; - top: -2px; - right: -21px; - color: inherit; -} -.alert-success { - background-color: #dff0d8; - border-color: #d6e9c6; - color: #3c763d; -} -.alert-success hr { - border-top-color: #c9e2b3; -} -.alert-success .alert-link { - color: #2b542c; -} -.alert-info { - background-color: #d9edf7; - border-color: #bce8f1; - color: #31708f; -} -.alert-info hr { - border-top-color: #a6e1ec; -} -.alert-info .alert-link { - color: #245269; -} -.alert-warning { - background-color: #fcf8e3; - border-color: #faebcc; - color: #8a6d3b; -} -.alert-warning hr { - border-top-color: #f7e1b5; -} -.alert-warning .alert-link { - color: #66512c; -} -.alert-danger { - background-color: #f2dede; - border-color: #ebccd1; - color: #a94442; -} -.alert-danger hr { - border-top-color: #e4b9c0; -} -.alert-danger .alert-link { - color: #843534; -} - -/* BUTTONS */ -[role="button"] { - cursor: pointer; -} -.btn { - display: inline-block; - margin-bottom: 0; - font-weight: normal; - text-align: center; - vertical-align: middle; - -ms-touch-action: manipulation; - touch-action: manipulation; - cursor: pointer; - background-image: none; - border: 1px solid transparent; - white-space: nowrap; - padding: 6px 12px; - font-size: 14px; - line-height: 1.42857143; - border-radius: 4px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.btn:focus, -.btn:active:focus, -.btn.active:focus, -.btn.focus, -.btn:active.focus, -.btn.active.focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -.btn:hover, -.btn:focus, -.btn.focus { - color: #333333; - text-decoration: none; -} -.btn:active, -.btn.active { - outline: 0; - background-image: none; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); -} -.btn.disabled, -.btn[disabled], -fieldset[disabled] .btn { - cursor: not-allowed; - opacity: 0.65; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; -} -a.btn.disabled, -fieldset[disabled] a.btn { - pointer-events: none; -} -.btn-default { - color: #333333; - background-color: #ffffff; - border-color: #cccccc; -} -.btn-default:focus, -.btn-default.focus { - color: #333333; - background-color: #e6e6e6; - border-color: #8c8c8c; -} -.btn-default:hover { - color: #333333; - background-color: #e6e6e6; - border-color: #adadad; -} -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - color: #333333; - background-color: #e6e6e6; - border-color: #adadad; -} -.btn-default:active:hover, -.btn-default.active:hover, -.open > .dropdown-toggle.btn-default:hover, -.btn-default:active:focus, -.btn-default.active:focus, -.open > .dropdown-toggle.btn-default:focus, -.btn-default:active.focus, -.btn-default.active.focus, -.open > .dropdown-toggle.btn-default.focus { - color: #333333; - background-color: #d4d4d4; - border-color: #8c8c8c; -} -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - background-image: none; -} -.btn-default.disabled, -.btn-default[disabled], -fieldset[disabled] .btn-default, -.btn-default.disabled:hover, -.btn-default[disabled]:hover, -fieldset[disabled] .btn-default:hover, -.btn-default.disabled:focus, -.btn-default[disabled]:focus, -fieldset[disabled] .btn-default:focus, -.btn-default.disabled.focus, -.btn-default[disabled].focus, -fieldset[disabled] .btn-default.focus, -.btn-default.disabled:active, -.btn-default[disabled]:active, -fieldset[disabled] .btn-default:active, -.btn-default.disabled.active, -.btn-default[disabled].active, -fieldset[disabled] .btn-default.active { - background-color: #ffffff; - border-color: #cccccc; -} -.btn-default .badge { - color: #ffffff; - background-color: #333333; -} -.btn-primary { - color: #ffffff; - background-color: #337ab7; - border-color: #2e6da4; -} -.btn-primary:focus, -.btn-primary.focus { - color: #ffffff; - background-color: #286090; - border-color: #122b40; -} -.btn-primary:hover { - color: #ffffff; - background-color: #286090; - border-color: #204d74; -} -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - color: #ffffff; - background-color: #286090; - border-color: #204d74; -} -.btn-primary:active:hover, -.btn-primary.active:hover, -.open > .dropdown-toggle.btn-primary:hover, -.btn-primary:active:focus, -.btn-primary.active:focus, -.open > .dropdown-toggle.btn-primary:focus, -.btn-primary:active.focus, -.btn-primary.active.focus, -.open > .dropdown-toggle.btn-primary.focus { - color: #ffffff; - background-color: #204d74; - border-color: #122b40; -} -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - background-image: none; -} -.btn-primary.disabled, -.btn-primary[disabled], -fieldset[disabled] .btn-primary, -.btn-primary.disabled:hover, -.btn-primary[disabled]:hover, -fieldset[disabled] .btn-primary:hover, -.btn-primary.disabled:focus, -.btn-primary[disabled]:focus, -fieldset[disabled] .btn-primary:focus, -.btn-primary.disabled.focus, -.btn-primary[disabled].focus, -fieldset[disabled] .btn-primary.focus, -.btn-primary.disabled:active, -.btn-primary[disabled]:active, -fieldset[disabled] .btn-primary:active, -.btn-primary.disabled.active, -.btn-primary[disabled].active, -fieldset[disabled] .btn-primary.active { - background-color: #337ab7; - border-color: #2e6da4; -} -.btn-primary .badge { - color: #337ab7; - background-color: #ffffff; -} -.btn-success { - color: #ffffff; - background-color: #5cb85c; - border-color: #4cae4c; -} -.btn-success:focus, -.btn-success.focus { - color: #ffffff; - background-color: #449d44; - border-color: #255625; -} -.btn-success:hover { - color: #ffffff; - background-color: #449d44; - border-color: #398439; -} -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - color: #ffffff; - background-color: #449d44; - border-color: #398439; -} -.btn-success:active:hover, -.btn-success.active:hover, -.open > .dropdown-toggle.btn-success:hover, -.btn-success:active:focus, -.btn-success.active:focus, -.open > .dropdown-toggle.btn-success:focus, -.btn-success:active.focus, -.btn-success.active.focus, -.open > .dropdown-toggle.btn-success.focus { - color: #ffffff; - background-color: #398439; - border-color: #255625; -} -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - background-image: none; -} -.btn-success.disabled, -.btn-success[disabled], -fieldset[disabled] .btn-success, -.btn-success.disabled:hover, -.btn-success[disabled]:hover, -fieldset[disabled] .btn-success:hover, -.btn-success.disabled:focus, -.btn-success[disabled]:focus, -fieldset[disabled] .btn-success:focus, -.btn-success.disabled.focus, -.btn-success[disabled].focus, -fieldset[disabled] .btn-success.focus, -.btn-success.disabled:active, -.btn-success[disabled]:active, -fieldset[disabled] .btn-success:active, -.btn-success.disabled.active, -.btn-success[disabled].active, -fieldset[disabled] .btn-success.active { - background-color: #5cb85c; - border-color: #4cae4c; -} -.btn-success .badge { - color: #5cb85c; - background-color: #ffffff; -} -.btn-info { - color: #ffffff; - background-color: #5bc0de; - border-color: #46b8da; -} -.btn-info:focus, -.btn-info.focus { - color: #ffffff; - background-color: #31b0d5; - border-color: #1b6d85; -} -.btn-info:hover { - color: #ffffff; - background-color: #31b0d5; - border-color: #269abc; -} -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - color: #ffffff; - background-color: #31b0d5; - border-color: #269abc; -} -.btn-info:active:hover, -.btn-info.active:hover, -.open > .dropdown-toggle.btn-info:hover, -.btn-info:active:focus, -.btn-info.active:focus, -.open > .dropdown-toggle.btn-info:focus, -.btn-info:active.focus, -.btn-info.active.focus, -.open > .dropdown-toggle.btn-info.focus { - color: #ffffff; - background-color: #269abc; - border-color: #1b6d85; -} -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - background-image: none; -} -.btn-info.disabled, -.btn-info[disabled], -fieldset[disabled] .btn-info, -.btn-info.disabled:hover, -.btn-info[disabled]:hover, -fieldset[disabled] .btn-info:hover, -.btn-info.disabled:focus, -.btn-info[disabled]:focus, -fieldset[disabled] .btn-info:focus, -.btn-info.disabled.focus, -.btn-info[disabled].focus, -fieldset[disabled] .btn-info.focus, -.btn-info.disabled:active, -.btn-info[disabled]:active, -fieldset[disabled] .btn-info:active, -.btn-info.disabled.active, -.btn-info[disabled].active, -fieldset[disabled] .btn-info.active { - background-color: #5bc0de; - border-color: #46b8da; -} -.btn-info .badge { - color: #5bc0de; - background-color: #ffffff; -} -.btn-warning { - color: #ffffff; - background-color: #f0ad4e; - border-color: #eea236; -} -.btn-warning:focus, -.btn-warning.focus { - color: #ffffff; - background-color: #ec971f; - border-color: #985f0d; -} -.btn-warning:hover { - color: #ffffff; - background-color: #ec971f; - border-color: #d58512; -} -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - color: #ffffff; - background-color: #ec971f; - border-color: #d58512; -} -.btn-warning:active:hover, -.btn-warning.active:hover, -.open > .dropdown-toggle.btn-warning:hover, -.btn-warning:active:focus, -.btn-warning.active:focus, -.open > .dropdown-toggle.btn-warning:focus, -.btn-warning:active.focus, -.btn-warning.active.focus, -.open > .dropdown-toggle.btn-warning.focus { - color: #ffffff; - background-color: #d58512; - border-color: #985f0d; -} -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - background-image: none; -} -.btn-warning.disabled, -.btn-warning[disabled], -fieldset[disabled] .btn-warning, -.btn-warning.disabled:hover, -.btn-warning[disabled]:hover, -fieldset[disabled] .btn-warning:hover, -.btn-warning.disabled:focus, -.btn-warning[disabled]:focus, -fieldset[disabled] .btn-warning:focus, -.btn-warning.disabled.focus, -.btn-warning[disabled].focus, -fieldset[disabled] .btn-warning.focus, -.btn-warning.disabled:active, -.btn-warning[disabled]:active, -fieldset[disabled] .btn-warning:active, -.btn-warning.disabled.active, -.btn-warning[disabled].active, -fieldset[disabled] .btn-warning.active { - background-color: #f0ad4e; - border-color: #eea236; -} -.btn-warning .badge { - color: #f0ad4e; - background-color: #ffffff; -} -.btn-danger { - color: #ffffff; - background-color: #d9534f; - border-color: #d43f3a; -} -.btn-danger:focus, -.btn-danger.focus { - color: #ffffff; - background-color: #c9302c; - border-color: #761c19; -} -.btn-danger:hover { - color: #ffffff; - background-color: #c9302c; - border-color: #ac2925; -} -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - color: #ffffff; - background-color: #c9302c; - border-color: #ac2925; -} -.btn-danger:active:hover, -.btn-danger.active:hover, -.open > .dropdown-toggle.btn-danger:hover, -.btn-danger:active:focus, -.btn-danger.active:focus, -.open > .dropdown-toggle.btn-danger:focus, -.btn-danger:active.focus, -.btn-danger.active.focus, -.open > .dropdown-toggle.btn-danger.focus { - color: #ffffff; - background-color: #ac2925; - border-color: #761c19; -} -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - background-image: none; -} -.btn-danger.disabled, -.btn-danger[disabled], -fieldset[disabled] .btn-danger, -.btn-danger.disabled:hover, -.btn-danger[disabled]:hover, -fieldset[disabled] .btn-danger:hover, -.btn-danger.disabled:focus, -.btn-danger[disabled]:focus, -fieldset[disabled] .btn-danger:focus, -.btn-danger.disabled.focus, -.btn-danger[disabled].focus, -fieldset[disabled] .btn-danger.focus, -.btn-danger.disabled:active, -.btn-danger[disabled]:active, -fieldset[disabled] .btn-danger:active, -.btn-danger.disabled.active, -.btn-danger[disabled].active, -fieldset[disabled] .btn-danger.active { - background-color: #d9534f; - border-color: #d43f3a; -} -.btn-danger .badge { - color: #d9534f; - background-color: #ffffff; -} -.btn-link { - color: #337ab7; - font-weight: normal; - border-radius: 0; -} -.btn-link, -.btn-link:active, -.btn-link.active, -.btn-link[disabled], -fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none; -} -.btn-link, -.btn-link:hover, -.btn-link:focus, -.btn-link:active { - border-color: transparent; -} -.btn-link:hover, -.btn-link:focus { - color: #23527c; - text-decoration: underline; - background-color: transparent; -} -.btn-link[disabled]:hover, -fieldset[disabled] .btn-link:hover, -.btn-link[disabled]:focus, -fieldset[disabled] .btn-link:focus { - color: #777777; - text-decoration: none; -} -.btn-lg { - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px; -} -.btn-sm { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-xs { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-block { - display: block; - width: 100%; -} -.btn-block + .btn-block { - margin-top: 5px; -} - -/*LABELS*/ -.label { - display: inline; - padding: .2em .6em .3em; - font-size: 75%; - font-weight: bold; - line-height: 1; - color: #ffffff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25em; -} -a.label:hover, -a.label:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} -.label:empty { - display: none; -} -.btn .label { - position: relative; - top: -1px; -} -.label-default { - background-color: #777777; -} -.label-default[href]:hover, -.label-default[href]:focus { - background-color: #5e5e5e; -} -.label-primary { - background-color: #337ab7; -} -.label-primary[href]:hover, -.label-primary[href]:focus { - background-color: #286090; -} -.label-success { - background-color: #5cb85c; -} -.label-success[href]:hover, -.label-success[href]:focus { - background-color: #449d44; -} -.label-info { - background-color: #5bc0de; -} -.label-info[href]:hover, -.label-info[href]:focus { - background-color: #31b0d5; -} -.label-warning { - background-color: #f0ad4e; -} -.label-warning[href]:hover, -.label-warning[href]:focus { - background-color: #ec971f; -} -.label-danger { - background-color: #d9534f; -} -.label-danger[href]:hover, -.label-danger[href]:focus { - background-color: #c9302c; -} - - -/*PANELS*/ -.badge { - display: inline-block; - min-width: 10px; - padding: 3px 7px; - font-size: 12px; - font-weight: bold; - color: #ffffff; - line-height: 1; - vertical-align: middle; - white-space: nowrap; - text-align: center; - background-color: #777777; - border-radius: 10px; -} -.badge:empty { - display: none; -} -.btn .badge { - position: relative; - top: -1px; -} -.btn-xs .badge, -.btn-group-xs > .btn .badge { - top: 0; - padding: 1px 5px; -} -a.badge:hover, -a.badge:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} -.list-group-item.active > .badge, -.nav-pills > .active > a > .badge { - color: #337ab7; - background-color: #ffffff; -} -.list-group-item > .badge { - float: right; -} -.list-group-item > .badge + .badge { - margin-right: 5px; -} -.nav-pills > li > a > .badge { - margin-left: 3px; -} - - - -/*PANELS*/ -.panel { - margin-bottom: 20px; - background-color: #ffffff; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); -} -.panel-body { - padding: 15px; -} -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-right-radius: 3px; - border-top-left-radius: 3px; -} -.panel-heading > .dropdown .dropdown-toggle { - color: inherit; -} -.panel-title { - margin-top: 0; - margin-bottom: 0; - font-size: 16px; - color: inherit; -} -.panel-title > a, -.panel-title > small, -.panel-title > .small, -.panel-title > small > a, -.panel-title > .small > a { - color: inherit; -} -.panel-footer { - padding: 10px 15px; - background-color: #f5f5f5; - border-top: 1px solid #dddddd; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .list-group, -.panel > .panel-collapse > .list-group { - margin-bottom: 0; -} -.panel > .list-group .list-group-item, -.panel > .panel-collapse > .list-group .list-group-item { - border-width: 1px 0; - border-radius: 0; -} -.panel > .list-group:first-child .list-group-item:first-child, -.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { - border-top: 0; - border-top-right-radius: 3px; - border-top-left-radius: 3px; -} -.panel > .list-group:last-child .list-group-item:last-child, -.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { - border-bottom: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { - border-top-right-radius: 0; - border-top-left-radius: 0; -} -.panel-heading + .list-group .list-group-item:first-child { - border-top-width: 0; -} -.list-group + .panel-footer { - border-top-width: 0; -} -.panel > .table, -.panel > .table-responsive > .table, -.panel > .panel-collapse > .table { - margin-bottom: 0; -} -.panel > .table caption, -.panel > .table-responsive > .table caption, -.panel > .panel-collapse > .table caption { - padding-left: 15px; - padding-right: 15px; -} -.panel > .table:first-child, -.panel > .table-responsive:first-child > .table:first-child { - border-top-right-radius: 3px; - border-top-left-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { - border-top-left-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { - border-top-right-radius: 3px; -} -.panel > .table:last-child, -.panel > .table-responsive:last-child > .table:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { - border-bottom-right-radius: 3px; -} -.panel > .panel-body + .table, -.panel > .panel-body + .table-responsive, -.panel > .table + .panel-body, -.panel > .table-responsive + .panel-body { - border-top: 1px solid #dddddd; -} -.panel > .table > tbody:first-child > tr:first-child th, -.panel > .table > tbody:first-child > tr:first-child td { - border-top: 0; -} -.panel > .table-bordered, -.panel > .table-responsive > .table-bordered { - border: 0; -} -.panel > .table-bordered > thead > tr > th:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, -.panel > .table-bordered > tbody > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, -.panel > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-bordered > thead > tr > td:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, -.panel > .table-bordered > tbody > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, -.panel > .table-bordered > tfoot > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; -} -.panel > .table-bordered > thead > tr > th:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, -.panel > .table-bordered > tbody > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, -.panel > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-bordered > thead > tr > td:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, -.panel > .table-bordered > tbody > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, -.panel > .table-bordered > tfoot > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; -} -.panel > .table-bordered > thead > tr:first-child > td, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, -.panel > .table-bordered > tbody > tr:first-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, -.panel > .table-bordered > thead > tr:first-child > th, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, -.panel > .table-bordered > tbody > tr:first-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { - border-bottom: 0; -} -.panel > .table-bordered > tbody > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, -.panel > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-bordered > tbody > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, -.panel > .table-bordered > tfoot > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { - border-bottom: 0; -} -.panel > .table-responsive { - border: 0; - margin-bottom: 0; -} -.panel-group { - margin-bottom: 20px; -} -.panel-group .panel { - margin-bottom: 0; - border-radius: 4px; -} -.panel-group .panel + .panel { - margin-top: 5px; -} -.panel-group .panel-heading { - border-bottom: 0; -} -.panel-group .panel-heading + .panel-collapse > .panel-body, -.panel-group .panel-heading + .panel-collapse > .list-group { - border-top: 1px solid #dddddd; -} -.panel-group .panel-footer { - border-top: 0; -} -.panel-group .panel-footer + .panel-collapse .panel-body { - border-bottom: 1px solid #dddddd; -} -.panel-default { - border-color: #dddddd; -} -.panel-default > .panel-heading { - color: #333333; - background-color: #f5f5f5; - border-color: #dddddd; -} -.panel-default > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #dddddd; -} -.panel-default > .panel-heading .badge { - color: #f5f5f5; - background-color: #333333; -} -.panel-default > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #dddddd; -} -.panel-primary { - border-color: #337ab7; -} -.panel-primary > .panel-heading { - color: #ffffff; - background-color: #337ab7; - border-color: #337ab7; -} -.panel-primary > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #337ab7; -} -.panel-primary > .panel-heading .badge { - color: #337ab7; - background-color: #ffffff; -} -.panel-primary > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #337ab7; -} -.panel-success { - border-color: #d6e9c6; -} -.panel-success > .panel-heading { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6; -} -.panel-success > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #d6e9c6; -} -.panel-success > .panel-heading .badge { - color: #dff0d8; - background-color: #3c763d; -} -.panel-success > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #d6e9c6; -} -.panel-info { - border-color: #bce8f1; -} -.panel-info > .panel-heading { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; -} -.panel-info > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #bce8f1; -} -.panel-info > .panel-heading .badge { - color: #d9edf7; - background-color: #31708f; -} -.panel-info > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #bce8f1; -} -.panel-warning { - border-color: #faebcc; -} -.panel-warning > .panel-heading { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; -} -.panel-warning > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #faebcc; -} -.panel-warning > .panel-heading .badge { - color: #fcf8e3; - background-color: #8a6d3b; -} -.panel-warning > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #faebcc; -} -.panel-danger { - border-color: #ebccd1; -} -.panel-danger > .panel-heading { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} -.panel-danger > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #ebccd1; -} -.panel-danger > .panel-heading .badge { - color: #f2dede; - background-color: #a94442; -} -.panel-danger > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #ebccd1; -} -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #f5f5f5; - border: 1px solid #e3e3e3; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -} -.well blockquote { - border-color: #ddd; - border-color: rgba(0, 0, 0, 0.15); -} -.well-lg { - padding: 24px; - border-radius: 6px; -} -.well-sm { - padding: 9px; - border-radius: 3px; -} diff --git a/docs/css/featherlight.min.css b/docs/css/featherlight.min.css deleted file mode 100644 index f225bec51..000000000 --- a/docs/css/featherlight.min.css +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Featherlight - ultra slim jQuery lightbox - * Version 1.2.3 - http://noelboss.github.io/featherlight/ - * - * Copyright 2015, Noël Raoul Bossart (http://www.noelboss.com) - * MIT Licensed. -**/ -@media all{.featherlight{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:2147483647;text-align:center;white-space:nowrap;cursor:pointer;background:#333;background:rgba(0,0,0,0)}.featherlight:last-of-type{background:rgba(0,0,0,.8)}.featherlight:before{content:'';display:inline-block;height:100%;vertical-align:middle;margin-right:-.25em}.featherlight .featherlight-content{position:relative;text-align:left;vertical-align:middle;display:inline-block;overflow:auto;padding:25px 25px 0;border-bottom:25px solid transparent;min-width:30%;margin-left:5%;margin-right:5%;max-height:95%;background:#fff;cursor:auto;white-space:normal}.featherlight .featherlight-inner{display:block}.featherlight .featherlight-close-icon{position:absolute;z-index:9999;top:0;right:0;line-height:25px;width:25px;cursor:pointer;text-align:center;font:Arial,sans-serif;background:#fff;background:rgba(255,255,255,.3);color:#000}.featherlight .featherlight-image{width:100%}.featherlight-iframe .featherlight-content{border-bottom:0;padding:0}.featherlight iframe{border:0}}@media only screen and (max-width:1024px){.featherlight .featherlight-content{margin-left:10px;margin-right:10px;max-height:98%;padding:10px 10px 0;border-bottom:10px solid transparent}} \ No newline at end of file diff --git a/docs/css/font-awesome.min.css b/docs/css/font-awesome.min.css deleted file mode 100644 index 540440ce8..000000000 --- a/docs/css/font-awesome.min.css +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/docs/css/horsey.css b/docs/css/horsey.css deleted file mode 100644 index 358f72d89..000000000 --- a/docs/css/horsey.css +++ /dev/null @@ -1,35 +0,0 @@ -.sey-list { - display: none; - position: absolute; - padding: 0; - margin: 0; - list-style-type: none; - box-shadow: 1px 2px 6px; - background-color: #fff; - color: #333; - transition: left 0.1s ease-in-out; - max-height: 70vh; - overflow: auto; - width: 265px; -} -.sey-show { - display: block; -} -.sey-hide { - display: none; -} -.sey-item { - cursor: pointer; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - padding: 7px; -} -.sey-item:hover { - background-color: #444; - color: #fff; -} -.sey-selected { - background-color: #333; - color: #fff; -} diff --git a/docs/css/hybrid.css b/docs/css/hybrid.css deleted file mode 100644 index 29735a189..000000000 --- a/docs/css/hybrid.css +++ /dev/null @@ -1,102 +0,0 @@ -/* - -vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid) - -*/ - -/*background color*/ -.hljs { - display: block; - overflow-x: auto; - padding: 0.5em; - background: #1d1f21; -} - -/*selection color*/ -.hljs::selection, -.hljs span::selection { - background: #373b41; -} - -.hljs::-moz-selection, -.hljs span::-moz-selection { - background: #373b41; -} - -/*foreground color*/ -.hljs { - color: #c5c8c6; -} - -/*color: fg_yellow*/ -.hljs-title, -.hljs-name { - color: #f0c674; -} - -/*color: fg_comment*/ -.hljs-comment, -.hljs-meta, -.hljs-meta .hljs-keyword { - color: #707880; -} - -/*color: fg_red*/ -.hljs-number, -.hljs-symbol, -.hljs-literal, -.hljs-deletion, -.hljs-link { - color: #cc6666 -} - -/*color: fg_green*/ -.hljs-string, -.hljs-doctag, -.hljs-addition, -.hljs-regexp, -.hljs-selector-attr, -.hljs-selector-pseudo { - color: #b5bd68; -} - -/*color: fg_purple*/ -.hljs-attribute, -.hljs-code, -.hljs-selector-id { - color: #b294bb; -} - -/*color: fg_blue*/ -.hljs-keyword, -.hljs-selector-tag, -.hljs-bullet, -.hljs-tag { - color: #81a2be; -} - -/*color: fg_aqua*/ -.hljs-subst, -.hljs-variable, -.hljs-template-tag, -.hljs-template-variable { - color: #8abeb7; -} - -/*color: fg_orange*/ -.hljs-type, -.hljs-built_in, -.hljs-builtin-name, -.hljs-quote, -.hljs-section, -.hljs-selector-class { - color: #de935f; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} diff --git a/docs/css/nucleus.css b/docs/css/nucleus.css deleted file mode 100644 index 073aa762a..000000000 --- a/docs/css/nucleus.css +++ /dev/null @@ -1,615 +0,0 @@ -*, *::before, *::after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; } - -@-webkit-viewport { - width: device-width; } -@-moz-viewport { - width: device-width; } -@-ms-viewport { - width: device-width; } -@-o-viewport { - width: device-width; } -@viewport { - width: device-width; } -html { - font-size: 100%; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; } - -body { - margin: 0; } - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -nav, -section, -summary { - display: block; } - -audio, -canvas, -progress, -video { - display: inline-block; - vertical-align: baseline; } - -audio:not([controls]) { - display: none; - height: 0; } - -[hidden], -template { - display: none; } - -a { - background: transparent; - text-decoration: none; } - -a:active, -a:hover { - outline: 0; } - -abbr[title] { - border-bottom: 1px dotted; } - -b, -strong { - font-weight: bold; } - -dfn { - font-style: italic; } - -mark { - background: #FFFF27; - color: #333; } - -sub, -sup { - font-size: 0.8rem; - line-height: 0; - position: relative; - vertical-align: baseline; } - -sup { - top: -0.5em; } - -sub { - bottom: -0.25em; } - -img { - border: 0; - max-width: 100%; } - -svg:not(:root) { - overflow: hidden; } - -figure { - margin: 1em 40px; } - -hr { - height: 0; } - -pre { - overflow: auto; } - -button, -input, -optgroup, -select, -textarea { - color: inherit; - font: inherit; - margin: 0; } - -button { - overflow: visible; } - -button, -select { - text-transform: none; } - -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; } - -button[disabled], -html input[disabled] { - cursor: default; } - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; } - -input { - line-height: normal; } - -input[type="checkbox"], -input[type="radio"] { - padding: 0; } - -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; } - -input[type="search"] { - -webkit-appearance: textfield; } - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; } - -legend { - border: 0; - padding: 0; } - -textarea { - overflow: auto; } - -optgroup { - font-weight: bold; } - -table { - border-collapse: collapse; - border-spacing: 0; - table-layout: fixed; - width: 100%; } - -tr, td, th { - vertical-align: middle; } - -th, td { - padding: 0.425rem 0; } - -th { - text-align: left; } - -.container { - width: 75em; - margin: 0 auto; - padding: 0; } - @media only all and (min-width: 60em) and (max-width: 74.938em) { - .container { - width: 60em; } } - @media only all and (min-width: 48em) and (max-width: 59.938em) { - .container { - width: 48em; } } - @media only all and (min-width: 30.063em) and (max-width: 47.938em) { - .container { - width: 30em; } } - @media only all and (max-width: 30em) { - .container { - width: 100%; } } - -.grid { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-flow: row; - -moz-flex-flow: row; - flex-flow: row; - list-style: none; - margin: 0; - padding: 0; } - @media only all and (max-width: 47.938em) { - .grid { - -webkit-flex-flow: row wrap; - -moz-flex-flow: row wrap; - flex-flow: row wrap; } } - -.block { - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - -webkit-flex: 1; - -moz-flex: 1; - -ms-flex: 1; - flex: 1; - min-width: 0; - min-height: 0; } - @media only all and (max-width: 47.938em) { - .block { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 100%; - -moz-flex: 0 100%; - -ms-flex: 0 100%; - flex: 0 100%; } } - -@media only all and (max-width: 47.938em) { - body [class*="size-"] { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 100%; - -moz-flex: 0 100%; - -ms-flex: 0 100%; - flex: 0 100%; } } - -.size-1-2 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 50%; - -moz-flex: 0 50%; - -ms-flex: 0 50%; - flex: 0 50%; } - -.size-1-3 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 33.33333%; - -moz-flex: 0 33.33333%; - -ms-flex: 0 33.33333%; - flex: 0 33.33333%; } - -.size-1-4 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 25%; - -moz-flex: 0 25%; - -ms-flex: 0 25%; - flex: 0 25%; } - -.size-1-5 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 20%; - -moz-flex: 0 20%; - -ms-flex: 0 20%; - flex: 0 20%; } - -.size-1-6 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 16.66667%; - -moz-flex: 0 16.66667%; - -ms-flex: 0 16.66667%; - flex: 0 16.66667%; } - -.size-1-7 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 14.28571%; - -moz-flex: 0 14.28571%; - -ms-flex: 0 14.28571%; - flex: 0 14.28571%; } - -.size-1-8 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 12.5%; - -moz-flex: 0 12.5%; - -ms-flex: 0 12.5%; - flex: 0 12.5%; } - -.size-1-9 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 11.11111%; - -moz-flex: 0 11.11111%; - -ms-flex: 0 11.11111%; - flex: 0 11.11111%; } - -.size-1-10 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 10%; - -moz-flex: 0 10%; - -ms-flex: 0 10%; - flex: 0 10%; } - -.size-1-11 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 9.09091%; - -moz-flex: 0 9.09091%; - -ms-flex: 0 9.09091%; - flex: 0 9.09091%; } - -.size-1-12 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 8.33333%; - -moz-flex: 0 8.33333%; - -ms-flex: 0 8.33333%; - flex: 0 8.33333%; } - -@media only all and (min-width: 48em) and (max-width: 59.938em) { - .size-tablet-1-2 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 50%; - -moz-flex: 0 50%; - -ms-flex: 0 50%; - flex: 0 50%; } - - .size-tablet-1-3 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 33.33333%; - -moz-flex: 0 33.33333%; - -ms-flex: 0 33.33333%; - flex: 0 33.33333%; } - - .size-tablet-1-4 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 25%; - -moz-flex: 0 25%; - -ms-flex: 0 25%; - flex: 0 25%; } - - .size-tablet-1-5 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 20%; - -moz-flex: 0 20%; - -ms-flex: 0 20%; - flex: 0 20%; } - - .size-tablet-1-6 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 16.66667%; - -moz-flex: 0 16.66667%; - -ms-flex: 0 16.66667%; - flex: 0 16.66667%; } - - .size-tablet-1-7 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 14.28571%; - -moz-flex: 0 14.28571%; - -ms-flex: 0 14.28571%; - flex: 0 14.28571%; } - - .size-tablet-1-8 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 12.5%; - -moz-flex: 0 12.5%; - -ms-flex: 0 12.5%; - flex: 0 12.5%; } - - .size-tablet-1-9 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 11.11111%; - -moz-flex: 0 11.11111%; - -ms-flex: 0 11.11111%; - flex: 0 11.11111%; } - - .size-tablet-1-10 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 10%; - -moz-flex: 0 10%; - -ms-flex: 0 10%; - flex: 0 10%; } - - .size-tablet-1-11 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 9.09091%; - -moz-flex: 0 9.09091%; - -ms-flex: 0 9.09091%; - flex: 0 9.09091%; } - - .size-tablet-1-12 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 8.33333%; - -moz-flex: 0 8.33333%; - -ms-flex: 0 8.33333%; - flex: 0 8.33333%; } } -@media only all and (max-width: 47.938em) { - @supports not (flex-wrap: wrap) { - .grid { - display: block; - -webkit-box-lines: inherit; - -moz-box-lines: inherit; - box-lines: inherit; - -webkit-flex-wrap: inherit; - -moz-flex-wrap: inherit; - -ms-flex-wrap: inherit; - flex-wrap: inherit; } - - .block { - display: block; - -webkit-box-flex: inherit; - -moz-box-flex: inherit; - box-flex: inherit; - -webkit-flex: inherit; - -moz-flex: inherit; - -ms-flex: inherit; - flex: inherit; } } } -.first-block { - -webkit-box-ordinal-group: 0; - -webkit-order: -1; - -ms-flex-order: -1; - order: -1; } - -.last-block { - -webkit-box-ordinal-group: 2; - -webkit-order: 1; - -ms-flex-order: 1; - order: 1; } - -.fixed-blocks { - -webkit-flex-flow: row wrap; - -moz-flex-flow: row wrap; - flex-flow: row wrap; } - .fixed-blocks .block { - -webkit-box-flex: inherit; - -moz-box-flex: inherit; - box-flex: inherit; - -webkit-flex: inherit; - -moz-flex: inherit; - -ms-flex: inherit; - flex: inherit; - width: 25%; } - @media only all and (min-width: 60em) and (max-width: 74.938em) { - .fixed-blocks .block { - width: 33.33333%; } } - @media only all and (min-width: 48em) and (max-width: 59.938em) { - .fixed-blocks .block { - width: 50%; } } - @media only all and (max-width: 47.938em) { - .fixed-blocks .block { - width: 100%; } } - -body { - font-size: 1.05rem; - line-height: 1.7; } - -h1, h2, h3, h4, h5, h6 { - margin: 0.85rem 0 1.7rem 0; - text-rendering: optimizeLegibility; } - -h1 { - font-size: 2.5rem; } - -h2 { - font-size: 2.55rem; } - -h3 { - font-size: 2.15rem; } - -h4 { - font-size: 1.8rem; } - -h5 { - font-size: 1.4rem; } - -h6 { - font-size: 0.9rem; } - -p { - margin: 1.7rem 0; } - -p.tableblock { - margin: 0; } - -ul, ol { - margin: 1rem 0; } - ul ul, ul ol, ol ul, ol ol { - margin-top: 0; - margin-bottom: 0; } - -blockquote { - margin: 1.7rem 0; - padding-left: 0.85rem; } - -cite { - display: block; - font-size: 0.925rem; } - cite:before { - content: "\2014 \0020"; } - -pre { - margin: 1.2rem 0; - padding: 0.938rem; } - -code { - vertical-align: bottom; } - -small { - font-size: 0.925rem; } - -hr { - border-left: none; - border-right: none; - border-top: none; - margin: 1.7rem 0; } - -fieldset { - border: 0; - padding: 0.938rem; - margin: 0 0 1.7rem 0; } - -input, -label, -select { - display: block; } - -label { - margin-bottom: 0.425rem; } - label.required:after { - content: "*"; } - label abbr { - display: none; } - -textarea, input[type="email"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="url"], input[type="color"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="month"], input[type="time"], input[type="week"], select[multiple=multiple] { - -webkit-transition: border-color; - -moz-transition: border-color; - transition: border-color; - border-radius: 0.1875rem; - margin-bottom: 0.85rem; - padding: 0.425rem 0.425rem; - width: 100%; } - textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus { - outline: none; } - -textarea { - resize: vertical; } - -input[type="checkbox"], input[type="radio"] { - display: inline; - margin-right: 0.425rem; } - -input[type="file"] { - width: 100%; } - -select { - width: auto; - max-width: 100%; - margin-bottom: 1.7rem; } - -button, -input[type="submit"] { - cursor: pointer; - user-select: none; - vertical-align: middle; - white-space: nowrap; - border: inherit; } - -/*# sourceMappingURL=nucleus.css.map */ diff --git a/docs/favicon.ico b/docs/favicon.ico deleted file mode 100644 index b30f559497be177547f5b312cbf359f646b310f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 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
  • 2a-ytx-(Y1%*Q`;e(V?9Smc22g?_xG~I&%zq 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≀A#j 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%0AHUW;|^l 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 diff --git a/docs/fonts/RobotoMono-Medium.ttf b/docs/fonts/RobotoMono-Medium.ttf deleted file mode 100644 index 0bcdc740c66c52cb33ca80ff854d9a1e8ecd4003..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113524 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 G*yFsbY~cLNXLP73aA74Mq6M9f^&YV`isWW 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

    5q!RY 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 - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/fonts/fontawesome-webfont.ttf b/docs/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2fa1196aad98c2adf4378a7611dd713aa3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165548 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 z 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 d0mRO}xo^G_%I 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 SdSQM28?+M|D(2r_;{O0|uQ74} diff --git a/docs/fonts/fontawesome-webfont.woff2 b/docs/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc60404b91e398a37200c4a77b645cfd9586..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77160 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 diff --git a/docs/fonts/glyphicons-halflings-regular.eot b/docs/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index b93a4953fff68df523aa7656497ee339d6026d64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20127 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/glyphicons-halflings-regular.ttf b/docs/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 1413fc609ab6f21774de0cb7e01360095584f65b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45404 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 G`u_lkUM?>H diff --git a/docs/fonts/glyphicons-halflings-regular.woff2 b/docs/fonts/glyphicons-halflings-regular.woff2 deleted file mode 100644 index 64539b54c3751a6d9adb44c8e3a45ba5a73b77f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18028 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 diff --git a/docs/getting-started/index.html b/docs/getting-started/index.html deleted file mode 100644 index 89268d56b..000000000 --- a/docs/getting-started/index.html +++ /dev/null @@ -1,443 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Getting Started :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -

    - - - - -
    -
    -
    - -
    - - - - - - - -
    -
    - -
    -
    - - -
    - - -
    - -

    Getting Started

    - - - - - - - - -
    -

    Latest Release: 2.1.0 2018-08-13

    -
    -
    -

    Examples are provided for the Kubernetes, OpenShift, and Docker environments in the -Kubernetes and OpenShift document.

    -
    -
    -

    For documentation relating to OpenShift Templates examples, visit the OpenShift Templates -document.

    -
    - - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/getting-started/index.xml b/docs/getting-started/index.xml deleted file mode 100644 index 0f7b84ca3..000000000 --- a/docs/getting-started/index.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - Getting Started on Crunchy Data Container Suite Documentation - https://crunchydata.github.io/crunchy-containers/getting-started/ - Recent content in Getting Started on Crunchy Data Container Suite Documentation - Hugo -- gohugo.io - en-us - Tue, 08 May 2018 08:56:03 -0700 - - - - - - \ No newline at end of file diff --git a/docs/getting-started/kubernetes-and-openshift/index.html b/docs/getting-started/kubernetes-and-openshift/index.html deleted file mode 100644 index e091a2924..000000000 --- a/docs/getting-started/kubernetes-and-openshift/index.html +++ /dev/null @@ -1,4137 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Kubernetes and Openshift :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
    - - - - -
    -
    -
    - -
    - - - - - - - -
    -
    - -
    -
    - - -
    - - -
    - -

    Kubernetes and Openshift

    - - - - - - - - - -
    -

    Latest Release: 2.1.0 2018-08-13

    -
    -
    -

    Getting Started

    -
    -
    -
    -

    The examples located in the kube directory work on both Kubernetes and OpenShift. Ensure the CCP_CLI environment variable -is set to the correct binary for your environment.

    -
    -
    - -
    -
    -

    Set the environment variable in .bashrc to ensure the examples will work in your environment.

    -
    -
    -
    -
    # Kubernetes
    -export CCP_CLI=kubectl
    -
    -# OpenShift
    -export CCP_CLI=oc
    -
    -
    -
    -

    Here are some useful resources for finding the right commands to troubleshoot & modify containers in -the various environments shown in this guide:

    -
    - -
    -
    -
    -

    Example Conventions

    -
    -
    -

    The examples provided in Container Suite are simple examples that -are meant to demonstrate key Container Suite features. These -examples can be used to build more production level deployments -as dictated by user requirements specific to their operating -environments.

    -
    -
    -

    The examples generally follow these conventions:

    -
    -
    -
      -
    • -

      There is a run.sh script that you will execute to start the example.

      -
    • -
    • -

      There is a cleanup.sh script that you will execute to shutdown and cleanup the example.

      -
    • -
    • -

      Each example will create resources such as Secrets, ConfigMaps, Services, and PersistentVolumeClaims, all which follow a naming convention of <example name>-<optional description suffix>. For example an example called primary might have a PersistentVolumeClaim called primary-pgconf to describe the purpose of that particular PVC.

      -
    • -
    • -

      The folder names for each example give a clue as to which Container Suite feature it demonstrates. For instance, the examples/kube/pgaudit example demonstrates how to enable the pg_audit capability of the crunchy-postgres container.

      -
    • -
    -
    -
    -
    -
    -

    Administration

    -
    -
    -

    Password Management

    -
    -

    The passwords used for the PostgreSQL user accounts are generated -by the OpenShift process command. To inspect what value is -supplied, you can inspect the primary pod as follows:

    -
    -
    -
    -
    ${CCP_CLI} get pod pr-primary -o json | grep -C 1 'PG_USER\|PG_PASSWORD\|PG_DATABASE'
    -
    -
    -
    -

    This will give you the environment variable values for the database created by default -in addition to the username and password of the standard user.

    -
    -
    -
      -
    • -

      PG_USER

      -
    • -
    • -

      PG_PASSWORD

      -
    • -
    • -

      PG_DATABASE

      -
    • -
    -
    -
    -
    -

    Kubernetes Secrets

    -
    -

    You can use Kubernetes Secrets to set and maintain your database -credentials. Secrets requires you base64 encode your user and password -values as follows:

    -
    -
    -
    -
    echo -n 'myuserid' | base64
    -
    -
    -
    -

    You will paste these values into your JSON secrets files for values.

    -
    -
    -

    This example allows you to set the PostgreSQL passwords -using Kubernetes Secrets.

    -
    -
    -

    The secret uses a base64 encoded string to represent the -values to be read by the container during initialization. The -encoded password value is password. Run the example -as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/secret
    -./run.sh
    -
    -
    -
    -

    The secrets are mounted in the /pguser, /pgprimary, and /pgroot volumes within the -container and read during initialization. The container -scripts create a PostgreSQL user with those values, and sets the passwords -for the primary user and PostgreSQL superuser using the mounted secret volumes.

    -
    -
    -

    When using secrets, you do NOT have to specify the following -environment variables if you specify all three secrets volumes:

    -
    -
    -
      -
    • -

      PG_USER

      -
    • -
    • -

      PG_PASSWORD

      -
    • -
    • -

      PG_ROOT_PASSWORD

      -
    • -
    • -

      PG_PRIMARY_USER

      -
    • -
    • -

      PG_PRIMARY_PASSWORD

      -
    • -
    -
    -
    -

    You can test the container as follows. In all cases, the password is password:

    -
    -
    -
    -
    psql -h secret -U pguser1 postgres
    -psql -h secret -U postgres postgres
    -psql -h secret -U primaryuser postgres
    -
    -
    -
    -
    -

    pgAdmin4

    -
    -

    This example deploys the pgadmin4 v2 web user interface -for PostgreSQL without TLS.

    -
    -
    -

    After running the example, you should be able to browse to http://127.0.0.1:5050 -and log into the web application using a user ID of admin@admin.com -and password of password.

    -
    -
    -

    If you are running this example using Kubernetes or -OpenShift, replace 127.0.0.1:5050 with the <NODE_IP>:30000.

    -
    -
    -

    To get the node IP, run the following:

    -
    -
    -
    -
    ${CCP_CLI} describe pod pgadmin4-http | grep Node:
    -
    -
    -
    -

    See the pgAdmin4 documentation for more details.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    To run this example, run the following:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/pgadmin4-http
    -./run.sh
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Start the container as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/pgadmin4-http
    -./run.sh
    -
    -
    -
    -
    -

    An emptyDir with write access must be mounted to the /run/httpd directory in OpenShift.

    -
    -
    - -
    -
    -
    -
    -

    pgAdmin4 with TLS

    -
    -

    This example deploys the pgadmin4 v2 web user interface -for PostgreSQL with TLS.

    -
    -
    -

    After running the example, you should be able to browse to https://127.0.0.1:5050 -and log into the web application using a user ID of admin@admin.com -and password of password.

    -
    -
    -

    If you are running this example using Kubernetes or -OpenShift, replace 127.0.0.1:5050 with the <NODE_IP>:30000.

    -
    -
    -

    To get the node IP, run the following:

    -
    -
    -
    -
    ${CCP_CLI} describe pod pgadmin4-https | grep Node:
    -
    -
    -
    -

    See the pgadmin4 documentation for more details.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    To run this example, run the following:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/pgadmin4-https
    -./run.sh
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Start the container as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/pgadmin4-https
    -./run.sh
    -
    -
    -
    -
    -

    An emptyDir with write access must be mounted to the /run/httpd directory in OpenShift.

    -
    -
    - -
    -
    -
    -
    -

    Upgrade

    -
    -
    -

    This example assumes you have run primary using a PG 9.5 or 9.6 image -such as centos7-9.5.14-2.1.0 prior to running this upgrade.

    -
    -
    - -
    -
    -

    Starting in release 1.3.1, the upgrade container will let -you perform a pg_upgrade either from a PostgreSQL version 9.5 database to -9.6 or from 9.6 to 10.

    -
    -
    -

    Prior to running this example, make sure your CCP_IMAGE_TAG -environment variable is using the next major version of PostgreSQL that you -want to upgrade to. For example, if you’re upgrading from 9.5 to 9.6, make -sure the variable references a PG 9.6 image such as centos7-9.6.10-2.1.0.

    -
    -
    -

    This will create the following in your Kubernetes environment:

    -
    -
    -
      -
    • -

      a Kubernetes Job running the crunchy-upgrade container

      -
    • -
    • -

      a new data directory name upgrade found in the pgnewdata PVC

      -
    • -
    -
    -
    -
    -

    Data checksums on the Crunchy PostgreSQL container were enabled by default in version 2.1.0. -When trying to upgrade, it’s required that both the old database and the new database -have the same data checksums setting. Prior to upgrade, check if data_checksums -were enabled on the database by running the following SQL: SHOW data_checksums

    -
    -
    - -
    -
    -

    Kubernetes and OpenShift

    -
    -
    -

    Before running the example, ensure you edit upgrade.json and update the OLD_VERSION -and NEW_VERSION parameters to the ones relevant to your situation.

    -
    -
    - -
    -
    -

    Start the upgrade as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/upgrade
    -./run.sh
    -
    -
    -
    -

    If successful, the Job will end with a successful status. Verify -the results of the Job by examining the Job’s pod log:

    -
    -
    -
    -
    ${CCP_CLI} get pod -l job-name=upgrade
    -${CCP_CLI} logs -l job-name=upgrade
    -
    -
    -
    -

    You can verify the upgraded database by running the post-upgrade.sh script in the -examples/kube/upgrade directory. This will create a PostgreSQL pod that mounts the -upgraded volume.

    -
    -
    -
    -
    -

    Cron Scheduler

    -
    -

    The crunchy-dba container implements a cron scheduler. The purpose of the crunchy-dba -container is to offer a way to perform simple DBA tasks that occur on some form of -schedule such as backup jobs or running a vacuum on a single PostgreSQL database container -(such as the primary example).

    -
    -
    -

    You can either run the crunchy-dba container as a single pod or include the container -within a database pod.

    -
    -
    -

    The crunchy-dba container makes use of a Service Account to perform the startup of -scheduled jobs. The Kubernetes Job type is used to execute the scheduled jobs with a Restart -policy of Never.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    The script to schedule vacuum on a regular schedule is executed through the following -commands:

    -
    -
    -
    -
    # Kubernetes
    -cd $CCPROOT/examples/kube/dba
    -./run-kube-vac.sh
    -
    -# OpenShift
    -cd $CCPROOT/examples/kube/dba
    -./run-ocp-vac.sh
    -
    -
    -
    -

    To run the script for scheduled backups, run the following in the same directory:

    -
    -
    -
    -
    # Kubernetes
    -cd $CCPROOT/examples/kube/dba
    -./run-kube-backup.sh
    -
    -# OpenShift
    -cd $CCPROOT/examples/kube/dba
    -./run-ocp-backup.sh
    -
    -
    -
    -

    Individual parameters for both can be modified within their respective JSON files; -please see the Container Specifications document for a full list of what can be modified.

    -
    -
    -
    -
    -

    Vacuum

    -
    -

    You can perform a PostgreSQL vacuum command by running the crunchy-vacuum -container. You specify a database to vacuum using environment variables. By default, -vacuum is executed against the primary example container.

    -
    -
    -

    The crunchy-vacuum container image exists to allow a DBA a way to run a job either -individually or scheduled to perform a variety of vacuum operations.

    -
    -
    -

    This example performs a vacuum on a single table in the primary PostgreSQL -database. The crunchy-vacuum image is executed with the PostgreSQL connection -parameters to the single-primary PostgreSQL container. The type of vacuum performed is -dictated by the environment variables passed into the job; these are defined with further detail -here.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    Run the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/vacuum
    -./run.sh
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/vacuum/
    -./run.sh
    -
    -
    -
    -

    Verify the job is completed:

    -
    -
    -
    -
    ${CCP_CLI} get job
    -
    -
    -
    -
    -
    -

    systemd

    -
    -

    The crunchy-pg.service is an example of a systemd unit file -that starts and stops a container named crunchy-pg that -has already been created.

    -
    -
    -

    The example scripts are located in the following directory:

    -
    -
    -
    -
    $CCPROOT/examples/systemd/
    -
    -
    -
    -

    There are two scripts within the directory.

    -
    -
    -
    -
    test-start.sh
    -
    -
    -
    -

    This script is called by the systemd start execution. The trick -with this script is that it blocks forever after starting the -docker crunchy-pg container. The blocking in the script -keeps systemd happy and thinking that this is a normal daemon.

    -
    -
    -
    -
    test-stop.sh
    -
    -
    -
    -

    This script stops the test-start.sh script and also stops the -crunchy-pg Docker container.

    -
    -
    -
    -
    -
    -

    Backup and Restoration

    -
    -
    -

    pg_dump

    -
    -

    The script assumes you are going to backup the primary example and that container -is running.

    -
    -
    -

    This example assumes you have configured a storage filesystem as described -in the Storage Configuration document.

    -
    -
    -

    A successful backup will perform pg_dump/pg_dumpall on the primary and store -the resulting files in the mounted volume under a directory named <HOSTNAME>-backups -as a sub-directory, then followed by a unique backup directory based upon a -date and timestamp - allowing any number of backups to be kept.

    -
    -
    -

    For more information on how to configure this container, please see the Container Specifications document.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    Run the backup with this command:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/pgdump
    -./run.sh
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/pgdump
    -./run.sh
    -
    -
    -
    -

    The Kubernetes Job type executes a pod and then the pod exits. You can -view the Job status using this command:

    -
    -
    -
    -
    ${CCP_CLI} get job
    -
    -
    -
    -

    The pgdump.json file within that directory specifies options that control the behavior of the pgdump job. -Examples of this include whether to run pg_dump vs pg_dumpall and advanced options for specific backup use cases.

    -
    -
    -
    -
    -

    pg_restore

    -
    -

    The script assumes you are going to restore to the primary example and that container -is running and a backup has been created using the pgdump example..

    -
    -
    -

    This example assumes you have configured a storage filesystem as described -in the Storage Configuration document.

    -
    -
    -

    Successful use of the crunchy-pgrestore container will run a job to restore files generated by -pg_dump/pg_dumpall to a container via psql/pg_restore; then container will terminate successfully -and signal job completion.

    -
    -
    -

    For more information on how to configure this container, please see the Container Specifications document.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    Run the restore with this command:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/pgrestore
    -./run.sh
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    By default, pgrestore container will automatically restore from the most recent backup. -If you want to restore to a specific backup, edit the pgrestore.json file and update the -PGRESTORE_BACKUP_TIMESTAMP setting to specify the backup path you want to restore with. For example:

    -
    -
    -
    -
    "name":"PGRESTORE_BACKUP_TIMESTAMP",
    -"value":"2018-03-27-14-35-33"
    -
    -
    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/pgrestore
    -./run.sh
    -
    -
    -
    -

    The Kubernetes Job type executes a pod and then the pod exits. You can -view the Job status using this command:

    -
    -
    -
    -
    ${CCP_CLI} get job
    -
    -
    -
    -

    The pgrestore.json file within that directory specifies options that control the behavior of the pgrestore job.

    -
    -
    -
    -
    -

    pgBackRest

    -
    -

    pgbackrest is a utility that performs a backup, restore, and archive -function for a PostgreSQL database. pgbackrest is written and -maintained by David Steele, and more information can be found on the -official website.

    -
    -
    -

    Backups are currently performed by manually executing pgbackrest commands against the desired pod. -Restores can now be performed via the crunchy-backrest-restore container, which offers FULL or -DELTA restore capability.

    -
    -
    -

    pgbackrest is configured using a pgbackrest.conf file that is -mounted into the crunchy-postgres container at /pgconf.

    -
    -
    -

    If you place a pgbackrest.conf file within this mounted directory, it -will trigger the use of pgbackrest within the PostgreSQL container -as the archive_command and will turn on the archive_mode to begin -archival. It is still required to define the ARCHIVE_TIMEOUT environment -variable within your container configuration as it is set to -a disable value of 0 by default.

    -
    -
    -

    The following changes will be made to the container’s postgresql.conf -file:

    -
    -
    -
    -
    ARCHIVE_MODE=on
    -ARCHIVE_TIMEOUT=60
    -ARCHIVE_COMMAND='pgbackrest --stanza=db archive-push %p'
    -
    -
    -
    -

    If you are using a crunchy-postgres image older than 1.7.1, archive_command must specify where -the pgbackrest.conf file is located:

    -
    -
    -
    -
    ARCHIVE_COMMAND='pgbackrest --config=/pgconf/pgbackrest.conf --stanza=db archive-push %p'
    -
    -
    -
    -
    -

    This requires you use a pgbackrest stanza name of db within the -pgbackrest.conf file you mount.

    -
    -
    - -
    -
    -

    When set, WAL files generated by the database will be written -out to the /backrestrepo/HOSTNAME-backups mount point.

    -
    -
    -

    Additionally, the Crunchy Postgres container can templatize pgbackrest.conf files -by searching for the HOSTNAME values in a mounted pgbackrest.conf file.

    -
    -
    -

    For example, db-path=/pgdata/HOSTNAME will render to db-path=/pgdata/primary if -the container’s hostname is primary. HOSTNAME will be replaced with the value of -PGDATA_PATH_OVERRIDE when working with deployments/replicasets.

    -
    -
    -
    -

    The templating example above works for db-path settings, however, repo-path should -follow the convention repo-path=/backrestrepo/HOSTNAME-backups in cases where -volumes are being mounted to a single mount point (such as hostPath or NFS). Without -the additional -backups the backups will populate in the pgdata directory.

    -
    -
    - -
    -
    -

    Kubernetes and OpenShift

    -
    -
    Backup
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/backup
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Kubernetes environment:

    -
    -
    -
      -
    • -

      configMap containing pgbackrest.conf

      -
    • -
    • -

      PostgreSQL pod with pgBackRest configured

      -
    • -
    • -

      PostgreSQL service

      -
    • -
    • -

      PVC for the PGDATA directory

      -
    • -
    • -

      PVC for the BackRest Backups and Archives directory

      -
    • -
    -
    -
    -

    Examine the /backrestrepo location to view the archive directory and ensure WAL archiving is working.

    -
    -
    -

    You can create a backup using backrest using this command within the container:

    -
    -
    -
    -
    ${CCP_CLI} exec -it backrest /bin/bash
    -pgbackrest --stanza=db backup --type=full
    -
    -
    -
    -
    -
    Async Archiving
    -
    -

    pgBackRest supports asyncronous archiving to pull and push Write Ahead Logs. -Asynchronous operation is more efficient because it can reuse connections and take -advantage of parallelism. For more information on async archiving, see the pgBackRest -official documentation.

    -
    -
    -

    This will create the following in your Kubernetes environment:

    -
    -
    -
      -
    • -

      configMap containing pgbackrest.conf

      -
    • -
    • -

      PostgreSQL pod with pgBackRest configured and archiving asynchronously.

      -
    • -
    • -

      PostgreSQL service

      -
    • -
    • -

      PVC for the PGDATA directory

      -
    • -
    • -

      PVC for the BackRest Backups and Archives directory

      -
    • -
    -
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/async-archiving
    -./run.sh
    -
    -
    -
    -

    Examine the /backrestrepo/HOSTNAME-backups location to view the archive directory -and ensure WAL archiving is working.

    -
    -
    -

    Examine the /pgdata/HOSTNAME-spool location to view the transient directory -used for async archiving.

    -
    -
    -

    You can create a backup using backrest using this command within the container:

    -
    -
    -
    -
    ${CCP_CLI} exec -it backrest-async-archive /bin/bash
    -pgbackrest --stanza=db backup
    -
    -
    -
    -
    -

    A spooling directory is automatically created in both /pgdata and /pgwal. It is -advised to configure pgBackRest to use the spooling location closest to the Write Ahead Log.

    -
    -
    -

    If the PostgreSQL container was created using the XLOGDIR variable, the /pgwal/HOSTNAME-spool -directory should be configured in pgbackrest.conf as such: spool-path=/pgwal/HOSTNAME-spool. -If WAL resides on PGDATA, use: spool-path=/pgdata/HOSTNAME-spool

    -
    -
    - -
    -
    -
    -
    -

    Restore

    -
    -

    There are three options to choose from when performing a restore:

    -
    -
    -
      -
    • -

      Delta - only restore missing files from PGDATA

      -
    • -
    • -

      Full - restore all files, pgdata must be empty

      -
    • -
    • -

      Point in Time Recovery (PITR) - delta restore to a certain point in time

      -
    • -
    -
    -
    -
    PITR
    -
    -
    -

    This example uses the backrest/backup example. It should be left running and a -pgBackRest backup has been created.

    -
    -
    - -
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/pitr
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Kubernetes environment:

    -
    -
    -
      -
    • -

      configMap containing pgbackrest.conf

      -
    • -
    • -

      Backrest-Restore pod with pgBackRest configured for PITR restore

      -
    • -
    -
    -
    -

    pgBackRest will restore the pgdata volume mounted to the restore container -to the point in time specified by the PITR_TARGET environment variable. To get -a compliant timestamp, PostgreSQL can be queried using the following SQL:

    -
    -
    -
    -
    psql -U postgres -Atc 'select current_timestamp'
    -
    -
    -
    -

    After a successful restore, run the following to start the restored PostgreSQL container:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/pitr
    -./post-restore.sh
    -
    -
    -
    -
    -
    Full
    -
    -
    -

    This example uses the backrest/backup example. It does not need to be running but a -pgBackRest backup is required.

    -
    -
    - -
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/full
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Kubernetes environment:

    -
    -
    -
      -
    • -

      configMap containing pgbackrest.conf

      -
    • -
    • -

      Backrest-Restore pod with pgBackRest configured for full restore

      -
    • -
    • -

      New PVC for the PGDATA directory (full restores require PGDATA to be empty)

      -
    • -
    -
    -
    -

    pgBackRest will restore all files to the pgdata volume mounted to the restore container.

    -
    -
    -

    After a successful restore, run the following to start the restored PostgreSQL container:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/full
    -./post-restore.sh
    -
    -
    -
    -
    -
    Delta
    -
    -
    -

    This example uses the backrest/backup example. It does not need to be running but a -pgBackRest backup is required.

    -
    -
    - -
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/delta
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Kubernetes environment:

    -
    -
    -
      -
    • -

      configMap containing pgbackrest.conf

      -
    • -
    • -

      Backrest-Restore pod with pgBackRest configured for full restore

      -
    • -
    -
    -
    -

    pgBackRest will restore files missing to the pgdata volume mounted to the restore container.

    -
    -
    -

    After a successful restore, run the following to start the restored PostgreSQL container:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/delta
    -./post-restore.sh
    -
    -
    -
    -
    -
    -

    Docker

    -
    -
    Backup
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/backrest/backup
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Docker environment:

    -
    -
    -
      -
    • -

      PostgreSQL container with pgBackRest configured

      -
    • -
    • -

      Volume for the PGDATA directory

      -
    • -
    • -

      Volume for the pgbackrest.conf configuration

      -
    • -
    • -

      Volume for the BackRest Backups and Archives directory

      -
    • -
    -
    -
    -

    Examine the /backrestrepo location to view the archive directory and ensure WAL archiving is working.

    -
    -
    -

    You can create a backup using backrest using this command within the container:

    -
    -
    -
    -
    docker exec -it backrest /bin/bash
    -pgbackrest --stanza=db backup --type=full
    -
    -
    -
    -
    -
    Async Archiving
    -
    -

    This will create the following in your Docker environment:

    -
    -
    -
      -
    • -

      PostgreSQL container with pgBackRest configured

      -
    • -
    • -

      Volume for the PGDATA directory

      -
    • -
    • -

      Volume for the pgbackrest.conf configuration

      -
    • -
    • -

      Volume for the BackRest Backups and Archives directory

      -
    • -
    -
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/backrest/async-archiving
    -./run.sh
    -
    -
    -
    -

    Examine the /backrestrepo/HOSTNAME-backups location to view the archive directory -and ensure WAL archiving is working.

    -
    -
    -

    Examine the /pgdata/HOSTNAME-spool location to view the transient directory -used for async archiving.

    -
    -
    -

    You can create a backup using backrest using this command within the container:

    -
    -
    -
    -
    docker exec -it backrest /bin/bash
    -pgbackrest --stanza=db backup
    -
    -
    -
    -
    -

    A spooling directory is automatically created in both /pgdata and /pgwal. It is -advised to configure pgBackRest to use the spooling location closest to the Write Ahead Log.

    -
    -
    -

    If the PostgreSQL container was created using the XLOGDIR variable, the /pgwal/HOSTNAME-spool -directory should be configured in pgbackrest.conf as such: spool-path=/pgwal/HOSTNAME-spool. -If WAL resides on PGDATA, use: spool-path=/pgdata/HOSTNAME-spool

    -
    -
    - -
    -
    -
    -
    -

    Restore

    -
    -
    PITR
    -
    -
    -

    This example uses the backrest/backup example. It should be left running and a -pgBackRest backup has been created.

    -
    -
    - -
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/backrest/pitr
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Docker environment:

    -
    -
    -
      -
    • -

      Backrest-Restore container with pgBackRest configured for PITR restore

      -
    • -
    -
    -
    -

    pgBackRest will restore the pgdata volume mounted to the restore container -to the point in time specified by the PITR_TARGET environment variable. To get -a compliant timestamp, PostgreSQL can be queried using the following SQL:

    -
    -
    -
    -
    psql -U postgres -Atc 'select current_timestamp'
    -
    -
    -
    -

    After a successful restore, run the following to start the restored PostgreSQL container:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/backrest/pitr
    -./post-restore.sh
    -
    -
    -
    -
    -
    Full
    -
    -
    -

    This example uses the backrest/backup example. It does not need to be running but a -pgBackRest backup is required.

    -
    -
    - -
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/backrest/full
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Docker environment:

    -
    -
    -
      -
    • -

      Backrest-Restore pod with pgBackRest configured for full restore

      -
    • -
    • -

      New Volume for the PGDATA directory (full restores require PGDATA to be empty)

      -
    • -
    -
    -
    -

    pgBackRest will restore all files to the pgdata volume mounted to the restore container.

    -
    -
    -

    After a successful restore, run the following to start the restored PostgreSQL container:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/backrest/full
    -./post-restore.sh
    -
    -
    -
    -
    -
    Delta
    -
    -
    -

    This example uses the backrest/backup example. It does not need to be running but a -pgBackRest backup is required.

    -
    -
    - -
    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/delta
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Docker environment:

    -
    -
    -
      -
    • -

      Backrest-Restore pod with pgBackRest configured for full restore

      -
    • -
    -
    -
    -

    pgBackRest will restore files missing to the pgdata volume mounted to the restore container.

    -
    -
    -

    After a successful restore, run the following to start the restored PostgreSQL container:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backrest/delta
    -./post-restore.sh
    -
    -
    -
    -
    -
    -
    -

    pgBackRest with SSHD

    -
    -

    The PostgreSQL and PostgreSQL GIS containers can enable an SSH daemon to allow developers -to do DBA tasks on the database server without the need for exec privileges. An administrator -who deploys the SSHD enabled PostgreSQL database can specify the authorized public keys for -access to the database server.

    -
    -
    -

    In order to activate SSHD in the PostgreSQL containers, the following files need to be -mounted to the PostgreSQL container:

    -
    -
    -
      -
    • -

      SSH Host keys mounted on the /sshd volume. Three keys are required:

      -
      -
        -
      • -

        ssh_host_rsa_key

        -
      • -
      • -

        ssh_host_ecdsa_key

        -
      • -
      • -

        ssh_host_ed25519_key

        -
      • -
      -
      -
    • -
    • -

      sshd_config mounted on the /pgconf volume

      -
    • -
    • -

      authorized_keys mounted on the /pgconf volume

      -
    • -
    -
    -
    -

    SSHD can be enabled in the PostgreSQL containers by adding the following line:

    -
    -
    -
    -
    ENABLE_SSHD=true
    -
    -
    -
    -

    The authorized_keys file is mounted on the /pgconf directory. In order to support -using this mount for authentication the following must be set in sshd_config:

    -
    -
    -
    -
    AuthorizedKeysFile /pgconf/authorized_keys
    -StrictModes no
    -
    -
    -
    -

    For OpenShift deployments, the following configuration needs to be set in sshd_config:

    -
    -
    -
    -
    UsePAM no
    -
    -
    -
    -

    Docker

    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/postgres-sshd
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Docker environment:

    -
    -
    -
      -
    • -

      A volume named pgconf which contains the pgbackrest.conf, pg_hba.conf, postgresql.conf, sshd_config, authorized_keys file

      -
    • -
    • -

      A volume named sshd containing the SSH Host keys

      -
    • -
    • -

      postgres-sshd container pgbackrest archive and sshd enabled. An initial stanza db will be created on initialization

      -
    • -
    -
    -
    -

    After running the example, SSH to the container using the forwarded port 2022:

    -
    -
    -
    -
    ssh -i ./keys/id_rsa -p 2022 postgres@0.0.0.0
    -
    -
    -
    -
    -

    Kubernetes / OpenShift

    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/postgres-sshd
    -./run.sh
    -
    -
    -
    -

    This will create the following in your Kubernetes environment:

    -
    -
    -
      -
    • -

      A configMap named pgconf which contains the pgbackrest.conf, pg_hba.conf, postgresql.conf, sshd_config, authorized_keys file

      -
    • -
    • -

      A secret named sshd-secrets containing the SSH Host keys

      -
    • -
    • -

      postgres-sshd pod with pgbackrest archive and sshd enabled. An initial stanza db will be created on initialization

      -
    • -
    • -

      postgres-sshd service with port 2022 for SSH

      -
    • -
    -
    -
    -

    After running the example, SSH to the service using the postgres-sshd service available in Kubernetes:

    -
    -
    -
    -
    ssh -i ./keys/id_rsa -p 2022 postgres@postgres-sshd
    -
    -
    -
    -
    -

    Using pgBackrest via SSH

    -
    -

    If a pgbackrest.conf file is located on the /pgconf volume and archiving is enabled, it’s possible to -run backups using the pgBackrest utility.

    -
    -
    -

    With the SSHD service running, the following command will issue a pgBackrest backup.

    -
    -
    -
    -
    ssh -i ./keys/id_rsa -p 2022 postgres@postgres-sshd pgbackrest --stanza=db backup
    -
    -
    -
    -

    To list all the available pgBackrest backups, run the following:

    -
    -
    -
    -
    ssh -i ./keys/id_rsa -p 2022 postgres@postgres-sshd pgbackrest info
    -
    -
    -
    -
    -
    -

    pg_basebackup

    -
    -

    The script assumes you are going to backup the primary -container created in the first example, so you need to ensure -that container is running. This example assumes you have configured storage as described -in the Storage Configuration documentation. Things to point out with this example -include its use of persistent volumes and volume claims to store the backup data files.

    -
    -
    -

    A successful backup will perform pg_basebackup on the primary container and store -the backup in the $CCP_STORAGE_PATH volume under a directory named primary-backups. Each -backup will be stored in a subdirectory with a timestamp as the name, allowing any number of backups to be kept.

    -
    -
    -

    The backup script will do the following:

    -
    -
    -
      -
    • -

      Start up a backup container named backup

      -
    • -
    • -

      Run pg_basebackup on the container named primary

      -
    • -
    • -

      Store the backup in the /tmp/backups/primary-backups directory

      -
    • -
    • -

      Exit after the backup

      -
    • -
    -
    -
    -

    When you are ready to restore from the backup, the restore example runs a PostgreSQL container -using the backup location. Upon initialization, the container will use rsync to copy the backup -data to this new container and then launch PostgreSQL using the original backed-up data.

    -
    -
    -

    The restore script will do the following:

    -
    -
    -
      -
    • -

      Start up a container named restore

      -
    • -
    • -

      Copy the backup files from the previous backup example into /pgdata

      -
    • -
    • -

      Start up the container using the backup files

      -
    • -
    • -

      Map the PostgreSQL port of 5432 in the container to your local host port of 12001

      -
    • -
    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    Run the backup with this command:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/backup
    -./run.sh
    -
    -
    -
    -

    When you’re ready to restore, a restore example is provided.

    -
    -
    -

    It’s required to specified a backup path for this example. To get the correct path -check the backup job logs or a timestamp:

    -
    -
    -
    -
    docker logs backup-vpk9l | grep BACKUP_PATH
    -Wed May  9 20:32:00 UTC 2018 INFO: BACKUP_PATH is set to /pgdata/primary-backups/2018-05-09-20-32-00.
    -
    -
    -
    -

    BACKUP_PATH can also be discovered by looking at the backup mount directly (if access -to the storage is available to the user).

    -
    -
    -

    An example of BACKUP_PATH is as followed:

    -
    -
    -
    -
    "name": "BACKUP_PATH",
    -"value": "primary-backups/2018-05-09-20-32-00"
    -
    -
    -
    -

    When you are ready to restore from the backup created, run the following example:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/restore
    -./run.sh
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/backup
    -./run.sh
    -
    -
    -
    -

    The Kubernetes Job type executes a pod and then the pod exits. You can -view the Job status using this command:

    -
    -
    -
    -
    ${CCP_CLI} get job
    -
    -
    -
    -

    When you’re ready to restore, a restore example is provided.

    -
    -
    -

    It’s required to specified a backup path for this example. To get the correct path -check the backup job logs or a timestamp:

    -
    -
    -
    -
    kubectl logs backup-vpk9l | grep BACKUP_PATH
    -Wed May  9 20:32:00 UTC 2018 INFO: BACKUP_PATH is set to /pgdata/primary-backups/2018-05-09-20-32-00.
    -
    -
    -
    -

    BACKUP_PATH can also be discovered by looking at the backup mount directly (if access -to the storage is available to the user).

    -
    -
    -

    An example of BACKUP_PATH defined as a variable within the JSON script is as follows:

    -
    -
    -
    -
    "name": "BACKUP_PATH",
    -"value": "primary-backups/2018-05-09-20-32-00"
    -
    -
    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/restore
    -./run.sh
    -
    -
    -
    -

    Test the restored database as follows:

    -
    -
    -
    -
    psql -h restore -U postgres postgres
    -
    -
    -
    -
    -
    -

    Point in Time Recovery (PITR)

    -
    -

    PITR (point-in-time-recovery) is a feature that allows for recreating a database -from backup and log files at a certain point in time. This is done using a write -ahead log (WAL) which is kept in the pg_wal directory within PGDATA. Changes -made to the database files over time are recorded in these log files, which allows -it to be used for disaster recovery purposes.

    -
    -
    -

    When using PITR as a backup method, in order to restore from the last checkpoint in -the event of a database or system failure, it is only necessary to save these log -files plus a full backup. This provides an additional advantage in that it is not -necessary to keep multiple full backups on hand, which consume space and time to create. -This is because point in time recovery allows you to "replay" the log files and recover -your database to any point since the last full backup.

    -
    -
    -

    More detailed information about Write Ahead Log (WAL) archiving can be found -here.

    -
    -
    -

    By default in the crunchy-postgres container, WAL logging is not enabled. -To enable WAL logging outside of this example, set the following environment -variables when starting the crunchy-postgres container:

    -
    -
    -
    -
    ARCHIVE_MODE=on
    -ARCHIVE_TIMEOUT=60
    -
    -
    -
    -

    These variables set the same name settings within the postgresql.conf -file that is used by the database. When set, WAL files generated by the database -will be written out to the /pgwal mount point.

    -
    -
    -

    A full backup is required to do a PITR. crunchy-backup currently -performs this role within the example, running a pg_basebackup on the database. -This is a requirement for PITR. After a backup is performed, code is added into -crunchy-postgres which will also check to see if you want to do a PITR.

    -
    -
    -

    There are three volume mounts used with the PITR example.

    -
    -
    -
      -
    • -

      /recover - When specified within a crunchy-postgres container, PITR is activated during container startup.

      -
    • -
    • -

      /backup - This is used to find the base backup you want to recover from.

      -
    • -
    • -

      /pgwal - This volume is used to write out new WAL files from the newly restored database container.

      -
    • -
    -
    -
    -

    Some environment variables used to manipulate the point in time recovery logic:

    -
    -
    -
      -
    • -

      The RECOVERY_TARGET_NAME environment variable is used to tell the PITR logic what the name of the target is.

      -
    • -
    • -

      RECOVERY_TARGET_TIME is also an optional environment variable that restores using a known time stamp.

      -
    • -
    -
    -
    -

    If you don’t specify either of these environment variables, then the PITR logic will assume you want to -restore using all the WAL files or essentially the last known recovery point.

    -
    -
    -

    The RECOVERY_TARGET_INCLUSIVE environment variable is also available to -let you control the setting of the recovery.conf setting recovery_target_inclusive. -If you do not set this environment variable the default is true.

    -
    -
    -

    Once you recover a database using PITR, it will be in read-only mode. To -make the database resume as a writable database, run the following SQL command:

    -
    -
    -
    -
    postgres=# select pg_wal_replay_resume();
    -
    -
    -
    -
    -

    If you’re running the PITR example for PostgreSQL versions 9.5 or 9.6, please note that -starting in PostgreSQL version 10, the pg_xlog directory was renamed to pg_wal. Additionally, all usages -of the function pg_xlog_replay_resume were changed to pg_wal_replay_resume.

    -
    -
    - -
    -
    -

    It takes about 1 minute for the database to become ready for use after initially starting.

    -
    -
    -
    -

    WAL segment files are written to the /tmp directory. Leaving the example running -for a long time could fill up your /tmp directory.

    -
    -
    - -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    Create a database container as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/pitr
    -./run-pitr.sh
    -
    -
    -
    -

    Next, we will create a base backup of that database using this:

    -
    -
    -
    -
    ./run-backup-pitr.sh
    -
    -
    -
    -

    After creating the base backup of the database, WAL segment files are created every 60 seconds -that contain any database changes. These segments are stored in the -/tmp/pitr/pitr/pg_wal directory.

    -
    -
    -

    Next, create some recovery targets within the database by running -the SQL commands against the pitr database as follows:

    -
    -
    -
    -
    ./run-sql.sh
    -
    -
    -
    -

    This will create recovery targets named beforechanges, afterchanges, and -nomorechanges. It will create a table, pitrtest, between -the beforechanges and afterchanges targets. It will also run a SQL -CHECKPOINT to flush out the changes to WAL segments. These labels can be -used to mark the points in the recovery process that will be referenced when -creating the restored database.

    -
    -
    -

    Next, now that we have a base backup and a set of WAL files containing -our database changes, we can shut down the pitr database -to simulate a database failure. Do this by running the following:

    -
    -
    -
    -
    docker stop pitr
    -
    -
    -
    -

    Next, let’s edit the restore script to use the base backup files -created in the step above. You can view the backup path name -under the /tmp/backups/pitr-backups/ directory. You will see -another directory inside of this path with a name similar to -2018-03-21-21-03-29. Copy and paste that value into the -run-restore-pitr.sh script in the BACKUP environment variable.

    -
    -
    -

    After that, run the script.

    -
    -
    -
    -
    vi ./run-restore-pitr.sh
    -./run-restore-pitr.sh
    -
    -
    -
    -

    The WAL segments are read and applied when restoring from the database -backup. At this point, you should be able to verify that the -database was restored to the point before creating the test table:

    -
    -
    -
    -
    psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'table pitrtest'
    -
    -
    -
    -

    This SQL command should show that the pitrtest table does not exist -at this recovery time. The output should be similar to:

    -
    -
    -
    -
    ERROR: relation "pitrtest" does not exist
    -
    -
    -
    -

    PostgreSQL allows you to pause the recovery process if the target name -or time is specified. This pause would allow a DBA a chance to review -the recovery time/name and see if this is what they want or expect. If so, -the DBA can run the following command to resume and complete the recovery:

    -
    -
    -
    -
    psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'select pg_wal_replay_resume()'
    -
    -
    -
    -

    Until you run the statement above, the database will be left in read-only -mode.

    -
    -
    -

    Next, run the script to restore the database -to the afterchanges restore point. Update the RECOVERY_TARGET_NAME to afterchanges:

    -
    -
    -
    -
    vi ./run-restore-pitr.sh
    -./run-restore-pitr.sh
    -
    -
    -
    -

    After this restore, you should be able to see the test table:

    -
    -
    -
    -
    psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'table pitrtest'
    -psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'select pg_wal_replay_resume()'
    -
    -
    -
    -

    Lastly, start a recovery using all of the WAL files. This will get the -restored database as current as possible. To do so, edit the script -to remove the RECOVERY_TARGET_NAME environment setting completely:

    -
    -
    -
    -
    ./run-restore-pitr.sh
    -sleep 30
    -psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'table pitrtest'
    -psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'create table foo (id int)'
    -
    -
    -
    -

    At this point, you should be able to create new data in the restored database -and the test table should be present. When you recover the entire -WAL history, resuming the recovery is not necessary to enable writes.

    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Start by running the example database container:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/pitr
    -./run-pitr.sh
    -
    -
    -
    -

    This step will create a database container, pitr. This -container is configured to continuously write WAL segment files -to a mounted volume (/pgwal).

    -
    -
    -

    After you start the database, you will create a base backup -using this command:

    -
    -
    -
    -
    ./run-backup-pitr.sh
    -
    -
    -
    -

    This will create a backup and write the backup files to a persistent -volume (/pgbackup).

    -
    -
    -

    Next, create some recovery targets within the database by running -the SQL commands against the pitr database as follows:

    -
    -
    -
    -
    ./run-sql.sh
    -
    -
    -
    -

    This will create recovery targets named beforechanges, afterchanges, and -nomorechanges. It will create a table, pitrtest, between -the beforechanges and afterchanges targets. It will also run a SQL -CHECKPOINT to flush out the changes to WAL segments.

    -
    -
    -

    Next, now that we have a base backup and a set of WAL files containing -our database changes, we can shut down the pitr database -to simulate a database failure. Do this by running the following:

    -
    -
    -
    -
    ${CCP_CLI} delete pod pitr
    -
    -
    -
    -

    Next, we will create 3 different restored database containers based -upon the base backup and the saved WAL files.

    -
    -
    -

    First, get the BACKUP_PATH created by the backup-pitr example by viewing the pods logs:

    -
    -
    -
    -
    ${CCP_CLI} logs backup-pitr-8sfkh | grep PATH
    -Thu May 10 18:07:58 UTC 2018 INFO: BACKUP_PATH is set to /pgdata/pitr-backups/2018-05-10-18-07-58.
    -
    -
    -
    -

    Edit the restore-pitr.json file and change the BACKUP_PATH environment variable -using the path discovered above (note: /pgdata/ is not required and should be excluded -in the variable):

    -
    -
    -
    -
    {
    -    "name": "BACKUP_PATH",
    -    "value": "pitr-backups/2018-05-10-18-07-58"
    -{
    -
    -
    -
    -

    Next, we restore prior to the beforechanges recovery target. This -recovery point is before the pitrtest table is created.

    -
    -
    -

    Edit the restore-pitr.json file, and edit the environment -variable to indicate we want to use the beforechanges recovery -point:

    -
    -
    -
    -
    {
    -    "name": "RECOVERY_TARGET_NAME",
    -    "value": "beforechanges"
    -{
    -
    -
    -
    -

    Then run the following to create the restored database container:

    -
    -
    -
    -
    ./run-restore-pitr.sh
    -
    -
    -
    -

    After the database has restored, you should be able to perform -a test to see if the recovery worked as expected:

    -
    -
    -
    -
    psql -h restore-pitr -U postgres postgres -c 'table pitrtest'
    -psql -h restore-pitr -U postgres postgres -c 'create table foo (id int)'
    -
    -
    -
    -

    The output of these commands should show that the pitrtest table is not -present. It should also show that you can not create a new table -because the database is paused in read-only mode.

    -
    -
    -

    To make the database resume as a writable database, run the following -SQL command:

    -
    -
    -
    -
    select pg_wal_replay_resume();
    -
    -
    -
    -

    It should then be possible to write to the database:

    -
    -
    -
    -
    psql -h restore-pitr -U postgres postgres -c 'create table foo (id int)'
    -
    -
    -
    -

    You can also test that if afterchanges is specified, that the -pitrtest table is present but that the database is still in recovery -mode.

    -
    -
    -

    Lastly, you can test a full recovery using all of the WAL files, if -you remove the RECOVERY_TARGET_NAME environment variable completely.

    -
    -
    -

    The storage portions of this example can all be found under $CCP_STORAGE_PATH.

    -
    -
    -
    -
    -
    -
    -

    Connection Pooling

    -
    -
    -

    pgBouncer

    -
    -

    Crunchy pgBouncer is a lightweight connection pooler for PostgreSQL databases.

    -
    -
    -

    The following examples create the following containers:

    -
    -
    -
      -
    • -

      pgBouncer Primary

      -
    • -
    • -

      pgBouncer Replica

      -
    • -
    • -

      PostgreSQL Primary

      -
    • -
    • -

      PostgreSQL Replica

      -
    • -
    -
    -
    -

    In Kubernetes and OpenShift, this example will also create:

    -
    -
    -
      -
    • -

      pgBouncer Primary Service

      -
    • -
    • -

      pgBouncer Replica Service

      -
    • -
    • -

      Primary Service

      -
    • -
    • -

      Replica Service

      -
    • -
    • -

      PostgreSQL Secrets

      -
    • -
    • -

      pgBouncer Secrets

      -
    • -
    -
    -
    -

    To cleanup the objects created by this example, run the following in the pgbouncer example directory:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -
    -

    For more information on pgBouncer, see the official website.

    -
    -
    - -
    -
    -

    Docker

    -
    -

    Run the pgbouncer example:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/pgbouncer
    -./run.sh
    -
    -
    -
    -

    Once all containers have deployed and are ready for use, psql to the target -databases through pgBouncer:

    -
    -
    -
    -
    psql -d userdb -h 0.0.0.0 -p 6432 -U testuser
    -psql -d userdb -h 0.0.0.0 -p 6433 -U testuser
    -
    -
    -
    -

    To connect to the administration database within pgbouncer, connect using psql:

    -
    -
    -
    -
    psql -d pgbouncer -h 0.0.0.0 -p 6432 -U pgbouncer
    -psql -d pgbouncer -h 0.0.0.0 -p 6433 -U pgbouncer
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -
    -

    OpenShift: If custom configurations aren’t being mounted, an emptydir volume is required -to be mounted at /pgconf.

    -
    -
    - -
    -
    -

    Run the pgbouncer example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/pgbouncer
    -./run.sh
    -
    -
    -
    -

    Once all containers have deployed and are ready for use, psql to the target -databases through pgBouncer:

    -
    -
    -
    -
    psql -d userdb -h pgbouncer-primary -p 6432 -U testuser
    -psql -d userdb -h pgbouncer-replica -p 6432 -U testuser
    -
    -
    -
    -

    To connect to the administration database within pgbouncer, connect using psql:

    -
    -
    -
    -
    psql -d pgbouncer -h pgbouncer-primary -p 6432 -U pgbouncer -c "SHOW SERVERS"
    -psql -d pgbouncer -h pgbouncer-replica -p 6432 -U pgbouncer -c "SHOW SERVERS"
    -
    -
    -
    -
    -
    -

    pgPool II

    -
    -

    An example is provided that will run a pgPool II container in conjunction with the -primary-replica example provided above.

    -
    -
    -

    You can execute both INSERT and SELECT statements after connecting to pgpool. -The container will direct INSERT statements to the primary and SELECT statements -will be sent round-robin to both the primary and replica.

    -
    -
    -

    The container creates a default database called userdb, a default user called -testuser and a default password of password.

    -
    -
    -

    You can view the nodes that pgpool is configured for by running:

    -
    -
    -
    -
    psql -h pgpool -U testuser userdb -c 'show pool_nodes'
    -
    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    Create the container as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/pgpool
    -./run.sh
    -
    -
    -
    -

    The example is configured to allow the testuser to connect -to the userdb database.

    -
    -
    -
    -
    psql -h localhost -U testuser -p 12003 userdb
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Run the following command to deploy the pgpool service:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/pgpool
    -./run.sh
    -
    -
    -
    -

    The example is configured to allow the testuser to connect -to the userdb database.

    -
    -
    -
    -
    psql -h pgpool -U testuser userdb
    -
    -
    -
    -
    -
    -
    -
    -

    Database

    -
    -
    -

    Single Primary

    -
    -

    This example starts a single PostgreSQL container and service, the most simple -of examples.

    -
    -
    -

    The container creates a default database called userdb, a default user called testuser -and a default password of password.

    -
    -
    -

    For all environments, the script additionally creates:

    -
    -
    -
      -
    • -

      A persistent volume claim

      -
    • -
    • -

      A crunchy-postgres container named primary

      -
    • -
    • -

      The database using predefined environment variables

      -
    • -
    -
    -
    -

    And specifically for the Kubernetes and OpenShift environments:

    -
    -
    -
      -
    • -

      A pod named primary

      -
    • -
    • -

      A service named primary

      -
    • -
    • -

      A PVC named primary-pgdata

      -
    • -
    • -

      The database using predefined environment variables

      -
    • -
    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    To create the example and run the container:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/primary
    -./run.sh
    -
    -
    -
    -

    Connect from your local host as follows:

    -
    -
    -
    -
    psql -h localhost -U testuser -W userdb
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    To create the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/primary
    -./run.sh
    -
    -
    -
    -

    Connect from your local host as follows:

    -
    -
    -
    -
    psql -h primary -U postgres postgres
    -
    -
    -
    -
    -

    Helm

    -
    -

    This example resides under the $CCPROOT/examples/helm directory. View the README to run this -example using Helm here.

    -
    -
    -
    -
    -

    PostgreSQL Deployment

    -
    -

    Starting in release 1.2.8, the PostgreSQL container can accept -an environment variable named PGDATA_PATH_OVERRIDE. If set, -the /pgdata/subdir path will use a subdirectory name of your -choosing instead of the default which is the hostname of the container.

    -
    -
    -

    This example shows how a Deployment of a PostgreSQL primary is -supported. A pod is a deployment that uses a hostname generated by -Kubernetes; because of this, a new hostname will be defined upon -restart of the primary pod.

    -
    -
    -

    For finding the /pgdata that pertains to the pod, you will need -to specify a /pgdata/subdir name that never changes. This requirement is -handled by the PGDATA_PATH_OVERRIDE environment variable.

    -
    -
    -

    The container creates a default database called userdb, a default user called -testuser and a default password of password.

    -
    -
    -

    This example will create the following in your Kubernetes and OpenShift environments:

    -
    -
    -
      -
    • -

      primary-deployment service which uses a PVC to persist PostgreSQL data

      -
    • -
    • -

      replica-deployment service, uses emptyDir persistence

      -
    • -
    • -

      primary-deployment deployment of replica count 1 for the primary -PostgreSQL database pod

      -
    • -
    • -

      replica-deployment deployment of replica count 1 for the replica

      -
    • -
    • -

      replica2-deployment deployment of replica count 1 for the 2nd replica

      -
    • -
    • -

      ConfigMap to hold a custom postgresql.conf, setup.sql, and -pg_hba.conf files

      -
    • -
    • -

      Secrets for the primary user, superuser, and normal user to -hold the passwords

      -
    • -
    • -

      Volume mount for /backrestrepo and /pgwal

      -
    • -
    -
    -
    -

    The persisted data for the PostgreSQL primary is found under /pgdata/primary-deployment. -If you delete the primary pod, the deployment will create another -pod for the primary and will be able to start up immediately since -it works out of the same /pgdata/primary-deployment data directory.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/primary-deployment
    -./run.sh
    -
    -
    -
    -
    -
    -

    Replication

    -
    -

    This example starts a primary and a replica pod containing a PostgreSQL database.

    -
    -
    -

    The container creates a default database called userdb, a default user called -testuser and a default password of password.

    -
    -
    -

    For the Docker environment, the script additionally creates:

    -
    -
    -
      -
    • -

      A docker volume using the local driver for the primary

      -
    • -
    • -

      A docker volume using the local driver for the replica

      -
    • -
    • -

      A container named primary binding to port 12007

      -
    • -
    • -

      A container named replica binding to port 12008

      -
    • -
    • -

      A mapping of the PostgreSQL port 5432 within the container to the localhost port 12000

      -
    • -
    • -

      The database using predefined environment variables

      -
    • -
    -
    -
    -

    And specifically for the Kubernetes and OpenShift environments:

    -
    -
    -
      -
    • -

      emptyDir volumes for persistence

      -
    • -
    • -

      A pod named pr-primary

      -
    • -
    • -

      A pod named pr-replica

      -
    • -
    • -

      A pod named pr-replica-2

      -
    • -
    • -

      A service named pr-primary

      -
    • -
    • -

      A service named pr-replica

      -
    • -
    • -

      The database using predefined environment variables

      -
    • -
    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    To create the example and run the container:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/primary-replica
    -./run.sh
    -
    -
    -
    -

    Connect from your local host as follows:

    -
    -
    -
    -
    psql -h localhost -p 12007 -U testuser -W userdb
    -psql -h localhost -p 12008 -U testuser -W userdb
    -
    -
    -
    -
    -

    Docker-Compose

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/compose/primary-replica
    -docker-compose up
    -
    -
    -
    -

    To deploy more than one replica, run the following:

    -
    -
    -
    -
    docker-compose up --scale db-replica=3
    -
    -
    -
    -

    To connect to the created database containers, first identify the ports exposed -on the containers:

    -
    -
    -
    -
    docker ps
    -
    -
    -
    -

    Next, using psql, connect to the service:

    -
    -
    -
    -
    psql -d userdb -h 0.0.0.0 -p <CONTAINER_PORT> -U testuser
    -
    -
    -
    -
    -

    See PG_PASSWORD in docker-compose.yml for the user password.

    -
    -
    - -
    -
    -

    To tear down the example, run the following:

    -
    -
    -
    -
    docker-compose stop
    -docker-compose rm
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Run the following command to deploy a primary and replica database cluster:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/primary-replica
    -./run.sh
    -
    -
    -
    -

    It takes about a minute for the replica to begin replicating with the -primary. To test out replication, see if replication is underway -with this command:

    -
    -
    -
    -
    psql -h pr-primary -U postgres postgres -c 'table pg_stat_replication'
    -
    -
    -
    -

    If you see a line returned from that query it means the primary is replicating -to the replica. Try creating some data on the primary:

    -
    -
    -
    -
    psql -h pr-primary -U postgres postgres -c 'create table foo (id int)'
    -psql -h pr-primary -U postgres postgres -c 'insert into foo values (1)'
    -
    -
    -
    -

    Then verify that the data is replicated to the replica:

    -
    -
    -
    -
    psql -h pr-replica -U postgres postgres -c 'table foo'
    -
    -
    -
    -

    primary-replica-dc

    -
    -
    -

    If you wanted to experiment with scaling up the number of replicas, you can run the following example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/primary-replica-dc
    -./run.sh
    -
    -
    -
    -

    You can verify that replication is working using the same commands as above.

    -
    -
    -

    This example creates 2 replicas when it initially starts. To scale -up the number of replicas and view what the deployment looks like before and after, run these commands:

    -
    -
    -
    -
    ${CCP_CLI} get deployment
    -${CCP_CLI} scale --current-replicas=2 --replicas=3 deployment/replica-dc
    -${CCP_CLI} get deployment
    -${CCP_CLI} get pod
    -
    -
    -
    -

    You can verify that you now have 3 replicas by running this query -on the primary:

    -
    -
    -
    -
    psql -h primary-dc -U postgres postgres -c 'table pg_stat_replication'
    -
    -
    -
    -
    -

    Helm

    -
    -

    This example resides under the $CCPROOT/examples/helm directory. View the README to run this example -using Helm here.

    -
    -
    -
    -
    -

    Synchronous Replication

    -
    -

    This example deploys a PostgreSQL cluster with a primary, a synchronous replica, and -an asynchronous replica. The two replicas share the same service.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    To run this example, run the following:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/sync
    -./run.sh
    -
    -
    -
    -

    You can test the replication status on the primary by using the following command -and the password password:

    -
    -
    -
    -
    psql -h 127.0.0.1 -p 12010 -U postgres postgres -c 'table pg_stat_replication'
    -
    -
    -
    -

    You should see 2 rows; 1 for the asynchronous replica and 1 for the synchronous replica. The -sync_state column shows values of async or sync.

    -
    -
    -

    You can test replication to the replicas by first entering some data on -the primary, and secondly querying the replicas for that data:

    -
    -
    -
    -
    psql -h 127.0.0.1 -p 12010 -U postgres postgres -c 'create table foo (id int)'
    -psql -h 127.0.0.1 -p 12010 -U postgres postgres -c 'insert into foo values (1)'
    -psql -h 127.0.0.1 -p 12011 -U postgres postgres -c 'table foo'
    -psql -h 127.0.0.1 -p 12012 -U postgres postgres -c 'table foo'
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/sync
    -./run.sh
    -
    -
    -
    -

    Connect to the primarysync and replicasync databases as follows for both the -Kubernetes and OpenShift environments:

    -
    -
    -
    -
    psql -h primarysync -U postgres postgres -c 'create table test (id int)'
    -psql -h primarysync -U postgres postgres -c 'insert into test values (1)'
    -psql -h primarysync -U postgres postgres -c 'table pg_stat_replication'
    -psql -h replicasync -U postgres postgres -c 'select inet_server_addr(), * from test'
    -psql -h replicasync -U postgres postgres -c 'select inet_server_addr(), * from test'
    -psql -h replicasync -U postgres postgres -c 'select inet_server_addr(), * from test'
    -
    -
    -
    -

    This set of queries will show you the IP address of the PostgreSQL replica -container. Note the changing IP address due to the round-robin service proxy -being used for both replicas. The example queries also show that both -replicas are replicating successfully from the primary.

    -
    -
    -
    -
    -

    Statefulsets

    -
    -

    This example deploys a statefulset named statefulset. The statefulset -is a new feature in Kubernetes as of version 1.5 and in OpenShift Origin as of -version 3.5. Statefulsets have replaced PetSets going forward.

    -
    -
    -

    Please view this Kubernetes description -to better understand what a Statefulset is and how it works.

    -
    -
    -

    This example creates 2 PostgreSQL containers to form the set. At -startup, each container will examine its hostname to determine -if it is the first container within the set of containers.

    -
    -
    -

    The first container is determined by the hostname suffix assigned -by Kubernetes to the pod. This is an ordinal value starting with 0. -If a container sees that it has an ordinal value of 0, it will -update the container labels to add a new label of:

    -
    -
    -
    -
    name=$PG_PRIMARY_HOST
    -
    -
    -
    -

    In this example, PG_PRIMARY_HOST is specified as statefulset-primary.

    -
    -
    -

    By default, the containers specify a value of name=statefulset-replica.

    -
    -
    -

    There are 2 services that end user applications will use to -access the PostgreSQL cluster, one service (statefulset-primary) routes to the primary -container and the other (statefulset-replica) to the replica containers.

    -
    -
    -
    -
    $ ${CCP_CLI} get service
    -NAME            CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    -kubernetes      10.96.0.1       <none>        443/TCP    22h
    -statefulset           None            <none>        5432/TCP   1h
    -statefulset-primary    10.97.168.138   <none>        5432/TCP   1h
    -statefulset-replica   10.97.218.221   <none>        5432/TCP   1h
    -
    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Start the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/statefulset
    -./run.sh
    -
    -
    -
    -

    You can access the primary database as follows:

    -
    -
    -
    -
    psql -h statefulset-primary -U postgres postgres
    -
    -
    -
    -

    You can access the replica databases as follows:

    -
    -
    -
    -
    psql -h statefulset-replica -U postgres postgres
    -
    -
    -
    -

    You can scale the number of containers using this command; this will -essentially create an additional replica database.

    -
    -
    -
    -
    ${CCP_CLI} scale --replicas=3 statefulset statefulset
    -
    -
    -
    -
    -

    Helm

    -
    -

    This example resides under the $CCPROOT/examples/helm directory. View the README to -run this example using Helm here.

    -
    -
    -
    -
    -

    Geospatial (PostGIS)

    -
    -

    An example is provided that will run a PostgreSQL with PostGIS pod and service in Kubernetes and OpenShift and a container in Docker.

    -
    -
    -

    The container creates a default database called userdb, a default user called -testuser and a default password of password.

    -
    -
    -

    You can view the extensions that postgres-gis has enabled by running the following command and viewing the listed PostGIS packages:

    -
    -
    -
    -
    psql -h postgres-gis -U testuser userdb -c '\dx'
    -
    -
    -
    -

    To validate that PostGIS is installed and which version is running, run the command:

    -
    -
    -
    -
    psql -h postgres-gis -U testuser userdb -c "SELECT postgis_full_version();"
    -
    -
    -
    -

    You should expect to see output similar to:

    -
    -
    -
    -
    postgis_full_version
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    - POSTGIS="2.4.2 r16113" PGSQL="100" GEOS="3.5.0-CAPI-1.9.0 r4084" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.11.4, released 2016/01/25" LIBXML="2.9.1" LIBJSON="0.11" TOPOLOGY RASTER
    -(1 row)
    -
    -
    -
    -

    As an exercise for invoking some of the basic PostGIS functionality for validation, try defining a 2D geometry point while giving inputs of -longitude and latitude through this command.

    -
    -
    -
    -
    psql -h postgres-gis -U testuser userdb -c "select ST_MakePoint(28.385200,-81.563900);"
    -
    -
    -
    -

    You should expect to see output similar to:

    -
    -
    -
    -
                    st_makepoint
    ---------------------------------------------
    - 0101000000516B9A779C623C40B98D06F0166454C0
    -(1 row)
    -
    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    Create the container as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/postgres-gis
    -./run.sh
    -
    -
    -
    -

    Enter the following command to connect to the postgres-gis container that is -mapped to your local port 12000:

    -
    -
    -
    -
    psql -h localhost -U testuser -p 12000 userdb
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/postgres-gis
    -./run.sh
    -
    -
    -
    -
    -
    -

    Custom Configuration

    -
    -

    You can use your own version of the SQL file setup.sql to customize -the initialization of database data and objects when the container and -database are created.

    -
    -
    -

    This works by placing a file named setup.sql within the /pgconf mounted volume -directory. Portions of the setup.sql file are required for the container -to work; please see comments within the sample setup.sql file.

    -
    -
    -

    If you mount a /pgconf volume, crunchy-postgres will look at that directory -for postgresql.conf, pg_hba.conf, pg_ident.conf, SSL server/ca certificates and setup.sql. -If it finds one of them it will use that file instead of the default files.

    -
    -
    -

    Docker

    -
    -

    This example can be run as follows for the Docker environment:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/custom-config
    -./run.sh
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/custom-config
    -./run.sh
    -
    -
    -
    -
    -
    -

    SSL Authentication

    -
    -

    This example shows how you can configure PostgreSQL to use SSL for -client authentication.

    -
    -
    -

    The example requires SSL certificates and keys to be created. Included in -the examples directory is a script to create self-signed certificates (server -and client) for the example: $CCPROOT/examples/ssl-creator.sh.

    -
    -
    -

    The example creates a client certificate for the user testuser. Furthermore, -the server certificate is created for the server name custom-config-ssl.

    -
    -
    -

    If as a client it’s required to confirm the identity of the server, verify-full can be -specified in the connection string. This will check if the server and the server certificate -have the same name:

    -
    -
    -
    -
    psql postgresql://custom-config-ssl:5432/postgres?sslmode=verify-full -U testuser"
    -
    -
    -
    -

    To connect via IP, sslmode can be changed to require.

    -
    -
    -
    -
    psql postgresql://IP_OF_PGSQL:5432/postgres?sslmode=require -U testuser"
    -
    -
    -
    -

    This example can be run as follows for the Docker environment:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/custom-config-ssl
    -./run.sh
    -
    -
    -
    -

    And the example can be run in the following directory for the Kubernetes and OpenShift environments:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/custom-config-ssl
    -./run.sh
    -
    -
    -
    -

    A required step to make this example work is to define -in your /etc/hosts file an entry that maps custom-config-ssl -to the service IP address for the container.

    -
    -
    -

    For instance, if your service has an address as follows:

    -
    -
    -
    -
    ${CCP_CLI} get service
    -NAME                CLUSTER-IP       EXTERNAL-IP   PORT(S)                   AGE
    -custom-config-ssl   172.30.211.108   <none>        5432/TCP
    -
    -
    -
    -

    Then your /etc/hosts file needs an entry like this:

    -
    -
    -
    -
    172.30.211.108 custom-config-ssl
    -
    -
    -
    -

    For production Kubernetes and OpenShift installations, it will likely be preferred for DNS -names to resolve to the PostgreSQL service name and generate -server certificates using the DNS names instead of the example -name custom-config-ssl.

    -
    -
    -

    In order to connect via certificate, environment variables must be set that point -to the client certificates. Source the env.sh file to set environment varaibles -for the example:

    -
    -
    -
    -
    source env.sh
    -
    -
    -
    -

    If as a client it’s required to confirm the identity of the server, verify-full can be -specified in the connection string. This will check if the server and the server certificate -have the same name:

    -
    -
    -
    -
    psql postgresql://custom-config-ssl:5432/userdb?sslmode=verify-full -U testuser"
    -
    -
    -
    -

    To connect via IP, sslmode can be changed to require.

    -
    -
    -
    -
    psql postgresql://IP_OF_PGSQL:5432/userdb?sslmode=require -U testuser"
    -
    -
    -
    -

    You should see a connection that looks like the following:

    -
    -
    -
    -
    psql (10.5)
    -SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
    -Type "help" for help.
    -
    -userdb=>
    -
    -
    -
    -
    -

    Docker Swarm

    -
    -

    This example shows how to run a primary and replica database -container on a Docker Swarm (v.1.12) cluster.

    -
    -
    -

    First, set up a cluster. The Kubernetes libvirt coreos cluster -example works well; see coreos-libvirt-cluster.

    -
    -
    -

    Next, on each node, create the Swarm using these -Swarm Install instructions.

    -
    -
    -

    Include this command on the manager node:

    -
    -
    -
    -
    docker swarm init --advertise-addr 192.168.10.1
    -
    -
    -
    -

    Then this command on all the worker nodes:

    -
    -
    -
    -
     docker swarm join \
    -     --token SWMTKN-1-65cn5wa1qv76l8l45uvlsbprogyhlprjpn27p1qxjwqmncn37o-015egopg4jhtbmlu04faon82u \
    -         192.168.10.1.37
    -
    -
    -
    -

    Before creating Swarm services, it is necessary -to define an overlay network to be used by the services you will -create. This can be done as follows:

    -
    -
    -
    -
    docker network create --driver overlay crunchynet
    -
    -
    -
    -

    We want to have the primary database always placed on -a specific node. This is accomplished using node constraints -as follows:

    -
    -
    -
    -
    docker node inspect kubernetes-node-1 | grep ID
    -docker node update --label-add type=primary 18yrb7m650umx738rtevojpqy
    -
    -
    -
    -

    In the above example, the kubernetes-node-1 node with ID -18yrb7m650umx738rtevojpqy has a user defined label of primary added to it. -The primary service specifies primary as a constraint when created; this -tells Swarm to place the service on that specific node. The replica specifies -a constraint of node.labels.type != primary to have the replica -always placed on a node that is not hosting the primary service.

    -
    -
    -

    Docker

    -
    -

    After you set up the Swarm cluster, you can then run this example as follows on the Swarm Manager Node:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/swarm-service
    -./run.sh
    -
    -
    -
    -

    You can then find the nodes that are running the primary and replica containers -by:

    -
    -
    -
    -
    docker service ps primary
    -docker service ps replica
    -
    -
    -
    -

    You can also scale up the number of replica containers.

    -
    -
    -
    -
    docker service scale replica=2
    -docker service ls
    -
    -
    -
    -

    Verify you have two replicas within PostgreSQL by viewing the pg_stat_replication table. -The password is password by default when logged into the kubernetes-node-1 host:

    -
    -
    -
    -
    docker exec -it $(docker ps -q) psql -U postgres -c 'table pg_stat_replication' postgres
    -
    -
    -
    -

    You should see a row for each replica along with its replication status.

    -
    -
    -
    -
    -
    -
    -

    Failover

    -
    -
    -

    Watch

    -
    -

    This example shows how to run the crunchy-watch container -to perform an automated failover. For the example to -work, the host on which you are running needs to allow -read-write access to /run/docker.sock. The crunchy-watch -container runs as the postgres user, so adjust the -file permissions of /run/docker.sock accordingly.

    -
    -
    -

    The primary-replica example is required to be run before this example.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    Run the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/watch
    -./run.sh
    -
    -
    -
    -

    This will start the watch container which tests every few seconds -whether the primary database is running, if not, it will -trigger a failover using docker exec on the replica host.

    -
    -
    -

    Test it out by stopping the primary:

    -
    -
    -
    -
    docker stop primary
    -docker logs watch
    -
    -
    -
    -

    Look at the watch container logs to see it perform the failover.

    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/watch
    -./run.sh
    -
    -
    -
    -

    Check out the log of the watch container as follows:

    -
    -
    -
    -
    ${CCP_CLI} log watch
    -
    -
    -
    -

    Then trigger a failover using this command:

    -
    -
    -
    -
    ${CCP_CLI} delete pod pr-primary
    -
    -
    -
    -

    Resume watching the watch container’s log and verify that it -detects the primary is not reachable and performs a failover -on the replica.

    -
    -
    -

    A final test is to see if the old replica is now a fully functioning -primary by inserting some test data into it as follows:

    -
    -
    -
    -
    psql -h pr-primary -U postgres postgres -c 'create table failtest (id int)'
    -
    -
    -
    -

    The above command still works because the watch container has -changed the labels of the replica to make it a primary, so the primary -service will still work and route now to the new primary even though -the pod is named replica.

    -
    -
    -

    You can view the labels on a pod with this command:

    -
    -
    -
    -
    ${CCP_CLI} describe pod pr-replica | grep Label
    -
    -
    -
    -
    -
    -
    -
    -

    Metrics and Performance

    -
    -
    -

    pgBadger

    -
    -

    pgbadger is a PostgreSQL tool that reads the log files from a specified database -in order to produce a HTML report that shows various PostgreSQL statistics and graphs. -This example runs the pgbadger HTTP server against a crunchy-postgres container and -illustrates how to view the generated reports.

    -
    -
    -

    The port utilized for this tool is port 14000 for Docker environments and port 10000 -for Kubernetes and OpenShift environments.

    -
    -
    -

    A requirement to build this container from source is golang. On RHEL 7.2, golang -is found in the 'server optional' repository which needs to be enabled in order to install -this dependency.

    -
    -
    -
    -
    sudo subscription-manager repos --enable=rhel-7-server-optional-rpms
    -
    -
    -
    -

    The container creates a default database called userdb, a default user called -testuser and a default password of password.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    Run the example as follows:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/pgbadger
    -./run.sh
    -
    -
    -
    -

    After execution, the container will run and provide a simple HTTP -command you can browse to view the report. As you run queries against -the database, you can invoke this URL to generate updated reports:

    -
    -
    -
    -
    curl -L http://127.0.0.1:14000/api/badgergenerate
    -
    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/pgbadger
    -./run.sh
    -
    -
    -
    -

    After execution, the container will run and provide a simple HTTP -command you can browse to view the report. As you run queries against -the database, you can invoke this URL to generate updated reports:

    -
    -
    -
    -
    curl -L http://pgbadger:10000/api/badgergenerate
    -
    -
    -
    -

    You can view the database container logs using these commands:

    -
    -
    -
    -
    ${CCP_CLI} logs pgbadger -c pgbadger
    -${CCP_CLI} logs pgbadger -c postgres
    -
    -
    -
    -
    -
    -

    Metrics Collection

    -
    -

    You can collect various PostgreSQL metrics from your database -container by running a crunchy-collect container that points -to your database container.

    -
    -
    -

    This example starts up 5 containers:

    -
    -
    -
      -
    • -

      Collect (crunchy-collect)

      -
    • -
    • -

      Grafana (crunchy-grafana)

      -
    • -
    • -

      PostgreSQL (crunchy-postgres)

      -
    • -
    • -

      Prometheus (crunchy-prometheus)

      -
    • -
    -
    -
    -

    Every 5 seconds by default, Prometheus will scrape the Collect container -for metrics. These metrics will then be visualized by Grafana.

    -
    -
    -

    By default, Prometheus detects which environment its running on (Docker, Kubernetes, or OpenShift Container Platform) -and applies a default configuration. If this container is running on Kubernetes or OpenShift Container Platform, -it will use the Kubernetes API to discover pods with the label "crunchy-collect": "true".

    -
    -
    -

    The collect container must have this label to be discovered in these environments. -Additionally, the collect container uses a special PostgreSQL role ccp_monitoring. -This user is created by setting the PGMONITOR_PASSWORD environment variable on the -PostgreSQL container.

    -
    -
    -

    Discovering pods requires a cluster role service account. See the -Kubernetes and OpenShift -metrics JSON file for more details.

    -
    -
    -

    For Docker environments the collect hostname must be specified as an environment -variable.

    -
    -
    -

    To shutdown the instance and remove the container for each example, run the following:

    -
    -
    -
    -
    ./cleanup.sh
    -
    -
    -
    -

    Docker

    -
    -

    To start this set of containers, run the following:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/metrics
    -./run.sh
    -
    -
    -
    -

    You will be able to access the Grafana and Prometheus services from the following -web addresses:

    -
    -
    - -
    -
    -

    The crunchy-postgres container is accessible on port 5432.

    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Running the example:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/metrics
    -./run.sh
    -
    -
    -
    -

    It’s required to use port-forward to access the Grafana dashboard. To start the -port-forward, run the following command:

    -
    -
    -
    -
    ${CCP_CLI} port-forward metrics 3000:3000
    -${CCP_CLI} port-forward metrics 9090:9090
    -
    -
    -
    - -
    -
    -

    You can view the container logs using these command:

    -
    -
    -
    -
    ${CCP_CLI} logs -c grafana metrics
    -${CCP_CLI} logs -c prometheus metrics
    -${CCP_CLI} logs -c collect primary
    -${CCP_CLI} logs -c postgres primary
    -${CCP_CLI} logs -c collect replica
    -${CCP_CLI} logs -c postgres replica
    -
    -
    -
    -
    -
    -

    pg_audit

    -
    -

    This example provides an example of enabling pg_audit output. -As of release 1.3, pg_audit is included in the crunchy-postgres -container and is added to the PostgreSQL shared library list in -postgresql.conf.

    -
    -
    -

    Given the numerous ways pg_audit can be configured, the exact -pg_audit configuration is left to the user to define. pg_audit -allows you to configure auditing rules either in postgresql.conf -or within your SQL script.

    -
    -
    -

    For this test, we place pg_audit statements within a SQL script -and verify that auditing is enabled and working. If you choose -to configure pg_audit via a postgresql.conf file, then you will -need to define your own custom file and mount it to override the -default postgresql.conf file.

    -
    -
    -

    Docker

    -
    -

    Run the following to create a database container:

    -
    -
    -
    -
    cd $CCPROOT/examples/docker/pgaudit
    -./run.sh
    -
    -
    -
    -

    This starts an instance of the pg_audit container (running crunchy-postgres) -on port 12005 on localhost. The test script is then automatically executed.

    -
    -
    -

    This test executes a SQL file which contains pg_audit configuration -statements as well as executes some basic SQL commands. These -SQL commands will cause pg_audit to create log messages in -the pg_log log file created by the database container.

    -
    -
    -
    -

    Kubernetes and OpenShift

    -
    -

    Run the following:

    -
    -
    -
    -
    cd $CCPROOT/examples/kube/pgaudit
    -./run.sh
    -
    -
    -
    -

    The script will create the pg_audit pod (running the crunchy-postgres container) -on the Kubernetes instance and then execute a SQL file which -contains pg_audit configuration statements as well as some -basic SQL commands. These SQL commands will cause pg_audit to create -log messages in the pg_log file created by the database container.

    -
    -
    -
    -
    -
    - - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/getting-started/kubernetes-and-openshift/index.xml b/docs/getting-started/kubernetes-and-openshift/index.xml deleted file mode 100644 index 6e0c91b21..000000000 --- a/docs/getting-started/kubernetes-and-openshift/index.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - Kubernetes and Openshift on Crunchy Data Container Suite Documentation - https://crunchydata.github.io/crunchy-containers/getting-started/kubernetes-and-openshift/ - Recent content in Kubernetes and Openshift on Crunchy Data Container Suite Documentation - Hugo -- gohugo.io - en-us - Tue, 15 May 2018 08:30:41 -0700 - - - - - - \ No newline at end of file diff --git a/docs/getting-started/openshift-templates/index.html b/docs/getting-started/openshift-templates/index.html deleted file mode 100644 index 7a0926049..000000000 --- a/docs/getting-started/openshift-templates/index.html +++ /dev/null @@ -1,478 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Openshift Templates :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
    - - - - -
    -
    -
    - -
    - - - - - - - -
    -
    - -
    -
    - - -
    - - -
    - -

    Openshift Templates

    - - - - - - - - -
    -

    Latest Release: 2.1.0 2018-08-13

    -
    -
    -

    The OpenShift template examples referenced in this documentation are located at the following -directory:

    -
    -
    -
    -
    $CCPROOT/examples/ocp-templates/
    -
    -
    -
    -

    The following templates for PostgreSQL are provided:

    -
    - - - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/getting-started/openshift-templates/index.xml b/docs/getting-started/openshift-templates/index.xml deleted file mode 100644 index b04c3e488..000000000 --- a/docs/getting-started/openshift-templates/index.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - Openshift Templates on Crunchy Data Container Suite Documentation - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/ - Recent content in Openshift Templates on Crunchy Data Container Suite Documentation - Hugo -- gohugo.io - en-us - Tue, 15 May 2018 08:35:00 -0700 - - - - - - Single Primary - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/single-primary/ - Tue, 15 May 2018 07:22:59 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/single-primary/ - v2.1.0 -The Crunchy PostgreSQL Primary Template creates a single primary pod. -Objects The Crunchy PostreSQL Primary Template creates the following objects: - PostgreSQL Secret - usernames and passwords generated from the template PGData PVC - Volume where PostgreSQL database will be stored Primary Service - Service connected to the Primary Pod Primary Pod - Primary database pod Storage This template assumes STORAGE_CLASS volumes will be used. -Form Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. - - - - Primary Restore - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore/ - Tue, 15 May 2018 07:22:51 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore/ - v2.1.0 -The Crunchy PostgreSQL Primary Restore Template creates a single primary pod from a pg_basebackup physical backup. -Objects The Crunchy PostreSQL Primary Template creates the following objects: - PostgreSQL Secret - usernames and passwords generated from the template PGData PVC - Volume where PostgreSQL database will be stored Primary Service - Service connected to the Primary Pod Primary Pod - Primary database pod Storage This template assumes STORAGE_CLASS volumes will be used. - - - - Primary Restore Secret - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore-secret/ - Tue, 15 May 2018 07:22:45 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore-secret/ - v2.1.0 -The Crunchy PostgreSQL Primary Restore Template creates a single primary pod from a pg_basebackup physical backup. -Objects The Crunchy PostreSQL Primary Template creates the following objects: - PGData PVC - Volume where PostgreSQL database will be stored Primary Service - Service connected to the Primary Pod Primary Pod - Primary database pod Storage This template assumes STORAGE_CLASS volumes will be used. -The template assumes a BACKUP PVC has been created and contains a backup. - - - - Primary Backup - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup/ - Tue, 15 May 2018 07:22:27 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup/ - v2.1.0 -The Crunchy Backup template takes a pg_basebackup of the target database. -Objects The Crunchy Backup Template creates the following objects: - Backup PVC - Volume where pg_basebackup physical backups will be stored. Backup Job - Short lived pod that creates a physical backup using pg_basebackup. Storage This template assumes STORAGE_CLASS volumes will be used. -Form Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. - - - - Primary Backup Secret - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup-secret/ - Tue, 15 May 2018 07:22:20 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup-secret/ - v2.1.0 -The Crunchy Backup Secrets template takes a pg_basebackup of the target database using a pre-existing OpenShift secret to retrieve usernames and passwords for backup purposes. -Objects The Crunchy Backup Template creates the following objects: - Backup PVC - Volume where pg_basebackup physical backups will be stored. Backup Job - Short lived pod that creates a physical backup using pg_basebackup. Storage This template assumes STORAGE_CLASS volumes will be used. - - - - Primary Replica - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/postgres-replicated/ - Tue, 15 May 2018 07:22:10 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/postgres-replicated/ - v2.1.0 -The Crunchy PostgreSQL Primary/Replica Template creates a primary pod with replica statefulsets to provide a database cluster with streaming replication. -Objects The Crunchy PostreSQL Primary/Replica Template creates the following objects: - PostgreSQL Secret - usernames and passwords generated from the template PGData PVC - Volume where PostgreSQL database will be stored Backup PVC - Volume where pg_basebackup physical backups will be stored Backrestrepo PVC - Volume where pgBackRest physical backups will be stored Primary Service - Service connected to the Primary Pod Replica Service - Service connected to the Replica Pods Primary Pod - Primary database pod Replica Statefulset - Replica database pods Storage This template assumes STORAGE_CLASS volumes will be used. - - - - pgAdmin4 - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/pgadmin4/ - Tue, 15 May 2018 07:22:02 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/pgadmin4/ - v2.1.0 -Crunchy pgAdmin4 Template provides a feature rich, GUI Open Source administration and development platform for PostgreSQL. -Objects The Crunchy pgAdmin4 Template creates the following objects: - pgAdmin4 Secret - email and password for login pgAdmin4 PVC - Volume where pgAdmin4 data will be stored pgAdmin4 Service - Service connected to the pgAdmin4 pod pgAdmin4 Pod - pgAdmin4 web application Storage This template assumes STORAGE_CLASS volumes will be used. - - - - \ No newline at end of file diff --git a/docs/getting-started/openshift-templates/pgadmin4/index.html b/docs/getting-started/openshift-templates/pgadmin4/index.html deleted file mode 100644 index 8a55d662e..000000000 --- a/docs/getting-started/openshift-templates/pgadmin4/index.html +++ /dev/null @@ -1,498 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -pgAdmin4 :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
    - - - - -
    -
    -
    - -
    - - - - - - - -
    -
    - -
    -
    - - -
    - - -
    - -

    pgAdmin4

    - - - - - - - - - -

    v2.1.0

    - -

    Crunchy pgAdmin4 Template provides a feature rich, GUI Open Source administration and development platform for PostgreSQL.

    - -

    Objects

    - -

    The Crunchy pgAdmin4 Template creates the following objects:

    - -
      -
    • pgAdmin4 Secret - email and password for login
    • -
    • pgAdmin4 PVC - Volume where pgAdmin4 data will be stored
    • -
    • pgAdmin4 Service - Service connected to the pgAdmin4 pod
    • -
    • pgAdmin4 Pod - pgAdmin4 web application
    • -
    - -

    Storage

    - -

    This template assumes STORAGE_CLASS volumes will be used.

    - -

    Form Required

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameDescription
    VOLUME_STORAGE_CLASSName of the Storage Class that provides persistence for the container.
    PGADMIN_EMAILEmail address used to login to the web application.
    PGADMIN_PASSWORDPassword used to login to the web application.
    - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/getting-started/openshift-templates/postgres-replicated/index.html b/docs/getting-started/openshift-templates/postgres-replicated/index.html deleted file mode 100644 index 29ae79ebf..000000000 --- a/docs/getting-started/openshift-templates/postgres-replicated/index.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Primary Replica :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
    - - - - -
    -
    -
    - -
    - - - - - - - -
    -
    - -
    -
    - - -
    - - -
    - -

    Primary Replica

    - - - - - - - - - -

    v2.1.0

    - -

    The Crunchy PostgreSQL Primary/Replica Template creates a primary pod with replica statefulsets to provide a database cluster with streaming replication.

    - -

    Objects

    - -

    The Crunchy PostreSQL Primary/Replica Template creates the following objects:

    - -
      -
    • PostgreSQL Secret - usernames and passwords generated from the template
    • -
    • PGData PVC - Volume where PostgreSQL database will be stored
    • -
    • Backup PVC - Volume where pg_basebackup physical backups will be stored
    • -
    • Backrestrepo PVC - Volume where pgBackRest physical backups will be stored
    • -
    • Primary Service - Service connected to the Primary Pod
    • -
    • Replica Service - Service connected to the Replica Pods
    • -
    • Primary Pod - Primary database pod
    • -
    • Replica Statefulset - Replica database pods
    • -
    - -

    Storage

    - -

    This template assumes STORAGE_CLASS volumes will be used.

    - -

    Form Required

    - - - - - - - - - - - - - - - -
    NameDescription
    VOLUME_STORAGE_CLASSName of the Storage Class that provides persistence for the container.
    - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/getting-started/openshift-templates/primary-backup-secret/index.html b/docs/getting-started/openshift-templates/primary-backup-secret/index.html deleted file mode 100644 index 8aa27c8b9..000000000 --- a/docs/getting-started/openshift-templates/primary-backup-secret/index.html +++ /dev/null @@ -1,503 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Primary Backup Secret :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
    - - - - -
    -
    -
    - -
    - - - - - - - -
    - -
    - - -
    - - -
    - -

    Primary Backup Secret

    - - - - - - - - - -

    v2.1.0

    - -

    The Crunchy Backup Secrets template takes a pg_basebackup of the target database using a pre-existing OpenShift secret to retrieve usernames and passwords for backup purposes.

    - -

    Objects

    - -

    The Crunchy Backup Template creates the following objects:

    - -
      -
    • Backup PVC - Volume where pg_basebackup physical backups will be stored.
    • -
    • Backup Job - Short lived pod that creates a physical backup using pg_basebackup.
    • -
    - -

    Storage

    - -

    This template assumes STORAGE_CLASS volumes will be used.

    - -

    Form Required

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameDescription
    VOLUME_STORAGE_CLASSName of the Storage Class that provides persistence for the container.
    PG_SECRET_NAMEName of the secret where PostgreSQL credentials are located.
    DB_HOSTNAMEService name of the PostgreSQL pod to backup.
    - -

    Multiple Backups

    - -

    This templates creates a PVC automatically, however, to take multiple backups on the same volume the BACKUP_PVC_NAME environment field should be configured to an existing PVC.

    - -

    A template error is expected when supplying an existing PVC and can be ignored.

    - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/getting-started/openshift-templates/primary-backup/index.html b/docs/getting-started/openshift-templates/primary-backup/index.html deleted file mode 100644 index c5cf6f923..000000000 --- a/docs/getting-started/openshift-templates/primary-backup/index.html +++ /dev/null @@ -1,508 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Primary Backup :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
    - - - - -
    -
    -
    - -
    - - - - - - - -
    - -
    - - -
    - - -
    - -

    Primary Backup

    - - - - - - - - - -

    v2.1.0

    - -

    The Crunchy Backup template takes a pg_basebackup of the target database.

    - -

    Objects

    - -

    The Crunchy Backup Template creates the following objects:

    - -
      -
    • Backup PVC - Volume where pg_basebackup physical backups will be stored.
    • -
    • Backup Job - Short lived pod that creates a physical backup using pg_basebackup.
    • -
    - -

    Storage

    - -

    This template assumes STORAGE_CLASS volumes will be used.

    - -

    Form Required

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameDescription
    VOLUME_STORAGE_CLASSName of the Storage Class that provides persistence for the container.
    BACKUP_USERName of the user to create the backup. Note: this user should have replication privileges (normally primaryuser in Crunchy PostgreSQL).
    BACKUP_PASSPassword of the user to create the backup.
    DB_HOSTNAMEService name of the PostgreSQL pod to backup.
    - -

    Multiple Backups

    - -

    This templates creates a PVC automatically, however, to take multiple backups on the same volume the BACKUP_PVC_NAME environment field should be configured to an existing PVC.

    - -

    A template error is expected when supplying an existing PVC and can be ignored.

    - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/getting-started/openshift-templates/primary-restore-secret/index.html b/docs/getting-started/openshift-templates/primary-restore-secret/index.html deleted file mode 100644 index 083cca898..000000000 --- a/docs/getting-started/openshift-templates/primary-restore-secret/index.html +++ /dev/null @@ -1,509 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Primary Restore Secret :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
    - - - - -
    -
    -
    - -
    - - - - - - - -
    -
    - -
    -
    - - -
    - - -
    - -

    Primary Restore Secret

    - - - - - - - - - -

    v2.1.0

    - -

    The Crunchy PostgreSQL Primary Restore Template creates a single primary pod from a pg_basebackup physical backup.

    - -

    Objects

    - -

    The Crunchy PostreSQL Primary Template creates the following objects:

    - -
      -
    • PGData PVC - Volume where PostgreSQL database will be stored
    • -
    • Primary Service - Service connected to the Primary Pod
    • -
    • Primary Pod - Primary database pod
    • -
    - -

    Storage

    - -

    This template assumes STORAGE_CLASS volumes will be used.

    - -

    The template assumes a BACKUP PVC has been created and contains a backup.

    - -

    Form Required

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameDescription
    VOLUME_STORAGE_CLASSName of the Storage Class that provides persistence for the container.
    BACKUP_PVC_NAMEName of the PVC where the physical backups are stored.
    BACKUP_DATETimestamp of the backup to use from the Crunchy Backup job.
    BACKUP_HOSTNAMEHostname of the backed up database.
    PG_SECRET_NAMEName of the secret of the backed up database (can be retrieved from secrets).
    - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/getting-started/openshift-templates/primary-restore/index.html b/docs/getting-started/openshift-templates/primary-restore/index.html deleted file mode 100644 index 8e1ef15cf..000000000 --- a/docs/getting-started/openshift-templates/primary-restore/index.html +++ /dev/null @@ -1,535 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Primary Restore :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
    - - - - -
    -
    -
    - -
    - - - - - - - -
    -
    - -
    -
    - - -
    - - -
    - -

    Primary Restore

    - - - - - - - - - -

    v2.1.0

    - -

    The Crunchy PostgreSQL Primary Restore Template creates a single primary pod from a pg_basebackup physical backup.

    - -

    Objects

    - -

    The Crunchy PostreSQL Primary Template creates the following objects:

    - -
      -
    • PostgreSQL Secret - usernames and passwords generated from the template
    • -
    • PGData PVC - Volume where PostgreSQL database will be stored
    • -
    • Primary Service - Service connected to the Primary Pod
    • -
    • Primary Pod - Primary database pod
    • -
    - -

    Storage

    - -

    This template assumes STORAGE_CLASS volumes will be used.

    - -

    The template assumes a BACKUP PVC has been created and contains a backup.

    - -

    Form Required

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameDescription
    VOLUME_STORAGE_CLASSName of the Storage Class that provides persistence for the container.
    BACKUP_PVC_NAMEName of the PVC where the physical backups are stored.
    BACKUP_DATETimestamp of the backup to use from the Crunchy Backup job.
    BACKUP_HOSTNAMEHostname of the backed up database.
    PG_USERUsername of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates).
    PG_PASSWORDPassword of the PG_USER from the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates).
    PG_DATABASEDatabase of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates).
    PG_PRIMARY_USERReplication username of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates).
    PG_PRIMARY_PASSWORDReplication username password of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates).
    PG_PRIMARY_PASSWORDSuperuser password of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates).**
    - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/getting-started/openshift-templates/single-primary/index.html b/docs/getting-started/openshift-templates/single-primary/index.html deleted file mode 100644 index 3667bd78f..000000000 --- a/docs/getting-started/openshift-templates/single-primary/index.html +++ /dev/null @@ -1,488 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Single Primary :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
    - - - - -
    -
    -
    - -
    - - - - - - - -
    -
    - -
    -
    - - -
    - - -
    - -

    Single Primary

    - - - - - - - - - -

    v2.1.0

    - -

    The Crunchy PostgreSQL Primary Template creates a single primary pod.

    - -

    Objects

    - -

    The Crunchy PostreSQL Primary Template creates the following objects:

    - -
      -
    • PostgreSQL Secret - usernames and passwords generated from the template
    • -
    • PGData PVC - Volume where PostgreSQL database will be stored
    • -
    • Primary Service - Service connected to the Primary Pod
    • -
    • Primary Pod - Primary database pod
    • -
    - -

    Storage

    - -

    This template assumes STORAGE_CLASS volumes will be used.

    - -

    Form Required

    - - - - - - - - - - - - - - - -
    NameDescription
    VOLUME_STORAGE_CLASSName of the Storage Class that provides persistence for the container.
    - - - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/grafana-dashboard-1.png b/docs/grafana-dashboard-1.png deleted file mode 100644 index b7e23f775d564d6f265dda8d93b9bbc2ec095a58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54209 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%0Dy$7`t zIwTU@u}dBSpx(z!@3|1_T&icBs}1cCe3dW@5emEmjL+C3`xz7+_{O#yhhVg=cX5@k zZqf;pfe%+#*G>bA(SiOxb&d4Qyu5aPC*+U9K;MU#3!;8C9VPBw6O%i2)lE|Ate4%z zV~_9I11-F|^uCaI3Ql@;4V{}N-#*u`qZe76^(=QB9ClyW6(yk# z&%I{IM;%yoTG3_oNi5zn#O-2!Hx=w+V3T{wMcCw;>FuY@lY>^ie`K@<4B+u)x=^~| zY%ht=$zZ$!U<=BEJ;R@0fxHU7a=7yJsh^$_Pe=_Ovt@R>JL5nocYb3DfkHwuKq=`|@@hpLg?w7d4Kxds8lLy!9ri8z1Y*{t5|)1CcGs_3=)*6rz5|rM z{Y#=XoyIwSxo;*xm7-Xk7qQie_6N68kS<6K^c~dfIRYW>@Q~!EpOLr8-BaoVLD@S5x|phWe9SVxal4Awk7c*ol0vF7LnlZa(nl23D1kS`@z5fWr+Uh(e6}12W$!q zZo!c&z*EjDLL0)##Wk|9YMuq~0bXO1_jH*)rq|M`f`29>BST$Z9}TI9^%sy&RMAC0 zvyZ2H^1#&1jjY1H^d8Gnd02B`HnPL^xWN#LUWppB=So~V#(+6{rcKj89sFtJB~1g5 zBsc(YvY)(Jh&yL>BT}_L7s6g(Mb0~4ghSOD^6z&6goy*q0dLy@)3+z6X_WjEPI6mjtcnmQ*eRx^(#kJ z^E$XcD~dOe?7b8iKC>}1Yxc(iBFZQ$(XGG4A zG=UsLc$;vth6;4iWDj)tnmL#}#v@SZIbK->1td{)k|ai1-bz*jePQv~az}xujYCy| zUlcCUA@{NdY!I=R{xv{rk zG&u8ySW$7ecxNnmfF#Pp-`~|gHKi-=P9R3cFkMSf1{G*lq1qHKk)8nwxXT_o}L1bx7ym< zlK~2w^mOH#(C^++R7<%Z(smKmq}Dz4hDS$@SKYQ0>9s*5raJg6B~QG0_wI_t z{rjfw?(Ui-Fqs3{bK(5?I7nkPGBK$gu|>}MnV6hxfxK0y(q}5qLDWY)O!SD(An(e% z)yIu9?vj3;0)$7|6pHyoB*WtWT=4V|uer0c7M!>_F+JUuBpbRZJToD~lEP(1F#?%a7$wRM2J7jF?8Uy29jxvR9a z-@+=K6-7xF6A%>q*lK|jnfl4r8A#B#-gXYw-Nbf-^=9pSlLi<+V$ z_}Ci1e$58LoToNtcwyD~IHmNzVBl|Sj7hyZY70mDiel7zmgk0~!S<&Bp((ZnSr`n; z$mkj**r#V?w7|K2ZN0t6?Q~BG%k&(eH@B&rS&t#inWMpxwD>sZZV6Elj;{$iGhLcmFTuWK#z82$YVJwicQ&-Pi#S?$?2_x^jqTgFPfSgQJx&i5}ZO=^-hR{4#42o14D+OOL?I>xuAS)1=f3ER9=V9hJVTXq$|m)3kN zOp?nCrM}KA;W-r{OWA6?7p@yl8-Z#+a% z{9VGGUzlk9==VMfVtVX-w7LP2no~%IydL2Zr(nGynhq diff --git a/docs/grafana_s1.png b/docs/grafana_s1.png deleted file mode 100644 index efc5f4a66762e9408eb40f7adc1d58f5a342129b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53743 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�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 diff --git a/docs/grafana_s2.png b/docs/grafana_s2.png deleted file mode 100644 index cb51cdd02d891dc12b107bf0ea84e27b149a4b5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42120 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 diff --git a/docs/images/clippy.svg b/docs/images/clippy.svg deleted file mode 100644 index 8a77a3303..000000000 --- a/docs/images/clippy.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/docs/images/favicon.png b/docs/images/favicon.png deleted file mode 100644 index 0f3bda8eaa4feb9fe80f806243d585d1e838b9ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1253 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m{l@EB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`f(~1RD^r68eAMwS&*t9 zlvO-#2=9ZF3nBND}m`vf$McMz^NCM7;+1MHoK%2WtOF;xE1B+Du6w0m5JLeE;!AD z>P^Av7FSoCdi8;h(Fa8>QdGl)fawRsgeP1e2cGm(^ML8S2$-;)6R-9IGlfBbPl&6N zqvP^r%SuX0&Yn5r@8_41p8o06r<*r#9yoAd)~s34QBlvHJ=?r_b6;<7V?)FL|NqT) zKmQKYD^L>T7YyVg1BM66v64W!|DG<6Ar-ggT<)FJqQJqB;PByo)&K3bF6(p6Z$Ims zsWbPy3G)qkrhiOKlNbz^?qKO_kZxjK{GX-na^aPItxw+EYZSL&z9W6b_=BWfL$hYW zndddE0{jycE--DFzu?6IE{E9*KJH@+;Hg+(-N5$9R)M*K{{TZR<5SKZj88ZZd{@1| zu>1(yj0}d0Z)VKD>3F}r(RViAmoEX&95W~LHL$&zWYQlsyNaz=_iu2b+}3@5?2q(4 z9xJ|BE4zQT^L}1~_@%)+_6WKCVP#pjev0;;qZ`?yn?BCjvT%8!{CWwV2i2FNZUrB^ zInmc5j!T^@r9{ebEm!(9x$mnoum0a$G5w?R0fyo_r71_fmAimJ!QkoY=d#Wzp$Pz* C*}?|^ diff --git a/docs/images/gopher-404.jpg b/docs/images/gopher-404.jpg deleted file mode 100644 index df1064868ef8fac1d0b3d66617e470266d70e7f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 220526 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

    e5?& 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 BCjNIF&}v`+@W|!a4HR1}acu&_xHa24&#r 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 diff --git a/docs/images/home_bg.jpg b/docs/images/home_bg.jpg deleted file mode 100644 index 1b7086eacb61afe9215eefe16240ceeaadca0676..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204942 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 - - - Crunchy Data Container Suite Documentation - - - - - -Crunchy Data Container Suite :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -

      - - - - -
      -
      -
      - - -
      - - - - - - - - - navigation - - -
      -
      -Crunchy Data Logo -
      -
      -
      -

      Latest Release: 2.1.0 2018-08-13

      -
      -
      -

      General

      -
      -
      -

      Please view the official Crunchy Data Container Suite documentation here. If you are -interested in contributing or making an update to the documentation, please view the Contributing Guidelines.

      -
      -
      -

      Warning: The master branch is considered unstable. Please consult the tagged release -currently deployed in your environment.

      -
      -
      -
      -
      -

      What is the Container Suite?

      -
      -
      -

      The Crunchy Container Suite provides Docker containers that enable -rapid deployment of PostgreSQL, including administration and -monitoring tools. Multiple styles of deploying PostgreSQL clusters -are supported.

      -
      -
      -

      Requirements

      -
      -

      The containers will execute in the following environments:

      -
      -
      -
        -
      • -

        Docker 1.12 and above

        -
      • -
      • -

        Openshift 3.4 and above

        -
      • -
      • -

        Kubernetes 1.5 and above

        -
      • -
      -
      -
      -
      -

      Containers

      -
      -

      The project includes the following containers:

      -
      -
      - -
      -
      -
      -containers -
      -
      -
      -

      For Kubernetes users of these containers, there is an associated -project worth taking a look at that uses the containers found -in this repo and provides a higher level automation. -That project is the postgres-operator.

      -
      -
      -

      Further descriptions of each of these containers and environment variables that can be used to tune them -can be found in the Container Specifications document.

      -
      -
      -
      -
      -
      -

      Getting Started

      -
      -
      -

      Complete build and install documentation is found here. The provided Dockerfiles build the containers -on a Centos 7 base image and use the community PostgreSQL RPMs.

      -
      -
      -

      Crunchy provides a commercially supported version of these containers -built upon RHEL 7 and the Crunchy supported PostgreSQL. Contact Crunchy -for more details at http://www.crunchydata.com.

      -
      -
      -
      -
      -

      Usage

      -
      -
      -

      Various examples are provided in the Getting Started documentation for running in Docker, -Kubernetes, and OpenShift environments.

      -
      -
      -

      You will need to set up your environment as per the Installation documentation in order to -execute the examples.

      -
      -
      -
      - - - - - - -
      - -
      -
      -
      - - - -
      -
      -
      -
      - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/index.json b/docs/index.json deleted file mode 100644 index 470d9934e..000000000 --- a/docs/index.json +++ /dev/null @@ -1,260 +0,0 @@ -[ -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres/", - "title": "crunchy-postgres", - "tags": [], - "description": "", - "content": " PostgreSQL (pronounced \u0026ldquo;post-gress-Q-L\u0026rdquo;) is an open source, ACID compliant, relational database management system (RDBMS) developed by a worldwide team of volunteers. The crunchy-postgres container image is unmodified, open source PostgreSQL packaged and maintained by professionals.\nFeatures The following features are supported by the crunchy-postgres container:\n Kubernetes and OpenShift secrets Backup and restoration from various tools: pgbackrest, pg_basebackup and pg_dump/pg_restore. Custom mounted configuration files (see below) Async and Sync Replication Packages The crunchy-postgres Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) pgBackRest (2.x) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PG_DATABASE None Set this value to create an initial database PG_PRIMARY_PORT None Set this value to configure the primary PostgreSQL port. It is recommended to use 5432. PG_MODE None Set to primary, replica or set to specify the mode of the database PG_USER None Set this value to specify the username of the general user account PG_PASSWORD None Set this value to specify the password of the user role PG_PRIMARY_USER None Set this value to specify the username of the replication user PG_PRIMARY_PASSWORD None Set this value to specify the password of the replication user PG_ROOT_PASSWORD None Set this value to specify the password of the superuser role Optional Name Default Description ARCHIVE_MODE Off Set this value to on to enable continuous WAL archiving ARCHIVE_TIMEOUT 60 Set to a number (in seconds) to configure archive_timeout in postgresql.conf CHECKSUMS true Enables data-checksums during initialization of the database. Can only be set during initial database creation. Set to false to disable data checksums. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. ENABLE_SSHD FALSE Set this value to true to enable SSHD. See SSHD Documentation for detailed setup instructions MAX_CONNECTIONS 100 Sets the max_connections value in postgresql.conf MAX_WAL_SENDERS 6 Set this value to configure the max number of WAL senders (replication) PG_LOCALE UTF-8 Set the locale of the database PG_PRIMARY_HOST None Set this value to specify primary host. Note: only used when PG_MODE != primary PG_REPLICA_HOST None Set this value to specify the replica host label. Note; used when PG_MODE is set PGAUDIT_ANALYZE None Set this to enable pgaudit_analyze PGBOUNCER_PASSWORD None Set this to enable pgBouncer support by creating a special pgbouncer user for authentication through the connection pooler. PGMONITOR_PASSWORD None Set this to enable pgMonitor support by creating a special ccp_monitoring user for collecting metrics from PostgreSQL servers. Required for the crunchy-collect container. PGDATA_PATH_OVERRIDE None Set this value to override the /pgdata directory name. By default /pgdata uses hostname of the container. In some cases it may be required to override this with a custom name (such as in a Statefulset) SHARED_BUFFERS 128MB Set this value to configure shared_buffers in postgresql.conf SYNC_REPLICA None Set this value to specify the names of replicas that should use synchronized replication TEMP_BUFFERS 8MB Set this value to configure temp_buffers in postgresql.conf WORK_MEM 4MB Set this value to configure work_mem in postgresql.conf XLOGDIR None Set this value to configure PostgreSQL to send WAL to the /pgwal volume (by default WAL is stored in /pgdata) Volumes Name Description /backrestrepo Volume used by the pgbackrest backup tool to store physical backups. /backup Volume used by the pg_basebackup backup tool to store physical backups. /pgconf Volume used to store custom configuration files mounted to the container. /pgdata Volume used to store the data directory contents for the PostgreSQL database. /pgwal Volume used to store Write Ahead Log (WAL) when XLOGDIR environment variable is set to true. /recover Volume used for Point In Time Recovery (PITR) during startup of the PostgreSQL database. /sshd Volume used to store SSHD requirements (sshd_config and server key). Custom Configuration The following configuration files can be mounted to the /pgconf volume in the crunchy-postgres container to customize the runtime:\n Name Description ca.crt Certificate of the CA used by the server when using SSL authentication ca.crl Revocation list of the CA used by the server when using SSL authentication pg_hba.conf Client authentication rules for the database pg_ident.conf Mapping of external users (such as SSL certs, GSSAPI, LDAP) to database users pgbackrest.conf pgBackRest configurations postgresql.conf PostgreSQL settings server.key Key used by the server when using SSL authentication server.crt Certificate used by the server when using SSL authentication setup.sql Custom SQL to execute against the database. Note: only run during the first startup (initialization) " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/installation/", - "title": "Installation", - "tags": [], - "description": "", - "content": "Latest Release: 2.1.0 2018-08-13\n Installation To set up the environment, visit the Environment Setup document. From there, navigate to Build the Containers page to either build or pull the container images necessary to run examples. The final step will be to configure storage in the Storage Configuration page, with either HostPath, NFS, or dynamic storage options.\n Next Steps There are many ways to configure the examples and containers further. Descriptions of each container offered and the variables that can be used to customize them are found on the Container Specifications page.\n Information can be found on the full scope of examples that can be performed on the Getting Started page.\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/installation/environment-setup/", - "title": "Environment Setup", - "tags": [], - "description": "", - "content": "Table of Contents Requirements Project Environment Installing Requirements CentOS 7 RHEL 7 PostgreSQL Docker OpenShift Kubernetes Helm Creating a Demo Namespace Kubernetes OpenShift Next Steps Latest Release: 2.1.0 2018-08-13\n Requirements The Crunchy Container Suite can run on different environments including:\n Docker 1.12+\n OpenShift Container Platform 3.6+\n Kubernetes 1.8+\n In this document we list the basic installation steps required for these environments.\n These installation instructions are developed and tested for the following operating systems:\n CentOS 7\n RHEL 7\n Project Environment First add the following lines to your .bashrc file to set the project paths:\n export GOPATH=$HOME/cdev export GOBIN=$GOPATH/bin export PATH=$PATH:$GOBIN export CCP_BASEOS=centos7 export CCP_PGVERSION=10 export CCP_PG_FULLVERSION=10.5 export CCP_VERSION=2.1.0 export CCP_IMAGE_PREFIX=crunchydata export CCP_IMAGE_TAG=$CCP_BASEOS-$CCP_PG_FULLVERSION-$CCP_VERSION export CCPROOT=$GOPATH/src/github.com/crunchydata/crunchy-containers export CCP_SECURITY_CONTEXT=\"\" export CCP_CLI=kubectl export CCP_NAMESPACE=demo Please see the Storage Configuration document for configuring storage using environment variables set in .bashrc.\n Additionally, the CCP_CLI setting above indicates you are running the examples on a Kubernetes platform and not an OpenShift platform. For OpenShift, use the value of oc as the CCP_CLI variable instead.\n It will be necessary to refresh your .bashrc file in order for the changes to take effect.\n . ~/.bashrc Next, set up a project directory structure and pull down the project:\n mkdir -p $HOME/cdev/src $HOME/cdev/pkg $HOME/cdev/bin Installing Requirements CentOS 7 cd $GOPATH sudo yum -y install golang git docker go get github.com/tools/godep cd src/github.com mkdir crunchydata cd crunchydata git clone https://github.com/crunchydata/crunchy-containers cd crunchy-containers git checkout 2.2.0 go get github.com/blang/expenv If you are a Crunchy enterprise customer, you will place the Crunchy repository key and yum repository file into the $CCPROOT/conf directory at this point. These files can be obtained through https://access.crunchydata.com/ on the downloads page.\n RHEL 7 When setting up the environment on RHEL 7, there are slightly different steps that need to be taken.\n cd $GOPATH sudo subscription-manager repos --enable=rhel-7-server-optional-rpms sudo yum-config-manager --enable rhel-7-server-extras-rpms sudo yum -y install git golang go get github.com/tools/godep cd src/github.com mkdir crunchydata cd crunchydata git clone https://github.com/crunchydata/crunchy-containers cd crunchy-containers git checkout 2.2.0 go get github.com/blang/expenv If you are a Crunchy enterprise customer, you will place the Crunchy repository key and yum repository file into the $CCPROOT/conf directory at this point. These files can be obtained through https://access.crunchydata.com/ on the downloads page.\n PostgreSQL These installation instructions assume the installation of PostgreSQL 10 through the official PGDG repository. View the documentation located here in order to view more detailed notes or install a different version of PostgreSQL.\n Locate and edit your distribution\u0026#8217;s .repo file, located:\n On CentOS: /etc/yum.repos.d/CentOS-Base.repo, [base] and [updates] sections\n On Red Hat: /etc/yum/pluginconf.d/rhnplugin.conf [main] section\n To the section(s) identified above, you need to append a line (otherwise dependencies might resolve to the PostgreSQL supplied by the base repository):\n exclude=postgresql* Next, install the RPM relating to the base operating system and PostgreSQL version you wish to install. The RPMs can be found here.\n For example, to install PostgreSQL 10 on a CentOS 7 system:\n sudo yum -y install https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm Or to install PostgreSQL 10 on a RHEL 7 system:\n sudo yum -y install https://download.postgresql.org/pub/repos/yum/testing/10/redhat/rhel-7-x86_64/pgdg-redhat10-10-2.noarch.rpm You\u0026#8217;ll need to update your system:\n sudo yum -y update Then, go ahead and install the PostgreSQL server package.\n sudo yum -y install postgresql10-server.x86_64 Docker As good practice, at this point you\u0026#8217;ll update your system.\n sudo yum -y update Now we\u0026#8217;ll install Docker.\n sudo yum -y install docker After that, it\u0026#8217;s necessary to add the docker group and give your user access to that group (here referenced as someuser):\n sudo groupadd docker sudo usermod -a -G docker someuser Remember to log out of the someuser account for the Docker group to be added to your current session. Once it\u0026#8217;s added, you\u0026#8217;ll be able to run Docker commands from your user account.\n su - someuser You can ensure your someuser account is added correctly by running the following command and ensuring docker appears as one of the results:\n groups Before you start Docker, you might consider configuring Docker storage: This is described if you run:\n man docker-storage-setup Follow the instructions available on the main OpenShift documentation page to configure Docker storage appropriately.\n These steps are illustrative of a typical process for setting up Docker storage. You will need to run these commands as root.\n First, add an extra virtual hard disk to your virtual machine (see this blog post for tips on how to do so).\n Run this command to format the drive, where /dev/sd? is the new hard drive that was added:\n fdisk /dev/sd? Next, create a volume group on the new drive partition within the fdisk utility:\n vgcreate docker-vg /dev/sd? Then, you\u0026#8217;ll need to edit the docker-storage-setup configuration file in order to override default options. Add these two lines to /etc/sysconfig/docker-storage-setup:\n DEVS=/dev/sd? VG=docker-vg Finally, run the command docker-storage-setup to use that new volume group. The results should state that the physical volume /dev/sd? and the volume group docker-vg have both been successfully created.\n Next, we enable and start up Docker:\n sudo systemctl enable docker.service sudo systemctl start docker.service Verify that Docker version 1.12.6 was installed, as per the OpenShift 3.6 requirements.\n docker version OpenShift See the OpenShift installation guide for details on how to install OpenShift Enterprise on your host. The main instructions are here:\n https://docs.openshift.com/container-platform/3.6/install_config/install/quick_install.html\n Note If you install OpenShift Enterprise on a server with less than 16GB memory and 40GB of disk, the following Ansible variables need to be added to ~/.config/openshift/installer.cfg.yml prior to installation: openshift_check_min_host_disk_gb: '10' # min 10gb disk openshift_check_min_host_memory_gb: '3' # min 3gb memory Kubernetes See kubeadm for installing the latest version of Kubernetes.\n Please see here to view the official documentation regarding configuring DNS for your Kubernetes cluster.\n Make sure your hostname resolves to a single IP address in your /etc/hosts file. The NFS examples will not work otherwise and other problems with installation can occur unless you have a resolving hostname.\n You should see a single IP address returned from this command:\n hostname --ip-address When running the containers in GKE Role Based Account Control will need to be set up.\n kubectl create clusterrolebinding cluster-admin-binding \\ --clusterrole cluster-admin --user $(gcloud config get-value account) If more than one user will be running on the same kubernetes cluster in GKE, from the above command cluster-admin-binding will need to be unique and is the name that is added to the clusterrolebidings. The example below will add another user to the clusterrolebinding with a unique value.\n $ ACCOUNT=$(gcloud info --format='value(config.account)') $ kubectl create clusterrolebinding \u0026lt;unique\u0026gt;-cluster-admin-binding \\ --clusterrole cluster-admin \\ --user $ACCOUNT ACCOUNT is just your google gcloud acount login, ie username@google.com Helm Some Kubernetes Helm examples are provided in the following directory as one option for deploying the Container Suite.\n $CCPROOT/examples/helm/ Once you have your Kubernetes environment configured, it is simple to get Helm up and running. Please refer to this document to get Helm installed and configured properly.\n Creating a Demo Namespace In Kubernetes, a concept called a namespace provides the means to separate created resources or components into individual logically grouped partitions.\n It is considered a best practice to have dedicated namespaces for projects in both testing and production environments.\n Note All examples in the Crunchy Container Suite operate within the namespace defined by the environment variable $CCP_NAMESPACE. The instructions below illustrate how to set up and work within new namespaces or projects in both Kubernetes and OpenShift. Kubernetes This section will illustrate how to set up a new Kubernetes namespace called demo, and will then show how to provide permissions to that namespace to allow the Kubernetes examples to run within that namespace.\n First, view currently existing namespaces:\n $ kubectl get namespace NAME STATUS AGE default Active 21d kube-public Active 21d kube-system Active 21d Then, create a new namespace called demo:\n $ kubectl create -f $CCPROOT/conf/demo-namespace.json namespace \"demo\" created $ kubectl get namespace demo NAME STATUS AGE demo Active 7s Then set the namespace as the current location to avoid using the wrong namespace:\n $ kubectl config set-context $(kubectl config current-context) --namespace=demo We can verify that the namespace was set correctly through the following command:\n $ kubectl config view | grep namespace: namespace: demo OpenShift This section assumes you are first logging into OpenShift as a normal user such as:\n oc login -u someuser For our development purposes only, we typically specify the OCP Authorization policy of AllowAll as documented here:\n https://docs.openshift.com/container-platform/3.7/install_config/configuring_authentication.html#AllowAllPasswordIdentityProvider\n We do not recommend this authentication policy for a production deployment of OCP.\n The next step is to create a demo namespace to run the examples within. The name of this OCP project will be what you supply in the CCP_NAMESPACE environment variable:\n $ oc new-project demo --description=\"Crunchy Containers project\" --display-name=\"Crunchy-Containers\" Now using project \"demo\" on server \"https://127.0.0.1:8443\". $ export CCP_NAMESPACE=demo If we view the list of projects, we can see the new project has been added and is \"active\".\n $ oc get projects NAME DISPLAY NAME STATUS demo Crunchy-Containers Active myproject My Project Active If you were on a different project and wanted to switch to the demo project, you would do so by running the following:\n $ oc project demo Now using project \"demo\" on server \"https://127.0.0.1:8443\". Finally, you will want to ensure the proper privileges are added to the user in order to have the ability to create persistent volumes. A command similar to the following can be used to accomplish this, by adding the cluster-admin role to the demo user:\n oc adm policy add-cluster-role-to-user cluster-admin demo Next Steps Next, build or pull the container images as demonstrated in the Build the Containers document.\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres-gis/", - "title": "crunchy-postgres-gis", - "tags": [], - "description": "", - "content": " PostgreSQL (pronounced \u0026ldquo;post-gress-Q-L\u0026rdquo;) is an open source, ACID compliant, relational database management system (RDBMS) developed by a worldwide team of volunteers. The crunchy-postgres-gis container image is unmodified, open source PostgreSQL packaged and maintained by professionals. This image is identical to the crunchy-postgres image except it includes the open source geospatial extension PostGIS for PostgreSQL in addition to the language extension PL/R which allows for writing functions in the R statistical computing language.\nFeatures The following features are supported by the crunchy-postgres-gis container:\n Kubernetes and OpenShift secrets Backup and restoration from various tools: pgbackrest, pg_basebackup and pg_dump/pg_restore. Custom mounted configuration files (see below) Async and Sync Replication PostGIS PL/R Packages The crunchy-postgres-gis Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) pgBackRest (2.x) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PG_DATABASE None Set this value to create an initial database PG_PRIMARY_PORT None Set this value to configure the primary PostgreSQL port. It is recommended to use 5432. PG_MODE None Set to primary, replica or set to specify the mode of the database PG_USER None Set this value to specify the username of the general user account PG_PASSWORD None Set this value to specify the password of the user role PG_PRIMARY_USER None Set this value to specify the username of the replication user PG_PRIMARY_PASSWORD None Set this value to specify the password of the replication user PG_ROOT_PASSWORD None Set this value to specify the password of the superuser role Optional Name Default Description ARCHIVE_MODE Off Set this value to on to enable continuous WAL archiving ARCHIVE_TIMEOUT 60 Set to a number (in seconds) to configure archive_timeout in postgresql.conf CHECKSUMS Off Enables data-checksums during initialization of the database. Can only be set during initial database creation. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. ENABLE_SSHD FALSE Set this value to true to enable SSHD. See SSHD Documentation for detailed setup instructions MAX_CONNECTIONS 100 Sets the max_connections value in postgresql.conf MAX_WAL_SENDERS 6 Set this value to configure the max number of WAL senders (replication) PG_LOCALE UTF-8 Set the locale of the database PG_PRIMARY_HOST None Set this value to specify primary host. Note: only used when PG_MODE != primary PG_REPLICA_HOST None Set this value to specify the replica host label. Note; used when PG_MODE is set PGAUDIT_ANALYZE None Set this to enable pgaudit_analyze PGBOUNCER_PASSWORD None Set this to enable pgBouncer support by creating a special pgbouncer user for authentication through the connection pooler. PGDATA_PATH_OVERRIDE None Set this value to override the /pgdata directory name. By default /pgdata uses hostname of the container. In some cases it may be required to override this with a custom name (such as in a Statefulset) SHARED_BUFFERS 128MB Set this value to configure shared_buffers in postgresql.conf SYNC_REPLICA None Set this value to specify the names of replicas that should use synchronized replication TEMP_BUFFERS 8MB Set this value to configure temp_buffers in postgresql.conf WORK_MEM 4MB Set this value to configure work_mem in postgresql.conf XLOGDIR None Set this value to configure PostgreSQL to send WAL to the /pgwal volume (by default WAL is stored in /pgdata) Volumes Name Description /backrestrepo Volume used by the pgbackrest backup tool to store physical backups. /backup Volume used by the pg_basebackup backup tool to store physical backups. /pgconf Volume used to store custom configuration files mounted to the container. /pgdata Volume used to store the data directory contents for the PostgreSQL database. /pgwal Volume used to store Write Ahead Log (WAL) when XLOGDIR environment variable is set to true. /recover Volume used for Point In Time Recovery (PITR) during startup of the PostgreSQL database. /sshd Volume used to store SSHD requirements (sshd_config and server key). Custom Configuration The following configuration files can be mounted to the /pgconf volume in the crunchy-postgres container to customize the runtime:\n Name Description ca.crt Certificate of the CA used by the server when using SSL authentication ca.crl Revocation list of the CA used by the server when using SSL authentication pg_hba.conf Client authentication rules for the database pg_ident.conf Mapping of external users (such as SSL certs, GSSAPI, LDAP) to database users pgbackrest.conf pgBackRest configurations postgresql.conf PostgreSQL settings server.key Key used by the server when using SSL authentication server.crt Certificate used by the server when using SSL authentication setup.sql Custom SQL to execute against the database. Note: only run during the first startup (initialization) Verifying PL/R In order to verify the successful initialization of the PL/R extension, the following commands can be run:\ncreate extension plr; SELECT * FROM plr_environ(); SELECT load_r_typenames(); SELECT * FROM r_typenames(); SELECT plr_array_accum(\u0026#39;{23,35}\u0026#39;, 42); CREATE OR REPLACE FUNCTION plr_array (text, text) RETURNS text[] AS \u0026#39;$libdir/plr\u0026#39;,\u0026#39;plr_array\u0026#39; LANGUAGE \u0026#39;c\u0026#39; WITH (isstrict); select plr_array(\u0026#39;hello\u0026#39;,\u0026#39;world\u0026#39;);" -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/", - "title": "Getting Started", - "tags": [], - "description": "", - "content": "Latest Release: 2.1.0 2018-08-13\n Examples are provided for the Kubernetes, OpenShift, and Docker environments in the Kubernetes and OpenShift document.\n For documentation relating to OpenShift Templates examples, visit the OpenShift Templates document.\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/installation/build-the-containers/", - "title": "Build the Containers", - "tags": [], - "description": "", - "content": "Table of Contents Build the Containers Next Steps Latest Release: 2.1.0 2018-08-13\n Build the Containers At this point, you have a decision to make - either download prebuilt containers from Dockerhub, or build the containers on your local host.\n To download the prebuilt containers, make sure you can login to Dockerhub, and then run the following:\n docker login cd $CCPROOT ./bin/pull-from-dockerhub.sh Or if you\u0026#8217;d rather build the containers from source, perform a container build as follows:\n godep restore cd $CCPROOT make setup make all After this, you will have all the Crunchy containers built and are ready for use in a standalone Docker environment.\n Next Steps Next, configure a storage type as demonstrated in the Storage Configuration document.\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backup/", - "title": "crunchy-backup", - "tags": [], - "description": "", - "content": " The crunchy-backup container executes a full backup against another database container using the standard pg_basebackup utility that is included with PostgreSQL.\nFeatures The following features are supported by the crunchy-backup container:\n Backup and restoration from: pg_basebackup Packages The crunchy-backup Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description BACKUP_LABEL crunchy-backup The label for the backup. BACKUP_HOST None Name of the database the backup is being performed on. BACKUP_USER None Username for the PostgreSQL role being used. BACKUP_PASS None Password for the PostgreSQL role being used. BACKUP_PORT 5432 Database port used to do the backup. Optional Name Default Description CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. Volumes Name Description /backup Volume used by the pg_basebackup backup tool to store physical backups. /pgdata Volume used to store the data directory contents for the PostgreSQL database. Backup Location Backups are stored in a mounted backup volume location, using the database host name plus -backups as a sub-directory, then followed by a unique backup directory based upon a date/timestamp. It is left to the user to perform database backup archives in this current version of the container. This backup location is referenced when performing a database restore.\n" -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/", - "title": "Container Specifications", - "tags": [], - "description": "", - "content": "Latest Release: 2.1.0 2018-08-13\n Introduction Each of the containers found within the Crunchy Container Suite for PostgreSQL are described in further detail within their respective pages.\n The containers and their relationships to the overall architecture are depicted below:\n Containers The following container images are provided with further information:\n crunchy-postgres\n crunchy-postgres-gis\n crunchy-backup\n crunchy-pgdump\n crunchy-collect\n crunchy-prometheus\n crunchy-grafana\n crunchy-pgbadger\n crunchy-pgpool\n crunchy-watch\n crunchy-vacuum\n crunchy-dba\n crunchy-pgbouncer\n crunchy-backrest-restore\n crunchy-pgadmin4\n crunchy-pgrestore\n crunchy-upgrade\n crunchy-sim\n crunchy-postgres The crunchy-postgres container executes the Postgres database.\n Packages The container image is built using either the Crunchy Postgres release or the community version based upon a flag in the Makefile.\n The crunchy-postgres RPMs are available to Crunchy customers only. The Crunchy release is meant for customers that require enterprise level support.\n The PGDG community RPMs can be used as well by simply commenting out the Crunchy yum repo within the Dockerfiles and uncommenting the PGDG yum repo.\n setup.sql The setup.sql script is used to define startup SQL commands that are executed when the database is first created.\n Environment Variables PG_MODE - either primary, replica or set, this value determines whether the database is set up as a primary or replica instance. In the case of set, it means the container is started within a StatefulSet in a Kubernetes cluster.\n PG_PRIMARY_USER - the value to use for the user ID created as primaryuser. The primaryuser has super user privileges.\n PG_PRIMARY_PASSWORD - the password for the PG_PRIMARY_USER database user\n PG_USER - the value to use for the user ID created as a normal user. This user is created as part of the setup.sql script upon database creation and allows users to predefine an application user.\n PG_PASSWORD - the password for the PG_USER database user that is created\n PG_DATABASE - a database that is created upon database initialization\n PG_ROOT_PASSWORD - the PostgreSQL user password set up upon database initialization\n PG_LOCALE - if set, the locale you want to create the database with, if not set, the default locale is used\n SYNC_REPLICA - if set, this value is used to specify the application_name of a replica that will be used for a synchronous replication\n CHECKSUMS - if set, this value is used to enable the --data-checksums option when initdb is executed at initialization, if not set, the default is to not enable data checksums\n ARCHIVE_MODE - if set to on, will enable continuous WAL archiving by setting the value within the postgresql.conf file archive_mode setting, if not set, the default is off\n ARCHIVE_TIMEOUT - if set to a number (in seconds) , will specify the postgresql.conf archive_timeout setting, if not set, the default value of 60 is used.\n PGAUDIT_ANALYZE - if set, will cause the container to also start the pgaudit_analyze program in the background\n PG_PRIMARY_HOST - for when PG_MODE is set, specifies the primary host for setting the primary label\n PG_REPLICA_HOST - for when PG_MODE is set, specifies the replica host for setting the replica label\n PGDATA_PATH_OVERRIDE - if set, will cause the container to use a /pgdata path name of your choosing rather than the hostname of the container which is the default. This is useful for a primary in a deployment.\n XLOGDIR - if set to true, will cause initdb to include --xlogdir=$PGWAL, this will cause a symlink to be created from /pgdata/containername/pg_wal (or pg_xlog if you\u0026#8217;re running PG 9.5 or 9.6) to /pgwal/containername-wal\n TEMP_BUFFERS - default is 8MB, set this value to override this PostgreSQL configuration setting\n MAX_CONNECTIONS - default is 100, set this value to override this PostgreSQL configuration setting\n SHARED_BUFFERS - default is 128MB, set this value to override this PostgreSQL configuration setting\n WORK_MEM - default is 4MB, set this value to override this PostgreSQL configuration setting\n MAX_WAL_SENDERS - default is 6, set this value to override this PostgreSQL configuration setting\n ENABLE_SSHD- default is false, set this value to true to enable SSHD\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n Features The following features are supported by the crunchy-postgres container:\n use of OpenShift secrets\n ability to restore from a database backup\n use of custom pg_hba.conf and postgresql.conf files\n ability to override postgresql.conf configuration parameters\n ability to override the default setup.sql script\n ability to set the database locale\n ability to specify a synchronous replica application_name\n ability to specify a recovery using PITR and WAL files\n ability to enable SSHD\n Locale Support Adding locale support to the container is accomplished by running 'yum reinstall glibc_common' within the container, this increases the size of the container image and can be removed if you do not require specific locale support.\n You can specify the PG_LOCALE env var which is passed to the initdb command when the initial data files are created, for example:\n \"name\": \"PG_LOCALE\", \"value\": \"fr_BE.UTF-8\" By default, no locale is specified when the initdb command is executed.\n crunchy-postgres-gis This container is the same as the crunchy-postgres container except that it includes the following PostgreSQL extensions:\n postgis\n pl/r\n You can test the pl/r extension by running the following commands for example:\n create extension plr; SELECT * FROM plr_environ(); SELECT load_r_typenames(); SELECT * FROM r_typenames(); SELECT plr_array_accum('{23,35}', 42); CREATE OR REPLACE FUNCTION plr_array (text, text) RETURNS text[] AS '$libdir/plr','plr_array' LANGUAGE 'c' WITH (isstrict); select plr_array('hello','world'); crunchy-backup The crunchy-backup container executes a pg_basebackup against another database container. The backup is a full backup using the standard utility included with PostgreSQL, pg_basebackup.\n Backup Location Backups are stored in a mounted backup volume location, using the database host name plus -backups as a sub-directory, then followed by a unique backup directory based upon a date/timestamp. It is left to the user to perform database backup archives in this current version of the container. This backup location is referenced when performing a database restore.\n Dependencies The container is meant to be using NFS or a similar network file system to persist database backups.\n Environment Variables BACKUP_LABEL - when set, will set the label of the backup, if not set the default label used is crunchy-backup\n BACKUP_HOST - required, this is the database we will be doing the backup for\n BACKUP_USER - required, this is the database user we will be doing the backup with\n BACKUP_PASS - required, this is the database password we will be doing the backup with\n BACKUP_PORT - required, this is the database port we will be doing the backup with\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n crunchy-pgdump The crunchy-pgdump container executes either a pg_dump or pg_dumpall against another Postgres database.\n Dump Location Dumps are stored in a mounted backup volume location, using the database host name plus -backups as a sub-directory, then followed by a unique backup directory based upon a date/timestamp. It is left to the user to perform database dump archives in this current version of the container.\n Dependencies The container is meant to be using NFS or a similar network file system to persist database dumps.\n Environment Variables REQUIRED ARGS PGDUMP_DB - Database to connect to\n PGDUMP_HOST - Hostname of the PostgreSQL database to connect to\n PGDUMP_PASS - Password of the PostgreSQL role used by the pgdump container\n PGDUMP_USER - PostgreSQL Role used by the pgdump container\n OPTIONAL/EXTENDED ARGS PGDUMP_ALL - Run pg_dump instead of pg_dumpall. Default is true, set to false to use pg_dump\n PGDUMP_CUSTOM_OPTS - Advanced options to pass into pg_dump or pg_dumpall. Default is empty\n PGDUMP_FILENAME - Name of the file created by the pgdump container. Default is dump\n PGDUMP_PORT - Port of the PostgreSQL database to connect to. Default is 5432\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs Note: this mode can reveal secrets in logs.\n Note: For a list of advanced options for configuring the PGDUMP_CUSTOM_OPTS variable, see the official documentation:\n https://www.postgresql.org/docs/current/static/app-pgdump.html\n https://www.postgresql.org/docs/current/static/app-pg-dumpall.html\n crunchy-collect Description Crunchy Collect container provides real time metrics about the PostgreSQL database via an API. These metrics are scrapped and stored by Crunchy Prometheus time-series database and visualized by Crunchy Grafana.\n Requirements This container requires TCP access to the PostgreSQL database to run queries for collecting metrics. The PostgreSQL database to be scrapped is specified by the DATA_SOURCE_NAME environment variable.\n Additionally, custom queries to collect metrics can be specified by the user. By mounting a queries.yml file to /conf on the container, additionally metrics can be specified for the API to collect. For an example of a queries.yml file, see here.\n Environment Variables Required:\n DATA_SOURCE_NAME - The URL for the PostgreSQL server\u0026#8217;s data source name. This is required to be in the form of postgresql://.\n Optional: * CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n crunchy-prometheus Description Prometheus is a multi-dimensional time series data model with an elastic query language. It is used in collaboration with Grafana in this metrics suite. Overall, it’s reliable, manageable, and operationally simple for efficiently storing and analyzing data for large-scale environments. It scraps metrics from exporters such as Crunchy Collect.\n The following port is exposed by the crunchy-prometheus container:\n crunchy-prometheus:9090 - the Prometheus web user interface\n Requirements The Crunchy Prometheus container must be able to reach the Crunchy Collect container to scrape metrics.\n By default, Crunchy Prometheus detects which environment its running on (Docker, Kube or OCP) and applies a default configuration. If this container is running on Kube or OCP, it will use the Kubernetes API to discover pods with the label \"crunchy-collect\": \"true\". Crunchy Collect container must have this label to be discovered.\n For Docker environments the Crunchy Collect hostname must be specified as an environment variable.\n A user may define a custom prometheus.yml file and mount to /conf for custom configuration. For a configuration examples, see here.\n Environment Variables Required:\n COLLECT_HOST - Hostname of Crunchy Collect container. Only required in Docker environments.\n Optional:\n SCRAPE_INTERVAL - default is \"5s\", set this value to the number of seconds to scrape metrics from exporters.\n SCRAPE_TIMEOUT - default is \"5s\", set this value to the number of seconds to timeout when scraping metrics from exporters.\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n crunchy-grafana Description Visual dashboards are created from the collected and stored data that crunchy-collect and crunchy-prometheus provides with the crunchy-grafana container, which hosts a web-based graphing dashboard called Grafana.\n Grafana is an open-source platform which can then apply the defined metrics and visualize information through various tools. It is extremely flexible with a powerful query and transformation language, producing beautiful and easily understandable graphics to analyze and monitor your data.\n By default, Crunchy Grafana will register the Crunchy Prometheus datasource within Grafana and import a premade dashboard for PostgreSQL monitoring.\n The following port is exposed by the crunchy-grafana container:\n crunchy-grafana:3000 - the Grafana web user interface\n Requirements The Crunchy Grafana container must be able to reach the Crunchy Prometheus container.\n Users must specify an administrator user and password to provide basic authentication for the web frontend.\n Additionally the Prometheus Host and Port are required. If Prometheus uses basic authentication, users must specify the username and password to access Prometheus via environment variables.\n Users may define a custom defaults.ini file and mount to /conf for custom configuration. For a configuration examples, see here.\n Environment Variables Required:\n ADMIN_USER - specifies the administrator user to be used when logging into the web frontend.\n ADMIN_PASS - specifies the administrator password to be used when logging into the web frontend.\n PROM_HOST - specifies the Prometheus container hostname for auto registering the prometheus datasource.\n PROM_PORT - specifies the Prometheus container port for auto registering the prometheus datasource.\n Optional:\n PROM_USER - specifies the Prometheus username, if one is required.\n PROM_PASS - specifies the Prometheus password, if one is required.\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n crunchy-pgbadger The crunchy-pgbadger container executes the pgbadger utility. A small http server is running on the container, when a request is made to:\n http://\u0026lt;\u0026lt;ip address\u0026gt;\u0026gt;:10000/api/badgergenerate Environment Variables Optional:\n BADGER_TARGET - only used in standalone mode to specify the name of the container, also used to find the location of the database log files in /pgdata/$BADGER_TARGET/pg_log/*.log\n BADGER_CUSTOM_OPTS - no default, set this value to provide custom flags to pgbadger. For a list of optional flags, see the official pgBadger documentation.\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n Features The following features are supported by the crunchy-pgbadger container:\n Generate a full report by default\n Optional custom options for more advanced use cases (such as incremental reports)\n Report persistence on a volume\n crunchy-pgpool The crunchy-pgpool container executes the pgpool utility. Pgpool can be used to provide a smart PostgreSQL-aware proxy to a PostgreSQL cluster, both primary and replica, so that applications can only have to work with a single database connection.\n Postgres replicas are read-only whereas a primary is both read and write capable.\n The default pgpool examples use a Secret to hold the set of pgpool configuration files used by the examples. The Secret is mounted into the pgconf volume mount where the container will look to find configuration files. If you do not specify your own configuration files via a Secret then you can specify environment variables to the container that it will attempt to use to configure pgpool, this is not recommended however for a real pgpool deployment.\n Environment Variables PG_USERNAME - user to connect to PostgreSQL\n PG_PASSWORD - user password to connect to PostgreSQL\n PG_PRIMARY_SERVICE_NAME - database host to connect to for the primary node\n PG_REPLICA_SERVICE_NAME - database host to connect to for the replica node\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n Features The following features are supported by the crunchy-pgpool container:\n basic invocation of pgpool\n crunchy-watch crunchy-watch runs as a pod unto itself typically. The watch container essentially does a health check on a primary database container and performs a failover sequence if the primary is not reached.\n The watch container has access to a service account that is used inside the container to issue commands to OpenShift.\n In Kube 1.5, if a policy file is being used for securing down the Kube cluster, you could possibly need to add a policy to allow the pg-watcher service account access to the Kube API as mentioned here: https://kubernetes.io/docs/admin/authorization/abac/#a-quick-note-on-service-accounts\n In Kube 1.6, an equivalent RBAC policy is also possibly required depending on your authorization/authentication configuration. See this link for details on the new RBAC policy mechanism: https://kubernetes.io/docs/admin/authorization/rbac/\n For example, you can grant cluster-admin permissions on the pg-watcher service account, in the my-namespace namespace as follows:\n kubectl create clusterrolebinding pgwatcher-view-binding --clusterrole=cluster-admin --serviceaccount=my-namespace:pg-watcher A less wide open policy would be applied like this on Kube 1.6 rbac:\n kubectl create rolebinding my-sa-binding --clusterrole=admin --serviceaccount=demo:pg-watcher --namespace=demo Note this kubectl command is only available in Kube 1.6, for prior Kube release such as 1.5 and the alpha RBAC, you will need to specify the role binding in a JSON/YAML file instead of using this command syntax above. You then reference the SA within the POD spec.\n The oc/docker/kubectl commands are included into the container from the host when the container image is built. These commands are used by the watch logic to interact with the replica containers.\n Starting with release 1.7.1 crunchy-watch source code is relocated to https://github.com/crunchydata/crunchy-watch\n Environment Variables CRUNCHY_WATCH_HEALTHCHECK_INTERVAL - the time to sleep in seconds between checking on the primary\n CRUNCHY_WATCH_FAILOVER_WAIT - the time to sleep in seconds between triggering the failover and updating its label (default is 40 secs)\n PG_CONTAINER_NAME - if set, the name of the container to refer to when doing an exec, this is required if you have more than 1 container in your database pod\n CRUNCHY_WATCH_PRIMARY - the primary service name\n CRUNCHY_WATCH_REPLICA - the replica service name\n PG_PRIMARY_PORT - database port to use when checking the database\n CRUNCHY_WATCH_USERNAME - database user account to use when checking the database using pg_isready utility\n CRUNCHY_WATCH_DATABASE - database to use when checking the database using pg_isready\n REPLICA_TO_TRIGGER_LABEL - the pod name of a replica that you want to choose as the new primary in a failover; this will override the normal replica selection\n CRUNCHY_WATCH_PRE_HOOK - path to an executable file to run before failover is processed.\n CRUNCHY_WATCH_POST_HOOK - path to an executable file to run after failover is processed.\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n Logic The watch container will watch the primary, if the primary dies, then the watcher will:\n create the trigger file on the replica that will become the new primary\n change the labels on the replica to be those of the primary\n start watching the new primary in case that falls over next\n look for replicas that have the metadata label value of replicatype=trigger to prefer the failover to. If found, it will use the first replica with that label; if not found, it will use the first replica it finds.\n Example of looking for the failover replica:\n oc get pod -l name=pg-replica-rc-dc NAME READY STATUS RESTARTS AGE pg-replica-rc-dc 1/1 Running 2 16m pg-replica-rc-dc-1-96qs8 1/1 Running 1 16m oc get pod -l replicatype=trigger NAME READY STATUS RESTARTS AGE pg-replica-rc-dc 1/1 Running 2 16m crunchy-vacuum Description The crunchy-vacuum container allows you to perform a SQL VACUUM job against a PostgreSQL database container. You specify a database to vacuum using various environment variables which are listed below. It is possible to run different vacuum operations either manually or automatically through scheduling.\n The crunchy-vacuum image is executed, passed in the Postgres connection parameters to the single-primary PostgreSQL container. The type of vacuum performed is dictated by the environment variables passed into the job.\n Environment Variables The complete set of environment variables read by the crunchy-vacuum job include:\n VAC_FULL - when set to true adds the FULL parameter to the VACUUM command\n VAC_TABLE - when set, allows you to specify a single table to vacuum, when not specified, the entire database tables are vacuumed\n JOB_HOST - required variable is the postgres host we connect to\n PG_USER - required variable is the postgres user we connect with\n PG_DATABASE - required variable is the postgres database we connect to\n PG_PASSWORD - required variable is the postgres user password we connect with\n PG_PORT - allows you to override the default value of 5432\n VAC_ANALYZE - when set to true adds the ANALYZE parameter to the VACUUM command\n VAC_VERBOSE - when set to true adds the VERBOSE parameter to the VACUUM command\n VAC_FREEZE - when set to true adds the FREEZE parameter to the VACUUM command\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n crunchy-dba The crunchy-dba container implements a cron scheduler. The purpose of the crunchy-dba container is to offer a way to perform simple DBA tasks that occur on some form of schedule such as backup jobs or running a vacuum on a single Postgres database container.\n You can either run the crunchy-dba container as a single pod or include the container within a database pod.\n The crunchy-dba container makes use of a Service Account to perform the startup of scheduled jobs. The Kube Job type is used to execute the scheduled jobs with a Restart policy of Never.\n Environment Variables The following environment variables control the actions of crunchy-dba:\n OSE_PROJECT - required, the OSE project name to log into\n JOB_HOST - required, the PostgreSQL container name the action will be taken against\n VAC_SCHEDULE - if set, this will start a vacuum job container. The setting value must be a valid cron expression as described below.\n BACKUP_SCHEDULE - if set, this will start a backup job container. The setting value must be a valid cron expression as described below.\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n For a vacuum job, you are required to supply the following environment variables:\n JOB_HOST\n PG_USER\n PG_PASSWORD\n PG_DATABASE - defaults to postgres when not specified\n PG_PORT - defaults to 5432 when not specified\n VAC_ANALYZE(optional) - defaults to true when not specified\n VAC_FULL(optional) - defaults to true when not specified\n VAC_VERBOSE(optional) - defaults to true when not specified\n VAC_FREEZE(optional) - defaults to false when not specified\n VAC_TABLE(optional) - defaults to all tables when not specified, or you can set this value to indicate a single table to vacuum\n For a backup job, you are required to supply the following environment variables:\n JOB_HOST\n PG_USER - database user used to perform the backup\n PG_PASSWORD - database user password used to perform the backup\n PG_PORT - port value used when connecting for a backup to the database\n BACKUP_PV_CAPACITY - a value like 1Gi is used to define the PV storage capacity\n BACKUP_PV_PATH - the storage path used to build the PV\n BACKUP_PV_HOST - the storage host used to build the PV\n BACKUP_PVC_STORAGE - a value like 75M means to allow 75 megabytes for the PVC used in performing the backup\n CRON Expression Format A cron expression represents a set of times, using 6 space-separated fields.\n Table 1. Table Fields Field name Mandatory? Allowed values Allowed special characters Seconds\n Yes\n 0-59\n * / , -\n Minutes\n Yes\n 0-59\n * / , -\n Hours\n Yes\n 0-23\n * / , -\n Day of month\n Yes\n 1-31\n * / , - ?\n Month\n Yes\n 1-12 or JAN-DEC\n * / , -\n Day of week\n Yes\n 0-6 or SUN-SAT\n * / , - ?\n Note Month and Day-of-week field values are case insensitive. SUN'', Sun'', and ``sun'' are equally accepted. Special Characters Asterisk ( * ) The asterisk indicates that the cron expression will match for all values of the field; e.g., using an asterisk in the 5th field (month) would indicate every month.\n Slash ( / ) Slashes are used to describe increments of ranges. For example 3-59/15 in the 1st field (minutes) would indicate the 3rd minute of the hour and every 15 minutes thereafter. The form *\\/\u0026#8230;\u0026#8203;'' is equivalent to the form first-last/\u0026#8230;\u0026#8203;'', that is, an increment over the largest possible range of the field. The form N/\u0026#8230;\u0026#8203;'' is accepted as meaning N-MAX/\u0026#8230;\u0026#8203;'', that is, starting at N, use the increment until the end of that specific range. It does not wrap around.\n Comma ( , ) Commas are used to separate items of a list. For example, using ``MON,WED,FRI'' in the 5th field (day of week) would mean Mondays, Wednesdays and Fridays.\n Hyphen ( - ) Hyphens are used to define ranges. For example, 9-17 would indicate every hour between 9am and 5pm inclusive.\n Question mark ( ? ) Question mark may be used instead of '*' for leaving either day-of-month or day-of-week blank.\n Predefined schedules You may use one of several pre-defined schedules in place of a cron expression.\n Table 2. Table Predefined Schedules Entry Description Equivalent To @yearly (or @annually)\n Run once a year, midnight, Jan. 1st\n 0 0 0 1 1 *\n @monthly\n Run once a month, midnight, first of month\n 0 0 0 1 * *\n @weekly\n Run once a week, midnight on Sunday\n 0 0 0 * * 0\n @daily (or @midnight)\n Run once a day, midnight\n 0 0 0 * * *\n @hourly\n Run once an hour, beginning of hour\n 0 0 * * * *\n Intervals You may also schedule a job to execute at fixed intervals. This is supported by formatting the cron spec like this:\n @every \u0026lt;duration\u0026gt; where ``duration'' is a string accepted by time.ParseDuration (http://golang.org/pkg/time/#ParseDuration).\n For example, ``@every 1h30m10s'' would indicate a schedule that activates every 1 hour, 30 minutes, 10 seconds.\n Note The interval does not take the job runtime into account. For example, if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes, it will have only 2 minutes of idle time between each run. Time zones All interpretation and scheduling is done in the machines local time zone (as provided by the Go time package (http://www.golang.org/pkg/time). Be aware that jobs scheduled during daylight-savings leap-ahead transitions will not be run!\n crunchy-pgbouncer Crunchy pgBouncer is a lightweight connection pooler for PostgreSQL databases.\n Environment Variables REQUIRED ARGS PGBOUNCER_PASSWORD - the password of the pgbouncer role in PostgreSQL. Must be also set on the primary database.\n PG_SERVICE - the hostname of the database service\n OPTIONAL/EXTENDED ARGS DEFAULT_POOL_SIZE - default 20, how many server connections to allow per user/database pair.\n MAX_CLIENT_CONN - default 100, maximum number of client connections allowed.\n MAX_DB_CONNECTIONS - default unlimited, do not allow more than this many connections per-database.\n MIN_POOL_SIZE - default 0 (disabled), adds more server connections to pool if below this number.\n POOL_MODE - default session, specifies when a server connection can be reused by other clients. Possible values: session, transaction and statement.\n RESERVE_POOL_SIZE - default 0 (disabled), how many additional connections to allow to a pool.\n RESERVE_POOL_TIMEOUT - default 5, if a client has not been serviced in this many seconds, pgbouncer enables use of additional connections from reserve pool. 0 disables.\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n Features The following features are supported by the crunchy-pgbouncer container:\n Crunchy pgBouncer uses auth_query to authenticate users. This requires only the pgbouncer username and password in users.txt. Automatically generated from environment variables.\n Mount a custom users.txt and pgbouncer.ini configurations for advanced usage.\n Tune pooling parameters via environment variables.\n Connect to the administration database in pgBouncer to view statistics of the target databases.\n Restrictions OpenShift: If custom configurations aren\u0026#8217;t being mounted, an emptydir volume is required to be mounted at /pgconf.\n Superusers cannot connect through the connection pooler.\n crunchy-backrest-restore The crunchy-backrest-restore container executes the pgbackrest utility, allowing FULL and DELTA restore capability. See the pgbackrest guide for more details. https://github.com/pgbackrest/pgbackrest\n Environment Variables Required: * STANZA - desired stanza to restore from. For most cases this should be set to db.\n Optional: * DELTA - when set to true, this will configure pgBackRest to do a delta restore. Delta restores do not require pgdata directoy to be empty. This will only pull in differences between pgdata and the backup. * BACKREST_CUSTOM_OPTS - pass in custom parameters to pgBackRest for advanced use cases (such as point in time recovery). * CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n Features The following features are supported by the crunchy-backrest-restore container:\n mount pgbackrest.conf config file via /pgconf volume\n mount the /backrestrepo for access to pgbackrest archives\n Restrictions for configuration, has to have pgbackrest.conf files mounted in /pgconf\n must have valid pgbackrest archive directory mounted in /backrestrepo\n crunchy-pgadmin4 The crunchy-ppgadmin4 container executes the pgadmin4 web application.\n The pgadmin4 project is found at the following location: https://www.pgadmin.org/\n pgadmin4 provides a web user interface to PostgreSQL databases. A sample screenshot is below:\n Environment Variables PGADMIN_SETUP_EMAIL - required, set this value to the email address used for pgAdmin4 login.\n PGADMIN_SETUP_PASSWORD - required, set this value to a password used for pgAdmin4 login. This should be a strong password.\n SERVER_PORT - default is 5050, set this value to a change the port pgAdmin4 listens on.\n ENABLE_TLS - default is false, set this value to true to enable HTTPS on the pgAdmin4 container. This requires a server.key and server.crt to be mounted on the /certs directory.\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n Features The following features are supported by the crunchy-pgadmin4 container:\n expose port (5050 by default) which is the web server port\n mount a certificate and key to the /certs directory and set ENABLE_TLS to true to activate HTTPS mode.\n Set username and password for login via environment variables.\n Restrictions An emptyDir, with write access, must be mounted to the /run/httpd directory in OpenShift.\n crunchy-pgrestore The restore image provides a means of performing a restore of a dump from pg_dump or pg_dumpall via psql or pg_restore to a Postgres container database.\n Dump-file Input Location As the input files for crunchy-pgrestore, files generated by crunchy-pgdump are retrieved in a mounted backup volume location, using the database host name plus -backups as a sub-directory, then followed by a unique backup directory based upon a date/timestamp. It is left to the user to restore database dump archives in this current version of the container.\n Dependencies The container is meant to be using NFS or a similar network file system to retrieve database dumps to be restored via psql or pg_restore.\n Environment Variables REQUIRED ARGS PGRESTORE_DB - Database to connect to\n PGRESTORE_HOST - Hostname of the PostgreSQL database to connect to\n PGRESTORE_PASS - Password of the PostgreSQL role used by the pgdump container\n PGRESTORE_USER - PostgreSQL Role used by the pgdump container\n OPTIONAL/EXTENDED ARGS PGDUMP_BACKUP_HOST - Hostname of the PostgreSQL server that was backed up by pgdump container. Used when restoring a backup to a new host.\n PGRESTORE_BACKUP_TIMESTAMP - Timestamp of the backup to restore from. Default is empty (restores from latest backup)\n PGRESTORE_CUSTOM_OPTS - Advanced options to pass into pg_restore. Default is empty\n PGRESTORE_PORT - Port of the PostgreSQL database to connect to. Default is 5432\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs Note: this mode can reveal secrets in logs.\n Note: For a list of advanced options for configuring the PGRESTORE_CUSTOM_OPTS variable, see the official documentation:\n https://www.postgresql.org/docs/current/static/app-pgrestore.html\n crunchy-upgrade The crunchy-upgrade container contains both the 9.5/9.6 and 9.6/10 Postgres packages in order to perform a pg_upgrade from 9.5 to 9.6 or 9.6 to 10 versions.\n Environment Variables OLD_DATABASE_NAME - required, refers to the database (pod) name that we want to convert\n NEW_DATABASE_NAME - required, refers to the database (pod) name that we give to the upgraded database\n OLD_VERSION - required, the Postgres version of the old database\n NEW_VERSION - required, the Postgres version of the new database\n PG_LOCALE - if set, the locale you want to create the database with, if not set, the default locale is used\n CHECKSUMS - if set, this value is used to enable the --data-checksums option when initdb is executed at initialization, if not set, the default is to not enable data checksums\n XLOGDIR - if set, initdb will use the specified directory for WAL\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n Features The following features are supported by the crunchy-upgrade container:\n supports only a pg_upgrade of the Postgres database\n doesn\u0026#8217;t alter the old database files\n creates the new database directory\n Restrictions does NOT support a postgis upgrade currently\n all environment variables are required\n supports upgrades from 9.5/9.6 to 10\n crunchy-sim The crunchy-sim container is a simple traffic simulator for PostgreSQL.\n Environment Variables PGSIM_HOST - required, the PostgreSQL host address\n PGSIM_PORT - required, the PostgreSQL host port\n PGSIM_USERNAME - required, the PostgreSQL username\n PGSIM_PASSWORD - required, the PostgreSQL password\n PGSIM_DATABASE - required, the database to connect\n PGSIM_INTERVAL - required, The units of the simulation interval\n PGSIM_MININTERVAL - required, the minimum interval value\n PGSIM_MAXINTERVAL - requited, the maximum interval value\n CRUNCHY_DEBUG - default is false, set this value to true to debugging in logs. Note: this mode can reveal secrets in logs.\n Valid values for PGSIM_INTERVAL are as follows:\n millisecond\n second\n minute\n Features Creates a single connection to PostgreSQL and will execute queries over a specified interval range.\n Queries are specified through a simple YAML file. Each query is a name-value pair and can span multiple lines by utilizing scalar notation (|'' or \u0026gt;'') as defined by the YAML spec.\n Queries are randomly chosen for execution.\n Restrictions Only one connection is created for all queries. \u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; aae224745f5caf481c142b4ccbf3332ab4f45f8e\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/installation/storage-configuration/", - "title": "Storage Configuration", - "tags": [], - "description": "", - "content": "Table of Contents Available Storage Types HostPath NFS Dynamic Storage Next Steps Latest Release: 2.1.0 2018-08-13\n Available Storage Types The Container Suite is tested on 3 different storage backends:\n hostPath (single node testing)\n NFS (single and multi-node testing)\n Gluster (dynamic storage on separate Gluster cluster)\n Other storage backends work as well including GCE, EBS, ScaleIO, and others, but may require you to modify various examples or configuration.\n Environment variables are set to determine how and what storage is to be used.\n HostPath HostPath is the simplest storage backend to setup. It is only feasible on a single node but is sufficient for testing the examples. In your .bashrc file, add the following variables to specify unique settings to the HostPath directory:\n export CCP_SECURITY_CONTEXT=\"\" export CCP_STORAGE_PATH=/data export CCP_STORAGE_MODE=ReadWriteMany export CCP_STORAGE_CAPACITY=400M Note It may be necessary to grant your user in OpenShift or Kubernetes the rights to modify the hostaccess SCC. This can be done with the command: oadm policy add-scc-to-user hostaccess $(oc whoami) NFS NFS can also be used as a storage mechanism. Instructions on setting up NFS are found at the bottom of this guide.\n For testing with NFS, in your .bashrc file, include the following variables that are unique to your NFS environment:\n export CCP_SECURITY_CONTEXT='\"supplementalGroups\": [65534]' export CCP_STORAGE_PATH=/mnt/nfsfileshare export CCP_NFS_IP=192.168.0.118 export CCP_STORAGE_MODE=ReadWriteMany export CCP_STORAGE_CAPACITY=400M In this example above the group ownership of the NFS mount is assumed to be nfsnobody or 65534.\n Configuration Notes for NFS Note: Most of the Crunchy containers run as the postgres UID (26), but you will notice that when supplementalGroups is specified, the pod will include the nfsnobody group in the list of groups for the pod user.\n First, if you are running your NFS system with SELinux in enforcing mode, you will need to run the following command to allow NFS write permissions:\n sudo setsebool -P virt_use_nfs 1 Detailed instructions that you can use for setting up a NFS server on Centos 7 are provided in the following link.\n http://www.itzgeek.com/how-tos/linux/centos-how-tos/how-to-setup-nfs-server-on-centos-7-rhel-7-fedora-22.html\n if you are running your client on a VM, you will need to add 'insecure' to the exportfs file on the NFS server due to the way port translation is done between the VM host and the VM instance.\n For more details on this bug, please see the following link.\n http://serverfault.com/questions/107546/mount-nfs-access-denied-by-server-while-mounting\n A suggested best practice for tuning NFS for PostgreSQL is to configure the PostgreSQL fstab mount options like so:\n proto=tcp,suid,rw,vers=3,proto=tcp,timeo=600,retrans=2,hard,fg,rsize=8192,wsize=8192 Network options:\n MTU=9000 If interested in mounting the same NFS share multiple times on the same mount point, look into the noac mount option.\n Dynamic Storage Dynamic storage classes can be used for the examples. Gluster is only one example of a storage type that supports dynamic storage classes. The environment variable CCP_STORAGE_CLASS is used in the examples to determine whether or not to create a PersistentVolume manually or that it will be created dynamically using a StorageClass. In the case of GKE, the default StorageClass is named default. Storage class names are determined by the Kubernetes administrator and can vary.\n Setting up a Gluster cluster will offer you the ability to use dynamic storage provisioning in the examples. A set of example Gluster configuration files is found at $CCPROOT/examples/gluster. This configuration is for a 3 node Gluster cluster which runs on a Centos7 Minimal VM deployment.\n Using block storage requires a security context to be set as follows:\n export CCP_SECURITY_CONTEXT='\"fsGroup\":26' export CCP_STORAGE_CLASS=standard export CCP_STORAGE_MODE=ReadWriteOnce export CCP_STORAGE_CAPACITY=400M Next Steps There are many ways to configure the examples and containers further. Descriptions of each container offered and the variables that can be used to customize them are found on the Container Specifications page.\n Information can be found on the full scope of examples that can be performed on the Getting Started page.\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backrest-restore/", - "title": "crunchy-backrest-restore", - "tags": [], - "description": "", - "content": " The crunchy-backrest-restore container executes the pgBackRest utility, allowing FULL and DELTA restore capability. See the pgBackRest guide for more details.\nFeatures The following features are supported and required by the crunchy-backrest-restore container:\n Mounted pgbackrest.conf configuration file via the /pgconf volume Mounted /backrestrepo for access to pgBackRest archives Packages The crunchy-backrest-restore Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) pgBackRest (2.x) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description STANZA None Must be set to the desired stanza for restore. DELTA None When set, will add the --delta option to the restore. The delta option allows pgBackRest to automatically determine which files in the database cluster directory can be preserved and which ones need to be restored from the backup - it also removes files not present in the backup manifest so it will dispose of divergent changes. Optional Name Default Description PG_HOSTNAME None When restoring a backup to a new volume, this volume should be set to the hostname of the PostgreSQL container that will mount the restored volume. Required for full restores to new volumes. PITR_TARGET None PostgreSQL timestamp used when restoring up to a point in time. Required for PITR delta restores. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/contributing/", - "title": "Contributing", - "tags": [], - "description": "", - "content": "Latest Release: 2.1.0 2018-08-13\n Getting Started Welcome! Thank you for your interest in contributing. Before submitting a new issue or pull request to the Crunchy Container Suite project on GitHub, please review any open or closed issues here in addition to any existing open pull requests.\n Documentation The documentation website (located at https://crunchydata.github.io/crunchy-containers/) is generated using Hugo and GitHub Pages.\n Hosting Hugo Locally (Optional) If you would like to build the documentation locally, view the official Installing Hugo guide to set up Hugo locally. You can then start the server by running the following commands -\n cd $CCPROOT/hugo/ vi config.toml hugo server When you edit config.toml, you\u0026#8217;ll set baseURL = \"/\". This will make the local version of the Hugo server accessible by default from localhost:1313. Once you\u0026#8217;ve run hugo server, that will let you interactively make changes to the documentation as desired and view the updates in real-time.\n Note Please make sure to revert baseURL back to its original value of https://crunchydata.github.io/crunchy-containers if you choose to run the server locally. Contributing to the Documentation When you\u0026#8217;re ready to commit a change, please view and run the script located at $CCPROOT/generate-docs.sh which will automatically generate a new set of webpages using Hugo that will update the live website after the change has been committed to the repository.\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgdump/", - "title": "crunchy-pgdump", - "tags": [], - "description": "", - "content": " The crunchy-pgdump container executes either a pg_dump or pg_dumpall database backup against another PostgreSQL database.\nPackages The crunchy-pgdump Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PGDUMP_DB None Name of the database the backup is being performed on. PGDUMP_HOST None Hostname of the database the backup is being performed on. PGDUMP_PASS None Password for the PostgreSQL role being used. PGDUMP_USER None Username for the PostgreSQL role being used. Optional Name Default Description PGDUMP_ALL TRUE Run pg_dump instead of pg_dumpall. Set to false to enable pg_dump. PGDUMP_CUSTOM_OPTS None Advanced options to pass into pg_dump or pg_dumpall. PGDUMP_FILENAME dump Name of the file created by the pgdump container. PGDUMP_PORT 5432 Port of the PostgreSQL database to connect to. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. For a list of advanced options for configuring the PGDUMP_CUSTOM_OPTS variable, see the official documentation:\nhttps://www.postgresql.org/docs/current/static/app-pgdump.html\nhttps://www.postgresql.org/docs/current/static/app-pg-dumpall.html\n Volumes Name Description /pgdata Volume used to store the data directory contents for the PostgreSQL database. Dump Location Backups are stored in a mounted backup volume location, using the database host name plus -backups as a sub-directory, then followed by a unique backup directory based upon a date/timestamp. It is left to the user to perform database backup archives in this current version of the container. This backup location is referenced when performing a database restore.\n" -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgrestore/", - "title": "crunchy-pgrestore", - "tags": [], - "description": "", - "content": " The restore image provides a means of performing a restore of a dump from pg_dump or pg_dumpall via psql or pg_restore to a PostgreSQL container database.\nPackages The crunchy-pgrestore Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PGRESTORE_DB None Name of the database to connect to. PGRESTORE_HOST None Hostname of the database to connect to. PGRESTORE_PASS None Password for the PostgreSQL role being used. PGRESTORE_USER None Username for the PostgreSQL role being used. Optional Name Default Description PGDUMP_BACKUP_HOST None Hostname of the PostgreSQL server that was backed up by pgdump container. Used when restoring a backup to a new host. PGRESTORE_BACKUP_TIMESTAMP Empty Timestamp of the backup to restore from. PGRESTORE_CUSTOM_OPTS Empty Advanced options to pass into pg_restore. PGRESTORE_PORT 5432 Port of the PostgreSQL database to connect to. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. For a list of advanced options for configuring the PGRESTORE_CUSTOM_OPTS variable, see the official documentation.\n Volumes Name Description /pgdata Volume used to store the data directory contents for the PostgreSQL database. Dump-file Input Location As the input files for crunchy-pgrestore, files generated by crunchy-pgdump are retrieved in a mounted backup volume location, using the database host name plus -backups as a sub-directory, then followed by a unique backup directory based upon a date/timestamp. It is left to the user to restore database dump archives in this current version of the container.\n" -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-collect/", - "title": "crunchy-collect", - "tags": [], - "description": "", - "content": " The crunchy-collect container provides real time metrics about the PostgreSQL database via an API. These metrics are scrapped and stored by a Prometheus time-series database and are then graphed and visualized through the open source data visualizer Grafana.\nThe crunchy-collect container uses pgMonitor for advanced metric collection. It is required that the crunchy-postgres container has the PGMONITOR_PASSWORD environment variable to create the appropriate user (ccp_monitoring) to collect metrics.\nCustom queries to collect metrics can be specified by the user. By mounting a queries.yml file to /conf on the container, additional metrics can be specified for the API to collect. For an example of a queries.yml file, see here\nPackages The crunchy-collect Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only PostgreSQL Exporter Node Exporter Environment Variables Required Name Default Description DATA_SOURCE_NAME None The URL for the PostgreSQL server\u0026rsquo;s data source name. This is required to be in the form of postgresql://. The user should be ccp_monitoring and use the PGMONITOR_PASSWORD value set in the PostgreSQL container. Optional Name Default Description CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-prometheus/", - "title": "crunchy-prometheus", - "tags": [], - "description": "", - "content": " Prometheus is a multi-dimensional time series data model with an elastic query language. It is used in collaboration with Grafana in this metrics suite. Overall, it’s reliable, manageable, and operationally simple for efficiently storing and analyzing data for large-scale environments. It scraps metrics from exporters such as the ones utilized by the crunchy-collect container. The crunchy-prometheus container must be able to reach the crunchy-collect container in order to to scrape metrics.\nBy default, crunchy-prometheus detects which environment its running on (Docker, Kubernetes, or OpenShift) and applies a default configuration. If this container is running on Kubernetes or OpenShift, it will use the Kubernetes API to discover pods with the label \u0026quot;crunchy-collect\u0026quot;: \u0026quot;true\u0026quot;. The crunchy-collect container must have this label defined in order to be discovered.\nFor Docker environments the crunchy-collect hostname must be specified as an environment variable.\nA user may define a custom prometheus.yml file and mount to /conf for custom configuration. For configuration examples, see here.\nThe following port is exposed by the crunchy-prometheus container:\n crunchy-prometheus:9090 - the Prometheus web user interface Packages The crunchy-prometheus Docker image contains the following packages:\n Prometheus CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description COLLECT_HOST None Hostname of Crunchy Collect container. Only required in Docker environments. Optional Name Default Description SCRAPE_INTERVAL 5s Set this value to the number of seconds to scrape metrics from exporters. SCRAPE_TIMEOUT 5s Set this value to the number of seconds to timeout when scraping metrics from exporters. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-grafana/", - "title": "crunchy-grafana", - "tags": [], - "description": "", - "content": " Visual dashboards are created from the collected and stored data that crunchy-collect and crunchy-prometheus provide for the crunchy-grafana container, which hosts an open source web-based graphing dashboard called Grafana.\nGrafana is a platform which can then apply the defined metrics and visualize information through various tools. It is extremely flexible with a powerful query and transformation language, producing beautiful and easily understandable graphics to analyze and monitor your data.\nBy default, crunchy-grafana will register the Prometheus datasource within Grafana and import a pre-made dashboard for PostgreSQL monitoring.\nThe crunchy-grafana container must be able to reach the crunchy-prometheus container.\nUsers must specify an administrator username and password to provide basic authentication for the web frontend. Additionally, the Prometheus hostname and port number are required. If Prometheus uses basic authentication, users must specify the username and password to access Prometheus via environment variables.\nA user may define a custom defaults.ini file and mount to /conf for custom configuration. For configuration examples, see here.\nThe following port is exposed by the crunchy-grafana container:\n crunchy-grafana:3000 - the Grafana web user interface Packages The crunchy-grafana Docker image contains the following packages:\n Grafana CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description ADMIN_USER None Specifies the administrator user to be used when logging into the web frontend. ADMIN_PASS None Specifies the administrator password to be used when logging into the web frontend. PROM_HOST None Specifies the Prometheus container hostname for auto registering the Prometheus datasource. PROM_PORT None Specifies the Prometheus container port for auto registering the Prometheus datasource. Optional Name Default Description PROM_USER 5s Specifies the Prometheus username, if one is required. PROM_PASS 5s Specifies the Prometheus password, if one is required. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgadmin4/", - "title": "crunchy-pgadmin4", - "tags": [], - "description": "", - "content": " The crunchy-ppgadmin4 container executes the pgAdmin4 web application.\npgAdmin4 provides a web user interface to PostgreSQL databases. A sample screenshot is below:\nFeatures The following features are supported by the crunchy-pgadmin4 container:\n Expose port (5050 by default) which is the web server port. Mount a certificate and key to the /certs directory and set ENABLE_TLS to true to activate HTTPS mode. Set username and password for login via environment variables. Restrictions An emptyDir, with write access, must be mounted to the /run/httpd directory in OpenShift. Packages The crunchy-pgadmin4 Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) pgAdmin4 CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PGADMIN_SETUP_EMAIL None Set this value to the email address used for pgAdmin4 login. PGADMIN_SETUP_PASSWORD None Set this value to a password used for pgAdmin4 login. This should be a strong password. SERVER_PORT 5050 Set this value to a change the port pgAdmin4 listens on. ENABLE_TLS FALSE Set this value to true to enable HTTPS on the pgAdmin4 container. This requires a server.key and server.crt to be mounted on the /certs directory. Optional Name Default Description CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-watch/", - "title": "crunchy-watch", - "tags": [], - "description": "", - "content": " The crunchy-watch container essentially does a health check on a primary database container and performs a failover sequence if the primary is not reached. The watch container has access to a service account that is used inside the container to issue commands to OpenShift.\nIn Kubrnetese 1.5, if a policy file is being used for securing down the Kubernetes cluster, you could possibly need to add a policy to allow the pg-watcher service account access to the Kubernetes API as mentioned here.\nIn Kubernetes 1.6, an equivalent RBAC policy is also possibly required depending on your authorization/authentication configuration. See this link for details on the new RBAC policy mechanism.\nFor example, you can grant cluster-admin permissions on the pg-watcher service account in the my-namespace namespace as follows:\nkubectl create clusterrolebinding pgwatcher-view-binding --clusterrole=cluster-admin --serviceaccount=my-namespace:pg-watcher A less wide open policy would be applied like this on Kube 1.6 rbac:\nkubectl create rolebinding my-sa-binding --clusterrole=admin --serviceaccount=demo:pg-watcher --namespace=demo The above kubectl command is only available in Kubernetes 1.6. For prior Kubernetes releases such as 1.5 and the alpha RBAC, you will need to specify the role binding in a JSON/YAML file instead of using the previous command syntax.\n The oc/docker/kubectl commands are included into the container from the host when the container image is built. These commands are used by the watch logic to interact with the replica containers.\nStarting with release 1.7.1, crunchy-watch source code is relocated to a separate GitHub repository located here.\nEnvironment Variables Required Name Default Description CRUNCHY_WATCH_HEALTHCHECK_INTERVAL None The time to sleep in seconds between checking on the primary. CRUNCHY_WATCH_FAILOVER_WAIT 40s The time to sleep in seconds between triggering the failover and updating its label. PG_CONTAINER_NAME None If set, the name of the container to refer to when doing an exec. This is required if you have more than 1 container in your database pod. CRUNCHY_WATCH_PRIMARY None The primary service name. CRUNCHY_WATCH_REPLICA None The replica service name. PG_PRIMARY_PORT None Database port to use when checking the database. CRUNCHY_WATCH_USERNAME None Database user account to use when checking the database using pg_isready utility. CRUNCHY_WATCH_DATABASE None Database to use when checking the database using pg_isready. REPLICA_TO_TRIGGER_LABEL None The pod name of a replica that you want to choose as the new primary in a failover; this will override the normal replica selection. CRUNCHY_WATCH_PRE_HOOK None Path to an executable file to run before failover is processed. CRUNCHY_WATCH_POST_HOOK None Path to an executable file to run after failover is processed. Optional Name Default Description CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. Logic The watch container will watch the primary. If the primary dies, then the watcher will:\n create the trigger file on the replica that will become the new primary change the labels on the replica to be those of the primary start watching the new primary in case that falls over next look for replicas that have the metadata label value of replicatype=trigger to prefer the failover to. If found, it will use the first replica with that label; if not found, it will use the first replica it finds. Example of looking for the failover replica:\noc get pod -l name=pg-replica-rc-dc NAME READY STATUS RESTARTS AGE pg-replica-rc-dc 1/1 Running 2 16m pg-replica-rc-dc-1-96qs8 1/1 Running 1 16m oc get pod -l replicatype=trigger NAME READY STATUS RESTARTS AGE pg-replica-rc-dc 1/1 Running 2 16m" -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-vacuum/", - "title": "crunchy-vacuum", - "tags": [], - "description": "", - "content": " The crunchy-vacuum container allows you to perform a SQL VACUUM job against a PostgreSQL database container. You specify a database to vacuum using various environment variables which are listed below. It is possible to run different vacuum operations either manually or automatically through scheduling.\nThe crunchy-vacuum image is executed, with the Postgres connection parameters passed to the single-primary PostgreSQL container. The type of vacuum performed is dictated by the environment variables passed into the job.\nMore information on the PostgreSQL VACUUM job can be found in the official PostgreSQL documentation.\nPackages The crunchy-vacuum Docker image contains the following packages:\n CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description JOB_HOST None The PostgreSQL host the VACUUM should be performed against. PG_DATABASE None The PostgreSQL database the VACUUM should be performed against. PG_PORT 5432 Allows you to override the default value of 5432. PG_USER None Username for the PostgreSQL role being used. PG_PASSWORD None Password for the PostgreSQL role being used. Optional Name Default Description VAC_FULL TRUE When set to true, adds the FULL parameter to the VACUUM command. VAC_TABLE FALSE When set to true, allows you to specify a single table to vacuum. When not specified, the entire database tables are vacuumed. VAC_ANALYZE TRUE When set to true, adds the ANALYZE parameter to the VACUUM command. VAC_VERBOSE TRUE When set to true, adds the VERBOSE parameter to the VACUUM command. VAC_FREEZE FALSE When set to true, adds the FREEZE parameter to the VACUUM command. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-upgrade/", - "title": "crunchy-upgrade", - "tags": [], - "description": "", - "content": " The crunchy-upgrade container contains both the 9.5\u0026frasl;9.6 and 9.6\u0026frasl;10 PostgreSQL packages in order to perform a pg_upgrade from 9.5 to 9.6 or 9.6 to 10 versions.\nFeatures The following features are supported by the crunchy-upgrade container:\n Supports a pg_upgrade of the PostgreSQL database. Doesn\u0026rsquo;t alter the old database files. Creates the new database directory. Restrictions Does not currently support a PostGIS upgrade. Supports upgrades from only 9.5 to 9.6, or 9.6 to 10. Packages The crunchy-upgrade Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description OLD_DATABASE_NAME None Refers to the database (pod) name that we want to convert. NEW_DATABASE_NAME None Refers to the database (pod) name that is given to the upgraded database. OLD_VERSION None The PostgreSQL version of the old database. NEW_VERSION None The PostgreSQL version of the new database. Optional Name Default Description PG_LOCALE Default locale If set, the locale you want to create the database with. CHECKSUMS true Enables data-checksums during initialization of the database. Can only be set during initial database creation. Set to false to disable data checksums. XLOGDIR None If set, initdb will use the specified directory for WAL. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. Data checksums on the Crunchy PostgreSQL container were enabled by default in version 2.1.0. When trying to upgrade, it\u0026rsquo;s required that both the old database and the new database have the same data checksums setting. Prior to upgrade, check if data_checksums were enabled on the database by running the following SQL: SHOW data_checksums\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-sim/", - "title": "crunchy-sim", - "tags": [], - "description": "", - "content": " The crunchy-sim container is a simple traffic simulator for PostgreSQL.\nFeatures Creates a single connection to PostgreSQL and will execute queries over a specified interval range. Queries are specified through a simple YAML file. Each query is a name-value pair and can span multiple lines by utilizing scalar notation (\u0026ldquo;|\u0026rdquo; or \u0026ldquo;\u0026gt;\u0026rdquo;) as defined by the YAML spec. Queries are randomly chosen for execution. Restrictions Only one connection is created for all queries. Packages The crunchy-sim Docker image contains the following packages:\n CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PGSIM_HOST None The PostgreSQL host address. PGSIM_PORT None The PostgreSQL host port. PGSIM_USERNAME None The PostgreSQL username. PGSIM_PASSWORD None The PostgreSQL password. PGSIM_DATABASE None The database to connect. PGSIM_INTERVAL None The units of the simulation interval. Valid values include: millisecond, second, and minute. PGSIM_MININTERVAL None The minimum interval value. PGSIM_MAXINTERVAL None The maximum interval value. Optional Name Default Description CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-dba/", - "title": "crunchy-dba", - "tags": [], - "description": "", - "content": " The crunchy-dba container implements a cron scheduler. The purpose of the crunchy-dba container is to offer a way to perform simple DBA tasks that occur on some form of schedule such as backup jobs or running a vacuum on a single PostgreSQL database container.\nYou can either run the crunchy-dba container as a single pod or include the container within a database pod.\nThe crunchy-dba container makes use of a Service Account to perform the startup of scheduled jobs. The Kubernetes Job type is used to execute the scheduled jobs with a Restart policy of Never.\nPackages The crunchy-dba Docker image contains the following packages:\n CentOS7 - publicly available RHEL7 - customers only Environment Variables General Name Default Description OSE_PROJECT None The OSE project name to log into. JOB_HOST None The PostgreSQL container name the action will be taken against. VAC_SCHEDULE None If set, this will start a vacuum job container. The setting value must be a valid cron expression as described below. BACKUP_SCHEDULE None If set, this will start a backup job container. The setting value must be a valid cron expression as described below. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. Vacuum Job For a vacuum job, you are required to supply the following environment variables:\n Name Default Description JOB_HOST None The PostgreSQL container name the action will be taken against. PG_USER None Username for the PostgreSQL role being used. PG_PASSWORD None Password for the PostgreSQL role being used. PG_DATABASE postgres Database host to connect to. PG_PORT 5432 Allows you to override the default value of 5432. VAC_ANALYZE TRUE When set to true, adds the ANALYZE parameter to the VACUUM command. VAC_FULL TRUE hen set to true, adds the FULL parameter to the VACUUM command. VAC_VERBOSE TRUE When set to true, adds the VERBOSE parameter to the VACUUM command. VAC_FREEZE FALSE When set to true, adds the FREEZE parameter to the VACUUM command. VAC_TABLE FALSE When set to true, allows you to specify a single table to vacuum. When not specified, the entire database tables are vacuumed. Backup Job For a backup job, you are required to supply the following environment variables:\n Name Default Description JOB_HOST None The PostgreSQL container name the action will be taken against. PG_USER None Username for the PostgreSQL role being used. PG_PASSWORD None Password for the PostgreSQL role being used. PG_PORT 5432 Allows you to override the default value of 5432. BACKUP_PV_CAPACITY None A value like 1Gi is used to define the PV storage capacity. BACKUP_PV_PATH None The storage path used to build the PV. BACKUP_PV_HOST None The storage host used to build the PV. BACKUP_PVC_STORAGE None A value like 75M means to allow 75 megabytes for the PVC used in performing the backup. CRON Expression Format A cron expression represents a set of times, using 6 space-separated fields.\n Field Name Mandatory? Allowed Values Allowed Special Characters Seconds Yes 0-59 * / , - Minutes Yes 0-59 * / , - Hours Yes 0-23 * / , - Day of month Yes 1-31 * / , - ? Month Yes 1-12 or JAN-DEC * / , - Day of week Yes 0-6 or SUN-SAT * / , - ? Month and Day-of-week field values are case insensitive. \u0026ldquo;SUN\u0026rdquo;, \u0026ldquo;Sun\u0026rdquo;, and \u0026ldquo;sun\u0026rdquo; are equally accepted.\n Special Characters Asterisk The asterisk indicates that the cron expression will match for all values of the field; e.g., using an asterisk in the 5th field (month) would indicate every month.\nSlash Slashes are used to describe increments of ranges. For example 3-59\u0026frasl;15 in the 1st field (minutes) would indicate the 3rd minute of the hour and every 15 minutes thereafter. The form \u0026ldquo;*\\/\u0026hellip;\u0026rdquo; is equivalent to the form \u0026ldquo;first-last/\u0026hellip;\u0026rdquo;, that is, an increment over the largest possible range of the field. The form \u0026ldquo;N/\u0026hellip;\u0026rdquo; is accepted as meaning \u0026ldquo;N-MAX/\u0026hellip;\u0026rdquo;, that is, starting at N, use the increment until the end of that specific range. It does not wrap around.\nComma Commas are used to separate items of a list. For example, using \u0026ldquo;MON,WED,FRI\u0026rdquo; in the 5th field (day of week) would mean Mondays, Wednesdays and Fridays.\nHyphen Hyphens are used to define ranges. For example, 9-17 would indicate every hour between 9am and 5pm inclusive.\nQuestion mark Question mark may be used instead of \u0026ldquo;*\u0026rdquo; for leaving either day-of-month or day-of-week blank.\nPredefined schedules You may use one of several pre-defined schedules in place of a cron expression.\n Entry Description Equivalent To @yearly (or @annually) Run once a year, midnight, Jan. 1st 0 0 0 1 1 * @monthly Run once a month, midnight, first of month 0 0 0 1 * * @weekly Run once a week, midnight on Sunday 0 0 0 * * 0 @daily (or @midnight) Run once a day, midnight 0 0 0 * * * @hourly Run once an hour, beginning of hour 0 0 * * * * Intervals You may also schedule a job to execute at fixed intervals. This is supported by formatting the cron spec like this:\n@every \u0026lt;duration\u0026gt; where \u0026ldquo;duration\u0026rdquo; is a string accepted by time.ParseDuration (http://golang.org/pkg/time/#ParseDuration).\nFor example, \u0026ldquo;@every 1h30m10s\u0026rdquo; would indicate a schedule that activates every 1 hour, 30 minutes, 10 seconds.\nNOTE: The interval does not take the job runtime into account. For example, if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes, it will have only 2 minutes of idle time between each run.\nTime zones All interpretation and scheduling is done in the machines local time zone (as provided by the Go time package (http://www.golang.org/pkg/time).\nBe aware that jobs scheduled during daylight-savings leap-ahead transitions will not be run.\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbouncer/", - "title": "crunchy-pgbouncer", - "tags": [], - "description": "", - "content": " pgBouncer is a lightweight connection pooler for PostgreSQL databases.\nFeatures The following features are supported by the crunchy-pgbouncer container:\n crunchy-pgbouncer uses auth_query to authenticate users. This requires only the pgbouncer username and password in users.txt. Automatically generated from environment variables. Mount a custom users.txt and pgbouncer.ini configurations for advanced usage. Tune pooling parameters via environment variables. Connect to the administration database in pgBouncer to view statistics of the target databases. Packages The crunchy-pgbouncer Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) pgBouncer CentOS7 - publicly available RHEL7 - customers only Restrictions OpenShift: If custom configurations aren\u0026rsquo;t being mounted, an emptydir volume is required to be mounted at /pgconf. Superusers cannot connect through the connection pooler. Environment Variables Required Name Default Description PGBOUNCER_PASSWORD None The password of the pgBouncer role in PostgreSQL. Must be also set on the primary database. PG_SERVICE None The hostname of the database service. Optional Name Default Description DEFAULT_POOL_SIZE 20 How many server connections to allow per user/database pair. MAX_CLIENT_CONN 100 Maximum number of client connections allowed. MAX_DB_CONNECTIONS Unlimited Do not allow more than this many connections per-database. MIN_POOL_SIZE 0 Adds more server connections to pool if below this number. POOL_MODE Session When a server connection can be reused by other clients. Possible values: session, transaction and statement. RESERVE_POOL_SIZE 0 How many additional connections to allow per pool. 0 disables. RESERVE_POOL_TIMEOUT 5 If a client has not been serviced in this many seconds, pgbouncer enables use of additional connections from reserve pool. 0 disables. QUERY_TIMEOUT 0 Queries running longer than that are canceled. IGNORE_STARTUP_PARAMETERS extra_float_digits Set to ignore particular parameters in startup packets. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgpool/", - "title": "crunchy-pgpool", - "tags": [], - "description": "", - "content": " The crunchy-pgpool container executes the pgPool II utility. pgPool can be used to provide a smart PostgreSQL-aware proxy to a PostgreSQL cluster, both primary and replica, so that applications only have to work with a single database connection.\nPostgreSQL replicas are read-only whereas a primary is capable of receiving both read and write actions.\nThe default pgPool examples use a Secret to hold the set of pgPool configuration files used by the examples. The Secret is mounted into the pgconf volume mount where the container will look to find configuration files. If you do not specify your own configuration files via a Secret then you can specify environment variables to the container that it will attempt to use to configure pgPool, although this is not recommended for production environments.\nFeatures The following features are supported by the crunchy-postgres container:\n Basic invocation of pgPool II Packages The crunchy-pgpool Docker image contains the following packages (versions vary depending on PostgreSQL version):\n PostgreSQL (10.5, 9.6.10 and 9.5.14) pgPool II CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PG_USERNAME None Username for the PostgreSQL role being used. PG_PASSWORD None Password for the PostgreSQL role being used. PG_PRIMARY_SERVICE_NAME None Database host to connect to for the primary node. PG_REPLICA_SERVICE_NAME None Database host to connect to for the replica node. Optional Name Default Description CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbadger/", - "title": "crunchy-pgbadger", - "tags": [], - "description": "", - "content": " The crunchy-pgbadger container executes the pgBadger utility, which generates a PostgreSQL log analysis report using a small HTTP server running on the container. This log report can be accessed through the URL http://\u0026lt;\u0026gt;:10000/api/badgergenerate.\nFeatures The following features are supported by the crunchy-pgbadger container:\n Generate a full report by default Optional custom options for more advanced use cases (such as incremental reports) Report persistence on a volume Packages The crunchy-badger Docker image contains the following packages:\n pgBadger CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description BADGER_TARGET None Only used in standalone mode to specify the name of the container. Also used to find the location of the database log files in /pgdata/$BADGER_TARGET/pg_log/*.log. Optional Name Default Description BADGER_CUSTOM_OPTS None For a list of optional flags, see the official pgBadger documentation. CRUNCHY_DEBUG FALSE Set this to true to enable debugging in logs. Note: this mode can reveal secrets in logs. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/", - "title": "Openshift Templates", - "tags": [], - "description": "", - "content": "Latest Release: 2.1.0 2018-08-13\n The OpenShift template examples referenced in this documentation are located at the following directory:\n $CCPROOT/examples/ocp-templates/ The following templates for PostgreSQL are provided:\n pgAdmin4\n Primary/Replica\n Primary Backup with Secrets\n Primary Restore with Secrets\n Primary Backup\n Primary Restore\n Single Primary\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/kubernetes-and-openshift/", - "title": "Kubernetes and Openshift", - "tags": [], - "description": "", - "content": "Table of Contents Getting Started Example Conventions Administration Password Management Kubernetes Secrets pgAdmin4 pgAdmin4 with TLS Upgrade Cron Scheduler Vacuum systemd Backup and Restoration pg_dump pg_restore pgBackRest pgBackRest with SSHD pg_basebackup Point in Time Recovery (PITR) Connection Pooling pgBouncer pgPool II Database Single Primary PostgreSQL Deployment Replication Synchronous Replication Statefulsets Geospatial (PostGIS) Custom Configuration SSL Authentication Docker Swarm Failover Watch Metrics and Performance pgBadger Metrics Collection pg_audit Latest Release: 2.1.0 2018-08-13\n Getting Started The examples located in the kube directory work on both Kubernetes and OpenShift. Ensure the CCP_CLI environment variable is set to the correct binary for your environment.\n Set the environment variable in .bashrc to ensure the examples will work in your environment.\n # Kubernetes export CCP_CLI=kubectl # OpenShift export CCP_CLI=oc Here are some useful resources for finding the right commands to troubleshoot \u0026amp; modify containers in the various environments shown in this guide:\n Docker Cheat Sheet\n Kubectl Cheat Sheet\n OpenShift Cheat Sheet\n Helm Cheat Sheet\n Example Conventions The examples provided in Container Suite are simple examples that are meant to demonstrate key Container Suite features. These examples can be used to build more production level deployments as dictated by user requirements specific to their operating environments.\n The examples generally follow these conventions:\n There is a run.sh script that you will execute to start the example.\n There is a cleanup.sh script that you will execute to shutdown and cleanup the example.\n Each example will create resources such as Secrets, ConfigMaps, Services, and PersistentVolumeClaims, all which follow a naming convention of \u0026lt;example name\u0026gt;-\u0026lt;optional description suffix\u0026gt;. For example an example called primary might have a PersistentVolumeClaim called primary-pgconf to describe the purpose of that particular PVC.\n The folder names for each example give a clue as to which Container Suite feature it demonstrates. For instance, the examples/kube/pgaudit example demonstrates how to enable the pg_audit capability of the crunchy-postgres container.\n Administration Password Management The passwords used for the PostgreSQL user accounts are generated by the OpenShift process command. To inspect what value is supplied, you can inspect the primary pod as follows:\n ${CCP_CLI} get pod pr-primary -o json | grep -C 1 'PG_USER\\|PG_PASSWORD\\|PG_DATABASE' This will give you the environment variable values for the database created by default in addition to the username and password of the standard user.\n PG_USER\n PG_PASSWORD\n PG_DATABASE\n Kubernetes Secrets You can use Kubernetes Secrets to set and maintain your database credentials. Secrets requires you base64 encode your user and password values as follows:\n echo -n 'myuserid' | base64 You will paste these values into your JSON secrets files for values.\n This example allows you to set the PostgreSQL passwords using Kubernetes Secrets.\n The secret uses a base64 encoded string to represent the values to be read by the container during initialization. The encoded password value is password. Run the example as follows:\n cd $CCPROOT/examples/kube/secret ./run.sh The secrets are mounted in the /pguser, /pgprimary, and /pgroot volumes within the container and read during initialization. The container scripts create a PostgreSQL user with those values, and sets the passwords for the primary user and PostgreSQL superuser using the mounted secret volumes.\n When using secrets, you do NOT have to specify the following environment variables if you specify all three secrets volumes:\n PG_USER\n PG_PASSWORD\n PG_ROOT_PASSWORD\n PG_PRIMARY_USER\n PG_PRIMARY_PASSWORD\n You can test the container as follows. In all cases, the password is password:\n psql -h secret -U pguser1 postgres psql -h secret -U postgres postgres psql -h secret -U primaryuser postgres pgAdmin4 This example deploys the pgadmin4 v2 web user interface for PostgreSQL without TLS.\n After running the example, you should be able to browse to http://127.0.0.1:5050 and log into the web application using a user ID of admin@admin.com and password of password.\n If you are running this example using Kubernetes or OpenShift, replace 127.0.0.1:5050 with the \u0026lt;NODE_IP\u0026gt;:30000.\n To get the node IP, run the following:\n ${CCP_CLI} describe pod pgadmin4-http | grep Node: See the pgAdmin4 documentation for more details.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker To run this example, run the following:\n cd $CCPROOT/examples/docker/pgadmin4-http ./run.sh Kubernetes and OpenShift Start the container as follows:\n cd $CCPROOT/examples/kube/pgadmin4-http ./run.sh An emptyDir with write access must be mounted to the /run/httpd directory in OpenShift.\n pgAdmin4 with TLS This example deploys the pgadmin4 v2 web user interface for PostgreSQL with TLS.\n After running the example, you should be able to browse to https://127.0.0.1:5050 and log into the web application using a user ID of admin@admin.com and password of password.\n If you are running this example using Kubernetes or OpenShift, replace 127.0.0.1:5050 with the \u0026lt;NODE_IP\u0026gt;:30000.\n To get the node IP, run the following:\n ${CCP_CLI} describe pod pgadmin4-https | grep Node: See the pgadmin4 documentation for more details.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker To run this example, run the following:\n cd $CCPROOT/examples/docker/pgadmin4-https ./run.sh Kubernetes and OpenShift Start the container as follows:\n cd $CCPROOT/examples/kube/pgadmin4-https ./run.sh An emptyDir with write access must be mounted to the /run/httpd directory in OpenShift.\n Upgrade This example assumes you have run primary using a PG 9.5 or 9.6 image such as centos7-9.5.14-2.2.0 prior to running this upgrade.\n Starting in release 1.3.1, the upgrade container will let you perform a pg_upgrade either from a PostgreSQL version 9.5 database to 9.6 or from 9.6 to 10.\n Prior to running this example, make sure your CCP_IMAGE_TAG environment variable is using the next major version of PostgreSQL that you want to upgrade to. For example, if you\u0026#8217;re upgrading from 9.5 to 9.6, make sure the variable references a PG 9.6 image such as centos7-9.6.10-2.2.0.\n This will create the following in your Kubernetes environment:\n a Kubernetes Job running the crunchy-upgrade container\n a new data directory name upgrade found in the pgnewdata PVC\n Data checksums on the Crunchy PostgreSQL container were enabled by default in version 2.1.0. When trying to upgrade, it\u0026#8217;s required that both the old database and the new database have the same data checksums setting. Prior to upgrade, check if data_checksums were enabled on the database by running the following SQL: SHOW data_checksums\n Kubernetes and OpenShift Before running the example, ensure you edit upgrade.json and update the OLD_VERSION and NEW_VERSION parameters to the ones relevant to your situation.\n Start the upgrade as follows:\n cd $CCPROOT/examples/kube/upgrade ./run.sh If successful, the Job will end with a successful status. Verify the results of the Job by examining the Job\u0026#8217;s pod log:\n ${CCP_CLI} get pod -l job-name=upgrade ${CCP_CLI} logs -l job-name=upgrade You can verify the upgraded database by running the post-upgrade.sh script in the examples/kube/upgrade directory. This will create a PostgreSQL pod that mounts the upgraded volume.\n Cron Scheduler The crunchy-dba container implements a cron scheduler. The purpose of the crunchy-dba container is to offer a way to perform simple DBA tasks that occur on some form of schedule such as backup jobs or running a vacuum on a single PostgreSQL database container (such as the primary example).\n You can either run the crunchy-dba container as a single pod or include the container within a database pod.\n The crunchy-dba container makes use of a Service Account to perform the startup of scheduled jobs. The Kubernetes Job type is used to execute the scheduled jobs with a Restart policy of Never.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Kubernetes and OpenShift The script to schedule vacuum on a regular schedule is executed through the following commands:\n # Kubernetes cd $CCPROOT/examples/kube/dba ./run-kube-vac.sh # OpenShift cd $CCPROOT/examples/kube/dba ./run-ocp-vac.sh To run the script for scheduled backups, run the following in the same directory:\n # Kubernetes cd $CCPROOT/examples/kube/dba ./run-kube-backup.sh # OpenShift cd $CCPROOT/examples/kube/dba ./run-ocp-backup.sh Individual parameters for both can be modified within their respective JSON files; please see the Container Specifications document for a full list of what can be modified.\n Vacuum You can perform a PostgreSQL vacuum command by running the crunchy-vacuum container. You specify a database to vacuum using environment variables. By default, vacuum is executed against the primary example container.\n The crunchy-vacuum container image exists to allow a DBA a way to run a job either individually or scheduled to perform a variety of vacuum operations.\n This example performs a vacuum on a single table in the primary PostgreSQL database. The crunchy-vacuum image is executed with the PostgreSQL connection parameters to the single-primary PostgreSQL container. The type of vacuum performed is dictated by the environment variables passed into the job; these are defined with further detail here.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker Run the example as follows:\n cd $CCPROOT/examples/docker/vacuum ./run.sh Kubernetes and OpenShift Running the example:\n cd $CCPROOT/examples/kube/vacuum/ ./run.sh Verify the job is completed:\n ${CCP_CLI} get job systemd The crunchy-pg.service is an example of a systemd unit file that starts and stops a container named crunchy-pg that has already been created.\n The example scripts are located in the following directory:\n $CCPROOT/examples/systemd/ There are two scripts within the directory.\n test-start.sh This script is called by the systemd start execution. The trick with this script is that it blocks forever after starting the docker crunchy-pg container. The blocking in the script keeps systemd happy and thinking that this is a normal daemon.\n test-stop.sh This script stops the test-start.sh script and also stops the crunchy-pg Docker container.\n Backup and Restoration pg_dump The script assumes you are going to backup the primary example and that container is running.\n This example assumes you have configured a storage filesystem as described in the Storage Configuration document.\n A successful backup will perform pg_dump/pg_dumpall on the primary and store the resulting files in the mounted volume under a directory named \u0026lt;HOSTNAME\u0026gt;-backups as a sub-directory, then followed by a unique backup directory based upon a date and timestamp - allowing any number of backups to be kept.\n For more information on how to configure this container, please see the Container Specifications document.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker Run the backup with this command:\n cd $CCPROOT/examples/docker/pgdump ./run.sh Kubernetes and OpenShift Running the example:\n cd $CCPROOT/examples/kube/pgdump ./run.sh The Kubernetes Job type executes a pod and then the pod exits. You can view the Job status using this command:\n ${CCP_CLI} get job The pgdump.json file within that directory specifies options that control the behavior of the pgdump job. Examples of this include whether to run pg_dump vs pg_dumpall and advanced options for specific backup use cases.\n pg_restore The script assumes you are going to restore to the primary example and that container is running and a backup has been created using the pgdump example..\n This example assumes you have configured a storage filesystem as described in the Storage Configuration document.\n Successful use of the crunchy-pgrestore container will run a job to restore files generated by pg_dump/pg_dumpall to a container via psql/pg_restore; then container will terminate successfully and signal job completion.\n For more information on how to configure this container, please see the Container Specifications document.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker Run the restore with this command:\n cd $CCPROOT/examples/docker/pgrestore ./run.sh Kubernetes and OpenShift By default, pgrestore container will automatically restore from the most recent backup. If you want to restore to a specific backup, edit the pgrestore.json file and update the PGRESTORE_BACKUP_TIMESTAMP setting to specify the backup path you want to restore with. For example:\n \"name\":\"PGRESTORE_BACKUP_TIMESTAMP\", \"value\":\"2018-03-27-14-35-33\" Running the example:\n cd $CCPROOT/examples/kube/pgrestore ./run.sh The Kubernetes Job type executes a pod and then the pod exits. You can view the Job status using this command:\n ${CCP_CLI} get job The pgrestore.json file within that directory specifies options that control the behavior of the pgrestore job.\n pgBackRest pgbackrest is a utility that performs a backup, restore, and archive function for a PostgreSQL database. pgbackrest is written and maintained by David Steele, and more information can be found on the official website.\n Backups are currently performed by manually executing pgbackrest commands against the desired pod. Restores can now be performed via the crunchy-backrest-restore container, which offers FULL or DELTA restore capability.\n pgbackrest is configured using a pgbackrest.conf file that is mounted into the crunchy-postgres container at /pgconf.\n If you place a pgbackrest.conf file within this mounted directory, it will trigger the use of pgbackrest within the PostgreSQL container as the archive_command and will turn on the archive_mode to begin archival. It is still required to define the ARCHIVE_TIMEOUT environment variable within your container configuration as it is set to a disable value of 0 by default.\n The following changes will be made to the container\u0026#8217;s postgresql.conf file:\n ARCHIVE_MODE=on ARCHIVE_TIMEOUT=60 ARCHIVE_COMMAND='pgbackrest --stanza=db archive-push %p' If you are using a crunchy-postgres image older than 1.7.1, archive_command must specify where the pgbackrest.conf file is located:\n ARCHIVE_COMMAND='pgbackrest --config=/pgconf/pgbackrest.conf --stanza=db archive-push %p' This requires you use a pgbackrest stanza name of db within the pgbackrest.conf file you mount.\n When set, WAL files generated by the database will be written out to the /backrestrepo/HOSTNAME-backups mount point.\n Additionally, the Crunchy Postgres container can templatize pgbackrest.conf files by searching for the HOSTNAME values in a mounted pgbackrest.conf file.\n For example, db-path=/pgdata/HOSTNAME will render to db-path=/pgdata/primary if the container\u0026#8217;s hostname is primary. HOSTNAME will be replaced with the value of PGDATA_PATH_OVERRIDE when working with deployments/replicasets.\n The templating example above works for db-path settings, however, repo-path should follow the convention repo-path=/backrestrepo/HOSTNAME-backups in cases where volumes are being mounted to a single mount point (such as hostPath or NFS). Without the additional -backups the backups will populate in the pgdata directory.\n Kubernetes and OpenShift Backup Start the example as follows:\n cd $CCPROOT/examples/kube/backrest/backup ./run.sh This will create the following in your Kubernetes environment:\n configMap containing pgbackrest.conf\n PostgreSQL pod with pgBackRest configured\n PostgreSQL service\n PVC for the PGDATA directory\n PVC for the BackRest Backups and Archives directory\n Examine the /backrestrepo location to view the archive directory and ensure WAL archiving is working.\n You can create a backup using backrest using this command within the container:\n ${CCP_CLI} exec -it backrest /bin/bash pgbackrest --stanza=db backup --type=full Async Archiving pgBackRest supports asyncronous archiving to pull and push Write Ahead Logs. Asynchronous operation is more efficient because it can reuse connections and take advantage of parallelism. For more information on async archiving, see the pgBackRest official documentation.\n This will create the following in your Kubernetes environment:\n configMap containing pgbackrest.conf\n PostgreSQL pod with pgBackRest configured and archiving asynchronously.\n PostgreSQL service\n PVC for the PGDATA directory\n PVC for the BackRest Backups and Archives directory\n Start the example as follows:\n cd $CCPROOT/examples/kube/backrest/async-archiving ./run.sh Examine the /backrestrepo/HOSTNAME-backups location to view the archive directory and ensure WAL archiving is working.\n Examine the /pgdata/HOSTNAME-spool location to view the transient directory used for async archiving.\n You can create a backup using backrest using this command within the container:\n ${CCP_CLI} exec -it backrest-async-archive /bin/bash pgbackrest --stanza=db backup A spooling directory is automatically created in both /pgdata and /pgwal. It is advised to configure pgBackRest to use the spooling location closest to the Write Ahead Log.\n If the PostgreSQL container was created using the XLOGDIR variable, the /pgwal/HOSTNAME-spool directory should be configured in pgbackrest.conf as such: spool-path=/pgwal/HOSTNAME-spool. If WAL resides on PGDATA, use: spool-path=/pgdata/HOSTNAME-spool\n Restore There are three options to choose from when performing a restore:\n Delta - only restore missing files from PGDATA\n Full - restore all files, pgdata must be empty\n Point in Time Recovery (PITR) - delta restore to a certain point in time\n PITR This example uses the backrest/backup example. It should be left running and a pgBackRest backup has been created.\n Start the example as follows:\n cd $CCPROOT/examples/kube/backrest/pitr ./run.sh This will create the following in your Kubernetes environment:\n configMap containing pgbackrest.conf\n Backrest-Restore pod with pgBackRest configured for PITR restore\n pgBackRest will restore the pgdata volume mounted to the restore container to the point in time specified by the PITR_TARGET environment variable. To get a compliant timestamp, PostgreSQL can be queried using the following SQL:\n psql -U postgres -Atc 'select current_timestamp' After a successful restore, run the following to start the restored PostgreSQL container:\n cd $CCPROOT/examples/kube/backrest/pitr ./post-restore.sh Full This example uses the backrest/backup example. It does not need to be running but a pgBackRest backup is required.\n Start the example as follows:\n cd $CCPROOT/examples/kube/backrest/full ./run.sh This will create the following in your Kubernetes environment:\n configMap containing pgbackrest.conf\n Backrest-Restore pod with pgBackRest configured for full restore\n New PVC for the PGDATA directory (full restores require PGDATA to be empty)\n pgBackRest will restore all files to the pgdata volume mounted to the restore container.\n After a successful restore, run the following to start the restored PostgreSQL container:\n cd $CCPROOT/examples/kube/backrest/full ./post-restore.sh Delta This example uses the backrest/backup example. It does not need to be running but a pgBackRest backup is required.\n Start the example as follows:\n cd $CCPROOT/examples/kube/backrest/delta ./run.sh This will create the following in your Kubernetes environment:\n configMap containing pgbackrest.conf\n Backrest-Restore pod with pgBackRest configured for full restore\n pgBackRest will restore files missing to the pgdata volume mounted to the restore container.\n After a successful restore, run the following to start the restored PostgreSQL container:\n cd $CCPROOT/examples/kube/backrest/delta ./post-restore.sh Docker Backup Start the example as follows:\n cd $CCPROOT/examples/docker/backrest/backup ./run.sh This will create the following in your Docker environment:\n PostgreSQL container with pgBackRest configured\n Volume for the PGDATA directory\n Volume for the pgbackrest.conf configuration\n Volume for the BackRest Backups and Archives directory\n Examine the /backrestrepo location to view the archive directory and ensure WAL archiving is working.\n You can create a backup using backrest using this command within the container:\n docker exec -it backrest /bin/bash pgbackrest --stanza=db backup --type=full Async Archiving This will create the following in your Docker environment:\n PostgreSQL container with pgBackRest configured\n Volume for the PGDATA directory\n Volume for the pgbackrest.conf configuration\n Volume for the BackRest Backups and Archives directory\n Start the example as follows:\n cd $CCPROOT/examples/docker/backrest/async-archiving ./run.sh Examine the /backrestrepo/HOSTNAME-backups location to view the archive directory and ensure WAL archiving is working.\n Examine the /pgdata/HOSTNAME-spool location to view the transient directory used for async archiving.\n You can create a backup using backrest using this command within the container:\n docker exec -it backrest /bin/bash pgbackrest --stanza=db backup A spooling directory is automatically created in both /pgdata and /pgwal. It is advised to configure pgBackRest to use the spooling location closest to the Write Ahead Log.\n If the PostgreSQL container was created using the XLOGDIR variable, the /pgwal/HOSTNAME-spool directory should be configured in pgbackrest.conf as such: spool-path=/pgwal/HOSTNAME-spool. If WAL resides on PGDATA, use: spool-path=/pgdata/HOSTNAME-spool\n Restore PITR This example uses the backrest/backup example. It should be left running and a pgBackRest backup has been created.\n Start the example as follows:\n cd $CCPROOT/examples/docker/backrest/pitr ./run.sh This will create the following in your Docker environment:\n Backrest-Restore container with pgBackRest configured for PITR restore\n pgBackRest will restore the pgdata volume mounted to the restore container to the point in time specified by the PITR_TARGET environment variable. To get a compliant timestamp, PostgreSQL can be queried using the following SQL:\n psql -U postgres -Atc 'select current_timestamp' After a successful restore, run the following to start the restored PostgreSQL container:\n cd $CCPROOT/examples/docker/backrest/pitr ./post-restore.sh Full This example uses the backrest/backup example. It does not need to be running but a pgBackRest backup is required.\n Start the example as follows:\n cd $CCPROOT/examples/docker/backrest/full ./run.sh This will create the following in your Docker environment:\n Backrest-Restore pod with pgBackRest configured for full restore\n New Volume for the PGDATA directory (full restores require PGDATA to be empty)\n pgBackRest will restore all files to the pgdata volume mounted to the restore container.\n After a successful restore, run the following to start the restored PostgreSQL container:\n cd $CCPROOT/examples/docker/backrest/full ./post-restore.sh Delta This example uses the backrest/backup example. It does not need to be running but a pgBackRest backup is required.\n Start the example as follows:\n cd $CCPROOT/examples/kube/backrest/delta ./run.sh This will create the following in your Docker environment:\n Backrest-Restore pod with pgBackRest configured for full restore\n pgBackRest will restore files missing to the pgdata volume mounted to the restore container.\n After a successful restore, run the following to start the restored PostgreSQL container:\n cd $CCPROOT/examples/kube/backrest/delta ./post-restore.sh pgBackRest with SSHD The PostgreSQL and PostgreSQL GIS containers can enable an SSH daemon to allow developers to do DBA tasks on the database server without the need for exec privileges. An administrator who deploys the SSHD enabled PostgreSQL database can specify the authorized public keys for access to the database server.\n In order to activate SSHD in the PostgreSQL containers, the following files need to be mounted to the PostgreSQL container:\n SSH Host keys mounted on the /sshd volume. Three keys are required:\n ssh_host_rsa_key\n ssh_host_ecdsa_key\n ssh_host_ed25519_key\n sshd_config mounted on the /pgconf volume\n authorized_keys mounted on the /pgconf volume\n SSHD can be enabled in the PostgreSQL containers by adding the following line:\n ENABLE_SSHD=true The authorized_keys file is mounted on the /pgconf directory. In order to support using this mount for authentication the following must be set in sshd_config:\n AuthorizedKeysFile /pgconf/authorized_keys StrictModes no For OpenShift deployments, the following configuration needs to be set in sshd_config:\n UsePAM no Docker Start the example as follows:\n cd $CCPROOT/examples/docker/postgres-sshd ./run.sh This will create the following in your Docker environment:\n A volume named pgconf which contains the pgbackrest.conf, pg_hba.conf, postgresql.conf, sshd_config, authorized_keys file\n A volume named sshd containing the SSH Host keys\n postgres-sshd container pgbackrest archive and sshd enabled. An initial stanza db will be created on initialization\n After running the example, SSH to the container using the forwarded port 2022:\n ssh -i ./keys/id_rsa -p 2022 postgres@0.0.0.0 Kubernetes / OpenShift Start the example as follows:\n cd $CCPROOT/examples/kube/postgres-sshd ./run.sh This will create the following in your Kubernetes environment:\n A configMap named pgconf which contains the pgbackrest.conf, pg_hba.conf, postgresql.conf, sshd_config, authorized_keys file\n A secret named sshd-secrets containing the SSH Host keys\n postgres-sshd pod with pgbackrest archive and sshd enabled. An initial stanza db will be created on initialization\n postgres-sshd service with port 2022 for SSH\n After running the example, SSH to the service using the postgres-sshd service available in Kubernetes:\n ssh -i ./keys/id_rsa -p 2022 postgres@postgres-sshd Using pgBackrest via SSH If a pgbackrest.conf file is located on the /pgconf volume and archiving is enabled, it\u0026#8217;s possible to run backups using the pgBackrest utility.\n With the SSHD service running, the following command will issue a pgBackrest backup.\n ssh -i ./keys/id_rsa -p 2022 postgres@postgres-sshd pgbackrest --stanza=db backup To list all the available pgBackrest backups, run the following:\n ssh -i ./keys/id_rsa -p 2022 postgres@postgres-sshd pgbackrest info pg_basebackup The script assumes you are going to backup the primary container created in the first example, so you need to ensure that container is running. This example assumes you have configured storage as described in the Storage Configuration documentation. Things to point out with this example include its use of persistent volumes and volume claims to store the backup data files.\n A successful backup will perform pg_basebackup on the primary container and store the backup in the $CCP_STORAGE_PATH volume under a directory named primary-backups. Each backup will be stored in a subdirectory with a timestamp as the name, allowing any number of backups to be kept.\n The backup script will do the following:\n Start up a backup container named backup\n Run pg_basebackup on the container named primary\n Store the backup in the /tmp/backups/primary-backups directory\n Exit after the backup\n When you are ready to restore from the backup, the restore example runs a PostgreSQL container using the backup location. Upon initialization, the container will use rsync to copy the backup data to this new container and then launch PostgreSQL using the original backed-up data.\n The restore script will do the following:\n Start up a container named restore\n Copy the backup files from the previous backup example into /pgdata\n Start up the container using the backup files\n Map the PostgreSQL port of 5432 in the container to your local host port of 12001\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker Run the backup with this command:\n cd $CCPROOT/examples/docker/backup ./run.sh When you\u0026#8217;re ready to restore, a restore example is provided.\n It\u0026#8217;s required to specified a backup path for this example. To get the correct path check the backup job logs or a timestamp:\n docker logs backup-vpk9l | grep BACKUP_PATH Wed May 9 20:32:00 UTC 2018 INFO: BACKUP_PATH is set to /pgdata/primary-backups/2018-05-09-20-32-00. BACKUP_PATH can also be discovered by looking at the backup mount directly (if access to the storage is available to the user).\n An example of BACKUP_PATH is as followed:\n \"name\": \"BACKUP_PATH\", \"value\": \"primary-backups/2018-05-09-20-32-00\" When you are ready to restore from the backup created, run the following example:\n cd $CCPROOT/examples/docker/restore ./run.sh Kubernetes and OpenShift Running the example:\n cd $CCPROOT/examples/kube/backup ./run.sh The Kubernetes Job type executes a pod and then the pod exits. You can view the Job status using this command:\n ${CCP_CLI} get job When you\u0026#8217;re ready to restore, a restore example is provided.\n It\u0026#8217;s required to specified a backup path for this example. To get the correct path check the backup job logs or a timestamp:\n kubectl logs backup-vpk9l | grep BACKUP_PATH Wed May 9 20:32:00 UTC 2018 INFO: BACKUP_PATH is set to /pgdata/primary-backups/2018-05-09-20-32-00. BACKUP_PATH can also be discovered by looking at the backup mount directly (if access to the storage is available to the user).\n An example of BACKUP_PATH defined as a variable within the JSON script is as follows:\n \"name\": \"BACKUP_PATH\", \"value\": \"primary-backups/2018-05-09-20-32-00\" Running the example:\n cd $CCPROOT/examples/kube/restore ./run.sh Test the restored database as follows:\n psql -h restore -U postgres postgres Point in Time Recovery (PITR) PITR (point-in-time-recovery) is a feature that allows for recreating a database from backup and log files at a certain point in time. This is done using a write ahead log (WAL) which is kept in the pg_wal directory within PGDATA. Changes made to the database files over time are recorded in these log files, which allows it to be used for disaster recovery purposes.\n When using PITR as a backup method, in order to restore from the last checkpoint in the event of a database or system failure, it is only necessary to save these log files plus a full backup. This provides an additional advantage in that it is not necessary to keep multiple full backups on hand, which consume space and time to create. This is because point in time recovery allows you to \"replay\" the log files and recover your database to any point since the last full backup.\n More detailed information about Write Ahead Log (WAL) archiving can be found here.\n By default in the crunchy-postgres container, WAL logging is not enabled. To enable WAL logging outside of this example, set the following environment variables when starting the crunchy-postgres container:\n ARCHIVE_MODE=on ARCHIVE_TIMEOUT=60 These variables set the same name settings within the postgresql.conf file that is used by the database. When set, WAL files generated by the database will be written out to the /pgwal mount point.\n A full backup is required to do a PITR. crunchy-backup currently performs this role within the example, running a pg_basebackup on the database. This is a requirement for PITR. After a backup is performed, code is added into crunchy-postgres which will also check to see if you want to do a PITR.\n There are three volume mounts used with the PITR example.\n /recover - When specified within a crunchy-postgres container, PITR is activated during container startup.\n /backup - This is used to find the base backup you want to recover from.\n /pgwal - This volume is used to write out new WAL files from the newly restored database container.\n Some environment variables used to manipulate the point in time recovery logic:\n The RECOVERY_TARGET_NAME environment variable is used to tell the PITR logic what the name of the target is.\n RECOVERY_TARGET_TIME is also an optional environment variable that restores using a known time stamp.\n If you don\u0026#8217;t specify either of these environment variables, then the PITR logic will assume you want to restore using all the WAL files or essentially the last known recovery point.\n The RECOVERY_TARGET_INCLUSIVE environment variable is also available to let you control the setting of the recovery.conf setting recovery_target_inclusive. If you do not set this environment variable the default is true.\n Once you recover a database using PITR, it will be in read-only mode. To make the database resume as a writable database, run the following SQL command:\n postgres=# select pg_wal_replay_resume(); If you\u0026#8217;re running the PITR example for PostgreSQL versions 9.5 or 9.6, please note that starting in PostgreSQL version 10, the pg_xlog directory was renamed to pg_wal. Additionally, all usages of the function pg_xlog_replay_resume were changed to pg_wal_replay_resume.\n It takes about 1 minute for the database to become ready for use after initially starting.\n WAL segment files are written to the /tmp directory. Leaving the example running for a long time could fill up your /tmp directory.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker Create a database container as follows:\n cd $CCPROOT/examples/docker/pitr ./run-pitr.sh Next, we will create a base backup of that database using this:\n ./run-backup-pitr.sh After creating the base backup of the database, WAL segment files are created every 60 seconds that contain any database changes. These segments are stored in the /tmp/pitr/pitr/pg_wal directory.\n Next, create some recovery targets within the database by running the SQL commands against the pitr database as follows:\n ./run-sql.sh This will create recovery targets named beforechanges, afterchanges, and nomorechanges. It will create a table, pitrtest, between the beforechanges and afterchanges targets. It will also run a SQL CHECKPOINT to flush out the changes to WAL segments. These labels can be used to mark the points in the recovery process that will be referenced when creating the restored database.\n Next, now that we have a base backup and a set of WAL files containing our database changes, we can shut down the pitr database to simulate a database failure. Do this by running the following:\n docker stop pitr Next, let\u0026#8217;s edit the restore script to use the base backup files created in the step above. You can view the backup path name under the /tmp/backups/pitr-backups/ directory. You will see another directory inside of this path with a name similar to 2018-03-21-21-03-29. Copy and paste that value into the run-restore-pitr.sh script in the BACKUP environment variable.\n After that, run the script.\n vi ./run-restore-pitr.sh ./run-restore-pitr.sh The WAL segments are read and applied when restoring from the database backup. At this point, you should be able to verify that the database was restored to the point before creating the test table:\n psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'table pitrtest' This SQL command should show that the pitrtest table does not exist at this recovery time. The output should be similar to:\n ERROR: relation \"pitrtest\" does not exist PostgreSQL allows you to pause the recovery process if the target name or time is specified. This pause would allow a DBA a chance to review the recovery time/name and see if this is what they want or expect. If so, the DBA can run the following command to resume and complete the recovery:\n psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'select pg_wal_replay_resume()' Until you run the statement above, the database will be left in read-only mode.\n Next, run the script to restore the database to the afterchanges restore point. Update the RECOVERY_TARGET_NAME to afterchanges:\n vi ./run-restore-pitr.sh ./run-restore-pitr.sh After this restore, you should be able to see the test table:\n psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'table pitrtest' psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'select pg_wal_replay_resume()' Lastly, start a recovery using all of the WAL files. This will get the restored database as current as possible. To do so, edit the script to remove the RECOVERY_TARGET_NAME environment setting completely:\n ./run-restore-pitr.sh sleep 30 psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'table pitrtest' psql -h 127.0.0.1 -p 12001 -U postgres postgres -c 'create table foo (id int)' At this point, you should be able to create new data in the restored database and the test table should be present. When you recover the entire WAL history, resuming the recovery is not necessary to enable writes.\n Kubernetes and OpenShift Start by running the example database container:\n cd $CCPROOT/examples/kube/pitr ./run-pitr.sh This step will create a database container, pitr. This container is configured to continuously write WAL segment files to a mounted volume (/pgwal).\n After you start the database, you will create a base backup using this command:\n ./run-backup-pitr.sh This will create a backup and write the backup files to a persistent volume (/pgbackup).\n Next, create some recovery targets within the database by running the SQL commands against the pitr database as follows:\n ./run-sql.sh This will create recovery targets named beforechanges, afterchanges, and nomorechanges. It will create a table, pitrtest, between the beforechanges and afterchanges targets. It will also run a SQL CHECKPOINT to flush out the changes to WAL segments.\n Next, now that we have a base backup and a set of WAL files containing our database changes, we can shut down the pitr database to simulate a database failure. Do this by running the following:\n ${CCP_CLI} delete pod pitr Next, we will create 3 different restored database containers based upon the base backup and the saved WAL files.\n First, get the BACKUP_PATH created by the backup-pitr example by viewing the pods logs:\n ${CCP_CLI} logs backup-pitr-8sfkh | grep PATH Thu May 10 18:07:58 UTC 2018 INFO: BACKUP_PATH is set to /pgdata/pitr-backups/2018-05-10-18-07-58. Edit the restore-pitr.json file and change the BACKUP_PATH environment variable using the path discovered above (note: /pgdata/ is not required and should be excluded in the variable):\n { \"name\": \"BACKUP_PATH\", \"value\": \"pitr-backups/2018-05-10-18-07-58\" { Next, we restore prior to the beforechanges recovery target. This recovery point is before the pitrtest table is created.\n Edit the restore-pitr.json file, and edit the environment variable to indicate we want to use the beforechanges recovery point:\n { \"name\": \"RECOVERY_TARGET_NAME\", \"value\": \"beforechanges\" { Then run the following to create the restored database container:\n ./run-restore-pitr.sh After the database has restored, you should be able to perform a test to see if the recovery worked as expected:\n psql -h restore-pitr -U postgres postgres -c 'table pitrtest' psql -h restore-pitr -U postgres postgres -c 'create table foo (id int)' The output of these commands should show that the pitrtest table is not present. It should also show that you can not create a new table because the database is paused in read-only mode.\n To make the database resume as a writable database, run the following SQL command:\n select pg_wal_replay_resume(); It should then be possible to write to the database:\n psql -h restore-pitr -U postgres postgres -c 'create table foo (id int)' You can also test that if afterchanges is specified, that the pitrtest table is present but that the database is still in recovery mode.\n Lastly, you can test a full recovery using all of the WAL files, if you remove the RECOVERY_TARGET_NAME environment variable completely.\n The storage portions of this example can all be found under $CCP_STORAGE_PATH.\n Connection Pooling pgBouncer Crunchy pgBouncer is a lightweight connection pooler for PostgreSQL databases.\n The following examples create the following containers:\n pgBouncer Primary\n pgBouncer Replica\n PostgreSQL Primary\n PostgreSQL Replica\n In Kubernetes and OpenShift, this example will also create:\n pgBouncer Primary Service\n pgBouncer Replica Service\n Primary Service\n Replica Service\n PostgreSQL Secrets\n pgBouncer Secrets\n To cleanup the objects created by this example, run the following in the pgbouncer example directory:\n ./cleanup.sh For more information on pgBouncer, see the official website.\n Docker Run the pgbouncer example:\n cd $CCPROOT/examples/docker/pgbouncer ./run.sh Once all containers have deployed and are ready for use, psql to the target databases through pgBouncer:\n psql -d userdb -h 0.0.0.0 -p 6432 -U testuser psql -d userdb -h 0.0.0.0 -p 6433 -U testuser To connect to the administration database within pgbouncer, connect using psql:\n psql -d pgbouncer -h 0.0.0.0 -p 6432 -U pgbouncer psql -d pgbouncer -h 0.0.0.0 -p 6433 -U pgbouncer Kubernetes and OpenShift OpenShift: If custom configurations aren\u0026#8217;t being mounted, an emptydir volume is required to be mounted at /pgconf.\n Run the pgbouncer example:\n cd $CCPROOT/examples/kube/pgbouncer ./run.sh Once all containers have deployed and are ready for use, psql to the target databases through pgBouncer:\n psql -d userdb -h pgbouncer-primary -p 6432 -U testuser psql -d userdb -h pgbouncer-replica -p 6432 -U testuser To connect to the administration database within pgbouncer, connect using psql:\n psql -d pgbouncer -h pgbouncer-primary -p 6432 -U pgbouncer -c \"SHOW SERVERS\" psql -d pgbouncer -h pgbouncer-replica -p 6432 -U pgbouncer -c \"SHOW SERVERS\" pgPool II An example is provided that will run a pgPool II container in conjunction with the primary-replica example provided above.\n You can execute both INSERT and SELECT statements after connecting to pgpool. The container will direct INSERT statements to the primary and SELECT statements will be sent round-robin to both the primary and replica.\n The container creates a default database called userdb, a default user called testuser and a default password of password.\n You can view the nodes that pgpool is configured for by running:\n psql -h pgpool -U testuser userdb -c 'show pool_nodes' To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker Create the container as follows:\n cd $CCPROOT/examples/docker/pgpool ./run.sh The example is configured to allow the testuser to connect to the userdb database.\n psql -h localhost -U testuser -p 12003 userdb Kubernetes and OpenShift Run the following command to deploy the pgpool service:\n cd $CCPROOT/examples/kube/pgpool ./run.sh The example is configured to allow the testuser to connect to the userdb database.\n psql -h pgpool -U testuser userdb Database Single Primary This example starts a single PostgreSQL container and service, the most simple of examples.\n The container creates a default database called userdb, a default user called testuser and a default password of password.\n For all environments, the script additionally creates:\n A persistent volume claim\n A crunchy-postgres container named primary\n The database using predefined environment variables\n And specifically for the Kubernetes and OpenShift environments:\n A pod named primary\n A service named primary\n A PVC named primary-pgdata\n The database using predefined environment variables\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker To create the example and run the container:\n cd $CCPROOT/examples/docker/primary ./run.sh Connect from your local host as follows:\n psql -h localhost -U testuser -W userdb Kubernetes and OpenShift To create the example:\n cd $CCPROOT/examples/kube/primary ./run.sh Connect from your local host as follows:\n psql -h primary -U postgres postgres Helm This example resides under the $CCPROOT/examples/helm directory. View the README to run this example using Helm here.\n PostgreSQL Deployment Starting in release 1.2.8, the PostgreSQL container can accept an environment variable named PGDATA_PATH_OVERRIDE. If set, the /pgdata/subdir path will use a subdirectory name of your choosing instead of the default which is the hostname of the container.\n This example shows how a Deployment of a PostgreSQL primary is supported. A pod is a deployment that uses a hostname generated by Kubernetes; because of this, a new hostname will be defined upon restart of the primary pod.\n For finding the /pgdata that pertains to the pod, you will need to specify a /pgdata/subdir name that never changes. This requirement is handled by the PGDATA_PATH_OVERRIDE environment variable.\n The container creates a default database called userdb, a default user called testuser and a default password of password.\n This example will create the following in your Kubernetes and OpenShift environments:\n primary-deployment service which uses a PVC to persist PostgreSQL data\n replica-deployment service, uses emptyDir persistence\n primary-deployment deployment of replica count 1 for the primary PostgreSQL database pod\n replica-deployment deployment of replica count 1 for the replica\n replica2-deployment deployment of replica count 1 for the 2nd replica\n ConfigMap to hold a custom postgresql.conf, setup.sql, and pg_hba.conf files\n Secrets for the primary user, superuser, and normal user to hold the passwords\n Volume mount for /backrestrepo and /pgwal\n The persisted data for the PostgreSQL primary is found under /pgdata/primary-deployment. If you delete the primary pod, the deployment will create another pod for the primary and will be able to start up immediately since it works out of the same /pgdata/primary-deployment data directory.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Kubernetes and OpenShift Start the example as follows:\n cd $CCPROOT/examples/kube/primary-deployment ./run.sh Replication This example starts a primary and a replica pod containing a PostgreSQL database.\n The container creates a default database called userdb, a default user called testuser and a default password of password.\n For the Docker environment, the script additionally creates:\n A docker volume using the local driver for the primary\n A docker volume using the local driver for the replica\n A container named primary binding to port 12007\n A container named replica binding to port 12008\n A mapping of the PostgreSQL port 5432 within the container to the localhost port 12000\n The database using predefined environment variables\n And specifically for the Kubernetes and OpenShift environments:\n emptyDir volumes for persistence\n A pod named pr-primary\n A pod named pr-replica\n A pod named pr-replica-2\n A service named pr-primary\n A service named pr-replica\n The database using predefined environment variables\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker To create the example and run the container:\n cd $CCPROOT/examples/docker/primary-replica ./run.sh Connect from your local host as follows:\n psql -h localhost -p 12007 -U testuser -W userdb psql -h localhost -p 12008 -U testuser -W userdb Docker-Compose Running the example:\n cd $CCPROOT/examples/compose/primary-replica docker-compose up To deploy more than one replica, run the following:\n docker-compose up --scale db-replica=3 To connect to the created database containers, first identify the ports exposed on the containers:\n docker ps Next, using psql, connect to the service:\n psql -d userdb -h 0.0.0.0 -p \u0026lt;CONTAINER_PORT\u0026gt; -U testuser See PG_PASSWORD in docker-compose.yml for the user password.\n To tear down the example, run the following:\n docker-compose stop docker-compose rm Kubernetes and OpenShift Run the following command to deploy a primary and replica database cluster:\n cd $CCPROOT/examples/kube/primary-replica ./run.sh It takes about a minute for the replica to begin replicating with the primary. To test out replication, see if replication is underway with this command:\n psql -h pr-primary -U postgres postgres -c 'table pg_stat_replication' If you see a line returned from that query it means the primary is replicating to the replica. Try creating some data on the primary:\n psql -h pr-primary -U postgres postgres -c 'create table foo (id int)' psql -h pr-primary -U postgres postgres -c 'insert into foo values (1)' Then verify that the data is replicated to the replica:\n psql -h pr-replica -U postgres postgres -c 'table foo' primary-replica-dc\n If you wanted to experiment with scaling up the number of replicas, you can run the following example:\n cd $CCPROOT/examples/kube/primary-replica-dc ./run.sh You can verify that replication is working using the same commands as above.\n This example creates 2 replicas when it initially starts. To scale up the number of replicas and view what the deployment looks like before and after, run these commands:\n ${CCP_CLI} get deployment ${CCP_CLI} scale --current-replicas=2 --replicas=3 deployment/replica-dc ${CCP_CLI} get deployment ${CCP_CLI} get pod You can verify that you now have 3 replicas by running this query on the primary:\n psql -h primary-dc -U postgres postgres -c 'table pg_stat_replication' Helm This example resides under the $CCPROOT/examples/helm directory. View the README to run this example using Helm here.\n Synchronous Replication This example deploys a PostgreSQL cluster with a primary, a synchronous replica, and an asynchronous replica. The two replicas share the same service.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker To run this example, run the following:\n cd $CCPROOT/examples/docker/sync ./run.sh You can test the replication status on the primary by using the following command and the password password:\n psql -h 127.0.0.1 -p 12010 -U postgres postgres -c 'table pg_stat_replication' You should see 2 rows; 1 for the asynchronous replica and 1 for the synchronous replica. The sync_state column shows values of async or sync.\n You can test replication to the replicas by first entering some data on the primary, and secondly querying the replicas for that data:\n psql -h 127.0.0.1 -p 12010 -U postgres postgres -c 'create table foo (id int)' psql -h 127.0.0.1 -p 12010 -U postgres postgres -c 'insert into foo values (1)' psql -h 127.0.0.1 -p 12011 -U postgres postgres -c 'table foo' psql -h 127.0.0.1 -p 12012 -U postgres postgres -c 'table foo' Kubernetes and OpenShift Running the example:\n cd $CCPROOT/examples/kube/sync ./run.sh Connect to the primarysync and replicasync databases as follows for both the Kubernetes and OpenShift environments:\n psql -h primarysync -U postgres postgres -c 'create table test (id int)' psql -h primarysync -U postgres postgres -c 'insert into test values (1)' psql -h primarysync -U postgres postgres -c 'table pg_stat_replication' psql -h replicasync -U postgres postgres -c 'select inet_server_addr(), * from test' psql -h replicasync -U postgres postgres -c 'select inet_server_addr(), * from test' psql -h replicasync -U postgres postgres -c 'select inet_server_addr(), * from test' This set of queries will show you the IP address of the PostgreSQL replica container. Note the changing IP address due to the round-robin service proxy being used for both replicas. The example queries also show that both replicas are replicating successfully from the primary.\n Statefulsets This example deploys a statefulset named statefulset. The statefulset is a new feature in Kubernetes as of version 1.5 and in OpenShift Origin as of version 3.5. Statefulsets have replaced PetSets going forward.\n Please view this Kubernetes description to better understand what a Statefulset is and how it works.\n This example creates 2 PostgreSQL containers to form the set. At startup, each container will examine its hostname to determine if it is the first container within the set of containers.\n The first container is determined by the hostname suffix assigned by Kubernetes to the pod. This is an ordinal value starting with 0. If a container sees that it has an ordinal value of 0, it will update the container labels to add a new label of:\n name=$PG_PRIMARY_HOST In this example, PG_PRIMARY_HOST is specified as statefulset-primary.\n By default, the containers specify a value of name=statefulset-replica.\n There are 2 services that end user applications will use to access the PostgreSQL cluster, one service (statefulset-primary) routes to the primary container and the other (statefulset-replica) to the replica containers.\n $ ${CCP_CLI} get service NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes 10.96.0.1 \u0026lt;none\u0026gt; 443/TCP 22h statefulset None \u0026lt;none\u0026gt; 5432/TCP 1h statefulset-primary 10.97.168.138 \u0026lt;none\u0026gt; 5432/TCP 1h statefulset-replica 10.97.218.221 \u0026lt;none\u0026gt; 5432/TCP 1h To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Kubernetes and OpenShift Start the example as follows:\n cd $CCPROOT/examples/kube/statefulset ./run.sh You can access the primary database as follows:\n psql -h statefulset-primary -U postgres postgres You can access the replica databases as follows:\n psql -h statefulset-replica -U postgres postgres You can scale the number of containers using this command; this will essentially create an additional replica database.\n ${CCP_CLI} scale --replicas=3 statefulset statefulset Helm This example resides under the $CCPROOT/examples/helm directory. View the README to run this example using Helm here.\n Geospatial (PostGIS) An example is provided that will run a PostgreSQL with PostGIS pod and service in Kubernetes and OpenShift and a container in Docker.\n The container creates a default database called userdb, a default user called testuser and a default password of password.\n You can view the extensions that postgres-gis has enabled by running the following command and viewing the listed PostGIS packages:\n psql -h postgres-gis -U testuser userdb -c '\\dx' To validate that PostGIS is installed and which version is running, run the command:\n psql -h postgres-gis -U testuser userdb -c \"SELECT postgis_full_version();\" You should expect to see output similar to:\n postgis_full_version ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- POSTGIS=\"2.4.2 r16113\" PGSQL=\"100\" GEOS=\"3.5.0-CAPI-1.9.0 r4084\" PROJ=\"Rel. 4.8.0, 6 March 2012\" GDAL=\"GDAL 1.11.4, released 2016/01/25\" LIBXML=\"2.9.1\" LIBJSON=\"0.11\" TOPOLOGY RASTER (1 row) As an exercise for invoking some of the basic PostGIS functionality for validation, try defining a 2D geometry point while giving inputs of longitude and latitude through this command.\n psql -h postgres-gis -U testuser userdb -c \"select ST_MakePoint(28.385200,-81.563900);\" You should expect to see output similar to:\n st_makepoint -------------------------------------------- 0101000000516B9A779C623C40B98D06F0166454C0 (1 row) To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker Create the container as follows:\n cd $CCPROOT/examples/docker/postgres-gis ./run.sh Enter the following command to connect to the postgres-gis container that is mapped to your local port 12000:\n psql -h localhost -U testuser -p 12000 userdb Kubernetes and OpenShift Running the example:\n cd $CCPROOT/examples/kube/postgres-gis ./run.sh Custom Configuration You can use your own version of the SQL file setup.sql to customize the initialization of database data and objects when the container and database are created.\n This works by placing a file named setup.sql within the /pgconf mounted volume directory. Portions of the setup.sql file are required for the container to work; please see comments within the sample setup.sql file.\n If you mount a /pgconf volume, crunchy-postgres will look at that directory for postgresql.conf, pg_hba.conf, pg_ident.conf, SSL server/ca certificates and setup.sql. If it finds one of them it will use that file instead of the default files.\n Docker This example can be run as follows for the Docker environment:\n cd $CCPROOT/examples/docker/custom-config ./run.sh Kubernetes and OpenShift Running the example:\n cd $CCPROOT/examples/kube/custom-config ./run.sh SSL Authentication This example shows how you can configure PostgreSQL to use SSL for client authentication.\n The example requires SSL certificates and keys to be created. Included in the examples directory is a script to create self-signed certificates (server and client) for the example: $CCPROOT/examples/ssl-creator.sh.\n The example creates a client certificate for the user testuser. Furthermore, the server certificate is created for the server name custom-config-ssl.\n If as a client it\u0026#8217;s required to confirm the identity of the server, verify-full can be specified in the connection string. This will check if the server and the server certificate have the same name:\n psql postgresql://custom-config-ssl:5432/postgres?sslmode=verify-full -U testuser\" To connect via IP, sslmode can be changed to require.\n psql postgresql://IP_OF_PGSQL:5432/postgres?sslmode=require -U testuser\" This example can be run as follows for the Docker environment:\n cd $CCPROOT/examples/docker/custom-config-ssl ./run.sh And the example can be run in the following directory for the Kubernetes and OpenShift environments:\n cd $CCPROOT/examples/kube/custom-config-ssl ./run.sh A required step to make this example work is to define in your /etc/hosts file an entry that maps custom-config-ssl to the service IP address for the container.\n For instance, if your service has an address as follows:\n ${CCP_CLI} get service NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE custom-config-ssl 172.30.211.108 \u0026lt;none\u0026gt; 5432/TCP Then your /etc/hosts file needs an entry like this:\n 172.30.211.108 custom-config-ssl For production Kubernetes and OpenShift installations, it will likely be preferred for DNS names to resolve to the PostgreSQL service name and generate server certificates using the DNS names instead of the example name custom-config-ssl.\n In order to connect via certificate, environment variables must be set that point to the client certificates. Source the env.sh file to set environment varaibles for the example:\n source env.sh If as a client it\u0026#8217;s required to confirm the identity of the server, verify-full can be specified in the connection string. This will check if the server and the server certificate have the same name:\n psql postgresql://custom-config-ssl:5432/userdb?sslmode=verify-full -U testuser\" To connect via IP, sslmode can be changed to require.\n psql postgresql://IP_OF_PGSQL:5432/userdb?sslmode=require -U testuser\" You should see a connection that looks like the following:\n psql (10.5) SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off) Type \"help\" for help. userdb=\u0026gt; Docker Swarm This example shows how to run a primary and replica database container on a Docker Swarm (v.1.12) cluster.\n First, set up a cluster. The Kubernetes libvirt coreos cluster example works well; see coreos-libvirt-cluster.\n Next, on each node, create the Swarm using these Swarm Install instructions.\n Include this command on the manager node:\n docker swarm init --advertise-addr 192.168.10.1 Then this command on all the worker nodes:\n docker swarm join \\ --token SWMTKN-1-65cn5wa1qv76l8l45uvlsbprogyhlprjpn27p1qxjwqmncn37o-015egopg4jhtbmlu04faon82u \\ 192.168.10.1.37 Before creating Swarm services, it is necessary to define an overlay network to be used by the services you will create. This can be done as follows:\n docker network create --driver overlay crunchynet We want to have the primary database always placed on a specific node. This is accomplished using node constraints as follows:\n docker node inspect kubernetes-node-1 | grep ID docker node update --label-add type=primary 18yrb7m650umx738rtevojpqy In the above example, the kubernetes-node-1 node with ID 18yrb7m650umx738rtevojpqy has a user defined label of primary added to it. The primary service specifies primary as a constraint when created; this tells Swarm to place the service on that specific node. The replica specifies a constraint of node.labels.type != primary to have the replica always placed on a node that is not hosting the primary service.\n Docker After you set up the Swarm cluster, you can then run this example as follows on the Swarm Manager Node:\n cd $CCPROOT/examples/docker/swarm-service ./run.sh You can then find the nodes that are running the primary and replica containers by:\n docker service ps primary docker service ps replica You can also scale up the number of replica containers.\n docker service scale replica=2 docker service ls Verify you have two replicas within PostgreSQL by viewing the pg_stat_replication table. The password is password by default when logged into the kubernetes-node-1 host:\n docker exec -it $(docker ps -q) psql -U postgres -c 'table pg_stat_replication' postgres You should see a row for each replica along with its replication status.\n Failover Watch This example shows how to run the crunchy-watch container to perform an automated failover. For the example to work, the host on which you are running needs to allow read-write access to /run/docker.sock. The crunchy-watch container runs as the postgres user, so adjust the file permissions of /run/docker.sock accordingly.\n The primary-replica example is required to be run before this example.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker Run the example as follows:\n cd $CCPROOT/examples/docker/watch ./run.sh This will start the watch container which tests every few seconds whether the primary database is running, if not, it will trigger a failover using docker exec on the replica host.\n Test it out by stopping the primary:\n docker stop primary docker logs watch Look at the watch container logs to see it perform the failover.\n Kubernetes and OpenShift Running the example:\n cd $CCPROOT/examples/kube/watch ./run.sh Check out the log of the watch container as follows:\n ${CCP_CLI} log watch Then trigger a failover using this command:\n ${CCP_CLI} delete pod pr-primary Resume watching the watch container\u0026#8217;s log and verify that it detects the primary is not reachable and performs a failover on the replica.\n A final test is to see if the old replica is now a fully functioning primary by inserting some test data into it as follows:\n psql -h pr-primary -U postgres postgres -c 'create table failtest (id int)' The above command still works because the watch container has changed the labels of the replica to make it a primary, so the primary service will still work and route now to the new primary even though the pod is named replica.\n You can view the labels on a pod with this command:\n ${CCP_CLI} describe pod pr-replica | grep Label Metrics and Performance pgBadger pgbadger is a PostgreSQL tool that reads the log files from a specified database in order to produce a HTML report that shows various PostgreSQL statistics and graphs. This example runs the pgbadger HTTP server against a crunchy-postgres container and illustrates how to view the generated reports.\n The port utilized for this tool is port 14000 for Docker environments and port 10000 for Kubernetes and OpenShift environments.\n A requirement to build this container from source is golang. On RHEL 7.2, golang is found in the 'server optional' repository which needs to be enabled in order to install this dependency.\n sudo subscription-manager repos --enable=rhel-7-server-optional-rpms The container creates a default database called userdb, a default user called testuser and a default password of password.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker Run the example as follows:\n cd $CCPROOT/examples/docker/pgbadger ./run.sh After execution, the container will run and provide a simple HTTP command you can browse to view the report. As you run queries against the database, you can invoke this URL to generate updated reports:\n curl -L http://127.0.0.1:14000/api/badgergenerate Kubernetes and OpenShift Running the example:\n cd $CCPROOT/examples/kube/pgbadger ./run.sh After execution, the container will run and provide a simple HTTP command you can browse to view the report. As you run queries against the database, you can invoke this URL to generate updated reports:\n curl -L http://pgbadger:10000/api/badgergenerate You can view the database container logs using these commands:\n ${CCP_CLI} logs pgbadger -c pgbadger ${CCP_CLI} logs pgbadger -c postgres Metrics Collection You can collect various PostgreSQL metrics from your database container by running a crunchy-collect container that points to your database container.\n This example starts up 5 containers:\n Collect (crunchy-collect)\n Grafana (crunchy-grafana)\n PostgreSQL (crunchy-postgres)\n Prometheus (crunchy-prometheus)\n Every 5 seconds by default, Prometheus will scrape the Collect container for metrics. These metrics will then be visualized by Grafana.\n By default, Prometheus detects which environment its running on (Docker, Kubernetes, or OpenShift Container Platform) and applies a default configuration. If this container is running on Kubernetes or OpenShift Container Platform, it will use the Kubernetes API to discover pods with the label \"crunchy-collect\": \"true\".\n The collect container must have this label to be discovered in these environments. Additionally, the collect container uses a special PostgreSQL role ccp_monitoring. This user is created by setting the PGMONITOR_PASSWORD environment variable on the PostgreSQL container.\n Discovering pods requires a cluster role service account. See the Kubernetes and OpenShift metrics JSON file for more details.\n For Docker environments the collect hostname must be specified as an environment variable.\n To shutdown the instance and remove the container for each example, run the following:\n ./cleanup.sh Docker To start this set of containers, run the following:\n cd $CCPROOT/examples/docker/metrics ./run.sh You will be able to access the Grafana and Prometheus services from the following web addresses:\n Grafana (http://0.0.0.0:3000)\n Prometheus (http://0.0.0.0:9090)\n The crunchy-postgres container is accessible on port 5432.\n Kubernetes and OpenShift Running the example:\n cd $CCPROOT/examples/kube/metrics ./run.sh It\u0026#8217;s required to use port-forward to access the Grafana dashboard. To start the port-forward, run the following command:\n ${CCP_CLI} port-forward metrics 3000:3000 ${CCP_CLI} port-forward metrics 9090:9090 Grafana dashboard can be then accessed from http://127.0.0.01:3000\n Prometheus dashboard can be then accessed from http://127.0.0.01:9090\n You can view the container logs using these command:\n ${CCP_CLI} logs -c grafana metrics ${CCP_CLI} logs -c prometheus metrics ${CCP_CLI} logs -c collect primary ${CCP_CLI} logs -c postgres primary ${CCP_CLI} logs -c collect replica ${CCP_CLI} logs -c postgres replica pg_audit This example provides an example of enabling pg_audit output. As of release 1.3, pg_audit is included in the crunchy-postgres container and is added to the PostgreSQL shared library list in postgresql.conf.\n Given the numerous ways pg_audit can be configured, the exact pg_audit configuration is left to the user to define. pg_audit allows you to configure auditing rules either in postgresql.conf or within your SQL script.\n For this test, we place pg_audit statements within a SQL script and verify that auditing is enabled and working. If you choose to configure pg_audit via a postgresql.conf file, then you will need to define your own custom file and mount it to override the default postgresql.conf file.\n Docker Run the following to create a database container:\n cd $CCPROOT/examples/docker/pgaudit ./run.sh This starts an instance of the pg_audit container (running crunchy-postgres) on port 12005 on localhost. The test script is then automatically executed.\n This test executes a SQL file which contains pg_audit configuration statements as well as executes some basic SQL commands. These SQL commands will cause pg_audit to create log messages in the pg_log log file created by the database container.\n Kubernetes and OpenShift Run the following:\n cd $CCPROOT/examples/kube/pgaudit ./run.sh The script will create the pg_audit pod (running the crunchy-postgres container) on the Kubernetes instance and then execute a SQL file which contains pg_audit configuration statements as well as some basic SQL commands. These SQL commands will cause pg_audit to create log messages in the pg_log file created by the database container.\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/single-primary/", - "title": "Single Primary", - "tags": [], - "description": "", - "content": " v2.2.0\nThe Crunchy PostgreSQL Primary Template creates a single primary pod.\nObjects The Crunchy PostreSQL Primary Template creates the following objects:\n PostgreSQL Secret - usernames and passwords generated from the template PGData PVC - Volume where PostgreSQL database will be stored Primary Service - Service connected to the Primary Pod Primary Pod - Primary database pod Storage This template assumes STORAGE_CLASS volumes will be used.\nForm Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore/", - "title": "Primary Restore", - "tags": [], - "description": "", - "content": " v2.2.0\nThe Crunchy PostgreSQL Primary Restore Template creates a single primary pod from a pg_basebackup physical backup.\nObjects The Crunchy PostreSQL Primary Template creates the following objects:\n PostgreSQL Secret - usernames and passwords generated from the template PGData PVC - Volume where PostgreSQL database will be stored Primary Service - Service connected to the Primary Pod Primary Pod - Primary database pod Storage This template assumes STORAGE_CLASS volumes will be used.\nThe template assumes a BACKUP PVC has been created and contains a backup.\nForm Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. BACKUP_PVC_NAME Name of the PVC where the physical backups are stored. BACKUP_DATE Timestamp of the backup to use from the Crunchy Backup job. BACKUP_HOSTNAME Hostname of the backed up database. PG_USER Username of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates). PG_PASSWORD Password of the PG_USER from the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates). PG_DATABASE Database of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates). PG_PRIMARY_USER Replication username of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates). PG_PRIMARY_PASSWORD Replication username password of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates). PG_PRIMARY_PASSWORD Superuser password of the backed up database (can be retrieved from existing secrets generated by Crunchy PostgreSQL Templates).** " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore-secret/", - "title": "Primary Restore Secret", - "tags": [], - "description": "", - "content": " v2.2.0\nThe Crunchy PostgreSQL Primary Restore Template creates a single primary pod from a pg_basebackup physical backup.\nObjects The Crunchy PostreSQL Primary Template creates the following objects:\n PGData PVC - Volume where PostgreSQL database will be stored Primary Service - Service connected to the Primary Pod Primary Pod - Primary database pod Storage This template assumes STORAGE_CLASS volumes will be used.\nThe template assumes a BACKUP PVC has been created and contains a backup.\nForm Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. BACKUP_PVC_NAME Name of the PVC where the physical backups are stored. BACKUP_DATE Timestamp of the backup to use from the Crunchy Backup job. BACKUP_HOSTNAME Hostname of the backed up database. PG_SECRET_NAME Name of the secret of the backed up database (can be retrieved from secrets). " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup/", - "title": "Primary Backup", - "tags": [], - "description": "", - "content": " v2.2.0\nThe Crunchy Backup template takes a pg_basebackup of the target database.\nObjects The Crunchy Backup Template creates the following objects:\n Backup PVC - Volume where pg_basebackup physical backups will be stored. Backup Job - Short lived pod that creates a physical backup using pg_basebackup. Storage This template assumes STORAGE_CLASS volumes will be used.\nForm Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. BACKUP_USER Name of the user to create the backup. Note: this user should have replication privileges (normally primaryuser in Crunchy PostgreSQL). BACKUP_PASS Password of the user to create the backup. DB_HOSTNAME Service name of the PostgreSQL pod to backup. Multiple Backups This templates creates a PVC automatically, however, to take multiple backups on the same volume the BACKUP_PVC_NAME environment field should be configured to an existing PVC.\nA template error is expected when supplying an existing PVC and can be ignored.\n" -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup-secret/", - "title": "Primary Backup Secret", - "tags": [], - "description": "", - "content": " v2.2.0\nThe Crunchy Backup Secrets template takes a pg_basebackup of the target database using a pre-existing OpenShift secret to retrieve usernames and passwords for backup purposes.\nObjects The Crunchy Backup Template creates the following objects:\n Backup PVC - Volume where pg_basebackup physical backups will be stored. Backup Job - Short lived pod that creates a physical backup using pg_basebackup. Storage This template assumes STORAGE_CLASS volumes will be used.\nForm Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. PG_SECRET_NAME Name of the secret where PostgreSQL credentials are located. DB_HOSTNAME Service name of the PostgreSQL pod to backup. Multiple Backups This templates creates a PVC automatically, however, to take multiple backups on the same volume the BACKUP_PVC_NAME environment field should be configured to an existing PVC.\nA template error is expected when supplying an existing PVC and can be ignored.\n" -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/postgres-replicated/", - "title": "Primary Replica", - "tags": [], - "description": "", - "content": " v2.2.0\nThe Crunchy PostgreSQL Primary/Replica Template creates a primary pod with replica statefulsets to provide a database cluster with streaming replication.\nObjects The Crunchy PostreSQL Primary/Replica Template creates the following objects:\n PostgreSQL Secret - usernames and passwords generated from the template PGData PVC - Volume where PostgreSQL database will be stored Backup PVC - Volume where pg_basebackup physical backups will be stored Backrestrepo PVC - Volume where pgBackRest physical backups will be stored Primary Service - Service connected to the Primary Pod Replica Service - Service connected to the Replica Pods Primary Pod - Primary database pod Replica Statefulset - Replica database pods Storage This template assumes STORAGE_CLASS volumes will be used.\nForm Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/pgadmin4/", - "title": "pgAdmin4", - "tags": [], - "description": "", - "content": " v2.2.0\nCrunchy pgAdmin4 Template provides a feature rich, GUI Open Source administration and development platform for PostgreSQL.\nObjects The Crunchy pgAdmin4 Template creates the following objects:\n pgAdmin4 Secret - email and password for login pgAdmin4 PVC - Volume where pgAdmin4 data will be stored pgAdmin4 Service - Service connected to the pgAdmin4 pod pgAdmin4 Pod - pgAdmin4 web application Storage This template assumes STORAGE_CLASS volumes will be used.\nForm Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. PGADMIN_EMAIL Email address used to login to the web application. PGADMIN_PASSWORD Password used to login to the web application. " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/", - "title": "Crunchy Data Container Suite", - "tags": [], - "description": "", - "content": " Latest Release: 2.1.0 2018-08-13\n General Please view the official Crunchy Data Container Suite documentation here. If you are interested in contributing or making an update to the documentation, please view the Contributing Guidelines.\n Warning: The master branch is considered unstable. Please consult the tagged release currently deployed in your environment.\n What is the Container Suite? The Crunchy Container Suite provides Docker containers that enable rapid deployment of PostgreSQL, including administration and monitoring tools. Multiple styles of deploying PostgreSQL clusters are supported.\n Requirements The containers will execute in the following environments:\n Docker 1.12 and above\n Openshift 3.4 and above\n Kubernetes 1.5 and above\n Containers The project includes the following containers:\n crunchy-postgres - executes Postgres\n crunchy-postgres-gis - executes Postgres plus the PostGIS extensions\n crunchy-backup - performs a full database backup\n crunchy-pgpool - executes pgpool\n crunchy-pgbadger - executes pgbadger\n crunchy-watch - performs a form of automated failover\n crunchy-collect - collects Postgres metrics\n crunchy-prometheus -stores Postgres metrics\n crunchy-grafana - graphs Postgres metrics\n crunchy-pgbouncer - pgbouncer connection pooler and simple form of failover\n crunchy-pgadmin4 - pgadmin4 web application\n crunchy-dba - implements a cron scheduler to perform simple DBA tasks\n crunchy-upgrade - allows you to perform a major postgres upgrade using pg_upgrade\n crunchy-backrest-restore - allows you to perform a pgbackrest restore\n crunchy-sim - executes queries over a specified interval range for Postgres traffic simulation purposes\n crunchy-pgdump - provides a means of performing either a pg_dump or pg_dumpall on a Postgres database\n crunchy-pgrestore - provides a means of performing a restore of a dump from pg_dump or pg_dumpall via psql or pg_restore to a Postgres container database\n For Kubernetes users of these containers, there is an associated project worth taking a look at that uses the containers found in this repo and provides a higher level automation. That project is the postgres-operator.\n Further descriptions of each of these containers and environment variables that can be used to tune them can be found in the Container Specifications document.\n Getting Started Complete build and install documentation is found here. The provided Dockerfiles build the containers on a Centos 7 base image and use the community PostgreSQL RPMs.\n Crunchy provides a commercially supported version of these containers built upon RHEL 7 and the Crunchy supported PostgreSQL. Contact Crunchy for more details at http://www.crunchydata.com.\n Usage Various examples are provided in the Getting Started documentation for running in Docker, Kubernetes, and OpenShift environments.\n You will need to set up your environment as per the Installation documentation in order to execute the examples.\n " -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/categories/", - "title": "Categories", - "tags": [], - "description": "", - "content": "" -}, -{ - "uri": "https://crunchydata.github.io/crunchy-containers/tags/", - "title": "Tags", - "tags": [], - "description": "", - "content": "" -}] \ No newline at end of file diff --git a/docs/index.xml b/docs/index.xml deleted file mode 100644 index e5ed834bd..000000000 --- a/docs/index.xml +++ /dev/null @@ -1,335 +0,0 @@ - - - - Crunchy Data Container Suite on Crunchy Data Container Suite Documentation - https://crunchydata.github.io/crunchy-containers/ - Recent content in Crunchy Data Container Suite on Crunchy Data Container Suite Documentation - Hugo -- gohugo.io - en-us - Mon, 23 Apr 2018 14:52:09 -0700 - - - - - - crunchy-postgres - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres/ - Thu, 24 May 2018 09:38:13 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres/ - PostgreSQL (pronounced &ldquo;post-gress-Q-L&rdquo;) is an open source, ACID compliant, relational database management system (RDBMS) developed by a worldwide team of volunteers. The crunchy-postgres container image is unmodified, open source PostgreSQL packaged and maintained by professionals. -Features The following features are supported by the crunchy-postgres container: - Kubernetes and OpenShift secrets Backup and restoration from various tools: pgbackrest, pg_basebackup and pg_dump/pg_restore. Custom mounted configuration files (see below) Async and Sync Replication Packages The crunchy-postgres Docker image contains the following packages (versions vary depending on PostgreSQL version): - - - - Environment Setup - https://crunchydata.github.io/crunchy-containers/installation/environment-setup/ - Tue, 08 May 2018 08:52:09 -0700 - - https://crunchydata.github.io/crunchy-containers/installation/environment-setup/ - Table of Contents Requirements Project Environment Installing Requirements CentOS 7 RHEL 7 PostgreSQL Docker OpenShift Kubernetes Helm Creating a Demo Namespace Kubernetes OpenShift Next Steps Latest Release: 2.1.0 2018-08-13 - Requirements The Crunchy Container Suite can run on different environments including: - Docker 1.12+ - OpenShift Container Platform 3.6+ - Kubernetes 1.8+ - In this document we list the basic installation steps required for these environments. - - - - crunchy-postgres-gis - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres-gis/ - Thu, 24 May 2018 09:51:16 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-postgres-gis/ - PostgreSQL (pronounced &ldquo;post-gress-Q-L&rdquo;) is an open source, ACID compliant, relational database management system (RDBMS) developed by a worldwide team of volunteers. The crunchy-postgres-gis container image is unmodified, open source PostgreSQL packaged and maintained by professionals. This image is identical to the crunchy-postgres image except it includes the open source geospatial extension PostGIS for PostgreSQL in addition to the language extension PL/R which allows for writing functions in the R statistical computing language. - - - - Build the Containers - https://crunchydata.github.io/crunchy-containers/installation/build-the-containers/ - Tue, 08 May 2018 08:52:16 -0700 - - https://crunchydata.github.io/crunchy-containers/installation/build-the-containers/ - Table of Contents Build the Containers Next Steps Latest Release: 2.1.0 2018-08-13 - Build the Containers At this point, you have a decision to make - either download prebuilt containers from Dockerhub, or build the containers on your local host. - To download the prebuilt containers, make sure you can login to Dockerhub, and then run the following: - docker login cd $CCPROOT ./bin/pull-from-dockerhub.sh Or if you&#8217;d rather build the containers from source, perform a container build as follows: - - - - crunchy-backup - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backup/ - Thu, 24 May 2018 10:06:08 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backup/ - The crunchy-backup container executes a full backup against another database container using the standard pg_basebackup utility that is included with PostgreSQL. -Features The following features are supported by the crunchy-backup container: - Backup and restoration from: pg_basebackup Packages The crunchy-backup Docker image contains the following packages (versions vary depending on PostgreSQL version): - PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description BACKUP_LABEL crunchy-backup The label for the backup. - - - - Storage Configuration - https://crunchydata.github.io/crunchy-containers/installation/storage-configuration/ - Tue, 08 May 2018 08:52:46 -0700 - - https://crunchydata.github.io/crunchy-containers/installation/storage-configuration/ - Table of Contents Available Storage Types HostPath NFS Dynamic Storage Next Steps Latest Release: 2.1.0 2018-08-13 - Available Storage Types The Container Suite is tested on 3 different storage backends: - hostPath (single node testing) - NFS (single and multi-node testing) - Gluster (dynamic storage on separate Gluster cluster) - Other storage backends work as well including GCE, EBS, ScaleIO, and others, but may require you to modify various examples or configuration. - - - - crunchy-backrest-restore - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backrest-restore/ - Thu, 24 May 2018 12:06:26 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-backrest-restore/ - The crunchy-backrest-restore container executes the pgBackRest utility, allowing FULL and DELTA restore capability. See the pgBackRest guide for more details. -Features The following features are supported and required by the crunchy-backrest-restore container: - Mounted pgbackrest.conf configuration file via the /pgconf volume Mounted /backrestrepo for access to pgBackRest archives Packages The crunchy-backrest-restore Docker image contains the following packages (versions vary depending on PostgreSQL version): - PostgreSQL (10.5, 9.6.10 and 9. - - - - crunchy-pgdump - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgdump/ - Thu, 24 May 2018 12:08:16 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgdump/ - The crunchy-pgdump container executes either a pg_dump or pg_dumpall database backup against another PostgreSQL database. -Packages The crunchy-pgdump Docker image contains the following packages (versions vary depending on PostgreSQL version): - PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PGDUMP_DB None Name of the database the backup is being performed on. - - - - crunchy-pgrestore - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgrestore/ - Thu, 24 May 2018 12:05:38 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgrestore/ - The restore image provides a means of performing a restore of a dump from pg_dump or pg_dumpall via psql or pg_restore to a PostgreSQL container database. -Packages The crunchy-pgrestore Docker image contains the following packages (versions vary depending on PostgreSQL version): - PostgreSQL (10.5, 9.6.10 and 9.5.14) CentOS7 - publicly available RHEL7 - customers only Environment Variables Required Name Default Description PGRESTORE_DB None Name of the database to connect to. - - - - crunchy-collect - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-collect/ - Thu, 24 May 2018 10:06:13 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-collect/ - The crunchy-collect container provides real time metrics about the PostgreSQL database via an API. These metrics are scrapped and stored by a Prometheus time-series database and are then graphed and visualized through the open source data visualizer Grafana. -The crunchy-collect container uses pgMonitor for advanced metric collection. It is required that the crunchy-postgres container has the PGMONITOR_PASSWORD environment variable to create the appropriate user (ccp_monitoring) to collect metrics. -Custom queries to collect metrics can be specified by the user. - - - - crunchy-prometheus - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-prometheus/ - Thu, 24 May 2018 10:06:21 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-prometheus/ - Prometheus is a multi-dimensional time series data model with an elastic query language. It is used in collaboration with Grafana in this metrics suite. Overall, it’s reliable, manageable, and operationally simple for efficiently storing and analyzing data for large-scale environments. It scraps metrics from exporters such as the ones utilized by the crunchy-collect container. The crunchy-prometheus container must be able to reach the crunchy-collect container in order to to scrape metrics. - - - - crunchy-grafana - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-grafana/ - Thu, 24 May 2018 10:06:17 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-grafana/ - Visual dashboards are created from the collected and stored data that crunchy-collect and crunchy-prometheus provide for the crunchy-grafana container, which hosts an open source web-based graphing dashboard called Grafana. -Grafana is a platform which can then apply the defined metrics and visualize information through various tools. It is extremely flexible with a powerful query and transformation language, producing beautiful and easily understandable graphics to analyze and monitor your data. - - - - crunchy-pgadmin4 - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgadmin4/ - Thu, 24 May 2018 12:05:42 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgadmin4/ - The crunchy-ppgadmin4 container executes the pgAdmin4 web application. -pgAdmin4 provides a web user interface to PostgreSQL databases. A sample screenshot is below: -Features The following features are supported by the crunchy-pgadmin4 container: - Expose port (5050 by default) which is the web server port. Mount a certificate and key to the /certs directory and set ENABLE_TLS to true to activate HTTPS mode. Set username and password for login via environment variables. - - - - crunchy-watch - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-watch/ - Thu, 24 May 2018 12:06:15 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-watch/ - The crunchy-watch container essentially does a health check on a primary database container and performs a failover sequence if the primary is not reached. The watch container has access to a service account that is used inside the container to issue commands to OpenShift. -In Kubrnetese 1.5, if a policy file is being used for securing down the Kubernetes cluster, you could possibly need to add a policy to allow the pg-watcher service account access to the Kubernetes API as mentioned here. - - - - crunchy-vacuum - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-vacuum/ - Thu, 24 May 2018 12:06:12 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-vacuum/ - The crunchy-vacuum container allows you to perform a SQL VACUUM job against a PostgreSQL database container. You specify a database to vacuum using various environment variables which are listed below. It is possible to run different vacuum operations either manually or automatically through scheduling. -The crunchy-vacuum image is executed, with the Postgres connection parameters passed to the single-primary PostgreSQL container. The type of vacuum performed is dictated by the environment variables passed into the job. - - - - crunchy-upgrade - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-upgrade/ - Thu, 24 May 2018 12:05:31 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-upgrade/ - The crunchy-upgrade container contains both the 9.5&frasl;9.6 and 9.6&frasl;10 PostgreSQL packages in order to perform a pg_upgrade from 9.5 to 9.6 or 9.6 to 10 versions. -Features The following features are supported by the crunchy-upgrade container: - Supports a pg_upgrade of the PostgreSQL database. Doesn&rsquo;t alter the old database files. Creates the new database directory. Restrictions Does not currently support a PostGIS upgrade. Supports upgrades from only 9. - - - - crunchy-sim - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-sim/ - Thu, 24 May 2018 12:05:28 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-sim/ - The crunchy-sim container is a simple traffic simulator for PostgreSQL. -Features Creates a single connection to PostgreSQL and will execute queries over a specified interval range. Queries are specified through a simple YAML file. Each query is a name-value pair and can span multiple lines by utilizing scalar notation (&ldquo;|&rdquo; or &ldquo;&gt;&rdquo;) as defined by the YAML spec. Queries are randomly chosen for execution. Restrictions Only one connection is created for all queries. - - - - crunchy-dba - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-dba/ - Thu, 24 May 2018 12:05:24 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-dba/ - The crunchy-dba container implements a cron scheduler. The purpose of the crunchy-dba container is to offer a way to perform simple DBA tasks that occur on some form of schedule such as backup jobs or running a vacuum on a single PostgreSQL database container. -You can either run the crunchy-dba container as a single pod or include the container within a database pod. -The crunchy-dba container makes use of a Service Account to perform the startup of scheduled jobs. - - - - crunchy-pgbouncer - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbouncer/ - Thu, 24 May 2018 12:05:03 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbouncer/ - pgBouncer is a lightweight connection pooler for PostgreSQL databases. -Features The following features are supported by the crunchy-pgbouncer container: - crunchy-pgbouncer uses auth_query to authenticate users. This requires only the pgbouncer username and password in users.txt. Automatically generated from environment variables. Mount a custom users.txt and pgbouncer.ini configurations for advanced usage. Tune pooling parameters via environment variables. Connect to the administration database in pgBouncer to view statistics of the target databases. - - - - crunchy-pgpool - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgpool/ - Thu, 24 May 2018 12:05:00 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgpool/ - The crunchy-pgpool container executes the pgPool II utility. pgPool can be used to provide a smart PostgreSQL-aware proxy to a PostgreSQL cluster, both primary and replica, so that applications only have to work with a single database connection. -PostgreSQL replicas are read-only whereas a primary is capable of receiving both read and write actions. -The default pgPool examples use a Secret to hold the set of pgPool configuration files used by the examples. - - - - crunchy-pgbadger - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbadger/ - Thu, 24 May 2018 12:04:55 -0700 - - https://crunchydata.github.io/crunchy-containers/container-specifications/crunchy-pgbadger/ - The crunchy-pgbadger container executes the pgBadger utility, which generates a PostgreSQL log analysis report using a small HTTP server running on the container. This log report can be accessed through the URL http://&lt;&gt;:10000/api/badgergenerate. -Features The following features are supported by the crunchy-pgbadger container: - Generate a full report by default Optional custom options for more advanced use cases (such as incremental reports) Report persistence on a volume Packages The crunchy-badger Docker image contains the following packages: - - - - Single Primary - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/single-primary/ - Tue, 15 May 2018 07:22:59 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/single-primary/ - v2.1.0 -The Crunchy PostgreSQL Primary Template creates a single primary pod. -Objects The Crunchy PostreSQL Primary Template creates the following objects: - PostgreSQL Secret - usernames and passwords generated from the template PGData PVC - Volume where PostgreSQL database will be stored Primary Service - Service connected to the Primary Pod Primary Pod - Primary database pod Storage This template assumes STORAGE_CLASS volumes will be used. -Form Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. - - - - Primary Restore - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore/ - Tue, 15 May 2018 07:22:51 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore/ - v2.1.0 -The Crunchy PostgreSQL Primary Restore Template creates a single primary pod from a pg_basebackup physical backup. -Objects The Crunchy PostreSQL Primary Template creates the following objects: - PostgreSQL Secret - usernames and passwords generated from the template PGData PVC - Volume where PostgreSQL database will be stored Primary Service - Service connected to the Primary Pod Primary Pod - Primary database pod Storage This template assumes STORAGE_CLASS volumes will be used. - - - - Primary Restore Secret - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore-secret/ - Tue, 15 May 2018 07:22:45 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-restore-secret/ - v2.1.0 -The Crunchy PostgreSQL Primary Restore Template creates a single primary pod from a pg_basebackup physical backup. -Objects The Crunchy PostreSQL Primary Template creates the following objects: - PGData PVC - Volume where PostgreSQL database will be stored Primary Service - Service connected to the Primary Pod Primary Pod - Primary database pod Storage This template assumes STORAGE_CLASS volumes will be used. -The template assumes a BACKUP PVC has been created and contains a backup. - - - - Primary Backup - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup/ - Tue, 15 May 2018 07:22:27 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup/ - v2.1.0 -The Crunchy Backup template takes a pg_basebackup of the target database. -Objects The Crunchy Backup Template creates the following objects: - Backup PVC - Volume where pg_basebackup physical backups will be stored. Backup Job - Short lived pod that creates a physical backup using pg_basebackup. Storage This template assumes STORAGE_CLASS volumes will be used. -Form Required Name Description VOLUME_STORAGE_CLASS Name of the Storage Class that provides persistence for the container. - - - - Primary Backup Secret - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup-secret/ - Tue, 15 May 2018 07:22:20 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/primary-backup-secret/ - v2.1.0 -The Crunchy Backup Secrets template takes a pg_basebackup of the target database using a pre-existing OpenShift secret to retrieve usernames and passwords for backup purposes. -Objects The Crunchy Backup Template creates the following objects: - Backup PVC - Volume where pg_basebackup physical backups will be stored. Backup Job - Short lived pod that creates a physical backup using pg_basebackup. Storage This template assumes STORAGE_CLASS volumes will be used. - - - - Primary Replica - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/postgres-replicated/ - Tue, 15 May 2018 07:22:10 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/postgres-replicated/ - v2.1.0 -The Crunchy PostgreSQL Primary/Replica Template creates a primary pod with replica statefulsets to provide a database cluster with streaming replication. -Objects The Crunchy PostreSQL Primary/Replica Template creates the following objects: - PostgreSQL Secret - usernames and passwords generated from the template PGData PVC - Volume where PostgreSQL database will be stored Backup PVC - Volume where pg_basebackup physical backups will be stored Backrestrepo PVC - Volume where pgBackRest physical backups will be stored Primary Service - Service connected to the Primary Pod Replica Service - Service connected to the Replica Pods Primary Pod - Primary database pod Replica Statefulset - Replica database pods Storage This template assumes STORAGE_CLASS volumes will be used. - - - - pgAdmin4 - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/pgadmin4/ - Tue, 15 May 2018 07:22:02 -0700 - - https://crunchydata.github.io/crunchy-containers/getting-started/openshift-templates/pgadmin4/ - v2.1.0 -Crunchy pgAdmin4 Template provides a feature rich, GUI Open Source administration and development platform for PostgreSQL. -Objects The Crunchy pgAdmin4 Template creates the following objects: - pgAdmin4 Secret - email and password for login pgAdmin4 PVC - Volume where pgAdmin4 data will be stored pgAdmin4 Service - Service connected to the pgAdmin4 pod pgAdmin4 Pod - pgAdmin4 web application Storage This template assumes STORAGE_CLASS volumes will be used. - - - - \ No newline at end of file diff --git a/docs/installation/build-the-containers/index.html b/docs/installation/build-the-containers/index.html deleted file mode 100644 index 223a510d8..000000000 --- a/docs/installation/build-the-containers/index.html +++ /dev/null @@ -1,489 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Build the Containers :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
      - - - - -
      -
      -
      - -
      - - - - - - - -
      -
      - -
      -
      - - -
      - - -
      - -

      Build the Containers

      - - - - - - - -
      -
      Table of Contents
      - -
      -
      -

      Latest Release: 2.1.0 2018-08-13

      -
      -
      -

      Build the Containers

      -
      -
      -

      At this point, you have a decision to make - either download prebuilt -containers from Dockerhub, or build the containers on your local host.

      -
      -
      -

      To download the prebuilt containers, make sure you can login to -Dockerhub, and then run the following:

      -
      -
      -
      -
      docker login
      -cd $CCPROOT
      -./bin/pull-from-dockerhub.sh
      -
      -
      -
      -

      Or if you’d rather build the containers from source, perform a container -build as follows:

      -
      -
      -
      -
      godep restore
      -cd $CCPROOT
      -make setup
      -make all
      -
      -
      -
      -

      After this, you will have all the Crunchy containers built and are ready -for use in a standalone Docker environment.

      -
      -
      -
      -
      -

      Next Steps

      -
      -
      -

      Next, configure a storage type as demonstrated in the Storage Configuration document.

      -
      -
      -
      - - - - -
      - -
      -
      -
      - - - -
      -
      -
      -
      - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/installation/environment-setup/index.html b/docs/installation/environment-setup/index.html deleted file mode 100644 index de54dd280..000000000 --- a/docs/installation/environment-setup/index.html +++ /dev/null @@ -1,1047 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Environment Setup :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
      - - - - -
      -
      -
      - -
      - - - - - - - -
      -
      - -
      -
      - - -
      - - -
      - -

      Environment Setup

      - - - - - - - - -
      -

      Latest Release: 2.1.0 2018-08-13

      -
      -
      -

      Requirements

      -
      -
      -

      The Crunchy Container Suite can run on different environments including:

      -
      -
      -
        -
      • -

        Docker 1.12+

        -
      • -
      • -

        OpenShift Container Platform 3.6+

        -
      • -
      • -

        Kubernetes 1.8+

        -
      • -
      -
      -
      -

      In this document we list the basic installation steps required for these -environments.

      -
      -
      -

      These installation instructions are developed and tested for the following operating systems:

      -
      -
      -
        -
      • -

        CentOS 7

        -
      • -
      • -

        RHEL 7

        -
      • -
      -
      -
      -
      -
      -

      Project Environment

      -
      -
      -

      First add the following lines to your .bashrc file to set -the project paths:

      -
      -
      -
      -
      export GOPATH=$HOME/cdev
      -export GOBIN=$GOPATH/bin
      -export PATH=$PATH:$GOBIN
      -export CCP_BASEOS=centos7
      -export CCP_PGVERSION=10
      -export CCP_PG_FULLVERSION=10.5
      -export CCP_VERSION=2.1.0
      -export CCP_IMAGE_PREFIX=crunchydata
      -export CCP_IMAGE_TAG=$CCP_BASEOS-$CCP_PG_FULLVERSION-$CCP_VERSION
      -export CCPROOT=$GOPATH/src/github.com/crunchydata/crunchy-containers
      -export CCP_SECURITY_CONTEXT=""
      -export CCP_CLI=kubectl
      -export CCP_NAMESPACE=demo
      -
      -
      -
      -
      -

      Please see the Storage Configuration document -for configuring storage using environment variables set in .bashrc.

      -
      -
      -

      Additionally, the CCP_CLI setting above indicates you are running the -examples on a Kubernetes platform and not an OpenShift platform. For -OpenShift, use the value of oc as the CCP_CLI variable instead.

      -
      -
      - -
      -
      -

      It will be necessary to refresh your .bashrc file in order for the changes to take -effect.

      -
      -
      -
      -
      . ~/.bashrc
      -
      -
      -
      -

      Next, set up a project directory structure and pull down the project:

      -
      -
      -
      -
      mkdir -p $HOME/cdev/src $HOME/cdev/pkg $HOME/cdev/bin
      -
      -
      -
      -
      -
      -

      Installing Requirements

      -
      -
      -

      CentOS 7

      -
      -
      -
      cd $GOPATH
      -sudo yum -y install golang git docker
      -go get github.com/tools/godep
      -cd src/github.com
      -mkdir crunchydata
      -cd crunchydata
      -git clone https://github.com/crunchydata/crunchy-containers
      -cd crunchy-containers
      -git checkout 2.1.0
      -go get github.com/blang/expenv
      -
      -
      -
      -
      -

      If you are a Crunchy enterprise customer, you will place the Crunchy repository -key and yum repository file into the $CCPROOT/conf directory at this point. These -files can be obtained through https://access.crunchydata.com/ on the downloads -page.

      -
      -
      - -
      -
      -
      -

      RHEL 7

      -
      -

      When setting up the environment on RHEL 7, there are slightly different steps that -need to be taken.

      -
      -
      -
      -
      cd $GOPATH
      -sudo subscription-manager repos --enable=rhel-7-server-optional-rpms
      -sudo yum-config-manager --enable rhel-7-server-extras-rpms
      -sudo yum -y install git golang
      -go get github.com/tools/godep
      -cd src/github.com
      -mkdir crunchydata
      -cd crunchydata
      -git clone https://github.com/crunchydata/crunchy-containers
      -cd crunchy-containers
      -git checkout 2.1.0
      -go get github.com/blang/expenv
      -
      -
      -
      -
      -

      If you are a Crunchy enterprise customer, you will place the Crunchy repository -key and yum repository file into the $CCPROOT/conf directory at this point. These -files can be obtained through https://access.crunchydata.com/ on the downloads -page.

      -
      -
      - -
      -
      -
      -

      PostgreSQL

      -
      -

      These installation instructions assume the installation of PostgreSQL 10 -through the official PGDG repository. View the documentation located -here in -order to view more detailed notes or install a different version of PostgreSQL.

      -
      -
      -

      Locate and edit your distribution’s .repo file, located:

      -
      -
      -
        -
      • -

        On CentOS: /etc/yum.repos.d/CentOS-Base.repo, [base] and [updates] sections

        -
      • -
      • -

        On Red Hat: /etc/yum/pluginconf.d/rhnplugin.conf [main] section

        -
      • -
      -
      -
      -

      To the section(s) identified above, you need to append a line (otherwise -dependencies might resolve to the PostgreSQL supplied by the base repository):

      -
      -
      -
      -
      exclude=postgresql*
      -
      -
      -
      -

      Next, install the RPM relating to the base operating system and PostgreSQL version -you wish to install. The RPMs can be found here.

      -
      -
      -

      For example, to install PostgreSQL 10 on a CentOS 7 system:

      -
      -
      -
      -
      sudo yum -y install https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm
      -
      -
      -
      -

      Or to install PostgreSQL 10 on a RHEL 7 system:

      -
      -
      -
      -
      sudo yum -y install https://download.postgresql.org/pub/repos/yum/testing/10/redhat/rhel-7-x86_64/pgdg-redhat10-10-2.noarch.rpm
      -
      -
      -
      -

      You’ll need to update your system:

      -
      -
      -
      -
      sudo yum -y update
      -
      -
      -
      -

      Then, go ahead and install the PostgreSQL server package.

      -
      -
      -
      -
      sudo yum -y install postgresql10-server.x86_64
      -
      -
      -
      -
      -

      Docker

      -
      -

      As good practice, at this point you’ll update your system.

      -
      -
      -
      -
      sudo yum -y update
      -
      -
      -
      -

      Now we’ll install Docker.

      -
      -
      -
      -
      sudo yum -y install docker
      -
      -
      -
      -

      After that, it’s necessary to add the docker group and give your user access -to that group (here referenced as someuser):

      -
      -
      -
      -
      sudo groupadd docker
      -sudo usermod -a -G docker someuser
      -
      -
      -
      -

      Remember to log out of the someuser account for the Docker group -to be added to your current session. Once it’s added, you’ll be able -to run Docker commands from your user account.

      -
      -
      -
      -
      su - someuser
      -
      -
      -
      -

      You can ensure your someuser account is added correctly by running the following -command and ensuring docker appears as one of the results:

      -
      -
      -
      -
      groups
      -
      -
      -
      -

      Before you start Docker, you might consider configuring Docker storage: -This is described if you run:

      -
      -
      -
      -
      man docker-storage-setup
      -
      -
      -
      -

      Follow the instructions available on the main OpenShift documentation page -to configure Docker storage appropriately.

      -
      -
      -

      These steps are illustrative of a typical process for setting up Docker storage. You will need to run these commands as root.

      -
      -
      -

      First, add an extra virtual hard disk to your virtual machine (see this blog post for tips on how to do so).

      -
      -
      -

      Run this command to format the drive, where /dev/sd? is the new hard drive that was added:

      -
      -
      -
      -
      fdisk /dev/sd?
      -
      -
      -
      -

      Next, create a volume group on the new drive partition within the fdisk utility:

      -
      -
      -
      -
      vgcreate docker-vg /dev/sd?
      -
      -
      -
      -

      Then, you’ll need to edit the docker-storage-setup configuration file in order to override default options. Add these two lines to /etc/sysconfig/docker-storage-setup:

      -
      -
      -
      -
      DEVS=/dev/sd?
      -VG=docker-vg
      -
      -
      -
      -

      Finally, run the command docker-storage-setup to use that new volume group. The results should state that the physical volume /dev/sd? and the volume group docker-vg have both been successfully created.

      -
      -
      -

      Next, we enable and start up Docker:

      -
      -
      -
      -
      sudo systemctl enable docker.service
      -sudo systemctl start docker.service
      -
      -
      -
      -

      Verify that Docker version 1.12.6 was installed, as per the OpenShift 3.6 -requirements.

      -
      -
      -
      -
      docker version
      -
      -
      -
      -
      -

      OpenShift

      -
      -

      See the OpenShift installation guide for details on how to install -OpenShift Enterprise on your host. The main instructions are here:

      -
      - -
      - - - - - -
      -
      Note
      -
      -If you install OpenShift Enterprise on a server with less than 16GB memory and 40GB -of disk, the following Ansible variables need to be added to ~/.config/openshift/installer.cfg.yml -prior to installation: -
      -
      -
      -
      -
      openshift_check_min_host_disk_gb: '10' # min 10gb disk
      -openshift_check_min_host_memory_gb: '3' # min 3gb memory
      -
      -
      -
      -
      -

      Kubernetes

      -
      -

      See kubeadm -for installing the latest version of Kubernetes.

      -
      -
      -

      Please see here -to view the official documentation regarding configuring DNS for your Kubernetes cluster.

      -
      -
      -

      Make sure your hostname resolves to a single IP address in your -/etc/hosts file. The NFS examples will not work otherwise and other problems -with installation can occur unless you have a resolving hostname.

      -
      -
      -

      You should see a single IP address returned from this command:

      -
      -
      -
      -
      hostname --ip-address
      -
      -
      -
      -

      When running the containers in GKE Role Based Account Control will need to be set up.

      -
      -
      -
      -
      kubectl create clusterrolebinding cluster-admin-binding \
      ---clusterrole cluster-admin --user $(gcloud config get-value account)
      -
      -
      -
      -

      If more than one user will be running on the same kubernetes cluster in GKE, from the above command cluster-admin-binding will need to be unique and is the name that is added to the clusterrolebidings. The example below will add another user to the clusterrolebinding with a unique value.

      -
      -
      -
      -
      $ ACCOUNT=$(gcloud info --format='value(config.account)')
      -$ kubectl create clusterrolebinding <unique>-cluster-admin-binding \
      -    --clusterrole cluster-admin \
      -    --user $ACCOUNT
      -
      -ACCOUNT is just your google gcloud acount login, ie username@google.com
      -
      -
      -
      -
      -

      Helm

      -
      -

      Some Kubernetes Helm examples are provided in the following directory as one -option for deploying the Container Suite.

      -
      -
      -
      -
      $CCPROOT/examples/helm/
      -
      -
      -
      -

      Once you have your Kubernetes environment configured, it is simple to get -Helm up and running. Please refer to this document -to get Helm installed and configured properly.

      -
      -
      -
      -
      -
      -

      Creating a Demo Namespace

      -
      -
      -

      In Kubernetes, a concept called a namespace provides the means to separate -created resources or components into individual logically grouped partitions.

      -
      -
      -

      It is considered a best practice to have dedicated namespaces for projects in -both testing and production environments.

      -
      -
      - - - - - -
      -
      Note
      -
      -All examples in the Crunchy Container Suite operate within the namespace -defined by the environment variable $CCP_NAMESPACE. The instructions below -illustrate how to set up and work within new namespaces or projects in both -Kubernetes and OpenShift. -
      -
      -
      -

      Kubernetes

      -
      -

      This section will illustrate how to set up a new Kubernetes namespace called demo, and will -then show how to provide permissions to that namespace to allow the Kubernetes examples to run -within that namespace.

      -
      -
      -

      First, view currently existing namespaces:

      -
      -
      -
      -
      $ kubectl get namespace
      -NAME          STATUS    AGE
      -default       Active    21d
      -kube-public   Active    21d
      -kube-system   Active    21d
      -
      -
      -
      -

      Then, create a new namespace called demo:

      -
      -
      -
      -
      $ kubectl create -f $CCPROOT/conf/demo-namespace.json
      -namespace "demo" created
      -$ kubectl get namespace demo
      -NAME      STATUS    AGE
      -demo      Active    7s
      -
      -
      -
      -

      Then set the namespace as the current location to avoid using the wrong namespace:

      -
      -
      -
      -
      $ kubectl config set-context $(kubectl config current-context) --namespace=demo
      -
      -
      -
      -

      We can verify that the namespace was set correctly through the following command:

      -
      -
      -
      -
      $ kubectl config view | grep namespace:
      -    namespace: demo
      -
      -
      -
      -
      -

      OpenShift

      -
      -

      This section assumes you are first logging into OpenShift as a normal -user such as:

      -
      -
      -
      -
      oc login -u someuser
      -
      -
      -
      -

      For our development purposes only, we typically specify the OCP -Authorization policy of AllowAll as documented here:

      -
      - -
      -

      We do not recommend this authentication policy for a production -deployment of OCP.

      -
      -
      -

      The next step is to create a demo namespace to run the examples within. The -name of this OCP project will be what you supply in the CCP_NAMESPACE -environment variable:

      -
      -
      -
      -
      $ oc new-project demo --description="Crunchy Containers project" --display-name="Crunchy-Containers"
      -Now using project "demo" on server "https://127.0.0.1:8443".
      -
      -$ export CCP_NAMESPACE=demo
      -
      -
      -
      -

      If we view the list of projects, we can see the new project has been added and is "active".

      -
      -
      -
      -
      $ oc get projects
      -NAME        DISPLAY NAME         STATUS
      -demo        Crunchy-Containers   Active
      -myproject   My Project           Active
      -
      -
      -
      -

      If you were on a different project and wanted to switch to the demo project, you would do -so by running the following:

      -
      -
      -
      -
      $ oc project demo
      -Now using project "demo" on server "https://127.0.0.1:8443".
      -
      -
      -
      -

      Finally, you will want to ensure the proper privileges are added to the user in order to -have the ability to create persistent volumes. A command similar to the following can be -used to accomplish this, by adding the cluster-admin role to the demo user:

      -
      -
      -
      -
      oc adm policy add-cluster-role-to-user cluster-admin demo
      -
      -
      -
      -
      -
      -
      -

      Next Steps

      -
      -
      -

      Next, build or pull the container images as demonstrated in the Build the Containers document.

      -
      -
      -
      - - - - -
      - -
      -
      -
      - - - -
      -
      -
      -
      - - - - - - - - - - - - - - - - - - diff --git a/docs/installation/index.html b/docs/installation/index.html deleted file mode 100644 index e1135f90c..000000000 --- a/docs/installation/index.html +++ /dev/null @@ -1,461 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Installation :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
      - - - - -
      -
      -
      - -
      - - - - - - - -
      -
      - -
      -
      - - -
      - - -
      - -

      Installation

      - - - - - - - - -
      -

      Latest Release: 2.1.0 2018-08-13

      -
      -
      -

      Installation

      -
      -
      -

      To set up the environment, visit the Environment Setup document. -From there, navigate to Build the Containers page to either -build or pull the container images necessary to run examples. The final step will be to configure storage -in the Storage Configuration page, with either HostPath, NFS, -or dynamic storage options.

      -
      -
      -
      -
      -

      Next Steps

      -
      -
      -

      There are many ways to configure the examples and containers further. Descriptions of each container -offered and the variables that can be used to customize them are found on the -Container Specifications page.

      -
      -
      -

      Information can be found on the full scope of examples that can be performed on the -Getting Started page.

      -
      -
      -
      - - - - - -
      - -
      -
      -
      - - - -
      -
      -
      -
      - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/installation/index.xml b/docs/installation/index.xml deleted file mode 100644 index 5ce157bb0..000000000 --- a/docs/installation/index.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - Installation on Crunchy Data Container Suite Documentation - https://crunchydata.github.io/crunchy-containers/installation/ - Recent content in Installation on Crunchy Data Container Suite Documentation - Hugo -- gohugo.io - en-us - Tue, 08 May 2018 08:55:54 -0700 - - - - - - Environment Setup - https://crunchydata.github.io/crunchy-containers/installation/environment-setup/ - Tue, 08 May 2018 08:52:09 -0700 - - https://crunchydata.github.io/crunchy-containers/installation/environment-setup/ - Table of Contents Requirements Project Environment Installing Requirements CentOS 7 RHEL 7 PostgreSQL Docker OpenShift Kubernetes Helm Creating a Demo Namespace Kubernetes OpenShift Next Steps Latest Release: 2.1.0 2018-08-13 - Requirements The Crunchy Container Suite can run on different environments including: - Docker 1.12+ - OpenShift Container Platform 3.6+ - Kubernetes 1.8+ - In this document we list the basic installation steps required for these environments. - - - - Build the Containers - https://crunchydata.github.io/crunchy-containers/installation/build-the-containers/ - Tue, 08 May 2018 08:52:16 -0700 - - https://crunchydata.github.io/crunchy-containers/installation/build-the-containers/ - Table of Contents Build the Containers Next Steps Latest Release: 2.1.0 2018-08-13 - Build the Containers At this point, you have a decision to make - either download prebuilt containers from Dockerhub, or build the containers on your local host. - To download the prebuilt containers, make sure you can login to Dockerhub, and then run the following: - docker login cd $CCPROOT ./bin/pull-from-dockerhub.sh Or if you&#8217;d rather build the containers from source, perform a container build as follows: - - - - Storage Configuration - https://crunchydata.github.io/crunchy-containers/installation/storage-configuration/ - Tue, 08 May 2018 08:52:46 -0700 - - https://crunchydata.github.io/crunchy-containers/installation/storage-configuration/ - Table of Contents Available Storage Types HostPath NFS Dynamic Storage Next Steps Latest Release: 2.1.0 2018-08-13 - Available Storage Types The Container Suite is tested on 3 different storage backends: - hostPath (single node testing) - NFS (single and multi-node testing) - Gluster (dynamic storage on separate Gluster cluster) - Other storage backends work as well including GCE, EBS, ScaleIO, and others, but may require you to modify various examples or configuration. - - - - \ No newline at end of file diff --git a/docs/installation/storage-configuration/index.html b/docs/installation/storage-configuration/index.html deleted file mode 100644 index 7c2b25208..000000000 --- a/docs/installation/storage-configuration/index.html +++ /dev/null @@ -1,649 +0,0 @@ - - - - Crunchy Data Container Suite Documentation - - - - - -Storage Configuration :: Crunchy Data Container Suite Documentation - - - - - - - - - - - - - - - - - - -
      - - - - -
      -
      -
      - -
      - - - - - - - -
      -
      - -
      -
      - - -
      - - -
      - -

      Storage Configuration

      - - - - - - - - -
      -

      Latest Release: 2.1.0 2018-08-13

      -
      -
      -

      Available Storage Types

      -
      -
      -

      The Container Suite is tested on 3 different storage backends:

      -
      -
      -
        -
      • -

        hostPath (single node testing)

        -
      • -
      • -

        NFS (single and multi-node testing)

        -
      • -
      • -

        Gluster (dynamic storage on separate Gluster cluster)

        -
      • -
      -
      -
      -

      Other storage backends work as well including GCE, EBS, ScaleIO, and -others, but may require you to modify various examples or configuration.

      -
      -
      -

      Environment variables are set to determine how and what storage -is to be used.

      -
      -
      -
      -
      -

      HostPath

      -
      -
      -

      HostPath is the simplest storage backend to setup. It is only feasible -on a single node but is sufficient for testing the examples. In your .bashrc -file, add the following variables to specify unique settings to -the HostPath directory:

      -
      -
      -
      -
      export CCP_SECURITY_CONTEXT=""
      -export CCP_STORAGE_PATH=/data
      -export CCP_STORAGE_MODE=ReadWriteMany
      -export CCP_STORAGE_CAPACITY=400M
      -
      -
      -
      - - - - - -
      -
      Note
      -
      -It may be necessary to grant your user in OpenShift or Kubernetes the -rights to modify the hostaccess SCC. This can be done with the command: oadm policy add-scc-to-user hostaccess $(oc whoami) -
      -
      -
      -
      -
      -

      NFS

      -
      -
      -

      NFS can also be used as a storage mechanism. Instructions -on setting up NFS are found at the bottom of this guide.

      -
      -
      -

      For testing with NFS, in your .bashrc file, include -the following variables that are unique to your NFS environment:

      -
      -
      -
      -
      export CCP_SECURITY_CONTEXT='"supplementalGroups": [65534]'
      -export CCP_STORAGE_PATH=/mnt/nfsfileshare
      -export CCP_NFS_IP=192.168.0.118
      -export CCP_STORAGE_MODE=ReadWriteMany
      -export CCP_STORAGE_CAPACITY=400M
      -
      -
      -
      -

      In this example above the group ownership of the NFS mount is assumed to be -nfsnobody or 65534.

      -
      -
      -
      -
      - - - - - Configuration Notes for NFS - - -
      - -
      -
      -
      -
      -
      -

      Dynamic Storage

      -
      -
      -

      Dynamic storage classes can be used for the examples. Gluster -is only one example of a storage type that supports dynamic storage -classes. The environment variable CCP_STORAGE_CLASS is used -in the examples to determine whether or not to create a PersistentVolume -manually or that it will be created dynamically using a StorageClass. In -the case of GKE, the default StorageClass is named default. Storage -class names are determined by the Kubernetes administrator and can vary.

      -
      -
      -

      Setting up a Gluster cluster will offer you the ability to use -dynamic storage provisioning in the examples. A set of example -Gluster configuration files is found at $CCPROOT/examples/gluster. -This configuration is for a 3 node Gluster cluster which runs -on a Centos7 Minimal VM deployment.

      -
      -
      -

      Using block storage requires a security context to be set -as follows:

      -
      -
      -
      -
      export CCP_SECURITY_CONTEXT='"fsGroup":26'
      -export CCP_STORAGE_CLASS=standard
      -export CCP_STORAGE_MODE=ReadWriteOnce
      -export CCP_STORAGE_CAPACITY=400M
      -
      -
      -
      -
      -
      -

      Next Steps

      -
      -
      -

      There are many ways to configure the examples and containers further. Descriptions of each container -offered and the variables that can be used to customize them are found on the -Container Specifications page.

      -
      -
      -

      Information can be found on the full scope of examples that can be performed on the -Getting Started page.

      -
      -
      -
      - - - - -
      - -
      -
      -
      - - - -
      -
      -
      -
      - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/js/auto-complete.js b/docs/js/auto-complete.js deleted file mode 100644 index 7fbde995e..000000000 --- a/docs/js/auto-complete.js +++ /dev/null @@ -1,223 +0,0 @@ -/* - JavaScript autoComplete v1.0.4 - Copyright (c) 2014 Simon Steinberger / Pixabay - GitHub: https://github.com/Pixabay/JavaScript-autoComplete - License: http://www.opensource.org/licenses/mit-license.php -*/ - -var autoComplete = (function(){ - // "use strict"; - function autoComplete(options){ - if (!document.querySelector) return; - - // helpers - function hasClass(el, className){ return el.classList ? el.classList.contains(className) : new RegExp('\\b'+ className+'\\b').test(el.className); } - - function addEvent(el, type, handler){ - if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler); - } - function removeEvent(el, type, handler){ - // if (el.removeEventListener) not working in IE11 - if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler); - } - function live(elClass, event, cb, context){ - addEvent(context || document, event, function(e){ - var found, el = e.target || e.srcElement; - while (el && !(found = hasClass(el, elClass))) el = el.parentElement; - if (found) cb.call(el, e); - }); - } - - var o = { - selector: 0, - source: 0, - minChars: 3, - delay: 150, - offsetLeft: 0, - offsetTop: 1, - cache: 1, - menuClass: '', - renderItem: function (item, search){ - // escape special characters - search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi"); - return '
      ' + item.replace(re, "$1") + '
      '; - }, - onSelect: function(e, term, item){} - }; - for (var k in options) { if (options.hasOwnProperty(k)) o[k] = options[k]; } - - // init - var elems = typeof o.selector == 'object' ? [o.selector] : document.querySelectorAll(o.selector); - for (var i=0; i 0) - that.sc.scrollTop = selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight; - else if (selTop < 0) - that.sc.scrollTop = selTop + scrTop; - } - } - } - addEvent(window, 'resize', that.updateSC); - document.body.appendChild(that.sc); - - live('autocomplete-suggestion', 'mouseleave', function(e){ - var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); - if (sel) setTimeout(function(){ sel.className = sel.className.replace('selected', ''); }, 20); - }, that.sc); - - live('autocomplete-suggestion', 'mouseover', function(e){ - var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); - if (sel) sel.className = sel.className.replace('selected', ''); - this.className += ' selected'; - }, that.sc); - - live('autocomplete-suggestion', 'mousedown', function(e){ - if (hasClass(this, 'autocomplete-suggestion')) { // else outside click - var v = this.getAttribute('data-val'); - that.value = v; - o.onSelect(e, v, this); - that.sc.style.display = 'none'; - } - }, that.sc); - - that.blurHandler = function(){ - try { var over_sb = document.querySelector('.autocomplete-suggestions:hover'); } catch(e){ var over_sb = 0; } - if (!over_sb) { - that.last_val = that.value; - that.sc.style.display = 'none'; - setTimeout(function(){ that.sc.style.display = 'none'; }, 350); // hide suggestions on fast input - } else if (that !== document.activeElement) setTimeout(function(){ that.focus(); }, 20); - }; - addEvent(that, 'blur', that.blurHandler); - - var suggest = function(data){ - var val = that.value; - that.cache[val] = data; - if (data.length && val.length >= o.minChars) { - var s = ''; - for (var i=0;i 40) && key != 13 && key != 27) { - var val = that.value; - if (val.length >= o.minChars) { - if (val != that.last_val) { - that.last_val = val; - clearTimeout(that.timer); - if (o.cache) { - if (val in that.cache) { suggest(that.cache[val]); return; } - // no requests if previous suggestions were empty - for (var i=1; ir;r++)n[r].fn.apply(n[r].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),r=n[t],o=[];if(r&&e)for(var i=0,a=r.length;a>i;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return o.length?n[t]=o:delete n[t],this}},e.exports=r},{}],8:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}n.__esModule=!0;var i=function(){function t(t,e){for(var n=0;n"; - } - }); - - // Change styles, depending on parameters set to the image - images.each(function (index) { - var image = $(this); - var o = getUrlParameter(image[0].src); - if (typeof o !== "undefined") { - var h = o["height"]; - var w = o["width"]; - var c = o["classes"]; - image.css({ - width: function () { - if (typeof w !== "undefined") { - return w; - } - }, - height: function () { - if (typeof h !== "undefined") { - return h; - } - } - }); - if (typeof c !== "undefined") { - var classes = c.split(','); - $.each(classes, function(i) { - image.addClass(classes[i]); - }); - } - } - }); - - // Add link button for every - var text, clip = new Clipboard('.anchor'); - $("h1~h2,h1~h3,h1~h4,h1~h5,h1~h6").append(function (index, html) { - var element = $(this); - var url = document.location.origin + document.location.pathname; - var link = url + "#" + element[0].id; - return " " + - "" + - ""; - }); - - $(".anchor").on('mouseleave', function (e) { - $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w'); - }); - - clip.on('success', function (e) { - e.clearSelection(); - $(e.trigger).attr('aria-label', 'Link copied to clipboard!').addClass('tooltipped tooltipped-s'); - }); - -}); - - - -function fallbackMessage(action) { - var actionMsg = ''; - var actionKey = (action === 'cut' ? 'X' : 'C'); - - if (/iPhone|iPad/i.test(navigator.userAgent)) { - actionMsg = 'No support :('; - } - else if (/Mac/i.test(navigator.userAgent)) { - actionMsg = 'Press ⌘-' + actionKey + ' to ' + action; - } - else { - actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action; - } - - return actionMsg; -} - -jQuery(document).ready(function() { - jQuery('#sidebar .category-icon').on('click', function() { - $( this ).toggleClass("fa-angle-down fa-angle-right") ; - $( this ).parent().parent().children('ul').toggle() ; - return false; - }); - - - jQuery('[data-clear-history-toggle]').on('click', function() { - sessionStorage.clear(); - location.reload(); - return false; - }); - - var ajax; - jQuery('[data-search-input]').on('input', function() { - var input = jQuery(this), - value = input.val(), - items = jQuery('[data-nav-id]'); - items.removeClass('search-match'); - if (!value.length) { - $('ul.topics').removeClass('searched'); - items.css('display', 'block'); - sessionStorage.removeItem('search-value'); - $(".highlightable").unhighlight({ element: 'mark' }) - return; - } - - sessionStorage.setItem('search-value', value); - $(".highlightable").unhighlight({ element: 'mark' }).highlight(value, { element: 'mark' }); - - if (ajax && ajax.abort) ajax.abort(); - - jQuery('[data-search-clear]').on('click', function() { - jQuery('[data-search-input]').val('').trigger('input'); - sessionStorage.removeItem('search-input'); - $(".highlightable").unhighlight({ element: 'mark' }) - }); - }); - - $.expr[":"].contains = $.expr.createPseudo(function(arg) { - return function( elem ) { - return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0; - }; - }); - - if (sessionStorage.getItem('search-value')) { - var searchValue = sessionStorage.getItem('search-value') - sessionStorage.removeItem('search-value'); - var searchedElem = $('article').find(':contains(' + searchValue + ')').get(0); - searchedElem && searchedElem.scrollIntoView(); - $(".highlightable").highlight(searchValue, { element: 'mark' }); - } - - // clipboard - var clipInit = false; - $('code').each(function() { - var code = $(this), - text = code.text(); - - if (text.length > 5) { - if (!clipInit) { - var text, clip = new Clipboard('.copy-to-clipboard', { - text: function(trigger) { - text = $(trigger).prev('code').text(); - return text.replace(/^\$\s/gm, ''); - } - }); - - var inPre; - clip.on('success', function(e) { - e.clearSelection(); - inPre = $(e.trigger).parent().prop('tagName') == 'PRE'; - $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's')); - }); - - clip.on('error', function(e) { - inPre = $(e.trigger).parent().prop('tagName') == 'PRE'; - $(e.trigger).attr('aria-label', fallbackMessage(e.action)).addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's')); - $(document).one('copy', function(){ - $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's')); - }); - }); - - clipInit = true; - } - - code.next('.copy-to-clipboard').on('mouseleave', function() { - $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w'); - }); - } - }); - - // allow keyboard control for prev/next links - jQuery(function() { - jQuery('.nav-prev').click(function(){ - location.href = jQuery(this).attr('href'); - }); - jQuery('.nav-next').click(function() { - location.href = jQuery(this).attr('href'); - }); - }); - - jQuery(document).keydown(function(e) { - // prev links - left arrow key - if(e.which == '37') { - jQuery('.nav.nav-prev').click(); - } - - // next links - right arrow key - if(e.which == '39') { - jQuery('.nav.nav-next').click(); - } - }); - - $('#top-bar a:not(:has(img)):not(.btn)').addClass('highlight'); - $('article a:not(:has(img)):not(.btn)').addClass('highlight'); -}); - -jQuery(window).on('load', function() { - // store this page in session - sessionStorage.setItem(jQuery('body').data('url'), 1); - - // loop through the sessionStorage and see if something should be marked as visited - for (var url in sessionStorage) { - if (sessionStorage.getItem(url) == 1) jQuery('[data-nav-id="' + url + '"]').addClass('visited'); - } -}); - -$(function() { - $('a[rel="lightbox"]').featherlight({ - root: 'section#body' - }); -}); - -jQuery.extend({ - highlight: function(node, re, nodeName, className) { - if (node.nodeType === 3) { - var match = node.data.match(re); - if (match && !(node.parentNode.ownerSVGElement instanceof SVGElement)) { - var highlight = document.createElement(nodeName || 'span'); - highlight.className = className || 'highlight'; - var wordNode = node.splitText(match.index); - wordNode.splitText(match[0].length); - var wordClone = wordNode.cloneNode(true); - highlight.appendChild(wordClone); - wordNode.parentNode.replaceChild(highlight, wordNode); - return 1; //skip added node in parent - } - } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children - !/(script|style)/i.test(node.tagName) && // ignore script and style nodes - !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted - for (var i = 0; i < node.childNodes.length; i++) { - i += jQuery.highlight(node.childNodes[i], re, nodeName, className); - } - } - return 0; - } -}); - -jQuery.fn.unhighlight = function(options) { - var settings = { - className: 'highlight', - element: 'span' - }; - jQuery.extend(settings, options); - - return this.find(settings.element + "." + settings.className).each(function() { - var parent = this.parentNode; - parent.replaceChild(this.firstChild, this); - parent.normalize(); - }).end(); -}; - -jQuery.fn.highlight = function(words, options) { - var settings = { - className: 'highlight', - element: 'span', - caseSensitive: false, - wordsOnly: false - }; - jQuery.extend(settings, options); - - if (!words) { return; } - - if (words.constructor === String) { - words = [words]; - } - words = jQuery.grep(words, function(word, i) { - return word != ''; - }); - words = jQuery.map(words, function(word, i) { - return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); - }); - if (words.length == 0) { return this; } - ; - - var flag = settings.caseSensitive ? "" : "i"; - var pattern = "(" + words.join("|") + ")"; - if (settings.wordsOnly) { - pattern = "\\b" + pattern + "\\b"; - } - var re = new RegExp(pattern, flag); - - return this.each(function() { - jQuery.highlight(this, re, settings.element, settings.className); - }); -}; diff --git a/docs/js/featherlight.min.js b/docs/js/featherlight.min.js deleted file mode 100644 index 635908195..000000000 --- a/docs/js/featherlight.min.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Featherlight - ultra slim jQuery lightbox - * Version 1.2.3 - http://noelboss.github.io/featherlight/ - * - * Copyright 2015, Noël Raoul Bossart (http://www.noelboss.com) - * MIT Licensed. -**/ -!function(a){"use strict";function b(a,c){if(!(this instanceof b)){var d=new b(a,c);return d.open(),d}this.id=b.id++,this.setup(a,c),this.chainCallbacks(b._callbackChain)}if("undefined"==typeof a)return void("console"in window&&window.console.info("Too much lightness, Featherlight needs jQuery."));var c=[],d=function(b){return c=a.grep(c,function(a){return a!==b&&a.$instance.closest("body").length>0})},e=function(a,b){var c={},d=new RegExp("^"+b+"([A-Z])(.*)");for(var e in a){var f=e.match(d);if(f){var g=(f[1]+f[2].replace(/([A-Z])/g,"-$1")).toLowerCase();c[g]=a[e]}}return c},f={keyup:"onKeyUp",resize:"onResize"},g=function(c){a.each(b.opened().reverse(),function(){return c.isDefaultPrevented()||!1!==this[f[c.type]](c)?void 0:(c.preventDefault(),c.stopPropagation(),!1)})},h=function(c){if(c!==b._globalHandlerInstalled){b._globalHandlerInstalled=c;var d=a.map(f,function(a,c){return c+"."+b.prototype.namespace}).join(" ");a(window)[c?"on":"off"](d,g)}};b.prototype={constructor:b,namespace:"featherlight",targetAttr:"data-featherlight",variant:null,resetCss:!1,background:null,openTrigger:"click",closeTrigger:"click",filter:null,root:"body",openSpeed:250,closeSpeed:250,closeOnClick:"background",closeOnEsc:!0,closeIcon:"✕",loading:"",otherClose:null,beforeOpen:a.noop,beforeContent:a.noop,beforeClose:a.noop,afterOpen:a.noop,afterContent:a.noop,afterClose:a.noop,onKeyUp:a.noop,onResize:a.noop,type:null,contentFilters:["jquery","image","html","ajax","iframe","text"],setup:function(b,c){"object"!=typeof b||b instanceof a!=!1||c||(c=b,b=void 0);var d=a.extend(this,c,{target:b}),e=d.resetCss?d.namespace+"-reset":d.namespace,f=a(d.background||['
      ','
      ','',d.closeIcon,"",'
      '+d.loading+"
      ","
      ","
      "].join("")),g="."+d.namespace+"-close"+(d.otherClose?","+d.otherClose:"");return d.$instance=f.clone().addClass(d.variant),d.$instance.on(d.closeTrigger+"."+d.namespace,function(b){var c=a(b.target);("background"===d.closeOnClick&&c.is("."+d.namespace)||"anywhere"===d.closeOnClick||c.closest(g).length)&&(b.preventDefault(),d.close())}),this},getContent:function(){var b=this,c=this.constructor.contentFilters,d=function(a){return b.$currentTarget&&b.$currentTarget.attr(a)},e=d(b.targetAttr),f=b.target||e||"",g=c[b.type];if(!g&&f in c&&(g=c[f],f=b.target&&e),f=f||d("href")||"",!g)for(var h in c)b[h]&&(g=c[h],f=b[h]);if(!g){var i=f;if(f=null,a.each(b.contentFilters,function(){return g=c[this],g.test&&(f=g.test(i)),!f&&g.regex&&i.match&&i.match(g.regex)&&(f=i),!f}),!f)return"console"in window&&window.console.error("Featherlight: no content filter found "+(i?' for "'+i+'"':" (no target specified)")),!1}return g.process.call(b,f)},setContent:function(b){var c=this;return(b.is("iframe")||a("iframe",b).length>0)&&c.$instance.addClass(c.namespace+"-iframe"),c.$instance.removeClass(c.namespace+"-loading"),c.$instance.find("."+c.namespace+"-inner").slice(1).remove().end().replaceWith(a.contains(c.$instance[0],b[0])?"":b),c.$content=b.addClass(c.namespace+"-inner"),c},open:function(b){var d=this;if(d.$instance.hide().appendTo(d.root),!(b&&b.isDefaultPrevented()||d.beforeOpen(b)===!1)){b&&b.preventDefault();var e=d.getContent();if(e)return c.push(d),h(!0),d.$instance.fadeIn(d.openSpeed),d.beforeContent(b),a.when(e).always(function(a){d.setContent(a),d.afterContent(b)}).then(d.$instance.promise()).done(function(){d.afterOpen(b)})}return d.$instance.detach(),a.Deferred().reject().promise()},close:function(b){var c=this,e=a.Deferred();return c.beforeClose(b)===!1?e.reject():(0===d(c).length&&h(!1),c.$instance.fadeOut(c.closeSpeed,function(){c.$instance.detach(),c.afterClose(b),e.resolve()})),e.promise()},chainCallbacks:function(b){for(var c in b)this[c]=a.proxy(b[c],this,a.proxy(this[c],this))}},a.extend(b,{id:0,autoBind:"[data-featherlight]",defaults:b.prototype,contentFilters:{jquery:{regex:/^[#.]\w/,test:function(b){return b instanceof a&&b},process:function(b){return a(b).clone(!0)}},image:{regex:/\.(png|jpg|jpeg|gif|tiff|bmp)(\?\S*)?$/i,process:function(b){var c=this,d=a.Deferred(),e=new Image,f=a('');return e.onload=function(){f.naturalWidth=e.width,f.naturalHeight=e.height,d.resolve(f)},e.onerror=function(){d.reject(f)},e.src=b,d.promise()}},html:{regex:/^\s*<[\w!][^<]*>/,process:function(b){return a(b)}},ajax:{regex:/./,process:function(b){var c=a.Deferred(),d=a("
      ").load(b,function(a,b){"error"!==b&&c.resolve(d.contents()),c.fail()});return c.promise()}},iframe:{process:function(b){var c=new a.Deferred,d=a(" - - -``` - - -### API - -The ``Reveal`` object exposes a JavaScript API for controlling navigation and reading state: - -```javascript -// Navigation -Reveal.slide( indexh, indexv, indexf ); -Reveal.left(); -Reveal.right(); -Reveal.up(); -Reveal.down(); -Reveal.prev(); -Reveal.next(); -Reveal.prevFragment(); -Reveal.nextFragment(); - -// Randomize the order of slides -Reveal.shuffle(); - -// Toggle presentation states, optionally pass true/false to force on/off -Reveal.toggleOverview(); -Reveal.togglePause(); -Reveal.toggleAutoSlide(); - -// Shows a help overlay with keyboard shortcuts, optionally pass true/false -// to force on/off -Reveal.toggleHelp(); - -// Change a config value at runtime -Reveal.configure({ controls: true }); - -// Returns the present configuration options -Reveal.getConfig(); - -// Fetch the current scale of the presentation -Reveal.getScale(); - -// Retrieves the previous and current slide elements -Reveal.getPreviousSlide(); -Reveal.getCurrentSlide(); - -Reveal.getIndices(); // { h: 0, v: 0 } } -Reveal.getPastSlideCount(); -Reveal.getProgress(); // (0 == first slide, 1 == last slide) -Reveal.getSlides(); // Array of all slides -Reveal.getTotalSlides(); // total number of slides - -// Returns the speaker notes for the current slide -Reveal.getSlideNotes(); - -// State checks -Reveal.isFirstSlide(); -Reveal.isLastSlide(); -Reveal.isOverview(); -Reveal.isPaused(); -Reveal.isAutoSliding(); -``` - -### Slide Changed Event - -A 'slidechanged' event is fired each time the slide is changed (regardless of state). The event object holds the index values of the current slide as well as a reference to the previous and current slide HTML nodes. - -Some libraries, like MathJax (see [#226](https://github.com/hakimel/reveal.js/issues/226#issuecomment-10261609)), get confused by the transforms and display states of slides. Often times, this can be fixed by calling their update or render function from this callback. - -```javascript -Reveal.addEventListener( 'slidechanged', function( event ) { - // event.previousSlide, event.currentSlide, event.indexh, event.indexv -} ); -``` - -### Presentation State - -The presentation's current state can be fetched by using the `getState` method. A state object contains all of the information required to put the presentation back as it was when `getState` was first called. Sort of like a snapshot. It's a simple object that can easily be stringified and persisted or sent over the wire. - -```javascript -Reveal.slide( 1 ); -// we're on slide 1 - -var state = Reveal.getState(); - -Reveal.slide( 3 ); -// we're on slide 3 - -Reveal.setState( state ); -// we're back on slide 1 -``` - -### Slide States - -If you set ``data-state="somestate"`` on a slide ``
      ``, "somestate" will be applied as a class on the document element when that slide is opened. This allows you to apply broad style changes to the page based on the active slide. - -Furthermore you can also listen to these changes in state via JavaScript: - -```javascript -Reveal.addEventListener( 'somestate', function() { - // TODO: Sprinkle magic -}, false ); -``` - -### Slide Backgrounds - -Slides are contained within a limited portion of the screen by default to allow them to fit any display and scale uniformly. You can apply full page backgrounds outside of the slide area by adding a ```data-background``` attribute to your ```
      ``` elements. Four different types of backgrounds are supported: color, image, video and iframe. - -#### Color Backgrounds -All CSS color formats are supported, like rgba() or hsl(). -```html -
      -

      Color

      -
      -``` - -#### Image Backgrounds -By default, background images are resized to cover the full page. Available options: - -| Attribute | Default | Description | -| :--------------------------- | :--------- | :---------- | -| data-background-image | | URL of the image to show. GIFs restart when the slide opens. | -| data-background-size | cover | See [background-size](https://developer.mozilla.org/docs/Web/CSS/background-size) on MDN. | -| data-background-position | center | See [background-position](https://developer.mozilla.org/docs/Web/CSS/background-position) on MDN. | -| data-background-repeat | no-repeat | See [background-repeat](https://developer.mozilla.org/docs/Web/CSS/background-repeat) on MDN. | -```html -
      -

      Image

      -
      -
      -

      This background image will be sized to 100px and repeated

      -
      -``` - -#### Video Backgrounds -Automatically plays a full size video behind the slide. - -| Attribute | Default | Description | -| :--------------------------- | :------ | :---------- | -| data-background-video | | A single video source, or a comma separated list of video sources. | -| data-background-video-loop | false | Flags if the video should play repeatedly. | -| data-background-video-muted | false | Flags if the audio should be muted. | -| data-background-size | cover | Use `cover` for full screen and some cropping or `contain` for letterboxing. | - -```html -
      -

      Video

      -
      -``` - -#### Iframe Backgrounds -Embeds a web page as a slide background that covers 100% of the reveal.js width and height. The iframe is in the background layer, behind your slides, and as such it's not possible to interact with it by default. To make your background interactive, you can add the `data-background-interactive` attribute. -```html -
      -

      Iframe

      -
      -``` - -#### Background Transitions -Backgrounds transition using a fade animation by default. This can be changed to a linear sliding transition by passing ```backgroundTransition: 'slide'``` to the ```Reveal.initialize()``` call. Alternatively you can set ```data-background-transition``` on any section with a background to override that specific transition. - - -### Parallax Background - -If you want to use a parallax scrolling background, set the first two config properties below when initializing reveal.js (the other two are optional). - -```javascript -Reveal.initialize({ - - // Parallax background image - parallaxBackgroundImage: '', // e.g. "https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg" - - // Parallax background size - parallaxBackgroundSize: '', // CSS syntax, e.g. "2100px 900px" - currently only pixels are supported (don't use % or auto) - - // Number of pixels to move the parallax background per slide - // - Calculated automatically unless specified - // - Set to 0 to disable movement along an axis - parallaxBackgroundHorizontal: 200, - parallaxBackgroundVertical: 50 - -}); -``` - -Make sure that the background size is much bigger than screen size to allow for some scrolling. [View example](http://revealjs.com/?parallaxBackgroundImage=https%3A%2F%2Fs3.amazonaws.com%2Fhakim-static%2Freveal-js%2Freveal-parallax-1.jpg¶llaxBackgroundSize=2100px%20900px). - - - -### Slide Transitions -The global presentation transition is set using the ```transition``` config value. You can override the global transition for a specific slide by using the ```data-transition``` attribute: - -```html -
      -

      This slide will override the presentation transition and zoom!

      -
      - -
      -

      Choose from three transition speeds: default, fast or slow!

      -
      -``` - -You can also use different in and out transitions for the same slide: - -```html -
      - The train goes on … -
      -
      - and on … -
      -
      - and stops. -
      -
      - (Passengers entering and leaving) -
      -
      - And it starts again. -
      -``` - - -### Internal links - -It's easy to link between slides. The first example below targets the index of another slide whereas the second targets a slide with an ID attribute (```
      ```): - -```html -Link -Link -``` - -You can also add relative navigation links, similar to the built in reveal.js controls, by appending one of the following classes on any element. Note that each element is automatically given an ```enabled``` class when it's a valid navigation route based on the current slide. - -```html - - - - - - -``` - - -### Fragments -Fragments are used to highlight individual elements on a slide. Every element with the class ```fragment``` will be stepped through before moving on to the next slide. Here's an example: http://revealjs.com/#/fragments - -The default fragment style is to start out invisible and fade in. This style can be changed by appending a different class to the fragment: - -```html -
      -

      grow

      -

      shrink

      -

      fade-out

      -

      fade-up (also down, left and right!)

      -

      visible only once

      -

      blue only once

      -

      highlight-red

      -

      highlight-green

      -

      highlight-blue

      -
      -``` - -Multiple fragments can be applied to the same element sequentially by wrapping it, this will fade in the text on the first step and fade it back out on the second. - -```html -
      - - I'll fade in, then out - -
      -``` - -The display order of fragments can be controlled using the ```data-fragment-index``` attribute. - -```html -
      -

      Appears last

      -

      Appears first

      -

      Appears second

      -
      -``` - -### Fragment events - -When a slide fragment is either shown or hidden reveal.js will dispatch an event. - -Some libraries, like MathJax (see #505), get confused by the initially hidden fragment elements. Often times this can be fixed by calling their update or render function from this callback. - -```javascript -Reveal.addEventListener( 'fragmentshown', function( event ) { - // event.fragment = the fragment DOM element -} ); -Reveal.addEventListener( 'fragmenthidden', function( event ) { - // event.fragment = the fragment DOM element -} ); -``` - -### Code syntax highlighting - -By default, Reveal is configured with [highlight.js](https://highlightjs.org/) for code syntax highlighting. Below is an example with clojure code that will be syntax highlighted. When the `data-trim` attribute is present, surrounding whitespace is automatically removed. HTML will be escaped by default. To avoid this, for example if you are using `` to call out a line of code, add the `data-noescape` attribute to the `` element. - -```html -
      -
      
      -(def lazy-fib
      -  (concat
      -   [0 1]
      -   ((fn rfib [a b]
      -        (lazy-cons (+ a b) (rfib b (+ a b)))) 0 1)))
      -	
      -
      -``` - -### Slide number -If you would like to display the page number of the current slide you can do so using the ```slideNumber``` and ```showSlideNumber``` configuration values. - -```javascript -// Shows the slide number using default formatting -Reveal.configure({ slideNumber: true }); - -// Slide number formatting can be configured using these variables: -// "h.v": horizontal . vertical slide number (default) -// "h/v": horizontal / vertical slide number -// "c": flattened slide number -// "c/t": flattened slide number / total slides -Reveal.configure({ slideNumber: 'c/t' }); - -// Control which views the slide number displays on using the "showSlideNumber" value: -// "all": show on all views (default) -// "speaker": only show slide numbers on speaker notes view -// "print": only show slide numbers when printing to PDF -Reveal.configure({ showSlideNumber: 'speaker' }); - -``` - - -### Overview mode - -Press "Esc" or "o" keys to toggle the overview mode on and off. While you're in this mode, you can still navigate between slides, -as if you were at 1,000 feet above your presentation. The overview mode comes with a few API hooks: - -```javascript -Reveal.addEventListener( 'overviewshown', function( event ) { /* ... */ } ); -Reveal.addEventListener( 'overviewhidden', function( event ) { /* ... */ } ); - -// Toggle the overview mode programmatically -Reveal.toggleOverview(); -``` - - -### Fullscreen mode -Just press »F« on your keyboard to show your presentation in fullscreen mode. Press the »ESC« key to exit fullscreen mode. - - -### Embedded media -Add `data-autoplay` to your media element if you want it to automatically start playing when the slide is shown: - -```html - -``` - -If you want to enable or disable autoplay globally, for all embedded media, you can use the `autoPlayMedia` configuration option. If you set this to `true` ALL media will autoplay regardless of individual `data-autoplay` attributes. If you initialize with `autoPlayMedia: false` NO media will autoplay. - -Note that embedded HTML5 `

      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%0AkScjZVo85&S&&fLn>7?y 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

    KpOE?ZR!MT73+7 zH$SV-csA>Np34f?ge&E;s-J(8EzzQCctQFtXq+f8PvNBaDtITwM1U2;c;SGVJ;p*s zs&FuwaXKZ3Bks!`6cmqvd}p3%?VB5$Hn*px&D`ABxTQV)DP3YoQld3Mhkp|jt%*8m zMfJLw85uLzRpW=YjEuH*)$wKK&`@(({EE1;jIc1^FG!Yup}I*55|2Zcuec0%w8|AV zlYfb7_?HnWS4p?1pHZcfl}FBMWp zrAO2!1zdZ^joU(ao26EOS$V5O0_8}g76O|J4^-lgY*;i^K@4O-SrwY+jmbb_Y9e~wfJwV6qVB}7)bu& zL#p!)kjgHn+(pWzW6Z+fD21-b9$|&@xm%I$UT~{?juqZ2zb0e7St%<$D8I~X2j!RK zmku(U{4$~SESK+>wyVE}13w8n(q;uJToTgLVxmK_QVIsl6JaX^eTW~6BFB7jWdv%8 zBPs=tLt>&f@k*4ImOK04$wUa(Vuo?5S3`|vig(SG0C7xlty!cc1XFL@pV#xqk>X+n zs@`$1p!v}QMTP9r2cBN+Cx*^q4p|q>%+ph@jGR$00k@u>^eEGHe6iVqUC&J2Yj6K_ z;|tjf&BDdFR6?+4_NCcfV-uYi_Cr|B^;k_`RhTN%ifEQA)>EZMIvv;s@azmocAGgDQ1Sjmo@2r7iA9LJ+13yFPGYJ3ElEnDPa3k~@2pNRa z$COD4&_n#;UIbwbKamONGwF6-;O#hVX@{&FZpMInYzH#8godozpXepHCmU{G+cS?xostt#a8#q;ijad z#Do-NU<@`*SPj!acg}AtPY2)5kmkzzSqo!)hvx}SdS_10K z^5y!!R@BzqxAAxNA2Hv|ny$Qp*>H7K^x3Ta)p63r74n%ktT%pm*R;ADPWCN(VSBYD zwR3;=&5JfC2cL->ShLt3;^yNP5Feqxz=|js5#z1Dt^IsIM~Q?Tc)NP^w)!0z!hBCJLWq>FOS3=VOP~>~0>_HD_&}dC zsrn{?kO`KoAPNW#!sQXy*f|VP@qm-T?7)j$3o7D(8smyd=n2NRYAk8<*T)yvTTl&R z*51sKk<2}v{r4`kjD!_-+nNRY$`QGhPP_LEg>psa360YrfJidt$@C~Dy-1A@^aWPuS= z5*+rVlyLw3lxEo6Oo@he6C05=(&I-i{*!VJr71_4Bwu2Z{XP_pap1^!9F%7=Dz#oH z3=2Kqf$Srr{`yEUCxQ6>SCwFae@CP1v$%Js-%eHHXJAgd%-)nKgyvd~3A7EWOv9_}5U%-y}L7Af)~ zI@)5CgqcOMJ9lo7F2E%)0@FF!RAL}DhPyj-Wm&#nv>b-3Fo)4bED42`G|}1#tYM<( zSvbLtK8VH}-0()tZ`8T%79o7b|=WJMA{C@Kw2)V<^OHV-U0M z85x<6Ze}KV7JEs4hn?Lizb@s;zN^`4Io*B;PtL}ZyRqJ0D%78%;#P=40q#IyZ%6$S zXQHM~ zBjFc80_coBR8RiUfjd+Di&Wx^U{?+>jB}5po*k)6uA&(6Cx$s44ebEt9Xrb}mDf&zNba+(Y=|Lgju=H2A7R ztQpQboz*yCB#qrizBXR_jBv+m?%u;RN4_6Woq>#H)&} z1(B%zVnAIkNF}_B4lnH`N$rAnVJtH#8HI=bokx^XIB@h7Z+rCEk>gn>S)>ziw;@z+ zXI6(Rxi2 z;-(&)Cq8m=#@svRX9sFt@b+CgFaxJ=7VNLzz-EX*JSf$gq+=or#eoBDxHcwUqjE!h zqAoFpvtOq*K-Q!J?S?QXKePU-)b(YPQ`c8KV~dUcY1{NzBYLI%CmHOmHTu5VjmKjf zpPzG$M0P>75M1QAbQB%{v#Q1F0py6v2X?m;6&Z{Lf_go!Svw49u32C2OH!&&BRyZo zXX}LHItqGn9GAlyQp&|bg&DIF7ZS>P?)^ovu`f)Y8XNy3SnK?(z`0e+?@zEDY5xJp zHKu^vNcDs2PhsH!VF4`+j1erK%PDMXVn^d19ZU_sBPfk5X1@T=(RJ{<(E?p7pSdor zAZp6X4?Keo8P`i|epxaUwB@~W#?8L{y7|q(=c=bkhp?ZztW!dRM9>+?Bkuc99QT0E zsew-A$ZwKHPG$|q{lu>vUXC%oYW2osfJ-Idy+5A}<}sd62923V)CtMDznDpcypOCFWY9vN5>C94w3Xk4htt}c@ zsF0Aq>_KFuqBV7#Hy*q3a{91!&yv?71JZ4lw0!Ee&@G$9ts6Fd^ zg2k*;M;lSVbjg9Y<*yFP|MpvyriL$s)W3d=EC zwM2>cQ=vo%r?Fs10TM2i!046Vl<{vUAbRCDbk9{E;&KE)pNsjykh3!&$__^5PEAUz z%ZWr4;zU#kj#}&+X4EC*F?9+&qmf8tAfOT{35w#Nc$O@}-&*P;<06uM;zHZXlj?E} z5&5k-ra1)>alWp5eZqn>YST?kb!Ei2w@aUhb!r)`p#d|7R)dCjkn9mms6rhMpzUHo zA039o9Vy_Bj))-7O83L&#D5flRlbG~;W=%Bb`pS;`}&;N5$-Dy>mqU*QZvd63gfg< z!9E)zEcI#e*YYD4`EcZY_(apF>P~+JJw-XzlRN6Ee+-YvOT* zB3@X`!A%%|-eR z!E=qlK?Xxmu<;W^PMlsJmt!zkOu7J5wjnqwDmXMIM#V0jl3tK~T>>#bQ~@Agw z&MLxT0KPR9H=v9$kfoeUP_1NAWGz%-5CukE?bBVWZF=}9Tpv9ioRAH*>C;=)q0#=K z8n?Cc+hVeS$tYI|m%K5C^zk((7BII;=u~DQBPnt_6Q({YifWX{+p$yhVvRGWJ=$NOI)^qrp{+fARvk{ zxWdIt+ivYYUti&}MP3GSK+e1)MY?>3dwf(Os@aOG5&>x(G!^Ti%s&B{K7x?JSrG~N zYkZkT+~^vg<0hC(?lCchgm!VITDW5L#A!_Ot*rm{;4Sj$ilV}bio&7_LFfF*+ z7dST5P9de}+AzznRI$Zkxs5%_ERz-O>(_`{_v)Gduu2qA_@Ds-mrB(d%s7raYT|im zG)_6jONt2n^0WV9zxjmy=6k8@;!&D8c9Cj3?zVCYx?%^@yuqztbW&|3?)L#H=}>ps2g()r=9pd6pTWjzr=T4b0LVq;r zz%vFP&%N9CNM{{A81-od`ULFsQE({FrnaPWoQ(>>0->OOt<3xk6%?rCv< z%O1JsQ9t2;_VJtcJf^iT(H;XGreSo)FuD*LS&+9U9J<)(NG#)9ou3n(UhmH*4pvAS zH@F~9Op3^Vp#l%W#kP4Diihs)9_>9kY#m+HIV$+-@4roGwm-S{r`zkN$j`DG&${g| zt*1|JyI(IJp|jbJH?PLINLHcxmoHA0a=>^TAdNfC88X?FlNy|$(Z|u|Fv6DM=q<`P z@zY}=pyT2bN9>ccXsnCyP9& zUQIh+*3wJTs{?uD1m zfN0L=iuCn`sV^oapz5}dJ9s-%LlvhceJ)M<+&cLq!py>%MLByxK-`HP0A3={hH^66lcYof+H$H*ddc4m zcv?zaEM{nkkBKq5(Kc61D@8+dR)cj=8gV}**#MPZowYo~OP>BAz9IgBk%duB!{O#z z=5*iImzC9b+nk>L=4@FE%xWpDo)Zx{r=qYmI}kC4Z(>qHJk(G7dzMt$D(Y`KGpyVA z?j0@FwpI35D%Q4VT2e!qJvqB@{!R6yLp><3mR7)D7>v&Ck6XP_enLzHE*Y4Kv0z#Z z-2Rxah$`r0@uLuuinCU(9i}E!S1dOlWYR6pU0-KU&$aFa~wEJ-;kyeoh7X7duWBV zw{6W9+sa4g)*dPzso8YA1Ld*i-{_jo^k2J*p%3^j%;&RMZ#&EzbtvS^eAjz z53<{;kma4-!L#|J*6mpCk;VIlE~i!w7(O)+YS zVyCmkmF!kWF2jWIGaYjaqM2GJjGpLcqM-c0v*#U{)o{2z$v?NOCbps7C!wzJ^Uun+ zzq)q)nH$QpI@gwq9RsrsWecjS21*U4s=nf?1?2|m%c|kVgp}y}UH$#MY}m;Oi2?QU z7r*vj_S((OP5aIc`L`Te(dauRZnu4X)#mP;obJt4{<+J#%ctaaZ!9MsMpdgeNmH>W zfhVE~5<`dmjtbZ0_d^-fK}Z0!g`)gHCA9~Y?9^&r?>XJI4*d-baWVc0Zm#58y>5Dk z8F4~|9^4W!JG6owix$qFSGM{2<-JdDpE_bH>&&X`$qNe1omDH_1;!Qti@|HmsE!?P2Df)jHiW^S1l zmo$A1W;aLPB&9$$B&bju8H)*V1^7SUEtop&7bpZAGMJ!Bh>sI#tLu>BNiGIG6$}In z49c@9JJtl9B`ebp>7H3qiadZth}FgyC;z6PuR5NY@+%DM(^9Cc)akBmO)*dXgsJTd z)hBM2JBt@DUR|A9mKNcj^D3>x&2o=a z1RkwZEmAl%`CnB~^^qd&r~sk-;)tB+`Fg;|f=XW$Ac=Qu`Veaf`M+@n#@B27Tcr{N zFp{Wm5$!@;ax7djv7W_3ubf8~weIQ79vxiVvMLrKk-MkOO6ol_eDPVSdd&hvLHdgs2nX$=lhTWpKh)p%@QUK%pFYECLi%AG{^KkQUmwXa@%H}r}=%0y@{1!%)0XV=;p+>l9Y3`1@ zv?MY=8AV~)OD?YDz+#{8Bq}^9uasJ$b=e3hV}s^`vfr3~tWgju@il&)jlnBQn5xcN z1okA6k)(JMImBm-8S!II>L6x90AYU4$C+4wUUH4h$<7LIUt4F0YS`L+VE=n>rnfA! zEzIkyNigMC8de7y0z678^4Gkyt?cppHteY0^Yg9EyK|&Jxp}**gOdsj@nsny=l0*6 z-(C{$8R#9B(O9A|fsmy5_&`&V#wVnB?xDd0XH(+#_q6Op2!woqsxENlUt$7a&#y>BWRW)H8?1L|}nLu7E;1QN0pC^B}b*eG3f(3(Vyg5;bAE zAT;dj>WX?dh~k7(ve%evi(4RQm?y2f**h>=7nZC^w)A9_%q@$Oe><{O3KKWlkHx12 zy7+iJX!MV$UNuu_zqD1{_##Qv1Hi+#aITg}@r`Im7~nZ4#5Wvb6fDdU0#4uPPV`&h507 zbmoUL7PYM1)>RO~z8^lbr`}d*|5p6-y4QA9wcPRU#`>G)7Z%M~U&!Qdb1O1C)>eR) zeR7MGgE^(EfH^Qk3Jm*B04|kI7KO>oLLF1_l6pu|mYf>Y*r2$42^aMf_FarpvQ6k7 zcw$4v$6D9<9VIaJ3!SQvu)~B?>PKpu^8u7?_zOWJb!n z^;%z$qJ28v7$3)(05ePsBysb_FqXbMrWHy%=*;) z5JZ*A#*c(!HcE&R`{)YRj8Yr0)Cj0C{sr-705ZUw`5w9kbH;v;kRJ_9$cap=jfjmb zEGRNGZUBG2M?5YL+eeBkW88y%pYRX%R-4)nEEGI`hVk8q@lD0}BAgYG{J7^HuXWIw zpT{ddq_J41;1a}%;`K(-BOSI26zo`ZH&P604q()wCG}`b8q+2QvIy)`(Rc;6{OG*o zjmr<3a$@`hZBnJ#R5ei2d262~b>QJuqobDE6rJD~lNl8j?5SOF=S%Y*V?J#M;%3e5 zOD`CjQ==0GbLUnkv>iORaPChJ&-as4guDD}dIs~#H_Xn7GteGrz#N_ijic%GMd|#I zmPK|q_~T3v8;AiPp{%A->SpqD)t^N%IYfH9WTGMgy=)yOSEY`@W?68WOplNv=lhyFt_g7sW*Gcal0uF@rD#akEv~F<5Jz$&DOkE&@@N>om@Y z;1x?hX1|gedLYRnxceId^>N{v?=)d?`oJiEcfpc0;%^M~HPozbo4(FyTsN(4O-*EB zoRqggzPzJ;|Kbuu^@COOj8+uhyUb>zKO4>1w>6RJa)(KFn) zQ9xB4&B+Nc4uatSB3TPr0(?5sEgiT6p6%&LD1xV?!wkZPGJ2m9{m<`>E%}7lxvlxxGv1$E@z{4b59S(nR5@!lHZg(U70Cs zc4L8t<#aUq#TF#cs(~x~T74D?xbWYExWRHXYJK?x33{lgMto}VLS3xCzflo4r1Lo8 z4CrA3!;;slBvXMaLnwSB7K9X6H6}+Cgy^Lp??{VA{@sZD2Te|-SCFI+$&XBKs4NP7 z2+p{3Q1-4(#VXlGXb_(saMK&E5xCIqv_wjVmo zI(DM;=K4reWYx-+){U{ojjgRKsv=Dh3#60s2V#7b92K1)xcPRWUuplvRiMC*D(3Qk zOM76S8C3I-ZHaORP_ik_Iuey?$QG4)$p_*#6WQwlB%uVr=LI30XIfwL5*HV}ave4# zE(2SIW}}JK1ZMcUyKsD@qb4QoOP&^{EFP8-jyS1S_V$ktUUFi+Eq&nVkWf&Q;LTR8 z3p8pk$S+DJ>1(-H5b~BCThe~V(xTJGqUPlFJ49w*C4GICIMWiW(;DOtCXy{p1`vAW zpcV+wUg#Kz!-B?v5)X)Tn<$LDUfd=M=SC$XKxY0 z_bUj0G>}>2UbpS^@ai)=t7~??w0!joTWdW=U5%x4D_}Us2=4apZr;6ln>QNBJie}U z`rUup#Zq?t>7JI7bti`^7FNYr25##zpUr>$og4O%Y>2{XxC?6$j`8OKeWn8T7tMOf z>{ri3y1P1nH=AWpaVW>9E+PT~D={J=DiXJZ8;rJ5-4_eN8s;CF9Ofl7n&Wa}eEp1hCN#SEqI})4-nqxtl}lgS zPd#pbr0Gn~%4au-KK3~K7s<7AGBdhsk}>in82K)YJODBQyh;T)q?;tTAuxtUMFio* zfU$jCT}3cpQPhiddc8hc9~FhI5r>`z9xjx73dTDrn}!1-#|F%%z40e~`<^*w^PD~H z|9s=qPuT+@35BtK+PIqPlY=HL4Esohx<`SY0Dn>1o7&4b& zcu^PwPbYLEwvI9&^Iyqmw9lyfc z6&YDNP=)#JEgpWLckaWhY@n`(?3z&3m6ra+7JE0Sdd(v7UmKoJiW^P zu)8&j4Sm2%xZEMch0MO^)BA+!7d66NBl1uCrDR%RH_+q-j6tVLx29;_0Doa<{Rccf z7!|sjyP%(WKrQ;8@xufED*ng2X?hS}qV%n3(V)eDd?RWNBK~tTf0+A_JR*O{+-|mf zn7)^}{qf)Oh%jJ3%>R5XoVD*1*6=^5j)P0S%1P}@opJ@dY7B=$>DgJr zVAZ^ma6`qynw;*+_|c{tPxq}pySpYLza@Lk)}{mJS9ia7sPjU6?SQp zqrB@4Di@J1Na}t7G%ikQ-a^3z$_N1P8qnFS5z8-Jkj)n^P?%5r;8F~*%yc3Xv3|fc zBXrJBD3cJop(Vq1R&w3+oJ}LL4qk^?76llveMA=lP7km++Cx&&1^I{|q;%afw=gaZ zK_S4N@fNVJpFShY57nO$vxZOa5M62Hfv^>*Pf#$uFObS+JBrXL!^hd-HR!@ogU)31 zljwbVHdca;JTBx*W(Fa&m6bCu`?rDCjt#9YYgBH zFJCzB|Hn%YE8O9t*8U;jKbYD5pkxJ}sVClmn%i*9<1fS{@tw$e;j$D2(3J|(k}8Z+ zIRM9vQB-juO)PpSRb0s3Sl0I-N?iw~*O?2p6%bK{BENvlr6<<2pUYVd{e?mPTHyq} zy$^36<}-rN7r_*~oHheKZ3k1*bM4zxNah``q z(NjUEkMN@puS1OzFU@Xfl}(SvY~XTfhcMUk!sb3IAO38OhRgA>r*on?-mt{~{Yw}l zF;)J@*ZvWkji;kSBgVNIKV8LH9bU&D;;h8NuFYA^f@<;dQ)`Qh*PdD~AC)iQS8GRZ z2$eqoGkvCL=)Rur`^syW|KWn@b>YIL zZ;ImckjxU37cX`f4&KAZL(7cQ`HdVDU*4gNXhS-VZXLaIeG~v?351hvp zWq;s?a}`(*xCXEL2JVX8L5(oO`R+(oC8He&Fw=^b$D2|j{{qUV(`lj~W3LLDIz_Os zTrs+|JAdch@^tpNsb;>dWUkF1UZ~vq!tnAlH%_g)>9y5MPj9Of*dHqf8xnqY)_T@9 z`__4xi4Dst`=8t0(0s@HyX2R5y??l=eDmpHl9zMAdlqxAeIlV_2mpgF7#KNP$YH1= z5cFJ#Q&s{U9cZW_R@2xO{5wSRk&URv1R>?eN`T->B=*Les1mytRpcOJeTC>KL6b!y z4(BY(7kxMVG-KVa6tfW0MOysQ(~myg^U+5=_~)fhy(6USTPQ*sMrzc2WLb z{*FN@U2H#$O}pY|klY=mKEL;CSzQ|yRlB-Hj&5B;Kdot{IeKF6Mq=;!AXf&cV}z$E zS6;$lmQ)m&;OYr<1BXNgA3{7HSNp^fU(i!e0F#IIA5G+}V)+B3q7&<#7umo2wgK?gm26dsBiH4ZrQa;rm5rDCj;uvHkCqBj6r zgPx$DJ+M_!xe=!Um)6tX0yAU+>6<(-6j+OL3?%YM6Na&Yodw4e zuJt9k5a13S80*FrPLiY0`(U<1?=&1t&j(=FQ~3KK|3BI*KlEpIcViq|D*yde*Tx%8 z&S%>$-5{%2iTnywoA2(EJA}tcG6jL+6b1hQy)*E~^iDQG?_>s1%>E$zKD0Jse`l(L zsUM^rVydqI>b%IFm22sbkRu3kD?85rF#GEm1@$nQjyQ4-X`UhfndTWm7Vx;{X+bBq z_&5{<^7HmW(t8feQ8Z6SO`u7N=h%)Q8~F;obNPyaVDx`A&$PvUUAy&(ISZd$UpBX+ ze^Jf0XBT!neN*e#Mii%`mS^i$d@O9PDGWBp1?pnW5p`>(C&xFeoLaReCUR5f)HTzS z;-+nx8IhY5OhLNFil>O$dqC|>Q2R=KGw_G>&5;o~djv65R5|{OJraJ}NIdCgJn1B! zG==m(RG6g5JG_@*4Lu}W0|BVv8$BM2KdjFx7Q02U*rm)-`N_DhJBPBEF}p0zo2DSHmjCC@ zFYc~?D|Oy|gY0d*X+7Rl!e;^m7J62Z4o;DUz*@wvmBR$&yGBjMA9R#xjfh^e*!jZj z(=74NCm%TZXO_ZDRG&zgZ@*nwY`+x`n?P$%70(OCClF60nTXh2d*q51r;UN1BnTKN z8#L-1WGcm69A~2++EzVU=O| zF-QUv2D7@b0Kp}Iqe-adceu#;z5}#oB+Q5goZrAb@!q0thNb`Z?h8G)&$n3S-`;bf z`}Tf|n5|2)B`4dGboNvJ2_?x%B?&sg)OTuMw?BJXwrRWfJ=3S_e`a5|R$jnv*Y@l? z)u*!zw3YeWYqe!F2Xb=;+DiR}lm2CG{cr_g--F{3mziuQV1<9wPS`Wb9ve9Th4(jb zsDls+6QgHt1wAYAOrEoX3@+L%6YK=#6mSEfj?!m*X#-((t~LpKnwX0eMN_Jx`*R~BXlK-o1&|TQIrzwA^tH`P&LZH(Y$`Dek958=7V zq1az5AqT4v8%|bLSN??bs2 zOJ>Pj0#5R|I2FJ#sb|4rqN!JDYO6K&V>F8H+|lK-u5T704rTiN?MOe}I#HPxoy=Mk12G8tmL>)?K5$?`|$+B7|FcD5gtqn}H-dtS|^&P@4em?bHM z<%K5af|FiGw<;+Qa>We5OEm>j;=vc-c~MihGpPnf6Eg6il=V2-0|@Qrrk;rbkHx`5~JZ1=Wa>&PlJWLm(i6vz5xRRF z_F>l8c|syGAc?50>k2;vjBP}~5DX)0j^lkIP&dPIvardncb=$(?hiCLq$2F$qOkOb zI~>|(6&lp6SH9OJvZ(X=eGb!_267+G>6@BDRv-c)!5Z&{TUXfQia8b#YKi=i-!JST*hL-N=^*Rh_U`%2j*rXX4-XG zwJ)}1XLlkCsk8}m{1X)C41(hF_RP-Bb#+@H6P%hL`}yzK+xFMxm%~yEBEl_6!8BWn z%G?27Oi>v}22L2%Hg`9Hf-)#>#uz{NV?mh^YxFfkH7}F;cx1CYSe_S zhJe#e?eZ5-K{>q76l0F`_Kq~i2=}qOFsWIa_@vlhWYW+lPKE(ttaQkWP~}>)5xD_Q z6lgj?CQu6+!4I4(_yQda%+*yu9+ormLCx@@uZTTja1_s(cy@sImp{F-FWxP;jIa>t z8F}>T?s(EO$B!OW^s>9SJ)-2Nz!^1+U=gkxj?Qwo3U|kBqFQ|BoZvnlf!!Y0YqS^iXB_@|M(((-YDxU*u-Qrbzkr zm|1&frIh1;DfmJ7z#h{zV@B8bzm79L+a-7`7Kw6Q%W$4WY!h-j!GDE@bO=pimr$8X zgvZ8rGeyXFEOL?`7tEDbi;ep%g-_%^jt<;Uipl*0a^#5 zG%HieJWe$@>{|JkWWe+IBnfMTs_>O2EsRtaNM9L`B_o78vDV+ z!=-~z8{l!UeYo2dnxI3I%2HkbMt+Nj2PX=I`NW$++yD4JF8}FfFfhEBXq%dn5EpBt zx>EizelZGdqq)#`(oj*kG!9KnkJ|N=!r*EaANh&_=NG8n$dHDyM63tzFHrS~?ZH`?kqx2M-^d7@X&g>1>2^Td|gwAp()rgpQ8 zhB;{<8KBS72cWDcEDiYky^)>-Q<>`dgYnLR90WIV_;4|1{7;FVlL&|wd3qmtv^rLQ zu;|9`**BlCfBeh-4Xb*9dXUo}9!lzCcD$((Z@LGp&lC0)-sCgsO{6-3yZq>zOs-;4 z|7-mN|76d6%ufGPE@M7}fk7-#{+#}BMea3bYH!E;P$^e>88g#@TR@i#AT6zi3fCi| z1Px~nZ488rc?b*k92$>sUl5<8=Xlf@jF-fn#!TJWk&7zcl73%C*Y6kK`rdo5yzv^d z{Xu@`g*NsYc|nvv2&w#B%t8ch9ea-?H6I7&P2)hXQ)L`VSPQ@p+G!Y+E1UVhAIaUB z#|oQ%-?s6+_kQvVK9YA&PG`RIsPhj5?OtIRy6w*xB#yulSr39D25@%7@u9Rrg5jv3 zpud~zOfb#ywf55h3ZpUV6xj+7i9@RLbtj97en*6q8Q^mg%cpH^PaE}%&52DJEu@;D zqv>5cTjggZt?Y82{Dc@FCAZ($BX_eSnHBLG`{TlNO?*Wr{oZ?1d!i`ZX@8RKrx7+| z&E|tvQ7WSfnb?sG&<6yZu@x~`D5Nf2sdm`?h;LGcpPw;+13Ji!6U_~jXmaK71bzBo zY?Kw{i)u}yKH(`5F~Ue{L`t~NNPPWZmHd@BD!bh-|3;YQmeIMh^OH|Of+7-M__RE&h?Rbb8aa`+ahz8@1+yFx^L z21V~ws^}=(5Si{5&7lce;;9BP)1vGxgJ=)~wD8-J)163bqO=PU_4(NERT;YT$vB25yYOT~S(pEy}CGdb!5H19W`krf4*6 zr=g>G10VWUQM>K!w^_%}h40>8GAzC%#$~&EuotC(%y{vG-ZxlSbDlf{Tqzt4aDz0r z@00(^!fcf+2wi>db!U|}`LDvw3}vX0lVFt+U6%uQQLdV9Z7Rh{)-kjus4>L~VkORy ztIIMKT2w4Up*HFc0;CKwHwYiYBuxnQ;}>W*9YKk6(@B2JCStxrv?u|%B9m~+eQ!K29uk8SQdvLrVzIW{Lg z%>8z)wQY&5a-hr*RWvPQ?Yh^*`y7=_sB(8Ds#m!qx2%+?Qu3cu1>(>FE#-cZQdER4 zEXcKtQ6-P%{cowlD}+oWN@77vc2J0AdM**A@7TJsp0))`ZL1!flU`$uNY3zY%AQ-F z#!}nXPfcC4di&->&p1gUEY%?(Nww)u$4y;U+psDoa!t$BHPezDB)Qq&+Pbi~tk)XR zTwGgyO!QL-BC1-U87u@kM-T3nPDnK*wF1vLF;NO?5~;7ysG(QK8iN9p6OHMy>5<`q zF+nkjF>Y`QkClA^<3RN)=sU1j9dHmM^>-(};wmk?Mn1j$Z5CX-u!+~Kw!e)c)?*c{ zgtgbmsef`x^Zi>Isao}OF3m?bH8h}vHF>c+p?y=|RUH^cB1hb*p*yO@9!k>XgO7j> zOW{52a)dLZ4Eg|5tRXQfF*GC~QXd)5=b@xZV)#x^P8NZTEU>+`Gy(XuIHc<`)#quS*jCnlyDFKYw5%n%KL=B^Sx0!bnOnl7*n6zsixs z<3R=9XiPlc55GXH&@Ya!$43Z#k6RAP2)XL$pt|xojS$t~IAX}6Rk~Lz<=1GGW+B?& z|K^l~bHg%&^ir@_RKAz|=U>Xh|6&WeyV>iv?s4;ZQ4q7@FQIWYt#-NGB)!710vX`a z;LUmf9Ma&~G{T}0p@}IylEPqlQPc`TTG_w+2zP>n2C>c*9gwTj)4Br>K#|5tg@~@v1$}Wb-b~I*- z=nr)m8#W=Y(63o4DcpV7RI{+${`^gc58p&I$Rrx@9iM?DiKSL=Jy?1gq&{eX!kdcY z(?C<7sfO}~$d{8W;Srm`!H)y7@aovoz4UI-) zrv;V$f-@@YJ zh5H(G_4^hT7cbgZk4>)XxV%CdbV&gnUEu@EQaz^B*hv8}QqB4RkAb^*KqUg7+ou9b zQs^f&%7HBbhO-m00MJAjMTApHzV=o2fhDCJk2;9jU?*=yoDS=a`TIJ>8?&0M=o;2^N^6>KX==Ek( zfEAeHj)rk08{r26G?gkkD|s4_j#*ia4Oul=)fHuh`8nCTXsuBb6cg|3Lk1p6_bZ)g z1V^HNwO9Gnz%8}Nvge*fZfNj)6f<>;qO1;VRWYmOz`}y;?rl>mhGLD&%Imky&MsJR zptW*FNmgpkS2?NX(wXJwqiWaAn{G_a-ML|jxohsyayi8ieMldh9;7~z*>}f0yRGxa zj+BDJ!h)2J8#{%U=iSkld3Iol-PS(6aR&R796h6Pdb{xQ;`!|T9meF?v}`});QZKR zqr5AjGIn-fSV4BO7xC0~Q1wRjhoEYms!esusx4;j9&Hn->cy&SPsCxX7O1@3RqkG7 zUMUp`I8o7-olF_e4wa{87##mj@E-h8}a>n`c^sv$C3-vg)#G z|NmJYY0~n7#&X$_O($pk#&ie)C#H7-KpC{L@>1{Tq z=Iz?JG^)7RTG@~ympB$ks!!{=b&kAc=C&D$RTULgi8Hp%WSh|EHtp%|74qJhEoH6L z(xtVmWhNV5(aqi*Um)HJvTSEB)6n^l%mtc#1ix6K0O2K4I@cO zedQUr+M$frOP@3OPtVGLXRyID$NkGt(`e?aC(YdCm^p=BINA$F zG@m;#R+Hx*=bZbGU3$IQYaO#kE-1;KA9AN(9-I8O>v^x$Cop;W;*Ywpp_%TIcS~K+ z_@Y$P#(LmUHJ>nNP7{Q;#;K!P0l@?iMUOls=ZR33)FaP%861nJi&If8>J zm6wQ(5qooX809!nvsgE}@QJmys%_5?4V_wV8(p=osK*wa*u1LlpuC&S_wBp)SF4%- z4S#u{vuxAzD-PUk9XdQi{<7`xkQL*8PTnQeK}(DIv2jBl{wL#(;Ny;&G;WRtRmM$> z)(N;Yi-{w%5AO_+B-9#n%Sx zlmL7!V6@^D-&#Y)zkn}FWG$GQh%lAN#CnqcQ!qm?954Vig5{#lWHFfZx`vZXFrW~9 zJ=_)wUA!8~0OWkv(c)Gc$P+Z>yP82bNmwR?a z^;X5Qh>kYBXP((mQ&kR{*;dClq%*9zN)QBR1e{M1_J&hOD!y%Coam0PrQ zi`Il5*t*`PJod6$J9T)Quojt)mrlvAp?}3wu&onSC8+ASShY=chw3R5mpKsu!uCaC zqEKE@%)toHqANN>xVfm^24h2lqCC~^9#cHrrwqnu1!TPp`!hfQC|=$h$lQV%c9TbM zD4P<_yuGG)_o{qV*kyhMo9FggK&>evEZRry<)!z+S)Tu&yvT8fx39OC@Bi_wl%v^w z=bhWPFIm#oX0s(F1)$2|olo8Q)MLjUdhp1-+wa(Z$Dv#I@4Io=l5I=2ZQ8JA_3~wH zi`y2@@9&+{)oGhyn=!3vYF$-DQb|%tVZH@DF#-|;5=}-!WN0vGi0DvE9Brg=ZsRz$ zV;bdHS%xtyYwVM&ulc`ya`ltD!?NqsP~a_W&{H295@OVQun)sfjWxZ&5;o)!7#k9d zkE;16bdlo|Px-B@KC(AXdKB*SwAbUR^hr;bm8Va9R@PPTlfH>B&j_WK%lrzpSWN7iT(R4KaoGV@)LFNm7mD}!E;n@_9=3&REt~-2|Bblcw->)4Wm>hWUoXR zA_I^QY>EmC)Pr66U{8A>hbq<>8iG6qGRaeLT=WzT7N}$EWvWX+WIb1L)cFZQJG9cAY)?bF;*eqQ)QU=`)^dzbzy$Um)Qz=MeBy{D3H zfQBOS%p7EeBP@?PWpJ32#~fY;aKy2c0ywd_;E<$RIuM zN9OlExV(s+HQG9}bGyr9!GJ}jcM_yAb>c}>4On$hAR#f46Rnn}Fl6muu#&@d5(0Uw zG(?5x#L>?W9uW?OrTR78vE=XwLwH|tg|mNB93`+CFejr!VS=;Y>@07koNB<8lx}}n zQt7a~av8fVXVE=Q}V`Pr3V^EUk_aQ-^l5=^|@fb|hnI2Cu6JA~R#GXIj zJuQFzE8AJqK!Ki}I(>rIo0VIp9{R(cwZFQp<@v&aoi(q%Zl{e&vynfR7Qu-aLa{vH zZ$;F}!2lRGCgw@?STHM|B7rtfV53wl?I_D6mrh*bL<3q@>_ncet+P;Q_j+^_N zR}CaiU2HqYvoby}UUzCm?w)N6gB~{>=!b{UC|mGeBro7SUt=)-szPfXHXLGg2*!}j z;({_%?r@UeXb1uiEh1)zeXFD-`m1;l3~GqRk0Pz^P(M&FZ7hcgU^gbc4qa+M{=^;UA!R&2 zG79mEQD{+N=NxO3-}xZ@?%I)&+PmX_i!-yYYhxO?!yhE@@qm;)hP3qe~EV5p9o9sw@9D8Ng+LZ znH?G&Q^n$4uVB7E^e)1={n)#npZkscx{%U+mL)$!t!d_)X{WnyW?^;qO*!N0*y%?s< zbdLO)bO^)Z8U3CfR80-!#aO^LL}yeRE`C6k!l*A}AZ0Zn_d=J5@^6axxN$z{J zD6VOJ>-6*zldnFdJoU>HUkYfgEL3hfv9Rct?frgFY4U2@QgeH&lLR?W9J;h0BOuSi z=h9|apjn8LtW@gKdgf+O+aK&(3XhEa=ECD6R7y4oHIPvtgdFT)*jnTcf`n007o#VB zN4B5x6?xysu7c|kouPB#eB%^WPcXO@mm6UUILw$Ah;tU^z-N?<#48+Ad110FP>^u* z^xJIaWyPz`?y1Y{-q94280H&WHQ(l@acgW%nYN;;X6=kLTVZ5*tUNu-9BoWXj86)T z3=a$MIriBOma_VnhiANH>E2#1zccIJWhIQYkL+i41E;pt*6sZ1pnP)MM>7zp{_DWw z*21IRtn0w7hjxQ%Q{k_98WJ~CRiRp=)Wq`40ro5dz%EWTZ~hx#Eg+){FAd16_>L2Y z;&x-yA(MUr;S{6!+Js9Ax+dYcv5YdBj-f<j|adt!6d&xC}k-u$}8-E(t=+Lsq^?6`BNxMI!2-Rl>euF|kuTJ~qB?P}g+o>>|j zRWL0bJR}s^-M_^#@F7V>p#q)-&w%5k3~%BfuI=!P>s=je#92K86|}hw*6`$Rru$xa z^CMO@db{5T_B61>H!prFeR46({;rZ2ACD}NN3g%I^%jMbTp%4jges^h23=87e(p>$;g%A4!rzq!2({VM}u8CoxnoqN{Us zgoht^fE~Otk)Op1e_&5vCz&7J95I_xP>g1Co7E!-vjMz*Y&KCeOf{7xnKT*N!_X|0 zxhUr#dh&$E<~`}sE2%R+?TMGcOW{GFUWYI-(u}V)VYBcIX1xEZ#H1I5&P!ijCp+mF z=G%?c?DBPmP)pv>_~#6tSS{zU^Oe2DVJtvnZ-cUW`Cpg6kZw|+Q^lh?S+ljl z%R%iJun;5ot_0l)+dx8~AAD0F^a>n+9BWKG1Au&DwuuQ$m64W^otPaN9u%n6c(|+L zSv=*js1celp%9zJ>=K|y+}r_OaAa;!yJD*6>afp6?~Uhnl(Wsd-JfHI1hIPkvEJ1W z&rfCcWs#N3n&Ydj*#YS~YjYpWtHVACH3eBsmQekyqkr1k6ZVT^bqhka{ptRhT@U|t z=b5R9L|VPHfm2@d3J=zZiyMkobXp1)9Hbem!hy)x2aXvJNz-C&2DT7$7G1_?jNl<4 z-tb=|?*&DWk-6hY9CvWT36oAsO~^{jiVP19^7r%fm^A4W(SqW0<8yYPHK;)|hdKbX zA$&jZ*!oJTxVyx_9v6~QeHw-jwk$fbAe-6usG|#7a#HJx&HCQ3+OEO&_>y#3Icu3N zxy-+A=Zix=*6s~8Rr7*o-?!X4b=UI?w-(N?Pxis7yxEW&A1K}tU*2gBPMKCjRZdQ# zfhJYU4<(HQx-fbifetPz0X4_fuo9%%2 z9jiR3il&Iq0Z=25psDCBs5ki`|H+YMea^i3hL5?2q zMNW+?@?>!KLR29dZ8jp63gR8=vC~cO$dKUxdv*(Z^aAgxi6)coAtAx;1toGDO3&Cg z30ub6YElo?t`^}*`vHuEsqV#?VnLZ78WZSqoiUkybWD5M@sYH4G``G>awh2fKjz*$ zKB_AH1HR|pJ2N3bNbhYj>B%IS^qxs0JtPo9LJ1v0FQIouP!L410MZl{5E~Y3Ye7_W zb?v(9?%HUasnTwb#6Crcl^R&*D+2a6JqQuj%~%VC;aJjQ(?WuL zeUQu`h9N5iB@}}0pQJ{;&X@DxQzl+N?gvC(ZF2rqZ|tlceeE-gHlDt$9G*>$tH1J z5%AkL6+QbqCR8IUKh}3E4lnYP*rAp`0F{Jq=9p0|`w$hXfN z8N2`bYmlC6pH@D!ddY$5=Vl$|lUkJCRu&gqHa4?iURCr7hXcMe4V0}-j+gEo zElCONC5MWXoksThZm1<5WGp2s1-&L|bt+gkWeqHqXnYO>yCL2P4c~;u}2*( zC$m!Sm+^y!AAqB6IJ8yRSIP{NVYhN67;00Hwn5Kbhn$0?iWxCNk|;ThuQ&P*HzP0) zY6l!(Gr1*^ucYe9ax8C1cfH(mBlshyOWJ*@$` zz=W6ZGaSQg(k$T}6i&)HoO8H-k~R`PtuU=jB>n-F1BE_8sgI*MQ_HkI#yI#=P#UZwa#5IKVvP* z5r!5(lj7TJyNw-9%`mrRj{Gt- zMV8Cw?Q9ykxFtTY{trGbCFtY*&Q~xs&*I6OU^@O1wPqnFU{WZ>b6Qb z8i|B3?k2}SAs=Zm#CA+;OfT>b6zf)w|NJ9xfe&YPov4gVippEEKS1Omh zT)dbZW5x_AoY&7ad~<@+F`M=alp~1ZkZ|3Nw~+4`S7qj8^|I&pToF}1t48}oVKJ+p zysT>3VtYq!unBc%ehLa5CU5AGkA!8_q+FSj_O0A?dij!^aiuY*^X4C#wd6>qe`V+V zk~Lu^MLE7f{#CUVJ}Z`7(feG^;`vkKYibWqdjqq3UR$kF_@3MB!v2TZaWP`h?4tGA zvH#=jAUuCMe|m6MbFTJ@$}Dq^_LOvvrCb8)Fn{l#e0+znX;b8G=k(a2`I&OGUYQj*TVd+`cp<|oJYCUe#14jDboKb8;iZoOB14fg`2z>^) zwqoo=IIxi}>_A0SHsH7zh8sOr0F>9g3(%Ik#v!zf`Uv~$1ziNJGw2z+dI#Yi2`};&5yA-0P*vTa6+J=)JE}ggS%mNda5Oo4fI1wisiOcBDn}A?CGfD)Il|awyiuhrg zz1atAq#y1+@+8M?vox*iOjQFS5`%}zb68ktY8I!)VaX8eCa$WinA4D=C@Zy}kxpjR z>y*880sG6P^SQP1@!gY8cTIYF>Sa%FD3dMCYud5%9as<2mBvZkV&`$E@4K8qX*1Qs zBoz8Yhg_SV@JGFPqJch=)oJ&}x}uOgE<6EALEx#FCrzwB=K01)VBDngILk`efxl7cTq<8@?i^l4VX9z)0ee%9^EEh#~K)-|xgX58C62P+3KqC?6a4jK}caK}qb_^}_09Co9X!cXiY(YD!9KT2!-Xiy}t^ed(9LUG4GfII zL}Xk>NI_!+-N5K$BEo#Vhj>WH*+HX6mA5=_H%d7#9NTrhXWvx#_2$VuVs!?u&xd-; zl|2V1Zhh^Vx|*wA+_dP{thC&nqY?XMwluD~n*}Bn#oOj&W_D+e-_nuNapQCIljlEo zLx&~m@vx}U>FY|8%hpXV#pp)@k8Z&kF;hl!okK516qV~Dqh}?A8*oApFkPgT!bJw= z5E6EET<<%?>;~-t<#uhqPjp&DQdvq6Fg@anFa*R^ExDm}^yaQyRXz9YvzOLTnG-j{ z#>J)NN!QK7n5r_UXX5Nt zEZEiDwq>4-;BXSD_gmmF28@)qeTv+_6Pb4cpGFoOyUMXllE!4&r9b@b zty+bOBu{bzJdTEH8Z%1eLy>dheu+J*@v9Zs!RN{)#ori5v9b2yNHKsg2>3pQG7p%4 zFm0P$}vmdL0#x;e~z* zKuU4_d60m0J}AKTNlWrCp&3<4%K^@?B6HsCuGr@48zsFtXq|>;r;I~zn;nT)A;MZ)& zM1V7~*%GedXo*wKEB6?K(bDZ8XGaq>&NOnFWob_FqFZO6_lBmcP=6LD9h{?cv?S_>!CmA*&1yt z{!C%FJS{(VhQ4~H7kk9mjqpMrrJRFrRxskL@C#nKn7m0PHYzDrlpik@uAwf?3cE21 zwF9$97epbCOjZ{DRRYsT6+}lDj7l#`Z=zo}rPEFggFZI{j9F=~I)EtVv0+C`dUBt0tVs0-X*i zVs?EuStkK;%^JKbD2}KI30Y44Sis;AAH(22I8|`NC8$S={Z&*^ntftg>+=o(|W);L2%xX-HGn?a58)p?L#|vjQTCI(<3S$dq zHl?OE%`E6`n;^GOXb-c+1qH>~!eYZR>4(g)OC9v9z<66&e5hy(jUV(IAj?(K)k-sJ z5*sDdXNS-){9+~UMoNCjxUu^Aa2!HlGU_JD?Y|s_<7@O$ITXp0w)(NHgmPB^N&|-y zZ?}+^2w%U zm4oW55Y>zi0$4^$9CnT!+Q1weKCV(uR1u{ZE@!Br;5eSpIE}W$RZUWF}4;~09GjPP+l`U4yrXz6x={9C0X*vU#?n%;sLRT zRF4Cm-S86SwFZlM%0K4=6^jyu2(etEN#sp0MzttAjvhV{MAkB+2jwr|zifl}U&59JI28mK@@Z=a(e7xKftAr9<*)r18ke)b(jTh)Vm4OGt< zS?UYFiYaJFO0LU|GP04d_<}yalU1?Q`ph%N^s?Hhf}Lx39-V#LqN0L1*N@L1Webch znNW0e=UQCtDA(0Ppvq)_dyn4(PEpA>Rv(6c;V(y#pk%Pmlst?>jUGc61DjOl30=j| zpriOZzjkc4w}dHVd^dSB8#`5fAY|wfiGk18Na(nNU)}k0MPxWg5AWPGlaq_CsS53?9ebsO>Z~FGp zOw}%Fdu^j;=jL^{lI4Fr=zcx$DNSmzH$@{kkC_=g=wzZc7Ng8*Mo*xW(J*x=Nr`j~ zm`b@QNDizb=EzkCSl~2kYD#jFo;C$pQ#ewQozGcCj}R&cf5`CZx&;u*1(=m9v^`2j z+w$5aQ$h>Ym#=(rcbj_8J@?#e8n^q!m1WC|Lo?>)*7l6C!P2emVRK~P$ybg`GC%9( zUA_I)ZQC!~zV+p+s(iej8{wBccJuh{mw{y1fl2%L9gKX)CrHEXp5r@OM;2wkV4u+! zfjd}e6^c}>y~}6W#g1I&4HqjifXvC`ELGF(_8HZ14CVh?jt>io55fP34GV>mIxcwF zo4jRaRjj3I2Jd;yD>ObhEIw!`dhnjw4MZ!|xSX!q&c2<0zF)}SMB|5htz`pX>EKi?54e?+%Pu({!-`c*WDY8I1>xd3Gglc-lYb{}m^Rv%jI^Yf5HDyPGmzUGbG(QMl^4CxO`V{`(8kkrV8&{MV7?@ZX7gv}RIM+Wq+Rr~a%KtU(4VJDfx^x{9 zzTBwHJDyl&3k$PVCH^(Bl76U6^t5JVSkI)|Y^l8;PXm{d7AQBU$cTfS#Qs<@zY&P> z0=mGVfR78MNi0zP;D0%0<+BYX>la*k`PR(~H1F-pcChURPi;F1dUCjS8Qa+VDbmbV zu_w9!^(LIL>u{%zk`e(mHriVT)Hv=Uq5=g)5(CJP3|W}onNH_z509_ekmN8Ar7IdBM$6JX?X1DI?g6Y>y=2ncsKh z&&ia8{_*JlCOBj|d)5&ke<}J$|IGW}#QXcw{Yd_jY*1v3`WZjqy$HPbh~X68d*0z8 ze{~;1%+pK4>Hf$v|#X_@gGB z*T$Y#uKt(do!?T7*As_N(Y{wta2zx~=%Ju5gGaDAhcVJpFlANmS4z#r%jDMH`_#%y zKgt1eW$%(__Q)^FXZJqSyM!PdmKQ1C;O?tPbjRRw9VoRfANqK6`49(4`R3C7$|!l! zGxSa(j^}0gswYMWT`|6j3h{94QGn|*P?Jr2SMxpnkJs2tR@*jSod%bs>NEI4zVwrN zzw$PCc9}F*@_b}eRY6*as^EQ)6fz4Z^wa-m~h8Zl!#1vBiyviH*gv$adI}P`_zXPHa&_LPA4PY|f-j^$E$h>FUrFk5vpR_cP*p!~~dm7t=05OqSamwcwK%%Fm( zIxFM__{cBuWS|An!-j-Kgbyh!&6>QeJ-#76*e^ArwXJ0QjwzWY&nL;&D4U$=^1in{hn!SPVl+z*?OG*4S*TrDd6cb1X>LC1K+un>d z6^SLeaMH156~tAn%<#-uRuPASN0HGvc_oPz>oWW^R=9c;##O9AkCo0Ix#+PbLs?Ya z#D@BZd5;M3^K7bqwz|pFFJuJFH$z!d^;iEx8^=uPfSRXPpg(FO&V&Kp&mO0Sc__p`aVVIDnHA(YL#0F6^bET~+xU#OPJZXZfS|v9>>mK7 zc0zBG{4RT^tV~PMl1nMRk@-71e-2n3)@1OBC-QMR1^Mj{)y zMw4|&!6P-IOMsvI&jiiiVlhA<1UKb>nETJ?Mivx|tSKm{KAcq$9v&1_nm4;65gPd< zizP|+iVO;k$|}yV7G_?$u5`Zq?t+qw@0^&gRGui&sw2X}B1XpUtK8Rna&M*hXLgo3 zx;#s3E#?0y=Suj0a$IgjMQ$nmwK63oD8XY$Oh8Ja_QuNil$7{V`fF@(WN>JjHPiZf z@7#MAm6a{JSDAd!K53Hu;3Ul!8W<2fiM?j$|6Qso>7|$E z3Obn;4&&G2ujSyXtue z*KX;Q|(@)jJK zH=lkwACT6Nm)l?spnvlktp4nu$i!7&f5jsUUR?0V7X0w&f}q0LP?$8$F8HCSyV+`O z?k>W~p|UDRarup;NFHdb$Oca-o>5y8s|g=0HXT+89)(>ZH3rA}CwLn?s7iYdWqu&! zhT%li6avm+ElpybA$JUQ3ToD!0U z1-)!(a!qw@5~^D>fAurvqVYFqU*fSI@qsW$Vm&MgCL|Tg)0c&RjVB@lljFBI<>Kjw z9(tNZA3GV8m}id7wpt^+VAAgl#8YIJ%@#g9)PI=z8GL2g4`zF2WI%9$cZeAQN#$8l z^mCZmm*%T}raohQ4&M&Ow?~-zz8#lk(2r{#9V!y!m9O|G1D;?CD=u!c8#Y}QXh{vC zkNmc5vm6=`8!>)NO_VjtM?sxV$0hZgI@Guauss1ADe+wM0&L)$I`r*Z4!_MTw`x}& z{Obqmxm~+1PGCq0EVCi%XNC~tb*?v2(T6CcL9B^lk*&8f3toOl$@<{k1BOq2+qDZ- zQ+~voY3fbNY2z8-RtUZs90+{t!!1{Ccc>x~vXs+l?W-Fb*Njbj$U8PaDKX#To%rNi zzZp)Jb~hxUeqL!C=#;obbz|&Fn4pylrw@ zWx$xc<+bD$fyf!uci0ID%~L{U1Wy>f2+ve`DXuMa?VSeolvCBr5iHJ3`_6fRGER$_ z^gVm)BlhO^n#wxv{`qHh=fxg&4|^8KD?I|(;{n?rTs)2JYM#QA1ayI?!b4sOG7XZ0 zj4)F}qa6U{a9V0?4DQF#!GU^EVhH0DS618v_$oMc29L1ECm!2a zKWl7uOI}3v>f5`%|30O$z#NfXXYKu4QhmNTrm!*jZFMJ$XC=b z?2`7Ze_TO)a!HauyVE-+FCn$S;zgW$GH5|9Xh9O!n9C%t7#36Y1;qeQL8pH<`9VYH zRSh;Jp=%P79wfz@a2oY;t_e<}ft;yaTz4i9Qfr2^U2*r6Wq-N?)`R-3k1v^h_hq9z z&wFlMRxzV01`=@PjLMvjiXjZ5+_O%83YL!s)Hi=w+Kw)KIzJkmP@KbZ{EcE`Q1tLnT?=ZXs#O{Wr z#0eRH;O^>SFJNjU;;Ah$)7S27T#ahIjMZ&9w)DYF2furDkEHxx6UT zmwm@RzA>>RIk08tnWfm{T`f7&uNgmcLhi)1RaaN7os?%B9^m~tmKU~atb`|DV_FH7 zMlR~(=*An#ZFS+kO&2ao`<MM5JSL}T)LEWhhV?Pi)EQmTn-GMzLcod;a z`e^c`;O-_RdJrAAGx_Ozm4mf?T`5C!Udp9sSgiIBb;sFW>Fim!Edb&ktgZ(}7$i|V zD>iE>1)wg4$(QF3sfK?r(l@K58+K)YbLyG$l)t68zXeabB>MjF10%4@VHRcA#o zb!YD|R9GuWpLz4#f-yNE(Z%EP@vS2m{q^|PF#47!!bE@zq}Ip9kF=uTjlO<9zWiI1 zeHBiU%#4F2hhBC5{3136b(HMvUF{S0;T76ZeB$C(C^3HST?fby19BH2i#lOcwT&h> z-id48ibqgN9IZzdyGOqNQpe9v0bB9jRd}zNj|gV~b&;@|KrA#M2Q;+QFv>e=Dld;j zWTIbrq=nD1@DEQOdGtdTE02*2FZL*fz3ds3)Ds;>0!9I236p*A70c}5q$isBW zLqpIrWaWzGYp3&h-Jby$+24_WI;%E4wtU57msM3ko3Q-xP1WBGYbB zP%FsB1!s1T9lQI?f{hE#T;JZl``HDoeC?E?qN!``o9t_+78gxjXD5W2IvKWPNh00Ji9*Q&wJ06maja$6{oUx z>(eV&oW}Y5mc>+e*Vc7cMVqVU)YT%pDI$ie)-URcJ+k7A*O+UcUA%Gev)8qax$e2e zta@Ene*WZjRhz2TO)kivyuJ#f-l^|ARn6p?q=nQ58Y090S1{D6`sOE^lTm}38*xat z#`znB7zSkr86!x#w8)eH^({Nwb!=TN1*{?P)}f`pYaLZ=i79GHdzT8aff^^bZ<$yz zqp2`Zi}94_vVfFwYg%Or(rGYh3--4Gt5`z!Bgl+k?&QH~KrH@3>@TEBnH)K}dup}P zSeT!km2QpoPcs6u895U7IXJiqkwaUG3%FB3Nv^rXfR$-1rM4?`+`*M2n>QXA3pPAT zy};tiMq5)xmBd=>CTEV@zoKf?<~ut(@7pmRP1d@uOzY^f1eTptkQhEJFt>H(xVH79 zlaf2Gnv4ooLB6rMv5C3yp~C_S+SjyqtQ!@V(0R@5+U~!gewXs zqmzDMK}gZGP5Y1IlJ*6=3^|Vi z^dCy)&b$Q98%L0GCUx|Ry80DkQt$S*k276&ZAemfn5W^St)(zJ zy0FC-m>B8n8<`jwyjBSc^$8koY-}zMPY4^KzzK&*8bszc%nBLBAA~eQW&s~VPF$AK zc3!(#E(}+Crabc)`oXORczclR;h^P2KTJ(07>NC|=z2!F5E;yB!KJP2PD^=aL|8_7 z{M5zpfEl^!$fVAjmzJkC&MeS=lN%7L7*$bKWr;0H3S_e}dh5sE*31 zOUY<0G&gLxt)pfC+GhE@9FtdL!W$#-<qNFIIm zC!esKnY%jLubW$xI(B_)Q>8h-F*Us*C&ClhL0s@fjG)FZg|6D&rKd4 zlGT)BtE49QHTSG#urLnOk)=;J0+GNl2 z^~)JKE~|aRn8d^}8``tRjm-7)&9XOIN3R*3l+?Pm_s+zUqyV5B`+ZWNy})@9))Em0<(;gV0Ay07#-mQ+#|nGZuk;$M%X!29j4Qh;|EQ)(-eRS zvg_KenO8X^V^j6Gozrv6dk%HYII^UKO*npGkKb2SvqD)&W}VGiml+nCRdg?FNsH|$;$ps^Czi@aIdz!5&NgHDuR~{c*+yW1r{AgnK1&$w;JxVmFoCPC` z3ht-Zau@7yM}=3P&~_?&Qd<^P;ybDIZ{_0F)W^#5^GfLtD;>M8H6fvO-PoJj*3+7; zZyP?orDgoR6Gx4j2+r1pkA9>;=j}$(OrU7;N00uQE%cL%ZP%@&apkISD^D6XVqE{T zP9)1@QJ%E6t*UQW)n>iV+fu-FA~R1N-)K0Q(OMKuhbu5C%GWn4DeyJoX)FUXz7;dh z#0XHznbR&2b%F`H>TN@<&@b=}Cz>nJEV5x7N)m*pM%l_AOK+K1T(zV%wZ>l8Xlq|y zmA|k(=dtQydr4izIQB+vs&91gh(t@yn1aZNg0Xpp9l`$N>+;)+qNvt-d~SYnK^kUi z!7;d73E*@IyoeR=z{X^J-KWRH2AI1u9y6v`A z>^Cj;f*;K|8#CUGFTh9q!4dpKx~LXcl5xq{MYM!6g4JfRueG}aeCkp*?}%+!+Eh5d zEn9w6vFDhr;lrvbLgT~zhp>(8rWtsaX9+W2?d>B4oh~Uz5Cxn5} zi8M-35F!ZyBO>zKw54e_TbeaHo2^bvwvczRfmcONSW2XK@iw2N3R`H@_VtCco2^NZ0JFAXV-ZAb5FA4$;^n4^b)Yk(t zBhdwu#pHCp(Akjgdcl`e{`}kz2R24zRVBn%+9D!smGKExSrOB-;$ky0V&k%myU%Lf7RBP{~C zP|FWZJoVI=(~4iX#kV;q{Brdc78{`bb%VJuBVj~*cLB0Q%50YUy7H; zKzr<`&wy~DPbZ(7qkNh=W<`DdiqY14ykqhc6Z2xcuM0^niA^lXu$iM$W(B8~#F_K6 zk-;I=a58grk=a}{I@3u}nOAH@W<+3EU}jucY(-WS{|P7U5~S0w;1~TzR(FcAh1x~_ z3e~W0mT?T=%`{nw!HpmcG-?RmjXqw1kt0IWlN0>_y9HM26zN4+T5J>zP&Tfec>tTF35b!O3;&iv zsYRLvY??B*x->V8u*niAkUb^=drM-AZqFj>%Oy2&Wc%{s1eqDnJLHscxZFJ07OFu(iIJG!KTx(`#!br<)w6DqK7qpYCxVF5auCAiImg;UPJ?x|Wy1IP)Au4ge z@inYj!F*J3(7|qr>`ow82xj0r#XykcVx)A{cbPLv1LNEo1>s^9{9r>31qwDC}nwqsoyUv|U6Ta|i=h%(f zJZOTlr|+83dG(ac(=0fxGTB;_6;9W8sa|VT7pwK)ZN>-rjnR+fPn42ie#lM|m??ZI zpzBFUfLTXLgGZ5(A{PEKYU!w~5mUbXPTT$0;36w(KpH(feRBd!C)ei%EYp7Yk?nkR zm?bqgYFP4cC9F!V&l^2C@eTGyZ?0x5s3UX3v(VTnw$?dCKlc8BTl!VedB{s5Kk6Yo zJS25JybP$8jK`@YGma?j1*V;;I>Vny*A#$?FpwDH-6DqB4vjtW6O&*i8J`<$^bQNq zE(V1RQ&um2?&z*fOQ&cIByW=(3MBo(Z>)@}-xB?{fnhO^e zup3!`md(D<{wXi*y+*|M^_KUJ!2WN8=hiY{Zip0zdB%iuZ$x0Oew(5EHv;MUA@Vl4 zBqF0cHnO}V+b1ljvZXV%>B{K^+C!|W54C%3`E|)YrlG?PcX|bT4@sW5dk*x6Zn!Sp zif?Z)q8KrD-iMz+Gp{^MyxI9(Kl80}PGnT>$b_g$doDg!J$j{S=3U%_Ll1uHSqo}ENHjw*s~H=`_JAPeF?K7FH1NQf^L!67Jr5EQ_L ziyUrq#xg4Rd3Y+(Q;I8RRa^3>U)4I=bMw5;E#s0w@^hwaZ3`>RP4~?XDXShCech{9 zlp~zI`s!Dv-v%z{ajGaY43%?I7=khNz3zX(#Z5$aB_Ny#aJ%Z}`KSl(iJiQBN6VCBYiojX zJIZY}X@S)%Z=E#x(9*JR!?S8rQtNUeL$gQa6i%wJ#8!3{gcavmy_AZ_H7U9vIV69< z;aNGe$JYggzGOWK!d% zf|`hqyzJKei0HDelI0g-XH-{o<^?NH;anM_OUD;#>w`Xca^8^z`QahY`b5W+v}e`M zEQ`2JBn)pZML{(JP zgz+lO9zCd8QQ)%XPH{1zsa)@&i43hrCGiVaH z%dc{z8Y+K;X9`)D9Up*tQT8Ao$wC#m5F-o=6K<5QR9(dszo?+tD5k8yJZ*_FM+Ksy zB;N2g`}hoj-dVUJf!lBsFxiYsVFLy`z)#0sdWp@r>Dy!Dk&E!?*VoVbVCD21rrY41 zGGouI#UIF5pFlCmX%GB-)54p6zJHp0wU*1O*Poofc+R~WYnTRB`2YVAGUD6nR8Yw% zX_nm+$=dZQ&m#Y1G?HauJ(&?pYBH5l*ebVS)*x*xw`2po+`710(OFbmgs~g>?aACN zN<#Ap0cXxOLMuA^JR$~;VB|9<->dyLuq5=+qu(NZ<5}&)-zf=w_QbW<;*20231|-G zGK7>to)s80co?Oy<5@g`2u|Aw4aVEU12wsXS2wJ~6m5RaIh0A3u(hsReCj|m{H$UqiKaTYn4ijTa8 z?bBv|^if3i$mFQXGBEzoy7o!d)+?vxz4D6o3-d78wcj2%dg76imJC1BkfDYe?;z&HiChDG*qED2oPmgpZOb?<@ zXTLu6u098(YuF^c&!m2Rx?FvZNW0h+z0Z_>eUe;#y0M)cj{GR=4`+v~&n<|9e1qVi z&l~P=JW8E?*vpPz+1=Dfd6eC)_n80`m~VIMDS=tH|8 z`gA*96MfuvVKc^4X`}xfA=4$Oe$KRFR-z8iVmUs2N zZM@`so4x$$TxwP3^43i_pM`2OT1oMR^I7hGKG$H*9fnWP3I@#gX&%?LIL9s8Kh)c4 z&cS@#!5lVkH4bsL9#|dDTf_TW4WGMOyU+1fS+u@@9T{&pi`MNR-A1Y6cA})>x6g^+ zVmv+4UC8Ce_gkcJbM^Vg)#rfp05}fO9LB#ZV7#KYqi$dvZ$&6RMc>dJ&TgcgXyNN| zWCiU6ijeZwMc`W#IS#by>#?*S4v2Qb0cyv3tair%-pX-6ynR60)NeIKJAGTUACWGD z&n{t!`_~B%1oZA7-0|Qxj4jXbGFr#!V_OCt2aVmp$1d7m)Y~z(weCADTEBO_eL%XL zYrK*1-tFx-U2k{)MEY>BXx>_cjC>~y1RF{*zAx9}?n2)dbY8U6+tiLV_jG@o^FHHG zXchbsl!=Yhsme(G6pPdK5c&|78>NLms(fWs{(ZqcYh4fyNgnL54&ksn1Z16cLOArp zBo1K`&-|B-jGiYU^MpfotFo6zK~xLE4Spyjk6}EH6RUyfY-JiHI4I_c{za@RC4Q=t zAr41I;N@_i;J7#+4-fcEFbiqy$O7cj20_D)TBcBpm=*bB_Ikxjhgj_Ooc zwcAEb)Cy+&!rr&D<~yjWe8RNis6=nm&JhuznGLpzE!nI@yBDE&i)4@~S=x#*S3ql6 zics?o``9XG@<^0X2q23Yq-;z8iW+i8Q5ZQPdYG68d2jNZRW-cS7}sD{lT^=Rf9s5m z_OhDlvL<^|TzafO985hu;F%cjj6ceb&B}6W+g%nfeu@6QnUY>E4;O2$wNz?Hc!ZQS zb!N3+Jw2Bx-`%%tZbofJ@V7-v@0dH~_El8@{?-9&(e!3oYk9iY-rZLRTC0b}=Y?8h z{B7e_RNwn(P5aEC#N4Q|m6P(*CtW>Bi>z6m;?sYn$~L_n6qgb5a@ROYUyD;c0cT^r ziFhqZAw)M$vFSRWn6Bf;CiE#Z(AgzQNPTudw@)}MD7b*p=7MoRdII@91h1Lx4uhX? z0RwUfKjBQL^8yC(Mlp`VQXyNU!&u}F!|ELjp z6V5Sg1BF{=B3UV(&-0+;X)Xtmyx^3B);hj64u@tlUK$DNi)ns@MyIKXWc9zcMmf5%E&K8IkKUOhdQ1v zXS}!xzvjrOYJtlcUDo)?spC}?f^f)vkgSQ~{&9!+J^Y6ji!MTD<;&hX;SnN|nLYn&<_M1Ll%uU3BWQnlV>DHfzO0t4n)*jhU?r$|vm0(C*J{ zuS)l17nP{u36ExUMD(AfZMxMocKf4qlP-I8ck`%S&n=%>Hh+}0woIN7TRpwZH=}c8 zvJ>MtwhD|p2z(hR*$r=nEHj!7Ky>I`?7>ho$gA=bl60=UzZKe2&gN zEd3noCu(8Ho=lPthrq6r-qfBIW6+-MH-=-*F|Y&bS`J|?hj2O0eHC9xShV>%EFZLz zB>hyHb^$`Y-lq|YJaIaCOdsYV?k!#DBknCnq=|#h-wS{<-YBCFq&Ix)2y7R`uc1@o zW8pA3#}_abI^Jc(@repJIX;JB*ssF?9kG5TdN_C_vuh;8^#znej=yrQPf(m(UqJcV z1?5m`B_Bs6rv#@!34%B!KptmrPyrvVhY$(}oStH2q9)&UC?ZJBr|TZ-3~-C*BtXyr zrziXGohH&Dm`^FwwC7ooc5cAQsVdiYv25)xhLbN`{NQZ=;{hUYR<(cvyoNEhLhDZ+ z1taa1ZuDx%5IsK$C>D?2D&qxleurcwCn9^FAX=1t2{r@Jrav6+05cdX*X|lT@cUsP z?PnglwBvVXAm7txMR4s{wrj@@JO0LI>ia%Z$Ku(@v*c}}vyv)ski9YJ-uEKp%{VTH z->l>5e;nWI*zvs%=XxzleUWF0#_bMKt=CCUX)lOA+6#K016s6t4O~v*DOnHibCvd@ z-seTV&)vY~(I&#>H2$p~M?Ndo$6T!U;aFyxi9Yas1-|!4#|B~I-CBw|nvaLW!FbMS zZ|UE9%LzwI#kryJa5(7mZz#<8xzOHrACKXF=Xh8*3i9p~eH{Coa4_ayjRx><0jFDL zj&pjSbN%2@7HvKr>9Dk|SN~S8^IJ5ptD(I=&dBb>So7lwOSF;CVOM$Z;i&(?~i8@s;l0KLKm``a2x@NQAy+DEip=UN3~5 zZvy&|{4_!DBkq9@p^vz!ExhD@TM-Z@xgZ>ZrQsnR!b9#5_-#c%ICRmSpAdwrO;cPD zZi6O}>uTI|EHsAA{Ps-{Oww)AR&m?Z^#=Pe*WD&Rz`*T^rLWjDjLZ)jGa! zZRmqLW4rsl?ZckHV&H^;J-LtX306YWF&d87De$l+{Q^P2zBzsxv~OZ0bmGNG4m!T$ zC!SW+spt0S-j5^dyw>eJ$lsewGi*G zOdHr^rWWJ|gRuNH?P&o;ds@eg>(QqV3iUZYsL#OJkks_Q&F0{D?z73nnS>1h>p>wB z^p%r?&g5pzOj>;OY1jK`+Mo5&{#hSwrdI0)hxEVv=C5lNI*_9ukr#42Lo5=lStjN8 zV9dm&gw4n*>4Fa#ccpX%zlCu7go(6%d~DJ|Si1&l{m8;_ukk5RE-|)l_An|e66~Ww z8o~*xH?;$X&_EuM4h)ipxK4!MLxe`<2(knW;V_2u!7!4hNx)br1+r2dXG-&@< z1p6m1*~VPEvNO!wlIEsv8P%ZHZ$7n9dF_%7zRFf>>*7k~HH`8$$YW!XjW$)9X7@w9 zr;-{7tqQDDGMvPCJyJ4ag;B{bZmyC^L)3Q{tD}T>16pfcH#M}vf(-Lsa$Fo)kbhT5 zb9yruO&Vkk%0fV$d1Or+b1a%WN@#5!4Kp=`FMu9lUK@>?qpxFut z2cz8A3;H1S4lYG))W`U*LH55?(5$-*9|FP^dY{9{Wng?zVM5=Y=eSk9!bEb#WqSJx zPDvE-FefEh_TSJ4vJU3aGs>Ss@TYk=&SDgZ`UX9|g&?q(w3{4@L5skN9g77m z`fvI;BkG)VoxSwQ%R1G2S*K{R_|kC$C>lG+$6Dc7g8L2KcSZFU(GJ?m+cC~nsH%t7 zM84j<)fnPxJ+LvAx2C$aT3xV@NSn9^ipT2NozL7^w??$n%&8qS zpF}ff`pkJNpSfr~FoVX9cwmu4nfyWiuj`pjO(mq!>rLhBtIa>X|C=3*>_&r7ua zLvN)!%(cj%L+ycm?ZgfF+e8!gaN7q;Ecdk={^Nq)?Mc=#CW}_^ch%oWdvb!$nlu9B z6~y#C;qk+UpV5AozA76aU(=4;ICRkt?xVN&NLz4kq4u=Cb|Wl!diw!rZz)zoW|?m7 zS+4dYh_KD!?Kyqz22F2=g+jb7i??}%CvQC|R&HlL-eoMGzbjfV;$3Q`mAiq%M#8ba zc4NG&9ac)vReHa`t=*uv!IHk^45ji<`D}{Mj1Q)(B=VKhtaSUG?`mIR0jW2a{b^O?f+o&NT56) zWb^nddoyEzCSg=VhsgXQ}nc8*%Dr z55%ck_%ZDPQvPzt;>6M(h}J_N(H<~{J;01atKw=s{I6`@n$2Y@D!@!RFw9b!z1U6j zW0XuDMicUgVlHF@8CwQy5A@Vux~0(Qzd2A*iJTg)c@RYwvpo2bJ6+;A zGWgEih7l9(*u>A5b8kd@1m320c&uGq##dn(Un9{g_mXzBmzhTj^_s z=<1}ahkPdT)`@%%U&kI&P7JeDV9)K-F-kB|!qt#X{r^P6s3*|SejK!a+KIlL8iTeE zNj9)|Vs^xf1z$KE5W~kG!)HesIG!{HqV=d)JGKEjXqtTzZ$E;YBC=+n{TQ`l{nrh; zDW1amcNzYLKF2wX9*4Ex`aY~BQGN_(J79Eb%$e_PTTdDV1 zsY?~2j|&cTT5-K)qEBy`-iLD{PEQ3Vf)9b@PEqeeZWm<5z;}2%#`3AAOD~#JdJ)`= zu$}sV9;CWsli*db#B*K*Y%$Tz+UYaFTaAS4#OZ+RM#6QO30$YvUB+m=m2O$P`*EV3 zScPT-@tS-1+dWC{Tx=)S5&1&&R@#esd>u(6<6K7$fpa4P;ox1wZ4lGRca!IN;1u>= z0e`JKh2^dM98)Wu=qEb6#vL#0Ug0#=RagIbmxtpP%5>@I>J4*qcCiTo-S{M@(-$ z6hN{aV?wqQt=%rzxMxfEP`iAO3-%#nf~y_3Xu;=+lS7I;uI=S{BB1B8+niQBxt=b) zs=_nE;0o-zA(Kym1S72l7vDsF@kLE!(;$N#-Fw}0Nyu9kjqZ2l&76E>MPDJfC`Q3Y__2roWO@Nh2J<3=40ez>x=tnWRRKnYZRB~Xk`z{EXh2&7t+WjeS z)#Xr}8E6$rq5)mt^3t|`Cy=)zvx8{IUCYbG6EQN;N@tJW1_pV$e>oelPZ}@7{l#WoS>H!Qbn>mcREFe!teZ z8NW}_-#hGncXT|DJJ}WdJ)6IH54;B7TL+hL6aRgY4zHH~{_lXdga7^!y+5cX@lR-1 z%8Z9FZj2POy8Git2=A3g9gpaE&u0dWoRMaRH*Nr=4g5KlKOey}tlDT#;LrFhXf8eD zPKy4Q;~BLr@tn+`i6+DLg=bjL(0)Ch$zEcFwuPQ?KZNfWJ*V^M&3Gm)y^*v7Xy;mN z=sS(12gft!0sRoQLqCUSuBGG8(9+=j%mhDzl;djFKPGM&s3JeL}RV6nDayCvUx0o2r)b zcb^iijNWDXyJC-4x%TL;p9bo0x8vJQ#@o^3MgIQX&pfH`;*e-B(J?WrOS8yWZ^;l-SX$&!rS=x!<@EJzf^? z|1{7SkK?2X^ptRt_VjmrZg0Via=9<4;3+-QhW@^wIHz2njX07rDa)RL5R87=hv4!w zL6W2h5uN}?jYy@jxG*dHT~EoIaKd;77?t*uu*G;Pi!+gjLp zLtN#QvfPQ4@!4$)iY6T0P(OP6!_zCTSl!)}$}Si(TIQAKc8yGAE3-!xTm3@n=k4n1 zy0JUIeEDtD^CncphUYeBWHsa``Gk#Hw7YBS4KuPrvzunFZ>X47ZVt_Az^)EFi~r48 zfSpv$=I1AsW5Rx{BcjjXH2*jL%+E8o@8Hy6?R%siZr>q`hHl@Hf`PBkalP-~d7nd4 z^dN7X|BdeO{o~`n{$VZy=@8M8TvIM^;C=B8$L9#BuH4S_0i5Y({yZ9Z$|UY-2A`f330?=35C9cN$VCsqAq(M* zr%V72N5Pa2{~x`qB$Hy0X(T9Mm?w<7C~s$?0&#G#L(&+eu%u96XCVfY15{E$FF~4Ls{8|C)Q0nwz?9(GMBbxHq0mv2`Qd&B0RGyv3c99;`SS# zUlhCO><#0J=ik(s+FTe@GJQjNY{iD@CA3OhU(0C^&KsTw(jwt?^*L4rtAthQ@6n5U zp_*=Z6|JB1)}FN+Cv4CwiK+;!3d0_ncRD7qaN2I;;91fu;k z3as}x?zCU9QCY#CRsQ^% z<9pL1u=vEQ-oR^<>aD)QSD(BytS;{iNN7_A_+~h3xq()7^Ea-loOVH*-7od(_Teb^OP%Ug!Mlo%4X@ zw@q!rIKM(4BYX9`EA<{%>OCgl7VQ@I!(KhVP4BTy@39Fz+#(Oys}~3M;26wj3k=3= zbF|6OSCZ`XIDh6`lD9)*M7sxO_BiKe@A8?EU&TP*(h&4H&MEhoG;-%n!==&sj|AeeJu=)UNlJ(s>iW4%Ae|10qDu3qD8+az# zH0nzDWEOvrqQ?V1>-?+=BWAMGrCg|%Wj)fT0cfxBE5S-rD zbeh`8;vle4>i*f?;=s?N@l&*l^SBV+K-mHZS++haao&!i51lt?1OD@qj-@~8J;bSo z_Ev||?f8T>P#=t=p&t~QiGb4mq5DjPw@)crIc>pA2FF7Qe<8vEA&K{o>}aR8r<)e@ z<7+<=QXBcy7@0qR=Iz9>sGar?f45_d$dAC<^)d2y48Nfd-l6?^mGnA_EUYIr_(DBj z?SBafh(+VR?QW~R0)1+E6w*Zj;S=sJqI(l@Ns@bp|D8ivD4E$n&v3zQ$QNP)hp^Ch zpf7}wM+t8Plx|pJ2jY!@LR?Qk=^slXAdGZDxJ|nI4!G(5oi40O7xk+Z*IQ|2uZ|| zkTRN6;e4&ZP>fR_Pq$-u;J+^W@V%Z2-uhS2z<3GwKl(js5i#bq*c~h9%_I493f@oQ z@8dSW-^V{hJ@ES&{{A=m`#c&5*eLG(>S+~^- zI!DrspmWF7S6Ll!kbJo6bR6V#&bSqQ1f4mqJ_Zd9xUBB)0~m&3rgKgh>}JRJTw)gy$fFdP8lZkj=;G@`^5qxb4o8SO|O`_f9yTm=z zu) zl@U?qTID0!9b7BtZHE7OTR_ z(CxiSUl}e<8m|=ZVgz)a=uRawai~aPTRQ|_aQqABsm1iJ3&K9fXUtAx00g^$ zz)xg{alZ?~zE`-ntSn*$XckYK=&sFIg6(x^EK7%wkKqk>-N3 z2egGt0~m)>8W3yoy$i~o_kYEA=v@D*e~0g;Ga3cs;c@0zd9kY__{x%egDrqUkxnGv zU+#rV`%5P>ocG5r^K}-{u3YXk5%q*5i}vH{evZYoQ%)>?0qZc{xBz{&>wUg+d?R+# z;j9IB3fM+ET_>Cq>i&M%_8QvhRvk~bYCeu{c{?92Mms^E-EY zMvJs-)rlNqNmik`Kk4|9)(L%n)YnPKJRjgY0?u*uMda}0eOQ;?M`$038wfbZ)zkgB z0bm$F%A7EOd*>LBYsZc)af6|8Za^@=4gT%U4c-H#Uu>d#J|6|R!9S35Ur?9v0)pdp z$WjwIHxLl^z3t8oXdVxF__!eK1=esMX^g?CL!)`z&AEYqu=lHh+<>o!2T>R?jy=$T zHS6POcALpW&J6^VJs%ImV7@n|$pVT*xQFW0ig1C z5OM6p&oIK z{)GCcL8s($*!tiNi#~aLh9}g=90T>|w*h`0m&L~E@E36S!Xx;!>)qq(-v`Ok!k>33 z`ruux;BobgV}O=Lf~;h?ooiM0@;bUr>buqglKono^G}Vin!vhuk9|Y{8=@q{%N|3J zYY#>08%~D6hdB=ZUn=5EsTQ`;h=fH$hA5<)Msz6(98b`5`6DZBDmo|qac3k8qBn#i zG}VK4@7o8{Xasf+=!=B4UMW0bk6#i}hf(kvWg2pNKntyRU=UB&gF<;C&n5h!^;}!( zr;oh<|1@{y@lh9N|Mxtz*^p!t!lB>^9#xA7yV>0wcqW@&2!ul*B51`;vLp-1ZrB45 zJn%kHv`RfIp4FPR9@TnQi+EpXD?+VDy`@@36ptz_?{{XNWEX4gr~kc1_L=iJW}bQG z{LOg$7td{7ojm-op6l9XpXcAY^|Sl7owMiRa~r02ju;W28k&3fUaqIVt4$mknsMnf zi*{M|{H45q^^7L;eamt$n^LpiMIT7d(r(;tdT)ESikeB4H#=AyZZ$8mB0P(}E4ai;Xdd1j} zQ8t{gN&*!_^ego3~)1=3o*zidv{0xMDYSLpKY{FH4`bc4V=Z^mL;|tR}cbf3) zfk)qUd4T3m&BKNb+i%#u`|6vs z4%(-()Q!8d@G+*o)mY!Pi)Tjc-Ccy+EA@TW*v;WPbL(kz=Z%TFy2Op0+uvWld^3&K zLBXamyX-QiDX2zt`j0=YdE)XD;Ot$vFgG^$)b68d_TIbhkUep4n%+y9gLV2J<#E^l z!Xw^J{63F<)&F+demsBE`ekd*3Wv{Hvn+S$+O=CYZCXE}Gco7&oM zS=``?^sZU6{n=dcs0k+os%D2Ur2qfUAMHR3)4J)DJGj@=-G3h%D%Ld{$8}J0=2}l( zqqr5I*u6)=ZD{%~G+y!TmOJlMmv2ArTVB1rl~?z2=h_@zf7!CiubadZ_s{}XY~9j-uiGeyyhIJ1jkLWWI3*D@TRS;J}G*V0T3 z9-v!=eq+lv2F-xHwYAR~o7b(|{N|f6I)X;#PM~*k8|c-Ob2qsj=)LyZ-tCVpr0KaM zwx0(}aBeP9RNA-i>|kE6_njei1)sR%eOPNfZqWPB#ss`?t@VY-Q_{Dui`g3Xbxn@B z$T1M-K(N2tpIlp;Gmu^xD>TZKXa&zkN;4+ep;78I2B)z|(4&5AJEzgSjx~7f{#ON` z{cm_qMw;OU&t}1s__s6%Bh6rg$MiOkwe#Q7j7FLgg9j^sKg17qqRj{c+GB12EHiH{ z_UnCXk$#s~h+G>^e!0ZO|t414#PiAES?WvzYLIfrM)>qf>Jq=H9~Jdvxl>XXdV=-DoHc zr#*64p3AGYckzLEZf#XBZt{JH_ujq|^rL7OIKT7b^oRdf`a{5oUp=@S+WvKJYwpY3 zmvr=HD{_xfNe;IamF6B>OdE2eXj$%T+R#f6<}Rf~E~2$jub-ZVojbQa{{(*p_?cxi z<{+&N_~Pfy+ybk?xdo!Z4V=VXqF!e_owp<7I5Yf5!DR;g8ylPG6ZP1)PmP;Ad0gEjEKKPC z209M{Gr6$y?3{pq)=kd-@L4y5_cO$;@GZzC;&v6JDZ*FBk4U)N*_Q^3yV#kC)gOze z1Q$G=D(*68C|w|Kk8=R67I!)BxOiOL70yf^Deg*VSI&rgkmKPCu)>(c-LWU(J+3(3 zm+o{jj(#)5iOGZa4o`bJ5o+Z z?pFNE;NM8xS&#$<>(cRYC+l=0O$-#Wz!yc%LW<-5L;i9793Eq+rGZIf)|`(4@A|I} zEvFjujl4A4ox$Hc(8(H(I*~5{*GQb^Tm*^7IDVWXE#$e6<3qrEA;&)~RUFcf1a?g) z1=x-}-A1Yf2up(U&Lui#Cus{MAA@pEB5w#aqH87%jB#MnGFtw0DQ6I_9-?I7H&;F1$PEGbnVrno})--eLLqFjrbofORW(ZCclGw^$e)K6gv=e44+gjqK!wD+nk%73o!OL6Q^50cfP=x%PX*I=5pS2wqTvV*ZI=f>U@P0YnM2m;Vslp zob#RQu^W9qb^t%6B4;C36fuH#-f`Z=V7?SHmAh~r^cHky)le()YNK|F(LCzF?ICfR zPYbAvx+y_P>Y;^LRZLTcvb2a6(-Jy~meMjhnNFco@p8{{I-Sm-GwCcko6ezg={!20 zE}#{3A;wlK>0-KseomLtWwZ+S*k4Xp(3Nx*T}{`}FX>uZP1n)&bOYT;H_^@XE4qbl zrC-x+)Jwmi-{Ps~+vyIvlkTG5)7^9r{ekYK`!Gg(fF7iW=#TU;J%ZP$*3hH0mL8+W z=?Qw0o}#De8O*|;qvz=bT1PM9uE)FSCA_zKpYu5GtGx#&E1y6wu@-AZf5CSiPog*Y z6Ygz$nby-Qw1GC#U+GoM%rB(Z=yiI7-lV@{o#bk)LT$$Dc$Z?0^;X=axyt#4^8md? zZ{yV5yYwEtPan{Sw2A&fAJND3Px^#D#e1Kh(H6YC`vq;KFX=1#n!cfb(YN#+ZKLg! zqaA2oxJn3b*Wv+Bc5^Wg;1Vw7GWKveSMWftN;VHVq_;5bL+3w`{NIr_| zxxv|i@l}W$Im{6r&l7N2;zYdU*vyl83Qy%}&NsM;{Aiwz_i1Nx3m=0U(T?TWJcp0t zVbAprH!wWgZY0hw#7vVLgC43Suuw zuj3c_CH^!2g=BmH)=C@$38szlrHHZ zj5`fJ;ZN}(;%B^tKj$xaD}Tvf@z?wf|BJun?|2(;=N#`)4xTMwh3o9_0F7G}s{yJ+ zm8vr3QRS*a4OEqCkQ%IpsG({XwW}JYhO6Dw?rIOUr`iiAt4FAj_>yy9wV&Ew{X`w0 z4paxJpQ=&nU^QADf(JjwDzEaXD&4#TbSN2nv!QL0`wsE}&J z05PJ*s|l(}O;nRqvzn}?sHtk2I$BLvGt^AgqK;9s)Uj%|nxl?W$E%;I6VzOFqKc|k z)u!52OwCgrs#C?)e6>Jzscw}}N!6nks+3BrjLND-YOz|PPEt$NGIg>#MV+cnQ_I!q z>I`+JI!m3c&Qa&8^VIq30<}V2s4h|~)y3)(^>e&?c9~kGexWYMYgAXNtJKx%8oWq$ zty-S^_idKRxuJ+EF+>(q(fLY;TJtGO<*w z-8G>#n&PI39G~x5(2ZX z;@&EMO;Nh7b8*!ABL0$&RCH0SE!o{#5^c+7tSb}mYBw%dXEM3KB=vhE1KN|B)>v0^ zaZx6jNT$o%<6tTsPa9uJG?C22x?=HY(fDY0ceJQ6)|H7C&FqY2qVDEscWZl;kB#%R zc+re_M|V_B>x`>u>3C7JtEV&SYDKD|4wJ84=PQo&q~nmrwG<-D!=^S7d<7M6<#ve@Rg$hs(p3q)Dxp`^moFsw8U=<03Lk#q!!P{% zg^pkN@(Vq`(DMsDztHgu9ly}=3mw1U4+!3X;0p-8fZz)VzJTx_5WE4w8xXt!!5a|% z1A;#&_=AE!D0qT`Cn$J=lD^t&<*ydGt3}>w$zL6mc;T~J_^cK_s|A0x;I9_^)xu}B z@L4T2Q)d;;Bp;sgLYXpCd;I9$Z#mQK)X@dv$@&!E@h4SM_VT7H9G%Wu$Y%Q@(^a6FAJFgz zXzCHr@BwJ#12lX98a@CGAAp7rK*I;1;RCRtJez2brP6IlbOWtj1ZPd4B$3XVjw9vjil?IPo>*Gj&TuxBG)a9z-siJy`FzzSv2-Th9nHkrOOlCL zEZ)(X>GWhe(ZyJIx@=y2QJ>qB2H`|s1iFsyXtYiDQ5t(B95ICwi9}4H0XCK_jir)f z(%o%6#hJx$WP66R#ZztB?s;9YCH;NP;Cz_wb##|hkgUI(DhTWEuqs-0S@b6vRKQaT zJw_(xt~cb}4HkqfXtW?~LBxXb7EG|9$%2U%OtPTag2@(4v0$nNM_Vx6f*BUfw4lX; zV=S0u!Lb(1wqT9{7f`)P1TsNl6lE&N?fQSn=Tz+VjQKWrmWM{ zmra<6_aU?ulkF)sB(goWAp6U;MCfFD23RuMVW=RBA(HJW5gKp_2_&)<;J_#*oyMr8 zBo$9|7`!Fz(R4hTToR93V*T}B)^<`V-qjUv%f#C%``o$=x?=M(p2C2ljxo`$Ohs2T z)q(Mm)>Wh`itE6lF8ymttSgc2mIBaD_cSAXaa*TNINcxUG4YJ63qPhD5aNzz zbVPZy8x1LqL6-KFj*q3f;co3p56n9a*782~OvRZ_$Xnm&ZiM*JjH?p`;F_s_GWaR2 z?=OqeXuq?#-VXVSqZYdB4JvokVysVgpo$h0M=dN1cTj50OwG#5m9x(Yn*W?K+l2Dq9*($$3@_Y|8yVe?NZ$l^&9 zc-&KL{)8>aM6@TF&ZLq(ow4GnB5YEGooa)#Z9v(Kd?}Ts^KMh6RX*EOR{3mCS>>}mWtGqNl)maJkDg`# z+SX=0e)mjEDPuv4t=p`v+ZGWwE8@0TakB;#wdf{Nl-0lGErr6CXA6DBEusTi3(IEZ zSua~$;GSLJJ}K{Z&#{HD)PT}C{TfudwBK1=A2zYY(U>i&sp+n0y3@Lo1#a8!O$iJL zXF83eL>mC(Dyug=mAFlAq=fJ!@G5+#UTdW<1G-`Zh z;R0foeG^_8{vNT4@J2`HbjQ}daT&o*dgfeE!pty!~f zYt)R}BPLBE@}*sBteFWOypu7LYz1mjSzy3SY-NGvG65B{ch-1o!A#V^y!|r%vN?G% zO6&EKi&?bsgzZ|1@xW5q(2^!SX4XqQDE_$aZmp-KAaUtby{clu2kAwbK2A(Xk)hyf zz^tQKD7fapqd>u>krz#h_Vh$~a+arL(c2jsYIBzDs%SFaB0F;cQL^EbwLuE~} zCm=KUfTRyfcu>NFec`f#5R@5yP-gZ);X4?1&oTzzz1V_T#wfcN8&EQPFUm)3!Sjg4GX=n&4MN|pt07+KHwgU(p>NmO5HIu_gnon2@6&g?-iCBSzd`6* zee;E_z5xn-yDkU6$R85=A)#;A=@2jShlGAe=!b-UNaPQR{2`%l_1PD;`V1)YTYZLK z4*9YMj`c}W;7y4GO;TQT=ui+Q@?Yg2bY}XY5MSiR2@QeIb&*2yO zt)9a#@>@NJU*xxX4!_86^&EbY-|D$9Z1o&aN(=;FtgW74BEU^ zdHc*sogwcH)EV);0jth{(rm0c!f%^Jz^a=!VAT!KkOMU2ya8K{fYMwoJ7`uCUnlA7 z#BbFL`K1|KHS`8*gTteSxz3AbtmzvQ!O3V)v* zVlHj-0^gF(u2g!1b~~raE1jt<+hR4hPM_hyF>{>X8wlv&oR0mEadPK*{ONOw2jcfw zYQygmT7qAk-@xy3T8`gKX%&8-C!{p_OL2;4v_p-N=9$3Y(#U{YVkiZD%2|8of( zfa460IIsVgQym+B@Lb1_p9J~gJa1zs-t5NnHGRAB|Km=)?BV~9xjx1YzTU&vyZCw^ zU+?5Ugq?i7m#=s8^?ttI(bs$WdRJfX>+7BUC$O`x_xAPfzTV&0JN$Z&-|q73eSW>u zulM@(Zol5|*E{~}vFERM{q?@T-uc&i|9bad@Bix)0QwAoJ_Vr90qBzeZ{eK7Qk(|R z=K=JI0DUGvp9;|D0`$oMeKtU!4zT9~^a%ldM&MJv3TM5_ab62I1LD-x@i@zMCjJ6A zKXtYf)aP69s^BIb<<#PA$q~*noa315T!d2?DV#9D84KqToUk~_S%WhctDHx%7yYjD G+W!IVeN|=v diff --git a/docs/fonts/RobotoMono-Regular.ttf b/docs/fonts/RobotoMono-Regular.ttf deleted file mode 100644 index 495a82ce92ede816ffde602ade57dc02dc7b6314..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113500 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 diff --git a/docs/fonts/Work_Sans_200.svg b/docs/fonts/Work_Sans_200.svg deleted file mode 100644 index 58ab4ba22..000000000 --- a/docs/fonts/Work_Sans_200.svg +++ /dev/null @@ -1,332 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/fonts/Work_Sans_200.ttf b/docs/fonts/Work_Sans_200.ttf deleted file mode 100644 index 68019e1ccdf13bd85696a6b5d957684ebcdd4fc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49752 zcmb@v2YjSexj%l+`%X)rUNVzpCexD4q)ytV&ZhTd)3e#^CY#On%~oJxS(+4C6aiPM zu8N50Rqrf_0xGB%6;v)3kfI`ZE$9`l1<@<) z&vQ-~XN(!}pZw)PI`5$O%aZn_qCD?5hXtx+v7>t#OM7z1+~EVbugCi@$62>y@1@&6bM(?(jByuZi<+GabK5kLyEij-a1y^) z@5BwwyQ(hqcOSm{cJ4cJH22>si}Cv{fXBFZ|NPuB>*hBZ+uw%%jr-<~9+1AC{@?iS zLwon)+`a|tXDc=`cHIN$BYI%};Ugcs=dq76cKz#k{?-GB77mnqKX)hKEkpZ9nZzp4 z?ic%X%%>RV1H4bAQfXCMqd~7uwS`O`gU4_18Y=iL@dG^i z2kGRQy+i!1cskye1*p35HZ4nMp=d!WS4q4_%~j|`#pdwx{$81jSL$@SbX~f^V9;w) z?IFKM>*W#d4az~S%)cLhWK#~$aPy3u9oL!7*T4EI_3?M!SzQ%>1dxhe18!@g zm6=?l;ysKreh9;4hqPS7Bv~WPF_o&nSB;Sj$bISQ>H2g%dPJYP)a(%V)LSvZ;}lusg@8A zMr>;U=Jp{^=f}xEdX+3@Phx77q@Jg_V>pz#OHfN* zUY&v$Wl(`f15(rdPR!1tV7PCgnz04Y^sIICEc=I(D(<(C3INim5f3e%iH97Hb zda|=UbUc@!tM_OMb9|wYFQ-s*=D75*+nw!nyPffnLTk&|-LQ;ZEh|^B%N6WOOYbly z&w}Q&Knrcr^_Y51idr+5##1mGDSS?cnU|-SEcf@Oa;=t4fjrm%>(fIl=uLW)(SS#@ z1YH^o=^zQe#ZyIe>9K&*a0CrrS)Pqg#^ZP9^N;XH;@9$$_zzvi*Bp+w-5zyF~hiFsF)!;!5PoNiYuxY{ITENAp6$a0C81(L3hbP-(v*_&x zd&sRzwT4Uy1}DJbc#7yLDcWe&PZ3u021;+05sN{ zgmRqq1-t=|3L?U%@#c#e$CTT&G|d`|*-DdMW0M9>Y@NKmr~CTJXCltBFAN=RZ9O_P zbm|IM?rH}{YBrz-tdivCMjeYCcu*qx`+sMFIR`@q3!wQ3r2 z13+jrY+A--jrS%Y8|DO$#qT$0F;PB^R>4euAXpJPQ-Qa#$X#ko zHxy*&1^wkC$J@?@d3;)Jt;!3Q8?9!G(Vv%Fnxh*3@ch|>ki<+M#Z2p%frX=m0z?&r zt0M5kB!kLQQW#4yr0BCU&`|5sfPI-Vn}&!{@Qc?F;XnA)r#|}3Gq>G-`>hW?D4o3T z)cv1@#J%ogciwu(nNtj0fR{*Dqc06f8_1dD_jKl94bgRKE@?Q|N}QNhp4LI&_V=a` zu@k8Qii`}#G8`Fp8@e_bpd8W+245Tr=$U68 zQsCmPR$i}w7JtPW|1r%b(R?YOOJk+cFnBxN-#DwC&_xDaaQ%nyB%Hb+gEypu6g&=d3q*IV`Qz-DCwDmo`Vp9qQehb zokmM4Ml~grT?*If1T4^aTCLUyt&M-sIQrC7*Rr-*1;i_gvUzhA7^G+3eRvrV%)f#G z(lHQPLdPglkSBD^S{!vmTWMOLRk#dHor5Hzj1?q7V*^c@8R-c<1H{UP)TEkO1u2h0 z%e=4(PEs%x%U~ucAs3X8!V04S%r&GQpM(98oE~Lj@Iwli0{_VNFbN9q;`3^ndKZ6G zI!06f6_5bElVsH{$SN<3MjMR=Ndvn`1yxUqN)5R&2Vo^m)j>?Q+6<>lliyj>s+f(}A zygvTT_jL{`GHrA`DbzZ5R+c#ue6UgQK``nAd4NRtoJK7XHzt%0AX-iT9Cn-sM+BeJ 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 diff --git a/docs/fonts/Work_Sans_200.woff2 b/docs/fonts/Work_Sans_200.woff2 deleted file mode 100644 index 20c68a75c4268754b7d4b7135b61e5f3f390bc3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21128 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 diff --git a/docs/fonts/Work_Sans_300.eot b/docs/fonts/Work_Sans_300.eot deleted file mode 100644 index ace799382ae503d52310c1713cc8605577306443..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24817 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/fonts/Work_Sans_300.ttf b/docs/fonts/Work_Sans_300.ttf deleted file mode 100644 index 35387c235791512188f3e9c2a51d5465e41d942b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50784 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%0A&*YHR7KP>@p1kA3D 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 GCMlI(>g#O) diff --git a/docs/fonts/Work_Sans_300.woff2 b/docs/fonts/Work_Sans_300.woff2 deleted file mode 100644 index f6e216d64de0aca0ecf31749708002145de48db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21548 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 diff --git a/docs/fonts/Work_Sans_500.svg b/docs/fonts/Work_Sans_500.svg deleted file mode 100644 index 4b030b790..000000000 --- a/docs/fonts/Work_Sans_500.svg +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/fonts/Work_Sans_500.ttf b/docs/fonts/Work_Sans_500.ttf deleted file mode 100644 index 5b8cc5342b5b0975b461e85213cbf54bf7e23e97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54232 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≷;p^qq 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 diff --git a/docs/fonts/Work_Sans_500.woff b/docs/fonts/Work_Sans_500.woff deleted file mode 100644 index df058514fbef579fe76aa47050c0249866c43912..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27900 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 diff --git a/docs/fonts/Work_Sans_500.woff2 b/docs/fonts/Work_Sans_500.woff2 deleted file mode 100644 index b06c54df0b24e4661f1c9e3ac5fbcdd787ece4e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22884 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

  • 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 diff --git a/docs/fonts/Inconsolata.eot b/docs/fonts/Inconsolata.eot deleted file mode 100644 index 0a705d653f6695115dbb13f56684ef17ea071502..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35620 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 diff --git a/docs/fonts/Inconsolata.svg b/docs/fonts/Inconsolata.svg deleted file mode 100644 index b7f97c875..000000000 --- a/docs/fonts/Inconsolata.svg +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/fonts/Inconsolata.ttf b/docs/fonts/Inconsolata.ttf deleted file mode 100644 index 4b8a36d249a05a0fe1575dc3d96ef7079dba6b07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63184 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 diff --git a/docs/fonts/Inconsolata.woff b/docs/fonts/Inconsolata.woff deleted file mode 100644 index 6f39625e58515fc078ae086db6ed81e777934359..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38248 zcmYgXV~{32*S^QLJv+8-+dH;x+ctM>+qS)9+t!Z#&GY{HQhinGTy>D7)0Iy5iJQEb z7ytBkm?=Z8c5AMgRhX4W32 zKb#Bz5VZmToYzr;n7W#q7#ITpasT;Z`wvgHhIHmXp=-w9-qGa8HhK0(@6Qj$r9U?f-GPksO+ThM0s>M3 zg36;T5I{hL5rR#<`}D`ghWh%3rbou7`e2jI_4Q{VBF&fu1O+mzpo2hy1~BN3Prv10 zVW;L`-~9&$2suZRWL^cN0s?>ly@PPq|M}I|2R1Y%L#|K@l59sCXE_x3Zc>X;4hCx zv!G5dXg6+<>*(yGnVM7|hAObQ(sLXZMj$uUC8ctz*YantO%tn{`ew=m5TSfXay ze3&Ax_TXQu4AFn~JeEYN#v+a0McJle-JT3uhTK*;D3k&OwG_zr+RHdRDL+4X2+#j8 z5Mwd_p;V%<$A%el)28Z@Qa23jH_ujaf>sN%cz{>RaAFJASN(-4<3t4Y&TZtLo4ZJE zfd|z2dq5Ty9o2JTwoF~dR~A=o*sx<&WaoSLW=G!Q8>YJ#hCws*V{yrPv)yw4tZa5D z(>*O7oRo*LJ}-12JnImGEzBz8XIcP20FXaV4LShi`x}7Z4&_QZZRXGFieSvc*VRN-2&;OES4T<8EC}T0o{KgT7@?QX2oU*2cHo_mewwLHzJUtpty;&n^~ zW$iz>E3zD$C0#=0iw_tce%+Ru6TAJ^+nZzlF`N;VcHI_V!I}yA@!ohp>fa%fs)H_a zN2+#8TL1E;qPo0g_!(y-`bEf96D>kysBzS~V{*2WR}TIpR-XlY8RpBM4yMmhkc8L< zSgQ9e9Y2#N`Sz}09D4*+&h&!{LdLXz^cYv}?2J5{c2qICeP7OfUyD-@`izZm7Aye|$O%2qC=?N`D2nIT6T8ob&T%caXw(u#Lhprv2qx;(M2 z8i)t&Vii0y2D~540?72900&M)Itd^XXJC}&O_^U&)F-`L6OxogiH0fupa$jy7osUWS3IFEg){5kc zhb`;oxz6#{rN(}{M%R*0Ze9E77Xkv-T58Ffvag+*?B+A*LPyWy*5k_oF1fw*%xCgv z__usbCeH4kTifX*G{<#j4YryTAhd8VNMV2I2Tb+v{06_qP z0Edi2;kXiInSwFu8gU7W@@rOsUb+!m0RE!MctX|uM{-NUuw;!_W7dGx@kNOJ;2cX; z;@FIf`7@gOc`sn;dv*$3#8A_DolCmyLj-3wQwfGbr1oK-p;R9mf*gpB1xKD`=@wSi-B>AsRkB&KFOJM>l?N>Vsd$P;B<0Ny`jZO+m zNYCVQ&7%nhDaJFZSBtaD-S@crwzZ6w8oEd4FRRxa-i(P+qT!l01M_qX<8pnBs1Y&y zCe(9T2)M=_eq-H4>&fmr>d@;kqQ8A1GoR_78GdO^YlEZ`acT_^2HD*ntP8X1;HuRP zT~AnIc%JNnM-n)kTpsBP8`D=u@b&|3uD~jRY5iA1J#XQ+76DmkdMjiep@REXAA(<) z^oc$HZha5$vC(Q-go~xp;JY17pzxR+O+r`}9{!m+;{RMHUWvz&LW2PYeY1 zAw83^E1PgMGrE|a2P8|VtjTIL z+qy;XeAFV;_l9~V+PZ1Uo6nVTuc7=UO=^#AIi%mTc~vM2ySBW7+KXkC(h{djv7K?e z^|3iIU9Ej-wZGC1&>H_1jN%@D_F0!SdV~eS*R(dj5W#LqOT(}**3E06TCChb_NAG% z5cY=$dgSQ8h!%F~dX-vc0C{HDFVY-`Bq+m6L@bz{5L+Uv(6#ti@OD96Zmmn1fBBSg zs=&L)7gfG-wJi-no5EV)NW>Zv;f;-wZo8f1RBF$WL)`DsK5vsY_x9ViB5*$$)(IPv zXbF0nIy*+r`d-Sc00kx6Txe`r*+Uj>7F!F_QIBm9CVj7XN_>ikSG89*Q!2@oC)=0J zhf0?1w`^h5@q;%;bC$2#9IYN@|Z!oSoJFhH!V7zrz0wy&H_CDkXk3&N1ctz=NH-5@&N>XkS zKa9NTzTm#M=QCWeO9p#Nb{X_LZeGRlf%Hj|tj7FGy|D-t=fXy3aZjt;d^PhNM*Mvp zl{4|qu3r4Br>dG42iolSm5!_56lts2hZsbXb>eEX^KHjp+4L@ctw^{nlwMPpH0y=T z2?$^x9m)&xY@g^y?Q8993FqcsRQ23D5@Gl#VMb2Qkh?`_>6f z+9Fvt#a97L7z)x#%mrWF_@c~V%nF{Yv95GCw%{`l1P5RDn<>`xyfZT&70h}Gu(y*H zwfUMC74oXxPVXr6yd%`PcBbe&jk=#9kFBb@t=@V%UTYAvqyqW5=nRZ~3q*Sy3hGlFmY=jS^bT%tMapr6)4w~FNHC-EbyzPsS*^EP1ufc8q^Vs8In;rZ?mkuGe|7q=kK7ih z_zI;wXyH@GST={&up74Ne`8Zc34>Msp_BclAyg6hT#>@h{~x3qC_( zzFzUTTp;>oh5drDCxiLT2!*?HA<`H9dpAC$t~bQDZJ{2g@=6Cf6na&5mktryqxou} zh=CRoF-(yq*B^z~IzSmG6rrJon@m#GCG1~WAfX>!-2_dk;^pxQm9(8!_FveY9&Ji% zb=)Ypnv+^B{B8FgZq*vkm18SnX<@szyX*e`&e~pFqtv5oQ*jUClfy4b&x(|6&omGn zRu=PCC0nRSynVwvr8~_#TgCMXY>G5nb9mwnO}5IB8|;e_jOcxi3R#!g%|1IV=k<%c zLPa*e(Yxq_q64%r3A`2up&HNmr^uL&qeJWI5Qu_?yO9AGULye;ABjrr9pb0W@p>9!_U5?FPz&H zoJA1{CZ9>|Ib`08XeUPE;LF)RbWx4?=azpfM)cs*bVdrtg;I? zs8lt}IXae=Svs&*U3dYn?Vah3_)Sr|)K9+$8_24}&pH+> zT}s+8YCv3pNF1vrOCzVL4R#aTPAbR=$6{&zrU*^(#oGr-KBxG!9!4Tb|GTJpAU9x9?# zT1+|3Aqk8fXa-2!-)Qw6b`s}^+a!RCzR*u@UAX>59*%N*R_4mE)>G2mtjc5J*?A{xcf*nR!|nz&7LSjhb>tw4vrGhpYWhr z+sTi5D*JxvXZ->ZnD0GLe0Mj+y;9>fx$gX&VuywAd$IKTZ86i5QcF)uz{BWOQpsEI zZOzcG-I^^MjN2QM)W)5o53V~^&eMg4Rm2vonB;D}I6;db#a$#`%scOUR!0)Uj;27A zopgzDqei;L3Y{3fqd|btLx+o&gP}|0C+aBKpCw7|Vem)mQ||Tt35I;TO0*EfS8;ORGq*6*JbASdk1wLd)(??)UE=kc# z$wSja70DbN)&0DEh#PN*Q5 zkz8UB%`H);L_-I9Bi5-e^MD2eCU2OhPLq-$2=k!V_?Q{q`QtBCt5wF zUxyvMhEQ5#aRW7^ok*SV2;Rtuap1AN&5U?X*(&;W&$*IEn{a)bw&EPSy|sKc*+iPP zZ7t;B?rqvAaNm*PeW>e8y&|6-ze}(pJ=Ote5OJw($^+FKlcb%dTtcQrmWt>iBjJz{ zMap@=4qOjBHKMbN-ldn|ODY7#f1R@ZR2zeHod(Wn z@|3|fE zj}ETBXo7(_Y6@J;LGaB-;lCz+@s|`@<55hbT7-sxfh;Z=@^J7Xv}GT>#Gm;n6A-!C5=Qej`!m!wi2aTISDKSPAv+ zo?mDtS!QqX^@avgU|yH$8I*smYBDI5G`QH!bC5iE_2o#{X#IOb!7co=>q2R*-6DRG zjERSYN-1jmO71vl_}2({iaXt|6zE~jW`)2BQS6E5SWhmIp3$CWnq(495tIpqV79_% z-UC)SXRcUP0OUo2*@33})E6SILwcU(!|IkXvCRvF;V~e^@^?$dRi12KD^$yG)H{dT z>FTo{=-+m`c|?ahR6LpKQ8pgw_+=WJGH+f0o(aQW(?zY3p0gcWR(0^Yk6p)~; z=Mo<;#J}%meBNJZ8xiQg|EWRKFnXag!mrJ?zD#RFyoyx{DLyezNKW};As_Ui=Ly#r zAb4@t1-tUB2gu%j#SY@lxMZE>Df9^MK;A94x1w`kT&zb;qyDMbeGGD)n08K)*RCtg zAP`TNGj8)BQ*(!AAR(I>&M62^d;&s(!6%s@sS&ISUV}YmttMEs7WN{o;rX9ufw!(zS_0v$&u{K!<=e#z&`juFbDG{n-w9S_-ju)^9VKo31|s z9}#h*xp;OXli2GNzB}rX^Sz%%`I0z;NGOISnH#j zkiI$CnP_$(bBNzPR zH6K$Rbc@$#%TGpGha=Ci;0?T|pJ*ADg!9Xf;E(`fdG{A9&mp3Hs6zM8y24xTsdm4C1*S+qiTb8gput?nY@ZS`q&S{W=P*DcVoOdvR zRDFS!SoOi$4|x(=G$&;oWIc-B5}TCQ=+BW5A`8pwigzA&qzPTilXZW=Z-sX+f;I2? z0_H`^{sH@elO%>FKL&&tpJNSJ=^3)zTTH8=p`pBj{t={}s@sZm#e3()%+=q|Kgz*lqMg4$k|}1;j6@xP2+;#$4K(ov zhJ^u;OFR(*uccviy2|J~i*O!}>JNmF!gfYj6ortJ4<2+@?Xu%cgw=rY4BpecUz``ixr|lQ&>)&gAVy3Sko%yFJTjw;_ABx!k`?eMF3DD`X3Ka)p zrX5T`5lkMCjn8I=8VBqZK-{+i#IMvF2maJ21`iRx3Q|JkPQf5qb{&Nqc^gh!@Ow`4 zL0`EjN^#W)_$jT8IRKF;L_{^`7B}D3=Ii=n&?A6{v_cpB`V`0$YSbUXeOtH0clq)4mhu-*$hhpxcUcLkruDRg6fT;gq?7jHf5okTKFI$It%j zVoA?CtksofWywR}0PRiIf38|&yE2a)LN@sFOy*|2XY0EN(HN9H(BPeaNTb+6yDvKS zgYbOyT3(os8tC-A7LTHhy|?UM;<@JyUG);3hlAk5_^+b}N^dtwjpgP4+5Pf5H%gtq z2IZy%dnzCXy$5OmbRlc1>*n>SHpGw!1xVR$^L!X1eZlCe4=iU+LQid7pAZh@)RJ9x zO9*}gp-ir=Et>+mRT|en+Xm&u2F&*gR4Oeo!di0t+1eCxQF-Y5F(P2OZB-T7-XjIf{+E+01Ze4Gk_m)BJsl9 zr4De287ZWrI&*#MXV~!#uE6Hq88(ne)?UxMY$-&3I!%sj5;+=v?&}6AMmuY}mY;T$ z6xQN)Q!A}(WoUPN!IunicZK{?BRR4qXrRGH)DE<}=rnA~#J;-hszQA~R9o(TZD8?Y z9^OoMRNMWRawn9TIJ|kz$;Kwj*#dYr_1skwTV{kZw%GjkQQdg{%E{f6zEk8orX9SoG-WSDZ!!M(cih(r90$sWmv?OouOB42yJ-KlUqr#zaHnL~eOjGr z<71Pk%+VW!VJs7LpWRL2GBI+}Syg)@NjKv=mC6yZA>ai+A*q^c*sIU;>PCY|0Ol*) zCnjP!+eLUMQ4B2}I!totlBx)}Rs-YRRK@z^r66C737fMh5Q&%lNz`fZgv~bnrQmV? zulF&l=VdF9qEH*@1f}C;Wtfl8tMf}u z>uJx#lYhOOfPdjVAUQ%cN8UoI0_ThfNRL;=kKz;gtZ7FwygL8{G&ZNE!8DG9tU#P4 z%$G$(NcgrqIAC-E0v3Nzpd#ohzbCqpA2#>$b>m3hf#=HSYmCL0{mh%bQ}e#5FSofb zzytCQ9l`lmPVT$FC0Y_+Z|yV-JM--NlLB*aY(nAvm^*D;u#lb3cVCE?OPnz0j$dke zsDCJW6_4gD6i~*Zo3X6E$XVm%pDfKJ#>nLLPRa?jZmYTtJtX zB9sWT^S*oRi6`XIBoXMOpPySF17uhl+v$t^84s-cZnTzqb9hZ&1Fm*MJxb7`(JJ&vp3q2GRnc2V~7HMZd;hsgg|eu~G}YT1E$Q`r>M>k-B&*nif(1 zdFZnS5bV-)MRs%8lvA?d6D4~;l9|AW(OUjiK$;d#YmIH2$9pW8$Q~_)v>Aw=SRjF6 zZgzZryUy$gc~`-2=bu1ReFF_ndl3@vw20q|o3`!b2*>0l6w>nt>D%$w={q1Q;2gv! zf&8}2bL@*3^+*NsQr)dfuY+8bE`$FW^j_T!qcuBDYoudc4?!$<=-o$N7X7BAzrOl> zCgq=C#YXraoBaD>*hEin-1>o)+QDi6tat6gDKSFkly?F4!0xyl(3f%g9@ai}DWxRE zUn+v&1p%$c3c#@0haSz{xP!;Rw-j}HA~!=cp++YIgfDQlPyC(n&Gd9bQ(=%xl+x3I z#Q+^zjZnqqoq@0P=!TZ**lif+wb-2XllQKz03Is)f$rJ6bF6Q@v%F`|o$@|Q zqwb)w1DEP@q^g&Ffq5NAGfflw(9~|Xb9r0jDSYSnD@W7Q!&EVMSDSksPd7Qzl=%X` z=X@e;xrBJqPWN%pxs`nFj6jFrTGqqxXk%I1@qI!hkoIh{sFO}>L)#4Ru*+|dU#8MO zLrUxJFTW;jLZ5DwFHMz#gzD?T(Vb? z+fYatl6Cx$wOF>vt(nD6z_-S)?|WnNi~i*djzDtX1|CEIdbjijVD@7VLI z?A7C5+B6`m0X@vI9db$Km^wlCie1mJB=1pPS%o=`_c$2~$82+n5H&e4af&3SIC^f5 z;nTqQvA_7+Zo%_w&(EfE$@lqv$A~|Q=LBhep_2mmM!%A^Q+h0AntiQxb;stLaMKyD zf)kWfMUe``f$(?$3`3_aL4Z^nFyU{!(wzm`8uozO;9}Yu++m81o9}Y&vfwJm58`0%F)GjW;(Z8QmbfBqO3Us4$ensTH9G zujEZ*}@^$J-kTuIRidz7t5rKh+z#CLIg4{0oUaE zLeNN=kSr-u{QI~}O9EP%s$ljvWz7ZDlQX!JgU6)s`MDNXBvkqd-d)e44?-0IvWJ>w zc%pMotWtqfwY8k{1Nh3;&@+J}=x=;^Es31$&xH!1Htw_e-t0Wy#m0}!b{em!5)q1h zOd)B*K3Pz24(ogj_#0IPAaC$85G>L_!Rf=Lr;aCN@O{vHPReQ)gzB{9kQlV&rW7JV zwxG`hVgA_;aTiN3VJ}er859O;Gf)Zkfu(hZ@L7GFzLj6^D&5C*0~2 zNA=%Gn@26n#Z9t*5t@rtz25NfUb}kTkItP>#zLK~CG)phq>Ou8BqL-Tmt-gZY<6*F z%eH{e_y1X3hp6rPvPm7$zN@hp^3SEo;U4uBVY52msS-`Hc8`jKR0RvY{d0~h<+8ga zfE5nHh_fe#bBPvy&?F-euWv_|qg`v33{y@v#brIqZ05})1MtUM4h@MJ$PN@xNedGm zZ~%(Jx3*vHnu}h9-)6dECSZzc%9xDa4c(HxW#G(n?Mb8R5!jzW35H@GT=f6!!>q&L z5K=%#E|wgQ5RE!6e#w6{nk=*tZq<1UNICMdH8HX~WOviOJDy8;XLr5@Y5efQ_jFfd z?rjgY_um=NXs68>j{J@TP#(KL7Tp8v>e=oQB=XZ?neA7R&v#FBGuL!6nX3qaJs1)O zyH|II%E-}(`3qsV{Mdv1q*uAkat%Y*{OUv-33gj)z8zkj??0b42a*=~nB6i*GViMC z<2=ClY{;@edxRCHVXl~OO?eh>J+HK0;EnQqN=)CWMnc%;-to;GX*->s4%Zs3UT7zC zG}+!!nu=q*|He_+B^iQGm?>&06DY%DMk4os+xMJmUrwGTv0394PFKaqt1(Y6bX})g zX(z5HW!Y)_%K@8fE0y4BTw%E;b`OBQtzRrWWY4&*GP`GcV-qDc^r(U#Movi>GtHuE zIIy!m)PoQgowcOQ)I zkG+u8%}8dGtqew=!DI`t6xTtw1X#(;4}C{~4?o$SB?9}PwBwqhqi z-x_Frh=>(g?tK|aKx?g*D&g<2HWgh#v%~K>`m79!dUy@n@=Lwk9^5Jz$H#U${9VWB z%-*}=I_6Aup@&JN_ir8Qc{T!qx-wx<3{@*N4G9Q+AJ$kS>y1pLe{A|&4+YGuaaU$v z&w-Zs#*Z^;^_D>Vbvhb@ri7n~`arbtp_X!)(JO1cJz)J6$+9%1a}O#Zuq=z}JUxR6 zYuk=AETwXJXw=M9q8i+!yzDg`(z{s5Kp2r#|)zxIrs@DxeH8I#~%;J<(M zmO34`GjGZO&qp%8>7us(9%*gyw6ZYL^ig#9daG;S1)cvTP1aD%n@tKunKP?TkFesb z*~s!QJ6z{patwnoaTjRZ`RD&BDv(A}ksQ`RncN%AAIz^57bd=ZTX`XH zl-IoLe&l$a$lY{5w=j1yZQd=1&BY&{%6g9s+Z)4a0G^P(<#C7eNN#X-!0t z3dH9Axibf%1j7KTM7?sNiIgEK4kvoma3#VZUH+%534V8sE2lb~XcLGUr_t3kKQs+-Rc)G1Vd|0X&$nx92!soVee45BhSmYa~v z0!dJx3Vm9Qp{pMh^QYp1WRY9iEf#36+>kDR-E4p;w^|7i3_7Zf&`2wyaxeXNCynEE zYI;vajb?P5LZ$;bYF+X%9|S}C62+?I0ts}G<05nf+>^s67B3mwpa%#U8?h(Qt}JTn zzbsfLP>z0=xv8|ZEX&lGc5W_`FtLKUv`*nsi@LRIsn1x> zO)C#}M&e)3WxMjgN}wX5?bYCeREYMNw{*K^6su%VJd9^$!EkNp)3OS@W!wcQXn(@; z>~Fr1ZVioWn$UM4#O=V82!KD3XXBin5tU71q>1O_wu>=Zg}@xBueNaU6a=J=ts_e2 zQ+wu{-Q{;1qlTsz=o_D&pBkOMKcmjjb-%AbOBKHd;;6XHS$C+d(J4~H{S6StFHNNa zoUu&ILDf8O*PV#emCI`G))NH_DwTP)GwU*?2sd}Rrknfn-}92*(jHKk%_@uGkh|k5 zc~$ED-(x|Slq1*+pkp9ilId}JY~A|_=k(dMnLgr?mzqOm!98ol6-CRn(XG(`3=BCy zS@A_AGm30)VW65OSz7)faUDi_^%HihOfH zF0~8SF?u;y^=JW+URV_pV+m;>t7agK|B_hX73k9a2(=jGze_~tb%Hvh-T<42-*SP! z`T|0y2cqbT0EOFcE%y}qB(RY{X`ryf{Sm-C*#h!1yS(YtSeHre7OI7?CqNt6UQLV# zAQWS0S?We7O1iU}?{cVT1=*=UyA|E-oVa1<{7mk2$d1gjGmm zOcK314xW0FuZ`XJ@gp#U`4oK^5c8lPo5GIY+9R(?A9ILb#gVa z-euN)wxubPH?;3*t?xdQsk~)Pw98j!5hLkfxwq2$Jo>Ebt9Mm)*8UtQ#D*i_kmcay zAX$(o&1ET>W*jFfN_$W5gzREKntluiJ;PkE2|jM(TYqPn#dd^=9y3++rJ!}W`CX}3P`o1BQim3f+WpH=He~d7gxXsht}2Cv~j4jFH?=L zz+;8*2SE{mcmx@8$Qco)32M0&xRzVSh)UY~PSwIz8tjRoWvl53njo+z!QeX3oxY z>NQZVCE?1}$l6L>%UnxamMb=3F8i~B1xEQhU5UVst`nH=Y}3uNj*=}!Q%A0UrxDse~@5lx6EW3nGEbJF^|>)<%dyG zMn6viKKr;m;_)|URSLqT0R=&iegfyj04U;~D|_px%^OGnt5Pozl(1yan=lXI^#2(u zU=X#|zCOuFr8g`AVTKHfFhG(B4pb!}E1F7s&?huFz)kWD1FIC?W9|Tg0HFBuD;@yv zI?xIrbnKR$r9q)#_`&<*o}=!A+VVobAnPM+-IPhbvc?80mx6S?PLT7x`Fd4huKV2+ zbBBew(Vex1Y98z#BWxm{QVp>#*fEL6Ai6gi{8hUw;=G4FYfD{Ak8F&w^oALE;@BPa zf5f~|?L&os1_1|B^p(a@@^|PX6tHjE(ueFCV%P$qLym5BpdSg@qs3kgLxmU=L?c7pW>0hzkOL4CxJry-RBd zOnXhEgkDSJQ*;2D?An#>{u|5YeZSW442hk|s_UT`a1ML>N#T5(1d(WX6|)U&tUZk9 zJ`+OZsRD6I*r(%%R%wMsbsTF@o^O5i(1x?%RKi!Wb(uNMgn}2P2?Ilu@U<-DH@|PNfDbis2$+hm|l@ zp)i6p?uC~i(04s%3=`n)7gZbarV-4wG1=t11j&xnE1-I0)%nli!IgTs;(`)P;qvQv zBadBVCoqM1xrocl|4VH3C1THL|4+cPF8T)O$W@*k3M~}Ox3UA|DgjJYi{^HSGHSV? z$#}Gnq{(c6?xudOxK(+z0&l}itFF28tdW@dDpHd6-9i9kc7TUI3QKHDyIW^OvfcgV zQ+RXE5lE7SnZBMtQSNR}9wf@;$nVr?iM_e(YaiQ(UkJ9(m-mD*;%=Z%`*V2x-GWHT z{!X^Di^jYL7j;W$gX?OH*{3osV83FtkSXZtn`myJBQix(h8em`8_7*DM6F6%Gx5^C zW&^n=`t_fuqtLbk3o_Y(5zzB@KKeoSjAB_t=JD~A--$U%Q<2;2x;LlU2xYTP=se*7>qmIGpr7)K3DlU~_i%lucl?#^jrbt>A^MQ~S zZk7hXF%MW*9<()vUem)%&9a(F`J)V$@e-g$fEbW0;y#rFWtYXaWeGI5c@9bbUSGA? z&@vUjBRQn?D1Z9A{V(kgvcJACzs!pAIm$=-aJ$i(`{fo3Mv;U_bV&q0$| z-+(5qSyw!nvcOlWaaghcYa{(-}bY9yT50~fRU3lEEC0GD`(G5j(-AQZZgGx&>BD%|*VY1+I`=B?*U)z&`ZmvWbz0fb(^(?{J-^&_}MT78~*d z@u>-ig|iPL$u&5gCxQjPpu-EEcvkF;i;#~njCr%o!%0pM$)M`jg6D1cSe3#S+A#__ zr)D{n5)j9m&>d>PmkosKVi^U^L9SrW zDT#k+hTQhz_L)@uqTS3@O%4FePrj~DSmpymFCy}2FeW*yQSfO@bMmm!*_<0{m3}`q z`=R%~<u2a{%MR}8iplCRI>+%ZrYIj61W;gzi3tJsgvzq&Gd*Sgbu3=iH?b_=};}k@X zz-*`U%MUcd>PU!G9gHd9D)S#>6~!(ve~2d0C z6SIF4h*WV4bQQCz%<&{tDzpc+9fS!7I!Tl3Rt$6qN|-%uA;+N5DjqxGG7F*nXCVEx zOGjCtvE*Yr^Xi2Jz+RYk!TMfF)cMLMDHFKYh|Tx4JdNLQ{mpI^e}UZ+oiGWqT2W<+ zbb-+~8}8WgTBBM0`Gl~JOy%hUl+!5rPs&OlakO<3Zoqx^C_%87EX5DbX4GZeyh&~8 zxY4iLkG`kIZf9SPceL1PY%TP5UGdwP=GL<$Hz#KfR7 zmRU=8a^stz`%NLyasdAdV*b0)l{=}80Hterk7n#BXoG(jNP0lp@ZR#w#ez+{9j->Q z#7O_7IawI=-{t)b@YKIS_`Y1!ECa%oF3e~jf3mFTlNf& zfagAov&dyWO;zj6Eg(L3D|m;8xKcEK+xZHOxeH_sp$%jo$79Ar0AbKH(s!s~8V?t+hc-h2jYWh#3?F5M1!1;cA|e=H1^yJ>J_PbHKI5_>!?W=(cv-r)FXArskp3FXPjV zn?~P-bTn$&S2ER?bF@75Hm+dy@4(zz+-gm7&yrZgI!RA$u*TvgP4hO{5^-@aF4dXi ztrg9!VeZc4=GbFlXsqZE-kuk6KU5se9q1AW(ZfM~rg}O8jKz3epfBYq4{+x&ZSvQuW zu+iQkV+k2&W{c8dP31{^Sj~rA5QLn*#7jd_Zx^0H#Dk1Evu`C@&lw)tUWoVZRxEX0 zS{i{9b7%>_4+Kjh*`@8%#Rx#S4aYJ58|MU+1=5u;oGc-LzPb;jSk;Yi@j&&FBq(Fq z=acpHH(oDiG~&KduP*KxrmGLF%q^@DF0~Z{N?q2D9sQ4K%x_t7v%y(SDY~n02DZ;Y zOv`I{Sd7MQoOQdKm=RCao||5*O$k)BhMV_JTWTwtb=CbSSL0BkPb)9a8%@N|7AfL) zO~b#Wz$oBtHSZ`w5-%5#r$p&K%GSfrvJtGBT-U&M37udqYr~q{9r_^P4}aN@?o6%K z=hf6CpOwIt;Lf|H7CfVFcP@|4rC4hYwUD3gGGMUP)y)~+6qv<lYeM(uBK>f_i=f9!@GpI4BSOjg?^44rB3)IK@g@u33?!``j_0BH_${l zSWe`HMacnPw5@`}GPI{2ITAJiz4#S@m$k>-(pwR!2hzSy-_l#qq3b}YxEUl$woe#z zbcCWbK-6d#2^W`xN#L@R)mm4QZZG z4N7@@h)dhmDS);NAM0h_zs+U;v~N6M94KOJA5iE>tY&O~3D0NPE`p?FJctD1`;$1Y zU;u@b@G!(wuLKKiRnN>=CAuGfgQCn_U98IBw4Nsepa2?ytjMX6!Fb5)WT@+`A=Ei9 znQG`h+D_1=8kQiyMDuU<*9|-$FHVv^`ynqO-HC|R4`Z36fXGx0%XT86k_F1}QDY(P zHz@dN4@Pevq8+`A+>`S>iCoc5YzLt1aLs_o0cWbon6oj4W(t>kE%j{4dDI&roV^!R zzH+Xz1s_MYh>__8iqlUi@B04&=s7x3aX9<#kQUd?O`BM#<`lbc4^K~*7g}>VAOBTT zA!q$f$oezZ5b8BHzxcU9@p}q)2L4uWonh_Iq6-0nJ0h8#UQ1eaK=MKgtme4w^x8x5 z@-SKUNRfq{`v>jkojylK1UFO5A5o3cUMCeb3zbSc(F*1aSab}L)XVET;|?JhTcpek zlkTi*v)o3K?7zzX4Fh(wmIcR#*CKT5NzYhBbeX~pqK?}F;v+^dW}920;!b=wnpu(0 ztnVcdg%)OgB{p(k12O~H4&l3))q+AYHLGB!8qk=Uz)udWl2YN|xwcaENbO)`#PY!U zbmIQovVAd!hv_4B-pbQDF~O&VL*z6@kRW@|_%1Sn2!q0d#F$LWxI;R#dP~Ar+VxyK zW~z$oMt{?!j}4en!>7~WXkgvc>uR{oeuc`7C^f)pnV)Ez?X*u@tKy?bfg>}eeQT7F zakf7c_h^$>td`G8Y|LKCkb~P!i*n8X-D?Rhjeiag!%Tu*Kg&H?*9l4Zd)As}RJ4+Q z87<#iS%oCgoaCdpNq-93db?y7*&uf3OLpfEXGzGz9m#t0(Rf+bs_F~7V41C7uUYU% zHR{|5bk(46l%FGv6(|9S57s57{6ig8p*RRqUHW1_<=RYj9U~z6F|r4upzovq-3uUjEf47K*U^02tjhNII$)8 zP;h@xqRI&J$_QG6(O_$kDkDyn5&vTRPvfYJIC##HdFp}l5QwV7d;g&R7Co5WT(*xI zaic~es1apO0wdwN4>jULjWEUM*%|YB^A+kf6X+|K;m!F===^^{Kug+r?{ILLorWZ| zVadbI@aEL&Xa6(Uwm7|}vnVsQ-R1VR^gi>9#m#FtLN$C-=V-wr4lb1SMvK9)U>W=L ze_F!sdUZoTl;l*e(YUp;KT~vtp&>l+n)Pk#bt|@8^Qa1c)9{^!s_;^9p?4s46!0Jp zuOW2-ki?-xQ2o5&kMT@HZI~EiI^3_L8+=H0Q3__+m()L0V-ixchH~&@4VBsl0B+b* zKBs?C59YhR;URaQ5lRpQHJ`2%UpKyB{9C9De-bB0jBDx}?V8GPG%IG;ops-b8A%9AP0Y$)x$rOD%q%gYTJk>HkIhZ-< z?|f71UC4{+Qmw*))L3La>B`9muw4(nT3E@%* zmqMpPbScF5r4?Nmgq~|eRXw_lPE^coX?IeMSc_JW2I{2^=gN)dn>~@tWfL|u&MJ~R z%`K>>Xi5p=O+)CFC4d`{!pm&R48v%K;WuGR9jBvIy2g;LbfYGR0ow_xcWUp4#Pu;q z%E&SlY3>Yc$TY_)Z4Bw{raegi9wwzuf~w1$f`0k^+->ku3U#;ChdCu}p z#!Kr!{`UcrfI9%o0G|Ln1?a{bcbg8F@F2Ya?T4w#?coS}55*L?F?CVjOE0#z2SY7t zQ#n>_78k3{W`oJ^G%j)Zy)A6A#TQA3!l@V~mm}X&5x~F6MW!@i` z5{y${@CZMt7zNl^)io~A2|P+CxTRs6_By3d=caj?yh70+G`EM4xuH5cwoyRZ~!&G^{lt+N&Zsm>T*1c*YG;ywHw z@zSBg>{58?uY*PKDBxMZdU=kLJy(Ex%|Zlcz_N;#&UFU51*2*nRzQPqj@IxgEbv54 zvsFYF759kL;UH`PyF~(JZfyRqNZ^KQc5B3jgX}%%`8$kzjo?{F8(y4*$~F;PGJprL z2XLOhLE0nX4bm0-?9}YTw$#hB(e6c-*HFE$&Y!PiZhVee*6a(#>D-EPELvWfZ@#HF zp6I)I+>>q#1juzWT>nEChW#V?n=O^s48)QHYdSja8c6*lzog*x78W&S7q|L7EsHsS zdo6pJ+QBKLSW86@e%sp(j+(`ZzFX6Obtnc9QBe8yfN{VepcNvzTL{2oaZRD3L$idZ zvld{pI5qmYoHtSC6Oo;ZNsf6%uALrLn(Z>*t!q%TnmrnkYmPLU$D_r0?H=tM9`tS# z9s+DP@t&{7Gn&g9aaLZ{ZQ9*haaL}X9Y*dy3n{=p0CbbV#{&m@Huu_Ek#zju*!{}~t(n2r zHSZVA6vaVVE9a8D6aCoktp`lno)I9vo3S_tGhAVGEC~jT_#s8zuo>J!*-dx=()y=0F$q z*XT!CPwfNjv@kkrxn`-$1$J2XT4BR(1v5H~B@uy8x4}Y&6Fc;K^#|dOp6`9=5yM_= zowr-|STL?ES1g#3tT%)e7_^Sv4pGUBVGf_g4)wUvG7W!&X|`?Yh-+m&v#cW&EsZwa zk=1i%k$vDx zGzU0^N<~AXr)qIVoZx3-{JcG5=!jDjif?~tZE7%RG;s3=?UU+7?KSFi!ki(}7(8=1 zo1)CwUoz|tF*-~%ZQC7kZC)r#BcL`A$BGcNp-#_9mvOEn4ddJiE0^t|3v+*r2o<4l zyb|}V5M6h7E^mz)>@IR5+ne`~vdJ~A9qr33PO~=Bu{imfvKH$hKJN+o?jH7T#o2*9 zvJ+DrL3P}D3O*$_cW^cOj)uTwyhCBycg)s`Z33le@S2QswPMSVnaq%qtZSIh(j~4Q zYb$g0*i8+mV?MwT0oRtLhoK;QDmWFShw<||woa`mpIqc{(>p(3D_ zU<5G9Q*8tn04D+00FMB?T?A!-x0{a&`I-#wvl*)&lp_r|pcD(>U~@F+D;H51uP0kC z3>WE4Je`@yoX$wKGF_Wpu+iBCJ3&yr&~~*AwjDU(L4nfUND+`cXr{LSPs86aHh4Ek zVY;D%%f@rEXkVOjkgp=6znES<>~9}x{=J)(I0zz~W4}!PcqwW+xpu(VIiiIV0qTw_4u+VRPd|tg*^| zo6_UXm_R8_*Gw43uB$Hk8FjC9)6c8!H|a;Hj=I*mV8i5sq8Q);wY8&!2%E&TR?iU5 zrAs6zCl>Z!k^shd-~c&!i3SQ~_p;HE#ga<>p^u77Oggjb!+mRSZe5&qHT86ieIU7I zc^|LCg(NFI!6t>U@Y9MJws>y~*HLj6EOTE26bZ1pf^LcPs4&d-Mm()H zx{YaLw{ge_;gx19y03Mrdd_;;Dk@VZ&e*0Z7l~NTYNFY#f}YC2nc$1ChNaz$d>+B0 zm2cztn_4I_Y5xt&s6Wwu4a=y9acWe%7HJ(Ue#?fTUc`@(W>Si8vCwz6?i7pc07-4nn0`7n=1lC73diBq2c(vN*wxw;|wjtYU+XkCvE4Vx^Y6jP38pJqo zPt`^?n!`H<&$HB1y_dbp86REtz3H3fU)?yzmkpFyb%Ixsc;X=g_!-#cdyzjFiylQy zkw-n^R`GBE{haGX7u3_-aQrFJF5J7pi$${+>t(+l%cBE`q6rQsFh~G zN;iM2s)q>`*PnAVa($=oec_5p&7S&F?qa zbkY(_+OzbITNbfN6$zqM;`DL0bo#H>d~8LV&+_qq{}{_oU*O}aNN|?=f(`7f>ush9jxPU@9Ni}5ZA{LMyCm~p@$ovXQZh7V_Y_5~HJ^;MTtKg4|S zCDk)HxdHZBKUHC;EUR3ql&VX$OeJrHD#EJ*&h8ZU2}&GGnLOhP8wIhhn*1umbwv{p z;VEP)RGE#iHEbh1fZU^j!iff|Cx9qm5a&cm!-Haocw8%b#jIEsM?`t+pkFsa2NlQRd9i$?3wX0#>kuvVriP79f=!Y`{nrhW=c z%S}+a_%Ai?)vNvLoVr)NTrHEGhk7?ISJkkLR{x{=-_+7cgsWaYFWLtrr=z8*MMs}gU_I-^RG3~wRyCfxymv+_@sbI5pcsO>#~T2 zjC@swIk1`$XmCl3OFDoavOmKW1Ge+-hU33C0Y3m-K^?wmc*XFBK_UfZ(m8{&Qic?i zA6)(?M{fJ<_S^pKtE;xN$$x&UQn~ssM-^J{CjS4+)F+edk#E}Mq>6;UNi4FG)X|c> z5`3Wh4+@_Y#G0;hk1&ck0G3;D)K+Pt_MaHltkrDN(3*9?hR1ExGTNk#i_!TsnZ|Um z&4g=6okz+IcoFb<0&WTTGb3tp=A1w^c|Vv^Hg1yYDb6zmBT+$NNEcYCh<*01PsKh^M^ z@NuNRLr`6=ze^8ls)v#cx}jg6!-@Z@>pm+w-&LpzV_S?ZzfWpH8f2}~1X5N;Y8dc+ zz_;g7^>#Nl;+Ft_OHj=iO4Q?PO5RZLM%39~qvUP;%}U<0mAP3%nfn(tRqcP3(0~&3 zo+X-8P=sdyF93c>AXGMrC?VjvhLq$m!7L5$VRj!`cUqv~y@dtHOUPu~^wZGrUaO3` zuIuk-2gT0_ap5VhV|z)79|8`tj~Nk_8vrbyZP!NrAg zd(X)K>UnTzb1Jy&j-{Ptji;H{!^P{HSWx_;APGK_l}I&N2_`v3!CWkIIY;8+k|p97 zfB8@RnR}@2PEp-ug+J#$o~LTn7pG_zNp z;?gQ0t8p^X@Ob!~5sLk$bEeBCC?Ig%;0(Cb1VW`u#}n{6a}ihH#MS3;^)vyiSCN`( zOpQ8Jl-x4VJgC=dSY)?Jtu0Phz98MQ`nHlgU^B=~(j8+`d&i1MeC1#hdwHa%y3;GJ?Z$wfQFNjw~=(}6M$Re^Kbt&=$`A43pCXQx~E7)+zqFGT$A(ecJF9B z(Pp9GuxVex7>y_G@m6yx)xuWCGVLC7IvPvc<35YelI8r!D(wmL;-3me+7*6=dJ(z( zCR58@;-lgdqD-q*a)GXWU5ka6mb*aLuGenSKBV2Rl@UUWE2yJ0X(7rUG<+>s4SqNH z{oua`<(cd+>l{xNV09Tto!x*PCYIMO1dt_(aYK6Sh~ubKqLn0fRQaMU>G7nJUZ2+! z6h+zIZefxn1;vup=S?QPp2T}EXY+=Lvy-`|-?GFL5q%<6li43*-yz$zh>&H^S8RUx z->^Ypk)Rs!7vaTmm7hnL_H!Yg8|xQ>aW|jQy@HZ-kyO|Php8@~tH~v8t)6zBb3w{W zC$VVps-S%Xpj9L?((wF1uW4pADd)^C)s0Y|PJTcdp#pv)f*U_k2V+)e3Ab+2K{8(szcJ>beb zZ#aj{&j8MakOHhp!mnlKct%8)*v;pNIC#JdaeFw2DkE`TNJ5jT=_8dShnaebn}wEW znf|7xW|b<`Qdm(=E_y&~=`pWZ8|%HTy(1s(%(zP877cAYZnG@xksPXoY5ISb+lIGj zwz@w3zT#~IX>t0)>@LyY+?N=-htrD8^`EeFWH+;bt*HnlDX*+Qca^BpOWcVR{fxIx zk*^Rw4VeslS828L^{lm~@`6}rg(>dD0unCJ;0U!NKi@Pp-c+o#x0digyLG&S_^QQ9 zSE;o@j{9lU^n)BX6w$S{gDf3nanKK@Dj`U7#nc~Dygh(ILr2|ni4e8}I0#x(C7-JniWPyOn@xZYZI9XaXP#z}eU{6w(uM1nz~# zbB1PtnhqNKpUqm?=uNmXQHS<}t4&Fb-KftN3f5HI-_>C*balF#hy5PES))o=7I$jk zI(@m=U(#CD4s*B|^<{g?O)GmDGg(Z*&Yan1PWKp0B(<<79&TDv^eb^dgs-u2 z(LxlmP1QksLC~(S64fTG1OihIM7}Fj8v-~`bK7VgKbRQNt_O;Gg+ z8EkqE^6m3UVNw8t_FVznV-54L3@edwL>1OyaLy!RWd+!TmG1*G!E?1}j`YA8&3Vlg z&CfNo(a>oq?O! zH{xWZ@aj70nsmX7m}`>@k89kDOhH9yY>ckDf8nOAM%@e-JrFUJJhW0j>%q7JoFtgI z=(*;3*MpE!Fi$$_J?Vwjv==)=A2?fpkq}*48`>12k2(^DDr@fNMX|$rC2f3cw`5g%;4D z1)$GJ??agCUzjDj43=~XY6EJE+XB~a7KU22T(DfV{DK;&denN-ih8o5Q`zXo<+i(Q zWKKKkT$vv{pp#4eRR4CskmP z0^Bu=YFyA^HG)l<4(tnL>ZEyvn?brRRU#lI11>O8=laK(tth~_qQJj4{32G|IDaNi9O%l0Y%chTi{;2;uyH^5#E$c=`X@ zO@Eetk^YEV$f2=n`h=@zp!|Uklm~iTp!+lSTpA&VcsYY=g^kmQxgzjAX;Cq1P-4$0 z+b{>&7t>a333g-CU!Gpf?xy?}U4Mz}m7f#_g;nCq6=x^>{B>dh1`s-(H%!qkF>Iv) zZvlFgYduA7PvCQQ(h=hCc3O`ur4t_CQod+Z?ur%1WM_h~O)FNdII2>Nc znd-wJBLF{O7_c318t^p1_^|a@8$I9|ZmUh5aWWu45l<1o{c@8?WwS1-3BJ$D7i2`O z8g6{qsRixfc>VlHGEz|*sYVkd+6ln5Y- z519Q?M+?9DWuxu*D8LB5=SbtD_LWh6eaHZx;pxlZyC(XP?$6+p-oV#v7{Vt3x`(ld zgIKsBI>s)pZcdPHCeWgccB3bR)?J=*}p6Sos(-a%@ zw+tjZ?v8Y-Maf`^w6%2`{Dt^UgDoivh}$1;yZw~Y*H*ImwaK<_akyPpn|uzV(G|3M zg8`?#c_`dv$}f$Tvz~lzfv7gv&7nff7VtRrzTTEt$&?)pksU$tUo~-eEN>+}R7XoJ z>kvd?i`dEb@OVi+;g80(JR<&e&=!jb=AOttR(Teww<$HDgh-OOfX79gDYEpm&<)ou zxZi@iEV!Ri6N>IT4CrMNJY&Hl5L6$M_sftU(US(c^=-hj*dkvyAP-7`!q~Zs6EBgw zSwX`*GY?K%!cOQ>JHLfQDCBaAk65T(!cJ$zf<%b4+LgHbX2HS!L$nJip)9PF?jCO` zj+e+T2>syR65?kd6>cdhA$%t84Q~$b3R8b8hOsXu88_Iwx4754w}2tbL$F%ikhc+F zv&yD0uuW=&@xd;%#d>U^2Aig1BO2P-W{czPmnw<&EaxH>tG6W9Q`iew)oy0H*rTwj zjldyOg2<2b4*fuTz39Wja+R+hpiHKlXzo2`r#pP8{fVfn)ivmnNG61Nr`>w2NA=El z)_QD-O7V9Z02?X*hv^dW=!2s{k&c6t!HYDMCdyF+ZlJ{T(U+pHB2nk?O&m@iPoGIs zp-O4!LuV)(>{QP{|Dv43!Y_9+H<_cOcXM>@Nd83rY+j;7@kH@#5jVBsrq+|KldW{r z-HC-z=kd-nosi^oBD=2RU1z%J=%-~Uca$f}r^|Gd?n9uSzF``P)$aZw48q6zQ41K6 zrT*dmv3{9u7#tqNl|h&j4UP@M)6$~!BKj#U8eSyQ$wgy0DlZ#Z2HT-!;5{#ET872? z5Tq4DqeDZGL zaC8incRYF~dLD_1*y-507-}PZB7HWE+DM}|GAA>W8B|#YRhC1TbDZ}L>%VG7k zoYiZsIYtFZuW!meQ9s0;A%~}=~ME3bk6_X5Bo5vgt*e$-e)0;IkyA~%S zT^Wxz+ve|H);9dX_BD&r>BVc>+tw`3{G@55I}+(0Y08dtN9mWXaA@?j$JOgS37WKqKGGcdvfVoQkPAb1FAAp2Kx;Ao4}w zh82q$u3BguYruj9nl5pD2&^Zq#fo2J<&3f7u>jpPhNavL*A!hEaw)==EngUox8E_aY@kpsEg9&JHe1b-HCK+CV^LE)?EEELH~r`A z>aER9WpUwv{?%B1VLsQdl~||BLbCFh-kl7b?M6&%;xhd;+b^gElkf;vO42BS0Y$Lw zvD#J~(u&yoP65p58+Xn=eT z%_bD33Tf*Ec59;)FsfAYVAGOOe%^gNv-6?sS0)bP=d17ianrUhW{-N5AAt#X3twSh zrPZ!1_|XHzOUEQ0FRoY%blUL0(-pg$Eg77CkKO&(yRKgshMA8&%gBkH0K;=tV_vcg zX`xf-lXg;lK&R?n8>`7p*Abu&yc#9ql7@VvYHUixph__VPrwA@&9qf$MqK>nC!1mA z(@e8T#(J!iZZCE=0DDg<-d`DLK%)XQ;cKEy%Rz3xc437rDF~i4_6mb zy;I35q3*IYZDrSIsY)}Klo$UE0a9BhR%PzZYzA?A6sI~ee4gtlR=0FK)FG1PSjX%1 zQz>@v^BKfX#5C2bf>!0RK4rFg8iHi(A@fPhe{Kqyr(IF-*T3udHs zXLU&H*p0|`5Z=-KV1mG25b@^B$_iBRI04b2oziYs+64mW8g_xIxk2IF!*0whZpj1cn2ca{^;HDn~}Z0rW?55ggGR3+JFwm_NnV z#Bhpy|Kd~ER+G;3W(EKc)EbI z1!$E4jsvz8aR@kEnhZrjGC1c^NT9j7N{vb zCLBG2C1AqQW5O{XH=i*}wQ4PagK^k`tnD`>I3un#E_|7L#Ema=H@Q(^{xs@sD6o1) zy_F)v5maAf3>D^zrlRzNSru&(V^rI*v3k9sVw1TURW_1ZgSz@e4$j#CPXqP;mY^V4ULBjSMv__zx zV}fGx|?Z!-$k?}CcH9k#GRGM4Z}@LQ+_oc)ls5V@MWN(D7c!p zVNqZO3ASvm)s=N4I-b^N^@uac z)8?$XY#t##qcA%ouL`j(M^rp5XXUay@*6YqSQLw1)jFnZwHocDX*f{AriEI zr{!Cso+m{lTA6jl#T1|$!^7Jz3h0vKY% z>2e0=F~RVah74k;9#hvmeF*$aWwn}M81Mr+>6j4&mXuRqRS(4n(pBMsV5yyOdb8)| zPG2GE(v!loKX03m4YD+SEzs8z^!u`rzL+G7VlLBc3+H^ai%a;NDTi*LIoTU`JDbSg zdroCiQ5|g&{+k^TKPwc4_aN`L({9y{Ngp6{!4x)}F(nl%R@DCkWwH9$Yd!c<4vRJbNia9pas?)WkEf&_;W z{mCowM#=M^@s>*yx3sKp+0r7dYk!XmSg#R zXR%3Z*2;RhB~4xjQpqmyvv4&K$ZO@csJAIU126dZ5^4{tXNSJnyWRYvvRMB82O|^p;oNRn@P>v(#%c1B4FP_QzWG*N<3|v zFhR8;!yuhd^chcTC$%!^qMDwkODQKdMT(w#M$OUb)Fe6=s-Ur5a}`a#qS?o@=8#$) zNOeRDD%-MDYQW4EO0uky7Fz=eha(xX4Ssx?*JSJ{wM1#hmFU^pV=fQfJhH%keflT4 zuBcfQZL!Xzj_DMikAKOk#OJXIh!K8FRC9fG`O+~ph6QLCI5o5FjTK*sN^m;#WesFt zN*pp<%{+otdsp_Q7qtd`eeYXFCdUc!Ywz8|c8lR6`OjKd^z(N8CbP2~`+{H;f)!CK zdG6jH=#GGjH%-e_y|9dti8hi|SedYQp_7LUj5WYYy2J#pc6uF;@7S2lC zavYg2&G2ENpKUx1Yb3sX6X8&k({qkCd|&m0+K)pS`~kyu=$W~#L|3aDG}|;{U5Br_ z$*{A2Nv4HBiBv05bPPg_KsHG}vKdsv4M5fWrmq8I2ru<})NyV4M552#8YAUbW0VpBvgtK+d#u~~LqD1e0) z{T3LxTEH`-6t`oQxQdh?Ka>r*Wr*HF>$hVGiI0R6(plJVAsQR;Oc0IjJi@ZUP#33- zB_sW0?PWV$z}P40N2vSsJ*Q#y2NA{%KTyWR{l+pLJ7GF&0z1n#X}f5X8rht%pQRrM zI_3;R)KVjaa%Wni*?2wi0>Tk8$noV$^xNclJk{NuOm%ln@l9+cx2!GbEi7rylgS(z z^!&xr{{F#%{sl{?4|b#NX76D?Jgz}6M6bifRIz2$U_3!^qv7fk0{1A5O|8HK>a)6& zZC$bYgzj0aw6E(hi4kDL8Muha1d$NZ8jf0O>XeHbI#ZIBAEx_i_Mx2_cGFigyLM*Y z^Bm27aa+?LD?faHDPMn{{ge0<=YZM-FWU(v8$I_e=A><);M6P9n2LZQB$A+l&rYr4 zpooC@B&roe1ef5_Dspb!$5ybr*@qxAeU-h*{tJ#z^~}$5*hxb# z8{oOG-(IAlWG`mF|!}NJ{PKh6e0yu{VdWYL$)a+G#G0+c1W!1Ljp`5sZ<_ zJ(!qXR&KA0rH$9=-~+{5#QY=A_Jj-4rN30s$@*GsvS+DkkEvB4cmY^Oio#3d`M=578YS=3(r{BCw?CkjTiBT5%=oX`MdJY?1c%!XN(8 z``-7%j+;y$vWiCo@2z3M7gIOi9NM*A+%f&Xf9&-2f-gmFdYt`;w`o==ifYbbDvsx9 zy@3|Z8*44P9veS_pxP=73LhsRR%ljAo!Vv4G#MQ@D1!bqA0SKU7|zAJade->%=Ie;oPjwH&m-^vi<&Hsc#BcOd8C z@L2c(${F3OG;b2k)Q^}`4wU`r;}FEMa6m-MaNV6=tZWg_0mCu z(oJDVER(Q7V)J)X;)=R!WFoDk(#47~twYMf`zBU_Ei}G5+!mbdps%tX>!QmELY%vAsm^dg;j$UGC-H z_DWVNYGq*Y0$iqh2YLTStcDG0>QzIU)tU_&B)GK~B}QG)>OsPdpjMPv?77YJ0T1=O zk`Fpi0qTDKa4y^%#m^0Sw zU0NWs2$eZ%3$?`3YNJ{<%F$3X*b)lm*vdK~R=U1;&g_ZU-Eoa7<8#LR=FXhTqB0vp z4lijBiOgrUMbhE+>7g2>#@gWef3gWKPc2fMLldF|b5qA%E`qShrN|iJYN8g2x1oJJ zNAVcC$d%UtdwhyF%8bm#0L7_!w2rNGV7;Mr429#$j}7o}0oCKsrHU_vEp7E--(%Qc zCaobHolH(9F}re8a_nY{B#0>T-PyzeGx(Zoxg>e8swT*;cY7OzD&_T&~9 zyv49PXk8?k0-j{RMo#^5qh79Y9gEYhW4g1g1eMCpB|f{S5Y6R0v1rnp?h3gxL0d6P zJberNh)NzY%{7nI!iB4X5E|53%~5l!c@Q62G=rj{5+5?7Y6U@<=edhN76c=|1NYKx z^W1a(r-Iy*pZsfp*TFIr!*N;Pj7s{xMz{v7bHHJ?%wiZLqPWi;7% ztY6Nd<0|VLT<9QxX8>mbKLex*po%=m$JG1>mTV~#UJbYe_*=jb;4y#-)@^1tC+%k1U71grQAN}z z@VEsEWLW*0Yf--$?J6Rs#IR{kV;6#9* z3$6)n3?k;#!QheLi6G8FF#SMudvs6q@#x{`@hCqRgO{G|u|2WJV~1nMV>maIT%FvI z+?GTnv!|02NiBsYN}W$(z*I91h)tG1RoC`4j%utr2-p&V`@igZ|Y#`Na{q2N-&waNF{L0*ta<{ z8V3bfNoW#|x_eGOC;Y_b^Vw`(@6t85-1XMTveW&`&L@gyUz|jaK66q0iQnn)`yEdI zd;k5TAF*BUJvMP%{IIG$VUKvtW^crv=)itXB?#=_NoUX^IE23=)mJHBi}F|*L*Lz? zM4g2e;gbzVLQ#Oh!uJ=3Vns9{1$u61g#K46=hVeo97AmC>{Hlyq-=`YJjZ;>f(;K) zjI*99D#o)>6)O?wBWe)UmfPtdB9anK0a4EAB!ti+x)b`*4vP}hysjD8g}O^f9cNka z>wox%M=$?=_uwxKn?5dXS@`#ZR~8;UDz;A_gWVAES6-pm<-OvtOq;`I4%Lmpn>*cAW5} zu1^1Lt@141+6q;6+m!+E$@m!ZW-Qd1q?nS)f zlYCyyHsvN14gXB00N(EXWr{-+>mcTmQA zQM}ibf+B;N_qrPQo|6P2g)+W|;ypo7_ZIbIq@&JOO7jvcys?^43b$5q?UfON0=gQe^Gg3eSa zky*a0t!=P>{Rh{sAKoNxF5Lc!;g+>GEwDORp||&)&u`oD$lv!;8}fMcd>z=PtOI31 zuu{-%D&;Qoqvj{flG0yzOm^Nc+8h1LRkh}$dAKix3c@Y<^_1pqJJ0>-Uq(cw=6BDZ z=XtuvU3o1F=?vg+0P6{mY2*HQ{eF}cc{ZW5HOgN`VdsFHIu-Xx{}d`>O62I&=j+ zZY2<^Fk`_5_6sJ`If+3{16dMqRdGBlzboH(_=+B{F#L@A6yvH(oHOiUpKbm9U4>nr zY5weIi=SpcZ{EGT@bKrFKmTyy^MW8zeSV9bCmy0+ND9qjsbcbDl=`tt1w;T(5RCh4 z-u_J(qFBfZfKxbpvgV;LPuEF&!ELni5`M@dDSljj6MnqPPh2^fQf}$Nb}p?vl})pC zGemP3)D2gEG^kCaswF5Ao3D!eK$IwbvCM`j4Oy%d_$(rdQ~{i0kTM3&(hLjYjYpdd!LjcY$I6 z&I2xl2-X6w0p7wSj8Nbrr4v~GBtctJ*vqEr5;Sh<(kQ}G!KRFo03HkSAGsG|z#D)A z1XYxeN(7ZBa2ZjelLXbZ)=gIUF|=Mo!9IzC9daR~Ai?SoJoJPv!@!lBPHZ5U*d0F* ze;Tg0x5sf~0`CS~K?(Pz=#l4BFG2kMgVbB7#P6m-@d&t&eUAgu=2AloUXy8Py~7qr zQkL%rJfZmCr3?Pfw|mnIZ_b4Jg6*Asi=%zFcZB==h3|aIFh`^v*90f8zFn(>WFzpZ-GZGrxbILW_6|VNPet3hlZg2%1VXj;5V^ zU6~8#eGc>q^K}G!WWbLj$YJKauExFR%!1&9=G{OBBqtNeh+7o}yv|GYXLx)^o_~LX zM(V1Yjk{<`R-YrW4meA5q)Ui1mBJ&s7Y0NT9>NK!LD!5ZB$x<2Q?Pj)s2WzF>kp2S^-!^p*JVfCmH)g#suc+kgtC15uXHWS7C$CayGmAv1e##PqaB?5=Be67$ZY|CYf|=!KFzK6arsmC;rJ6 z%6dFaN(}W9%^g$XSA;VAT*cP#T{b{4VG$xiQ6TnX7^k8HgSz#$Ew+bj`)w*>li1KC zfGHc+E`TUNXA=~5F~ogkS>X;78BCX3W;2g%e0x*zmZM7K7vaX1#X2)qiFRfb6SP=H z<*w;?MyPkekhx;aq;bj($p;TsBJwRwdo8?^1Z_5eM~!9xcr-{6RQH%4H={+JI6*LR z#CyVf)+-UA@LuymA2Ecs1Y8B7+TD4eQ>?FW+`lE)Bgoa~MCE};G3mYNRS|vj;*QYc zpf%Ux$h{LTuED2Mc)2q|pK~ROm86(&bykT z4$(nT^1?}bDrBb+8NNU+Y+;8#{mD@4U?M-_(8Y^Ak)~yxp-9>5ise1=a>mtT4!1;I z*@!*Rwlp_A#>c7>8&Q0L#_AG2R$rvkW*#!XYHf?QfvYz6K2A$MAJt z&Ayq%E~1DP{ZhoITY7paj~lPXoDFr_w5}U(T#Yvl;{*bhz%G3Di_3WNX}tJw{CHff zZ`&(RC$M_}r~8I~c$Z7VnPUw_q6XKy7GP3imTtHV?y8+uyCV6~WS`a66JFXsRc`t|Y3`VEVluxh)2U4+QGyBt0EEI}8xGt?}?Hx+x zx>C_-%A0QWF1uY~{@c7fw8D z#~F#UoO}w)DIwx#JVo|yDUitV)Tz`|>h%=KFYzO;;|1fas3ypyVJS9F_KHY$UgA-& zc^E{%1tY-_Uu*&{cnHP<1P=t!>!PQlSe-_(u#4dmLG?oNDiqF#GVtlRF}EYPH+L|n z*dJ-=%zgRa%YQ!q$N4|ce>4A`yk_0Rx%}n)&+;@gsPpbT89*s)rbh6%VZ8VXfbWLa z;O!fOjK6l4BlzmMk={DJ(_`HB2#y!d?n zO8)0~u_o`K7gskGb{53hOeA0bivL*W~u^tDssad=u9xIT~1;dRw!%>OC`r@JH{mpP9)C__?_ukp_2F`z@k;iuh z%o_tuv!6TExW0)ALeqE~35MJ5ZQBev>p&Zl5_#)x!^{8>s6US{Y^+0-ctv>kx0G`J z1C_J7%5<+utSup}Jjls>_kQ9RmkdD5q`|z&-8;H-gfb z5M)|UMbOO#qN}1bdZIikPNnGPORQqC^5G)g*h*5NRuEr+)7{E9rK-yL26UUn7W1MCA_ zyz%bJHcV@K04coQ4d@13&4N_cDV2)mzLv(zQZtr_paG6KRso*0vI)(UumNR)ub6Us zGexhrE#q~kI(BRgbllX|d~;tS-ZPrMxy_mjK4jn6(sOG|?!&frSIg4Y)+J4Lck`lr z(~?%dsD0?K`aiHNofuf%(Y|(ZrZc@PoNNuI{Z?Np)QmBq#8csGyjzqt-Y>zw+K+EN zMF9R)t#4y|-P)iTwn~)q%>e5O_%N8~UeFA4bs)bAJh``PH#YA3M&mxv5N|b-EoQ~7 z3a4!spf!uZ*|`5}jr-4VniFZlJrk@~GXg;;a0Ph{>H`+{ZmeIH1^vw2>Q4RIIe2z~F#VDZ-<`%unL6!h)B$ z*<7qNQxVuP^I({5oIZHL+^87LO9!!@7&TLz=T{lM zA)%=x`0J{#B;KH5IgeBJhIi|bmDiySQY|WFN}19+{**E4nNp^*P@hdS!nO{zu3Gj zgW20?9C82ieEg2hTpyr`AByisy{>QYsAk{W80+y>xb1D_wj1|-qj4X`x>4a-or>VD z#yy7`_h9_G$1^m3GqBIZQlY`9LY~~uFMs#ljd$y+1KCyC2A@iavqQQ}9wEz$uqDb@ zEFLV{J&dvg)B+S7bIb2QnNyzPJgK>Ss#X)2=mgleMQ1UqtiN`DsGrRU#{RIz=hgB7 zNpI#%5N$m`QuUnva)XHl1xm5jFFgjFFzhkZqZNO`Lf{7MX>hf+TlZKomAz4O<2pN^ zZ9G=I;c|m9rgTlq-noHccKYGXl7PpG`whW%`25v>i)P+vJ57Ei+KzZgW7qz4{(w98 z)#B|m+VW7NEz$OY@fK?PmQ^kHwjit`=53*cTA){vizsU~Hc51G$*+rMIm?mm?;3rs z7G<&?T$1-A-Su}#zhZ~r6`I&R6+JBJx%xy>&wZ>Vi%_kQl8~rCM>45sP{>oTy5WS-?pGM_0!Tg%5RO z+H`9gmXam1+?doGaj;(I{aCU+T!$yw}-e&NW^LX^4FgD zGh36d|AQ+(wKo@IAGAe%7C{o!v{v{L?dPLHlYk)2njp1kZ%|XyJ$<{E%Kd2X6TMX6 zRlWDpPes)9(nTdGx+bV>)+?@F{)7%wBG=HC-vP&_2uY@U9|_vCW|&&>@u z#2xrm(_%NoZ#va{fz>MyVJlm62be>h_Yf%d%bb4@Q+DxbCCX@yemtD#TDjb-Xi1)7 za408HV~Lo`0H<%nX{#K^i6I$h0hbA?FrLLm9VgBM&T;0d5fh*tYK|`C1UQGnJmA`n z4shIc#s#JokJIlXI6+W74NNgg~B~|FYI2Lw5IdjO<7mhx{<|qmwkV!8|fVE-)_$i6xOeE*(GOUFwonlargu# z>}KzgefBp5wXh3Z(nkfzWe5-e{t4+>SU^RjB7U|=57AFW79av`2$?HIwEilj2;dc{ z5@kd+PO&NWI(4j?ym`0G`&+d~HHrW~?;@0e5@&_n@FC2KxYbeWfc$s&X7@)6H{UA8 zzW6^94{YH4x2mXTE4Zy@Uwr|N_e2;}q<&|EO$X)vpKIFh7hm|}@E%UrpAu#AX7QY0 z7s5d7~K% z$Aji0<`ZU|Q*3oGV?!Es!lGR#%>R-Rd5yeL-XZUm56W4b*4oFS11eVvmx;FQ3KYi`i32(pj{T?xOhRK*An{GGf$@-==`W5x{@6+udS> zeM9^j&6|g5uH#L`-A%zVisnKAM0C9kT0DTi0Tcn(0S^JV46Bu(=JeZ!IleMbj~_zE zJQTiEGdP>Dm?Ea4NkU8!#L5GOD_QWRWZ|>PxzoANNr@LduXx_@(1bS8V;Qxq#kGyj z9nQUU&5_{?9;|Wdet&3q?rHAsvo}Qp8l%l*)TP3C(!dS|jc&i#5*_n|JX(vxkWD7M zL2rQf*9o?nEg>6kt8la8RHgcmv|plbzeIvT^pg_82O?IAOlwPgi&~HrP0Q+|>L=86 zqd^iB#Y}WafQA{v7-Etsjc`7C7`atIOn#7pNRh zQ90UqITk487&JU9{f+dp^qTZGy}LRft-^>_^Os>j8w9ETS~K^+@Px>Rt&^-0xMMhF zHfHS~iqm_Y7Q9!?ulh*X-|x`dtxl6qdGGZ#terZhRapH0;Juao^sP5uo|^yV%11kE z@5VRd-J-CHzWEvc%`ss=Sn9$h6kt}RS6ijQTKLATycF}-J>PGV_cT&&qvxFnu{Y&> z-HGR&gHA4xwBb$P2QG4d-Vyqc2(-hX)jFsBGINeu_(6P|%M$nd zn_ixgZZxjd#v3;^>k!|)fWG@s?Ynn0zWaBsc>b-p-T61pmz}RU-*)15=c-wsSqa*l z{QGA057@$)={w==ZcbZy<{ZEDU?P;X*{SIQ^m&xFIC)yk-})h?57``O$JFdY0pCY` z>JaZ!G2!?BZ}uu4l<5+EU+s%#edfI1S9v_5#Bs0ek8sA2Vp1S-$L?s!xxG>|x0fEm z=b@M4Q)i@|__P~6HdQ~g*S-|=`wM+!6=w!*qhHaFz@%ZClc))@ff?$7mv5K zQA7cH_7ABijB(rETTx4Myiy51nn1lErV=;fWkn>Eoyv6?6C6SH3He!B3818&Wov>yNw?*lKmZMO0*$D z0FraY%SP3@*;_r>2+K^ZY}~jLHJLjC6S*md-lWA9#)HSaWnkpq(D0JsRRi=LXIq7_ zLS|r~XX5y_ZQ|#CT73Tp5>Nbz(syFSN0}o1_cr#SijP#(IA^o+Y?|O@fZ$8lT-c^b z^g!RHqu2T@IHxaGY)Z-om4A%uG+1juZd;E8cZH8cerkp!!8}KJKx*(J`PZl~G!agDl6>#ofyJfNk;ydm*X{_ymw(V_u+8%F{Vc2|Q%_NgHn+m%XCpIsD z6Cr|4fXPt9O?TzR7HmEMLj~O4HaAzsqq&mVswSa!x?J?*b~ha3XUM}sCk@&X{VtSf z6H!YP^h=}whj+(_ZH@7XW1By3m4YNh&eOM*%J8DEpXk# z#uniI)#6v!Q7JCCsh6`Ncb{P?DxOfEAQ;p|EJX`qeyhk>i%!%QV3s)xFiT?rW*{qn zT7VfMhN3}PfH{=~Shs1&wAzH2EAI2|D{j8-GL4$n;*`QSpv0v6qWhYA#saK+#`^2? zEu~(2CK1qhJl1r$+2ct@{8)W`ov*$k?i*__QMg|mXP=f_+#l=_V#`(E)?SCQ>b=^{ zV0v4%+)Vd(@D5v9Py4@yi`d`f9rk7r&SH&vk~S7nrvL&S&f_Zf|Bjc~7c61!6V~-D zBtjvlOH$9{C6);v6CY)}B@fZyBg*VpxsFDP5GZ>!Yr8ev5?(Adh=$k)W*%0H0bk~wAK?&+&)=4P}8$}q~ZB*A1} zy+*x}_IH&YHC#H52nfsv8*pijv{91k8@`Wy-u{He2o_=WIGbTbD`34Ml5&R9 z8=s`Cxid3ZoL)3vGsCCYC(VzTzhr)f(&Q-5eAX<^I#+$w{3e}pkQy~9sVRf#Yramu zG3IwLzrkP+gvBLGe2XIqU%=|LX?%Uc{{;&C*Ny-H0RR910RquvPG@yr4?Oh%8w2P7 z0002U_|jbf0002YNlA(T0RK+`{R2V(000O80ssI20001Z0b^ifU|^2^@5I2s_=SPt z|98f}KoL~H0sw{+1&;uD0Zq>X$Q@7=0N`)7ZR59X+k6UBp3)F!q-8D62vfEjGL~(( ztextq@7}|7R{R52Ob|8STysFX!%q9-xnU(Lyf);kZnc(;7*HK`pDFG7WB%GH70&B+ z%r@0ZG-@;HbmSQ|O7$vH>xj1a&FURf>wq0f9FFR~ZgVnDsnM=kMdU7L4Z5USuc@f} zo!73^MJ+M!bl!GV_Nvw3ue1_;Q|+97r(@FNx~<0bNg0ajuG=bHi|H@>b^Ge2J7RB5 z*c5qNk=07HWzA$A6&K_!#IMadtWA@eA{#a5>q}YZ#SM8w@jJ8jYL9=(25UX?&1)$? zybe=3!bdN{xGPSmu;{Xz-umqMe|K>^eEM0s2f+?gbo-2kdRxLIzFfP0>m@!B(yfSn%WHY8TtTjqD4mRF5t~e?=dO93B#yf00 zay`60ygzn7`al#wpg|@`YEfYD{uYgie@GHcxs` z3{cQe`cbG+=28q&a8jaEPE(>(j8)oKTv$|Ca9Dy^npm<}##%O7yj(6^NL*B0YFvU` znp~z_yjRA**qd}oknsAsrm&S)fQTxoJ?hH02-uxY|-mTItS z=4;MvRBfhh(r$uo{%=BWes8>RIB=+O9&tQzc5$q6+;Ti~ICD^QymUBpo^;lA5Or7p z0RR91+W=qy1psUS1ONd5000003IG5C00%Ju0ssMc0dSkZBwlmCv;P_=obeLwA6XOcIcLG?D;MG|{mffE`d|BQaOKUBH(tp|2_WOTpG6bnJ38aFa{0bIewfx-X)0I;;@F1WjUac2eQXBhaC2!ZQaguuNEK`8X# z(UWH{UcGtu;nSCIKYsoB7ZaC|l#-T_m6KOcR8m$^Ra4i{)Y8_`)zddHG%_|3nVOkf zSXx=z*xK1UI6B=3f`{cizyJV%`%V8^&s5vCZCg{@J=L~j+nSi?*vUD&CYfxiX{MWD zrdej2W3GATTVSC@7F%MeWtLlErBzm2W36@8+hC(jzI*42tCBp^?3#OSd*O@sVVGO$ zT=qCb!foE@+aEPy zlt#6p#mMwulq}aJOOY5xhcUXs*f1`P4->*fQzG-1&7C{cayTF%5Cs4v zw|V+Jco=D384v|1S>H0aT3t7PZ@U!civREY_2zc{c(Xe0IuEP(&_Gg@i#!#R0+y=O zP=98YLzP=vkurRCSgX{P-%4|9zV!lqeT0d40o%Z!&9I4)g-M%n6Du>2+|KIjWUemG zz@fdJEy@GRVy{T@HCF_(7`8LQ1)1P1=B#iRLs<}ur8y_W2CQ%s2P?bw1_lM!+Dr+T zO$l6##hVU*2n8<2l1=_RK$biYkX6saSh{IGh|uQ)iur?x{}2{P7DTKE5$AyfNJ%MB a0!Y+@i2njWb@~E8iFhCZ0O61}VE_O-Q=5qZ diff --git a/docs/fonts/Lato-Bold.ttf b/docs/fonts/Lato-Bold.ttf deleted file mode 100644 index 74343694e2b2114272f38b1124813b972cb592e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121788 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 diff --git a/docs/fonts/Lato-Bold.woff2 b/docs/fonts/Lato-Bold.woff2 deleted file mode 100644 index 254684c7f95e1bf7c3b4710536b477c20bd4e86b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32304 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�r(aJ zZ33HkgG;a`qEg`DFB$$iS~G&mOkPzQ`iwI*Hi_VuTD%Q52}^*S8tJ0oD`Q)6ne@hV&no+d+meobxEgh>q^H?C1wRm~aOxy}xvhKEZC9|$udEKnE zk`0xM8dlACYViYS9Z!_s^2LJk^$YX!3MS?j&YH92_LVEYbmOd{&F@uHN|qE%FRfWv zw5oDm`O>_J3ktKQue*QUr5yWjx1RVCx@5Kwoz3ky4!vH4gh=B$Dyy?G4Kp zFRGkhGOu9nY}`_xF+Om<>UHLI3G`M)LsP03l-Z&pGgA>ljk$Fc9HUVf$-`@bW&V7( z>2yK$blz%wtSyoUE=`WcWfeGNhyHu0h7N;Bv<{I>|DVbar>WA}%GKy~e{K0NoCp>V zyPjfVLjQ=6uZgYXGuNEA8H;-uL#$))5&o~M6N&{Bv_u;|iBP;58)?9moh`veMqvm* zZ{U#RKZTQrK;V|Ykw6Sbb=gJ??pf8}ptSfmi!&8&^WHK#5tj{DqUVpw1$@QSoosM} zd(*)YdRN;g(xS_eKK9!`i56CQgXD6sLJ|p|Dsvu%SWE<6ku>eW&fW5M8t`6%Gx-1R z7(vJ#8RdrlTTESr5YG2^xxp90nL=!R8YQ~=_`lFPq7$3?uv4r8(a78_hC_aFu}bKu z-{Qb=Q3`3bHqsyfC=UB(y7|5Nn-@=uG%sbA z-xT4f`qH(U7#@Z)dKer_FrmI;qKyGQydq(DVJByr7)_$#!1)&$nZOCFwU1=Q6}eqG zZ4cyz*{F%h$*^3}Jr3nbhXt+1^?ya4@(j?^7#gG|)5KNP{1thH&DA3#*}6idWMPAW z@WZFmh$WMv1uo?t771_ZA9gE-&!x?O2%Ae!srl;drGYcq=Zt!EdyL1KUv}a%p3&#g zjWO88c$al%d)3Gz-J_!xR4{!Zh%SMUdPdoU248kWA(N*{a~>GK@S-+KR7NWlAp|AF*r z4(4yA-^ur3ZB`6^h~4z<2nng?Ugdd3RTV|m^QvdhoIFW!7wi%}@uA=EU%znIliTZ#-oI@9O}l?k)p6-7^R^vsn6ajEO8!mv zE?V<<>u0H6_F|y(Zw`)?xKTaQ_#J$>tS_ApsQOx~^y`d2kD9)7SUT&`djD6$(wV=N z{<~r6tY0hrPNrkbwZ-^8VqqV^Q>rn;SYX}zpp#co4?G`W29&@a+)6IPA_s{UD}pX! z`gT!G4u-wJ)nJZT76@)a4aW6uVJxe8TT)i|uJWv;k^i>+-wyN02)F;`nh^=)p=$7K z#H@(xjVy3bWX`BcoHcW1(X1lwg&Q|E0cTW(_L`Tc!zLFNOyMp!4iGSHM_7rO0d2iv z@|~>H-vhdf$vZ7Et>#~y2lStLu*H;qdO1QJz2e_OEeKxtMSt1H)?9ul7ft4aZulWf zsp)*+gm5+?&F0PIR1;CBaX4d`8;UTOxBtWZg*@+ZMa#V6F=ZLoeSP5)9{aeeqht~0 z@f$DwQ<-`8`i2$vteR>TFTZ=$)WU&POYHY7`r%HV1378pvW&E67eDRiVURi5o5rVJ z{`UUQ*jARz+w%2+$wgZp+Ss%C@`XIM2c7q%_CUW3=LG*x?O|m4&SB|n57zs?8kSDI zx6f`X4!T5qhkvy zCVj#!1vh_gRe9RPsP@ZE?YQx>+cy6>+x#iX(&ms$2b3UM@(k!oN+lb5EWy4!?twZnrVx12?^~` z@RwoZR|G^t-GWd#M@YsN_9&dHiGSeux=aXHf$p$62{tWFQqOMu#9Yxf@%^>rPL@bX znFrVX*8YW=Q!L1ZYB?$ob`_gCy84=O#zcx$c1SwI_ zImn#D((I5l$d0uDh!Id$NXr8A5vd}^qSvscGyEdAA?6ys|>)Qy~6UHZ;e~32DApM-$;>bjC?KtyMU58dPh9b77SX&$!AK z#x$CXdzLYwF%3?UtB^soiHlYEo%CZct$G`?%esL+_X)Sld<7eHn70RMaGmNBOBoi>FuiW%Ny-?UtVpSb@>(B znN35g9cE5LksU({i^42}{p1~6<;G(3dsP!E=9`$L%wJrw*jtQ9IjQ=2Aa+lfy{U(Wgs(((CVr` zJ=bCVcFhB^ZxLb_oV}32`zOMTo?0O(?l8eGXnR z61?~Ptg}5E(S3W>`$S7C5CYese!{)Jm`c^V$7SZl-T4Y^WU zfR$40qOdDYlJ-D@&-88os za2v~rY}lR7L^g;$yLt((mJPKYN4G0as44v{DGn`DK9u&Nvy90c=X>8vCAEG1Rns(!XeN5GhjyRep1itK@t$AY1`QMtjM_R^ts z1CM|0?PImI$KL+h;{)qbtL{C%b?fo_7A&}rfA6gdb-I7Jul)-@GTo0Ww4$T&50?vC zU+G-6s`HiB)>pooMNJrEEzSlOWf8z@+OaH)MZ##CbqSv{26~>H8H=GxXwegE zvK$iew3ojjm%xpf)SBg=ToyAL<1*|{wTc4u4Exuxf+0(e5~Mk!Wa&0>LK&-9IYqg2 zz26YeBeNopTrgbu*JY*knC$RODL{<>0$ae={pHzWl%v&DY+}Q4!C-{j-U0@Pf3e-C z>c&yBg=00yI~NwCTxv%{oQLHL&oQ@fVlh?Kjc^O)tI52KvqCF|j}YL}=j1)y-;WhV z>kL}U+dpP#QSpz%78U1jsG60S5?i1(#e08PJnu()wjA0~Rdw&t+gpB6l>gn!NB@5J zq(xg7FWtI$(jNQgu!uPQ%0$6WdY`dK*86d0LfHHCb6W5JnkzlX zCkkVR-z)ynibZmni!=?G*`e=jet=I)i)lo@wUe|q`miQ`K&dSGov;^O;u6Y zg@74xXylcI7Kh;@__E=IEes-Up`*$@)=&5WTgH(KPbyDANR~#Mp-t6Dw@#fyBb(g}?)~>8j&HggP0=ogE27C6J@DVu?ZCM>P_nzEqZ1>(Vp{~+r5InTLg0i4_e|i_ z$rLk1E1uM}L`1MrdT<5sM1vSJbe11Z*|ds;K_8XJTKx>XoQ0A1B=mVGvKE}s*NyU$ z!|L(5H@hHswkQvtHuG=Tx*+}jxJlj_GrW`H?oVIv`G~K~xc;`{EH94io9fLfzU}%M zl*-wN@0;ItT*O}T^r7<#;>a3XfQHC6PCG^%5omtfx-ru_=b1NVI!c45K938#E7Q0$ z;tS@V9lz0Db({mld*XR2g3fJaA0AU#-aO5Stx^kkS4g<_v#o{nMaOCBP^}}Kv zTVb7la_7Y2>Z#MNFPS*8PTTamq^a?o86%QW<_*lnaPywgQkCe!yxx`M!j0`n3En58Ru1aY z132!`tUbn1D_4qs%(i}nv@rbyqQFq}T!xD(@{k0JpcfD$1d0c0Jv`|A6P#a%PRFr! zLa{S2Pd^`b3n2^OIa}r{4WR6bG88e3bm`2{(AjT-_0?X{FVtPDNEs#(7D+cm_5}(@6AIPB<^D%?`9<@F4K)9P&PO^mp+N zKM3^0aH+HJ5_@rQTW@zvx2enlqE5+Jv;(CAcud26xhq`(1)bP zezzjFq{N*I^C(EI&p&p40$|5c|>zVtP_?{f3KdtyDyqY-#lvC!tP ziW!^4OEOJkpUrLmp6wwF2(JBnwSD%9mwsz|s5$Vx|wk%Hc|wFg7kJHFCWDk9nWT+jw~KBuA_> z&XqiK?z{;T7v;pnjz!bJzB>EAn@b$OxAKMNU|T=q2Aq+K#DV-^nsuIs8J{t3!>aI% z9ly`poVO{Manh_n#xY}gm(Rw5cg-cn`(gP`xz>E&ziPJ70?5I3ljJa$=a6Kk!CQ7! zSs+&Ennd)>waaYgRfTDzENwd_OO-7RhtZ>KSCQv6i^F{M+66!J>Y{_}P$#yXs*~{Y zU8NvbNxo7It}NeGEAW$w2c6kD@Nh(;<7p$){9;vH=7jNSV{j)-tSf?d!Yn^CAC_na zoC$`BO*wWWeJnN_aAywgFNQ(3<9ixuUK|(^F~*t)uxFok#V2?RA4H%j!=CVS>jQRr z{!wWR`yjM^%pIZ81E=+cSI|Id&>he%IgA!;A6!(7k-%=Sz~sFw^sz0(ll3voAlbq| zljX&;${Usk3}<=pYsZyeBLoWlH9o?qY}C&+6~|~Lsc;_M^{ICJNwrs)#k?OU%aa5f znw#Xw+Bt2;q!p`I=Z>9PRGgE#^6|wprw-hgnp0dfb?m^s_U_EQXjiP=d=qE(jEx*; z=4F--Y`*kgsj2p8bH8k7uwLhwzpolIXZEa_({i)3a62FDl~uorwP5{*xPh6?v^gRs zPtN6z7?vrb z%x(;37tQPa}e?Gunt+p=>mZ(DuxwSoiKaht7sE$qHty-c+=7< ztOfB7A$UDU)h=`Q)R~JPUuh}X$^(mMOf&b4u4|W%m1pLeX^{hIsj220k!jRF8{@%D z<7dWi?HBAXU?f-`nky|olZx8WITw^O?1hPuAEq@N46?210hP&rXIXbHjhM3htZYli ziW_!+uB_~HyKh+0v8Bvb6a3c=_!oYKX}NjueaCv^UC_=o%8W;O#}(sh8M7GJYp78u zf@>^-I3+^6oPrBYiNk-vUMBv+rQ;0#Vik7SJ63_mBdC)jYqElh!r|1WRgFAG4^P9` z!)%llRy=~iDWCH1n@1k<5aAe^f_?s3v&SKxGbw2j|7In9aYS%u@H!z~I;2a8W^-~n zJNR!bVpI>l7xf*-QOR(wvDnyPY%?A-e^oW%e*ZnbJGXAG!du8o!&^cRu0xZnQ&!lslesL88$eEA-K#^at+^N`6E^tux+_8 z+)i}Lm(6-DzsmR6xe|7Ov-aIzkw-9&bUr!(8$w$1!2#EZSoYC5aya6L6(q$f2$f}7 zC=*0?L_4r)>QgdxREAG=|!6Z^qgG;I+UKQ;_y=61OqI4Nk9%;4dPjf%lE9Bal# zQ0CEY<%v1E%jwnzo8WZ-$~zR`HPUSnIb!ugXMxEj^=WTT8Q}mKnUn3A!kg}?Ty*#P zyu9^yFS>5WjdTA#eeQxOQ*g%m_&oldn{I21P9OWgpWkw&C$&0?3U9i5==FQn=Y4tP z>-Mdmnqx%ey0%Sud7IkSt#7Z*;{_HAYsP|4%u50Cs zt?Slz@Wqbx3vVeM2M^%F1snO|#s#19yX+s%b~pc3XS-w0U`ytlVYGAIM;_sR)g#+s zJ9rMD`I^oFM4pK_2o9&XU2))_`P#4}{%p8`akSI?kl!FY+4gMsq|mT62Hd_Temd$QF0 zYSo0LOR8{Pp0_wZZ^ks7AGu-j)awWP#%Sp?wo+sD|cx0}cdnm^gmx80% z$ZP(#99=HhMI1#HC@cSP_2;wKk}Imh&CBl4+J}Y(IBz>LHil_VoF!&SC2BM(F;@SR zRG{0)hPM4UBQ;paiZfHv%~b1o0`8OH`R%&2Oy?+P7Zv0ba(czLGw6;Lh}a+&gb=`HYEau~D&6%a{D@p?fawzA52r z?fAXJ-g5s>9$K;G=0(x&oY^@q{9|!qM)K5@gbDE_o{X1XN|`uiVoGG>lH2cE^^I3r zZjYakkUT9JgX${#^^R%K-3j3IjjFMknVC76Ia4NM(F5zGX=9T;^v!E*OI<2T9TOjC zcVH|JU2@1rxK13$OfG?;r<6=s?ug7nuJ{W+qT1 z&M>N0gnbqng_um-zvqA#hsWUH@Ch8R3zLqQadT4?0)246o+>izjB~E3TiGGl2TcsK zS$N$DsVOt&LPWk*mn)wD!9yPfV=D6Q+ z9Jh%5j=Syg7ju-UIqA6DJJuz?CuN&6HzNgIB^MfCPuS$Rkc9qIeZ9_G4*0+5&zd~+ zHpH$umi98S-RfP%(O9Fc*`vP;PaoE|!U>R)j`$em1Fk6WefZ9>BPB2-Q_;A_f$sut z&@2!AEkjqpqcAXU>>cIHO`_ z#nc=`dukjTI$;GTDcg;_bm$fg<i}VciiW>rgccIB zte?@gARsg|?T12Md>{WdxHN|dcsQ?d|0vo!UCS6y4;?FxrC!4}%CX`yc%gH}vx^*Q z-|ZiW>HjW{694$P^CtfHP4Ku5JleryqVcsVg?rHgYxRk|VOJqf27ze;6Evqf{f(O{ zWTtSichE1N8F~{A8~#2e>=Uk4RZR=M0okIqX|8RfT`y;?Git+L3eRI>HyMp;D_R%v ztxKP?&AhuID3*J(OF3@)Yo)3YzF&6Yw4LS-Le(2b~)B)7q0qF zJm0Cx4bK9@Gaj!*k!2HParlSUl|2_01Yk?iNd@j?wn&ur7Kk&JUizbaP$#5)9Ncng*T3@L#;FxINubKTS<8al4`Q_85 z@=Ut&Rr6OB%$-^`tt>Nxx216(k)r<8g)g6#hO4>J{X_R)hM;ud*X4|cm18fQt;YzK zoBPE1!2V=m=rd4`bl5e&E>28}F(pu3fPpBYnXQn@TFS zug}k4zy0#6$rZ)_+No6ahPhU|s zDQ|;+#R~t;bA$h$do%yNA#d-5qQ$wniwiTy&Z*AJ!vz+>znO(hFG4FC>>fB^uf>=k z+vu!vWu}iwcH^{$PX-V$taSz+&TBP`xfo0IMs9<{j{ zVede@ptDj_?uteUf;Tzy)1ZyS5+Ae-vCh0o+HM`1pp_`B1e-fk&hE`wJTb}^l{jJS zmWKFd_kzzpxIBB=1eZNJd16}WP4lNjMO^npe_X=)=s1^S+s;4#>Gr+1&T=QLh;=*7 z@nyFxR9|q$yx;x{`*S#jsMt)Z8kdodfQfuY&8HV<6zdk|DBgx0IumhaGTNR!$%)pM zmjz+XnS{=oXBMFSvFwUJMI1OyaNwF`xW{^CGPsP1lW{D>RQ$ zl@e5V7S`8O(6I!@XtaQt?5wF-?v%9HZ3T0)rezI0;YR9R zd9(2x7f79&h1S?@eAoVd#QpGT{Y%xDBpz0e`-#H3L_;;k>#pftG0dr`0f%!MYAE2n zwxOo5Yaccv8xK5pb25zy{$d@~8nfcI3{H!2Fn!TAepgjF^a<2!g!dPLUJ=*=35p0s zqZe4S1d(Qqf--!+urWzlxC;W;Az=2F6`5U(n^=ppy3MzI5BlC8_}Q)ILj(EuK6vlI zAI;^r4y?C-_5JrdUg)@Vse@+{*o;nNwf*6Ue?VM(iZQDSmlY%>!V^%H=}CYxIS|@G zZDI-Vz>brK-N=d{Rg=q=*d~UViDQD90lyyTciNqa;|7+_E*O`eVtywr>C&I29}OXR1uu^)MW#0EXBVh#b8DDf5oIH zeCf~s7%0O7gL@$B55RJ=kynLghz1KeO!CCJoOW7zPI0a-ih^h}8>cmBjuvfdALIjO zyWead_>%tvGdU{W;fRYi#}2%i=yJqI*}iWty7ZGvFWL()e>XKJF)=6Aw%E30Ms{Kj zq7Tf$fq~~*OBiC7;1Ww|h@^rxj=1g3( z!^|0V06T&eKiuMoz;r80omDi;({OV&$+lgW&Hlqdrse- zvns=BOHPUz8~^RcZCjokSZBY*?MO+!zT}oiwpX}Zx40wCZ*&%1%Cv93v>#OwsM8M| zXR&^JfH$w5 zMxZR*A$&Cb%8zhb8EQ#G_@VDD)zMfm$PQ-)G$F3N$8?*st9{;s)Bw|XaiGim^57X5fa|K@M2vO8 zL+Vy!Ds2X~PT?g~H(-oO6M?N$On?A}eqw^P?1oKcJXAzyS0tHRQ*n}iT9PXxtzz!# zlvvk<{OZCnakwQOcIxLiv+G&sNAMwMkS#0T`wz}Bww=xowBEFS#2tvNwZHW)XBJ_^vc$-%oL}UH z%_+IOnmIRx7dV?IaB1@xT-NOI;PU1%xU|{XJSLa_%EeXB)&gRRwn@&f z!**YLywW1`Hv{9XyGOk*fhmFPWOUqlKee+ung+dd8)E z`4yKZag4|L(Jx}7e&UM7wtkjp@LlA0pYzuU>8`B8;Y@L{Fk!R?lq&*(F$#rw4-ZVn zhQm<;lOaOZ;2d;q*w#gNe{q5BzK+=R=;o-1sEFq1^w^I7JmYjlI&Y1@T?e;1BVQg) zKaunk6VR=O(TCDl8`T1gF)$iwq>n-%2HDzWhd^Y}$61DHB8*u^oRCmp zMb;K1JI#VUU%Pwd`t>XCe#r4(cl*lb&oBGDALZ$HW}2rWlc4X=k)gZKtY$i54$ZsI zMy|P;r;;blN*gK4wva=WeN>1j#W^y%mCWLP@b~=7)z8^UYbTW;CVKK#3 zS$KiH8B8C<&2Erk)zC0l3I4H0cq7)M!()bbW)>{U;k=OZ#+*e3nHz#J!_Hl~3+Id* zH)mmPP8FA+t8!*|y)%L_!{eM$w)M`JF@HM4cv{{Y6^N(BtVw>UO{kCm|3%BP8iobS zI)|cVPi9XsZyPhcVrq6(S>f18Q_L-?Gb(elt4a%ZK)jOwC{ahc<0OrCLl;RHOe zUD%A3XqSI-z60BtWNf`kysR|ye=I7N9LT6M6gDgLWFC8-k+5G&$jLIF|Im|>viYf` zsS};={5Z~iE_v*a-ElzZ?8^~;^MK=-QTmuKqQ2s-{zQRb?rZ2{%wc`ZgJWVM6DOvz zkMTO5K_`<{ws9dknWc~v8b$qY4Kp!&GZrLcUq=5LJ-7@QKbQ_o7+eYT=s8j8**J~O zVNBL@j-ICr^M!>%FHQ$^z?(!Y$10M;sMPbK!GFZ_lEFj3rNV0ATH!k3Hc@O4HVT`B z&7#;MY!$W%+l3v%-NHR8L#MDy*e&c4_6i>s_Ni>%zBG7w-z+ zQ_2Uz4}~8iXWVWiWDUAhgD%ye%U}(<4A!7aHRv)}gD!(L=rUM?E`v4bGFXEy)u2l? z=u!>3a1;1HBAqqpQVqHg%fe^Ypvzzlx(wE!%U}(<4A!8_U=6wq)}YH^4Y~~0pvzzl zx(wE!%U}(<4A!8_U=6wq)}YH^4Y~~0pvzzlx(wE!%U}(<4A!8_U=6wq)}YH^4Y~~0 zpvzzlx(wE!%U}(<4A!8_U=6wq)}YH^4Y~~0pvzzlx(wE!%U}(<4A!8_U=6wq)}RY# zMiW_sE`v4bGFXEygEiO4%^z$MeR)r-8M4u2;_6lyig7r<6uL`}N$U=RL~5 zQ`jZ!7WN2xg%1n+MDbZY|5W&jQeIO&uM6K$&Tk6e7QQ2VPrrU3{80E2(i0$!mB47+ z0+Ilk@YyYl$2$qoZDOK+oh+mr5+H|v0G6UfBp7AjIswwy44e;Jfw_ZztyexipfNJy_ZX~q z585enX1#k1*1HF-mCvkq585oBS??aSL?Y|mgO*5Sy?f9SiL7^z!Fu2ZRzPIECt}Q!2aHBaBJ4Du-NN|6Dm*8k z1`|>Hd`{Fm8H300JV7`~Z)QWPiLiCdAxF>Cg|kq$M97f8777;)eg)4N3;1XAi%!foQB zLFiM;J+Qlp#tz}V%Arxe?ox_h?=&f;S*2Zs8tL?-X_kyM;Z%Ug5*S z1LEbN@R0DZ@QCoJ@R;zp@PzQB@Rabh@JZoQD*stMpA()JUJ&*RFABe_H@_$RzVHXa zr&a!E^v<&?;d6R^UihNk`Ki)hQp#(R%LI%tou^b1eGVY_v^2$3xGvp@GCiy)#)@Jop$=yeL&REYI(Nt9eFKkvmEy7k|o3LHjA>1wOQ_fH8`4v6?TvT2a{zCYM@_bYH zmP-4!p5GC^tCWxQ{4w%@qZi|c$>5jh7ABy~lM(g!0x(=QmJd`#G%#Yh9|%7L=1S{wrFFT|x?E{puCy*!T9+%W%azvU z!oIzVuc&po(mL!DfY#+o>vE-axzf5^oPqocq*Lp1A@i4k)Vf^Qd?K|j7b7$xwJsMU zG$OSw7b7$xwJsOd{tS>>mkT@3XKG!pL9NR*sCBup_RN!7my0pa3qWdJE^I!LT9*qu z&u41gH1O*O#-lHr2JVQ7O34^}7S9uelQ6cQ27dYGtie*?64084u_&=xxLR+n5w2BA zjh@%(`9?k8EWB6PtlV0Jt->~8yRbvJTXo6?i6+jyM;Z%Ug5*SdoSvT-{!}S1>G?I4>UH6J!ViQW0_PZxf!_dKLbov9n1_@E zXz3h`X!tw{Qk?@yo&n|vrwj9ig~H;&b@DjMeo0PIg`E&}qgx$g(VXyFE zVV_FKT9|{m6_K?t2XiYTYhe!NRz%jq9L%kVtc5w4TM=0cb1=6eKC3)g3v)1^BK}k< ztc5wSHk8I|D&gzGH&o^~g>OmDZ|nIT;k!zCPj7x8{80E2e$AJqMI1itPrfWI?stZ5 z%$KFjm!-{@rOlV6MK7l}X=(FiY4c@i^JQuCWoh$eY4c@i^JQuCWoh$eY4c@i^JQuC zWoh$eY4c@i^JQuCWoh$eY4c@i^JQuCWoh$eY4c@i^JQuCWoh$eY4c@i^JQuCWoh$e zY4c@i^JQrZ!0%3@0Nh0ZJ;Fq#Ocu_9rWIhO{}ONs^uGZ5MywXD6|NID>-`pCtFTSj zF6T?UF35C*xLTN&w zG@($MP$*3(lqM8P6AGmXh0=sVX+ohip-`GoC`~AoCKO5&3Z)5!(u6{3LZLLFP?}IE zO(>Km6iO2cr3r=7ghFXTp){dTnouZBD3m4?!4|!Yvwi53ERq+fNM4{Kd4Y<+-HS*s zfzB7nCsQP!Op$ytMe@lM$tP1JpG=W_GDXHCdVinrQQ>1kdhLqj8!3jI{fNJ3UtbIh zNo0>-tRBDE$iQs67(G5Q8*QyvJ$^CD$>-_9S%W2b&ewCHaM7R>DN6=t1D6V`h0Cxr zsMuJo+|~%!D!oR}>-2o1p4Si7;mw=%yg}vJICu|IHVtkE)+*(e!QFV?rsoFXy?Vb< z&rL#(D2h?1M2;wmQKv+XD2h?1M2;wmAysnJDeMw<3wwmU!iR+i#N9#RA>m=+5#dqc zG2wA>bV7JicuII$_@wYDmHDim&k4^9F9`dE7lq%|o8J?DU-$zdM=8bdfKleps)Wz! z{pW=*>Ybk|{UxQmCds@mQpoFp;C060{d0M>Qp&NaU!-E8l__RPMtweG6Xs7QCQXg=hK}yr9cx z`WC#<$zwqJ7Q6<13tnjEi$MAoywFTO)3@NoxO6L!z6Gy*3trgLui%-!1ury{NZ*3j zpl`t|-+~wV$(-q1@S;!Wuk09v1 zx8Q}Ak_-A4yas&>UW2{`uY3z$gT4hXd_Me@z6GyA-+~vOAEwZ^;Dv;V^euQHVIqAC zUPzco-+~u9OzQM4cwrfc^euQ{8Hn^Pcwrfc^euSdrzO(2;Dw)-NZ*1Nep(`Z3tsqX ziS#XaF_s|Gx8TKCf=J(j*Pw5~ixCB%>09t(L_wr)!HW?Ek-i15LEnPcpl`uz(6`_< z=v(kYH&}l97QE2m7lHIGcrofA(zoD+y<$3j3to&mC>i<|yas&>UW2{`FSLt#Lf?Yd zpl`toO=Aju3tsrOi1aOZ4f+%p@9d0)WA|{U@0`P9nT5yTb4ot`JAYC zCPD8?p>KSD*5JdyMJQn@^onnCZK4!2WHBRxqVONUbP^ zRuFdx8yv6s5Pd%r#C+kekf$Em7>-TVE;X5LuF|DzXNhMRHoTb8QMFaIU6cN zjr1Al?FXEYF^)ijs%g~CSz%yqUq6#xLMB|2KV9pjaW%6hh6mpYn4*3@^8~u4MLw% z?!io;9BqequX1SAue+4u*E>y0X%;Un!d79MuwB?8+%4qHs~mMrD79J5E6&@2FR~b$SPYO>7PYa(EKBe-X)$=*wdEo_Nzwn~)yL$6` z!tV=zAbeWoe?}BJk1L1%u&$pMzNmLNn=6MFG5s~+>%uoAt2c#jNjKis^E<+KmGYk6 z{6P4j@FV^DG3d^RUR?xIf96AfehkbJP8a423x!Jte~Dk03af={h3kat2Y-)WH((|> zAGJ^1rkopujlw439_7|4>=JehdxX8hhlR(L^9kWe;VI#1;giC%!gIp&!VAKF;YH!I z%I!HlKQH{LQeM*YYbw?2!uNz92tNc?KqkKca*ewJt%=Ar?h3RcBKwgF^&=JPM=I2V zRHz53fc@b+T;r~QP7=AsT>+gWa*ewJI!UBeuaH%*kX5gcRj-g$uaH%*kX5gcRj-g$ zuaH%*kX5gcRj+{kVQ#eN6|(0Qus=+pRj-tfx>7#sO8KZOQTs03~KI%&Os4HQynNA;dCFXbhl|Jf9NRJfhqppPXi1blcLV85{s4F2oB7M}A27T0( z27T0(27T0(nEkO-^ifwr4n+E>E75|OKYi4dnEjC=ebkkh_Yvu%u7rK&uk=w@!aft} zqh16V_5)o)w{Qbwy9n0r55QVI*DKv8yhpf0xJ&34z9D>5__pvJ;YYy5pmGT462>CW z#i%c)crm7044E^fQqNU--Z1z&QZ~Woxfo^O^Jb;j>noqoFMLDzrtodyJHn5E)uLN1 zy49G={}w5vTP?cPqFXJx)tI64SJJH(-D=UT7Ts#pJHH~`YSbx_bgLm}BI#B`&P39^ z9(~^;AR>2wh?oGz58e;-2uPZwTKMzNN3;*7G~Uca`!Ho|mfz zm#YSsgS&pDum+c_2A8V_m!telXALfgt`b>;%b}%2*5Gn*L}U#v2S-HK;Bs)(Z>)r6 zcow)+SS?&DTqis(JRv+OJS99Wd{TH;cusg;ctO}NyeNE5_`L8X;A(NVTHLJ`cdNzS zYH_z(+^rUOtHs@FakpCBtrmBy#ocOgw_4n-7I&+~-D+{SMpV{_${JBwBPwe|1viXC zo@+#9ji{^=l<3{K_aS{5a8!=WP z9uyuD9u^)E9u*!FJ|lcf-@XgnfRW@AK<2qYd2Ya*h$)kWOVDyRKtGAq!nMM6!e+hG zB5W153EPDo!rj8-djEv*r0|sRwD3vcS>ZY1dEo_Nzwn~)Y325uo}U-KBqT>0Fv}o* zjCVGIqo;u$;akFYft%FgHmSvJ0!Pmxg)MFq`eGtm+$Qv}M7Fq1=wXR$ahuS?64~N5 zp@${1#ce_lOJs}NgdUd27Pkp~E0Ha(R&uVDoNFcLTFDt}wkT~aO7%LBa;}w}Yf&mb zQ_i)RA@Uu{xfUJ+BIR5Qj{%W#u7$^dNIBP{{6xyR7Ud^W&b25%k#ep@`H7TsEy_=% zoNG~jBIR5QF8EA2*MbWo|T$nokl)&8u`>|T$nokl+OsH0_=$urip9%G)BKt>DKqo$Zn zk8VBci_i4y)`MRnV@>P9FOjjP^_bBT87*9o5dohWYg!L!90D#CGS;*n(jYR{v>xLh zQe>=YJw`i3#+ufn_DPYkruC?OB4bVKQTs&3n%1NCiHtR^hdhalHLZs{iHtR^hdhal zHLX{4U%jIH>J{BrujsydMfcS!y02c*ef5g&tB3qqLdKfbL;gg@n$|=9M8=xdL;gg@ zn$|=9M8=xdL;gg@n$|8)}t<162_X=qb`VyHLXWo@R_lu^%#Ru0*p1Shwia1 z7;9ROaTik*|xz-GatsYZG)92GM;T4>V?R7wr!{vV!M#>Y}-&T zM8>mi1MhrhJli&`FEHmpXHrRhYGoGzMoHmHl z265UTP8-B&gE(yvrw!t?L7X;-(*|+cAWj>^X@fXz5T^~|v_YIUh|>mf+8|CF#A$;# zZ4jpo&_I@loHmHl265UTP8-B&gE(!#O3KT4hnzNu(*|+cAWj>^X@fXz5T^~|bUQeG z+1L(FUj;H!XuH;rwu4_jGg4?f_$4w@Xgl~NawTy)_5SRf zj$W9^n2qh=n#h=q?ckdEFlJ*rxF#}YV>`GeGG=2txF#}YV>`I!Gh;TkYyD`u){nMp z{b)P5W}b}M*bc5)TE=W_2iHW#Y-|VDd}hpsPqxS>TjY~1^2rwYWQ%;VMLyXgpKOs& zw#X-2 zTjY~1^2rwYWQ%;VMLyXgpKOs&w#X-2`j4$R}ImlP&Ve z7Wrh0e6mG8*&?58kx#bBCtKu`E%M10`DBZHvPC}GBA;xLPqxS>TjY~1^2rwYWQ%;V zMLyXgpKOs&w#X-2`j4$R}ImlP$UjHCPS*Z=!Ir(2LsO zIsviVm~yY^DBD(7|%OIYlmp53~B&{8y zwL`Rapa%I4Y3)D_5=mPopePqbyIOEKj2>PopePBTCC0Xk!~?c^YMT8fAGJ zWqBH9c^YMT8fAGJWqBH9c^YMT8fAGJWqBH9c^YMT8fAGJWqBH9c^YMT8fAHQNvgXf z)m@V6E=iRuI;B|Gp;UKCs=FlBU6Sf9Np+W`x=T{sC8_R`RCh_LyCl_JlIku=)el_Hz4pBJIM`_1E_p818)!zN!i_|&x@T1E_p818)!zMT?|!v+zuLQB?cJ~T?pJ&FtG)Zx-u-ItezkYM z+Ph!v-LLlUS9@<#yJ%9oXi~dqQoCqUyJ%9oXi~dqQoCqUyJ%9oXi~dqQoCqUyJ%9o zXi~dqQoCqUyJ%9oXi~dqQoCqUyJ%9oXi~dqQoCqUyJ%9oXi~dqQoCqUyJ%9oXi~dq zQoCqUyJ%9oXi~dqQoCqUyJ%9oXi~dq2B*u6X7EU46l=3Qgw660HbYlmMG8HH&CpUJ zJ%r8BRX)>0*bLsGTk;S#Ljw2VnI6Js@Q&FIxMm7Hgw2>K6B)(YEDvF`JcP}V22c?g>!CH_heVKX$76zL&shGr7!A#8?b66qmqhGr7!A#9e1uvs3$W_bvk zAw!mm9>Qkm36UPcW_bvk6W7Rj(h zGHj6yTO`94$*@H-Y>^CGB*PZTuthR#kqlcT!xqV~MKWxW3|l0_7Rj(hGHj6yTO`94 z$*@H-Y>^CGB*PZTuthR#kqlcT!xqV~MKWxW3|l0_7Rj(hGHj6yTO`94$*@H-Y>^CG zB*PZTuthR#kqlcT!xqV~MKWxW3|l0_7Rj(hGHj6yTO`94$*@&2Y?TaKCBs(9uvIc_ zl?+=Y!&b?#RWfXq3|l3`R>`ncGHjI$TP4F*$*@&2Y?TaKCBs(9uvIc_l?+=Y!&b?# zRWfXq3|l3`R>`ncGHjI$TP4F*$*@&2Y?TaKCBs(9uvIc_l?+=Y!&b?#RWfXq3|l3` zR>`ncGHjI$TP4F*$*@&2Y?TaKCBs(9uvIc_l?>Y?!#2sVO)_kg4BI5bHp#F}GHjC! z+a$v_$*@f_Y?BPzB*QkzuuU>-lMLG=!#2sVO)_kg4BI5bHp#F}GHjC!+a$v_$*@f_ zY?BPzB*QkzuuU>-lMLG=!#2sVO)_kg4BI5bHp#F}GHjC!+a$v_$*@f_Y?BPzB*Qkz zuuU>-lMLG=!#2sVO)_kg4BI5bHp#GEGHjO&+a<$x$*^5AY?ln%CBt^fuw622mkiq_ z!*cSh_%4n*#Z*n=GIH1Sy_#k3 zh0K{7XW4rpPa*Kv+TW)8rQdqDXu%kb*H%Q6xW^N zx>HUUxb76!o#MJvTz87=PI28S zt~rQdqDXu%kb*H%Q6xUtix=UPliR&(L-6gKO#C4ar?h@Bs z;<`&*cZusRaor`ZyTo;uxb70yUE;b+Tz84c{*InYeOI&w}>n?HK zC9b=~b(gsA64zbgx=UPliR&(L-6gKO#C4ar?h@Bs;<{U0cZ=(8aosJhyTx_4xb7C$ z*kuUa=oZ)A;u^7m(By7$-7T)W#dWv1?iSbG;<{U0cZ=(8aosJhyTx_4xb7C$-Qv1i zTz8A>ZgJf$uDiu`x47;W*WKc}TU>XG>uzz~Ev~!8b+@?g7T4Y4x<_31i0dA4-6O7h z#C4Cj?h)5L;<`s%_lWBraor=Xd&G5*xb6|xJ>t4YT=$6U9&z0xu6x9FkGSp;*FEC8 zM_l)a>mG64Bd&YIb&t625!XH9x<_31i0dA4-6O7h#C4Cj?h)5L;<`s%_loOYaosDf zd&PCHxb79#z2dr8T=$CWUUA(ku6xCGuek0N*S+GpS6ugs>t1o)E3SLRb+5SY71zDu zx>sEHitAo+-7Btp#dWW^?iJU);<{H{_loOYaosDfd&PCHxb79#z2dr8T=$CWN5Jn3 z#v|bFB_Jbv9|3nvVPx+kC>xQHy^o-5L`L>Lg0c}A+4~5}Mr35~BcR9}7}@&>@_)hD zr~LOR|9#4TpYq?Q{P!vUeae5I^53WY_bLB<%735o->3ZdDgS-Sf1mPyRQW%u{2x{R zk1GF1mH(s4|54@tsPcbQ`9G@sA65R3D*s27|D($PQRV-r@_$VEKc@U2Q~r-B|HqX7 zW6J+A<^P!Se@yv5ru-jM{*NjD$CUqL%KtIt|CsXcQ*2%zsMNy8!PvY$L@5v%o7acl zc{7l)d3~VEcNm+8Q$K`^t?I)#=M0dsd3_k|@R_lBeTvQN!)S-kjLqwVSLXrX66ML* zygqn!h>XqaQ*2(JV)Odo=V3Zy^ZMZJ;WK0N`VhJL0FbeHeHa(*12Q(R4=dDuAY=3T zu&%=LGd8aeBMKs8^ZMYk#Qqt01c{8z>%&NczcMzj556M4!`Qq&NR_-WHm?s-B{DXz z4^kyEHm?s-B{DXz4`V7KWApkjrXn&nuMcA?B4hLV;5&K%cu;sqcv#5TygvAjh>Xqa zgYRfFkg<7v@Es8uo7V^55s|TZeTa5u`5Bwn2M-dFv3Y&)AQAh87ln+?>qE3Nk+FGw zh;}A2Hm}ckMid#F*9XrMzh!J*AEKT44rBBB;9p|OYr@xsjLqvq+$@o?d3}hRMr%aI=Jg@knZGhNZ@+BaerVmRc;?7$zii!p*}DDEy%&(ek=uS~9pB-| zZNF^Ye%ZSHvUU4q>-Njm?U$|FFI%@?wr;;{-G14+{jzoYQM1g4Be(siSt3Vn`%$w* zj@%C@MHX3bb&( zj*z?@5|u-ua!6FLBC2%qa!6DTiOL~SIV38FMCFjE91@j7qH;)74vWfRQ8_GL4vWfR zQ8_FshehSEcsVR8hehSEs2moR!=iFnR1S;EVNp3ODn~@+h^QP9l_R2ZL{yH5$`MgH zA}U8j<%p;p5tSpNazs>)h{_RBIU*`YMCGWc92J$LqH%t16?BH+>U`Rk#TM(ME8W~o)Fy=qI*JgPl)abw9v2M zP0~Ffx+g^Ugy^0S-4mjFLUd1v?g`O7A-X3-_k`%45Z#lads1{yitb6#Jt?{;MfarW zo)q1aqI*(wPm1nI(LE`;Cq?(9=$;halcIZ4bWe)zNzpwex~D|DqI+6&PmAtp(LF7?r$zU) z=$;nc)1rG?bWe-!Y0*6`x~E0=wCJ7|-P59bT69l~?rG6|3UvF8r$Cp;_Wl%d{w#VptEAGyUyR+i%thhTX z?#_z4v*PZoxH~KE&WgLU;_j@tJ1g$aio3Jo?yR^wEAGyUyR+i%oamkt-E*RQPIS+S z?m5vtC%WfE_nhdS6Ww#7droxEiS9YkJtw;7ME9KNo)g`3qI*ts&x`JP(LFD^=SBCt z=$;qd^P+oRbkB?KdC@&Dy5~jryy%`6-SeV*UUbik?s?HYFS_SN_k!qN5Zw!+dqH$B zi0%c^y&$?5ME8Q|UJ%_2qI*GfFNp31(Y+wL7ex1h=w1-r3!-~Lbo)iOUv&FLw_kMo zMYmsc`$e~3bo)iOUv&FLw_kMoMYmsc`$e~3bo)iOUv&FLw_kKGita_xy(qdDMfalU zUKHJnqI*$vFN*F((Y+|T7e)7?=w1}v|F6BXfs*UI&-xu%UzTn8BTA$AD-$_&>{wdK zj^o%$abjC>Y_ZrOcI^lasR>36 zL5zi0ZkGjemthd52$P+ey)$IP4BW$V4h_%mxigkz$7$7WdnB{cnRo8qx%a;J|MC9s zec$*0KF?9td(`zFb-hPj?@`x#)b$E&QL#}NbuNj<$6W6**L%$M9&^3NT<nFFE49BpKO5#Cu8gQWEiAQoWQ! zyyG7KJnr$&;~xJ!?(xs#9{)V<@z3KP|2*#T&*L8dJnr$&DSOwHy=%%|J!S8jvUg3{ zyQb`2Q}(VYd)Jh`Ys%g=W$&7@cTL%=r|ex*_Ub8n*Oa|$%HB0)?|Mb`mV;MRFXd$} zuTVeY71jHMN-)P>k)MpJ{HXW*IlT$Lq8cglK7P!{7hD#-r!0SaMcSi0=>0$C?Wg_g zU-BMM#a@wRDd)VW?y})ynl2-kEtd=awd1nuGS>cSTXx!(owjACrI}OO&$DdWmYud` zr)}A3TXx!(owjACZP{sCcG{Mmwq>Vn*=bvL#@3m!b!Kdx8Cz$@)|s(&W^A1qTW7}B znXz?dY@HcfXU5i-2`PkQvBvOy^6(TDEQhwjmb?$L+t(TDEQhwjmb?$L+t z(TDEQhwjmb?$L+t(TDEQhsp_gQrDzMAG${$x-J=iP zqYvGq58a~=-J=f`TR4Uuedr#2=pKFO9)0K@edr#2=pKFO9)0K@edr#2=pOy7{OV{h zYyX**|GcbiR@=?Wb0}GDH!Gi^WVPL_yoHk0cC+#gN>!)h{RIQ(? z^;5Nes@6}{`l(t!RqLl}{nV_Vn)M?@J>6l=`l(qz!r<{9^i#8bYSvH9`l(qzHS4El z{nV_Vn)Oq&erncF&HAZXKQ-&8X8qLcKQ-&8X8);KKQ-&8X8qKxpPKbkvwmvUPtE$N zSwA)Fr)K@ste=|oQ?q_*)=$m)saZcY>!)V@)U2PH^;5HcYSvH9`kB+yKR=TA1AKiP2pq*e?nf3l&LqVYAg6iV`?8)_+(tlem+T~H%yHyUael&sxoNGH@t z{$xWsp=9kwLpq^k?M6d7p=9kwLoJAswHpn!AWGJ5G}MA9S-a8DxbO8U!3l5ZiAnjK z%U^Z*yi0Jx8_u6>sKs%Itlem+#Zj_$qoEc@`3;w>-Ds%AQL=WUp%zEU+Kq-<93^Wv z8hR#jW!7#q)cV-Z+Kq-!n7HryrO!n7HryrOZ8`(CX$v-O!KN+Pv;~{CVAB?C+Ja5ROpW~7f=yenX$v-O z!KN+Pv;~{CVAB?C+Ja46uxSf6ZNa83*t7+kwqVm1Y}$fNTd-*hHf_PCEjX`eb8RrM zI711>^1SSLKqc7P^RgNx7|Zjr8YLLZ^Nu<5iaCSYroS`q{?5GO412&>p4WS9MJ3qU z^NKuN8I0w5*^3g4<#}0+Z7`PSWjnUN;Om32JTHq-g0Va=i%^2GJTHq-(i@tWPS^%x zdEPyvd1-*_fU!KUh{Tn_Se{obq6A}kUfSSSFqY?~4N5SUBl~k?e~#?Wk^MQcKS%cG z$o?GJpCkKoWPgtA&yoE(vOh=m=g9u770dGH$o?GJpCkKoWPgtA&yoE(vOh=m=g9sX z*`Fi(b7X&x?9Y+?IkG=T_UFj{9NC{E`*UP}j_l8o{W-EfNA~B){v6q#Bl~k?e~#?W zk^MQcKS%cG$o?GJpCkKoWPgtA&yoE(vOh=m=g9sX*`Fi(b7X&x?9Y+?IkG=T_UFj{ z9NC{E`*UP}j_l8o{W-EfNA~B){v6q#Bm1-XRuqw1wqVN^Y}tY>Td-vdwrs(cE!eUJ zTee`!7HrvqEnBc<3$|=Qtu~hhTee`!7HrvqEnBc<3$|>*mMz$_1zWaY%NA_ef-PIH zWec`!!Imx9vISeVV9OS4*@7)wuw@IjY{8Z-*s=v%wqVN^Y}tY>Td-vdwrs(cE!eUJ zTee`!7HrvqEnBc<3$|>*mMz$_1zWaY%NA_ef-PIHWec`!!Imx9vISeVV9OS4*@7)w zuw@IjY{8Z-*s=v%wqVN^Y}tZsN2InRQri)!?TFNNL~1)CwH=Y#j!11sq_!hc+Yzbl zh}3pOYC9se9g*6ONNq=?wj)y85vlEn)OJK_J0i6mk=l+(ZAYZGEOH`fJ0i6mk=l+( zZAYZGBU0NDsqKi=c0_7BBDEcn+KxzVN2InRQri)!?TFNNL~1)CwH=Y#jz|lB8(ffA zPX`Nr8(i?);DS8-fcEg-yCC1@SKfOUtcL}^4KDa?aKUeb3w|41@Y~>m-v$@_Hn`xo z!3Dn!F33x{0`I*G@={9Pdl%%Tl)U#Y$V(}C?_H25u+4k#g5L%g{5H7Yx4{L!4KDa? za6xwGK6&q5@Y~>me1JW?_b$lp(?Q3Qb}VVfl6EX<$C7p|X~&XwENRD*b}VVfl6EX< z$C7p|X~&XwENRD*b}VVfl6EX<$C7p|X~&XwENRD*b}VVfl6EX<$C7p|X~&XwENRD* zb}VVfl6EX<$C7p|X~&XwEos-1b}ebwl6Ea=*OGQEY1fi=Eos-1b}ebwl6Ea=*OGQE zY1fi=Eos-1b}ebwl6Ea=*OGQEY1fi=Eos-1b}ebwl6Ea=*OGQEY1fi=Eos-1b}ebw zl6Ea=*OGQEsh9&5jblgS*wHw4G>#pOV@KoI(KvQAjvb9-N8{MhICeCS9gSm0S9XdF8l$BxFaqjBtL96K7vj>fU0aqMUuI~vE1#<8Pu>}VW28pn>tv7>S9 zXdF8l$BxFaqjBtL96K7vj>fU0aqMUuI~vE1#<8Pu>}VW28pn>tv7>S9XdF8l$BxFa zqjBtL96K7vj>fU0aqMUuI~vE1#<8Pu>}VW28pn>tv7>S9XdF8l$BxFaqjBtL96K7v zj>fU0aqMUuI~p&_S9b=B@={7>QWj;$X_X)gEy{vbm8=_Dl4H?$}Vvdy}oMR~7Q zTX`mBQ9gV?+svda%6o-JAire~GbxLT%#_TeEXsD&!c5Ad{Fyz>q%3+SWl`2-KQk$d z@^gM=CS_6fqDIyYEy`Y$tQ%UCy(n2Xv?zN~vTkV6GbxLnNm=wv%A#5Ucg0M~qO?cJ zOvU?i|MX-K#xwm~$@aXE#_qJCC8&_9*+pB_4uKr$cdv&mJP5+u}f+yEJ*4w`} z*tX`Iz3q#G>(|tK+v`@nxOQc4`;uVWW#8&;Um6Tw*6wXzmipQCpX_a~4{pDF_P)Zz z!D4P?w4Ad z^ry0=Y;j+9IDLO%yqtb0GnP$n8qAann+DQ@xuNWMNk2`F4`++%@@O{w$b*CFhbOY* z$30XTL(D#Q`wQpe5Tm1IjOi`@Afo@sA3rTG@34`_EKT8IF#j_ExoJw{9GxWNtcV6;p|wZxHnzc{g$E+^zZDA zI(dVNPG7c^ktT{cE;*6iof*oecW1_O`Ge`YE4B50)ibE?Y`VbwinAcK2jnweQNv zvbvd4L3W!cl(XaIT!tTp3gf%;xuJ4yd?YLNF%D$7_uj=1b7?uZR50ulpCd=vlK65x%n#gAkCY9>SBf0TR z9>wR%rL)hL4~$3|rQB25(m?uAInYo(Q!3?#bo@lIFi|L$lXO!rt^)X0P;{-Ip7d9(RuD+N{P7k!AyF0Hk-$o^6LGPvpl+4s?JGE7Oq?@=(ke2I5||FEXoy%1;mh? z<;<>JK37h(f(sWWOXJy6X<)Qmp4h&1>;C=w)fy%oAqIvDV_V;9f8TjaTa!le*?xQ8 z`iF@>!*WHX@5zdVzAFgq=Wl)rE%B%kghPMy=l#u3~IZqUp9$J zgX?phtd8ScYMgYL$|KP;Iz_RMRaeTB{X?J*rw)b(<%KP~wN{OQ-s zosOs;q%5kAvt>S0;y22>U03g4C6V~_b@;8X&$l|}hu_&YA^3kpXFsm{D(QZ>`|;qG zo+WbHhkmhVqNjrHy=blV>)B%MpT3v={tA)eK51AWhb+&ZDw{c0Dx^xgNzv#-m!KUx~v*_mFRcAbed`2QoaUjIHe>1xSc zCao^9_04V>4@%34)o5{8kyewI>{t&y;K7OP+;3i=@t$T%Ix=Z*6WYR~Xooo;m7Fo8 z{o}euUVDf9+qg8BmXD!tVH2t33~I)+`75pMQT;}}v{W>NH>HEmX&*-AJ(c7?ceTxVBw7idy%dQRlFZ=ekHs#5yf$a?c~a9@^-8 zJokn6-nwqCRh0CJXW&CmX}e@AJlcyuL$0x;z33~sKDwe+QZu?jqosfdl*rA#A#024 zCwkwfeOzOg{zhA8`{<<3#K&pfi3f5uWFn>_Q4$Y1x2*phx!d)R>8fY82yBh7j{1Ad z_lCauaXst$NBlRfiCBD(u6Vi*+Ct(($iWu((${9m=Vu*7-rQF6s;}VRh&6k4E_aue z6gfwrj*J3Q?<{g%w#QA6^4;M#a9&%VC*4r@TP}`FJhyKR z?t-H-@=C6SjnDKIBu%0Mt(NFYI~Y*S_~3-%!&d#@@BhiOfi{uEBXmZr8PgHxdi>cI z=ZU`ctl0b6H@%N+{S$ldx#^sx;mzy9d0XNscDB7rvLjwFA)8};qF7$vM86SP=3%|> z!F%^czxacl7X&Ljk`XB5@j$Y5cA0voMmARHsEafXvnp7v5ty~X#mX4GM57{?X$0hQ z@#0=7?$LJy8-jNRKNh?z*ciM!xH`BdxHh;>v*quR{@<&o&<)~b{Bf}xzF!jFtg)M0 z)Q-03uDAMK_%?Ax-7cn|JH+mCr$#fk>&@&ZgrR=7#xXyp2zjqOY==;t?+-p9%;X1y zox&L&4E~G|h9B1Z+Mm^X*dxKCLW+G%Z*!j(QtD@fPWl&uzbI_Z&jwEhnbbvE@$|F7 zUkU!X);ep3Tcb!nAN-x**MjF#8eK}Q5^Bxg(%5=8_=P}gcT=l_-wpmp@T}IK{IB4D zYW(zY@DG(sIu-neTIx{nj3UnOs5PDlemnR#$^`w_!Hi}`cWdPE-v<9K_(!tJ_k+Ko z+^N~%-^-S*;J*urV2`Y}SFJIxcKj={-RB$&N{S3+#m@bj^E{xZ-$CUh3I{28G5EW| z&jddm918xjW>dZw98IlBtquNf@O!C?Q|p5N5WE)rx6~!6OM|Zm|2TD7YJKosWySnf z>hjbTsVh@gDL1AOJg*F>|C)M7@SlQLgZ~_y3jSm8U$oZs8(Kl}&ETIZpZJB~p9KF( z7(SKYuLi#!yc~R6<7eMWZ3w=k5!zpt&A$@-ZOu6Rs?Y?!8vOm>uM1D$mx6zm`Z48_ z|I5_7QX5n6PFQnHNQ{K9hVs z<*#+087`DFLtJ>>Q?GBj_S^2eYvso$i-lD?viWj`UANtF$6Z%=d`f-Su}tr@kz!_F zc7QR1%Z78hyHc*?zb;8`-P`M2nKv&V$`ywu$9Ctl2a=yOz)~1bHg^@(zxU?)*YCxD zUR+dnJUOPE%MT~VTsb;9K9VU;j^#6x<>bfYTBS_Btag}EySpk_^MfC#m8JAIj4wNb z6+7-9d^A{}&y>g2&Q{W1bp*ek-qx9WH4GN4cez2o@q1D-qDrgRC}oh^IqtLe1@Vga zUG%AoUR||r)v?u2tl6-(a`EW8d)MVJx$2VdUV7uD?e$l!fAR9-6&tVEb7k$StKV^A z!}s3#!n;1R@!E~gzx&X;U%qbj_V$~?#T7q zuRs2tPWqYm4!n2vh7~sq-tgu3-TuCx{_(Hfxbyw*d;jm;K-iecRKwZMyBm2iJe_(GPy*gQsr4@%H@f-~P}QAKLYy7w%Yn z$KV~$-tqkp-}~WT{BZrwJMaABUBh?%gS%$8-?;tA_V0b#nNZ|Gkp)E#6d6#@=|lF@^ZJnabVMJrp2&G3OE1z?A`020R&HML(bq97`}P!Hxkp2Fw`nV!(<4CkBid@L|Al1jEtS^nu+7ZX=kD z;5CBP2u>pyjo>qa_X5@nIE-MtfbU}2Zs%gREtXQ;R$; zvb4z2B14OnD`aPpn?+_8d0Av-k&{J67Wr6YW08yXe$SGV_dvEUxxQpPkncdY1Gx^# z9Y5n4adLaf>?N<4tX^_@$>=4Ym#hYI8pvoMpMh)!av8{EAdi78267l?buM|kWbKl( zOU5pF3uG;jt4qcL`3ht!T$noDtM}Y(dO{rV^Y$`r!|w;XAKZR0`@!o6s~?Nrhw-44nIQwAigRc*^KDhcG*KF#iwGB%j z9DOkK!OsT|8{B*_^A)uX+Ab)#F!I622X-smYcTP_!v_l=9DFeF!M_Ll9^89h&^6)R zgLMziJs9`k+kGc84>n_y-k{38$pm>4d z1%ekS*`RlU-34+N=nr5&fcyaN1E>#RK7jZD-UDb4U_F4*1$Q~j<)Cwc%>}*#=nkNA zf$R|L8&roooFPDd0NDZL29Oy*UI1AEV>kM3rV?qH8<-lMbk=I$bTjIQvx!sZG)Jlyaw!@~;?D?FU=Fv7zJ4;wsO@G!x{0}l&4 z9Plu}!~YKZJFKcOzr*_u>pPt9u%*J43NPvvlIVmanvp~^lIVn_5E`sLASQvA1X>bU zNgySGlLSf<7)c-`fsb^nY|MJ#*W|6Q$y;BOr@kgneNB3JReE?;dU(}*g|HRE+zwMA zJcV$!!%+xBA^e1}6T(dhGa69MF?nBH3-unJcFM*Lqr+%iyeQDuPhd~|wblB73PKP-i-gH>g;Y^1y9lmtf(&0)6 z69_~g@PI%A0t*NvAmae3u5;JI*U!+x*R2J3&tW}>^Bl%=_|9QFhwB`sb9l~SIfvsM zhI9DMFN}CPAfMhRpI$4UUMrv8C!gM@mMMlZ*%AhF_{U)%hkN`{ec&C3bsWxd7{}oo zhix3LahS&88HZ&Yj&T^q;TMNp{MU3Y%;NBh!zvD^IE>;i=mVQLT;ec^!y^uhI2__I zh{GQadpO+TFo(k%4r};@q2CQ^58qLHIJ+kdxA&cTKK!WOD@@+-c*Eiihc~@W-oyX= z>v0wC?$fdLNyXMDRU24kPpigf)dHXO8e(|5Vd;jW8-{N9xnbvqn;T|sc)4Naenj6e za>K_B8~3O64HGv!+^}%N!3_g9{M)c^!@UjjHoV(EDmKHj4a+th+c0dyuMN94+}bc} z!>bLeHk{fpYQv`un>Jk9Floc14U0A$+AwJUrs{<~8}4kFv*FE#H5<o^5&`h8LPK z!lcgvR`V&fw4YOaJgm2uO=@9>)v~^#7Ij1|>hy>N+|T_{iO1AdlfK3&wU$%8zQ#87 zHMXhMoKimn<^}p0r__25E2bV+Og*fadRQ^_uwv?A#ni)UAxG3gj;MtkQ42Yu7IH)_ z28USHwx+vGha zXY2;B7(rqLhY=J;Fc?8#1b-3qMUWb>Iqx-~F81GT;6m=d-|P_j!2LQ8Oa>4cKv;zP z80KTJ6+u=6R}oZ2Fcm>m1bqSQ1&|lOT>wWB6h$x;K~Mxg5%ff`6G2V{HxblCFcU#c z1TPV^M6eP;N(3hnl*AwPJ_ITvn268m19}432_Pqcga{5ID2QMnf`ADAA?Sx-AA)=c z?jfj$U>?4x&ryBAMgZ#&q(g8HK{*8D5Ih9X5I{Es+Yn?!a1B88G>a9 zk|8*TpcsN-*wqL8LeLAh$s$L47I<0Oe_7A9m!x#~ru%7E<%vLi@A-~@pZ1V#`DLEr;z&{aTLe9j0mAo+pg$9jIS^gz-BzYlg? zu=}3$)y0UV<3NdO=mTC~qz_nqAoVT%6|Yj%5^u0R@Y}*}3%4!Iw(#1*Y73_=jJELE z!e$GXEljrX*ur89hb;`YOQkayYT>7aD-)(ncrszhgd-D%O!zTj$AlXbW=wc7Va0?K z6GlwHrMa)AxysVpZ|SdinY;ilD0rMs>V4s)V*E+P_>+q9Cl%vQD#o8w zj6bQ^d{UkOOOcqO^p^7*ub&B{D?FpHjKVPrlPmn9u#3Vi3bQD@qOgj>DGH+~e4?<4 z!X*lmC_JLDh{7QXgDCu=u!q7O3UesDp|FO+846=4e4+ijS=9cOx|@pR&^m5?;9}jN z`&nAwI{&0Tf1VD@^IYdL&vky!7@gmDcVUd(EVqYqX%AQFdGdgIO%Lcf@_;kX;6Q`{ z5e7^6D`Av`PZBmsxFlhcghvt8^Bsw}PdUbJ%wUHOEYS| ze3c(QzqB-ZS^61-4Bw( z^-jq;r$fp+IiwtfvT_j0%0VbA2cfJyltaoxIix(4L&`@eFVWok(rae<9drWyV z>%z|_yYMAAzvo}h@4H)`={uL1zGZEli?%MzRmRIUJ{KD=YwKLJbz!!M^ZN<5e0P6% z9Ej!CdoHc_?K={Z64u!&tpT`1YXJJVap1y%3U_l44X%#__huY8@ZZ3G`_n>w>tnwC zg188l+S5W)`@FE-Kz{o^Hl ziV)uZUhtgo&YllE6;O#?|T7Oz2q*>$Jx;Y`e~>tDy|x=1KoEA&?%w@XX{!r2qb9#~|- zjV?Fmb0eAHHkWsnCMQb4-7a_Z(7a9~dr@1;b%GnlHmH4Twf=u&Z|_FeloIk@a_rqY z;@;pAQ02gr152)tA}8#)l#utp2wNf4ze|OQw;~u!tx@@~KAUyrpR%4)vgUolxBHxI d3)lz{Xfc9M412p diff --git a/docs/fonts/Lato-Regular.woff2 b/docs/fonts/Lato-Regular.woff2 deleted file mode 100644 index c4e8b1abc1e5b3fa634da8d623231aab3ed24b1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32704 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/Novecentosanswide-Normal-webfont.ttf b/docs/fonts/Novecentosanswide-Normal-webfont.ttf deleted file mode 100644 index 8cfb62dd59e199f956469a9bf7576af6264c6e95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56884 zcmc$H2Vh*qwf4-tTUB?pP134tkydTht8K|%tILvQ$(CiwHnxll#vR*$vB7i#h6F-F zi%l>+BoNj>fDn>E;*dNb1VTt?0Ur4&A>@Szyu8Qzt=<1SbMID3#wH~HUhUpCcjnBQ z)91_;GR9kRHLs_$tDBo}hw(9-yLyHeExF{C!1FlY!&uEo z&yuC>zrDEK##rsMjHS0MT2fuNzT~d67@LP@*u>hcYjy+sCmYtP#4GQX<* z8e{W&alduLj?=dObjQ21aefJ7sasB4vug*gn;0AT2z$e6Th7_Ae$T!?;QW6W+j4B< z`Zeq1Eo(n!?1!J?e$z%=(2vV+G4_}r=S3U0?%wm^?UhEH4>2ZRwPpL-HM7b`su=t6 z>uCR1Ti5K_A-VXwjQ#Wuly_}gvvvLARiAX?{3v72rXAaN?G9gf%JYo9dWacX4vXglEM@-kE*A@Q%palO#q`@h ze>r{^E*ik^;6NvShX(rbyLiz;{Emo{Ba7(@i`2t6uiv?i8KN!AIJPn$lW;|5S&g!eG594@)fK0~d*jXOVbD18$3&Ve7S*$30AFB*s z$~v)M7`}>Kfc=H|UWD((_+EnVrTAWk?_qpz#rHORZ^!ozeDB2fE_^wlv9X`9mzk8G zLG9&S;~Zf1)DxDD@Bi0N_``6JrH5Y*zZw2JzQOQw;oto$0Sdnn-p`!j@1o^*!ncIK zg8kD>kKYdg(>viGhYz8|Az<*I^Rb3s3qQ=P;iKsN{|$c-ej)r(_(M=p+$TJV6FK}z z__Hq`3eXuo;TM$V&;nyA%5ki%@Fys7G)%ICg+BwlpM_sm%X}%j@EbJ#N>xfLbWE)( zpV(34O8ni}wJ&lM{z>F1K*7SlrL*vJk!$~&efUAp+dW~(Ur^kG;kU!@Oy6!I9>Ra0 zzSK!xmBpA(L)|eb;@cIaPqK*QG%en#9HEEO1yKjXW;R>!2i#H!rux1 zFnk-1Uch)f1AcoGSAviLZ(xL`!O+RJG+lXc{U?wxe+%CPu4myt0*dEUULY-^e6)b( zFDUmuoreERaAE&$_+!BLVfc4|?_kGp!qYq@kQT#$Sh7XGKmr?e|xcXoW>k73f5H4O68Qfx3@dKR zCyDk!v!s#K&lef-$g{Ku-A459OVGcUgnxv-I-~kG7~cKQ)W0gd6CiqgtqIgkS7!cv zDV7uPEn~#qj*J+Npa;Y!#%GWO;g`VwimrZJ;eTBF7)S48dxLZVD1$gim6b92n7IRV z2bK-#^h4kQ();R2$8-zn!tfvQy-Sq-5M^-`z7I5@${JN#E3mzWd(feRisWf&iK>bJ z0LMc1s60O%|HT*ovh7vS9zNj<@qH)!u-cb5!#~D3S$|}0v+zy$UW@Z!_?O{(!`I?0 zh)uPb6zEj`6MO+3ay0x5O1%KB{sNx+F}4rG_Y0l!2Gt$+$-wCChrZb#z6)gzVhe_E z6D!*`MK; z@cj^UHv!#qp=yz487z z83YBs4~Xaf9G(O&Coxh<)=&6eai8QL>^Siu$^tzmf8u2qN}PfFDdEd;^mp|3Gokrl z`Qw}@|K9LJ_$40MgmHQYRPaprI-K1Hd`0b3Y9V~1_!T^X-U!;j*gqGM>)_RwaZc8= zkj=Og?Lq8_>iE}x2ul&HMdZi73JQVW&%#$nC_=$kL@Fy+2`1tR{JsecK7(<(G6tXe z#4mB@Gf`6T4az2rPpo{>k(p{l>7&B_e=YnXjw2M5RP+Q+DR%J%KLoETe-sK4)*e+B z?+-_K>I*h9^)b@_Z^HfxDtsZJ0KXmoLlhg8|M8_yUMG6M5!XTfT?@W`4f5x1l9r^4 zg)Q?AxNZ|H-s@D!K=qp_k~JM?TN!)OKjQnedKKsD5v(fp2)qschlEF2q8K58 zi2l%idic)pV>mj>>L3^4mxF6x3*U_^4+)J)52>H(jOZ^fS!cP1697PY)U zT2@FGNLUXd1n(yKBkl^^s2GaUUvkNr&LhuFy^lLilGxBIpH15~(M_Ue zqDs^&Q|nW&oDeUBw^3=t_7p8AdQO@G=iq;$KKwq9@3qiAN5fCz_iDg-5nWe4O20^t zqLiY4qWFtR4zd+Ri6o6E{EH``&+bv42d|N|74=}R)I{|9OS($upwt(H4M_5e#!S=* z&iDkQ_ga*Ksk)Q=oE+VrWaTpzC;119`()%Q;&dm#g)=oc^*Ss9efWOm`oG%uh2;4V z6lB7O3}5lCZHgsX2Ol05SVa_e}X>9Gt5{*D-^_$bsowGJTzl@hO^ zJlSW$)}C7O>`k*in+UFxFc<4MGmlc$884mz@ToCB7_G^bfaU9y5+JO%x7iCZMEn@t-4VU zXiF8}RP1RZh$_|1ie6dKS}kz#k9>*&g_gYmF3A@CufS0TaMg-R^MJuTKxILjb*uqn zG#gN7;;25Z$#j$_7|8FXkFw{=iF!`g8qtn~aWgU}MxzW@tQc+OV`EKdrAchcUZb8V z*XddgdauXG=vV>zZ5I#v)aMm?(?!q9K?i2k$Up_LPqjF#Vr|h&xqv*jMS2juEehyg*(iII{fwQ-{vF!|Ofr?D29|zT#zmk7;1HJE!36le^b=TN!Vde=D;5>P z>$#74;3+-`i8u)>_1|#xCZsd0XUI*8o~7XGm!_9z=!J}Sa`FA=e25xUU+ZKVARVRX z$m2aF;u!@f8S(RuS6JLbN%Dd3175F%&lvGSNFz~v5w-+keaqQylmq7KDMiMK6Ju4+*FQBWRPD#eg&kq^n2h}}YCDL%r2 zLzHK_kK#E^d*`w66R1mgR?7W|KQHXhn14>#RV=S0ss!efuBi2hNCd{_&6tIy+&S6b zSd?IES8Bg+t;gv={U#>kk{Rp8g8c~8@ zMB^fD$M2KxfFc!N__3+nG^H%4XF5Bb>Zh2f*e6I*@G;4l7s9`Vtc}8?L~p{sQl2=m z--wSH*^9OmihLpbNF)+_Vs%X|H62A_W?F$gf!0XN{Ehmd`E2wh zybs@x5T$zt`iki1J`rO{k^%5};d|olXW(+OWX1e9VH0u^%^|*@(heAGN zCtUiR6Y@8xNci@t1;dA@Ui(L`D7Zs*Q-bgO6$dhNofzE+YVu#<#mi;RE8)t ztMZvTXE+m1riBBAr(Re6?xT^K)L8fzp9hFkl(e5t)(B}fEoNf9PO1i{pywO$`$Cjk z^@!aN{8sSV>o|^LEb^>qJL2J&g5m|=iE=_`qPCOb#7Mm-H>%O6j;j}9rQq|N^hZ$6 zH1_%-$jQV4R z`^A;FBi5PdNs7{+*we>5QZfNVf(Pt?L0B#X=0CC&i)<#i9>6!tb?+o|r^W3Q*P#514wADtb~TdP4DvT)<8J z@rwSKvG=0RB5WM-As>#*u^B|PMT_W19gZ8Yk>B0~+%{v=u@-DL_|&uE#m~X!M%<(o z-f|nZDuEpbeD6-tgKogL0Gov^#FohxW3#XkY!-Ojqkwc7Ha#1|mcqu_a`b8iwtTh{ zTN*t0Q-Hg5*et?_&w>xX8OK|&l?qSZB0PB~yMSGWUVH_cfn5u)-T<%uM*QBy4guPm zv1!<0b{C+!8=Hka0H5CipZ`(({*XP6)_;sGjr|l`8hZkpfjx=Mf~dgH@GOm7u^6*r zFlptxkr7WaoudW`zELTTlw5g=AJwyO<6K57L^G5>FV9%Ik1avo_{^nq#kfcE z@S9J#`GdT2_Y@8C%%U_MPjtvC&;;?$`yoS5`vMuL;NLfKGiHI54P`mWJzOd2mny z{bq_^ii4FRUfIGnvK?#>xZ-kl4fx@>`&H`x z5_KO`_irnEW3IX%Q}>6|{k!TuB=%BDK}x%Nv@+!}UKEwvYzp*0a(AOq-2 zD@lqVwK^eXByh3J&SAUQZd{jDew4wZr6|z~={f{yvkv^Yhh4<3LKzS0B%E+?uY_L< zxK`ngf6kH8lEUkr8R7c>0Z|HcK@H@4CmV!ZJ{7n<3zWp6-RSer#!x(7T;Sd5VENZU zVFX20fuGvh0QA)a+a%~oiCO(~FcIJX0&x4(_WxPEkF;z6FZiMH1JK+f&{`WY=EMtM zZo84zsMb8lwd6McIj!kI#pSSR=CWQ$iIr$unM?Y|$1=V@v=S__oiC#|krrq+C?>^d zM(rONn@Ft$VK!uJeBECh>PW3xjBSL2IV_@+hcr?X!D5G&j@5Uv&_!y}V9XV+A}i}e zA&NXrty-aJB6XY?6p^Q8;Fu_#w9N5ajyys2XF-E0&mFI|$P*Iq!fER)XV9xkqi~ifDi0-B=0gWgeg@no~}L^D)pDX?C1-14z!h!2$dt6(kAoaR)R<6DY7Nt_>Ps{wkW^@N^{ zJx`L5`lYlx8*-}sglmY^LV82#uL45=y1e(K>WS4wIye!YZs>)`*a>} zX+`em;=UDM@=B=$(VU!we;L=P9Pv=36h#Bb>x@`#)0e3ewqbG^YOgg~6KA)e9*Qfp zp?;bp&V>#AZR8z1fvrV>Jbd1VNoE>Ln=?f%D6&ov4!59xK|J@U#eD4*ya)CcaB9 zQ5{#J8h2;1pJl0>Ujtg!NC%`b)YGr*`6|}Ohj7lcdJK$xI8YOtJ*c&wc2&B+XHWlKIwSwFuRXE%onSrnakwLcIBz1XGKf% z@PCE>6#f}9GoJ`=3on?QoP7VSU%d6iTR(p5@wa~X*28ao|E)XUy6~;WH=j@;6xE-| z4~I9TbP9V3PtZ61gPXEOtJ52dDXD4c8JQ+?mc?qbJF;_foq72Mg)Xh*MMJ}jmy9eOT{bqpe8tLB zR;`{`!!Eh>D_4B|`a`!KzU_|N@4Wk-?|k=r_uc#b`;R>Mz(WuJ;ISY6=y7(&y7i~O zcGfN1H@|)6CU)74Y$rpAMSQmGWp_P#{#tRob>Hi!UU2bsPdxeJ?_Pf8rQbioe)==^ z?{849+u473m0fh;!YeQT>esHm>Kor=*M95ZP3-4Kci`3@@#vJFMWD}K)=M-1N+4Mb z>ImDVr^BD%d`|e&@TYXn+|oHg=640z(y^{_m#hC#mNDEP)Gb*)7Hn_^OUEZRxDG5G z3rfXnen`njYu9>Db-LX_HXdXh-p&Vr`i_bA${_a#T@xEBgOcC1&J}!OD5&u*f1s47 zbabulTD)S+?R7g3jJbkCLu2k>VBF~nw$M?___*tcQfSS(U@0!CXRcrk-LIjNPYjK@ z0K|bcu3*a0*aWV)=w1pPHPKPigmYqieB2r2731UHAR8K6KR#X=l>M$QS5Q;D1^{V0 zhQ@+gZ+lSZZ3p<{K|WC#)cC!C%eC%^_SAM4-BB73rgY$TS5Pi@<7$WNfa?HiK2oDC zJ}^8sG2~pccznz|j(dS6W4Pg@4ymnH2DSd6zN6v+5TQVe4yWFBFVO34UlWv0-4Nt! zQF%~XUK!N;T?Ali$J$3V>{Jv1h=GZ5Dl*Y205td?(5JGFuJ&?w6wyY1BH~k&T6hIO z=s<5LTwMpeYiJMzmY9<;8FV=TWCY5fT`~w*$|#cleLU zw9ob*(a=7}e?&|BT>lXr?VbK3dfMmtj~Hm5?>}OseSx0^(<{CJAcX*=02R0Z2<_bf zg!Uc)LVGU&p?whmp?xs`p}h})(7ptK(7qIa(7w#?Y87-|?nnPk6Rr-z1r6F7?1N=Q zR2BYUc}1`s?BWNd_JE|OKk3Uf)XzZw1 zf1t|iacOYn(Wq7zbk}KeGlPL6La7*R(jjXrUYZ!cMe; z`le|FfRH5AfV+WvEeJ_FrB>9q1`ihtAn*$nLLw~I7O13|aNt7gTAzvoZ!1vKA}$9F z;9i%j+uK8p(P+&QD5DOj7-b`4RjyVjJ%U)hh{|Fp*A?Te54WOfRT-$M#5LhnM+Puf z24|}fbVP<`g7j`O;vz#i$M1Dj5!SjPbz8@)j#O|f7_T*Y8KW7y+!nnoN=F_|C^Od| zY^;dfNvL$5KiE`p05n9zascc&rC|(9Rj>l>2L!r^03+BX;_`wks=y=)jPoHZAfTg^ z8tL!nlVZVF7Q8qS6Shp z9|xQc2K*0jab+P6#FarR(~et!4fJ%2P0I54wh0GIvAxg z0URu&GITITW$0j>%Fw}bD${|36;y@}R#F){IEBj4!73^<4+pEM3>{2R89G=)W$55k zf3P`<=CyPZoP*2j#8E4b)(d*VrB9<1QF@~|qSB{}BPzPdADk5}x|vQy z(JkVLif$E0RCJp^I6GQ&JDrH4JH!zcJwqH((VhMWjT$Lp8MRjg4eNt)(a;`JHI=ZJ zIeaIYBX`4JDVM$lPfX9MU~yEpKA_j+{k86hPWyW61G0oec0{JjTDtszUYCEY^#M-T z>&T zeDYl>cXD>VKQGS@xN7{D%DY?dT&WR zzWX(u+COSLwbJA7;)AY8h}bY`J3JaE@&MJ-7 z_|estiM+17!}(qL6V{35)z(#cUHP}-Y>jo|-R4`HAMD+XPw%rmoABv*_F0UxH+&a= zL^^R`2tAbT(^&r{ua?fOjqW^OsWO=yZkoIi6gP!)~>hGE%ZqvvfwC(UN6K*E%YST#XGbTeIx7 z@Vcf3;L~Ph;*wrD)miP_OE1HF?D3YzL!lyk`lNokZ~+|`7ZtsBe=vC0C5=wjOaOem zA zYvh01wRO|>KuyKG4Xd84=*_=i-~73}?e3ded%C;6KH0N+?f8OOeMZUHF{`Klo7N4Z z<&E9-wKa_w5dnf%*?z&RIjR)EI1-xzDB^ipWlv&FVoQ3aC0x#z$W8 zoynmuGMjj-oGyJ^8q_zT^6XV)Efh#t>C>F zLgbAE048uo&}}Ft*y?pOcJ+0TKstTNT)xGYlkadA)|R>LZrNe8Iz5HO3o^ZiGQhQt zh4@>%1J7p%Y&d6paZE^UUiQwhRKzUj!$V4AC!&TiB6rEVWubz1x2VN~X`y}9&IO=n5f+*y9> zK<}zWZKJdHNxWOYK{z}LI7->d9rD;xJ-mEjz zdeV0+UNteF`($0uoc@)|7FZhR%tZioPIaZfc7tVM&!YAg5T*oO!T4Jkn-pZw)C4Ml zA}t0-3rVPzx9T{+$GihyjXppL2qN-8L1&pwdaV;ib)&n{Qg5!ec}p6-vSSYCUmFa) z{n@U?iwEW3N-NL4wudhZ-P!TS3q$Wocp9|n2Y#MGdtTDLK#k0t5E-z_Aafzbpm|A0 zX-0t|G^om6(4E-|neHXzSR9dIO2Cg8K#SYv)@MjxkxZTbu}wQy4xf?PnbO}hXTgGb zHFMME)$_(MGs#f(tvsu6!;;a{N4m|m%^kC5cldI%cvasiR-af;SsfZ#-#52+#d5yXU&|ZH${QL(zp0xwtFE?DnS&&G@)F>uHL7B4mbIu&QW6z>Rt!;yU zlWH~&jc(a=%DhdTU*Z292+W%sm^%+tATc4&`6H0$W;UTnbecW`uLuyNF*0vs*8J3a z!j_+U8IM5Hr>7V*(v9X6v&E!^FjS3rn^leo{R0go^qUmX&lf}X=i3~i%Og4fc76C; z>|OyMMmgZN+l;bA^McY2f>N<+A$K?%D6^P|gko(ZX+ou`*|wa#Y*imd+xv#>u-bAx z1;zat9%x3YZUrlo3Zxw95Z!~A$*QcVogWOqUlEdKHB{`+ILCc@1xeKJp7gL-=TJ%MviJByEb67rlxQWsSRZ~3$<`o zG@z-iR5|g0wHH!J9)nbrv*n1+K5j7^iUp2a0u^DrEe<$?dAasNM@ESNvnHa2m_ z@W=-5757Hy0vXQXZ%KcZ&Saf@eIO+pxq|iFm?ELe8LEGp42*N0`x=I>u6ssRJ-*GEpIHB#CMQ z3a76L-p2`4Rr%$@78pFqeljh3I>PkSS^d<`Vu~wZ@0i~!`UXLk* z{8w)VhcXcUK)p?<0wEX4QH%&k;VeQ}&ehgCMCqs{iYNJhNSW>auGM3GBl&W3RZV?U zWmUaqVNQN=>8+Psdi%G|%Wo)kdH6S#75(!s|IWP!zIm%YH9a#mt*E5#XZPOx{I3tK*j9n@gv}@&g%zlWJgW*+ zV8&Z3X|%8av><*hBLg4}b{gmDyw6}Tm za2YQj=jF?`E=(y-O_g}Z!p9yXOOtCJ$sWti<+nWwwvv$#&!m2|n+a{?CJO{ML6RmC zyoV48f)QjX!Hy+E$(>*+xy_1HFIH4e1;;t*o(j(IZ9Db6ouU6cwrW><=&9RV`v*D> zKGwH%W#^;(964otX!+^V<7@io4W_p>H_V-UzI`6J0J6k~+1QsL8**7`pg27Zi~`34 z`cZKPAqi9s2}8Z8#Oo!KxL6rH6LF_QUnNI|wMn{cQR)3V4n6zqq1|_T7o~Y-Evw&m z)1kALUiPZ()E!Ur?q61NQ^mpOMcmC$rhd&#>Q>Se`hhe+ zfW+J2Cj4T(5^zfI3{3K6F%K3?vCL-0gC&kxILyxg z2Cf-U$Kv;RwuH3=8UdH8617~T<(n}uaK1L{xJHxKYtTy(SG9zdfMarOwj3jQT;^6j zmp3%Eam6+EDl!+UB#+yzHX1k!HnVgI`YRcYm3bG`o}XW7Gy)&PqyHiOZG_LUH&j>q z3XFy<^U~Tsy;VPI&N3JaeAU$r_RueY*iru7*ceM!0$!)k2xNybG7aF!^37972urGR z0H>Kmg`0chA>#Fr#I4-d&`2cJ652q(Eau4#}lhnR1^g(`w1gHf8&)Wc_m`*c|b<5D%q(0m0I-AAEJmS0ADd zhOQHxyM?d5{ui0&o}2lL>u-JfnNYjv;6)c7jPq@FL5kZMi2u0atMA^llS4rMM-IkHT(Nt4@PHApsYEjMnlKlPK*I#NM zEV!qpyxG>YG_6rGWEPeL%2uo!9kcCiYjT$5 z+ENVq3|Co~|J3zaZKi%*GM~rj_gGLcZ)G_2MWlhpvfOK(56T~;M-!cP;83CpUX!~W3_|C%+l^_LLXhT zWa8;l!KNF(dGn#`_>G~ByLRl@#cw3oum(yZnViZB0?tIi2iTztEfxhlH|#Zw-BI7v zY^mp$uL*sy;_4Bjls@=%^epuCmvc*h!FQv+EcEV2sLxCC3Kk*x*RbSC3~WXqR>%RG zJ`nOMBK)zO(q=^l z;~+SD{*u*;Q#^LbQI@`S_}_V}e@zZP>#IZ00Kx}9)9}}MX6PgLt{%>NE-T|pAS^@{ zyYx-Ko5LCdb=j!^6O=_vCKK3TvuVT@*0)>O_^2rozVTE>(ueM z0PvVualk`qu!7R#^^r0xHd_`n2B-!^!|NRdypY!`E%P%Lhdy3)v#C&T0DcNgw~Py; ztA=0ouDvQPH8r);{=Pz&$N`tup{+vZ50u$xx(l6STLQ?#C$14Bt%Tc&p!sv7p<9*$1^8e+ zYPg1H$S%|j`yD1I1%zSfg5M;V*b?DE;)zXL8ZmK;Zz)=qe!t+DX@R^_)D_@cr4`bX z$cDECvdC(J_9v4D^BNX0uOXK}>FW953vGX1@P4awUg)Dz?hpNrR;?}!KOtR(vd5V# z&=Q`nntW247YK;d;dcRm_`JbMd$8=XW+-&nskOcWc*}RI_;YYPqVss3tU0@2?bdL_W;njf+?&#yKNB z$xjng7qR$yQM{j)s71)clrs8@u3CP?ccOh zs<|l?x~}i^Uy+OwIDQTFPV1iu#2(*21Mk2~Tga~n{o<2PctEP@yRGL3qKMnHp`Fjudy^jh|7vX&!@a|=2slHjE>YG`Q=R09Q z;(fE3eJ2zIe@ERi3X2NQso3kbtDaMCn-;i0dzDB z6ta_6LE&K@oHRZZDIv)$rW|PsM2IXm+RGaZ{d#ba*AE^$Ce{4qFKS)vAnJ>MDs@XcU>=Rhrnic2#plS)d*B3!w*g z?VCHRdSof@kM*w%_1jr(pvndXE~et71Yaqm7ZU-ZuXqM8Q?TTiEjlO+w=7&HTb`uL z<8Yjspda-X{+nk`N5`f7>Sx!!@)w@J<%m>si^-MaFr~?w!kQP~4BfBNAI)h*d?(SF zUA1J4%Fd_|n^1h)y}NM2J$yw_B~3arIu2WF}iuc_G!^8-#v0au(P zMak9)^=_6tT)L<6yBL^()n{e7bkJn!Zu9POo_Aa5X+AqGt+?Eu8Nw{t?_90v={fTX zU!;*zVkv}2r_eF*-!MbH74#x&7}-ZLauJS^N-k4eqgDyN5sW;kY$)_Iz%V$(+ax~7 zf2h%l zK(LTKzGh)a(v*zvp8vfEe~b1#x^M4ed%5HMJ4wdfb>752l5u$V6xtwp|3~z12A>GS zCuUft`b0M26A4lG@W!2IoW5~zaC3WiSI1_lX4UZGl`nEz%eq-ai`0*+L_gA@Q{Z>0 zJ`rxZ@8Iy+M*m~2*Q=QTS9w_lAeh4!mm+I2X6^X80OcA;yb zyF{RutsrIHvkPlxL)7 zmyj12=l%5PhTG?K8dG!4CDz&$x4$v(^wkf!yK;86&hHs2D4OGSZeLy8-cfa>rFM2* zjVae+N=enGNP3fNR>{E7<(8Gz6;&mfI%BSDcJa{S^g^2I0?e?V`2PZ5i9V0u-f4Uu z{=Y{Df6iax?}c*sd(b=_|NZe(sSwYnvxv_lNGGC~(FVjA5(^?e57KDJ=W)T~Dctw& z-bH*a7~skM=byiy&kOzVzWZR+3%JPNS%7-Y$^H(i7oy8yi}*WmJyf$=CZA{d^1qFq znNwykQkW$x-?V!PTKJDSYppiD!CleiT-3x`K?ZMUO5S$#Ur_sF|11K0H4Iceq~f${Jbt=&RLZ z7HgJemH!n$JlV9thN#a9|BEmBSAZ03>zlc($R@0{ll*|)Nxo3-jJ^=4JQf8+2nVjn z6ko^!UnmZ4*}|V&=P1=1AgWf6zw)b7hV2#b2MmTv+ra3*y?#+aV@k@#3%Q$TZq1*S znv#;*mVbKaqtIKiF-sF;2A{|b$2Z9*iVPh95uP;kYf|&Paq#!!%dNf?WJ#rzTE-Xu z;XU4WMgE-3%*>3o{L4d+2-+ZjNJcw$lFjBcZ8Xjxd?C?F)E6o-H^uovP4RvZndWln z)8YoWHw9JP7b@Y|g*BL1?+LxmU*PYCUMy?D8Sh)bo4oZXBy?4{l5djpF}n_nJSSTZ zJx?JH*Z`6|0m9;Vp8$4{(u@yyJ#H6r9?@BAg~evgko5(ce2%Fho5$D28%nU=4beVu zyv?I~GsBXdq0?p}F>t~B^=I_tW#*l+e*OZfc^8rg9R`UTvpuuCJ6Cjd@7Q_PnfhLB zrn~2?ojZESSwUm1ct`#DvL0|y-V(vFn6ASWV#uNrc}oZ#dRsd>Wc@MmI)Bc}(3c+c z#Y+*ZY=;hB8~Q?V4^9)^@GVDRH&W zD+ziYvl`CiJMyS{2a~%-0B1}yrlqDR>03G)YMQ|%%To^B%MCWB3 zy#`1zG0_AQ8n`WDUd)9cLBmW&S}~#zG~rzW%U#LEQ-HHs9q>b7zvz)%!(R$5^5tsU znhX;o-*@yGXE$xu|MI8WQf|1tudh#ES>b31^yUvPz1iB_xGkkWQ0*K9TtHG8a*>YE1-el7ou z!5zycd+_2>8Z7z{m-E>fI4I-%ST3oI^*KA+!#5C4GYAG@C; z-%(7G+wba&-_^Wr&qYs;JGxNM>IdG&3jMy)0P6l-3C&z+(7oqo(S(%+k&KfBDj zZoI++GSy|~*SLoZT>~AhS6S9~R#=Q?eVQ$|+&MB~cUjVfCup8)Ey&6wrL8wn-}lP~ zeuKPT)TD9gOho044f^=xhj?$EfBmKxU%ctY z7hmM=(0?3x;PNXTe5%Q@s&(m>ZA)8MWi{$&H?%G6Z(A&#`CRDebIxYWa*|kjhWfC3+A@blqmY;WjhejBYV~YuLF6S@b767ZYxPtXlwmebW6r^ zh1C#P=$~#mXeR>+a8|1Wv|tm?KZ&en_&FAD2`x{cFls%Fy%Gz=*z)Gf=3d%TcxaKN z(PSBN_vRY1G`EHx{tNF4{b=xKsVSAVK)_a+5_+V$S?~e#BL{*bzL?GoKSk9H%C1DptA65%>c6CjUx`;gCO=mFmk*Sk;O&#oN!BEcuLlxxMPSU$H3r_3s+W+z ztw9E83JtW51{yE-Gw6&HAT*8EFm<4Je)>?6Cn)n_j zxKUF^`|YLaj-uB6T?>a-ywSB}N!QeY4*lpG{91lSYvYjR<|o_cLb9DB>-iyh0K+(A zjyC0z@k60Ma<8mMgjHf@X(9Vmt`u|uYX`Mpeny^9Cg`AAm1!D@4HylX=?04tsnBuR zc~-1UfB;cKP!Fw}H*Z~FXP(EC=k$1_h4W6GH}BLmkCQIsdePQ3XfRF6MVv2_tx{|Y zmx0o5p~oq^9SNsu4y;b6A7y%dx*n>fAif9!Q#u5uuq+``U_5{+n@mb=k0fpwDba$W zctTRw+hoM}mCShF|0g7;U&7Dny5*LxTW<|LOF?GNT>NF;EN_6GoE2z7LL9>84*W_8Xm2D`yKZj=m6RE4 zvUknv>9KcJN|Lksa{ltXeZG2^udpa%Q=qw{C957*x7 z`q6x9*!8j&)CjmZ-eZM3G2_ILS6Vl(y)n~QS(;zyEA{2&6nOyh>`GrfwVxQb2elANH<-i} zffwr?_`t>v>Em0G>PPX@-Tc2HgG7uE^gt%-R)pL*CuJ>qkr7FTD1yMD*qfFn70p6= z&*5f%=lJ5&H*Y?D@+z8MT7O$o`bB=e`y~pmt6pTJf`y;CIgF3JXJHLrcPv`%{n;n?g6!{#mMPNb2mJQVNs=qCVDAQzU zD~h)^ui!5?JUZWsxhri&(Z&#^pbCAko$rSon~MAs{Ewgj@h69dCGCbB4GKdE%K>31 zbC%UwZTEXmAsjy0gY)AW%e@(>%dl(sfWl9Vb(R2@W3+tFCs5)-oO_YH2AeYw2z2?rNXc zM%tpjuBN)GvdmxRw=3&lvS44Gu;?zPb%MtsxX%&o+=&rk;pr(56AUwp{YRAnN~TAO zYkw@Ii`YRSTOBYKSh7+ykfW*)b*l0hQ3M#C%1Re`9CAh^j2GYhjuMhb1REj+ z;6xgY#zJFZQJEK$3fUEmVhJ=2=CEa8-4J9fdHT2@!Z3|I9m~UVa`RT5eM-;bD?JPC zm#o`)cG3J!zZz}0TFDnbU!;rs`x?EbD-^ltfU-X-=AlV4b_V8ybXXU}gN&C>Yq45Z ztAqQfL-<996+*;9WFsL>U4 z&=@q60b4~`0I8F@5NDVQXPs3w zHn}|+D52XFJZ*zMcQ7}b2%JJOGc3Ua+tY+16a=h#odF60+CmBHA)*9g&rZ>aWbP z+H!Ji)||i1LS>6&d326ZU#q;6}-AK|V!Wjwc0lZhQ>Q?RF1K*!!UBKw( z^sF}3EY3C^z5e#;)(H57Y|f+z2H2UTABSMZ0!6&P0jW+R$%zuBv|8OLgdyo~4NPB+ zK(WOv#2@mBxurT}A4iM7xytu83V8-|i9!+|a>T z!{jH$8jiF}^3_b)h^ll&pCPSgUc#W$>C8GoP7Wbn#rpGv{{CCZ#?yUQ|25XI?5-MH zR(aMjEDKQD#h~A*nQ}%3Rm4m@x9EIR9rW^b0b~~1j zQ~S0eYmpE&N)%48rXp;_VLU26f`GAFa!Jl0A_osWy3|66(ZvavV}FbQ33`{p|BK%{ z1x<)|dBo8Kne~t?q?GQDnDIpOfg_l1#lvfx~B%JE{ zpsc^YYW^zWiEArF_dd@6qb9b-cB-_A+`MR8+78T9HJ7G%=eEnrCqdLn@6 zBFC7Zr*;N}OkXX2zc~yvCx~&vvgile6zg)*;2&d^IeaKRd}A4FTqvgr00~o9Oc#iG zaU@0{Tb!18L|5rhf+6LL(@Gt3jnvgT?d|G%og+t-6+67IFZ39#+IfQ}N-!RjZ+4|j zdc1-y4&V)^@MI`zFZCD^XN8-GFr@~8O9W%}+Rb=CodaV+k&yMC){7Zap~OulQ-!I5 zl2WqVUblxdAl?cAZ5^8#gEb9p7+q74kipMCGv_ttk2|Y!uy-ymC|i+`(J!xu)+X(J z><7n9?x*-Na{C31sTuKc6ss;fhT$8FGa%2u2uY$alR&r9bjkjF9OCPvq>O)}>&f|3 z(*CDwKSt#vtI>sGp)Ir$(f~b_G z4y9r$Q%JIDVUP-iNDEz`1cfTtCQGJZA_fQ17g9HDgei08ghA zFEg-dX(a~cTHPL^`DBus9@yL{E#1?oN%5zI2B&b4zt~Sl0OgmrF#$)_9D)& zz7z!!!VAu;JMX+&<&S&L#Yx?{=hdEjZkJU|6bG{n3n}Z*W-5BQ#tac zFeif@>bPBcWx>|x4{jRiZ(FeaH-|QjE|~n|AYaiwc+O#-v**@<(4F(8rzbYve(N)} zYpYLP|D9W(uA2y*wttBKs_0N?;?PCsE(*=^Kpcs64}#Y*mlP;dIbCAg5%Ux)z|_?* zpmAs@iw1(*CW4;C>)ND+5WE;{&aaKEh9Cxia>{~;sckCUecU!ND+PxdPGMp4;tReT ztbJ>wNn+`#O-B1k{A^>GLr}SycTHXD0gY$VVWmWlG7>ZfQ~LRVZ{z7D*YNB}vnmh2 zHl?$IJ`@})IuZXXJ>XY3K?^$tnJHQ=)RRspnAWDjS`do|o5ex8ktVaIae^Glc+V0l zQgML}M1e}um#0mI4s$EeUl)k+w^8P}9+7U$&ZbC;QVZ*2m;^~HUV;gtWkL@ zPhA{w8b)Mk@&XAVY#+qR)Z|4HiVk(aKS_nnKr0e3fr60Cgos>3R5<4Og_-1m?)JJw zpcfXJRZaLq${$TpeS7cTOE2BKcX;@`?|tt)scOqpr+))MO7}$~q6MgNw_;DlUyVM1Wu;0(^dDJhp~D0O zvu+flExNc`_QridGRZAE!J=%M`vyiznY0F+gEX4re*8 z99Mo`gg`B6dpwsCb0GSCnJ2*X9m83-e97k{svaq}4jo;k;Il zH@7v#=9&C^GX9mgQ=9aP8ZYy(9sNN!Fi;l3Tr^ZhF&RDv%|Wj_ApxRB{+yT)SI0+D zE6D-2Xi3aMBgW=&dITjGA^n6rjHL7v5~^}i7vGHJqmUJ4NFuFs6Y^6g!wFqf`zL2% zX2*;E^KC}1W{hR%Fp_Rza$^2uu__Z9b z0^%lPQ4wNprSUO0vSK5%%dwyv8M0zRgw}Qy?(83$+uEF$Q{B5``<2Oyyyh=WF$c>0 zrj|@!InT?yWoP_~FJU|I*My$=oOl~F?s4L66me1FPc%Gk+iM#au3ivXtR?H=sAfi% zY)x%5=A99IaZ;y+a1A!ui6T#mG^FgT}+ z%eBJI85xX_1rqxu767;YC9bX*O~k!OQK>62E_W3M{o8|)!4`Ev(zEx)I8TYoMVF~f z8<%^(w11#e5V?o!`qDGMl0?H zUS^D!bYRvU(%2da-6f?jQsi!d7!DL@61Nfa-XXuW1CEXHYLcY>G`V|U(Y z?2cA%QU(<*lqQ2!gzl78obB!EI?nscMh2y+N;~v;>XbfOl>|-jXzh_60sgHdC(=vn7NxB_UU_d8(41i^OMUe2V1m z$+w1A0w)1@{Dw$AXZS1VRUl@Bg1jjrx+qMVxbUKPN_;W0436Kgm^V35d*_CPb#c-w zWa5ymgOJ+s*2qz84Qu2Cuh5(I@|EiGQq1O^2P-J*0Eg1tO3zRjAWb;!@@s;VQzic{kkAxNhp&DAu z){@~srbP*4pc2}S()moqiQZ45{u8d6C_I(sj)}aLNM{mxPm8}_B-3?he zAh9orf;e(?@RJ<)76Du$puDy7&XqT$e~wD9s6>{5Q3 zviOoj+>=w+UrudLk#Ldt>a^`8##dwQ@qS3RGu6eOkZQ+ik7SxyHRRa;b~*lSZdi8q9cwX4K;X1rTvOyRnMc&-znRkW^#R8BF0bwNON?GlgW25=psf#ZwF;2^p7hoz@<b?5-4y8D?oQJoH9U z#3!S%S21vym@a}B>xo2MZOCDv71q&rgB%?E!yg6*2Zy@mw|5TlA09rqAM0PgR$fzG zfhwVED88Hq`AF{x^Rd+r`y6%`THp~4ZctnUZ7VhvBAsfH*vQ2f zfQ+PQG?IUXjGQuyPwILqww{hn8Tp)Br(jJCVEl~H>B%UhJi=r0{n8V_UOw9&NWpvb zH91%pOfNz7k^BcU&;p!QNb=Q42-{Hf9IICJY>cC?Vm(@8qzn>VBSp~d=wY-lc}LOb zV8!J-z2q9Fod3Je%G>ffYnk?PUE0=DmwTu!}{kgQ6t ze4VCqSZe)wofBiKbPk6n*Evd>5}gyyUa?4}q|WJNOXyr%#YK1DeQ{|HKTmnL%H*kg z);aU?oa^?;heC&BdeO@BYj$h-x3#-sG}% zn4eTk!AQP>b((1qZQP{HmgMP>gk*+1UnqUb%m`=uq)+%wB0mHF?}5{tq?ldiH;LIN zb>|qPC>wP$hp+{htkJOTOgupOG&)_Ll5YpQ)Gh?0)H& zu(~7vV?rzf5&vVt(xgnc(wsA8=4`dG;90ZV=!0jFbKByl!W71RH};7MK8C!O;$@&7fb?>5hm ztT}lC4=%KqhzCnzKd5a3+9sS7(nvvmV@R-nd(Z1UEWOPo`dKA6i7q3-U(2$5~G_Jf`J%V_8-^{PsfATHJqKeRP+)5j3 zWL=MllGv<2>#nZuuKsnU*Hc;P@d9?4%?kgQbS~BikUYv|jmnF0GwHuFVX-J;z2g0= z&OpKy7*mM1T41MG#0zX7h@uiH>0n=Zc6Pbr74iEg@tc}m#bu&gxs8#VThC0f~P;p{!1&HPCvz zbptzSLH_oDmsP9-^(MXR)j@WV@e+aU$1`?F zN5_zCk7w;htLn~#jDfN4g1bu2|H(?`10^sb=t;%BBd2`x#v#+*lhN*zB<)R^T&n{1{1x$8 zM`bMh$yisDl*wcGpQ9$3jFfDhlDV#JcvkW)^sBYAa;($PqEj-? zHCVE&zoPsX$;N*qWm@l}{U6W+^fzO-$qj^qv<|U`&plLpu491HE_1PT`4BhG#Ywlh zu4`~S9LLYV*3N)F(CfMb^(Cm!LjGHm`&{LAz6^B>LHAnFuwN?ip9ab9UrLH=horjh z#q*?FBp37kJZVOr1N`L%*DyRQSPT4_7{3YlRv;e?e1As%5RO}c|0Irg0RL3v$5H<@ zQa94q!LJXHKZt&5Xgde|qk+E>_-_FINx)wY{8s?~B;davu%41>$j1Z!DzSO*x)yNG zW9%jw54@@DgZ4VtFg#P9jkc|5yB&4lJC9Mn+QJn9^x29h{JcmRsC&XyiFg})MtK+N z@~ww;oV!T!?UX^D8-A1LeUkfiNi#Aa|D%$e!Tqdfqyou>6c4_|JN$<%e9;LsJ;Y-p z1IockltB^TRw0q!{Umoj>L~;8KRU@toVP!T^X(_0%O~;B(+c3X`A-@2O4KdZQ3lZo zGO&IJxX9h_fM)RA=*2L^T*G9o^%Cp>mUJpW zbtk!V-8Z>!aqn;+jmeDZj@dQ9HDJbojsY*nro=YHZjap;do1?cz+l{(xP5pFPx+wW zplySm^E7+z^E~P~8lMG@Ael+<|N@~iYl#MC-QqB&|8@hSuj-jun z#-ui+?n-@on0HuU*loiO50AmOdiVpwPp1Xa_NKiyqHe^-5ogmUr!Pwnr@x*4&yhtV z*NuEWV^l^_#!VUPGM>%&U{u+tx=}~3sLRaC+?e^w=#itFN5A6D^KSE=7_(^1mNAF2 z;9sr*++wOxm3CK_EavWli z=j`$zl;5z+p0suHfnAQ5=_9)Ba)K0$*lU*u%cCPs*ySYgrEj&%$&!%1&n_R7;pq;p z7o;HlHLZW$EvX~p*3WD2_BZ;2;dXDRJ{a=$v^Dv?^V&OC)(5Pr~X}$-hR$7501WNQbjAOrIem6I^aX=ygphtb}Qx|N_IAggiI2B;y7 zZZr5vhw|4iU8reC3n?PU!|30EnikX(DreJZ>PcCXp|25jenUwE^04&am#rMFv*p}W zCdAbWNC7iXooyjF&Ys?j^CcCelQeKdv!OJEULPLq;3$HGS(A^Gsll!DT z3@Dr@u}5IHfVOtiDxBnlRHWY`9)gDE6TA6 z^^`baQG2=#-Y!EEF{uC>OXNFoQ5X438WmOp+EsSM;Dt4j+Q`g9#^%T) zLTHmUW+Y|wQ9AC-U%5~2YKb;L8fh_8QOkL?fJXHos^vKh>yIC^yFxjyUO)yv{7psF*nsD z@=5KE`1;y7J!=8#9bGTPQK_kMXyBZw6U0Q16S}1St3A|%LiVJ`ZNM+7bu^k1r-bRh z9Js1^>a|EKJy!G#X~zu)g3d%?(O-sbZ_0VGm+GnV)xk*HqE;&%^nvucv?D@|co=8? z&bScTnt_3GQl0a|7RbFOe3f?Efk)vZVbjiBts%0WwxEtYX+>{xk~+2$CC77K)2p3QqTU2dZ{=+TC?*%k z)mdl>7~ex}B@fkC=zMjBY995GI>4FGR-M&R zeGnzDJtCU15-{lzlqPD2BW2ZjO1Co#5~Ue7@TrfKCT+9DtbfW;N1l`;R|m>_l?`8g z8ND)RqI54dnh}kKmZW}*)JCrrTs73IbG&LItt|vOQAg-O*y7O80lH|NVdQG9^ef8S zN@&h}>_feXP#HNaMtKo9U2CKh%?U!Jr7FEsQ0hBpN?Tilz{FWcB+St{!0u2Uy&h@A zq3ey~k;kLILq9blX!uABj?R1(M6Q^WHnC9~$J?{5#@s5PGae+af25YWOs#e_hrA(d zuIwDEb8uov`fpOe7{hNvtpV2k2x z&6|rlt{C)tS{vcq0@FsnNd4eiPP=g82rrH~qS0VfE#u6U4#sU1OjtD`H;Xk8Jwf~YQYHCJflIAx$dfb^)3ru{NLX_FO(ijN;# zYvgh>M(B*&Fggc5l#n%&BfYfA2)^q;1u3~1JfbDn8mj1Zc{J1ThPte??A=;nA`;4r zQQvG}*CgQ=U#7N7hT(3d7)A$SW`%NTThiVJsL9R{gLHTe7)C77&_Uav#b-~N9jh>X6!M-eW z9b`^zV@|C7!FA#>wW@sdBIPysa(Ctx*3?{_M+LY=9KCmW%#mxebIt+Bmom#Bijzp`v#@C=_wSlC(Xf#xlCSu!dW|9NC zLS|Oc9<9HT{mqi2sj*?m*3l69`&HmB_hXEQH5w(wYE2q#ko$~$`^H-ufpGSeG9{?~ zPFDk!KoQ1$yaeW<*QF#tYxr+*k<>U`EHZqc<N7g;bO_Bh>N9{#l@wc5En^}!^P511sCVok#RmEF^!QKm2q8k)<#;o z#$j9wxGK;y_l}SmNjZ?{&ABf1jj%Oxrq^ct7m4J!k7P8;h)d5j^o{m)E$@FH;ZV(p zuN_dGn1Z`r#(BCYBE>oA!7~kv__*%$odYS-{ip-eiLGmG&ZyU0aFI`pm>LW;jwGM- z+=>%l>I%eFt}iaGBGuq<^u8(wT;Sfq;SgiA5A()ZAuhEy;%cgA54pbT{)~}Jli>{K z7%)5U)wT?{UUI)iY|3Xn|EZCWLQ~o_C$5deUDS{WzatuSxm@QQ``f><{?a=!hvWV2VJ<%wSQa&V zYJZK91hr82mH)fghi3u9(9EgO(0r8op0{3&2%i?mXt34nwEWPJJVa64LG~WqgBG@3 zy8i-5ojVGRvT0A;S5k9yo{oK1VP`o9aWL(&3b?5ui_IwZr3Z4(X3=)JlOQafDbl!= zdak<xF8fL``KW2RS8s?pvCdTP+x zft=^7+82OHD zluh!qd=*!?Z<8%@mwZdUhpYT|%2Byh?zix_Gjfk?mY>QSR-9~?o${WXllSG@@&kE6 zelEM<0~&FEMw9#k{5~j$tlTR{0%boh+?LGHj_ zyA6BcmC(?jJOmkh!SJ7U9fs!g$Z708){de=JHAYYPq<&Saz`<^|x zW8pP<9j~|b;Kg|fc!?C>!JcF#TPgVS*;KsmU^wn2d0h6%k8quFuRI|?liTI{R+>B` zKek3#>2h~$OJH?JYvI7IU|T^!L8ayu1$J&9&nVL48O3%!g?SMM*tr>xW77}0>4&_; zZZEa-GCRM@&L`Ws1Fu4l3vIZCg`VcNmaa~JQ+=pan~JJ6FRhNL>gsG4xo*E4T(o45 zWo=oy+j=q%TG-gJM+VGzEX|T!79RKDpLw*D8f!|iGY;T(V*DWqY6s3Z07Wuow^Z)Q zwl*(Zvb%iql0ELG$~`_F9f;e23&7=@8*5Q1m3Z`J>Ej7;RzmK6>%ykpG574jQvfg! Lt2X1!TSfj2VF}Y^ diff --git a/docs/fonts/Novecentosanswide-Normal-webfont.woff b/docs/fonts/Novecentosanswide-Normal-webfont.woff deleted file mode 100644 index d5c42907915e60c1975b42031480512706bb0e49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24772 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 PrN01{BPHPXGwO`#%R7pr8Wxzk&ZbrUC%q{{*`; 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 dh{%}o=5WF?NX7>fM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/Novecentosanswide-UltraLight-webfont.ttf b/docs/fonts/Novecentosanswide-UltraLight-webfont.ttf deleted file mode 100644 index 9ce9c7f99d47aa88905ee8c931e10aff278dfe9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55600 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 diff --git a/docs/fonts/Novecentosanswide-UltraLight-webfont.woff b/docs/fonts/Novecentosanswide-UltraLight-webfont.woff deleted file mode 100644 index 381650c98d2a6a0464d9e6d579b04c34e6631efb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23476 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 diff --git a/docs/fonts/Novecentosanswide-UltraLight-webfont.woff2 b/docs/fonts/Novecentosanswide-UltraLight-webfont.woff2 deleted file mode 100644 index 7e659549bc11aa2c4968d6b22aab220fe25dd417..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18716 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 LH=H;$pY{DTEzR!f diff --git a/docs/fonts/Roboto-Italic.ttf b/docs/fonts/Roboto-Italic.ttf deleted file mode 100644 index ff6046d5bfa7cd4498ad4a549d2d9028f6c73372..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161484 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 cASb?` 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