From 2b887123540de2cfcbfcae2a3afbfa5fab45d1d6 Mon Sep 17 00:00:00 2001 From: Soma Szelpal Date: Sat, 24 Oct 2020 23:47:03 +0200 Subject: [PATCH] Refactored template generation to use embedded binary assets. --- assets/templates/graphql_input_objects.gotmpl | 6 +- assets/templates/graphql_objects.gotmpl | 10 +- go.sum | 11 ++ internal/config/schema.go | 2 +- internal/gqlassist/generator.go | 43 ++++-- internal/statikdata/statik.go | 2 +- internal/statikdata/statikdata.go | 136 ++++++++++++++++++ internal/utils/common.go | 11 +- internal/utils/errors.go | 106 ++++++++++++++ internal/utils/formatters.go | 52 +++++++ main.go | 2 +- 11 files changed, 349 insertions(+), 32 deletions(-) create mode 100644 internal/utils/errors.go create mode 100644 internal/utils/formatters.go diff --git a/assets/templates/graphql_input_objects.gotmpl b/assets/templates/graphql_input_objects.gotmpl index 83463cd..252b4d9 100644 --- a/assets/templates/graphql_input_objects.gotmpl +++ b/assets/templates/graphql_input_objects.gotmpl @@ -34,15 +34,15 @@ ReverseTypeMapInputObjects = map[string]string{ {{- define "inputObject" -}} // {{ .name | identifier }} @graphql="{{ .name }}" {{ if .description }}{{ .description | clean | formatDescription }}{{ end }} - type {{.name | identifier }} struct {{- "{" }} + type {{.name | identifier }} struct { {{- range .inputFields -}} {{- if eq .type.kind "NON_NULL" }} // {{ .name | identifier }} @graphql="{{ .name }}" {{ if .description }}{{ .description | clean | formatDescription }}{{ end }} (Required.) - {{ .name | identifier }} {{ .type | type }} ` + "`" + `json:"{{ .name }}" graphql:"!{{ .name }}"` + "`" + ` + {{ .name | identifier }} {{ .type | type }} `json:"{{ .name }}" graphql:"!{{ .name }}"` {{- end -}} {{- if ne .type.kind "NON_NULL" }} // {{ .name | identifier }} @graphql="{{ .name }}" {{ if .description }}{{ .description | clean | formatDescription }}{{ end }} (Optional.) - {{ .name | identifier }} {{ .type | type }} ` + "`" + `json:"{{ .name }},omitempty" graphql:"{{ .name }}"` + "`" + ` + {{ .name | identifier }} {{ .type | type }} `json:"{{ .name }},omitempty" graphql:"{{ .name }}"` {{- end -}} {{- end -}} } diff --git a/assets/templates/graphql_objects.gotmpl b/assets/templates/graphql_objects.gotmpl index 882296d..9066bc2 100644 --- a/assets/templates/graphql_objects.gotmpl +++ b/assets/templates/graphql_objects.gotmpl @@ -15,8 +15,8 @@ import ( type Object interface{} type GQLMeta struct { -// GQLTypeName @graphql="__typename" Is a meta field containing the GraphQL type name -GQLTypeName *string ` + "`" + `json:"__typename,omitempty"` + "`" + ` + // GQLTypeName @graphql="__typename" Is a meta field containing the GraphQL type name + GQLTypeName *string `json:"__typename,omitempty"` } var ( @@ -39,16 +39,16 @@ ReverseTypeMapObjects = map[string]string{ {{- define "object" -}} // {{ .name | identifier }} @graphql="{{ .name }}" {{ if .description }}{{ .description | clean | formatDescription }}{{ end }} - type {{.name | identifier }} struct {{- "{" }} + type {{.name | identifier }} struct { GQLMeta {{- range .fields -}} {{- if eq .type.kind "NON_NULL" }} // {{ .name | identifier }} @graphql="{{ .name }}" {{ if .description }}{{ .description | clean | formatDescription }}{{ end }} (Required.) - {{ .name | identifier }} {{ .type | type }} ` + "`" + `json:"{{ .name }}" graphql:"!{{ .name }}"` + "`" + ` + {{ .name | identifier }} {{ .type | type }} `json:"{{ .name }}" graphql:"!{{ .name }}"` {{- end -}} {{- if ne .type.kind "NON_NULL" }} // {{ .name | identifier }} @graphql="{{ .name }}" {{ if .description }}{{ .description | clean | formatDescription }}{{ end }} (Optional.) - {{ .name | identifier }} {{ .type | type }} ` + "`" + `json:"{{ .name }},omitempty" graphql:"{{ .name }}"` + "`" + ` + {{ .name | identifier }} {{ .type | type }} `json:"{{ .name }},omitempty" graphql:"{{ .name }}"` {{- end -}} {{- end -}} } diff --git a/go.sum b/go.sum index f2726c0..f852622 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,7 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= @@ -41,6 +42,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -75,6 +77,7 @@ github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -113,6 +116,7 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= @@ -121,8 +125,10 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -155,6 +161,7 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -177,7 +184,9 @@ github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f h1:tygelZueB1EtXk github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -197,6 +206,7 @@ github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -320,6 +330,7 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= diff --git a/internal/config/schema.go b/internal/config/schema.go index f7ac451..7cb3e94 100644 --- a/internal/config/schema.go +++ b/internal/config/schema.go @@ -20,7 +20,7 @@ type ( Debug bool `json:"debug" envconfig:"debug" default:"false"` OutputDirectory string `json:"output_directory" envconfig:"output_directory" default:"internal/graphqltypes" split_words:"true"` OutputPackage string `json:"output_package" envconfig:"output_package" required:"true" split_words:"true" default:"graphqltypes"` - GraphQLEndpoint string `json:"graphql_endpoint" envconfig:"graphql_endpoint" required:"true" split_words:"true"` + GraphQLEndpoint string `json:"graphql_endpoint" envconfig:"graphql_endpoint" required:"true" split_words:"false"` GraphQLAuthHeader string `json:"graphql_auth_header" envconfig:"graphql_auth_header" required:"true" split_words:"true" default:"Authorization"` GraphQLAuthToken string `json:"graphql_auth_token" envconfig:"graphql_auth_token" split_words:"true"` } diff --git a/internal/gqlassist/generator.go b/internal/gqlassist/generator.go index 008e52d..dc28740 100644 --- a/internal/gqlassist/generator.go +++ b/internal/gqlassist/generator.go @@ -13,6 +13,7 @@ import ( "text/template" "github.com/shakahl/gqlassist/internal/apiclient" + "github.com/shakahl/gqlassist/internal/statikdata" "github.com/shakahl/gqlassist/internal/utils" ) @@ -29,9 +30,10 @@ type GraphQLTypeDefGeneratorConfig struct { } type GraphQLTypeDefGenerator struct { - options GraphQLTypeDefGeneratorConfig - client *apiclient.ApiClient - logger *log.Logger + options GraphQLTypeDefGeneratorConfig + client *apiclient.ApiClient + logger *log.Logger + templates map[string]*template.Template } func New(options GraphQLTypeDefGeneratorConfig, logger *log.Logger) *GraphQLTypeDefGenerator { @@ -46,15 +48,26 @@ func New(options GraphQLTypeDefGeneratorConfig, logger *log.Logger) *GraphQLType } // getTemplates returns a template map (filename->template) -func (g *GraphQLTypeDefGenerator) createTemplates(params map[string]interface{}) map[string]*template.Template { - // Filename -> Template. - var templates = map[string]*template.Template{ - "gen_graphql_scalars.go": renderGeneratorTemplate("graphql_scalars.gotmpl", GeneratorTemplateScalar), - "gen_graphql_enums.go": renderGeneratorTemplate("graphql_enums.gotmpl", GeneratorTemplateEnum), - "gen_graphql_input_objects.go": renderGeneratorTemplate("graphql_input_objects.gotmpl", GeneratorTemplateInputObjects), - "gen_graphql_objects.go": renderGeneratorTemplate("graphql_objects.gotmpl", GeneratorTemplateObjects), - } - return templates +func (g *GraphQLTypeDefGenerator) GetTemplates(params map[string]interface{}) map[string]*template.Template { + if g.templates != nil { + return g.templates + } + + statikTemplates := map[string]string{ + "gen_graphql_enums.go": "/graphql_enums.gotmpl", + "gen_graphql_scalars.go": "/graphql_scalars.gotmpl", + "gen_graphql_input_objects.go": "/graphql_input_objects.gotmpl", + "gen_graphql_objects.go": "/graphql_objects.gotmpl", + } + + g.templates = make(map[string]*template.Template) + + for name, path := range statikTemplates { + content := statikdata.MustReadFileString(path) + g.templates[name] = renderGeneratorTemplate(name, content) + } + + return g.templates } func (g *GraphQLTypeDefGenerator) getWorkingDirectory() string { @@ -95,8 +108,8 @@ func (g *GraphQLTypeDefGenerator) fetchGraphQLSchema() (string, error) { return string(result.GetBody()), nil } -func (g *GraphQLTypeDefGenerator) decodeStringToInterface(schema string) (interface{}, error) { - var target interface{} +func (g *GraphQLTypeDefGenerator) decodeStringToInterface(schema string) (map[string]interface{}, error) { + var target map[string]interface{} s := strings.NewReader(schema) if err := json.NewDecoder(s).Decode(&target); err != nil { return nil, err @@ -138,7 +151,7 @@ func (g *GraphQLTypeDefGenerator) Generate() error { } // use_integer_enums - templates := g.createTemplates(params) + templates := g.GetTemplates(params) for filename, t := range templates { outputFile := g.getOutputFilePath(filename) diff --git a/internal/statikdata/statik.go b/internal/statikdata/statik.go index 2ba7b04..610899d 100644 --- a/internal/statikdata/statik.go +++ b/internal/statikdata/statik.go @@ -7,6 +7,6 @@ import ( ) func init() { - data := "PK\x03\x04\x14\x00\x08\x00\x08\x006\x931Q\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x00gen_graphql_enums.gotmplUT\x05\x00\x01(\xaac_\xac\x97Mo\xe36\x10\x86\xef\xfa\x15S\xd6]HY[F\xafY\x04h\xd3\xe4\xe0\x02\xeb\x00M\xd2\x1e\\\xc3\xa0\xa5\x91\xc3D\xa2\x14\x92r\xd6U\xf4\xdf\x0b~\xc4\xa6l\xe5c\xb3\xc9amK\xc3\xd1;\xcf\xbcCq\xc7c\xf8\xa3L\x11V\xc8QP\x85),7\xfaG\xbc*\xbf\xc0\xd9\x05L/\xae\xe0\xfclr\x15\x07AE\x93;\xbaBh\x1a\xa8\xeeV\x9c\x16\x08m\x1b\x04\xac\xa8J\xa1 \x0c\xc8r\xa3P\x92\x80 O\xca\x94\xf1\xd5\xf8V\x96\x9c\x04D*\xc1\xf8J\x92`<\x06\x92\x15\x8a\x04Q\x104\x8d\xa0|\x85\x10\xa7T\xd1x\xb1\x90\xc9\x0d\x164V\x9b\n%Go&KG\xe6| \xfe$U\xce\xc1\xafG\xdf\xee&\xd3\xf1\xf9\x97\xab\x8b G\x92\x0b'\x92\xe9\xd4fs\xaaD\xe2\x965\xd9~\x1f\xfc\x14<\x84\x84\xb1\x18\xe8\xaaJ\xe5\xc8\xccDF>0\xf6,\x0czl\xb2\xac\xe9\xab\xa8\xdb\xfd\xf1\xc3#e\xce\xe2\x0c\x95\xa8\xbf[g\xa4*~\xac\x17\xcf\xbc\x87\x11\xaa\xa0\xa3\xf5\xb0\xc2+*W\xb0\xda\xb8\xf3\xe5(2\x1d\x84\xe0\xbd\x9c\x81\x16Hb\xf6a\xf2 \x04\x06 \xb6!i\x9b\xb0\x82\xccI99\x93d\xb0\xc2\xa2\xd1.vf\xb8\x9b\xb1 \x9eF\xa9\xa4r\xc4\"\x83\xee\x1f\x0b\xec\x96\x9e\xc9Xz?\xc3x\x9b\xe3\xa3&_0\xbcn\xb8\xcf\x98\xf7\x7f\xcb\xc2\x9f;\xb6U\xef\xa8\xaaK\xe1\x08\\\xbe\x00\xe6HB`\xde\x93\xca\xe35\xed\xc2\xa2\xb8\x01r\x9aIu\x98\xbd\x81\xd1\x0e\xc6\xb1\x17\x10\x02>\x15F\xd4\xf3Ey\xc6\xb7)!p\xac)'9\xd9\xcc\xc8\xdaI\xadZ*\xfb\x91\x15\xb2\x92D\\g\xdaT\xc2]\x1efw\x08\xa3\x86vz\xbc?.b=\xc5\x88F\xb8\xe7\xd8R\x18l^Nk\xab\x9df\xbbu\xb5I\xe9h\xc6\x02\x1d\xd2\xd1x4\x1d\xdd\xdd\xdclo\xda\xfc\xde\x19\x04z\xb7\xb4h\xa4\xa1<\xe9\xef\xe9\xfa\xad\xa8\xb8\xd1\x92[\xad\x01\x86\x80{\x9c\x80\xdfs\x9c\xe0\xfe\xd1j5\xdc\x97\xdb\x99\x18\xf2\x0f\xbb\xe1\x9d3{\xe8\xa2\xac#8\x15\xfd'8\xc7mL\x94\xff\x08\xe7\xa9\xaed\x1cD\xb7\xdc\x01\xfbV\xae\x87\xdf\x81\xedF~\x05\x00\x00\xff\xffPK\x07\x08\xb9\xb5\xee\xca?\x02\x00\x00T\x07\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\xef\x901Q\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00 \x00gen_graphql_objects.gotmplUT\x05\x00\x01\xe3\xa5c_\xd4TMo\xdb:\x10\xbc\xf3W\xcc\xe3\xc9~\x89\xa5\xbb\x1f\x02<\xe4\xa3A\n\xc7F\x02\xf7T\x14\x0e#\xadd&\x16)STP\x83\xe6\x7f/(K\x8e\x92:h\x8b\xa2-\xea\x0b\xad\xe5\xecrf\xb8\xcb8\xc6\x99N 9)2\xc2R\x8a\xfbM\xf8\x88r\xfd\x1f\xceg\x98\xce\xe6\xb88\xbf\x9aG\x8c\x95\"y\x149\xc19\x94\x8f\xb9\x12\x05\xc1{\xc6dQjc1`\xdc\xca\x828c<\x97vY\xdfG\x89.\xe2\\\xeb|Eq]\xcb\x94\xb3!cq\x8c\xd9\xfd\x03%\x16\x86JC\x15)[A+\x82\xce`\x97\x84+U\xd6\x16\x955ub\xab1\x8b\xe3\x90\xe1\xdc\x83\x96\n\x03\xfal\x8dH\xec;I\xab\x14<\x10\xe0\x18dre\xc9\x9cn\xc0\x1f\xa5J9\xf8\xec\xf4\xfd\xc5\xd9\x9c#J\x85\x15\xd1bQ%K*Dd7%U\xc3!\xf81\xb8\xf7\x11c!\xd0\x91\x91\xca\x92\xc9DB\xce\xb7\x1b\x977\x93k\xb2\xa2\xa5\x02\x17x\\\xdeL\xe6\x9b\x92\xa6A\xf9\xff\xb9\x11\xe5r\xbd:\xe1\x8bEH\xd8\xb1\xb9\xaa P\x84\xbc\xac!\x99he\x85TR\xe5\x8d\xba\xcb\x90s3AsB\xc8`\xfd\x92\xffV\xd6\x04\xe4\x1d\x8e\xc0\xef8\x8ep\xf7Pi5\xee\x9dp\xac\x0bi\xa9(\xed\x86\xf7P\xcc3\xf6$\x0c\x06,\xd4\xba\x16\xe5NU\x85\x13\x14\xa2\xfc\xb8+\xfbi\xb78\xe6\x1c\x8cP9\x1d4\x08[\xbci\xe8\x16\x956\xf6t\xd3\x90\x1dy\xef\x9c\xcc@kD\x01\xf7\x0c\x1by\xcf\x00\x846\x89\x9a&\xd9B\xa6\xa4\xac\xcc$\x19l\xb1\xae\xb5\x0d\x9d3\xee#\xba\xe0q\xa0G*E(?j\xff1\xcfn\xe9\x89LE\xbfY\x1f\xbeW\xe0AM\xcf\xaa\xbf\xado\xc8\x98s?O\xfb\xadK\xd93\x0e\xcd\xb3\x12\x96\xc0u\xe3!G\xe4=s\x8eT\x1ar\x9b\x85\x05.#\xa4\x94I\xd5\x03v\xb2\x9b\x81\x9eV\xd0\xd4\x95\xc4E\"\x15\x92\xb2c(\xfa\xef\x03)\xd9V\xd6\xc6y1L\xe9\x9e\x0f^\x1e^-\x16\xf8\xa02BA\x924\xb3\x94a\xbds\x8b\xa4P\xef\xb1\xbc\xc1\xf5\xcd\nW\xcbt\x95\x04A\xc3\xf8\x1d+\x08]\x87\xe6\xae\x90\xac&\xf4}\x10\x88\xbaQ\xda\"\nB+j\n\x83 ,\x84-\xdbu\xc2U\xbd(\x94**Z\xb4\xad\xc8\xc2 \x0e\x82\xae\x83\xc8\x91\xb3\xca\x10\xe6}\x1f\xcc\xec\xae!D\xc1l\xb1\xc0\xa5R\x151 M\x8d&C\xd2\x1aX\xdd\x12\x94\x1e\x01\x1bV\xb5d\x92`\xb6\xaf\\+U\x05\x1e\xfb\xb1R\xccN\x91F\x14\x922d\xaa]W4o4qa\x84\x92\xc85\xe3V(\xc9\xaa\x91\x0e\xccx\x06\xd3\x10\x17\xb9\x18\x1a\x90^]]\xe1\x87\xef\xcf\x92`60\xe7\xee\xf7\xdd\xd9 \x96.\xa7J\x0c\xad\x14\xf7-Ad$\xad\xa3\xd0\xb0%\xb3\x10\x06\x97\xcc\xd0\xbb3\xa8u\xde\x1a\xee\xba\x9b \xb5\x9eC\x18\xa8\xdc\x92Dk(\x83U\xd0\x94\x93\xe5%\x98\x84Z\xffK\xdc\xba}3\x83;\xda!w\x7f\xc1\x19/)\xc1\xaa$\xa4KO\xe2\x9b\xc7\x9a\x86\x986\x10\x12\x0c\xbf\xdc\xde\\C\x93i\x944\xe4\xe0\x0c\xb7V\x0bY\xbcG\xa9\xb6\xb4!\xfd\n\xc2[\x93j4\"-\xc9l\xf0\xb0&\x94m\xcd\xe4\\\x13\xcb\xd8\xba\xa2\x04\x7f\x95$A\x0f\x0dq\x97\x0dG(!d\xd3Z/\xfe\xcaS0\xb9\x83\xf1*\x88L\xeb\xf6`\x10\xfe\xf9\xf7u\xc5\xc5w\x0f\xbf^\x9c\x9f\x87\xb1\xdb\x8cS*H\x1fk\xce\xe2\x81\xca\x93\xf8\xd3\xc0VT\x95\xb3\xc18\xa7\xe6\xa8\x98.\x93}\xe7\x1d\x8b\xce\x19\xa7\xae\x0ff\xe9r\x14\x1e\x0fF>\xc9\x80Tr>9\xef1\x12\xdbRU\x04\xd9\xd6\xa4\x05?fj\x84\xf3i\x00\xf7\x11Y\x93\xdd\x12I\xcc\xa37\xff\xbc}\x1d\x83\xc9\x0c\xee\x1f\xe6x\x9d\x043\x87\x13\xd2\xbe}3\xb8\x18\x1a\xfe$\xc6\xf4`[V!c\x96\xb9\x1d\xfd\xb1\xfa8\xff\x11\xbcd\xce\x1ci\x18\xbaoI\xf2\xbd\x8fU)\xccp\xb6\xc2\xa0V\xc6N\xa3\xb2\xde\xe1g\xcd\x9a\xf2\xb7OCj\xf6VsM4\xcf\x95\xae=\xc5\xd3c\xf4\x06\x92`6:\x1b[6\x8b\x07\xbf\xd7\xb4\xdd_(\xe1\x02SR\xd5\xb8\x0c+\xd4\xec\x8e\xc0 i\x8bo\xc7\x92$\x98\xe5\xad\xe4\x13P\xb4\xd9\xdf\xdc\xf8P\x85\x0e\x9al\xab%\xbe\xd9\xa0?\xc8\x0cw\xe9\x84\x88/\x98H\xf8u\xb4\x19\xaew<\xbe\x7f\x86\xdce\xe3yf\x9f\xa0=m\xba\x8c6H\x97\xb1{\xfc\x1c\x9b\xad%\x99\x1d>T/X\xf8\xe2\xf5\xca\x81\xfac\x04^\xc0\x9f\x88\xc6i\xe4$2\xa7\x0b\xa3\xcd\x0b{\x88_\x92\xfa\"z\x87s\x0c\xfe\x0b\x00\x00\xff\xffPK\x07\x08\xaf\x84#\xfa\xa5\x03\x00\x00L\x08\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x006\x931Q\xfaxUG7\x04\x00\x00\xb8\x0e\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x81\x00\x00\x00\x00gen_graphql_enums.gotmplUT\x05\x00\x01(\xaac_PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\xe2\x901Q\xb9\xb5\xee\xca?\x02\x00\x00T\x07\x00\x00 \x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x81\x86\x04\x00\x00gen_graphql_input_objects.gotmplUT\x05\x00\x01\xc8\xa5c_PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\xef\x901Q\x870\xed}\x81\x02\x00\x00\xd4\x07\x00\x00\x1a\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x81\x1c\x07\x00\x00gen_graphql_objects.gotmplUT\x05\x00\x01\xe3\xa5c_PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\xc4\x901Q\xaf\x84#\xfa\xa5\x03\x00\x00L\x08\x00\x00\x1a\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x81\xee \x00\x00gen_graphql_scalars.gotmplUT\x05\x00\x01\x91\xa5c_PK\x05\x06\x00\x00\x00\x00\x04\x00\x04\x00H\x01\x00\x00\xe4\x0d\x00\x00\x00\x00" + data := "PK\x03\x04\x14\x00\x08\x00\x08\x00\xedNXQ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00 \x00graphql_enums.gotmplUT\x05\x00\x01\x0f\xfa\x93_\xac\x97QS\xe36\x10\xc7\xdf\xf3)\xb6nzcs\xc1\x99\xbe\xd2a\xa6e\xa0S:si\xa7\x1c\xedC\x9a\xc9\x08{\x1d\x04\xb6l$9\x1c5\xfe\xee\x9d\x95\x94DN\x1c\xc8q\xdc\xc3\xc5\xb6v\xd7\xbb\xbf\xfd\xaf,\x9a\xe6\x18\xe2_y\x8e\xbf!KQB\xdb\x0e\x06\x15K\xee\xd9\x02\xa1i \xfe\xd3^OX\x81f\x8d\x17U)5\x84\x03\x00\x80\xe0\xe6I\xa3\n\xec5\x8a\xa4L\xb9X\x8c\xefT)\xdc3\xa5%\x17\x0bg1\x1eC\x90\x15:\x18D\x83A\xd3\x80db\x81\x10_%\xb7X\xb08e\x9a\xc5\xf3\xb9\xb2w\xfa\xa9B\x05\xcf\x90\xf1\\\xa3<{\x82\xe0\x9e\x8b4\x80\xe0br\xfd)\x80gP\xa5\xd4gO\xab\xac(:\x15\xc23`\"\x85\x10\x1f &\x07g\x1fA(J\x0d!W\x17_\x92\xbcN1\x85X\xb0\x02\xa3\x08\x8e\x9d\xf7*\x82\xc6\xa2\xca\x99F*\xa7.\x02\x88\xd7\x16\xb4\x8a\"5\xf7Mc.\x89\xc7\x80\x9e\xa7\x98q\xb1\xf6Yy\x8c\xc7\x86 \xbd \x9e\x81\xd6>?U\x94/\xfc\xbc\x90\xac\xba}\xc8O\x83\xb5A\xdb\x06\xd04<\x838E\x95H^i^\x8a\xb6m\x1a\xff\x1e\x9e!\xc9\x91\xd1oV\xca\x82\xe9\xf3\xae-\x8at\x9d-\xc1\xc8\x90\xe9Z\"\x04\xb5\xc29\x17\x1a\x17(\xe7\x94\x88\n:\x95\x13\xee}\xb9r\xa17\xf5\xe7\n\x0fv\xb4\xbd\xef\xb0#`o\"cl\xec\xdb\x96,\xafQ\xc5\xef\x00+W\xd8\x85\x96\x94B\xad\xa4\xfdu\x00\xa9@\xab\xe7!\x1f\xc1\x10\xe1\xe4\x14b\xb2\xfb\xdbd\xdb\x11\xec_\xb8\x04\xcfu\xe5>\xdc\xc6A\xb9\x0d\xd1\x7fz\x99\xa2\xd0<\xe3(M\xd8\xab:\xcb\xf8\x97\xb6\xb5(2.\x95\x86!\x87\xa1q\xdc\x8d\x06\xa7\xc0K\xcd\xe0#\xfc\x08\xaej\xdb\x88o\xe5\xb8\xe6\xe7\xb8\xad\xa6d\xafj6\xb4|F\x1dB;\x80z\xf1\x1c\x06g\xed\xca\xd7&\x86\xc6\xc6\xff\xa1.5Z\x1c\xbe\x00\xadc\xdb~\xef,\xdfyF\xf7\xe1\xf2\xee#\xf3\xff\x92\xc97\xabr\x17\xdb|\xae\xcb+3\x9bp\n\x05\xab\xa6\xfdf3;\xbf\x8d\x9f\xean\xd3\xb6\x85}\xbc\xd3\xb8]a\x03a\x80W{\x07m{\xb2\xdd#\x8a?\xda\x86\xe7\xbd\xd2\xed/n\xb1\xbf\xf6\xcbsW\xb7-p\xd6_\xfe\xb7\xd7\xddM\xdc\x16\xd33\xe6p\x90\x90\xe1\xb5\xbaWW\xe3#\xcf\xcc\x0f\xfbK\x9e\xdb\xdc/\xbbS0\xedi\xf4\xab\xf5\xfa9\xbb\xe1\x19\xbd\x94\xd5\xd1\xf8\xa5\xdd\x00^\xc9\x13L\xa2^\xcb\xdeI\x9a\xc7\xb0#\xae\x93\xdd\xce\x1d&9\xef\x13\x07fp\xcdOV\x8b\x04B\xdcj\x85UX\x04v\n\xc3\xc8}*\xa1y\xc3\x8cK\xd4\xb5\x14{>\xa7\x9bQ\x9f\xe2\xacO\"\xce{\x1a\xc7q\x0f\xd4\xbe]\xfaMTG\x9d\xa0\xfe\x06G\xffZ?\xb9\x97\x94\xa2\xe8\xb3j\xd3\x0c1Z?\xe6\x19,GP\xde\xd3\xea\x01\x9a\x9f\xaa\xd9Od\xddlSX\xf6\x08\xb7b\x82'aV\xe8\xf8B\xcaRfap)\x96,\xe7)\xd0\xc9\xd2\x1eF E\x8d\x89\xc6\xf4\x04~\xf8\xb8\x0cF\x80Q\xd4\xa7\x89\xcd\xe1\xe7\x13\x93\xea\x96\xe5\xbf_\xfd1\x81\xc2^+\xd0\xb7h\x8f9L\x01\xb3\xecR\xa0\xb3\xb4\x7f\x92zYP^\xdc0\x82p:\xa3\xf3\xf9\x08\x90R\x8f\\\xc17u\x96\xa1$V\xe6\xf0\x1eO\xf0\xf1\xcc\x14\xc5\xdf\xf5)\xee_O 4\xf6{\xa0\xf0\xa7\xdb\xca:\xba\xa4t\xed\xd3\x18\xa9j_;jm\xc9\x91\xae\xcb\x82\xac\xef>$;i\x12\xb2v\x83\xc2\xb6'\xd9\xf7\x1e[\xe7\xfc\xa4\xeb\xdc\x04\x92sY\xe1G\x149\x1a\xf0\x9e\xb1Fd\x8f\xa2Dp\x0e\x92\xab\xfey&j\x8c=Y7\xda\x10\x8c\x18'Y#g\x8c\x97\x92\x96\xed}\x92\xe9:-\xb5.+L\xdbV\xe6\x9c\x8d\x19KS\xb8PMK`\xb01hQ\x91\x05\xad\x10t\x01\xb4\xc4\xa1g\xc9\xb4\x19\xd9)K\xd3\xf0\x81s\x0fZ*\x18\xe1w2\"\xa3s\x89U\x0e\\\x89\x1a9\x8c\nY\x11\x9a\xb35\xf0G\xa9r\x0e\xfcbvu{\xb3\x98\x9f}\xfa\xf0\xee\x86C\xf2%[b-\x92\\\x90H\x16\x0b\xdb\xbf\xd1\xbaA;\x1e\x03?\x01\xee}\xc2X(\x0c\x9bKEh\n\x91\xa1\xf3\x8c= \x03#v\xb3n\xf0\xb3hb\x7f~\xff\x80\x19Y8\x85Z4_-\x19\xa9\xcao\xfd\xe2\x98s`\x84*\xf1\xa5m\xa1\x83W\xd3x=\xf7\x981\xe7\xde8\xc9\xcb\xe7\xb7\x0dAX7\x95 \x04.\x9fqsH\xbcg\xce\xa1\xca\xc3o\xe2\xc2\x82\xc7 \xe4XHu\xa8\xde0\x89Cs\xec>x\x0f\xff\x97F4\xcbUu\xca\xb7\x12\xef9\xf4\xb0\x93\x1cmfdCR\xab\x08g\xbf\xd2AV\xa1\x08k\xa1M-\xe8\xfd\xa1z \x19<\xc4\x91r\xee\xb8\x89~\xc2\xc1\x0d\xe1'\x9b\xeb\x13\xd3\xc4\x01\xb7\xdb0\x1b\xc9\x001\xfcw 9\x9b\xcf\x16\xb3\xdb\xcbK\x0e;\xd2\xbf ?\x8c\xaeq\xd5J\x83y2\xde\xf3\xf5SS\xa1\x11\x81u=7\xef\xe1\xee\xc1j5\xdd79X\x9f\xf2\xffv\xcbw{\x98\x82\x85#\xe8\x14\xfe#\xe8\xe6\xb1&\xaa7Ew\xa2k\x19&\x8c\xd6;\x10\x7f\x8d\xe1\xe1\xbbg\xbb\x95\x1f\x01\x00\x00\xff\xffPK\x07\x08$v\x16O&\x02\x00\x00-\x07\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00t\xadXQ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00 \x00graphql_objects.gotmplUT\x05\x00\x01\x0d\xa0\x94_\xd4\x94\xc1n\xdb8\x10\x86\xef|\x8aY\x9e\xecE,\xdd\x0d\x04Xd\xdb\xa4)\x1c\xbbI\xd3SQ8\x8c4\x92\x99H\xa4L\x8e\x82\x1a4\xdf\xbd %'r\xe0\xb49\x04h{\xa24\x9c\x19\xfd\xff'\x0e\x9d\x9b@r*+\xfc\x80\"G\x03\xde3\xd6\x88\xec^\x94\x08\xceA\xf2\xa9{\x9e\x8b\x1a\xe3\x9e\xac\x1bm\x08F\x8c\x93\xac\x913\xc6KI\xab\xf66\xc9t\x9d\x96Z\x97\x15\xa6m+s\xce\xc6\x8c\xa5),n\xef0#0\xd8\x18\xb4\xa8\xc8\x82V\x08\xba\x00Z!\x9c\xab\xa6%\xb0d\xda\x8c\xec\x94\xa5i\xa8p\xeeNK\x05#\xfcNFdt*\xb1\xca\x81+Q#\x87Q!+Bs\xb2\x01~/U\xce\x81/N>\xbe\xff\xff\x9aC\xf29[a-\x92\\\x90H\x96K\xdb\xbd\xd1\xa6A;\x1e\x03?\x02\xee}\xc2X\x08\xec4IEh\n\x91\xa1\xf3\xfd\xc6\xd9\xe5\xec\x02I\xf4\x8a\xc01\x00\x804\x0d\xf1\xebM\xd3A\xf8\xaf4\xa2Y\xad\xabc\xbe\\\x86\xa2N\xd8\xb9\x05\x01u\xa8-\xa2\xdeL+\x12RIUF\xa3g\xa1\xe6r\x06\xf1+\xa1\"v\x1e\xb6\xfd\xd7\x92 \xd97wV\xab\xe9\xa0\xf7\x91\xae%a\xdd\xd0\x86\xdf0\xcf\xd8\x8300b\xa1\xeeB4\x9d\x13\x0b\xc7P\x8b\xe6k\xd7\xe2[\xb78\xe6\x1c\x18\xa1J\xfc\x19\x1b\xd8\xc2\x8bH\xb7`\xb5\xa1\x93M\xd47\xf1\xde9Y\x00\xae! yOi\x13\xef\xa3\x9bpZ\x82`\xd8\x82\xccQ\x91,$\x1a\xd8\xc2\xba\xd5\x14\xce\xcet\x98\xb1\x0b\x1e\x05\x95\xa8r\x08\xed'\xfd\x13\xf3\xec\n\x1f\xd0X\xfc=6\xe1\xb5>\x0fZ{2\xffk\x9bc\xc6\x9c{3\xf5/\xfd\xa2G\xe1\xe1\x1cU\x82\x10\xb8\x8eD9$\xde3\xe7P\xe5\xa16.,H\x9a@\x8e\x85T\x83\xc4\x9d\xfb8\xa0\x87~\xb4\xf7\x83\xd1xL\xf1\x9eC\x074\xc9\xd1fF6$\xb5\x8a\x18\xf6#[\xc8*\x14a-\xb4\xa9\x05\xbd{\x9e\xdd3\x0b\x1a\xe2\x149wX\xc4\xde\xec\xf6\x03\xdd\xdb\x9f\xec\x0eJ\x9cQ\xfb\xe8i\xb7\xdb\xb3\x0b\xed{\x80\xf3\xc5|9\xff2\x9bq\x18\xa4\xfe\x01\x18`t\x85\xebV\x1a\xcc\x93\xf1\x9e\xae\x17E\x85\x8d\xc8m\xdb\xe1\xf3~w\xd5\xec\x89\xec\xa5O\xf9?\xc3\xf0\xcd\x1e\xa6 \xe1\x00:\x85\x7f \xbaE\x8c\x89\xeaM\xd1\x0d\xae\xe9'\x88\xafc\xf8\xfc\xdd\xb3a\xe4G\x00\x00\x00\xff\xffPK\x07\x08s\xf3\xa4Sd\x02\x00\x00\xa1\x07\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x004NXQ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00 \x00graphql_scalars.gotmplUT\x05\x00\x01\xb5\xf8\x93_\x84U[o\xdb6\x18}\xb6~\xc5\x81\x1e\x06i\xa8\xe5\xb5\xcd\xba\x01C\x815s\xbai\xe8\xb2K\xb2\xcb\xd3\x8a\xcf\xd4'\x8b\x8bD*$e\xc7P\xfc\xdf\x07Rr\xact\x8b\xf3bH\xe6\xb9\x91<\xa4\xfa~\x8e\xec\xbd\xac\xf9\x07\xa6\x82\x0d\xf6\xfb(jI\xdc\xd0\x9a\xd1\xf7\xc8~\x19\x9e/\xa9\xe10&\x9bV\x1b\x87$\x9a\xc5N6\x1cG\xd1,^KWu\xabL\xe8f\xb1\xd6z]\xf3\xa2\xebd\x11Gi\x14\xf5=d\x89\x92j\x1b\xe83\xb7k\xd9\x93\x17\x0b\x9ck]3)\x18n\x0d[V\xce\xc2\x99\x8e\xa1\xcd\x88\xdfP\xdd\xb1\xcd\xa2\xd9\x01\xb9\xd2\xba\x8e\x02\xf7}\xad\xc9M\x99V\xae\x15\x17(t\xb7\xaay\xde\x1a\x16\xd2J\xadP\x1a\x12NjE\xf5(\x07\xb2A\xc1\xb6,d)\xb9\xc0j\x87\xfc\xe2\xe2\x02_}y\x96E\xb3A\xb9\xf4\xbfo\xce\x06\xb3|9u\"tJ\xdev\x0cY\xb0r^\xc2\xc0U\xe4 -\xce\xc9\xf2\x9b3\xe8U\xd9YA\x8e\x8b\x0c\xb9\x0b\x1a\xd2B\x97\x8e\x15:\xcb\x05\x9c\x86\xe1\x92\x9d\xa8@\nz\xf5\x0f\x0b\xe7\xe7M\x167\xbcC\xe9\x1f!HT\x9c\xe1\xbab\xe4\xcb \x12\x16\x8f\xda\x96\xc9XH\x05\xc2\x8fW?_\xc2\xb0m\xb5\xb2\xec\xe9\x84+g\xa4Z\x7f\x83Joy\xc3\xe6\x05d\x88\xa6\xf4\x18D9V\xc5\x90a\xc5\xa8\xba\x86\xd4\xdc0\x15\xb4\xaa9\xc3\x9f\x15+\xf0]\xcb\xc2q\x11\x04\x15\xa4j;\x17\xcc_\x04 R;\xd8\xe0\x82\xc4v~\x0e\x16\xf1\x1f\x7f]\xd6B~q\xf7\xd3\xbb\xb7o\xe3\xd4O\xc6;\xad\xd9\x1c1g\xe9 \x15D\xc2n`+\xeb\xda\xc7 !\xb8=:\xe6\xcb\xec\xb0\xf2^\xc5\x94$\xb8\xdfG\xb3|9\x1a\x8f\x1b\xa3\x1eu@i5\x9f\xec\xf7X\x89m\xa5k\x86\xea\x1a6R\x1c;5\xd2\xc5\xb4\x80\x87\x8a\xac\xd8m\x99\x15\xe6\xc9\xab\xbf_\xbfLA\xaa\x80\x7f\xc2\x1c/\xb3h\xe6yR\xb9\xd7\xaf\x86\x14\xc3\x82?\xaa1\xdf\xb9\x8ej\x14\xe4\xc8\xcf\xe8\xf7\xeb\xf7\xf3\xaf!*\xf2\xe1\xd8\xc0\xf2m\xc7J\x1cr\\W\xd2\x0e{+-\x1am\xdd\xb4*\xab\x1d\xbe7\xd4V\xbf~\x18Zs\x88Z\x1a\xe6y\xa9M\x13$\x1eoc\x08\x90E\xb31\xd9\xb8d\xb3t\xc8{\xc9\xdb\xc3\x81\x92\xbe0\x15\xd7\xad\xef\xb0FC7\x0c\x82\xe2->\x1f!Y4+;%&\xa4ds8\xb9\xe9\x03\n=\x0c\xbb\xce(|\xb6\xc1\xfe\xc1f8K'L\x02`b\x11\xde\x93\xcdp\xbc\xd3q\xfc q\xdf\x8d\xa7\x95C\x83\x0e\xb2\xf92\xd9 _\xa6\xfe\xef\xa7\xd4\xd4\xc9\xa0\xb9\x9a\xc6\xcc\x95\x0f\x99+\x1f\xd1\x13\xff_r\\\xfd\x13\xaa\x03b\"<\xfc\x91l\xc6N\xa5\x07\xc8'\x0e}\x0fV\x05\xe6\xfe>\xee{\x18RkFv%*n(\xf3\xa5\xcb>~\xb4\xc3\x9b\xaf\x95\xc5=JY;6\xe7;\xc47R\x151\xe2\xab\xef\xde}x\xf7[\x8c{Xm\xdc\xf9.\\\xf0^q\xe6\xbf\x08\xb2\x0c\xa5O\xf8\x16\x99'<\xe0S$J;$\xd2^\xdc\x89\xba\xf3\x17I\xa6\xa8\xe14\x1d\xc8\x81\xed\xb8ikr\x8c\xd8\n\xaa\xc9\xc4\xc8\x8e\xd2c\xf2\xc3\xe30\x879\n.\xa5\x9a0\x02~\xb1\x08\xdf o\xe0\x83\x86\xa1\xfcx\xed\xee\xf7\xf8v\xed\x0f\xc7m\xfd6~\x00\xee\xf71\xfa^\x96\xc8\n\xb6\xc2\xc8\xd6\xdf\x07\xdep\xfa\x8e{\x88\xd0\xdc{\x7f\xdb6\xe4\x96\x8f\xb1\xac\x8a\x87\xcf\xd53\x11\xfe3|\xedI\xfbc\x11\x9e\xe1\x9f(\xc8i\xe6\xa48\xa7\x81\xc9\xe6\x999\xa4\xcfY}Z\xf1i\x03\xff\x0d\x00\x00\xff\xffPK\x07\x08\xf2\xd8\x92\xf4\x95\x03\x00\x00B\x08\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\xedNXQ\x1e`RE'\x04\x00\x00\xdc\x0e\x00\x00\x14\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x81\x00\x00\x00\x00graphql_enums.gotmplUT\x05\x00\x01\x0f\xfa\x93_PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00l\xadXQ$v\x16O&\x02\x00\x00-\x07\x00\x00\x1c\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x81r\x04\x00\x00graphql_input_objects.gotmplUT\x05\x00\x01\xfd\x9f\x94_PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00t\xadXQs\xf3\xa4Sd\x02\x00\x00\xa1\x07\x00\x00\x16\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x81\xeb\x06\x00\x00graphql_objects.gotmplUT\x05\x00\x01\x0d\xa0\x94_PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x004NXQ\xf2\xd8\x92\xf4\x95\x03\x00\x00B\x08\x00\x00\x16\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x81\x9c \x00\x00graphql_scalars.gotmplUT\x05\x00\x01\xb5\xf8\x93_PK\x05\x06\x00\x00\x00\x00\x04\x00\x04\x008\x01\x00\x00~\x0d\x00\x00\x00\x00" fs.Register(data) } diff --git a/internal/statikdata/statikdata.go b/internal/statikdata/statikdata.go index 56026bd..2ff32f2 100644 --- a/internal/statikdata/statikdata.go +++ b/internal/statikdata/statikdata.go @@ -1,9 +1,145 @@ package statikdata import ( + "fmt" + "io/ioutil" + "net/http" + "os" + + "github.com/pkg/errors" + "github.com/rakyll/statik/fs" _ "github.com/rakyll/statik/fs" + + "github.com/shakahl/gqlassist/internal/utils" +) + +var ( + statikFs http.FileSystem ) func init() { } + +func Init() { + if statikFs != nil { + return + } + sfs, err := fs.New() + if err != nil { + panic(errors.Wrapf(err, "statikdata: error during intialization")) + } + statikFs = sfs + + dumpRegisteredAssets() +} + +func GetFileSystem() http.FileSystem { + if statikFs != nil { + return statikFs + } + Init() + return statikFs +} + +func Open(name string) (http.File, error) { + return GetFileSystem().Open(name) +} + +func MustOpen(name string) http.File { + file, err := GetFileSystem().Open(name) + if err != nil { + panic(err) + } + return file +} + +// ReadDir reads the contents of the directory associated with file and +// returns a slice of FileInfo values in directory order. +func ReadDir(name string) ([]os.FileInfo, error) { + f, err := GetFileSystem().Open(name) + if err != nil { + return nil, err + } + defer f.Close() + return f.Readdir(-1) +} + +// Stat returns the FileInfo structure describing file. +func Stat(name string) (os.FileInfo, error) { + f, err := GetFileSystem().Open(name) + if err != nil { + return nil, err + } + defer f.Close() + return f.Stat() +} + +// ReadFile reads the file named by path from fs and returns the contents. +func ReadFile(path string) ([]byte, error) { + rc, err := GetFileSystem().Open(path) + if err != nil { + return nil, err + } + defer rc.Close() + return ioutil.ReadAll(rc) +} + +func MustReadFile(path string) []byte { + s, err := ReadFile(path) + if err != nil { + panic(err) + } + return s +} + +// ReadFileString reads the file named by path from fs and returns the contents. +func ReadFileString(path string) (string, error) { + buf, err := ReadFile(path) + if err != nil { + return "", err + } + return string(buf), nil +} + +func MustReadFileString(path string) string { + s, err := ReadFileString(path) + if err != nil { + panic(err) + } + return s +} + +// Exists reports whether the named file or directory exists in http.FileSystem. +func Exists(name string) bool { + if _, err := Stat(name); err != nil { + if os.IsNotExist(err) { + return false + } + } + return true +} + +func MustExists(name string) bool { + if !Exists(name) { + panic(errors.New("statikdata: required asset does not exists: " + name)) + } + return true +} + +func dumpRegisteredAssets() { + var err error + var files []string + walkerFn := func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + fmt.Printf(" - %s (size: %s)\n", path, utils.FormatFileSize(info.Size())) + files = append(files, path) + return nil + } + err = fs.Walk(statikFs, "/", walkerFn) + if err != nil { + panic(errors.Wrapf(err, "statikdata: error while trying to list registered assets")) + } +} diff --git a/internal/utils/common.go b/internal/utils/common.go index 893d3e9..816cd94 100644 --- a/internal/utils/common.go +++ b/internal/utils/common.go @@ -2,7 +2,6 @@ package utils import ( "fmt" - "log" "os" ) @@ -29,11 +28,11 @@ func GetValue(v interface{}, def string) string { } // Must halts the application if error is not nil -func Must(err error) { - if err != nil { - log.Fatalf("ERROR : %s\n", err) - } -} +// func Must(err error) { +// if err != nil { +// log.Fatalf("ERROR : %s\n", err) +// } +// } // Die halts the execution with a message func Die(msg string) { diff --git a/internal/utils/errors.go b/internal/utils/errors.go new file mode 100644 index 0000000..8772bbd --- /dev/null +++ b/internal/utils/errors.go @@ -0,0 +1,106 @@ +package utils + +import ( + "fmt" + "log" + "os" + + "github.com/pkg/errors" +) + +const ( + ErrMessageFatal = "fatal error" +) + +var ( + ErrFatal = errors.New(ErrMessageFatal) +) + +// Must will be panic if one its argument is an error. +// +// func myFunction(n int) (int, error) { +// if n === 0 { +// return 0, fmt.Errorf("myFunction error: %s", "n cannot be zero") +// } +// return n, nil +// } +// Must(myFunction(0)) // will panic +// Must(myFunction(1)) // won't panic, execution continues +// +func Must(args ...interface{}) { + var err error = nil + if len(args) == 0 { + return + } + if e, ok := args[len(args)-1].(error); ok { + err = e + args = args[:len(args)-1] + } + + if err == nil { + for _, arg := range args { + if e, ok := arg.(error); ok { + err = e + } + } + } + if err != nil { + err = errors.Wrap(err, "FATAL ERROR") + panic(err) + } +} + +// Fatal is equivalent to Print() followed by a call to os.Exit(1). +func FatalErr(err error) { + log.Fatal(errors.Wrap(err, ErrFatal.Error())) +} + +// Fatal starts to panic with error +func Fatal(err error) { + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "%s", err) + perr := errors.Wrap(err, ErrFatal.Error()) + perr = errors.Wrap(perr, "panic") + panic(perr) + } +} + +// Catch catches a panic and recovers from it +func Catch(f func(), g func(interface{})) { + defer func() { + if v := recover(); v != nil { + g(v) + } + }() + f() +} + +// Cause returns the underlying cause of the error, if possible. +// An error value has a cause if it implements the following +// interface: +// +// type causer interface { +// Cause() error +// } +// +// If the error does not implement Cause, the original error will +// be returned. If the error is nil, nil will be returned without further +// investigation. +func Cause(err error) error { + type causer interface { + Cause() error + } + + for err != nil { + cause, ok := err.(causer) + if !ok || cause.Cause() == nil { + break + } + err = cause.Cause() + } + return err +} + +func recovery() { + recover() +} diff --git a/internal/utils/formatters.go b/internal/utils/formatters.go new file mode 100644 index 0000000..b941647 --- /dev/null +++ b/internal/utils/formatters.go @@ -0,0 +1,52 @@ +package utils + +import ( + "fmt" + "reflect" + "strings" +) + +func FormatFileSize(value interface{}) string { + defer recovery() + + var size float64 + + v := reflect.ValueOf(value) + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + size = float64(v.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + size = float64(v.Uint()) + case reflect.Float32, reflect.Float64: + size = v.Float() + default: + return "" + } + + var KB float64 = 1 << 10 + var MB float64 = 1 << 20 + var GB float64 = 1 << 30 + var TB float64 = 1 << 40 + var PB float64 = 1 << 50 + + sizeFormat := func(filesize float64, suffix string) string { + return strings.Replace(fmt.Sprintf("%.1f %s", filesize, suffix), ".0", "", -1) + } + + var result string + if size < KB { + result = sizeFormat(size, "bytes") + } else if size < MB { + result = sizeFormat(size/KB, "KB") + } else if size < GB { + result = sizeFormat(size/MB, "MB") + } else if size < TB { + result = sizeFormat(size/GB, "GB") + } else if size < PB { + result = sizeFormat(size/TB, "TB") + } else { + result = sizeFormat(size/PB, "PB") + } + + return result +} diff --git a/main.go b/main.go index dfedcbe..b7a3970 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,4 @@ -//go:generate statik -dest=internal -p statikdata -src=assets/templates/ -include=*.gotmpl +//go:generate statik -f -dest=internal -p statikdata -src=assets/templates/ -include=*.gotmpl package main