cmd/cue/cmd: support binary file type

- add special binary import mode
- allow specifying custom extensions for import
- encoder/decoder for binary

Note that there are no default file extensions for binary.

Change-Id: Ieeb90edc38b47a05e25e736479730e857345d853
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9570
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go
index 7caf830..1840f97 100644
--- a/cmd/cue/cmd/common.go
+++ b/cmd/cue/cmd/common.go
@@ -19,6 +19,7 @@
 	"io"
 	"os"
 	"path/filepath"
+	"regexp"
 	"strings"
 
 	"golang.org/x/text/language"
@@ -357,8 +358,12 @@
 	outMode filetypes.Mode
 
 	fileFilter     string
+	reFile         *regexp.Regexp
+	encoding       build.Encoding
 	interpretation build.Interpretation
 
+	overrideDefault bool
+
 	noMerge bool // do not merge individual data files.
 
 	loadCfg *load.Config
@@ -378,12 +383,21 @@
 	if err := p.parseFlags(); err != nil {
 		return nil, err
 	}
+	re, err := regexp.Compile(p.cfg.fileFilter)
+	if err != nil {
+		return nil, err
+	}
+	cfg.reFile = re
 
 	cfg.loadCfg.Tags = flagInject.StringArray(cmd)
 
 	return p, nil
 }
 
+func (p *buildPlan) matchFile(file string) bool {
+	return p.cfg.reFile.MatchString(file)
+}
+
 type decoderInfo struct {
 	file *build.File
 	d    *encoding.Decoder // may be nil if delayed
@@ -407,9 +421,21 @@
 // returned slices. It is up to the caller to Close any of the decoders that are
 // returned.
 func (p *buildPlan) getDecoders(b *build.Instance) (schemas, values []*decoderInfo, err error) {
-	for _, f := range b.OrphanedFiles {
+	files := b.OrphanedFiles
+	if p.cfg.overrideDefault {
+		files = append(files, b.UnknownFiles...)
+	}
+	for _, f := range files {
+		if !p.matchFile(f.Filename) && f.Filename != "-" {
+			continue
+		}
+		if p.cfg.overrideDefault {
+			f.Encoding = p.cfg.encoding
+			f.Interpretation = p.cfg.interpretation
+		}
 		switch f.Encoding {
-		case build.Protobuf, build.YAML, build.JSON, build.JSONL, build.Text:
+		case build.Protobuf, build.YAML, build.JSON, build.JSONL,
+			build.Text, build.Binary:
 			if f.Interpretation == build.ProtobufJSON {
 				// Need a schema.
 				values = append(values, &decoderInfo{f, nil})
diff --git a/cmd/cue/cmd/flags.go b/cmd/cue/cmd/flags.go
index f0ab776..edfa8dd 100644
--- a/cmd/cue/cmd/flags.go
+++ b/cmd/cue/cmd/flags.go
@@ -44,6 +44,7 @@
 	flagFiles       flagName = "files"
 	flagProtoPath   flagName = "proto_path"
 	flagProtoEnum   flagName = "proto_enum"
+	flagExt         flagName = "ext"
 	flagWithContext flagName = "with-context"
 	flagOut         flagName = "out"
 	flagOutFile     flagName = "outfile"
diff --git a/cmd/cue/cmd/help.go b/cmd/cue/cmd/help.go
index a34742c..aadbca6 100644
--- a/cmd/cue/cmd/help.go
+++ b/cmd/cue/cmd/help.go
@@ -189,8 +189,10 @@
     textproto    .textproto     Text-based protocol buffers.
     proto        .proto         Protocol Buffer definitions.
     go           .go            Go source files.
-    text         .txt           Raw text file; the evaluated
-                                value must be of type string.
+    text         .txt           Raw text file; the evaluated value
+                                must be of type string.
+    binary                      Raw binary file; the evaluated value
+                                must be of type string or bytes.
 
 OpenAPI, JSON Schema and Protocol Buffer definitions are
 always interpreted as schema. YAML and JSON are always
diff --git a/cmd/cue/cmd/import.go b/cmd/cue/cmd/import.go
index c57c3c0..15f2432 100644
--- a/cmd/cue/cmd/import.go
+++ b/cmd/cue/cmd/import.go
@@ -55,6 +55,8 @@
    json       Look for JSON files (.json, .jsonl, .ldjson).
    yaml       Look for YAML files (.yaml .yml).
    text       Look for text files (.txt).
+   binary     Look for files with extensions specified by --ext
+              and interpret them as binary.
    jsonschema Interpret JSON, YAML or CUE files as JSON Schema.
    openapi    Interpret JSON, YAML or CUE files as OpenAPI.
    auto       Look for JSON or YAML files and interpret them as
@@ -65,7 +67,9 @@
    proto      Convert Protocol buffer definition files and
               transitive dependencies.
 
-For user-specified files the modes only affect the
+Using the --ext flag in combination with a mode causes matched files to be
+interpreted as the format indicated by the mode, overriding any other meaning
+attributed to that extension.
 
 auto mode
 
@@ -101,6 +105,11 @@
 The module root is implicitly added as an import path.
 
 
+Binary mode
+
+Loads matched files as binary.
+
+
 JSON/YAML mode
 
 The -f option allows overwriting of existing files. This only
@@ -249,6 +258,7 @@
 	cmd.Flags().Bool(string(flagFiles), false, "split multiple entries into different files")
 	cmd.Flags().Bool(string(flagDryrun), false, "only run simulation")
 	cmd.Flags().BoolP(string(flagRecursive), "R", false, "recursively parse string values")
+	cmd.Flags().StringArray(string(flagExt), nil, "match files with these extensions")
 
 	return cmd
 }
@@ -261,11 +271,18 @@
 		interpretation: build.Auto,
 		loadCfg:        &load.Config{DataFiles: true},
 	}
+
 	var mode string
+	extensions := flagExt.StringArray(cmd)
 	if len(args) >= 1 && !strings.ContainsAny(args[0], `/\:.`) {
 		c.interpretation = ""
+		if len(extensions) > 0 {
+			c.overrideDefault = true
+		}
+
 		mode = args[0]
 		args = args[1:]
+		c.encoding = build.Encoding(mode)
 		switch mode {
 		case "proto":
 			c.fileFilter = `\.proto$`
@@ -275,14 +292,24 @@
 			c.fileFilter = `\.(yaml|yml)$`
 		case "text":
 			c.fileFilter = `\.txt$`
+		case "binary":
+			if len(extensions) == 0 {
+				return errors.Newf(token.NoPos,
+					"use of --ext flag required in binary mode")
+			}
 		case "auto", "openapi", "jsonschema":
 			c.interpretation = build.Interpretation(mode)
+			c.encoding = "yaml"
 		case "data":
 			// default mode for encoding/ no interpretation.
+			c.encoding = ""
 		default:
 			return errors.Newf(token.NoPos, "unknown mode %q", mode)
 		}
 	}
+	if len(extensions) > 0 {
+		c.fileFilter = `\.(` + strings.Join(extensions, "|") + `)$`
+	}
 
 	b, err := parseArgs(cmd, args, c)
 	exitOnErr(cmd, err, true)
diff --git a/cmd/cue/cmd/orphans.go b/cmd/cue/cmd/orphans.go
index 13f7c62..810125c 100644
--- a/cmd/cue/cmd/orphans.go
+++ b/cmd/cue/cmd/orphans.go
@@ -17,7 +17,6 @@
 import (
 	"fmt"
 	"path/filepath"
-	"regexp"
 	"strconv"
 
 	"cuelang.org/go/cue"
@@ -89,13 +88,8 @@
 
 	var files []*ast.File
 
-	re, err := regexp.Compile(b.cfg.fileFilter)
-	if err != nil {
-		return err
-	}
-
 	for _, di := range a {
-		if !i.User && !re.MatchString(filepath.Base(di.file.Filename)) {
+		if !i.User && !b.matchFile(filepath.Base(di.file.Filename)) {
 			continue
 		}
 
diff --git a/cmd/cue/cmd/testdata/script/import_binary.txt b/cmd/cue/cmd/testdata/script/import_binary.txt
new file mode 100644
index 0000000..e22371d
--- /dev/null
+++ b/cmd/cue/cmd/testdata/script/import_binary.txt
@@ -0,0 +1,33 @@
+cue import binary --ext crt .
+cmp x.cue out/expect.cue
+
+cue export bin.cue --out binary
+cmp stdout out/bin
+
+# TODO: txtarscript should distinguish final newline
+cue export str.cue --out binary
+cmp stdout out/str
+
+-- x.crt --
+1234
+-- y.crt2 --
+// Skip this file, wrong extension.
+-- bin.cue --
+'''
+  foo
+
+  '''
+-- str.cue --
+"""
+  foo
+
+  """
+-- out/bin --
+foo
+-- out/str --
+foo
+-- out/expect.cue --
+'''
+	1234
+
+	'''
diff --git a/cue/build/file.go b/cue/build/file.go
index ecfdfb0..7a5d6d7 100644
--- a/cue/build/file.go
+++ b/cue/build/file.go
@@ -35,6 +35,7 @@
 	YAML        Encoding = "yaml"
 	JSONL       Encoding = "jsonl"
 	Text        Encoding = "text"
+	Binary      Encoding = "binary"
 	Protobuf    Encoding = "proto"
 	TextProto   Encoding = "textproto"
 	BinaryProto Encoding = "pb"
diff --git a/internal/encoding/encoder.go b/internal/encoding/encoder.go
index dacf6e7..4d9b0ba 100644
--- a/internal/encoding/encoder.go
+++ b/internal/encoding/encoder.go
@@ -219,6 +219,17 @@
 			return err
 		}
 
+	case build.Binary:
+		e.concrete = true
+		e.encValue = func(v cue.Value) error {
+			b, err := v.Bytes()
+			if err != nil {
+				return err
+			}
+			_, err = w.Write(b)
+			return err
+		}
+
 	default:
 		return nil, fmt.Errorf("unsupported encoding %q", f.Encoding)
 	}
diff --git a/internal/encoding/encoding.go b/internal/encoding/encoding.go
index 79e2fe5..522f023 100644
--- a/internal/encoding/encoding.go
+++ b/internal/encoding/encoding.go
@@ -31,6 +31,7 @@
 	"cuelang.org/go/cue/build"
 	"cuelang.org/go/cue/errors"
 	"cuelang.org/go/cue/format"
+	"cuelang.org/go/cue/literal"
 	"cuelang.org/go/cue/parser"
 	"cuelang.org/go/cue/token"
 	"cuelang.org/go/encoding/json"
@@ -251,6 +252,11 @@
 		b, err := ioutil.ReadAll(r)
 		i.err = err
 		i.expr = ast.NewString(string(b))
+	case build.Binary:
+		b, err := ioutil.ReadAll(r)
+		i.err = err
+		s := literal.Bytes.WithTabIndent(1).Quote(string(b))
+		i.expr = ast.NewLit(token.STRING, s)
 	case build.Protobuf:
 		paths := &protobuf.Config{
 			Paths:   cfg.ProtoPath,
diff --git a/internal/filetypes/types.cue b/internal/filetypes/types.cue
index 935deb3..6bc5d2b 100644
--- a/internal/filetypes/types.cue
+++ b/internal/filetypes/types.cue
@@ -201,6 +201,10 @@
 		encoding: "text"
 		form:     "data"
 	}
+	binary: {
+		encoding: "binary"
+		form:     "data"
+	}
 	go: {
 		encoding:       "code"
 		interpretation: ""
@@ -310,6 +314,11 @@
 	stream: false
 }
 
+encodings: binary: {
+	forms.data
+	stream: false
+}
+
 encodings: toml: {
 	forms.data
 	stream: false
diff --git a/internal/filetypes/types.go b/internal/filetypes/types.go
index 1bb1ac0..2093cd0 100644
--- a/internal/filetypes/types.go
+++ b/internal/filetypes/types.go
@@ -41,5 +41,5 @@
 	return v
 }
 
-// Data size: 1707 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?P\xbfF\xbfR\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^Bv\xbd\xf5\xf74\xde\x1a\xfa6\u024b\u04fc\xec\x91n\xcc\x05\u024b\xa2`Yv`Y\u05a0\x85K8\xf7\u02e7t,N-\x9b\xf1\xb2\x04\xc9\xd2\xe4\x0e]\xb2\xb8\xb5\t\xae\x94=\xddZJ5S\x98r\x8f-\x0f\u0390.^Z\x94\xc6_\t\xb7:/\xfeb\x94\xcc\u00f7E\x0eS4\xbc\xb7j\f\xe7\xe0U\xaex\xdb\xdcW\xe5~\x1a\a\xca\xfb\f/\xe9v\xbd\x95p\x17\xc1-\x8c_|\xb2\xc6y`\xf5t\x95\xf3%\xb8\xe4\xfc\u24f7\xb0N\xf9\x1c9?\xb0L\xf5\x9d\x1d.\x8e\xf7\xea\xd9\xd3\xf7\xef\u05b3\xa7\xf7\xf5\v\xbf\xa5J\xf0\xff_\xe7\x8b\xcf^\xbc\xff0>{\xf1\x960jAi?\x8d\xa3\xc2\xfag\x85\xf1\xf4\xd3\u03df\xbd\xf7\xd4tV\uf65fC\xaf{5\xa4)\xb4\xbc3\xbe\xad\xc4\u0525B\x16\n\xa3\x87:M\x05\xd1\n\xaa\x83\x8b\f\xcf\xf3i\xbf\xbd`YNc\xc2(\xa4\xceK\x02\x16\vA\x94\x93`\x00\x9a\x80\x8c@CHSE\xa59\"oEB\xf1\x88\xd6H\xc0\xc6\x12\xb1\x02\xd8K;\a,^Z\x02v*F\u701d\"q\xa7\x95US\u007f\x9d\xc0Y\xc2K;\xa0\xa3\xa59\xba\x9d\xf8\x1cQ\x96Qs\xf9\xe2\xe5\x17\x1b\xa0@\f\xfe\xf5\x89\x13\xe5\u01600*m\x85\xec\xb6pv\x06[!\xb9\xbe\xea\xb6\xe3\xd00\x8cJ d%J\u07df\xfc\x01\xd2m\xe0\xd659\x8d\x9dF\x83\x92\x06\x17\xe0t\xb4;\xcd\u06c2\x8d\x83\xd6\x06\x1e\x9d\xe7\xb97)a>bA\x85\x16u;\x99HJ\u0516\v9\xd8\x01\xb3W}SQ\x1f\x9c\xcd%gg\xf0Zi\x18\x86\xd9'\xe0jE\u02ef\x16+\x81SO6\xa5\x16[\uf7ff\xc1O\u0efd(\xf7 \xac\xc1\xa6v=\x94KR-\x95\xfc\x16\xb5\xf5\u0357\xc3\xe7\u007f~\x154\n\xb6\x98\x0e\u01c1\xcf\u0344\xd3K\x1b\xe4\xb5\x1bNg\xc3\xe30\x84-F\xb6\xbcV\xca\xdff?rz\xad\xdco\x9c\x87\u3833\xf2\xd9U\xaa\xb6\xa5A\xad\x11\x12\xbd\u062a\xe3\xbc\"\xc0e\x947\xe3\x93\xd9[\x1f-S\n\xef4\xef\xf63\xd4I<X\xf1\xdd\f\xaa\xf8n\x00,_ 6\x18t\xf5\xe2{6\xadf\xae\x989\x90\xa2<BC\xe8\x01nV\xf1\xc6/\xa0\x14;\xc2]\x86:\xd8]\xfe#\xdcg\x90[0f\xc8\u0462\x98j\xb4\xd0%K\xb7\xa5\xd9\xd8\xcd\xec(\xec\x1e5\x11=\xe4BH\x17\x18L<\x015\xc3Y\xd6m7p:\xdf\xc5\xff\xe5C\xa6\xe5\xecx\xb8\xc8i\u007f\xb8\x865\xc5G\xe7w\xab:q\x88r5\xc0|<0\xe7G<\xb4\xdd\x11!\xc1Uz\x17\xdc\xe6f6\u07b1,k\xb8\xdbdG\xf4\x85.G\xaa\xef\xc5\xea\xf0\xb2\nvi\xf8\xf2\xf8\x91\xba\x9b\xcbV6\x9c\xcd\\\xe1\x9eM\xf3\xe2\xc8P\\\xf0.\xe6T\x87\x92w\xe2\x16[\x01}\aC>\xd3]\xab\x1d\x1fj\xa1\xe5R\xa9\xe5M\xe3\xc1\x02\xdeX\xa8\x14\x1a\x90\u0282\x90e\xd3W\xe8\u07c9J\xb7\xf0\xe6e\xc1\xdc:\xe7\x90{\xa5\xd2{\xfc||\xaa\x8e\x95\xc8yO-\xf7b\xadN\xc0\xe8e\xa0\x02\xae!w\u04cc\xfb4\u0509\xc5\x03j90\u035fa\xcb)d\xfe\xe8[\xa2\xf3\xe7\xdf\xc73\xf8\xb7\xf0\xd1R\u00b2\xc5\xe3pio\xfeL\\\xa2\xf3\xc7\xe1\x02=P\u0156\xc3\xfc9\x1d\x87\x8e\xf8\n\x1c\x1d\xed\xb7\x1eU\xb4\u007fT\x8a\xe3\x01x\xae\x89u*\xc1\xfe\xbf\xcb\xdd\xc5c\x9c|>\xe2|\x9d\xeb;\xbdY\xf0\xb8\xce\xdf:o1\x9eY\xf70\x85\x8ba\x12\u06e3\xf3x\x85\x86\x1f\x06\xa6\xca\xd3\x0eC\x8f\x81\u0752\x97G\xe7\xa1!\u037d\x1d\u071a\xfd\x121\xc65\xfd\x05b5\x80U^F\xbf\x0el>\x1f\x8f\xddnH\x82\x18A\xecu\xf19\xb3\xc8\x16\x9f$p=\x9c\xdbt\x98\x1f\xfc\x98\xce\xf0\xd1xl\x84srgnP\x1az\xcb\xf3\u07ba\xea\u03f80v\x8f\xd5u\xd1\a\xab\u06bb\f\u0185\x93\x8e\xbbH\x9cw\xea\xd23\ubdf4\xec\t\xadq\u07e1Y\xdemf\xdaR\u05ec\xc4>\xb6p\xfe(\xd0\x03\x9b\x17\xff{\x14`\xf7\xd6\xf1\x9dm\xbe\u02f2U\xddJ\xe0\x9dM\u9775V\xc9Z^\x91\x03K\x92\xff\x05\x00\x00\xff\xff\xa6\xedNA]\x16\x00\x00")
+// Data size: 1713 bytes.
+var cuegenInstanceData = []byte("\x01\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xacX\u074f\u0736\x11\x97\xce.P\x11i\u07da\xb7\x02c\x19\b\u0483\xabE\x1e\x8c\x18\v\x1c\f'\xb6\v\xbf4E\x91>\x05\xc1\x81+\x8dv\xd9H\xa4JR\xc9\x1dr\xfb\xd06M\xfbW{\x8b!\xa9o\xdd\xd9\xd7\xfa^nw~\x9c\xe1\xccp>\xf7W\xa7\u007f\x9f\xc5g\xa7\xffD\xf1\xe9\x1fQ\xf4\xf9\xe9\xef\x0f\xe2\xf8#!\x8d\xe52\u01d7\xdcr\xa2\xc7\x0f\xe2\x87\u007fV\xca\xc6gQ\xfc\xf0O\xdc\x1e\u23e2\xf8\x17\xafE\x85&>\xfd\x1cE\xd1oO\xff:\x8b\xe3_\u007f\xf3m\xdebV\x8a*p\xfe\x1c\u0167\x9f\xa2\xe8\xd3\xd3?\x1f\xc4\xf1/\a\xfaOQ|\x16?\xfc#\xaf\x91\x04=tD\x16E\xd1\u06cf3\xd2$\x8e\xcf\xe28\xb1\xd7\r\x9a,o1~\xfb\xf1o\x1a\x9e\u007f\xc7\xf7\b\xbbVT\x05c\x9b\r\xbc\x00\xba\x1fr\xa55\x9aF\xc9\u0080U\xc0\xe1\x0f\xca\x1f\xca\b\xce\xd8c\xfa\xb7\x85\x1fYB\xd7K^\xe3\x16\u009f\xb1Z\xc8=KP\xe6\xaa\x10r\xdf\x03\x8f_\x05\nK\x84\xb4\xa8\x1b\x8d\x96[\xa1\xe4\xf3-<~3\xa1\xb0\xa4T\xba~\u07b3\x12\xf7k\xa5k\x96X\xbe7\xcf\xdd\xc5\xc97\xfe\xa6o\xb7\xfd\x95GvtF\xbc\u0112\xb7\x95\x05a\xc0\x1e\x10HEh\r\x16P*\r\xc6\x16B\x02\x97\x05}R\xad\xcd\xe0\xeb\x03\x82Ak\x85\xdc\x1b(\xb0AY\x90\x14%\a\xeeZ\x15du\x10\xbc\x05g?|2u\xc0y\xfa\xfb\x14n:m\x8e#\u007f\xbe\x91\xa5\x82\x02K!\xd1\xc0A\xfd\x00\u070b\x15\x06\x9c\x9b\xb0p\n\xf5n\xc1\"\xb8\x98\x18\x9d\xb5\xee\x1bK\nn\xf9\xe0\x95s\xab[\x84\x1b(ye\x90%\x1aK\xd4(s4\xdb%\x98_\xe7\x95\aV8\x9dj\x82<O'vJU,Q\r}\xe7\x95g\xf1\xb4\\Ic5\x17\xd2\x0e\xe7\xbeCl\x82_\xcc6\u0404\xccU\xddTh]X\x04Z\xdd(m;\r<\xcdX\x8d\xbc\xee\x94\xf2\xb4B\xe5f0\xd1\u04f8\xb5Z\xecZ\xeb\rp4\xef^z\x17C\x8fG\x0f\xe7up\x8f\\\x88\xd2\xf9\u0082jPso\x89?\x9d\xb1\u0346X\xbf>\xa0A\xb0X7\x15\xb7h\x80kt\x0f \xe95\xac\x82\x1dB+E)\x90\xde\x05\xb8u\xc1\xa0\x95\xb2\xa0J\xb0\aaHH\xaed)\xf6\xad\xbf!c\xee\x02\xf7^B6\xad\xf5q:D\r}\x1b\xe5\xc5y\x9a\xb7H\x11sI\xf4,\xcbX\x92\x1cY\x92Th\xe1\n.\xfc\xf1\xb1;f\xaf\x96L\xfc2\aI\xd2(\x86\xae\xd8p\xb5\t\xaa\xe4-E-\xa5\x9a\xc9L~\xc0\x9a\ae\x88\x17\xaf,J\xe3C\u009dN\xb3\xbf\x1a%\xd3\xf0m\x96\xc3d\ro\xad\xea\xcd9z\x96k^W\xf7e\xb9\x1f\u01d1\xf2>\xc1+\x8a\xaew:\xdcYp\x8b\xc7/?[\xf3y\xf0\xea\xf9\xaa\xcf\xe7\xe0\xdc\u75df\xbd\xc3\xeb\x94\u03c3\u03cf,Qmc\xbb\xc0\xf1Z={\xfa\xe1\xd5z\xf6\xf4\xbez\xe1\xf7T\t\xfe\xf7p\xbe\xfc\xe2\u01477\xe3\x8b\x17\xef0\xa3\x14\x94\xf6c;\n,\xff/3\x9e~\xfe\xe5\xb3\x0f\x9e\x9aN\xea=\xf3\xb3\xebu\xaf\xba4\x85\x9a7\u01b7\x95!u\xa9\x90\x85\xc2\xe8\xa1FSA\xb4\x82\xea\xe0,\xc3\xd3t\xdco/Y\x92\u0498\xd0\x13\xa9\xf3\x12\x81\r\x85`\xa0\x13\xa1\x03\xaa\x80\xf4@EHU\fLSD\u078a\x84\xe21H#\x02\xebK\xc4\n`\xaf\xec\x14\xb0xe\t\u062b\xc1:\a\xec\x15\x91\x1b\xad\xac\x1a\xeb\xeb\bN\x12^\xd9\x0e\xed%M\xd1\xddH\xe7\x01e\t5\x97\xaf^~\xb5\x052\xc4\xe0\u07de8R\x9au\f=\xd3N\xc8f\a\x9b\r\xec\x84\xe4\xfa\xba\xd9\xf5CC7*\x81\x90\x85\xc8}\u007f\xf2\x0fH\xd1\xc0\xadkr\x1a\x1b\x8d\x06%\r.\xc0\xe9i\xf7\x9a\xd7\x19\xeb\a\xad-<\xbaHS/R\xc2t\u0102\x02-\xeaz4\x91\xe4\xa8-\x17\xb2\x93\x03\xe6\xa0\u06aa\xa0>8\x99K6\x1bx\xad4t\xc3\xec\x13p\xb5\xa2\xe6\u05f3\x93\xc0\xa9'\x9b\\\x8b\x9d\xd7\xcfG\xf0\x13\xf8\xe1 \xf2\x03\bk\xb0*]\x0f\xe5\x92Xs%\xbfGm}\xf3\xe5\xf0\xe5_^\x05\x8e\x8c\u0366\xc3~\xe0s3\xe18h\x03\xbdt\xc3\xe9dx\uc1b0\xd9\u0216\x96J\xf9h\xf6#\xa7\xe7J\xfd\xc5ix\x0ez+\x9f]\xb9\xaak\x1a\xd4*!\u0453\xadZ\xe6\x15\x01.\xa3\xbc\x18\x9f\xcc^z/\x99Rx\xafys\x98\xa0\x8e\xe2\xc1\x82\xef'P\xc1\xf7\x1d`\xf9\f\xb1A\xa0\xab\x17?\xb2q5s\xc5\u0301d\xe5\x02\r\xa6\a\xb8Z\xc5+\u007f\x80Rl\x81\xbb\fu\xb0\v\xfe\x05\xee3\xc8\x1d\xe83dqhH5:\u84a5\xd9\xd1l\xecfv\x14\xf6\x80\x9a\x1c\xdd\xe5BH\x17\xe8D<\x015\xc1Y\xd2\xec\xb6p>\xbd\xc5\xff\xa5]\xa6\xa5l9\\\xa4t?\xdc\xc0\x1a\u38cb\xbbY\x1d9X\xb9j`\xda?\x98\xd3cx4/v\xc1\xe3\u0277r\xed\x17n\f\x06\xd26q\x9bqI\x1f\x99IRqw\u035e\x9c\x1ez#\xb1~\x10\xa9\xdd>\x16\xe4\xd2\xc8\xe6\xf1\x05\xbb\x9b\xe6V.\x9cLj!:\xc7\u0674\x104\x1cx\x1fq\xaaA\xc9\x1bq\x8b\xac\x80\xbe\x87 _\x1f\\\x83\xee\u05fb\u0428\xa9@\xf3\xaa\xf2`\x06o,\x14\n\rHeA\u023cj\v\xf4\u06e5\xd25\xbcy\x991w\xce)\xe4v[\xda\xe2/\xfa\x05\xb7\xaf_N{j\u0517k\xd5\x05z-\x83+\xe0\x06R7\x03\xb9O]u\x99\xad]\xf31k\xba\xbc\xcdg\x97\xe9\xaa8G\xa7K\xe3\xa7\x13\xf8w\xf0\u025c\u0092\xd9J9\x977].\xe7\xe8t\xa5\x9c\xa1G\xaa\xf3\xb2\x9bZ\xc7C\xd4\xc2_\xc1G\x8b\xfb\u05ad\x1a\xe4/\n\xf8\xf0\x00\xde\xd7\xe4u*\xdc\xfe\xbf\xcb\xdd\xd9\nO:/|\xbe\xee\xeb;\xb5\x99\xf9q\xdd\u007f\xeb~\x1b\xec\x99\xf4\x1c\x939\x1bF\xb6=\xba\x18B\xa8\xfb9a\xcc<\xeeK\xb4B\xec\xe7~yt\x11\xda\xd8T\xdbN\xad\xc9\xef\x17\xbd]\xe3\xdf-V\rX\xf5K\xaf\u05d1M\xa7\xea\xbeGvI0X0t\xc8a\t\x9ae\x8bO\x12\xb8\xe9\xdem\xbc\x02tz\x8c'\xffA\xf8\xd0>\xa7\u039d\xa8Ai\xe8%O;\xf2\xaa>\xfd\xc1\xa1\u7b1e\x1bt\x18\xb7\x9aw\x1c\xb5\xaa\xbe\xeb\xee\xe1\u0a25\xcfr\xec\xbd\u0180\x89\xf4[f\x82\xd1\v\xccm\xa1F\u007f\x97\x98q\xcf^\x932\xb4\xbc\x99\xf2\vC\x8fl\xda'\xeeQ\xab\xdd2\xe5\x9b\xe0\xf4\x96yW\xbb\u0541w\xf6\xaf\xf7\xe6Zu\xd6<\x9a\x8e,\x8a\xfe\x1b\x00\x00\xff\xff\x8e\xf7,\xe9\xbe\x16\x00\x00")