diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go index 39ec623b3..d6deeec18 100644 --- a/cmd/cue/cmd/common.go +++ b/cmd/cue/cmd/common.go @@ -296,7 +296,7 @@ func (i *streamingIterator) scan() bool { if schema := i.b.encConfig.Schema; schema.Exists() { i.e = schema.Err() if i.e == nil { - i.v = i.v.Unify(schema) + i.v = i.v.Unify(schema) // TODO(required fields): don't merge in schema i.e = i.v.Err() } i.f = nil @@ -409,6 +409,19 @@ func (p *buildPlan) getDecoders(b *build.Instance) (schemas, values []*decoderIn for _, f := range b.OrphanedFiles { switch f.Encoding { case build.Protobuf, build.YAML, build.JSON, build.JSONL, build.Text: + if f.Interpretation == build.ProtobufJSON { + // Need a schema. + values = append(values, &decoderInfo{f, nil}) + continue + } + case build.TextProto: + if p.importing { + return schemas, values, errors.Newf(token.NoPos, + "cannot import textproto files") + } + // Needs to be decoded after any schema. + values = append(values, &decoderInfo{f, nil}) + continue default: return schemas, values, errors.Newf(token.NoPos, "unsupported encoding %q", f.Encoding) @@ -569,13 +582,17 @@ func parseArgs(cmd *Command, args []string, cfg *config) (p *buildPlan, err erro } switch { + default: + fallthrough + + case p.schema != nil: + p.orphaned = values + case p.mergeData, p.usePlacement(), p.importing: if err = p.placeOrphans(b, values); err != nil { return nil, err } - default: - p.orphaned = values } if len(b.Files) > 0 { diff --git a/cmd/cue/cmd/help.go b/cmd/cue/cmd/help.go index 67ec13976..a34742c1c 100644 --- a/cmd/cue/cmd/help.go +++ b/cmd/cue/cmd/help.go @@ -185,9 +185,11 @@ var filetypeHelp = &cobra.Command{ jsonl .jsonl/.ldjson Line-separated JSON values. jsonschema JSON Schema. openapi OpenAPI schema. + pb Use Protobuf mappings (e.g. json+pb) + textproto .textproto Text-based protocol buffers. proto .proto Protocol Buffer definitions. - go .go Go source files. - text .txt Raw text file; the evaluated + go .go Go source files. + text .txt Raw text file; the evaluated value must be of type string. OpenAPI, JSON Schema and Protocol Buffer definitions are @@ -495,7 +497,6 @@ cuelang.org/go/pkg/tool/tool.cue. // - id= // TODO: filetypes: -// - textpb // - binpb // TODO: cue.mod help topic diff --git a/cmd/cue/cmd/orphans.go b/cmd/cue/cmd/orphans.go index e35dbb407..13f7c62df 100644 --- a/cmd/cue/cmd/orphans.go +++ b/cmd/cue/cmd/orphans.go @@ -27,6 +27,7 @@ import ( "cuelang.org/go/cue/errors" "cuelang.org/go/cue/parser" "cuelang.org/go/cue/token" + "cuelang.org/go/encoding/protobuf/jsonpb" "cuelang.org/go/internal" "cuelang.org/go/internal/astinternal" "cuelang.org/go/internal/encoding" @@ -172,6 +173,7 @@ func placeOrphans(b *buildPlan, d *encoding.Decoder, pkg string, objs ...*ast.Fi expr := internal.ToExpr(file) p, _, _ := internal.PackageInfo(file) + var path cue.Path var labels []ast.Label switch { @@ -227,6 +229,22 @@ func placeOrphans(b *buildPlan, d *encoding.Decoder, pkg string, objs ...*ast.Fi a = append(a, cue.Label(label)) labels = append(labels, label) } + + path = cue.MakePath(a...) + } + + switch d.Interpretation() { + case build.ProtobufJSON: + v := b.instance.Value().LookupPath(path) + if b.useList { + v, _ = v.Elem() + } + if !v.Exists() { + break + } + if err := jsonpb.NewDecoder(v).RewriteFile(file); err != nil { + return nil, err + } } if b.useList { diff --git a/cmd/cue/cmd/testdata/script/cmd_jsonpb.txt b/cmd/cue/cmd/testdata/script/cmd_jsonpb.txt new file mode 100644 index 000000000..ec041bb48 --- /dev/null +++ b/cmd/cue/cmd/testdata/script/cmd_jsonpb.txt @@ -0,0 +1,81 @@ +cue eval schema.cue json+pb: data.json +cmp stdout out/data1 + +cue eval schemaflag.cue -d '#X' json+pb: data.json +cmp stdout out/data1 + +! cue eval schema.cue json+pb: data-err.json +cmp stderr out/data-err + +cue eval .:nested yaml+pb: stream.yaml -l kind +cmp stdout out/stream + +-- schema.cue -- +a: int @protobuf(1,int64) // to string +b: int @protobuf(2,int32) // also allow string +c: int // also allow +d: float +s: string +t: bytes + +-- nested.cue -- +package nested + +A: { + a: int @protobuf(1,int64) // to string + b: bytes +} + +B: { + a: int @protobuf(1,int64) // to string + s: string +} + +-- schemaflag.cue -- +#X: { + a: int @protobuf(1,int64) // to string + b: int @protobuf(2,int32) // also allow string + c: int // also allow + d: float + s: string + t: bytes +} + +-- data.json -- +{"a": "10", "b": "20", "c": 30, "d": "1.2", +"s":"SGVsbG8sIOS4lueVjA==", +"t": "SGVsbG8sIOS4lueVjA=="} + +-- data-err.json -- +{"a": "10", "b": "20", "c": "30", "t": "SGVsbG8sIOS4lue???VjA==" } + +-- stream.yaml -- +kind: "A" +a: "10" +b: "SGVsbG8sIOS4lueVjA==" +--- +kind: "B" +a: "10" +s: "SGVsbG8sIOS4lueVjA==" + +-- out/data1 -- +a: 10 +b: 20 +c: 30 +d: 1.2 +s: "SGVsbG8sIOS4lueVjA==" +t: 'Hello, 世界' +-- out/stream -- +A: { + kind: "A" + a: 10 + b: 'Hello, 世界' +} +B: { + kind: "B" + a: 10 + s: "SGVsbG8sIOS4lueVjA==" +} +-- out/data-err -- +t: failed to decode base64: illegal base64 data at input byte 15: + ./data-err.json:1:40 diff --git a/cmd/cue/cmd/testdata/script/cmd_textproto.txt b/cmd/cue/cmd/testdata/script/cmd_textproto.txt new file mode 100644 index 000000000..e1549b16a --- /dev/null +++ b/cmd/cue/cmd/testdata/script/cmd_textproto.txt @@ -0,0 +1,37 @@ +cue eval topschema.cue foo.textproto +cmp stdout out/topfoo.textproto + +cue eval -d '#X' schema.cue foo.textproto +cmp stdout out/foo.textproto + +! cue eval -d '#X' schema.cue foo.textproto -l c +cmp stderr out/stderr3 + +-- topschema.cue -- +a: int +b: [...int] +c: string +-- schema.cue -- +#X: { + a: int + b: [...int] + c: string +} +-- foo.textproto -- +a: 4 +b: 1 +b: 2 +b: 3 +b: 4 +b: 5 +c: "foo" +-- out/topfoo.textproto -- +a: 4 +b: [1, 2, 3, 4, 5] +c: "foo" +-- out/foo.textproto -- +a: 4 +b: [1, 2, 3, 4, 5] +c: "foo" +-- out/stderr3 -- +cannot combine --schema flag with flag "path", "list", or "files" diff --git a/cue/build/file.go b/cue/build/file.go index 2aef149a5..ecfdfb03d 100644 --- a/cue/build/file.go +++ b/cue/build/file.go @@ -30,17 +30,17 @@ type File struct { type Encoding string const ( - CUE Encoding = "cue" - JSON Encoding = "json" - YAML Encoding = "yaml" - JSONL Encoding = "jsonl" - Text Encoding = "text" - Protobuf Encoding = "proto" + CUE Encoding = "cue" + JSON Encoding = "json" + YAML Encoding = "yaml" + JSONL Encoding = "jsonl" + Text Encoding = "text" + Protobuf Encoding = "proto" + TextProto Encoding = "textproto" + BinaryProto Encoding = "pb" // TODO: // TOML - // TextProto - // BinProto Code Encoding = "code" // Programming languages ) @@ -62,9 +62,10 @@ const ( // the info.title and info.version fields. // // In all other cases, the underlying data is interpreted as is. - Auto Interpretation = "auto" - JSONSchema Interpretation = "jsonschema" - OpenAPI Interpretation = "openapi" + Auto Interpretation = "auto" + JSONSchema Interpretation = "jsonschema" + OpenAPI Interpretation = "openapi" + ProtobufJSON Interpretation = "pb" ) // A Form specifies the form in which a program should be represented. diff --git a/internal/encoding/encoder.go b/internal/encoding/encoder.go index 40db53ff6..dacf6e79a 100644 --- a/internal/encoding/encoder.go +++ b/internal/encoding/encoder.go @@ -30,6 +30,8 @@ import ( "cuelang.org/go/cue/format" "cuelang.org/go/cue/token" "cuelang.org/go/encoding/openapi" + "cuelang.org/go/encoding/protobuf/jsonpb" + "cuelang.org/go/encoding/protobuf/textproto" "cuelang.org/go/internal" "cuelang.org/go/internal/filetypes" "cuelang.org/go/pkg/encoding/yaml" @@ -87,6 +89,12 @@ func NewEncoder(f *build.File, cfg *Config) (*Encoder, error) { } return openapi.Generate(i, cfg) } + case build.ProtobufJSON: + e.interpret = func(v cue.Value) (*ast.File, error) { + f := valueToFile(v) + return f, jsonpb.NewEncoder(v).RewriteFile(f) + } + // case build.JSONSchema: // // TODO: get encoding options // cfg := openapi.Config{} @@ -182,6 +190,20 @@ func NewEncoder(f *build.File, cfg *Config) (*Encoder, error) { return err } + case build.TextProto: + // TODO: verify that the schema is given. Otherwise err out. + e.concrete = true + e.encValue = func(v cue.Value) error { + v = v.Unify(cfg.Schema) + b, err := textproto.NewEncoder().Encode(v) + if err != nil { + return err + } + + _, err = w.Write(b) + return err + } + case build.Text: e.concrete = true e.encValue = func(v cue.Value) error { diff --git a/internal/encoding/encoding.go b/internal/encoding/encoding.go index 67ad18138..fada36097 100644 --- a/internal/encoding/encoding.go +++ b/internal/encoding/encoding.go @@ -37,6 +37,8 @@ import ( "cuelang.org/go/encoding/jsonschema" "cuelang.org/go/encoding/openapi" "cuelang.org/go/encoding/protobuf" + "cuelang.org/go/encoding/protobuf/jsonpb" + "cuelang.org/go/encoding/protobuf/textproto" "cuelang.org/go/internal" "cuelang.org/go/internal/filetypes" "cuelang.org/go/internal/third_party/yaml" @@ -48,6 +50,7 @@ type Decoder struct { cfg *Config closer io.Closer next func() (ast.Expr, error) + rewriteFunc rewriteFunc interpretFunc interpretFunc interpretation build.Interpretation expr ast.Expr @@ -59,6 +62,7 @@ type Decoder struct { } type interpretFunc func(*cue.Instance) (file *ast.File, id string, err error) +type rewriteFunc func(*ast.File) (file *ast.File, err error) // ID returns a canonical identifier for the decoded object or "" if no such // identifier could be found. @@ -89,7 +93,15 @@ func (i *Decoder) Next() { } func (i *Decoder) doInterpret() { - // Interpretations + if i.rewriteFunc != nil { + i.file = i.File() + var err error + i.file, err = i.rewriteFunc(i.file) + if err != nil { + i.err = err + return + } + } if i.interpretFunc != nil { var r cue.Runtime i.file = i.File() @@ -208,6 +220,9 @@ func NewDecoder(f *build.File, cfg *Config) *Decoder { case build.JSONSchema: i.interpretation = build.JSONSchema i.interpretFunc = jsonSchemaFunc(cfg, f) + case build.ProtobufJSON: + i.interpretation = build.ProtobufJSON + i.rewriteFunc = protobufJSONFunc(cfg, f) default: i.err = fmt.Errorf("unsupported interpretation %q", f.Interpretation) } @@ -242,6 +257,13 @@ func NewDecoder(f *build.File, cfg *Config) *Decoder { PkgName: cfg.PkgName, } i.file, i.err = protobuf.Extract(path, r, paths) + case build.TextProto: + b, err := ioutil.ReadAll(r) + i.err = err + if err == nil { + d := textproto.NewDecoder() + i.expr, i.err = d.Parse(cfg.Schema, path, b) + } default: i.err = fmt.Errorf("unsupported encoding %q", f.Encoding) } @@ -286,6 +308,16 @@ func openAPIFunc(c *Config, f *build.File) interpretFunc { } } +func protobufJSONFunc(cfg *Config, file *build.File) rewriteFunc { + return func(f *ast.File) (*ast.File, error) { + if !cfg.Schema.Exists() { + return f, errors.Newf(token.NoPos, + "no schema specified for protobuf interpretation.") + } + return f, jsonpb.NewDecoder(cfg.Schema).RewriteFile(f) + } +} + func reader(f *build.File, stdin io.Reader) (io.ReadCloser, error) { switch s := f.Source.(type) { case nil: diff --git a/internal/filetypes/types.cue b/internal/filetypes/types.cue index 07521dba1..935deb338 100644 --- a/internal/filetypes/types.cue +++ b/internal/filetypes/types.cue @@ -139,20 +139,22 @@ modes: def: { // Extension maps file extensions to default file properties. extensions: { - "": _ - ".cue": tags.cue - ".json": tags.json - ".jsonl": tags.jsonl - ".ldjson": tags.jsonl - ".ndjson": tags.jsonl - ".yaml": tags.yaml - ".yml": tags.yaml - ".txt": tags.text - ".go": tags.go - ".proto": tags.proto + "": _ + ".cue": tags.cue + ".json": tags.json + ".jsonl": tags.jsonl + ".ldjson": tags.jsonl + ".ndjson": tags.jsonl + ".yaml": tags.yaml + ".yml": tags.yaml + ".txt": tags.text + ".go": tags.go + ".proto": tags.proto + ".textproto": tags.textproto + ".textpb": tags.textproto // perhaps also pbtxt + // TODO: jsonseq, - // ".textproto": tags.textpb - // ".pb": tags.binpb + // ".pb": tags.binpb // binarypb } // A Encoding indicates a file format for representing a program. @@ -179,12 +181,22 @@ tags: { cue: encoding: "cue" - json: encoding: "json" - jsonl: encoding: "jsonl" - yaml: encoding: "yaml" - proto: encoding: "proto" - // "textpb": encodings.textproto + json: encoding: "json" + jsonl: encoding: "jsonl" + yaml: encoding: "yaml" + proto: encoding: "proto" + textproto: encoding: "textproto" // "binpb": encodings.binproto + + // pb is used either to indicate binary encoding, or to indicate + pb: *{ + encoding: "binarypb" + interpretation: "" + } | { + encoding: !="binarypb" + interpretation: "pb" + } + text: { encoding: "text" form: "data" @@ -308,10 +320,17 @@ encodings: proto: { encoding: "proto" } -// encodings: textproto: { -// forms.DataEncoding -// encoding: "textproto" -// } +encodings: textproto: { + forms.data + encoding: "textproto" + stream: false +} + +encodings: binarypb: { + forms.data + encoding: "binarypb" + stream: false +} // encodings: binproto: { // forms.DataEncoding @@ -340,3 +359,8 @@ interpretations: openapi: { forms.schema encoding: *"json" | _ } + +interpretations: pb: { + forms.data + stream: true +} diff --git a/internal/filetypes/types.go b/internal/filetypes/types.go index 41f7abaea..b2948eabb 100644 --- a/internal/filetypes/types.go +++ b/internal/filetypes/types.go @@ -41,5 +41,5 @@ func cuegenMake(name string, x interface{}) cue.Value { return v } -// Data size: 1624 bytes. -var cuegenInstanceData = []byte("\x01\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xacW\xddo\xd4H\x12\xb7CN:\xb7\xb8{\xe2\xf5\xa4\xc2H\x88\x8b\xc0\x11\x0f\b4R\x84\x80\xc0)/\xc7\xe9\xc4=!\x14\xf5\xd8\xe5\x99>\xecn\xaf\xbb\r\x89\xc8<\xec.\xcb\xee_\u036c\xaa\xbb\xfd9\xe6#\xbb\xc9K\xc6\xf5\xd5U\xd5\xfd\xab\x8f\xbfm\u007f\xdd\v\xf7\xb6\xbf\x05\xe1\xf6\xa7 x\xb8\xfd\xf1Z\x18^\x17R\x1b.S<\xe6\x86\x13=\xbc\x16\xee\xffW)\x13\xee\x05\xe1\xfe\u007f\xb8Y\x87\u05c3\xf0//D\x81:\xdc~\n\x82\xe0\x1f\xdb_\xf6\xc2\xf0\xef\xaf\u07e4\r&\xb9(\xbc\xe6\xa7 \xdc~\f\x82;\u06df\xaf\x85\xe1_{\xfa\xc7 \xdc\v\xf7\xff\xcdK$C\xfb\x96\u0202 \xf8|\xe3\x1ey\x12\x86{a\x18\x99\xf3\nu\x926\x18~\xbeq\xa3\xe2\xe9[\xbeBX6\xa2\xc8\x18;<\x84'@\xe7C\xaa\xea\x1au\xa5d\xa6\xc1(\xe0\xf0/\xe5\x84\x12b'\xec\x16\xfd[\xc0\a\x16\xd1\U000525f8\x00\xff\xa7M-\xe4\x8aE(S\x95\t\xb9\xea\x18\xb7\x9e{\n\x8b\x844XW5\x1an\x84\x92\x8f\x17p\xebdDaQ\xae\xea\xf2q\xa7J\xda/T]\xb2\xc8\xf0\x95~l\x0f\x8e^\xbb\x93\xde,\xba#7lc\x838\u019c7\x85\x01\xa1\xc1\xac\x11\xc8Eh4f\x90\xab\x1a\xb4\u0244\x04.3\xfa\xa5\x1a\x93\xc0\xab5\x82Fc\x84\\i\u0230B\x99\x91\x15%{\xedRe\x14\xb57\xbc\x00\x1b?\xdc\x1e'\xe0 \xbe\x17\xc3E\xeb\xcdf\x90\xcf\x13\x99+\xc80\x17\x125\xac\xd5{\xe0\u03ac\xd0`\u04c4\x99u\xa8K\vf>\u0164h\xa3\xb5_,\u02b8\xe1}V\x0eL\xdd \\@\xce\v\x8d,\xaa1\xc7\x1ae\x8az\xb1\xcbL\xcf\xd3\xc21f4\xadk\x822O\x12K\xa5\n\x16\xa9\x8a\xbey\xe1T\x1c-UR\x9b\x9a\viz\xb9\xb7\x88\x95\u03cb^x\x9a\x90\xa9*\xab\x02\x8d}\x16\x9eVV\xaa6\xad\a\x8e\xa6M\x8d\xbcl\x9dr\xb4L\xa5\xba\x0f\xd1\u04781\xb5X6\xc6\x05`i.\xbdt/\x9a.\x8f.\xce\xf9`/9\x13\xb9\u0345\x01Ua\xcd]$N:a\x87\x87\xa4\xfaj\x8d\x1a\xc1`Y\x15\u0720\x06^\xa3\xbd\x00I\xb7a\x14,\x11\x1a)r\x81t/\xc0\x8d}\f\xb5R\x06T\x0ef-4\x19I\x95\xcc\u016aq'$\xcc\x1e`\xef\ub512P5\xc6=\xd5\xfe\xe1\xd0\xd7\x00\x1a\aq\xda =\x9aS\xa2'I\u00a2h\u00e2\xa8@\x03gp\xe4\u0107\x19\x99\\\\4J\u0354I\x96\x06\xcf\xe8\x8c\xf5Gk\xefJ\xda\xd0\xc3%\xb4\xe9D\xa7k,\xb9w\x86t\xf1\u0320\xd4\xeeUX\xe98\xf9\xbfV2\xf6_\x13\x18S4\xbc1\xaa\vg\xe3T\xceyY\\V\xe5r\x1a\x1b\x82~\x84g\xf4\xc0\xbe\x99p\x1b\xc1\x172~z\u007f.\xe7>\xab\a\xb39\x9f2\xa79?\xbd\xff\x8d\xac\x13\xa4\xfb\x9coX\xa4\x9a\u02b4\x0f\xc7y\xf5\xe8\xc1\u057b\xf5\xe8\xc1e\xfd\xc2wT\f\xfe\xf8s>}\xfa\xe4\xea\xc3x\xfa\xe4\x1ba\u4090?\x8c#\xc3\xfcO\x85\xf1\xe0\xe1\xb3GW\x0eMk\xf5\x92\xf8l\xdb\xdd\xf3\x16\xa6P\xf2J\xbb\xce\xd2C\x97j\x99\xaf\x8d\x8eU\xd5T\x13\x8d\xa0R8Ax\x1cw\x95\xf7\x94E1\x8d\t\x8eBm\x97\xbeX_\x02<\x91\xbeZ*\x81\xb6\xa7\x16D.2/>&\xcby\xb2/\x15\xde\b}\xb1\xae\x1aL\xa9\xe6\xcc\f\xa8\x06\xcf\fQW\u0287`\xa9+E\xb4\xaaVFu\xae\xd9/\x16Q\axy\xfcr\x01t\xb8\xc6\x1f\xeeZRl\r\xb5\n\x9d\xe5j\xe9\xb9\u0572\u03d0\xe5.\x85\xac\x96]\xafo'\x1c\x102\x13\xa9k+.\xe9t\x83\xdc\xd8\xdeTcU\xa3FI\xf3\x06p\xba\x8eU\xcd\u02c4u\xf3\xd1\x02n\x1e\u01713)a<\x19A\x86\x06\xebr0H\xa4X\x1b.dk\a\xf4Z5EF\xedk4N\x1c\x1e\xc2\vUC;\x83\xde\x05\x8b\uf49fO$\x81S+\xd5i-\x96\xce?\xf7\xea\xee\xc2\xfb\xb5H\xd7 \x8c\xc6\"\xb7\xad\x8fKRM\x95|\x87\xb5q=\x93\u00f3\xff=\xf7\x1a\t\x9b\fu\u075cfG\xb9\xe1l\xe7\u9e5d)G3_;;M&\xad8W\u02bdC7):\xad\xd8\x1d\x1c\xfb\xeb\xa0\xfbq\x88HUY\xd2|U\b\x89\x8el\xd4.\x16\x88aQ\xe0\xcc8\x00:\xeb\x9de\x82\u076a\xe6\xd5z\u0135\x14\xc7\xcc\xf8j\xc4\xca\xf8\xaae\x18>\xe1\x18o\xd0b\xfc\x03\x1bV [\x80,\x93\xa2\xdc\xe1\xfa\xd0=\xbb\x98\xe5\x17N\x80\xe0\xb2\u00f78\xb3l\xfb\xd4w\xf8\x0e\x00V\x80\x9e\xbd\x83@\xbc\x80\xae:\xf50q\x12\x16\x06\x04\x8d^\x82HN\x80dw\x8e b\xdce\xc3^_\x9f\x91\u054eK\xee/\xa6Y\x99\xb4\xa6CAL\xc4\xee\x02\xa3\xa8\xe0\xf6\x90\x15\x05\xe1\xcb>\xa9^\x89\xd5v\xdb\xf0vi\x1aq\xfc\x1du;\xa8\xcc\x1c8\x1aB\xfc%\x0e\x1f\u074e\xa1^\xe0{\u0329\n%\xaf\xc4\x17ly\xeew\x18r0\xb2\xbd\xa7[^|\x0f\xa2:\u018b\xc21\x1381\x90)\xd4 \x95\x01!\u04e2\xc9\xd0\xedN\xaa.\xe1\xe48aV\xce:d77\xdaQ\x8f\xba\xf5\xad\x83\xb9\xf5\x9ez\xd0\xe9\x1c\b\xbb\xad\xa7E#\\@l\u06fb\xfd\u0542p\xb2TL'\x88\xf1j2m\xcb\xe3Eh\xca\x1d\xafDwF\xec\u007f\xc2\xed)\x85E\x93\x85ijo\xbc:M\xb9\xe3\x85i\xc2\xddP9\x94\xed@6\x9c\x0fv\xf2\xe5s\xb4s\xde|T\xbd\xfd\x9d:\xd7_\x80\xcb5e\x9d\xea\x9b\xfbo\xb1;YP\xc9\u775c\xcf\xe7\xfa\xab\xdeL\xf28\x9f\xbf\xf9\xbc\xf5\xf1\x8cJ\xb3Nl\f\x83\xd8n\x1e\xf5O\xa8]\x96\x87\xca\xc3\xf2M\xd3\xf1j\x9a\x97\x9bG\xbe\u068f\xbdm\xdd\x1am\xe7]\\\u00ed|6\x80\u067ct~m\xd8x`\xecZI\v\x82>\x82\xbe\x91\xf4\xf3\xfd\x04-\x0e$p\xd1\xde\xdbp\xbam\xfd\x18\x0e\xb5\xbd\xf1\xbe\u02cc\x93;r\x83`\xe8,\x8f\x1b\u05ec?\x9d`\xdf=f\xe5z\x1f\x8c*\xbff\xb0\x17\x1c\xf4\xbc\tp\xe6[`\xdf9&\xe2;\xa67l\\n/Q\xf2\xec\xc4\xedz\xc9\xf8\x94is\xf8\xa2\xcb_m\x03\u07eb\xb5aA\xf0{\x00\x00\x00\xff\xff\xf8\xf7_\xa3\xbd\x14\x00\x00") +// Data size: 1709 bytes. +var cuegenInstanceData = []byte("\x01\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xacX_\x8f\u0736\x11\x97\xce.P\x11i\xdf\xf2X`,\x03Azpu\u0203\x11c\x81\x83\xe1\xc4v\u15e6(\u04a7 8p\xa5\xd1.\x1b\x89TI*\xb9Cn\x1f\u06a6i\xbfQ\xbfF?Q\xae\x18\x92\x12%\xad\xee\xeck|/\xb7;?\xcep\xe6G\xce\x1f\xee\xafn\xfeu\x92\x9e\xdc\xfc;Io\xfe\x9e$\x9f\xde\xfc\xedA\x9a~ \xa4\xb1\\\x96\xf8\x92[N\xf2\xf4A\xfa\xf0OJ\xd9\xf4$I\x1f\xfe\x91\xdb}\xfaA\x92\xfe\xe2\xb5h\u04247?&I\xf2\x9b\x9b\u007f\x9e\xa4\u9bff\xfa\xba\ucc68E\x134\u007fL\u049b\x1f\x92\xe4\xe3\x9b\u007f\xfc\x03o\x91\f=tB\x96$\xc9O\x1f\xfe\x97y\v\xeb\x94\u0491\xf3\x03\xcbT\xdf\xd9\xe1\xe2x\xaf\x9e=}\xffn={z_\xbf\xf0[*\x06\xff\xffu\xbe\xf8\xec\xc5\xfb\x0f\xe3\xb3\x17o\t\xa3\x16\x94\xf9\xd38*\xac\u007fV\x18O?\xfd\xfc\xd9{OMg\xf5\x9e\xf99\xb4\xbbWC\x9aB\xcb;\xe3;KL]\xaae\xa16z\xa8\xd3T\x13\xad\xa0R\xb8\xc8\xf0<\x9f\xb6\xdc\v\x96\xe54)\x8cBj\xbe$`\xb1\x10D9\t\x06\xa0\t\xc8\b4\x844UT\x9a#\xf2V$\x14\x8fh\x8d\x04l,\x11+\x80\xbd\xb4s\xc0\xe2\xa5%`\xa7bt\x0e\xd8)\x12wZY5\xf5\xd7\t\x9c%\xbc\xb4\x03:Z\x9a\xa3\u06c9\xcf\x11e\x19\xf5\x97/^~\xb1\x01\n\xc4\xe0_\x9f8Q^\f\n\xa3\xd2V\xc8n\vgg\xb0\x15\x92\xeb\xabn;\xce\r\u00f4\x04BV\xa2\xf4-\xca\x1f \xdd\x06n]\x9f\xd3\xd8i4(iv\x01NG\xbb\u04fc-\xd88km\xe0\xd1y\x9e{\x93\x12\xe6S\x16ThQ\xb7\x93\xa1\xa4Dm\xb9\x90\x83\x1d0{\xd57\x15\xb5\xc2\xd9hrv\x06\xaf\x95\x86a\x9e}\x02\xaeV\xb4\xfcj\xb1\x128\xb5eSj\xb1\xf5\xfe\xf9\x1b\xfc\x04\xbe\u06cbr\x0f\xc2\x1alj\xd7F\xb9$\xd5R\xc9oQ[\xdf\u007f9|\xfe\xe7WA\xa3`\x8b\x01q\x9c\xf9\xdcX8\xbd\xb4A^\xbb\xf9t6?\x0es\xd8bj\xcbk\xa5\xfcm\xf6S\xa7\xd7\xca\xfd\xc6y8\x0e:+\x9f]\xa5j[\x9a\xd5\x1a!\u044b\xad:\xce+\x02\\Fy3>\x99\xbd\xf5\xd12\xa5\xf0N\xf3n?C\x9d\u0103\x15\xdf\u0360\x8a\xef\x06\xc0\xf2\x05b\x83AW/\xbeg\xd3j\u6299\x03)\xca#4\x84\x1e\xe0f\x15o\xfc\x02J\xb1#\xdce\xa8\x83\xdd\xe5?\xc2}\x06\xb9\x05c\x86\x1c-\x8a\xa9F\v]\xb2t[\x1a\x8f\xdd\u060e\xc2\xeeQ\x13\xd1C.\x84t\x81\xc1\xc4\x13P3\x9ce\xddv\x03\xa7\xf3]\xfc_>dZ\u038e\x87\x8b\x9c\xf6\x87kXS|t~\xb7\xaa\x13\x87(W\x03\xcc\xc7\x03s~\xc4C\xdb\x1d\x11\x12\\\xa5\xa7\xc1mnf\xe3\x1d\u02f2\x86\xbbMvD_\xe8r\xa4\xfa^\xac\x0e\x8f\xab`\x97\x86/\x8f\x1f\xa9\xbb\xb9le\xc3\xd9\xcc\x15\xee\xd94/\x8e\f\xc5\x05\xefbNu(y'n\xb1\x15\xd0w0\xe43\u0775\xda\xf1\xad\x16Z.\x95Z\xde4\x1e,\xe0\x8d\x85J\xa1\x01\xa9,\bY6}\x85\xfe\xa9\xa8t\vo^\x16\u032ds\x0e\xb9\x87*=\xc9\xcf\xc7\xd7\xeaX\x89\x9c\xf7\xd4r/\xd6\xea\x04\x8c^\x06*\xe0\x1ar7\u0378OC\x9dX\xbc\xa1\x96\x03\xd3\xfc%\xb6\x9cB\xe6\xef\xbe%:\u007f\x01~<\x83\u007f\v\x1f-%,[\xbc\x0f\x97\xf6\xe6/\xc5%:\u007f\x1f.\xd0\x03Ul9\u031f\xd3q\u822f\xc0\xd1\xd1~\xebQE\xfbG\xa58\x1e\x80\xe7\x9aX\xa7\x12\xec\xff\xbb\xdc]\xbc\xc7\xc9\xe7#\xce\u05f9\xbe\u04db\x05\x8f\xeb\xfc\xad\xf3\x16\xe3\x99u\x0fS\xb8\x18&\xb1=:\x8fWh\xf8m`\xaa<\xed0\xf4\x18\xd8-yyt\x1e\x1a\xd2\xdc\xdb\xc1\xad\u064f\x11c\\\xd3\x1f!V\x03X\xe5e\xf4\xeb\xc0\xe6\xf3\xf1\xd8\xed\x86$\x88\x11\xc4^\x17\x9f3\x8bl\xf1I\x02\xd7\u00f9M\x87\xf9\xc1\x8f\xe9\f\x1f\x8d\xc7F8'w\xe6\x06\xa5\xa1\xb7<\ufb6b\xfe\x8c\vc\xf7X]\x17}\xb0\xaa\xbd\xcb`\\8\u9e0b\xc4y\xa7.=\xb3~K\u02de\xd0\x1a\xf7\x1d\x9a\xe5\xddf\xa6-u\xcdJ\xecc\v\xe7\x8f\x02=\xb0y\xf1\xbfG\x01vo\x1d\xdf\xd9\xe6\xbb,[\u056d\x04\xde\u0654\xdeYk\x95\xac\xe5\x159\xb0$\xf9_\x00\x00\x00\xff\xff\x13*\xa9\xaf`\x16\x00\x00")