cmd/cue/cmd: hook up protobuf encodings types

Closes #606

Change-Id: I712ed6f9fc37d53b633a44ed87e4c71c1e018b0f
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9372
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go
index 39ec623..d6deeec 100644
--- a/cmd/cue/cmd/common.go
+++ b/cmd/cue/cmd/common.go
@@ -296,7 +296,7 @@
 	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 @@
 	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 @@
 		}
 
 		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 67ec139..a34742c 100644
--- a/cmd/cue/cmd/help.go
+++ b/cmd/cue/cmd/help.go
@@ -185,9 +185,11 @@
     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 @@
 // - id=<url>
 
 // TODO: filetypes:
-// - textpb
 // - binpb
 
 // TODO: cue.mod help topic
diff --git a/cmd/cue/cmd/orphans.go b/cmd/cue/cmd/orphans.go
index e35dbb4..13f7c62 100644
--- a/cmd/cue/cmd/orphans.go
+++ b/cmd/cue/cmd/orphans.go
@@ -27,6 +27,7 @@
 	"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 @@
 		expr := internal.ToExpr(file)
 		p, _, _ := internal.PackageInfo(file)
 
+		var path cue.Path
 		var labels []ast.Label
 
 		switch {
@@ -227,6 +229,22 @@
 				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 0000000..ec041bb
--- /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 0000000..e1549b1
--- /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 2aef149..ecfdfb0 100644
--- a/cue/build/file.go
+++ b/cue/build/file.go
@@ -30,17 +30,17 @@
 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 @@
 	// 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 40db53f..dacf6e7 100644
--- a/internal/encoding/encoder.go
+++ b/internal/encoding/encoder.go
@@ -30,6 +30,8 @@
 	"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 @@
 			}
 			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 @@
 			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 67ad181..fada360 100644
--- a/internal/encoding/encoding.go
+++ b/internal/encoding/encoding.go
@@ -37,6 +37,8 @@
 	"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 @@
 	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 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) 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 @@
 	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 @@
 			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 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 07521db..935deb3 100644
--- a/internal/filetypes/types.cue
+++ b/internal/filetypes/types.cue
@@ -139,20 +139,22 @@
 
 // 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 @@
 
 	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 @@
 	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 @@
 	forms.schema
 	encoding: *"json" | _
 }
+
+interpretations: pb: {
+	forms.data
+	stream: true
+}
diff --git a/internal/filetypes/types.go b/internal/filetypes/types.go
index 41f7aba..b2948ea 100644
--- a/internal/filetypes/types.go
+++ b/internal/filetypes/types.go
@@ -41,5 +41,5 @@
 	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<H\xd3_F\xf9\x0fIz\x92>\xfc\x03o\x91\f=tB\x96$\xc9O\x1f\xfe\x97<I\u04d34\xcd\xecU\x87\xa6({L\u007f\xfa\xf0?\x1d/\xbf\xe1;\x84m/\x9a\x8a\xb1\xb33x\x01\xb4?\x94Jk4\x9d\x92\x95\x01\xab\x80\xc3\xef\x95_T\x10\\\xb0\xc7\xf4o\x03\u07f3\x8c\xb6\x97\xbc\xc5\r\x84?c\xb5\x90;\x96\xa1,U%\xe4n\x04\x1e\xbf\n\x12\x96\tiQw\x1a-\xb7B\xc9\xe7\x1bx\xfcf&aY\xadt\xfb|T%\xed\xd7J\xb7,\xb3|g\x9e\xbb\x8d\xb3\xaf\xfcN_o\xc6-\x0f\xec\xe0\x82x\x895\xef\x1b\v\u0080\xdd#\x90\x8b\xd0\x1b\xac\xa0V\x1a\x8c\xad\x84\x04.+\xfa\xa4z[\xc0\x97{\x04\x83\xd6\n\xb93Pa\x87\xb2\"+JF\xedVU\x14u0\xbc\x01\x17?|4'\xe04\xff]\x0e\u05c37\x87\t\x9fod\xad\xa0\xc2ZH4\xb0W\xdf\x01\xf7f\x85\x01G\x13V\u03a1\x91\x16\xac\x02\u0164\xe8\xa2u\xdfXVq\xcb#+\xa7V\xf7\b\xd7P\xf3\xc6 \xcb4\u05a8Q\x96h6\xc7`yU6\x1eX\xd1t\xae\tb\x9eVl\x95jX\xa6:\xfa\xce\x1b\xaf\xe2e\xa5\x92\xc6j.\xa4\x8d\xeb\xbeA\xec\x02/f\x13dB\x96\xaa\xed\x1a\xb4\xeeZ\x04Y\xdb)m\a\x0f\xbc\xccX\x8d\xbc\x1d\x9c\xf2\xb2J\x95&\x86\xe8e\xdcZ-\xb6\xbd\xf5\x018\x99\xa7\x97\xce\xc5\xd0\xe1\xd1\xc1y\x1f\xdc!W\xa2v\\XP\x1dj\xee#\xf1\xab\vvvF\xaa_\xee\xd1 Xl\xbb\x86[4\xc05\xba\x03\x90t\x1aV\xc1\x16\xa1\x97\xa2\x16H\xe7\x02\u073a\u02e0\x95\xb2\xa0j\xb0{a\xc8H\xa9d-v\xbd\u07e1`n\x03w^\x17DB\xd7[\u007fU\xe3\u0161o\x93\xd48\xcd\xcb\x1e\xe9\xd2\\\x90\xbc(\n\x96e\a\x96e\rZ\xb8\x84s\xbf|\xca\xc8\xe2\xe0\xb2\x195K\x90,M\xae\xd1%\x8b[\x9b\xe0J\xd9\xd3\u0165l3\x85)\xf7\xd8\xf2\xe0\f\xe9\xe2\xa5Ei\xfc\xadp\xab\xf3\xe2/F\xc9<|[\xa41E\xc3{\xab\xc6p\x0e^\u52b7\xcd}U\xee\xa7q\xa0\xd4\xcf\xf0\x92.\xd8[\tw\x11\xdc\xc2\xf8\xc5'k\x9c\aVOW9_\x82K\xce/>y\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")