added yamlv3 (#457)
authorHrishikesh Barman <geekodour@users.noreply.github.com>
Wed, 10 Apr 2019 16:17:39 +0000 (21:47 +0530)
committerBrian Brazil <brian.brazil@robustperception.io>
Wed, 10 Apr 2019 16:17:39 +0000 (17:17 +0100)
* added yamlv3
* removed unused packages

Signed-off-by: geekodour <hrishikeshbman@gmail.com>
25 files changed:
config/config.go
config/config_test.go
go.mod
go.sum
main.go
vendor/gopkg.in/yaml.v2/encode.go
vendor/gopkg.in/yaml.v3/.travis.yml [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/LICENSE [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/NOTICE [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/README.md [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/apic.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/decode.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/emitterc.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/encode.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/go.mod [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/parserc.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/readerc.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/resolve.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/scannerc.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/sorter.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/writerc.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/yaml.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/yamlh.go [new file with mode: 0644]
vendor/gopkg.in/yaml.v3/yamlprivateh.go [new file with mode: 0644]
vendor/modules.txt

index 728a9a69f885beefea5650cdd1db5e645da6f8c6..5c06eec959d8f84d0a7a52cdb5ceb787cacfa317 100644 (file)
@@ -16,12 +16,12 @@ package config
 import (
        "errors"
        "fmt"
-       "io/ioutil"
+       "os"
        "runtime"
        "sync"
        "time"
 
-       yaml "gopkg.in/yaml.v2"
+       yaml "gopkg.in/yaml.v3"
 
        "github.com/prometheus/client_golang/prometheus"
        "github.com/prometheus/common/config"
@@ -94,12 +94,14 @@ func (sc *SafeConfig) ReloadConfig(confFile string) (err error) {
                }
        }()
 
-       yamlFile, err := ioutil.ReadFile(confFile)
+       yamlReader, err := os.Open(confFile)
        if err != nil {
                return fmt.Errorf("error reading config file: %s", err)
        }
+       decoder := yaml.NewDecoder(yamlReader)
+       decoder.KnownFields(true)
 
-       if err := yaml.UnmarshalStrict(yamlFile, c); err != nil {
+       if err = decoder.Decode(c); err != nil {
                return fmt.Errorf("error parsing config file: %s", err)
        }
 
index 5f150fe107b46fc010ffee4fd5f999e60228ad3d..4fc45298ffc54f82849438d7757a2d5d9c69a8ed 100644 (file)
@@ -17,7 +17,7 @@ import (
        "strings"
        "testing"
 
-       yaml "gopkg.in/yaml.v2"
+       yaml "gopkg.in/yaml.v3"
 )
 
 func TestLoadConfig(t *testing.T) {
diff --git a/go.mod b/go.mod
index aff37916660e03bdfdf131838debc39159e286f1..23ef3fddaa512abee68f799ec3ba5c7d153acd03 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -30,5 +30,6 @@ require (
        golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect
        golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b // indirect
        gopkg.in/alecthomas/kingpin.v2 v2.2.5
-       gopkg.in/yaml.v2 v2.2.1
+       gopkg.in/yaml.v2 v2.2.2 // indirect
+       gopkg.in/yaml.v3 v3.0.0-20190405144635-389beb8b7082
 )
diff --git a/go.sum b/go.sum
index 032fc01e393ac5d7954bdca43297e344a7616f91..c57d797abf847ea90db932a82746e68d771028a5 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -58,5 +58,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.5 h1:qskSCq465uEvC3oGocwvZNsO3RF3SpLVLumOAhL
 gopkg.in/alecthomas/kingpin.v2 v2.2.5/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20190405144635-389beb8b7082 h1:vNUppUUdBItwKdEibnFCxOCjAaAq9buDhqCE29m62s8=
+gopkg.in/yaml.v3 v3.0.0-20190405144635-389beb8b7082/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/main.go b/main.go
index c9023db85c273d98b6bdcd6331e386ca260b68bb..b70e751c90d0ae4c07c3051c393b4b709c6363e0 100644 (file)
--- a/main.go
+++ b/main.go
@@ -35,7 +35,7 @@ import (
        "github.com/prometheus/common/promlog/flag"
        "github.com/prometheus/common/version"
        "gopkg.in/alecthomas/kingpin.v2"
-       "gopkg.in/yaml.v2"
+       "gopkg.in/yaml.v3"
 
        "github.com/prometheus/blackbox_exporter/config"
        "github.com/prometheus/blackbox_exporter/prober"
index a14435e82f84fb34158b2687793d4974aaaf1080..0ee738e11b6738a901b552764e2ed0ef5bba7913 100644 (file)
@@ -13,6 +13,19 @@ import (
        "unicode/utf8"
 )
 
+// jsonNumber is the interface of the encoding/json.Number datatype.
+// Repeating the interface here avoids a dependency on encoding/json, and also
+// supports other libraries like jsoniter, which use a similar datatype with
+// the same interface. Detecting this interface is useful when dealing with
+// structures containing json.Number, which is a string under the hood. The
+// encoder should prefer the use of Int64(), Float64() and string(), in that
+// order, when encoding this type.
+type jsonNumber interface {
+       Float64() (float64, error)
+       Int64() (int64, error)
+       String() string
+}
+
 type encoder struct {
        emitter yaml_emitter_t
        event   yaml_event_t
@@ -89,6 +102,21 @@ func (e *encoder) marshal(tag string, in reflect.Value) {
        }
        iface := in.Interface()
        switch m := iface.(type) {
+       case jsonNumber:
+               integer, err := m.Int64()
+               if err == nil {
+                       // In this case the json.Number is a valid int64
+                       in = reflect.ValueOf(integer)
+                       break
+               }
+               float, err := m.Float64()
+               if err == nil {
+                       // In this case the json.Number is a valid float64
+                       in = reflect.ValueOf(float)
+                       break
+               }
+               // fallback case - no number could be obtained
+               in = reflect.ValueOf(m.String())
        case time.Time, *time.Time:
                // Although time.Time implements TextMarshaler,
                // we don't want to treat it as a string for YAML
diff --git a/vendor/gopkg.in/yaml.v3/.travis.yml b/vendor/gopkg.in/yaml.v3/.travis.yml
new file mode 100644 (file)
index 0000000..fc88f9b
--- /dev/null
@@ -0,0 +1,15 @@
+language: go
+
+go:
+    - "1.4"
+    - "1.5"
+    - "1.6"
+    - "1.7"
+    - "1.8"
+    - "1.9"
+    - "1.10"
+    - "1.11"
+    - "1.12"
+    - tip
+
+go_import_path: gopkg.in/yaml.v2
diff --git a/vendor/gopkg.in/yaml.v3/LICENSE b/vendor/gopkg.in/yaml.v3/LICENSE
new file mode 100644 (file)
index 0000000..2683e4b
--- /dev/null
@@ -0,0 +1,50 @@
+
+This project is covered by two different licenses: MIT and Apache.
+
+#### MIT License ####
+
+The following files were ported to Go from C files of libyaml, and thus
+are still covered by their original MIT license, with the additional
+copyright staring in 2011 when the project was ported over:
+
+    apic.go emitterc.go parserc.go readerc.go scannerc.go
+    writerc.go yamlh.go yamlprivateh.go
+
+Copyright (c) 2006-2010 Kirill Simonov
+Copyright (c) 2006-2011 Kirill Simonov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+### Apache License ###
+
+All the remaining project files are covered by the Apache license:
+
+Copyright (c) 2011-2019 Canonical Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/vendor/gopkg.in/yaml.v3/NOTICE b/vendor/gopkg.in/yaml.v3/NOTICE
new file mode 100644 (file)
index 0000000..866d74a
--- /dev/null
@@ -0,0 +1,13 @@
+Copyright 2011-2016 Canonical Ltd.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/vendor/gopkg.in/yaml.v3/README.md b/vendor/gopkg.in/yaml.v3/README.md
new file mode 100644 (file)
index 0000000..08eb1ba
--- /dev/null
@@ -0,0 +1,150 @@
+# YAML support for the Go language
+
+Introduction
+------------
+
+The yaml package enables Go programs to comfortably encode and decode YAML
+values. It was developed within [Canonical](https://www.canonical.com) as
+part of the [juju](https://juju.ubuntu.com) project, and is based on a
+pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
+C library to parse and generate YAML data quickly and reliably.
+
+Compatibility
+-------------
+
+The yaml package supports most of YAML 1.2, but preserves some behavior
+from 1.1 for backwards compatibility.
+
+Specifically, as of v3 of the yaml package:
+
+ - YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being
+   decoded into a typed bool value. Otherwise they behave as a string. Booleans
+   in YAML 1.2 are _true/false_ only.
+ - Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_
+   as specified in YAML 1.2, because most parsers still use the old format.
+   Octals in the  _0o777_ format are supported though, so new files work.
+ - Does not support base-60 floats. These are gone from YAML 1.2, and were
+   actually never supported by this package as it's clearly a poor choice.
+
+and offers backwards
+compatibility with YAML 1.1 in some cases.
+1.2, including support for
+anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
+implemented, and base-60 floats from YAML 1.1 are purposefully not
+supported since they're a poor design and are gone in YAML 1.2.
+
+Installation and usage
+----------------------
+
+The import path for the package is *gopkg.in/yaml.v3*.
+
+To install it, run:
+
+    go get gopkg.in/yaml.v3
+
+API documentation
+-----------------
+
+If opened in a browser, the import path itself leads to the API documentation:
+
+  - [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3)
+
+API stability
+-------------
+
+The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in).
+
+
+License
+-------
+
+The yaml package is licensed under the MIT and Apache License 2.0 licenses.
+Please see the LICENSE file for details.
+
+
+Example
+-------
+
+```Go
+package main
+
+import (
+        "fmt"
+        "log"
+
+        "gopkg.in/yaml.v3"
+)
+
+var data = `
+a: Easy!
+b:
+  c: 2
+  d: [3, 4]
+`
+
+// Note: struct fields must be public in order for unmarshal to
+// correctly populate the data.
+type T struct {
+        A string
+        B struct {
+                RenamedC int   `yaml:"c"`
+                D        []int `yaml:",flow"`
+        }
+}
+
+func main() {
+        t := T{}
+    
+        err := yaml.Unmarshal([]byte(data), &t)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- t:\n%v\n\n", t)
+    
+        d, err := yaml.Marshal(&t)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- t dump:\n%s\n\n", string(d))
+    
+        m := make(map[interface{}]interface{})
+    
+        err = yaml.Unmarshal([]byte(data), &m)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- m:\n%v\n\n", m)
+    
+        d, err = yaml.Marshal(&m)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- m dump:\n%s\n\n", string(d))
+}
+```
+
+This example will generate the following output:
+
+```
+--- t:
+{Easy! {2 [3 4]}}
+
+--- t dump:
+a: Easy!
+b:
+  c: 2
+  d: [3, 4]
+
+
+--- m:
+map[a:Easy! b:map[c:2 d:[3 4]]]
+
+--- m dump:
+a: Easy!
+b:
+  c: 2
+  d:
+  - 3
+  - 4
+```
+
diff --git a/vendor/gopkg.in/yaml.v3/apic.go b/vendor/gopkg.in/yaml.v3/apic.go
new file mode 100644 (file)
index 0000000..65846e6
--- /dev/null
@@ -0,0 +1,746 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+       "io"
+)
+
+func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
+       //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
+
+       // Check if we can move the queue at the beginning of the buffer.
+       if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
+               if parser.tokens_head != len(parser.tokens) {
+                       copy(parser.tokens, parser.tokens[parser.tokens_head:])
+               }
+               parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
+               parser.tokens_head = 0
+       }
+       parser.tokens = append(parser.tokens, *token)
+       if pos < 0 {
+               return
+       }
+       copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
+       parser.tokens[parser.tokens_head+pos] = *token
+}
+
+// Create a new parser object.
+func yaml_parser_initialize(parser *yaml_parser_t) bool {
+       *parser = yaml_parser_t{
+               raw_buffer: make([]byte, 0, input_raw_buffer_size),
+               buffer:     make([]byte, 0, input_buffer_size),
+       }
+       return true
+}
+
+// Destroy a parser object.
+func yaml_parser_delete(parser *yaml_parser_t) {
+       *parser = yaml_parser_t{}
+}
+
+// String read handler.
+func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
+       if parser.input_pos == len(parser.input) {
+               return 0, io.EOF
+       }
+       n = copy(buffer, parser.input[parser.input_pos:])
+       parser.input_pos += n
+       return n, nil
+}
+
+// Reader read handler.
+func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
+       return parser.input_reader.Read(buffer)
+}
+
+// Set a string input.
+func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
+       if parser.read_handler != nil {
+               panic("must set the input source only once")
+       }
+       parser.read_handler = yaml_string_read_handler
+       parser.input = input
+       parser.input_pos = 0
+}
+
+// Set a file input.
+func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
+       if parser.read_handler != nil {
+               panic("must set the input source only once")
+       }
+       parser.read_handler = yaml_reader_read_handler
+       parser.input_reader = r
+}
+
+// Set the source encoding.
+func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
+       if parser.encoding != yaml_ANY_ENCODING {
+               panic("must set the encoding only once")
+       }
+       parser.encoding = encoding
+}
+
+// Create a new emitter object.
+func yaml_emitter_initialize(emitter *yaml_emitter_t) {
+       *emitter = yaml_emitter_t{
+               buffer:     make([]byte, output_buffer_size),
+               raw_buffer: make([]byte, 0, output_raw_buffer_size),
+               states:     make([]yaml_emitter_state_t, 0, initial_stack_size),
+               events:     make([]yaml_event_t, 0, initial_queue_size),
+       }
+}
+
+// Destroy an emitter object.
+func yaml_emitter_delete(emitter *yaml_emitter_t) {
+       *emitter = yaml_emitter_t{}
+}
+
+// String write handler.
+func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
+       *emitter.output_buffer = append(*emitter.output_buffer, buffer...)
+       return nil
+}
+
+// yaml_writer_write_handler uses emitter.output_writer to write the
+// emitted text.
+func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
+       _, err := emitter.output_writer.Write(buffer)
+       return err
+}
+
+// Set a string output.
+func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
+       if emitter.write_handler != nil {
+               panic("must set the output target only once")
+       }
+       emitter.write_handler = yaml_string_write_handler
+       emitter.output_buffer = output_buffer
+}
+
+// Set a file output.
+func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
+       if emitter.write_handler != nil {
+               panic("must set the output target only once")
+       }
+       emitter.write_handler = yaml_writer_write_handler
+       emitter.output_writer = w
+}
+
+// Set the output encoding.
+func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
+       if emitter.encoding != yaml_ANY_ENCODING {
+               panic("must set the output encoding only once")
+       }
+       emitter.encoding = encoding
+}
+
+// Set the canonical output style.
+func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
+       emitter.canonical = canonical
+}
+
+// Set the indentation increment.
+func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
+       if indent < 2 || indent > 9 {
+               indent = 2
+       }
+       emitter.best_indent = indent
+}
+
+// Set the preferred line width.
+func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
+       if width < 0 {
+               width = -1
+       }
+       emitter.best_width = width
+}
+
+// Set if unescaped non-ASCII characters are allowed.
+func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
+       emitter.unicode = unicode
+}
+
+// Set the preferred line break character.
+func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
+       emitter.line_break = line_break
+}
+
+///*
+// * Destroy a token object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_token_delete(yaml_token_t *token)
+//{
+//    assert(token);  // Non-NULL token object expected.
+//
+//    switch (token.type)
+//    {
+//        case YAML_TAG_DIRECTIVE_TOKEN:
+//            yaml_free(token.data.tag_directive.handle);
+//            yaml_free(token.data.tag_directive.prefix);
+//            break;
+//
+//        case YAML_ALIAS_TOKEN:
+//            yaml_free(token.data.alias.value);
+//            break;
+//
+//        case YAML_ANCHOR_TOKEN:
+//            yaml_free(token.data.anchor.value);
+//            break;
+//
+//        case YAML_TAG_TOKEN:
+//            yaml_free(token.data.tag.handle);
+//            yaml_free(token.data.tag.suffix);
+//            break;
+//
+//        case YAML_SCALAR_TOKEN:
+//            yaml_free(token.data.scalar.value);
+//            break;
+//
+//        default:
+//            break;
+//    }
+//
+//    memset(token, 0, sizeof(yaml_token_t));
+//}
+//
+///*
+// * Check if a string is a valid UTF-8 sequence.
+// *
+// * Check 'reader.c' for more details on UTF-8 encoding.
+// */
+//
+//static int
+//yaml_check_utf8(yaml_char_t *start, size_t length)
+//{
+//    yaml_char_t *end = start+length;
+//    yaml_char_t *pointer = start;
+//
+//    while (pointer < end) {
+//        unsigned char octet;
+//        unsigned int width;
+//        unsigned int value;
+//        size_t k;
+//
+//        octet = pointer[0];
+//        width = (octet & 0x80) == 0x00 ? 1 :
+//                (octet & 0xE0) == 0xC0 ? 2 :
+//                (octet & 0xF0) == 0xE0 ? 3 :
+//                (octet & 0xF8) == 0xF0 ? 4 : 0;
+//        value = (octet & 0x80) == 0x00 ? octet & 0x7F :
+//                (octet & 0xE0) == 0xC0 ? octet & 0x1F :
+//                (octet & 0xF0) == 0xE0 ? octet & 0x0F :
+//                (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
+//        if (!width) return 0;
+//        if (pointer+width > end) return 0;
+//        for (k = 1; k < width; k ++) {
+//            octet = pointer[k];
+//            if ((octet & 0xC0) != 0x80) return 0;
+//            value = (value << 6) + (octet & 0x3F);
+//        }
+//        if (!((width == 1) ||
+//            (width == 2 && value >= 0x80) ||
+//            (width == 3 && value >= 0x800) ||
+//            (width == 4 && value >= 0x10000))) return 0;
+//
+//        pointer += width;
+//    }
+//
+//    return 1;
+//}
+//
+
+// Create STREAM-START.
+func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
+       *event = yaml_event_t{
+               typ:      yaml_STREAM_START_EVENT,
+               encoding: encoding,
+       }
+}
+
+// Create STREAM-END.
+func yaml_stream_end_event_initialize(event *yaml_event_t) {
+       *event = yaml_event_t{
+               typ: yaml_STREAM_END_EVENT,
+       }
+}
+
+// Create DOCUMENT-START.
+func yaml_document_start_event_initialize(
+       event *yaml_event_t,
+       version_directive *yaml_version_directive_t,
+       tag_directives []yaml_tag_directive_t,
+       implicit bool,
+) {
+       *event = yaml_event_t{
+               typ:               yaml_DOCUMENT_START_EVENT,
+               version_directive: version_directive,
+               tag_directives:    tag_directives,
+               implicit:          implicit,
+       }
+}
+
+// Create DOCUMENT-END.
+func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
+       *event = yaml_event_t{
+               typ:      yaml_DOCUMENT_END_EVENT,
+               implicit: implicit,
+       }
+}
+
+// Create ALIAS.
+func yaml_alias_event_initialize(event *yaml_event_t, anchor []byte) bool {
+       *event = yaml_event_t{
+               typ:    yaml_ALIAS_EVENT,
+               anchor: anchor,
+       }
+       return true
+}
+
+// Create SCALAR.
+func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
+       *event = yaml_event_t{
+               typ:             yaml_SCALAR_EVENT,
+               anchor:          anchor,
+               tag:             tag,
+               value:           value,
+               implicit:        plain_implicit,
+               quoted_implicit: quoted_implicit,
+               style:           yaml_style_t(style),
+       }
+       return true
+}
+
+// Create SEQUENCE-START.
+func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
+       *event = yaml_event_t{
+               typ:      yaml_SEQUENCE_START_EVENT,
+               anchor:   anchor,
+               tag:      tag,
+               implicit: implicit,
+               style:    yaml_style_t(style),
+       }
+       return true
+}
+
+// Create SEQUENCE-END.
+func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
+       *event = yaml_event_t{
+               typ: yaml_SEQUENCE_END_EVENT,
+       }
+       return true
+}
+
+// Create MAPPING-START.
+func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
+       *event = yaml_event_t{
+               typ:      yaml_MAPPING_START_EVENT,
+               anchor:   anchor,
+               tag:      tag,
+               implicit: implicit,
+               style:    yaml_style_t(style),
+       }
+}
+
+// Create MAPPING-END.
+func yaml_mapping_end_event_initialize(event *yaml_event_t) {
+       *event = yaml_event_t{
+               typ: yaml_MAPPING_END_EVENT,
+       }
+}
+
+// Destroy an event object.
+func yaml_event_delete(event *yaml_event_t) {
+       *event = yaml_event_t{}
+}
+
+///*
+// * Create a document object.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_initialize(document *yaml_document_t,
+//        version_directive *yaml_version_directive_t,
+//        tag_directives_start *yaml_tag_directive_t,
+//        tag_directives_end *yaml_tag_directive_t,
+//        start_implicit int, end_implicit int)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    struct {
+//        start *yaml_node_t
+//        end *yaml_node_t
+//        top *yaml_node_t
+//    } nodes = { NULL, NULL, NULL }
+//    version_directive_copy *yaml_version_directive_t = NULL
+//    struct {
+//        start *yaml_tag_directive_t
+//        end *yaml_tag_directive_t
+//        top *yaml_tag_directive_t
+//    } tag_directives_copy = { NULL, NULL, NULL }
+//    value yaml_tag_directive_t = { NULL, NULL }
+//    mark yaml_mark_t = { 0, 0, 0 }
+//
+//    assert(document) // Non-NULL document object is expected.
+//    assert((tag_directives_start && tag_directives_end) ||
+//            (tag_directives_start == tag_directives_end))
+//                            // Valid tag directives are expected.
+//
+//    if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
+//
+//    if (version_directive) {
+//        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
+//        if (!version_directive_copy) goto error
+//        version_directive_copy.major = version_directive.major
+//        version_directive_copy.minor = version_directive.minor
+//    }
+//
+//    if (tag_directives_start != tag_directives_end) {
+//        tag_directive *yaml_tag_directive_t
+//        if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
+//            goto error
+//        for (tag_directive = tag_directives_start
+//                tag_directive != tag_directives_end; tag_directive ++) {
+//            assert(tag_directive.handle)
+//            assert(tag_directive.prefix)
+//            if (!yaml_check_utf8(tag_directive.handle,
+//                        strlen((char *)tag_directive.handle)))
+//                goto error
+//            if (!yaml_check_utf8(tag_directive.prefix,
+//                        strlen((char *)tag_directive.prefix)))
+//                goto error
+//            value.handle = yaml_strdup(tag_directive.handle)
+//            value.prefix = yaml_strdup(tag_directive.prefix)
+//            if (!value.handle || !value.prefix) goto error
+//            if (!PUSH(&context, tag_directives_copy, value))
+//                goto error
+//            value.handle = NULL
+//            value.prefix = NULL
+//        }
+//    }
+//
+//    DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
+//            tag_directives_copy.start, tag_directives_copy.top,
+//            start_implicit, end_implicit, mark, mark)
+//
+//    return 1
+//
+//error:
+//    STACK_DEL(&context, nodes)
+//    yaml_free(version_directive_copy)
+//    while (!STACK_EMPTY(&context, tag_directives_copy)) {
+//        value yaml_tag_directive_t = POP(&context, tag_directives_copy)
+//        yaml_free(value.handle)
+//        yaml_free(value.prefix)
+//    }
+//    STACK_DEL(&context, tag_directives_copy)
+//    yaml_free(value.handle)
+//    yaml_free(value.prefix)
+//
+//    return 0
+//}
+//
+///*
+// * Destroy a document object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_document_delete(document *yaml_document_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    tag_directive *yaml_tag_directive_t
+//
+//    context.error = YAML_NO_ERROR // Eliminate a compiler warning.
+//
+//    assert(document) // Non-NULL document object is expected.
+//
+//    while (!STACK_EMPTY(&context, document.nodes)) {
+//        node yaml_node_t = POP(&context, document.nodes)
+//        yaml_free(node.tag)
+//        switch (node.type) {
+//            case YAML_SCALAR_NODE:
+//                yaml_free(node.data.scalar.value)
+//                break
+//            case YAML_SEQUENCE_NODE:
+//                STACK_DEL(&context, node.data.sequence.items)
+//                break
+//            case YAML_MAPPING_NODE:
+//                STACK_DEL(&context, node.data.mapping.pairs)
+//                break
+//            default:
+//                assert(0) // Should not happen.
+//        }
+//    }
+//    STACK_DEL(&context, document.nodes)
+//
+//    yaml_free(document.version_directive)
+//    for (tag_directive = document.tag_directives.start
+//            tag_directive != document.tag_directives.end
+//            tag_directive++) {
+//        yaml_free(tag_directive.handle)
+//        yaml_free(tag_directive.prefix)
+//    }
+//    yaml_free(document.tag_directives.start)
+//
+//    memset(document, 0, sizeof(yaml_document_t))
+//}
+//
+///**
+// * Get a document node.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_node(document *yaml_document_t, index int)
+//{
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (index > 0 && document.nodes.start + index <= document.nodes.top) {
+//        return document.nodes.start + index - 1
+//    }
+//    return NULL
+//}
+//
+///**
+// * Get the root object.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_root_node(document *yaml_document_t)
+//{
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (document.nodes.top != document.nodes.start) {
+//        return document.nodes.start
+//    }
+//    return NULL
+//}
+//
+///*
+// * Add a scalar node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_scalar(document *yaml_document_t,
+//        tag *yaml_char_t, value *yaml_char_t, length int,
+//        style yaml_scalar_style_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    tag_copy *yaml_char_t = NULL
+//    value_copy *yaml_char_t = NULL
+//    node yaml_node_t
+//
+//    assert(document) // Non-NULL document object is expected.
+//    assert(value) // Non-NULL value is expected.
+//
+//    if (!tag) {
+//        tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
+//    }
+//
+//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
+//    tag_copy = yaml_strdup(tag)
+//    if (!tag_copy) goto error
+//
+//    if (length < 0) {
+//        length = strlen((char *)value)
+//    }
+//
+//    if (!yaml_check_utf8(value, length)) goto error
+//    value_copy = yaml_malloc(length+1)
+//    if (!value_copy) goto error
+//    memcpy(value_copy, value, length)
+//    value_copy[length] = '\0'
+//
+//    SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
+//    if (!PUSH(&context, document.nodes, node)) goto error
+//
+//    return document.nodes.top - document.nodes.start
+//
+//error:
+//    yaml_free(tag_copy)
+//    yaml_free(value_copy)
+//
+//    return 0
+//}
+//
+///*
+// * Add a sequence node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_sequence(document *yaml_document_t,
+//        tag *yaml_char_t, style yaml_sequence_style_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    tag_copy *yaml_char_t = NULL
+//    struct {
+//        start *yaml_node_item_t
+//        end *yaml_node_item_t
+//        top *yaml_node_item_t
+//    } items = { NULL, NULL, NULL }
+//    node yaml_node_t
+//
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (!tag) {
+//        tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
+//    }
+//
+//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
+//    tag_copy = yaml_strdup(tag)
+//    if (!tag_copy) goto error
+//
+//    if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
+//
+//    SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
+//            style, mark, mark)
+//    if (!PUSH(&context, document.nodes, node)) goto error
+//
+//    return document.nodes.top - document.nodes.start
+//
+//error:
+//    STACK_DEL(&context, items)
+//    yaml_free(tag_copy)
+//
+//    return 0
+//}
+//
+///*
+// * Add a mapping node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_mapping(document *yaml_document_t,
+//        tag *yaml_char_t, style yaml_mapping_style_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    tag_copy *yaml_char_t = NULL
+//    struct {
+//        start *yaml_node_pair_t
+//        end *yaml_node_pair_t
+//        top *yaml_node_pair_t
+//    } pairs = { NULL, NULL, NULL }
+//    node yaml_node_t
+//
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (!tag) {
+//        tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
+//    }
+//
+//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
+//    tag_copy = yaml_strdup(tag)
+//    if (!tag_copy) goto error
+//
+//    if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
+//
+//    MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
+//            style, mark, mark)
+//    if (!PUSH(&context, document.nodes, node)) goto error
+//
+//    return document.nodes.top - document.nodes.start
+//
+//error:
+//    STACK_DEL(&context, pairs)
+//    yaml_free(tag_copy)
+//
+//    return 0
+//}
+//
+///*
+// * Append an item to a sequence node.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_sequence_item(document *yaml_document_t,
+//        sequence int, item int)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//
+//    assert(document) // Non-NULL document is required.
+//    assert(sequence > 0
+//            && document.nodes.start + sequence <= document.nodes.top)
+//                            // Valid sequence id is required.
+//    assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
+//                            // A sequence node is required.
+//    assert(item > 0 && document.nodes.start + item <= document.nodes.top)
+//                            // Valid item id is required.
+//
+//    if (!PUSH(&context,
+//                document.nodes.start[sequence-1].data.sequence.items, item))
+//        return 0
+//
+//    return 1
+//}
+//
+///*
+// * Append a pair of a key and a value to a mapping node.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_mapping_pair(document *yaml_document_t,
+//        mapping int, key int, value int)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//
+//    pair yaml_node_pair_t
+//
+//    assert(document) // Non-NULL document is required.
+//    assert(mapping > 0
+//            && document.nodes.start + mapping <= document.nodes.top)
+//                            // Valid mapping id is required.
+//    assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
+//                            // A mapping node is required.
+//    assert(key > 0 && document.nodes.start + key <= document.nodes.top)
+//                            // Valid key id is required.
+//    assert(value > 0 && document.nodes.start + value <= document.nodes.top)
+//                            // Valid value id is required.
+//
+//    pair.key = key
+//    pair.value = value
+//
+//    if (!PUSH(&context,
+//                document.nodes.start[mapping-1].data.mapping.pairs, pair))
+//        return 0
+//
+//    return 1
+//}
+//
+//
diff --git a/vendor/gopkg.in/yaml.v3/decode.go b/vendor/gopkg.in/yaml.v3/decode.go
new file mode 100644 (file)
index 0000000..f864136
--- /dev/null
@@ -0,0 +1,864 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package yaml
+
+import (
+       "encoding"
+       "encoding/base64"
+       "fmt"
+       "io"
+       "math"
+       "reflect"
+       "strconv"
+       "time"
+)
+
+// ----------------------------------------------------------------------------
+// Parser, produces a node tree out of a libyaml event stream.
+
+type parser struct {
+       parser   yaml_parser_t
+       event    yaml_event_t
+       doc      *Node
+       anchors  map[string]*Node
+       doneInit bool
+}
+
+func newParser(b []byte) *parser {
+       p := parser{}
+       if !yaml_parser_initialize(&p.parser) {
+               panic("failed to initialize YAML emitter")
+       }
+       if len(b) == 0 {
+               b = []byte{'\n'}
+       }
+       yaml_parser_set_input_string(&p.parser, b)
+       return &p
+}
+
+func newParserFromReader(r io.Reader) *parser {
+       p := parser{}
+       if !yaml_parser_initialize(&p.parser) {
+               panic("failed to initialize YAML emitter")
+       }
+       yaml_parser_set_input_reader(&p.parser, r)
+       return &p
+}
+
+func (p *parser) init() {
+       if p.doneInit {
+               return
+       }
+       p.anchors = make(map[string]*Node)
+       p.expect(yaml_STREAM_START_EVENT)
+       p.doneInit = true
+}
+
+func (p *parser) destroy() {
+       if p.event.typ != yaml_NO_EVENT {
+               yaml_event_delete(&p.event)
+       }
+       yaml_parser_delete(&p.parser)
+}
+
+// expect consumes an event from the event stream and
+// checks that it's of the expected type.
+func (p *parser) expect(e yaml_event_type_t) {
+       if p.event.typ == yaml_NO_EVENT {
+               if !yaml_parser_parse(&p.parser, &p.event) {
+                       p.fail()
+               }
+       }
+       if p.event.typ == yaml_STREAM_END_EVENT {
+               failf("attempted to go past the end of stream; corrupted value?")
+       }
+       if p.event.typ != e {
+               p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
+               p.fail()
+       }
+       yaml_event_delete(&p.event)
+       p.event.typ = yaml_NO_EVENT
+}
+
+// peek peeks at the next event in the event stream,
+// puts the results into p.event and returns the event type.
+func (p *parser) peek() yaml_event_type_t {
+       if p.event.typ != yaml_NO_EVENT {
+               return p.event.typ
+       }
+       if !yaml_parser_parse(&p.parser, &p.event) {
+               p.fail()
+       }
+       return p.event.typ
+}
+
+func (p *parser) fail() {
+       var where string
+       var line int
+       if p.parser.problem_mark.line != 0 {
+               line = p.parser.problem_mark.line
+               // Scanner errors don't iterate line before returning error
+               if p.parser.error == yaml_SCANNER_ERROR {
+                       line++
+               }
+       } else if p.parser.context_mark.line != 0 {
+               line = p.parser.context_mark.line
+       }
+       if line != 0 {
+               where = "line " + strconv.Itoa(line) + ": "
+       }
+       var msg string
+       if len(p.parser.problem) > 0 {
+               msg = p.parser.problem
+       } else {
+               msg = "unknown problem parsing YAML content"
+       }
+       failf("%s%s", where, msg)
+}
+
+func (p *parser) anchor(n *Node, anchor []byte) {
+       if anchor != nil {
+               n.Anchor = string(anchor)
+               p.anchors[n.Anchor] = n
+       }
+}
+
+func (p *parser) parse() *Node {
+       p.init()
+       switch p.peek() {
+       case yaml_SCALAR_EVENT:
+               return p.scalar()
+       case yaml_ALIAS_EVENT:
+               return p.alias()
+       case yaml_MAPPING_START_EVENT:
+               return p.mapping()
+       case yaml_SEQUENCE_START_EVENT:
+               return p.sequence()
+       case yaml_DOCUMENT_START_EVENT:
+               return p.document()
+       case yaml_STREAM_END_EVENT:
+               // Happens when attempting to decode an empty buffer.
+               return nil
+       default:
+               panic("attempted to parse unknown event: " + p.event.typ.String())
+       }
+}
+
+func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {
+       var style Style
+       if tag != "" && tag != "!" {
+               tag = shortTag(tag)
+               style = TaggedStyle
+       } else if defaultTag != "" {
+               tag = defaultTag
+       } else if kind == ScalarNode {
+               tag, _ = resolve("", value)
+       }
+       return &Node{
+               Kind:        kind,
+               Tag:         tag,
+               Value:       value,
+               Style:       style,
+               Line:        p.event.start_mark.line + 1,
+               Column:      p.event.start_mark.column + 1,
+               HeadComment: string(p.event.head_comment),
+               LineComment: string(p.event.line_comment),
+               FootComment: string(p.event.foot_comment),
+       }
+}
+
+func (p *parser) parseChild(parent *Node) *Node {
+       child := p.parse()
+       parent.Content = append(parent.Content, child)
+       return child
+}
+
+func (p *parser) document() *Node {
+       n := p.node(DocumentNode, "", "", "")
+       p.doc = n
+       p.expect(yaml_DOCUMENT_START_EVENT)
+       p.parseChild(n)
+       if p.peek() == yaml_DOCUMENT_END_EVENT {
+               n.FootComment = string(p.event.foot_comment)
+       }
+       p.expect(yaml_DOCUMENT_END_EVENT)
+       return n
+}
+
+func (p *parser) alias() *Node {
+       n := p.node(AliasNode, "", "", string(p.event.anchor))
+       n.Alias = p.anchors[n.Value]
+       if n.Alias == nil {
+               failf("unknown anchor '%s' referenced", n.Value)
+       }
+       p.expect(yaml_ALIAS_EVENT)
+       return n
+}
+
+func (p *parser) scalar() *Node {
+       var parsedStyle = p.event.scalar_style()
+       var nodeStyle Style
+       switch {
+       case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:
+               nodeStyle = DoubleQuotedStyle
+       case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:
+               nodeStyle = SingleQuotedStyle
+       case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0:
+               nodeStyle = LiteralStyle
+       case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0:
+               nodeStyle = FoldedStyle
+       }
+       var nodeValue = string(p.event.value)
+       var nodeTag = string(p.event.tag)
+       var defaultTag string
+       if nodeStyle == 0 {
+               if nodeValue == "<<" {
+                       defaultTag = mergeTag
+               }
+       } else {
+               defaultTag = strTag
+       }
+       n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue)
+       n.Style |= nodeStyle
+       p.anchor(n, p.event.anchor)
+       p.expect(yaml_SCALAR_EVENT)
+       return n
+}
+
+func (p *parser) sequence() *Node {
+       n := p.node(SequenceNode, seqTag, string(p.event.tag), "")
+       if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {
+               n.Style |= FlowStyle
+       }
+       p.anchor(n, p.event.anchor)
+       p.expect(yaml_SEQUENCE_START_EVENT)
+       for p.peek() != yaml_SEQUENCE_END_EVENT {
+               p.parseChild(n)
+       }
+       n.LineComment = string(p.event.line_comment)
+       n.FootComment = string(p.event.foot_comment)
+       p.expect(yaml_SEQUENCE_END_EVENT)
+       return n
+}
+
+func (p *parser) mapping() *Node {
+       n := p.node(MappingNode, mapTag, string(p.event.tag), "")
+       if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
+               n.Style |= FlowStyle
+       }
+       p.anchor(n, p.event.anchor)
+       p.expect(yaml_MAPPING_START_EVENT)
+       for p.peek() != yaml_MAPPING_END_EVENT {
+               k := p.parseChild(n)
+               v := p.parseChild(n)
+               if v.FootComment != "" {
+                       k.FootComment = v.FootComment
+                       v.FootComment = ""
+               }
+       }
+       n.LineComment = string(p.event.line_comment)
+       n.FootComment = string(p.event.foot_comment)
+       p.expect(yaml_MAPPING_END_EVENT)
+       return n
+}
+
+// ----------------------------------------------------------------------------
+// Decoder, unmarshals a node into a provided value.
+
+type decoder struct {
+       doc     *Node
+       aliases map[*Node]bool
+       terrors []string
+
+       stringMapType  reflect.Type
+       generalMapType reflect.Type
+
+       knownFields bool
+       uniqueKeys  bool
+}
+
+var (
+       nodeType       = reflect.TypeOf(Node{})
+       durationType   = reflect.TypeOf(time.Duration(0))
+       stringMapType  = reflect.TypeOf(map[string]interface{}{})
+       generalMapType = reflect.TypeOf(map[interface{}]interface{}{})
+       ifaceType      = generalMapType.Elem()
+       timeType       = reflect.TypeOf(time.Time{})
+       ptrTimeType    = reflect.TypeOf(&time.Time{})
+)
+
+func newDecoder() *decoder {
+       d := &decoder{
+               stringMapType:  stringMapType,
+               generalMapType: generalMapType,
+               uniqueKeys:     true,
+       }
+       d.aliases = make(map[*Node]bool)
+       return d
+}
+
+func (d *decoder) terror(n *Node, tag string, out reflect.Value) {
+       if n.Tag != "" {
+               tag = n.Tag
+       }
+       value := n.Value
+       if tag != seqTag && tag != mapTag {
+               if len(value) > 10 {
+                       value = " `" + value[:7] + "...`"
+               } else {
+                       value = " `" + value + "`"
+               }
+       }
+       d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type()))
+}
+
+func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
+       if err := u.UnmarshalYAML(n); err != nil {
+               fail(err)
+       }
+       return true
+}
+
+func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) {
+       terrlen := len(d.terrors)
+       err := u.UnmarshalYAML(func(v interface{}) (err error) {
+               defer handleErr(&err)
+               d.unmarshal(n, reflect.ValueOf(v))
+               if len(d.terrors) > terrlen {
+                       issues := d.terrors[terrlen:]
+                       d.terrors = d.terrors[:terrlen]
+                       return &TypeError{issues}
+               }
+               return nil
+       })
+       if e, ok := err.(*TypeError); ok {
+               d.terrors = append(d.terrors, e.Errors...)
+               return false
+       }
+       if err != nil {
+               fail(err)
+       }
+       return true
+}
+
+// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
+// if a value is found to implement it.
+// It returns the initialized and dereferenced out value, whether
+// unmarshalling was already done by UnmarshalYAML, and if so whether
+// its types unmarshalled appropriately.
+//
+// If n holds a null value, prepare returns before doing anything.
+func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
+       if n.ShortTag() == nullTag {
+               return out, false, false
+       }
+       again := true
+       for again {
+               again = false
+               if out.Kind() == reflect.Ptr {
+                       if out.IsNil() {
+                               out.Set(reflect.New(out.Type().Elem()))
+                       }
+                       out = out.Elem()
+                       again = true
+               }
+               if out.CanAddr() {
+                       outi := out.Addr().Interface()
+                       if u, ok := outi.(Unmarshaler); ok {
+                               good = d.callUnmarshaler(n, u)
+                               return out, true, good
+                       }
+                       if u, ok := outi.(obsoleteUnmarshaler); ok {
+                               good = d.callObsoleteUnmarshaler(n, u)
+                               return out, true, good
+                       }
+               }
+       }
+       return out, false, false
+}
+
+func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) {
+       if n.ShortTag() == nullTag {
+               return reflect.Value{}
+       }
+       for _, num := range index {
+               for {
+                       if v.Kind() == reflect.Ptr {
+                               if v.IsNil() {
+                                       v.Set(reflect.New(v.Type().Elem()))
+                               }
+                               v = v.Elem()
+                               continue
+                       }
+                       break
+               }
+               v = v.Field(num)
+       }
+       return v
+}
+
+func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
+       if out.Type() == nodeType {
+               out.Set(reflect.ValueOf(n).Elem())
+               return true
+       }
+       switch n.Kind {
+       case DocumentNode:
+               return d.document(n, out)
+       case AliasNode:
+               return d.alias(n, out)
+       }
+       out, unmarshaled, good := d.prepare(n, out)
+       if unmarshaled {
+               return good
+       }
+       switch n.Kind {
+       case ScalarNode:
+               good = d.scalar(n, out)
+       case MappingNode:
+               good = d.mapping(n, out)
+       case SequenceNode:
+               good = d.sequence(n, out)
+       default:
+               panic("internal error: unknown node kind: " + strconv.Itoa(int(n.Kind)))
+       }
+       return good
+}
+
+func (d *decoder) document(n *Node, out reflect.Value) (good bool) {
+       if len(n.Content) == 1 {
+               d.doc = n
+               d.unmarshal(n.Content[0], out)
+               return true
+       }
+       return false
+}
+
+func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {
+       if d.aliases[n] {
+               // TODO this could actually be allowed in some circumstances.
+               failf("anchor '%s' value contains itself", n.Value)
+       }
+       d.aliases[n] = true
+       good = d.unmarshal(n.Alias, out)
+       delete(d.aliases, n)
+       return good
+}
+
+var zeroValue reflect.Value
+
+func resetMap(out reflect.Value) {
+       for _, k := range out.MapKeys() {
+               out.SetMapIndex(k, zeroValue)
+       }
+}
+
+func (d *decoder) scalar(n *Node, out reflect.Value) bool {
+       var tag string
+       var resolved interface{}
+       if n.indicatedString() {
+               tag = strTag
+               resolved = n.Value
+       } else {
+               tag, resolved = resolve(n.Tag, n.Value)
+               if tag == binaryTag {
+                       data, err := base64.StdEncoding.DecodeString(resolved.(string))
+                       if err != nil {
+                               failf("!!binary value contains invalid base64 data")
+                       }
+                       resolved = string(data)
+               }
+       }
+       if resolved == nil {
+               if out.CanAddr() {
+                       switch out.Kind() {
+                       case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
+                               out.Set(reflect.Zero(out.Type()))
+                               return true
+                       }
+               }
+               return false
+       }
+       if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
+               // We've resolved to exactly the type we want, so use that.
+               out.Set(resolvedv)
+               return true
+       }
+       // Perhaps we can use the value as a TextUnmarshaler to
+       // set its value.
+       if out.CanAddr() {
+               u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
+               if ok {
+                       var text []byte
+                       if tag == binaryTag {
+                               text = []byte(resolved.(string))
+                       } else {
+                               // We let any value be unmarshaled into TextUnmarshaler.
+                               // That might be more lax than we'd like, but the
+                               // TextUnmarshaler itself should bowl out any dubious values.
+                               text = []byte(n.Value)
+                       }
+                       err := u.UnmarshalText(text)
+                       if err != nil {
+                               fail(err)
+                       }
+                       return true
+               }
+       }
+       switch out.Kind() {
+       case reflect.String:
+               if tag == binaryTag {
+                       out.SetString(resolved.(string))
+                       return true
+               }
+               out.SetString(n.Value)
+               return true
+       case reflect.Interface:
+               out.Set(reflect.ValueOf(resolved))
+               return true
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               // This used to work in v2, but it's very unfriendly.
+               isDuration := out.Type() == durationType
+
+               switch resolved := resolved.(type) {
+               case int:
+                       if !isDuration && !out.OverflowInt(int64(resolved)) {
+                               out.SetInt(int64(resolved))
+                               return true
+                       }
+               case int64:
+                       if !isDuration && !out.OverflowInt(resolved) {
+                               out.SetInt(resolved)
+                               return true
+                       }
+               case uint64:
+                       if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
+                               out.SetInt(int64(resolved))
+                               return true
+                       }
+               case float64:
+                       if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
+                               out.SetInt(int64(resolved))
+                               return true
+                       }
+               case string:
+                       if out.Type() == durationType {
+                               d, err := time.ParseDuration(resolved)
+                               if err == nil {
+                                       out.SetInt(int64(d))
+                                       return true
+                               }
+                       }
+               }
+       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+               switch resolved := resolved.(type) {
+               case int:
+                       if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
+                               out.SetUint(uint64(resolved))
+                               return true
+                       }
+               case int64:
+                       if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
+                               out.SetUint(uint64(resolved))
+                               return true
+                       }
+               case uint64:
+                       if !out.OverflowUint(uint64(resolved)) {
+                               out.SetUint(uint64(resolved))
+                               return true
+                       }
+               case float64:
+                       if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
+                               out.SetUint(uint64(resolved))
+                               return true
+                       }
+               }
+       case reflect.Bool:
+               switch resolved := resolved.(type) {
+               case bool:
+                       out.SetBool(resolved)
+                       return true
+               case string:
+                       // This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html).
+                       // It only works if explicitly attempting to unmarshal into a typed bool value.
+                       switch resolved {
+                       case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
+                               out.SetBool(true)
+                               return true
+                       case "n", "N", "no", "No", "NO", "off", "Off", "OFF":
+                               out.SetBool(false)
+                               return true
+                       }
+               }
+       case reflect.Float32, reflect.Float64:
+               switch resolved := resolved.(type) {
+               case int:
+                       out.SetFloat(float64(resolved))
+                       return true
+               case int64:
+                       out.SetFloat(float64(resolved))
+                       return true
+               case uint64:
+                       out.SetFloat(float64(resolved))
+                       return true
+               case float64:
+                       out.SetFloat(resolved)
+                       return true
+               }
+       case reflect.Struct:
+               if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
+                       out.Set(resolvedv)
+                       return true
+               }
+       case reflect.Ptr:
+               panic("yaml internal error: please report the issue")
+       }
+       d.terror(n, tag, out)
+       return false
+}
+
+func settableValueOf(i interface{}) reflect.Value {
+       v := reflect.ValueOf(i)
+       sv := reflect.New(v.Type()).Elem()
+       sv.Set(v)
+       return sv
+}
+
+func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
+       l := len(n.Content)
+
+       var iface reflect.Value
+       switch out.Kind() {
+       case reflect.Slice:
+               out.Set(reflect.MakeSlice(out.Type(), l, l))
+       case reflect.Array:
+               if l != out.Len() {
+                       failf("invalid array: want %d elements but got %d", out.Len(), l)
+               }
+       case reflect.Interface:
+               // No type hints. Will have to use a generic sequence.
+               iface = out
+               out = settableValueOf(make([]interface{}, l))
+       default:
+               d.terror(n, seqTag, out)
+               return false
+       }
+       et := out.Type().Elem()
+
+       j := 0
+       for i := 0; i < l; i++ {
+               e := reflect.New(et).Elem()
+               if ok := d.unmarshal(n.Content[i], e); ok {
+                       out.Index(j).Set(e)
+                       j++
+               }
+       }
+       if out.Kind() != reflect.Array {
+               out.Set(out.Slice(0, j))
+       }
+       if iface.IsValid() {
+               iface.Set(out)
+       }
+       return true
+}
+
+func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
+       l := len(n.Content)
+       if d.uniqueKeys {
+               nerrs := len(d.terrors)
+               for i := 0; i < l; i += 2 {
+                       ni := n.Content[i]
+                       for j := i + 2; j < l; j += 2 {
+                               nj := n.Content[j]
+                               if ni.Kind == nj.Kind && ni.Value == nj.Value {
+                                       d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
+                               }
+                       }
+               }
+               if len(d.terrors) > nerrs {
+                       return false
+               }
+       }
+       switch out.Kind() {
+       case reflect.Struct:
+               return d.mappingStruct(n, out)
+       case reflect.Map:
+               // okay
+       case reflect.Interface:
+               iface := out
+               if isStringMap(n) {
+                       out = reflect.MakeMap(d.stringMapType)
+               } else {
+                       out = reflect.MakeMap(d.generalMapType)
+               }
+               iface.Set(out)
+       default:
+               d.terror(n, mapTag, out)
+               return false
+       }
+
+       outt := out.Type()
+       kt := outt.Key()
+       et := outt.Elem()
+
+       stringMapType := d.stringMapType
+       generalMapType := d.generalMapType
+       if outt.Elem() == ifaceType {
+               if outt.Key().Kind() == reflect.String {
+                       d.stringMapType = outt
+               } else if outt.Key() == ifaceType {
+                       d.generalMapType = outt
+               }
+       }
+
+       if out.IsNil() {
+               out.Set(reflect.MakeMap(outt))
+       }
+       for i := 0; i < l; i += 2 {
+               if isMerge(n.Content[i]) {
+                       d.merge(n.Content[i+1], out)
+                       continue
+               }
+               k := reflect.New(kt).Elem()
+               if d.unmarshal(n.Content[i], k) {
+                       kkind := k.Kind()
+                       if kkind == reflect.Interface {
+                               kkind = k.Elem().Kind()
+                       }
+                       if kkind == reflect.Map || kkind == reflect.Slice {
+                               failf("invalid map key: %#v", k.Interface())
+                       }
+                       e := reflect.New(et).Elem()
+                       if d.unmarshal(n.Content[i+1], e) {
+                               out.SetMapIndex(k, e)
+                       }
+               }
+       }
+       d.stringMapType = stringMapType
+       d.generalMapType = generalMapType
+       return true
+}
+
+func isStringMap(n *Node) bool {
+       if n.Kind != MappingNode {
+               return false
+       }
+       l := len(n.Content)
+       for i := 0; i < l; i++ {
+               if n.Content[i].ShortTag() != strTag {
+                       return false
+               }
+       }
+       return true
+}
+
+func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
+       sinfo, err := getStructInfo(out.Type())
+       if err != nil {
+               panic(err)
+       }
+
+       var inlineMap reflect.Value
+       var elemType reflect.Type
+       if sinfo.InlineMap != -1 {
+               inlineMap = out.Field(sinfo.InlineMap)
+               inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
+               elemType = inlineMap.Type().Elem()
+       }
+
+       for _, index := range sinfo.InlineUnmarshalers {
+               field := d.fieldByIndex(n, out, index)
+               d.prepare(n, field)
+       }
+
+       var doneFields []bool
+       if d.uniqueKeys {
+               doneFields = make([]bool, len(sinfo.FieldsList))
+       }
+       name := settableValueOf("")
+       l := len(n.Content)
+       for i := 0; i < l; i += 2 {
+               ni := n.Content[i]
+               if isMerge(ni) {
+                       d.merge(n.Content[i+1], out)
+                       continue
+               }
+               if !d.unmarshal(ni, name) {
+                       continue
+               }
+               if info, ok := sinfo.FieldsMap[name.String()]; ok {
+                       if d.uniqueKeys {
+                               if doneFields[info.Id] {
+                                       d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
+                                       continue
+                               }
+                               doneFields[info.Id] = true
+                       }
+                       var field reflect.Value
+                       if info.Inline == nil {
+                               field = out.Field(info.Num)
+                       } else {
+                               field = d.fieldByIndex(n, out, info.Inline)
+                       }
+                       d.unmarshal(n.Content[i+1], field)
+               } else if sinfo.InlineMap != -1 {
+                       if inlineMap.IsNil() {
+                               inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
+                       }
+                       value := reflect.New(elemType).Elem()
+                       d.unmarshal(n.Content[i+1], value)
+                       inlineMap.SetMapIndex(name, value)
+               } else if d.knownFields {
+                       d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
+               }
+       }
+       return true
+}
+
+func failWantMap() {
+       failf("map merge requires map or sequence of maps as the value")
+}
+
+func (d *decoder) merge(n *Node, out reflect.Value) {
+       switch n.Kind {
+       case MappingNode:
+               d.unmarshal(n, out)
+       case AliasNode:
+               if n.Alias != nil && n.Alias.Kind != MappingNode {
+                       failWantMap()
+               }
+               d.unmarshal(n, out)
+       case SequenceNode:
+               // Step backwards as earlier nodes take precedence.
+               for i := len(n.Content) - 1; i >= 0; i-- {
+                       ni := n.Content[i]
+                       if ni.Kind == AliasNode {
+                               if ni.Alias != nil && ni.Alias.Kind != MappingNode {
+                                       failWantMap()
+                               }
+                       } else if ni.Kind != MappingNode {
+                               failWantMap()
+                       }
+                       d.unmarshal(ni, out)
+               }
+       default:
+               failWantMap()
+       }
+}
+
+func isMerge(n *Node) bool {
+       return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag)
+}
diff --git a/vendor/gopkg.in/yaml.v3/emitterc.go b/vendor/gopkg.in/yaml.v3/emitterc.go
new file mode 100644 (file)
index 0000000..aa5581d
--- /dev/null
@@ -0,0 +1,1957 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+       "bytes"
+       "fmt"
+)
+
+// Flush the buffer if needed.
+func flush(emitter *yaml_emitter_t) bool {
+       if emitter.buffer_pos+5 >= len(emitter.buffer) {
+               return yaml_emitter_flush(emitter)
+       }
+       return true
+}
+
+// Put a character to the output buffer.
+func put(emitter *yaml_emitter_t, value byte) bool {
+       if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
+               return false
+       }
+       emitter.buffer[emitter.buffer_pos] = value
+       emitter.buffer_pos++
+       emitter.column++
+       return true
+}
+
+// Put a line break to the output buffer.
+func put_break(emitter *yaml_emitter_t) bool {
+       if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
+               return false
+       }
+       switch emitter.line_break {
+       case yaml_CR_BREAK:
+               emitter.buffer[emitter.buffer_pos] = '\r'
+               emitter.buffer_pos += 1
+       case yaml_LN_BREAK:
+               emitter.buffer[emitter.buffer_pos] = '\n'
+               emitter.buffer_pos += 1
+       case yaml_CRLN_BREAK:
+               emitter.buffer[emitter.buffer_pos+0] = '\r'
+               emitter.buffer[emitter.buffer_pos+1] = '\n'
+               emitter.buffer_pos += 2
+       default:
+               panic("unknown line break setting")
+       }
+       if emitter.column == 0 {
+               emitter.space_above = true
+       }
+       emitter.column = 0
+       emitter.line++
+       // [Go] Do this here and below and drop from everywhere else (see commented lines).
+       emitter.indention = true
+       return true
+}
+
+// Copy a character from a string into buffer.
+func write(emitter *yaml_emitter_t, s []byte, i *int) bool {
+       if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
+               return false
+       }
+       p := emitter.buffer_pos
+       w := width(s[*i])
+       switch w {
+       case 4:
+               emitter.buffer[p+3] = s[*i+3]
+               fallthrough
+       case 3:
+               emitter.buffer[p+2] = s[*i+2]
+               fallthrough
+       case 2:
+               emitter.buffer[p+1] = s[*i+1]
+               fallthrough
+       case 1:
+               emitter.buffer[p+0] = s[*i+0]
+       default:
+               panic("unknown character width")
+       }
+       emitter.column++
+       emitter.buffer_pos += w
+       *i += w
+       return true
+}
+
+// Write a whole string into buffer.
+func write_all(emitter *yaml_emitter_t, s []byte) bool {
+       for i := 0; i < len(s); {
+               if !write(emitter, s, &i) {
+                       return false
+               }
+       }
+       return true
+}
+
+// Copy a line break character from a string into buffer.
+func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool {
+       if s[*i] == '\n' {
+               if !put_break(emitter) {
+                       return false
+               }
+               *i++
+       } else {
+               if !write(emitter, s, i) {
+                       return false
+               }
+               if emitter.column == 0 {
+                       emitter.space_above = true
+               }
+               emitter.column = 0
+               emitter.line++
+               // [Go] Do this here and above and drop from everywhere else (see commented lines).
+               emitter.indention = true
+       }
+       return true
+}
+
+// Set an emitter error and return false.
+func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool {
+       emitter.error = yaml_EMITTER_ERROR
+       emitter.problem = problem
+       return false
+}
+
+// Emit an event.
+func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+       emitter.events = append(emitter.events, *event)
+       for !yaml_emitter_need_more_events(emitter) {
+               event := &emitter.events[emitter.events_head]
+               if !yaml_emitter_analyze_event(emitter, event) {
+                       return false
+               }
+               if !yaml_emitter_state_machine(emitter, event) {
+                       return false
+               }
+               yaml_event_delete(event)
+               emitter.events_head++
+       }
+       return true
+}
+
+// Check if we need to accumulate more events before emitting.
+//
+// We accumulate extra
+//  - 1 event for DOCUMENT-START
+//  - 2 events for SEQUENCE-START
+//  - 3 events for MAPPING-START
+//
+func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool {
+       if emitter.events_head == len(emitter.events) {
+               return true
+       }
+       var accumulate int
+       switch emitter.events[emitter.events_head].typ {
+       case yaml_DOCUMENT_START_EVENT:
+               accumulate = 1
+               break
+       case yaml_SEQUENCE_START_EVENT:
+               accumulate = 2
+               break
+       case yaml_MAPPING_START_EVENT:
+               accumulate = 3
+               break
+       default:
+               return false
+       }
+       if len(emitter.events)-emitter.events_head > accumulate {
+               return false
+       }
+       var level int
+       for i := emitter.events_head; i < len(emitter.events); i++ {
+               switch emitter.events[i].typ {
+               case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT:
+                       level++
+               case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT:
+                       level--
+               }
+               if level == 0 {
+                       return false
+               }
+       }
+       return true
+}
+
+// Append a directive to the directives stack.
+func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool {
+       for i := 0; i < len(emitter.tag_directives); i++ {
+               if bytes.Equal(value.handle, emitter.tag_directives[i].handle) {
+                       if allow_duplicates {
+                               return true
+                       }
+                       return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive")
+               }
+       }
+
+       // [Go] Do we actually need to copy this given garbage collection
+       // and the lack of deallocating destructors?
+       tag_copy := yaml_tag_directive_t{
+               handle: make([]byte, len(value.handle)),
+               prefix: make([]byte, len(value.prefix)),
+       }
+       copy(tag_copy.handle, value.handle)
+       copy(tag_copy.prefix, value.prefix)
+       emitter.tag_directives = append(emitter.tag_directives, tag_copy)
+       return true
+}
+
+// Increase the indentation level.
+func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool {
+       emitter.indents = append(emitter.indents, emitter.indent)
+       if emitter.indent < 0 {
+               if flow {
+                       emitter.indent = emitter.best_indent
+               } else {
+                       emitter.indent = 0
+               }
+       } else if !indentless {
+               emitter.indent += emitter.best_indent
+       }
+       return true
+}
+
+// State dispatcher.
+func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+       switch emitter.state {
+       default:
+       case yaml_EMIT_STREAM_START_STATE:
+               return yaml_emitter_emit_stream_start(emitter, event)
+
+       case yaml_EMIT_FIRST_DOCUMENT_START_STATE:
+               return yaml_emitter_emit_document_start(emitter, event, true)
+
+       case yaml_EMIT_DOCUMENT_START_STATE:
+               return yaml_emitter_emit_document_start(emitter, event, false)
+
+       case yaml_EMIT_DOCUMENT_CONTENT_STATE:
+               return yaml_emitter_emit_document_content(emitter, event)
+
+       case yaml_EMIT_DOCUMENT_END_STATE:
+               return yaml_emitter_emit_document_end(emitter, event)
+
+       case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE:
+               return yaml_emitter_emit_flow_sequence_item(emitter, event, true, false)
+
+       case yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE:
+               return yaml_emitter_emit_flow_sequence_item(emitter, event, false, true)
+
+       case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE:
+               return yaml_emitter_emit_flow_sequence_item(emitter, event, false, false)
+
+       case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE:
+               return yaml_emitter_emit_flow_mapping_key(emitter, event, true, false)
+
+       case yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE:
+               return yaml_emitter_emit_flow_mapping_key(emitter, event, false, true)
+
+       case yaml_EMIT_FLOW_MAPPING_KEY_STATE:
+               return yaml_emitter_emit_flow_mapping_key(emitter, event, false, false)
+
+       case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE:
+               return yaml_emitter_emit_flow_mapping_value(emitter, event, true)
+
+       case yaml_EMIT_FLOW_MAPPING_VALUE_STATE:
+               return yaml_emitter_emit_flow_mapping_value(emitter, event, false)
+
+       case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE:
+               return yaml_emitter_emit_block_sequence_item(emitter, event, true)
+
+       case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE:
+               return yaml_emitter_emit_block_sequence_item(emitter, event, false)
+
+       case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE:
+               return yaml_emitter_emit_block_mapping_key(emitter, event, true)
+
+       case yaml_EMIT_BLOCK_MAPPING_KEY_STATE:
+               return yaml_emitter_emit_block_mapping_key(emitter, event, false)
+
+       case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE:
+               return yaml_emitter_emit_block_mapping_value(emitter, event, true)
+
+       case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE:
+               return yaml_emitter_emit_block_mapping_value(emitter, event, false)
+
+       case yaml_EMIT_END_STATE:
+               return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END")
+       }
+       panic("invalid emitter state")
+}
+
+// Expect STREAM-START.
+func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+       if event.typ != yaml_STREAM_START_EVENT {
+               return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START")
+       }
+       if emitter.encoding == yaml_ANY_ENCODING {
+               emitter.encoding = event.encoding
+               if emitter.encoding == yaml_ANY_ENCODING {
+                       emitter.encoding = yaml_UTF8_ENCODING
+               }
+       }
+       if emitter.best_indent < 2 || emitter.best_indent > 9 {
+               emitter.best_indent = 2
+       }
+       if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 {
+               emitter.best_width = 80
+       }
+       if emitter.best_width < 0 {
+               emitter.best_width = 1<<31 - 1
+       }
+       if emitter.line_break == yaml_ANY_BREAK {
+               emitter.line_break = yaml_LN_BREAK
+       }
+
+       emitter.indent = -1
+       emitter.line = 0
+       emitter.column = 0
+       emitter.whitespace = true
+       emitter.indention = true
+       emitter.space_above = true
+
+       if emitter.encoding != yaml_UTF8_ENCODING {
+               if !yaml_emitter_write_bom(emitter) {
+                       return false
+               }
+       }
+       emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE
+       return true
+}
+
+// Expect DOCUMENT-START or STREAM-END.
+func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+
+       if event.typ == yaml_DOCUMENT_START_EVENT {
+
+               if event.version_directive != nil {
+                       if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) {
+                               return false
+                       }
+               }
+
+               for i := 0; i < len(event.tag_directives); i++ {
+                       tag_directive := &event.tag_directives[i]
+                       if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) {
+                               return false
+                       }
+                       if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) {
+                               return false
+                       }
+               }
+
+               for i := 0; i < len(default_tag_directives); i++ {
+                       tag_directive := &default_tag_directives[i]
+                       if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) {
+                               return false
+                       }
+               }
+
+               implicit := event.implicit
+               if !first || emitter.canonical {
+                       implicit = false
+               }
+
+               if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) {
+                       if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
+                               return false
+                       }
+                       if !yaml_emitter_write_indent(emitter) {
+                               return false
+                       }
+               }
+
+               if event.version_directive != nil {
+                       implicit = false
+                       if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) {
+                               return false
+                       }
+                       if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) {
+                               return false
+                       }
+                       if !yaml_emitter_write_indent(emitter) {
+                               return false
+                       }
+               }
+
+               if len(event.tag_directives) > 0 {
+                       implicit = false
+                       for i := 0; i < len(event.tag_directives); i++ {
+                               tag_directive := &event.tag_directives[i]
+                               if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) {
+                                       return false
+                               }
+                               if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) {
+                                       return false
+                               }
+                               if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) {
+                                       return false
+                               }
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                       }
+               }
+
+               if yaml_emitter_check_empty_document(emitter) {
+                       implicit = false
+               }
+               if !implicit {
+                       if !yaml_emitter_write_indent(emitter) {
+                               return false
+                       }
+                       if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) {
+                               return false
+                       }
+                       if emitter.canonical || true {
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                       }
+               }
+
+               if len(emitter.head_comment) > 0 {
+                       if !yaml_emitter_process_head_comment(emitter) {
+                               return false
+                       }
+                       if !put_break(emitter) {
+                               return false
+                       }
+               }
+
+               emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE
+               return true
+       }
+
+       if event.typ == yaml_STREAM_END_EVENT {
+               if emitter.open_ended {
+                       if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
+                               return false
+                       }
+                       if !yaml_emitter_write_indent(emitter) {
+                               return false
+                       }
+               }
+               if !yaml_emitter_flush(emitter) {
+                       return false
+               }
+               emitter.state = yaml_EMIT_END_STATE
+               return true
+       }
+
+       return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END")
+}
+
+// Expect the root node.
+func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+       emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE)
+
+       if !yaml_emitter_process_head_comment(emitter) {
+               return false
+       }
+       if !yaml_emitter_emit_node(emitter, event, true, false, false, false) {
+               return false
+       }
+       if !yaml_emitter_process_line_comment(emitter) {
+               return false
+       }
+       if !yaml_emitter_process_foot_comment(emitter) {
+               return false
+       }
+       return true
+}
+
+// Expect DOCUMENT-END.
+func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+       if event.typ != yaml_DOCUMENT_END_EVENT {
+               return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END")
+       }
+       if !yaml_emitter_write_indent(emitter) {
+               return false
+       }
+       if len(emitter.foot_comment) > 0 {
+               if !put_break(emitter) {
+                       return false
+               }
+               if !yaml_emitter_process_foot_comment(emitter) {
+                       return false
+               }
+       }
+       if !event.implicit {
+               // [Go] Allocate the slice elsewhere.
+               if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
+                       return false
+               }
+               if !yaml_emitter_write_indent(emitter) {
+                       return false
+               }
+       }
+       if !yaml_emitter_flush(emitter) {
+               return false
+       }
+       emitter.state = yaml_EMIT_DOCUMENT_START_STATE
+       emitter.tag_directives = emitter.tag_directives[:0]
+       return true
+}
+
+// Expect a flow item node.
+func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool {
+       if first {
+               if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) {
+                       return false
+               }
+               if !yaml_emitter_increase_indent(emitter, true, false) {
+                       return false
+               }
+               emitter.flow_level++
+       }
+
+       if event.typ == yaml_SEQUENCE_END_EVENT {
+               emitter.flow_level--
+               emitter.indent = emitter.indents[len(emitter.indents)-1]
+               emitter.indents = emitter.indents[:len(emitter.indents)-1]
+               if emitter.canonical && !first {
+                       if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+                               return false
+                       }
+                       if !yaml_emitter_write_indent(emitter) {
+                               return false
+                       }
+               }
+               if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) {
+                       return false
+               }
+               if !yaml_emitter_process_line_comment(emitter) {
+                       return false
+               }
+               if !yaml_emitter_process_foot_comment(emitter) {
+                       return false
+               }
+               emitter.state = emitter.states[len(emitter.states)-1]
+               emitter.states = emitter.states[:len(emitter.states)-1]
+
+               return true
+       }
+
+       if !first && !trail {
+               if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+                       return false
+               }
+       }
+
+       if !yaml_emitter_process_head_comment(emitter) {
+               return false
+       }
+       if emitter.column == 0 {
+               if !yaml_emitter_write_indent(emitter) {
+                       return false
+               }
+       }
+
+       if emitter.canonical || emitter.column > emitter.best_width {
+               if !yaml_emitter_write_indent(emitter) {
+                       return false
+               }
+       }
+       if len(emitter.line_comment) > 0 || len(emitter.foot_comment) > 0 {
+               emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE)
+       } else {
+               emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE)
+       }
+       if !yaml_emitter_emit_node(emitter, event, false, true, false, false) {
+               return false
+       }
+       if len(emitter.line_comment) > 0 || len(emitter.foot_comment) > 0 {
+               if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+                       return false
+               }
+       }
+       if !yaml_emitter_process_line_comment(emitter) {
+               return false
+       }
+       if !yaml_emitter_process_foot_comment(emitter) {
+               return false
+       }
+       return true
+}
+
+// Expect a flow key node.
+func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool {
+       if first {
+               if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) {
+                       return false
+               }
+               if !yaml_emitter_increase_indent(emitter, true, false) {
+                       return false
+               }
+               emitter.flow_level++
+       }
+
+       if event.typ == yaml_MAPPING_END_EVENT {
+               emitter.flow_level--
+               emitter.indent = emitter.indents[len(emitter.indents)-1]
+               emitter.indents = emitter.indents[:len(emitter.indents)-1]
+               if emitter.canonical && !first {
+                       if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+                               return false
+                       }
+                       if !yaml_emitter_write_indent(emitter) {
+                               return false
+                       }
+               }
+               if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) {
+                       return false
+               }
+               if !yaml_emitter_process_line_comment(emitter) {
+                       return false
+               }
+               if !yaml_emitter_process_foot_comment(emitter) {
+                       return false
+               }
+               emitter.state = emitter.states[len(emitter.states)-1]
+               emitter.states = emitter.states[:len(emitter.states)-1]
+               return true
+       }
+
+       if !first && !trail {
+               if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+                       return false
+               }
+       }
+
+       if !yaml_emitter_process_head_comment(emitter) {
+               return false
+       }
+       if emitter.column == 0 {
+               if !yaml_emitter_write_indent(emitter) {
+                       return false
+               }
+       }
+
+       if emitter.canonical || emitter.column > emitter.best_width {
+               if !yaml_emitter_write_indent(emitter) {
+                       return false
+               }
+       }
+
+       if !emitter.canonical && yaml_emitter_check_simple_key(emitter) {
+               emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)
+               return yaml_emitter_emit_node(emitter, event, false, false, true, true)
+       }
+       if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) {
+               return false
+       }
+       emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE)
+       return yaml_emitter_emit_node(emitter, event, false, false, true, false)
+}
+
+// Expect a flow value node.
+func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
+       if simple {
+               if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
+                       return false
+               }
+       } else {
+               if emitter.canonical || emitter.column > emitter.best_width {
+                       if !yaml_emitter_write_indent(emitter) {
+                               return false
+                       }
+               }
+               if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) {
+                       return false
+               }
+       }
+       if len(emitter.line_comment) > 0 || len(emitter.foot_comment) > 0 {
+               emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE)
+       } else {
+               emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE)
+       }
+       if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
+               return false
+       }
+       if len(emitter.line_comment) > 0 || len(emitter.foot_comment) > 0 {
+               if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+                       return false
+               }
+       }
+       if !yaml_emitter_process_line_comment(emitter) {
+               return false
+       }
+       if !yaml_emitter_process_foot_comment(emitter) {
+               return false
+       }
+       return true
+}
+
+// Expect a block item node.
+func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+       if first {
+               if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) {
+                       return false
+               }
+       }
+       if event.typ == yaml_SEQUENCE_END_EVENT {
+               emitter.indent = emitter.indents[len(emitter.indents)-1]
+               emitter.indents = emitter.indents[:len(emitter.indents)-1]
+               emitter.state = emitter.states[len(emitter.states)-1]
+               emitter.states = emitter.states[:len(emitter.states)-1]
+               return true
+       }
+       if !yaml_emitter_process_head_comment(emitter) {
+               return false
+       }
+       if !yaml_emitter_write_indent(emitter) {
+               return false
+       }
+       if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) {
+               return false
+       }
+       emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE)
+       if !yaml_emitter_emit_node(emitter, event, false, true, false, false) {
+               return false
+       }
+       if !yaml_emitter_process_line_comment(emitter) {
+               return false
+       }
+       if !yaml_emitter_process_foot_comment(emitter) {
+               return false
+       }
+       return true
+}
+
+// Expect a block key node.
+func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+       if first {
+               if !yaml_emitter_increase_indent(emitter, false, false) {
+                       return false
+               }
+       }
+       if event.typ == yaml_MAPPING_END_EVENT {
+               emitter.indent = emitter.indents[len(emitter.indents)-1]
+               emitter.indents = emitter.indents[:len(emitter.indents)-1]
+               emitter.state = emitter.states[len(emitter.states)-1]
+               emitter.states = emitter.states[:len(emitter.states)-1]
+               return true
+       }
+       if !yaml_emitter_process_head_comment(emitter) {
+               return false
+       }
+       if emitter.states[len(emitter.states)-1] != yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE {
+               if !yaml_emitter_write_indent(emitter) {
+                       return false
+               }
+       }
+       if yaml_emitter_check_simple_key(emitter) {
+               emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)
+               return yaml_emitter_emit_node(emitter, event, false, false, true, true)
+       }
+       if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) {
+               return false
+       }
+       emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE)
+       return yaml_emitter_emit_node(emitter, event, false, false, true, false)
+}
+
+// Expect a block value node.
+func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
+       if simple {
+               if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
+                       return false
+               }
+       } else {
+               if !yaml_emitter_write_indent(emitter) {
+                       return false
+               }
+               if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) {
+                       return false
+               }
+       }
+       emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE)
+       if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
+               return false
+       }
+       if !yaml_emitter_process_line_comment(emitter) {
+               return false
+       }
+       if !yaml_emitter_process_foot_comment(emitter) {
+               return false
+       }
+       return true
+}
+
+// Expect a node.
+func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
+       root bool, sequence bool, mapping bool, simple_key bool) bool {
+
+       emitter.root_context = root
+       emitter.sequence_context = sequence
+       emitter.mapping_context = mapping
+       emitter.simple_key_context = simple_key
+
+       switch event.typ {
+       case yaml_ALIAS_EVENT:
+               return yaml_emitter_emit_alias(emitter, event)
+       case yaml_SCALAR_EVENT:
+               return yaml_emitter_emit_scalar(emitter, event)
+       case yaml_SEQUENCE_START_EVENT:
+               return yaml_emitter_emit_sequence_start(emitter, event)
+       case yaml_MAPPING_START_EVENT:
+               return yaml_emitter_emit_mapping_start(emitter, event)
+       default:
+               return yaml_emitter_set_emitter_error(emitter,
+                       fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ))
+       }
+}
+
+// Expect ALIAS.
+func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+       if !yaml_emitter_process_anchor(emitter) {
+               return false
+       }
+       emitter.state = emitter.states[len(emitter.states)-1]
+       emitter.states = emitter.states[:len(emitter.states)-1]
+       return true
+}
+
+// Expect SCALAR.
+func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+       if !yaml_emitter_select_scalar_style(emitter, event) {
+               return false
+       }
+       if !yaml_emitter_process_anchor(emitter) {
+               return false
+       }
+       if !yaml_emitter_process_tag(emitter) {
+               return false
+       }
+       if !yaml_emitter_increase_indent(emitter, true, false) {
+               return false
+       }
+       if !yaml_emitter_process_scalar(emitter) {
+               return false
+       }
+       emitter.indent = emitter.indents[len(emitter.indents)-1]
+       emitter.indents = emitter.indents[:len(emitter.indents)-1]
+       emitter.state = emitter.states[len(emitter.states)-1]
+       emitter.states = emitter.states[:len(emitter.states)-1]
+       return true
+}
+
+// Expect SEQUENCE-START.
+func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+       if !yaml_emitter_process_anchor(emitter) {
+               return false
+       }
+       if !yaml_emitter_process_tag(emitter) {
+               return false
+       }
+       if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE ||
+               yaml_emitter_check_empty_sequence(emitter) {
+               emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE
+       } else {
+               emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE
+       }
+       return true
+}
+
+// Expect MAPPING-START.
+func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+       if !yaml_emitter_process_anchor(emitter) {
+               return false
+       }
+       if !yaml_emitter_process_tag(emitter) {
+               return false
+       }
+       if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE ||
+               yaml_emitter_check_empty_mapping(emitter) {
+               emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE
+       } else {
+               emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE
+       }
+       return true
+}
+
+// Check if the document content is an empty scalar.
+func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool {
+       return false // [Go] Huh?
+}
+
+// Check if the next events represent an empty sequence.
+func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool {
+       if len(emitter.events)-emitter.events_head < 2 {
+               return false
+       }
+       return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT &&
+               emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT
+}
+
+// Check if the next events represent an empty mapping.
+func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool {
+       if len(emitter.events)-emitter.events_head < 2 {
+               return false
+       }
+       return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT &&
+               emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT
+}
+
+// Check if the next node can be expressed as a simple key.
+func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool {
+       length := 0
+       switch emitter.events[emitter.events_head].typ {
+       case yaml_ALIAS_EVENT:
+               length += len(emitter.anchor_data.anchor)
+       case yaml_SCALAR_EVENT:
+               if emitter.scalar_data.multiline {
+                       return false
+               }
+               length += len(emitter.anchor_data.anchor) +
+                       len(emitter.tag_data.handle) +
+                       len(emitter.tag_data.suffix) +
+                       len(emitter.scalar_data.value)
+       case yaml_SEQUENCE_START_EVENT:
+               if !yaml_emitter_check_empty_sequence(emitter) {
+                       return false
+               }
+               length += len(emitter.anchor_data.anchor) +
+                       len(emitter.tag_data.handle) +
+                       len(emitter.tag_data.suffix)
+       case yaml_MAPPING_START_EVENT:
+               if !yaml_emitter_check_empty_mapping(emitter) {
+                       return false
+               }
+               length += len(emitter.anchor_data.anchor) +
+                       len(emitter.tag_data.handle) +
+                       len(emitter.tag_data.suffix)
+       default:
+               return false
+       }
+       return length <= 128
+}
+
+// Determine an acceptable scalar style.
+func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+
+       no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0
+       if no_tag && !event.implicit && !event.quoted_implicit {
+               return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified")
+       }
+
+       style := event.scalar_style()
+       if style == yaml_ANY_SCALAR_STYLE {
+               style = yaml_PLAIN_SCALAR_STYLE
+       }
+       if emitter.canonical {
+               style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+       }
+       if emitter.simple_key_context && emitter.scalar_data.multiline {
+               style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+       }
+
+       if style == yaml_PLAIN_SCALAR_STYLE {
+               if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed ||
+                       emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed {
+                       style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+               }
+               if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) {
+                       style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+               }
+               if no_tag && !event.implicit {
+                       style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+               }
+       }
+       if style == yaml_SINGLE_QUOTED_SCALAR_STYLE {
+               if !emitter.scalar_data.single_quoted_allowed {
+                       style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+               }
+       }
+       if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE {
+               if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context {
+                       style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+               }
+       }
+
+       if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE {
+               emitter.tag_data.handle = []byte{'!'}
+       }
+       emitter.scalar_data.style = style
+       return true
+}
+
+// Write an anchor.
+func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
+       if emitter.anchor_data.anchor == nil {
+               return true
+       }
+       c := []byte{'&'}
+       if emitter.anchor_data.alias {
+               c[0] = '*'
+       }
+       if !yaml_emitter_write_indicator(emitter, c, true, false, false) {
+               return false
+       }
+       return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor)
+}
+
+// Write a tag.
+func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool {
+       if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 {
+               return true
+       }
+       if len(emitter.tag_data.handle) > 0 {
+               if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) {
+                       return false
+               }
+               if len(emitter.tag_data.suffix) > 0 {
+                       if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
+                               return false
+                       }
+               }
+       } else {
+               // [Go] Allocate these slices elsewhere.
+               if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) {
+                       return false
+               }
+               if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
+                       return false
+               }
+               if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) {
+                       return false
+               }
+       }
+       return true
+}
+
+// Write a scalar.
+func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool {
+       switch emitter.scalar_data.style {
+       case yaml_PLAIN_SCALAR_STYLE:
+               return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
+
+       case yaml_SINGLE_QUOTED_SCALAR_STYLE:
+               return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
+
+       case yaml_DOUBLE_QUOTED_SCALAR_STYLE:
+               return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
+
+       case yaml_LITERAL_SCALAR_STYLE:
+               return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value)
+
+       case yaml_FOLDED_SCALAR_STYLE:
+               return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value)
+       }
+       panic("unknown scalar style")
+}
+
+// Write a head comment.
+func yaml_emitter_process_head_comment(emitter *yaml_emitter_t) bool {
+       if len(emitter.head_comment) == 0 {
+               return true
+       }
+       space_above := emitter.space_above
+       if !emitter.indention {
+               if !put_break(emitter) {
+                       return false
+               }
+       }
+       if !space_above &&
+               emitter.state != yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE &&
+               emitter.state != yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE &&
+               emitter.state != yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE &&
+               emitter.state != yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE {
+               if !put_break(emitter) {
+                       return false
+               }
+       }
+       if !yaml_emitter_write_indent(emitter) {
+               return false
+       }
+       if !yaml_emitter_write_comment(emitter, emitter.head_comment) {
+               return false
+       }
+       emitter.head_comment = emitter.head_comment[:0]
+       return true
+}
+
+// Write an line comment.
+func yaml_emitter_process_line_comment(emitter *yaml_emitter_t) bool {
+       if len(emitter.line_comment) == 0 {
+               return true
+       }
+       if !emitter.whitespace {
+               if !put(emitter, ' ') {
+                       return false
+               }
+       }
+       if !yaml_emitter_write_comment(emitter, emitter.line_comment) {
+               return false
+       }
+       emitter.line_comment = emitter.line_comment[:0]
+       return true
+}
+
+// Write a foot comment.
+func yaml_emitter_process_foot_comment(emitter *yaml_emitter_t) bool {
+       if len(emitter.foot_comment) == 0 {
+               return true
+       }
+       if !yaml_emitter_write_indent(emitter) {
+               return false
+       }
+       if !yaml_emitter_write_comment(emitter, emitter.foot_comment) {
+               return false
+       }
+       emitter.foot_comment = emitter.foot_comment[:0]
+       return true
+}
+
+// Check if a %YAML directive is valid.
+func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool {
+       if version_directive.major != 1 || version_directive.minor != 1 {
+               return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive")
+       }
+       return true
+}
+
+// Check if a %TAG directive is valid.
+func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool {
+       handle := tag_directive.handle
+       prefix := tag_directive.prefix
+       if len(handle) == 0 {
+               return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty")
+       }
+       if handle[0] != '!' {
+               return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'")
+       }
+       if handle[len(handle)-1] != '!' {
+               return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'")
+       }
+       for i := 1; i < len(handle)-1; i += width(handle[i]) {
+               if !is_alpha(handle, i) {
+                       return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only")
+               }
+       }
+       if len(prefix) == 0 {
+               return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty")
+       }
+       return true
+}
+
+// Check if an anchor is valid.
+func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool {
+       if len(anchor) == 0 {
+               problem := "anchor value must not be empty"
+               if alias {
+                       problem = "alias value must not be empty"
+               }
+               return yaml_emitter_set_emitter_error(emitter, problem)
+       }
+       for i := 0; i < len(anchor); i += width(anchor[i]) {
+               if !is_alpha(anchor, i) {
+                       problem := "anchor value must contain alphanumerical characters only"
+                       if alias {
+                               problem = "alias value must contain alphanumerical characters only"
+                       }
+                       return yaml_emitter_set_emitter_error(emitter, problem)
+               }
+       }
+       emitter.anchor_data.anchor = anchor
+       emitter.anchor_data.alias = alias
+       return true
+}
+
+// Check if a tag is valid.
+func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool {
+       if len(tag) == 0 {
+               return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty")
+       }
+       for i := 0; i < len(emitter.tag_directives); i++ {
+               tag_directive := &emitter.tag_directives[i]
+               if bytes.HasPrefix(tag, tag_directive.prefix) {
+                       emitter.tag_data.handle = tag_directive.handle
+                       emitter.tag_data.suffix = tag[len(tag_directive.prefix):]
+                       return true
+               }
+       }
+       emitter.tag_data.suffix = tag
+       return true
+}
+
+// Check if a scalar is valid.
+func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
+       var (
+               block_indicators   = false
+               flow_indicators    = false
+               line_breaks        = false
+               special_characters = false
+
+               leading_space  = false
+               leading_break  = false
+               trailing_space = false
+               trailing_break = false
+               break_space    = false
+               space_break    = false
+
+               preceded_by_whitespace = false
+               followed_by_whitespace = false
+               previous_space         = false
+               previous_break         = false
+       )
+
+       emitter.scalar_data.value = value
+
+       if len(value) == 0 {
+               emitter.scalar_data.multiline = false
+               emitter.scalar_data.flow_plain_allowed = false
+               emitter.scalar_data.block_plain_allowed = true
+               emitter.scalar_data.single_quoted_allowed = true
+               emitter.scalar_data.block_allowed = false
+               return true
+       }
+
+       if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) {
+               block_indicators = true
+               flow_indicators = true
+       }
+
+       preceded_by_whitespace = true
+       for i, w := 0, 0; i < len(value); i += w {
+               w = width(value[i])
+               followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
+
+               if i == 0 {
+                       switch value[i] {
+                       case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`':
+                               flow_indicators = true
+                               block_indicators = true
+                       case '?', ':':
+                               flow_indicators = true
+                               if followed_by_whitespace {
+                                       block_indicators = true
+                               }
+                       case '-':
+                               if followed_by_whitespace {
+                                       flow_indicators = true
+                                       block_indicators = true
+                               }
+                       }
+               } else {
+                       switch value[i] {
+                       case ',', '?', '[', ']', '{', '}':
+                               flow_indicators = true
+                       case ':':
+                               flow_indicators = true
+                               if followed_by_whitespace {
+                                       block_indicators = true
+                               }
+                       case '#':
+                               if preceded_by_whitespace {
+                                       flow_indicators = true
+                                       block_indicators = true
+                               }
+                       }
+               }
+
+               if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode {
+                       special_characters = true
+               }
+               if is_space(value, i) {
+                       if i == 0 {
+                               leading_space = true
+                       }
+                       if i+width(value[i]) == len(value) {
+                               trailing_space = true
+                       }
+                       if previous_break {
+                               break_space = true
+                       }
+                       previous_space = true
+                       previous_break = false
+               } else if is_break(value, i) {
+                       line_breaks = true
+                       if i == 0 {
+                               leading_break = true
+                       }
+                       if i+width(value[i]) == len(value) {
+                               trailing_break = true
+                       }
+                       if previous_space {
+                               space_break = true
+                       }
+                       previous_space = false
+                       previous_break = true
+               } else {
+                       previous_space = false
+                       previous_break = false
+               }
+
+               // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
+               preceded_by_whitespace = is_blankz(value, i)
+       }
+
+       emitter.scalar_data.multiline = line_breaks
+       emitter.scalar_data.flow_plain_allowed = true
+       emitter.scalar_data.block_plain_allowed = true
+       emitter.scalar_data.single_quoted_allowed = true
+       emitter.scalar_data.block_allowed = true
+
+       if leading_space || leading_break || trailing_space || trailing_break {
+               emitter.scalar_data.flow_plain_allowed = false
+               emitter.scalar_data.block_plain_allowed = false
+       }
+       if trailing_space {
+               emitter.scalar_data.block_allowed = false
+       }
+       if break_space {
+               emitter.scalar_data.flow_plain_allowed = false
+               emitter.scalar_data.block_plain_allowed = false
+               emitter.scalar_data.single_quoted_allowed = false
+       }
+       if space_break || special_characters {
+               emitter.scalar_data.flow_plain_allowed = false
+               emitter.scalar_data.block_plain_allowed = false
+               emitter.scalar_data.single_quoted_allowed = false
+               emitter.scalar_data.block_allowed = false
+       }
+       if line_breaks {
+               emitter.scalar_data.flow_plain_allowed = false
+               emitter.scalar_data.block_plain_allowed = false
+       }
+       if flow_indicators {
+               emitter.scalar_data.flow_plain_allowed = false
+       }
+       if block_indicators {
+               emitter.scalar_data.block_plain_allowed = false
+       }
+       return true
+}
+
+// Check if the event data is valid.
+func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+
+       emitter.anchor_data.anchor = nil
+       emitter.tag_data.handle = nil
+       emitter.tag_data.suffix = nil
+       emitter.scalar_data.value = nil
+
+       if len(event.head_comment) > 0 {
+               emitter.head_comment = event.head_comment
+       }
+       if len(event.line_comment) > 0 {
+               emitter.line_comment = event.line_comment
+       }
+       if len(event.foot_comment) > 0 {
+               emitter.foot_comment = event.foot_comment
+       }
+
+       switch event.typ {
+       case yaml_ALIAS_EVENT:
+               if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) {
+                       return false
+               }
+
+       case yaml_SCALAR_EVENT:
+               if len(event.anchor) > 0 {
+                       if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
+                               return false
+                       }
+               }
+               if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) {
+                       if !yaml_emitter_analyze_tag(emitter, event.tag) {
+                               return false
+                       }
+               }
+               if !yaml_emitter_analyze_scalar(emitter, event.value) {
+                       return false
+               }
+
+       case yaml_SEQUENCE_START_EVENT:
+               if len(event.anchor) > 0 {
+                       if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
+                               return false
+                       }
+               }
+               if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
+                       if !yaml_emitter_analyze_tag(emitter, event.tag) {
+                               return false
+                       }
+               }
+
+       case yaml_MAPPING_START_EVENT:
+               if len(event.anchor) > 0 {
+                       if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
+                               return false
+                       }
+               }
+               if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
+                       if !yaml_emitter_analyze_tag(emitter, event.tag) {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
+// Write the BOM character.
+func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool {
+       if !flush(emitter) {
+               return false
+       }
+       pos := emitter.buffer_pos
+       emitter.buffer[pos+0] = '\xEF'
+       emitter.buffer[pos+1] = '\xBB'
+       emitter.buffer[pos+2] = '\xBF'
+       emitter.buffer_pos += 3
+       return true
+}
+
+func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool {
+       indent := emitter.indent
+       if indent < 0 {
+               indent = 0
+       }
+       if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) {
+               if !put_break(emitter) {
+                       return false
+               }
+       }
+       for emitter.column < indent {
+               if !put(emitter, ' ') {
+                       return false
+               }
+       }
+       emitter.whitespace = true
+       //emitter.indention = true
+       emitter.space_above = false
+       return true
+}
+
+func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool {
+       if need_whitespace && !emitter.whitespace {
+               if !put(emitter, ' ') {
+                       return false
+               }
+       }
+       if !write_all(emitter, indicator) {
+               return false
+       }
+       emitter.whitespace = is_whitespace
+       emitter.indention = (emitter.indention && is_indention)
+       emitter.open_ended = false
+       return true
+}
+
+func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool {
+       if !write_all(emitter, value) {
+               return false
+       }
+       emitter.whitespace = false
+       emitter.indention = false
+       return true
+}
+
+func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool {
+       if !emitter.whitespace {
+               if !put(emitter, ' ') {
+                       return false
+               }
+       }
+       if !write_all(emitter, value) {
+               return false
+       }
+       emitter.whitespace = false
+       emitter.indention = false
+       return true
+}
+
+func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool {
+       if need_whitespace && !emitter.whitespace {
+               if !put(emitter, ' ') {
+                       return false
+               }
+       }
+       for i := 0; i < len(value); {
+               var must_write bool
+               switch value[i] {
+               case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']':
+                       must_write = true
+               default:
+                       must_write = is_alpha(value, i)
+               }
+               if must_write {
+                       if !write(emitter, value, &i) {
+                               return false
+                       }
+               } else {
+                       w := width(value[i])
+                       for k := 0; k < w; k++ {
+                               octet := value[i]
+                               i++
+                               if !put(emitter, '%') {
+                                       return false
+                               }
+
+                               c := octet >> 4
+                               if c < 10 {
+                                       c += '0'
+                               } else {
+                                       c += 'A' - 10
+                               }
+                               if !put(emitter, c) {
+                                       return false
+                               }
+
+                               c = octet & 0x0f
+                               if c < 10 {
+                                       c += '0'
+                               } else {
+                                       c += 'A' - 10
+                               }
+                               if !put(emitter, c) {
+                                       return false
+                               }
+                       }
+               }
+       }
+       emitter.whitespace = false
+       emitter.indention = false
+       return true
+}
+
+func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
+       if !emitter.whitespace {
+               if !put(emitter, ' ') {
+                       return false
+               }
+       }
+
+       spaces := false
+       breaks := false
+       for i := 0; i < len(value); {
+               if is_space(value, i) {
+                       if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) {
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                               i += width(value[i])
+                       } else {
+                               if !write(emitter, value, &i) {
+                                       return false
+                               }
+                       }
+                       spaces = true
+               } else if is_break(value, i) {
+                       if !breaks && value[i] == '\n' {
+                               if !put_break(emitter) {
+                                       return false
+                               }
+                       }
+                       if !write_break(emitter, value, &i) {
+                               return false
+                       }
+                       //emitter.indention = true
+                       breaks = true
+               } else {
+                       if breaks {
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                       }
+                       if !write(emitter, value, &i) {
+                               return false
+                       }
+                       emitter.indention = false
+                       spaces = false
+                       breaks = false
+               }
+       }
+
+       emitter.whitespace = false
+       emitter.indention = false
+       if emitter.root_context {
+               emitter.open_ended = true
+       }
+
+       return true
+}
+
+func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
+
+       if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) {
+               return false
+       }
+
+       spaces := false
+       breaks := false
+       for i := 0; i < len(value); {
+               if is_space(value, i) {
+                       if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) {
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                               i += width(value[i])
+                       } else {
+                               if !write(emitter, value, &i) {
+                                       return false
+                               }
+                       }
+                       spaces = true
+               } else if is_break(value, i) {
+                       if !breaks && value[i] == '\n' {
+                               if !put_break(emitter) {
+                                       return false
+                               }
+                       }
+                       if !write_break(emitter, value, &i) {
+                               return false
+                       }
+                       //emitter.indention = true
+                       breaks = true
+               } else {
+                       if breaks {
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                       }
+                       if value[i] == '\'' {
+                               if !put(emitter, '\'') {
+                                       return false
+                               }
+                       }
+                       if !write(emitter, value, &i) {
+                               return false
+                       }
+                       emitter.indention = false
+                       spaces = false
+                       breaks = false
+               }
+       }
+       if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) {
+               return false
+       }
+       emitter.whitespace = false
+       emitter.indention = false
+       return true
+}
+
+func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
+       spaces := false
+       if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) {
+               return false
+       }
+
+       for i := 0; i < len(value); {
+               if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) ||
+                       is_bom(value, i) || is_break(value, i) ||
+                       value[i] == '"' || value[i] == '\\' {
+
+                       octet := value[i]
+
+                       var w int
+                       var v rune
+                       switch {
+                       case octet&0x80 == 0x00:
+                               w, v = 1, rune(octet&0x7F)
+                       case octet&0xE0 == 0xC0:
+                               w, v = 2, rune(octet&0x1F)
+                       case octet&0xF0 == 0xE0:
+                               w, v = 3, rune(octet&0x0F)
+                       case octet&0xF8 == 0xF0:
+                               w, v = 4, rune(octet&0x07)
+                       }
+                       for k := 1; k < w; k++ {
+                               octet = value[i+k]
+                               v = (v << 6) + (rune(octet) & 0x3F)
+                       }
+                       i += w
+
+                       if !put(emitter, '\\') {
+                               return false
+                       }
+
+                       var ok bool
+                       switch v {
+                       case 0x00:
+                               ok = put(emitter, '0')
+                       case 0x07:
+                               ok = put(emitter, 'a')
+                       case 0x08:
+                               ok = put(emitter, 'b')
+                       case 0x09:
+                               ok = put(emitter, 't')
+                       case 0x0A:
+                               ok = put(emitter, 'n')
+                       case 0x0b:
+                               ok = put(emitter, 'v')
+                       case 0x0c:
+                               ok = put(emitter, 'f')
+                       case 0x0d:
+                               ok = put(emitter, 'r')
+                       case 0x1b:
+                               ok = put(emitter, 'e')
+                       case 0x22:
+                               ok = put(emitter, '"')
+                       case 0x5c:
+                               ok = put(emitter, '\\')
+                       case 0x85:
+                               ok = put(emitter, 'N')
+                       case 0xA0:
+                               ok = put(emitter, '_')
+                       case 0x2028:
+                               ok = put(emitter, 'L')
+                       case 0x2029:
+                               ok = put(emitter, 'P')
+                       default:
+                               if v <= 0xFF {
+                                       ok = put(emitter, 'x')
+                                       w = 2
+                               } else if v <= 0xFFFF {
+                                       ok = put(emitter, 'u')
+                                       w = 4
+                               } else {
+                                       ok = put(emitter, 'U')
+                                       w = 8
+                               }
+                               for k := (w - 1) * 4; ok && k >= 0; k -= 4 {
+                                       digit := byte((v >> uint(k)) & 0x0F)
+                                       if digit < 10 {
+                                               ok = put(emitter, digit+'0')
+                                       } else {
+                                               ok = put(emitter, digit+'A'-10)
+                                       }
+                               }
+                       }
+                       if !ok {
+                               return false
+                       }
+                       spaces = false
+               } else if is_space(value, i) {
+                       if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 {
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                               if is_space(value, i+1) {
+                                       if !put(emitter, '\\') {
+                                               return false
+                                       }
+                               }
+                               i += width(value[i])
+                       } else if !write(emitter, value, &i) {
+                               return false
+                       }
+                       spaces = true
+               } else {
+                       if !write(emitter, value, &i) {
+                               return false
+                       }
+                       spaces = false
+               }
+       }
+       if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) {
+               return false
+       }
+       emitter.whitespace = false
+       emitter.indention = false
+       return true
+}
+
+func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool {
+       if is_space(value, 0) || is_break(value, 0) {
+               indent_hint := []byte{'0' + byte(emitter.best_indent)}
+               if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) {
+                       return false
+               }
+       }
+
+       emitter.open_ended = false
+
+       var chomp_hint [1]byte
+       if len(value) == 0 {
+               chomp_hint[0] = '-'
+       } else {
+               i := len(value) - 1
+               for value[i]&0xC0 == 0x80 {
+                       i--
+               }
+               if !is_break(value, i) {
+                       chomp_hint[0] = '-'
+               } else if i == 0 {
+                       chomp_hint[0] = '+'
+                       emitter.open_ended = true
+               } else {
+                       i--
+                       for value[i]&0xC0 == 0x80 {
+                               i--
+                       }
+                       if is_break(value, i) {
+                               chomp_hint[0] = '+'
+                               emitter.open_ended = true
+                       }
+               }
+       }
+       if chomp_hint[0] != 0 {
+               if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) {
+                       return false
+               }
+       }
+       return true
+}
+
+func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool {
+       if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) {
+               return false
+       }
+       if !yaml_emitter_write_block_scalar_hints(emitter, value) {
+               return false
+       }
+       if !put_break(emitter) {
+               return false
+       }
+       //emitter.indention = true
+       emitter.whitespace = true
+       breaks := true
+       for i := 0; i < len(value); {
+               if is_break(value, i) {
+                       if !write_break(emitter, value, &i) {
+                               return false
+                       }
+                       //emitter.indention = true
+                       breaks = true
+               } else {
+                       if breaks {
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                       }
+                       if !write(emitter, value, &i) {
+                               return false
+                       }
+                       emitter.indention = false
+                       breaks = false
+               }
+       }
+
+       return true
+}
+
+func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool {
+       if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) {
+               return false
+       }
+       if !yaml_emitter_write_block_scalar_hints(emitter, value) {
+               return false
+       }
+
+       if !put_break(emitter) {
+               return false
+       }
+       //emitter.indention = true
+       emitter.whitespace = true
+
+       breaks := true
+       leading_spaces := true
+       for i := 0; i < len(value); {
+               if is_break(value, i) {
+                       if !breaks && !leading_spaces && value[i] == '\n' {
+                               k := 0
+                               for is_break(value, k) {
+                                       k += width(value[k])
+                               }
+                               if !is_blankz(value, k) {
+                                       if !put_break(emitter) {
+                                               return false
+                                       }
+                               }
+                       }
+                       if !write_break(emitter, value, &i) {
+                               return false
+                       }
+                       //emitter.indention = true
+                       breaks = true
+               } else {
+                       if breaks {
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                               leading_spaces = is_blank(value, i)
+                       }
+                       if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width {
+                               if !yaml_emitter_write_indent(emitter) {
+                                       return false
+                               }
+                               i += width(value[i])
+                       } else {
+                               if !write(emitter, value, &i) {
+                                       return false
+                               }
+                       }
+                       emitter.indention = false
+                       breaks = false
+               }
+       }
+       return true
+}
+
+func yaml_emitter_write_comment(emitter *yaml_emitter_t, comment []byte) bool {
+       breaks := false
+       pound := false
+       for i := 0; i < len(comment); {
+               if is_break(comment, i) {
+                       if !write_break(emitter, comment, &i) {
+                               return false
+                       }
+                       //emitter.indention = true
+                       breaks = true
+                       pound = false
+               } else {
+                       if breaks && !yaml_emitter_write_indent(emitter) {
+                               return false
+                       }
+                       if !pound {
+                               if comment[i] != '#' && (!put(emitter, '#') || !put(emitter, ' ')) {
+                                       return false
+                               }
+                               pound = true
+                       }
+                       if !write(emitter, comment, &i) {
+                               return false
+                       }
+                       emitter.indention = false
+                       breaks = false
+               }
+       }
+       if !breaks && !put_break(emitter) {
+               return false
+       }
+
+       emitter.whitespace = true
+       //emitter.indention = true
+       return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/encode.go b/vendor/gopkg.in/yaml.v3/encode.go
new file mode 100644 (file)
index 0000000..95d9ad7
--- /dev/null
@@ -0,0 +1,524 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package yaml
+
+import (
+       "encoding"
+       "fmt"
+       "io"
+       "reflect"
+       "regexp"
+       "sort"
+       "strconv"
+       "strings"
+       "time"
+       "unicode/utf8"
+)
+
+type encoder struct {
+       emitter  yaml_emitter_t
+       event    yaml_event_t
+       out      []byte
+       flow     bool
+       indent   int
+       doneInit bool
+}
+
+func newEncoder() *encoder {
+       e := &encoder{}
+       yaml_emitter_initialize(&e.emitter)
+       yaml_emitter_set_output_string(&e.emitter, &e.out)
+       yaml_emitter_set_unicode(&e.emitter, true)
+       return e
+}
+
+func newEncoderWithWriter(w io.Writer) *encoder {
+       e := &encoder{}
+       yaml_emitter_initialize(&e.emitter)
+       yaml_emitter_set_output_writer(&e.emitter, w)
+       yaml_emitter_set_unicode(&e.emitter, true)
+       return e
+}
+
+func (e *encoder) init() {
+       if e.doneInit {
+               return
+       }
+       if e.indent == 0 {
+               e.indent = 4
+       }
+       e.emitter.best_indent = e.indent
+       yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
+       e.emit()
+       e.doneInit = true
+}
+
+func (e *encoder) finish() {
+       e.emitter.open_ended = false
+       yaml_stream_end_event_initialize(&e.event)
+       e.emit()
+}
+
+func (e *encoder) destroy() {
+       yaml_emitter_delete(&e.emitter)
+}
+
+func (e *encoder) emit() {
+       // This will internally delete the e.event value.
+       e.must(yaml_emitter_emit(&e.emitter, &e.event))
+}
+
+func (e *encoder) must(ok bool) {
+       if !ok {
+               msg := e.emitter.problem
+               if msg == "" {
+                       msg = "unknown problem generating YAML content"
+               }
+               failf("%s", msg)
+       }
+}
+
+func (e *encoder) marshalDoc(tag string, in reflect.Value) {
+       e.init()
+       var node *Node
+       if in.IsValid() {
+               node, _ = in.Interface().(*Node)
+       }
+       if node != nil && node.Kind == DocumentNode {
+               e.nodev(in)
+       } else {
+               yaml_document_start_event_initialize(&e.event, nil, nil, true)
+               e.emit()
+               e.marshal(tag, in)
+               yaml_document_end_event_initialize(&e.event, true)
+               e.emit()
+       }
+}
+
+func (e *encoder) marshal(tag string, in reflect.Value) {
+       tag = shortTag(tag)
+       if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
+               e.nilv()
+               return
+       }
+       iface := in.Interface()
+       switch value := iface.(type) {
+       case *Node:
+               e.nodev(in)
+               return
+       case time.Time:
+               e.timev(tag, in)
+               return
+       case *time.Time:
+               e.timev(tag, in.Elem())
+               return
+       case time.Duration:
+               e.stringv(tag, reflect.ValueOf(value.String()))
+               return
+       case Marshaler:
+               v, err := value.MarshalYAML()
+               if err != nil {
+                       fail(err)
+               }
+               if v == nil {
+                       e.nilv()
+                       return
+               }
+               e.marshal(tag, reflect.ValueOf(v))
+               return
+       case encoding.TextMarshaler:
+               text, err := value.MarshalText()
+               if err != nil {
+                       fail(err)
+               }
+               in = reflect.ValueOf(string(text))
+       case nil:
+               e.nilv()
+               return
+       }
+       switch in.Kind() {
+       case reflect.Interface:
+               e.marshal(tag, in.Elem())
+       case reflect.Map:
+               e.mapv(tag, in)
+       case reflect.Ptr:
+               e.marshal(tag, in.Elem())
+       case reflect.Struct:
+               e.structv(tag, in)
+       case reflect.Slice, reflect.Array:
+               e.slicev(tag, in)
+       case reflect.String:
+               e.stringv(tag, in)
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               e.intv(tag, in)
+       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+               e.uintv(tag, in)
+       case reflect.Float32, reflect.Float64:
+               e.floatv(tag, in)
+       case reflect.Bool:
+               e.boolv(tag, in)
+       default:
+               panic("cannot marshal type: " + in.Type().String())
+       }
+}
+
+func (e *encoder) mapv(tag string, in reflect.Value) {
+       e.mappingv(tag, func() {
+               keys := keyList(in.MapKeys())
+               sort.Sort(keys)
+               for _, k := range keys {
+                       e.marshal("", k)
+                       e.marshal("", in.MapIndex(k))
+               }
+       })
+}
+
+func (e *encoder) fieldByIndex(v reflect.Value, index []int) (field reflect.Value) {
+       for _, num := range index {
+               for {
+                       if v.Kind() == reflect.Ptr {
+                               if v.IsNil() {
+                                       return reflect.Value{}
+                               }
+                               v = v.Elem()
+                               continue
+                       }
+                       break
+               }
+               v = v.Field(num)
+       }
+       return v
+}
+
+func (e *encoder) structv(tag string, in reflect.Value) {
+       sinfo, err := getStructInfo(in.Type())
+       if err != nil {
+               panic(err)
+       }
+       e.mappingv(tag, func() {
+               for _, info := range sinfo.FieldsList {
+                       var value reflect.Value
+                       if info.Inline == nil {
+                               value = in.Field(info.Num)
+                       } else {
+                               value = e.fieldByIndex(in, info.Inline)
+                               if !value.IsValid() {
+                                       continue
+                               }
+                       }
+                       if info.OmitEmpty && isZero(value) {
+                               continue
+                       }
+                       e.marshal("", reflect.ValueOf(info.Key))
+                       e.flow = info.Flow
+                       e.marshal("", value)
+               }
+               if sinfo.InlineMap >= 0 {
+                       m := in.Field(sinfo.InlineMap)
+                       if m.Len() > 0 {
+                               e.flow = false
+                               keys := keyList(m.MapKeys())
+                               sort.Sort(keys)
+                               for _, k := range keys {
+                                       if _, found := sinfo.FieldsMap[k.String()]; found {
+                                               panic(fmt.Sprintf("cannot have key %q in inlined map: conflicts with struct field", k.String()))
+                                       }
+                                       e.marshal("", k)
+                                       e.flow = false
+                                       e.marshal("", m.MapIndex(k))
+                               }
+                       }
+               }
+       })
+}
+
+func (e *encoder) mappingv(tag string, f func()) {
+       implicit := tag == ""
+       style := yaml_BLOCK_MAPPING_STYLE
+       if e.flow {
+               e.flow = false
+               style = yaml_FLOW_MAPPING_STYLE
+       }
+       yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
+       e.emit()
+       f()
+       yaml_mapping_end_event_initialize(&e.event)
+       e.emit()
+}
+
+func (e *encoder) slicev(tag string, in reflect.Value) {
+       implicit := tag == ""
+       style := yaml_BLOCK_SEQUENCE_STYLE
+       if e.flow {
+               e.flow = false
+               style = yaml_FLOW_SEQUENCE_STYLE
+       }
+       e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
+       e.emit()
+       n := in.Len()
+       for i := 0; i < n; i++ {
+               e.marshal("", in.Index(i))
+       }
+       e.must(yaml_sequence_end_event_initialize(&e.event))
+       e.emit()
+}
+
+// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
+//
+// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
+// in YAML 1.2 and by this package, but these should be marshalled quoted for
+// the time being for compatibility with other parsers.
+func isBase60Float(s string) (result bool) {
+       // Fast path.
+       if s == "" {
+               return false
+       }
+       c := s[0]
+       if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
+               return false
+       }
+       // Do the full match.
+       return base60float.MatchString(s)
+}
+
+// From http://yaml.org/type/float.html, except the regular expression there
+// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
+var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
+
+func (e *encoder) stringv(tag string, in reflect.Value) {
+       var style yaml_scalar_style_t
+       s := in.String()
+       canUsePlain := true
+       switch {
+       case !utf8.ValidString(s):
+               if tag == binaryTag {
+                       failf("explicitly tagged !!binary data must be base64-encoded")
+               }
+               if tag != "" {
+                       failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
+               }
+               // It can't be encoded directly as YAML so use a binary tag
+               // and encode it as base64.
+               tag = binaryTag
+               s = encodeBase64(s)
+       case tag == "":
+               // Check to see if it would resolve to a specific
+               // tag when encoded unquoted. If it doesn't,
+               // there's no need to quote it.
+               rtag, _ := resolve("", s)
+               canUsePlain = rtag == strTag && !isBase60Float(s)
+       }
+       // Note: it's possible for user code to emit invalid YAML
+       // if they explicitly specify a tag and a string containing
+       // text that's incompatible with that tag.
+       switch {
+       case strings.Contains(s, "\n"):
+               style = yaml_LITERAL_SCALAR_STYLE
+       case canUsePlain:
+               style = yaml_PLAIN_SCALAR_STYLE
+       default:
+               style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+       }
+       e.emitScalar(s, "", tag, style, nil, nil, nil)
+}
+
+func (e *encoder) boolv(tag string, in reflect.Value) {
+       var s string
+       if in.Bool() {
+               s = "true"
+       } else {
+               s = "false"
+       }
+       e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
+}
+
+func (e *encoder) intv(tag string, in reflect.Value) {
+       s := strconv.FormatInt(in.Int(), 10)
+       e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
+}
+
+func (e *encoder) uintv(tag string, in reflect.Value) {
+       s := strconv.FormatUint(in.Uint(), 10)
+       e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
+}
+
+func (e *encoder) timev(tag string, in reflect.Value) {
+       t := in.Interface().(time.Time)
+       s := t.Format(time.RFC3339Nano)
+       e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
+}
+
+func (e *encoder) floatv(tag string, in reflect.Value) {
+       // Issue #352: When formatting, use the precision of the underlying value
+       precision := 64
+       if in.Kind() == reflect.Float32 {
+               precision = 32
+       }
+
+       s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
+       switch s {
+       case "+Inf":
+               s = ".inf"
+       case "-Inf":
+               s = "-.inf"
+       case "NaN":
+               s = ".nan"
+       }
+       e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
+}
+
+func (e *encoder) nilv() {
+       e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
+}
+
+func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot []byte) {
+       // TODO Kill this function. Replace all initialize calls by their underlining Go literals.
+       implicit := tag == ""
+       if !implicit {
+               tag = longTag(tag)
+       }
+       e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
+       e.event.head_comment = head
+       e.event.line_comment = line
+       e.event.foot_comment = foot
+       e.emit()
+}
+
+func (e *encoder) nodev(in reflect.Value) {
+       e.node(in.Interface().(*Node))
+}
+
+func (e *encoder) node(node *Node) {
+       // If the tag was not explicitly requested, and dropping it won't change the
+       // implicit tag of the value, don't include it in the presentation.
+       var tag = node.Tag
+       var stag = shortTag(tag)
+       var rtag string
+       var forceQuoting bool
+       if tag != "" && node.Style&TaggedStyle == 0 {
+               if node.Kind == ScalarNode {
+                       if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 {
+                               tag = ""
+                       } else {
+                               rtag, _ = resolve("", node.Value)
+                               if rtag == stag {
+                                       tag = ""
+                               } else if stag == strTag {
+                                       tag = ""
+                                       forceQuoting = true
+                               }
+                       }
+               } else {
+                       switch node.Kind {
+                       case MappingNode:
+                               rtag = mapTag
+                       case SequenceNode:
+                               rtag = seqTag
+                       }
+                       if rtag == stag {
+                               tag = ""
+                       }
+               }
+       }
+
+       switch node.Kind {
+       case DocumentNode:
+               yaml_document_start_event_initialize(&e.event, nil, nil, true)
+               e.event.head_comment = []byte(node.HeadComment)
+               e.emit()
+               for _, node := range node.Content {
+                       e.node(node)
+               }
+               yaml_document_end_event_initialize(&e.event, true)
+               e.event.foot_comment = []byte(node.FootComment)
+               e.emit()
+
+       case SequenceNode:
+               style := yaml_BLOCK_SEQUENCE_STYLE
+               if node.Style&FlowStyle != 0 {
+                       style = yaml_FLOW_SEQUENCE_STYLE
+               }
+               e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(tag), tag == "", style))
+               e.event.head_comment = []byte(node.HeadComment)
+               e.emit()
+               for _, node := range node.Content {
+                       e.node(node)
+               }
+               e.must(yaml_sequence_end_event_initialize(&e.event))
+               e.event.line_comment = []byte(node.LineComment)
+               e.event.foot_comment = []byte(node.FootComment)
+               e.emit()
+
+       case MappingNode:
+               style := yaml_BLOCK_MAPPING_STYLE
+               if node.Style&FlowStyle != 0 {
+                       style = yaml_FLOW_MAPPING_STYLE
+               }
+               yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(tag), tag == "", style)
+               e.event.head_comment = []byte(node.HeadComment)
+               e.emit()
+
+               for i := 0; i+1 < len(node.Content); i += 2 {
+                       e.node(node.Content[i])
+                       e.node(node.Content[i+1])
+               }
+
+               yaml_mapping_end_event_initialize(&e.event)
+               e.event.line_comment = []byte(node.LineComment)
+               e.event.foot_comment = []byte(node.FootComment)
+               e.emit()
+
+       case AliasNode:
+               yaml_alias_event_initialize(&e.event, []byte(node.Value))
+               e.event.head_comment = []byte(node.HeadComment)
+               e.event.line_comment = []byte(node.LineComment)
+               e.event.foot_comment = []byte(node.FootComment)
+               e.emit()
+
+       case ScalarNode:
+               value := node.Value
+               if !utf8.ValidString(value) {
+                       if tag == binaryTag {
+                               failf("explicitly tagged !!binary data must be base64-encoded")
+                       }
+                       if tag != "" {
+                               failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
+                       }
+                       // It can't be encoded directly as YAML so use a binary tag
+                       // and encode it as base64.
+                       tag = binaryTag
+                       value = encodeBase64(value)
+               }
+
+               style := yaml_PLAIN_SCALAR_STYLE
+               switch {
+               case node.Style&DoubleQuotedStyle != 0:
+                       style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+               case node.Style&SingleQuotedStyle != 0:
+                       style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+               case node.Style&LiteralStyle != 0:
+                       style = yaml_LITERAL_SCALAR_STYLE
+               case node.Style&FoldedStyle != 0:
+                       style = yaml_FOLDED_SCALAR_STYLE
+               case strings.Contains(value, "\n"):
+                       style = yaml_LITERAL_SCALAR_STYLE
+               case forceQuoting:
+                       style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+               }
+
+               e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment))
+       }
+}
diff --git a/vendor/gopkg.in/yaml.v3/go.mod b/vendor/gopkg.in/yaml.v3/go.mod
new file mode 100644 (file)
index 0000000..f407ea3
--- /dev/null
@@ -0,0 +1,5 @@
+module "gopkg.in/yaml.v3"
+
+require (
+       "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405
+)
diff --git a/vendor/gopkg.in/yaml.v3/parserc.go b/vendor/gopkg.in/yaml.v3/parserc.go
new file mode 100644 (file)
index 0000000..0f7bb1c
--- /dev/null
@@ -0,0 +1,1188 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+       "bytes"
+)
+
+// The parser implements the following grammar:
+//
+// stream               ::= STREAM-START implicit_document? explicit_document* STREAM-END
+// implicit_document    ::= block_node DOCUMENT-END*
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+// block_node_or_indentless_sequence    ::=
+//                          ALIAS
+//                          | properties (block_content | indentless_block_sequence)?
+//                          | block_content
+//                          | indentless_block_sequence
+// block_node           ::= ALIAS
+//                          | properties block_content?
+//                          | block_content
+// flow_node            ::= ALIAS
+//                          | properties flow_content?
+//                          | flow_content
+// properties           ::= TAG ANCHOR? | ANCHOR TAG?
+// block_content        ::= block_collection | flow_collection | SCALAR
+// flow_content         ::= flow_collection | SCALAR
+// block_collection     ::= block_sequence | block_mapping
+// flow_collection      ::= flow_sequence | flow_mapping
+// block_sequence       ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+// indentless_sequence  ::= (BLOCK-ENTRY block_node?)+
+// block_mapping        ::= BLOCK-MAPPING_START
+//                          ((KEY block_node_or_indentless_sequence?)?
+//                          (VALUE block_node_or_indentless_sequence?)?)*
+//                          BLOCK-END
+// flow_sequence        ::= FLOW-SEQUENCE-START
+//                          (flow_sequence_entry FLOW-ENTRY)*
+//                          flow_sequence_entry?
+//                          FLOW-SEQUENCE-END
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// flow_mapping         ::= FLOW-MAPPING-START
+//                          (flow_mapping_entry FLOW-ENTRY)*
+//                          flow_mapping_entry?
+//                          FLOW-MAPPING-END
+// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+
+// Peek the next token in the token queue.
+func peek_token(parser *yaml_parser_t) *yaml_token_t {
+       if parser.token_available || yaml_parser_fetch_more_tokens(parser) {
+               token := &parser.tokens[parser.tokens_head]
+               yaml_parser_unfold_comments(parser, token)
+               return token
+       }
+       return nil
+}
+
+// yaml_parser_unfold_comments walks through the comments queue and joins all
+// comments behind the position of the provided token into the respective
+// top-level comment slices in the parser.
+func yaml_parser_unfold_comments(parser *yaml_parser_t, token *yaml_token_t) {
+       for parser.comments_head < len(parser.comments) && token.start_mark.index >= parser.comments[parser.comments_head].after.index {
+               comment := &parser.comments[parser.comments_head]
+               if len(comment.head) > 0 {
+                       if len(parser.head_comment) > 0 {
+                               parser.head_comment = append(parser.head_comment, '\n')
+                       }
+                       parser.head_comment = append(parser.head_comment, comment.head...)
+               }
+               if len(comment.foot) > 0 {
+                       if len(parser.foot_comment) > 0 {
+                               parser.foot_comment = append(parser.foot_comment, '\n')
+                       }
+                       parser.foot_comment = append(parser.foot_comment, comment.foot...)
+               }
+               if len(comment.line) > 0 {
+                       if len(parser.line_comment) > 0 {
+                               parser.line_comment = append(parser.line_comment, '\n')
+                       }
+                       parser.line_comment = append(parser.line_comment, comment.line...)
+               }
+               *comment = yaml_comment_t{}
+               parser.comments_head++
+       }
+}
+
+// Remove the next token from the queue (must be called after peek_token).
+func skip_token(parser *yaml_parser_t) {
+       parser.token_available = false
+       parser.tokens_parsed++
+       parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN
+       parser.tokens_head++
+}
+
+// Get the next event.
+func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool {
+       // Erase the event object.
+       *event = yaml_event_t{}
+
+       // No events after the end of the stream or error.
+       if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE {
+               return true
+       }
+
+       // Generate the next event.
+       return yaml_parser_state_machine(parser, event)
+}
+
+// Set parser error.
+func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool {
+       parser.error = yaml_PARSER_ERROR
+       parser.problem = problem
+       parser.problem_mark = problem_mark
+       return false
+}
+
+func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool {
+       parser.error = yaml_PARSER_ERROR
+       parser.context = context
+       parser.context_mark = context_mark
+       parser.problem = problem
+       parser.problem_mark = problem_mark
+       return false
+}
+
+// State dispatcher.
+func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool {
+       //trace("yaml_parser_state_machine", "state:", parser.state.String())
+
+       switch parser.state {
+       case yaml_PARSE_STREAM_START_STATE:
+               return yaml_parser_parse_stream_start(parser, event)
+
+       case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
+               return yaml_parser_parse_document_start(parser, event, true)
+
+       case yaml_PARSE_DOCUMENT_START_STATE:
+               return yaml_parser_parse_document_start(parser, event, false)
+
+       case yaml_PARSE_DOCUMENT_CONTENT_STATE:
+               return yaml_parser_parse_document_content(parser, event)
+
+       case yaml_PARSE_DOCUMENT_END_STATE:
+               return yaml_parser_parse_document_end(parser, event)
+
+       case yaml_PARSE_BLOCK_NODE_STATE:
+               return yaml_parser_parse_node(parser, event, true, false)
+
+       case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
+               return yaml_parser_parse_node(parser, event, true, true)
+
+       case yaml_PARSE_FLOW_NODE_STATE:
+               return yaml_parser_parse_node(parser, event, false, false)
+
+       case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
+               return yaml_parser_parse_block_sequence_entry(parser, event, true)
+
+       case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
+               return yaml_parser_parse_block_sequence_entry(parser, event, false)
+
+       case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
+               return yaml_parser_parse_indentless_sequence_entry(parser, event)
+
+       case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
+               return yaml_parser_parse_block_mapping_key(parser, event, true)
+
+       case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
+               return yaml_parser_parse_block_mapping_key(parser, event, false)
+
+       case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
+               return yaml_parser_parse_block_mapping_value(parser, event)
+
+       case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
+               return yaml_parser_parse_flow_sequence_entry(parser, event, true)
+
+       case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
+               return yaml_parser_parse_flow_sequence_entry(parser, event, false)
+
+       case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
+               return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event)
+
+       case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
+               return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event)
+
+       case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
+               return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event)
+
+       case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
+               return yaml_parser_parse_flow_mapping_key(parser, event, true)
+
+       case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
+               return yaml_parser_parse_flow_mapping_key(parser, event, false)
+
+       case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
+               return yaml_parser_parse_flow_mapping_value(parser, event, false)
+
+       case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
+               return yaml_parser_parse_flow_mapping_value(parser, event, true)
+
+       default:
+               panic("invalid parser state")
+       }
+}
+
+// Parse the production:
+// stream   ::= STREAM-START implicit_document? explicit_document* STREAM-END
+//              ************
+func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+       if token.typ != yaml_STREAM_START_TOKEN {
+               return yaml_parser_set_parser_error(parser, "did not find expected <stream-start>", token.start_mark)
+       }
+       parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE
+       *event = yaml_event_t{
+               typ:        yaml_STREAM_START_EVENT,
+               start_mark: token.start_mark,
+               end_mark:   token.end_mark,
+               encoding:   token.encoding,
+       }
+       skip_token(parser)
+       return true
+}
+
+// Parse the productions:
+// implicit_document    ::= block_node DOCUMENT-END*
+//                          *
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//                          *************************
+func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool {
+
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+
+       // Parse extra document end indicators.
+       if !implicit {
+               for token.typ == yaml_DOCUMENT_END_TOKEN {
+                       skip_token(parser)
+                       token = peek_token(parser)
+                       if token == nil {
+                               return false
+                       }
+               }
+       }
+
+       if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN &&
+               token.typ != yaml_TAG_DIRECTIVE_TOKEN &&
+               token.typ != yaml_DOCUMENT_START_TOKEN &&
+               token.typ != yaml_STREAM_END_TOKEN {
+               // Parse an implicit document.
+               if !yaml_parser_process_directives(parser, nil, nil) {
+                       return false
+               }
+               parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
+               parser.state = yaml_PARSE_BLOCK_NODE_STATE
+
+               var head_comment []byte
+               if len(parser.head_comment) > 0 {
+                       // [Go] Scan the header comment backwards, and if an empty line is found, break
+                       //      the header so the part before the last empty line goes into the
+                       //      document header, while the bottom of it goes into a follow up event.
+                       for i := len(parser.head_comment) - 1; i > 0; i-- {
+                               if parser.head_comment[i] == '\n' {
+                                       if i == len(parser.head_comment)-1 {
+                                               head_comment = parser.head_comment[:i]
+                                               parser.head_comment = parser.head_comment[i+1:]
+                                               break
+                                       } else if parser.head_comment[i-1] == '\n' {
+                                               head_comment = parser.head_comment[:i-1]
+                                               parser.head_comment = parser.head_comment[i+1:]
+                                               break
+                                       }
+                               }
+                       }
+               }
+
+               *event = yaml_event_t{
+                       typ:        yaml_DOCUMENT_START_EVENT,
+                       start_mark: token.start_mark,
+                       end_mark:   token.end_mark,
+
+                       head_comment: head_comment,
+               }
+
+       } else if token.typ != yaml_STREAM_END_TOKEN {
+               // Parse an explicit document.
+               var version_directive *yaml_version_directive_t
+               var tag_directives []yaml_tag_directive_t
+               start_mark := token.start_mark
+               if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) {
+                       return false
+               }
+               token = peek_token(parser)
+               if token == nil {
+                       return false
+               }
+               if token.typ != yaml_DOCUMENT_START_TOKEN {
+                       yaml_parser_set_parser_error(parser,
+                               "did not find expected <document start>", token.start_mark)
+                       return false
+               }
+               parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
+               parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE
+               end_mark := token.end_mark
+
+               *event = yaml_event_t{
+                       typ:               yaml_DOCUMENT_START_EVENT,
+                       start_mark:        start_mark,
+                       end_mark:          end_mark,
+                       version_directive: version_directive,
+                       tag_directives:    tag_directives,
+                       implicit:          false,
+               }
+               skip_token(parser)
+
+       } else {
+               // Parse the stream end.
+               parser.state = yaml_PARSE_END_STATE
+               *event = yaml_event_t{
+                       typ:        yaml_STREAM_END_EVENT,
+                       start_mark: token.start_mark,
+                       end_mark:   token.end_mark,
+               }
+               skip_token(parser)
+       }
+
+       return true
+}
+
+// Parse the productions:
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//                                                    ***********
+//
+func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+       if token.typ == yaml_VERSION_DIRECTIVE_TOKEN ||
+               token.typ == yaml_TAG_DIRECTIVE_TOKEN ||
+               token.typ == yaml_DOCUMENT_START_TOKEN ||
+               token.typ == yaml_DOCUMENT_END_TOKEN ||
+               token.typ == yaml_STREAM_END_TOKEN {
+               parser.state = parser.states[len(parser.states)-1]
+               parser.states = parser.states[:len(parser.states)-1]
+               return yaml_parser_process_empty_scalar(parser, event,
+                       token.start_mark)
+       }
+       return yaml_parser_parse_node(parser, event, true, false)
+}
+
+// Parse the productions:
+// implicit_document    ::= block_node DOCUMENT-END*
+//                                     *************
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//
+func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+
+       start_mark := token.start_mark
+       end_mark := token.start_mark
+
+       implicit := true
+       if token.typ == yaml_DOCUMENT_END_TOKEN {
+               end_mark = token.end_mark
+               skip_token(parser)
+               implicit = false
+       }
+
+       parser.tag_directives = parser.tag_directives[:0]
+
+       parser.state = yaml_PARSE_DOCUMENT_START_STATE
+       *event = yaml_event_t{
+               typ:        yaml_DOCUMENT_END_EVENT,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+               implicit:   implicit,
+
+               foot_comment: parser.head_comment,
+       }
+       parser.head_comment = nil
+       return true
+}
+
+func yaml_parser_set_event_comments(parser *yaml_parser_t, event *yaml_event_t) {
+       event.head_comment = parser.head_comment
+       event.line_comment = parser.line_comment
+       event.foot_comment = parser.foot_comment
+       parser.head_comment = nil
+       parser.line_comment = nil
+       parser.foot_comment = nil
+}
+
+// Parse the productions:
+// block_node_or_indentless_sequence    ::=
+//                          ALIAS
+//                          *****
+//                          | properties (block_content | indentless_block_sequence)?
+//                            **********  *
+//                          | block_content | indentless_block_sequence
+//                            *
+// block_node           ::= ALIAS
+//                          *****
+//                          | properties block_content?
+//                            ********** *
+//                          | block_content
+//                            *
+// flow_node            ::= ALIAS
+//                          *****
+//                          | properties flow_content?
+//                            ********** *
+//                          | flow_content
+//                            *
+// properties           ::= TAG ANCHOR? | ANCHOR TAG?
+//                          *************************
+// block_content        ::= block_collection | flow_collection | SCALAR
+//                                                               ******
+// flow_content         ::= flow_collection | SCALAR
+//                                            ******
+func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool {
+       //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)()
+
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+
+       if token.typ == yaml_ALIAS_TOKEN {
+               parser.state = parser.states[len(parser.states)-1]
+               parser.states = parser.states[:len(parser.states)-1]
+               *event = yaml_event_t{
+                       typ:        yaml_ALIAS_EVENT,
+                       start_mark: token.start_mark,
+                       end_mark:   token.end_mark,
+                       anchor:     token.value,
+               }
+               yaml_parser_set_event_comments(parser, event)
+               skip_token(parser)
+               return true
+       }
+
+       start_mark := token.start_mark
+       end_mark := token.start_mark
+
+       var tag_token bool
+       var tag_handle, tag_suffix, anchor []byte
+       var tag_mark yaml_mark_t
+       if token.typ == yaml_ANCHOR_TOKEN {
+               anchor = token.value
+               start_mark = token.start_mark
+               end_mark = token.end_mark
+               skip_token(parser)
+               token = peek_token(parser)
+               if token == nil {
+                       return false
+               }
+               if token.typ == yaml_TAG_TOKEN {
+                       tag_token = true
+                       tag_handle = token.value
+                       tag_suffix = token.suffix
+                       tag_mark = token.start_mark
+                       end_mark = token.end_mark
+                       skip_token(parser)
+                       token = peek_token(parser)
+                       if token == nil {
+                               return false
+                       }
+               }
+       } else if token.typ == yaml_TAG_TOKEN {
+               tag_token = true
+               tag_handle = token.value
+               tag_suffix = token.suffix
+               start_mark = token.start_mark
+               tag_mark = token.start_mark
+               end_mark = token.end_mark
+               skip_token(parser)
+               token = peek_token(parser)
+               if token == nil {
+                       return false
+               }
+               if token.typ == yaml_ANCHOR_TOKEN {
+                       anchor = token.value
+                       end_mark = token.end_mark
+                       skip_token(parser)
+                       token = peek_token(parser)
+                       if token == nil {
+                               return false
+                       }
+               }
+       }
+
+       var tag []byte
+       if tag_token {
+               if len(tag_handle) == 0 {
+                       tag = tag_suffix
+                       tag_suffix = nil
+               } else {
+                       for i := range parser.tag_directives {
+                               if bytes.Equal(parser.tag_directives[i].handle, tag_handle) {
+                                       tag = append([]byte(nil), parser.tag_directives[i].prefix...)
+                                       tag = append(tag, tag_suffix...)
+                                       break
+                               }
+                       }
+                       if len(tag) == 0 {
+                               yaml_parser_set_parser_error_context(parser,
+                                       "while parsing a node", start_mark,
+                                       "found undefined tag handle", tag_mark)
+                               return false
+                       }
+               }
+       }
+
+       implicit := len(tag) == 0
+       if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN {
+               end_mark = token.end_mark
+               parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
+               *event = yaml_event_t{
+                       typ:        yaml_SEQUENCE_START_EVENT,
+                       start_mark: start_mark,
+                       end_mark:   end_mark,
+                       anchor:     anchor,
+                       tag:        tag,
+                       implicit:   implicit,
+                       style:      yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
+               }
+               return true
+       }
+       if token.typ == yaml_SCALAR_TOKEN {
+               var plain_implicit, quoted_implicit bool
+               end_mark = token.end_mark
+               if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') {
+                       plain_implicit = true
+               } else if len(tag) == 0 {
+                       quoted_implicit = true
+               }
+               parser.state = parser.states[len(parser.states)-1]
+               parser.states = parser.states[:len(parser.states)-1]
+
+               *event = yaml_event_t{
+                       typ:             yaml_SCALAR_EVENT,
+                       start_mark:      start_mark,
+                       end_mark:        end_mark,
+                       anchor:          anchor,
+                       tag:             tag,
+                       value:           token.value,
+                       implicit:        plain_implicit,
+                       quoted_implicit: quoted_implicit,
+                       style:           yaml_style_t(token.style),
+               }
+               yaml_parser_set_event_comments(parser, event)
+               skip_token(parser)
+               return true
+       }
+       if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN {
+               // [Go] Some of the events below can be merged as they differ only on style.
+               end_mark = token.end_mark
+               parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE
+               *event = yaml_event_t{
+                       typ:        yaml_SEQUENCE_START_EVENT,
+                       start_mark: start_mark,
+                       end_mark:   end_mark,
+                       anchor:     anchor,
+                       tag:        tag,
+                       implicit:   implicit,
+                       style:      yaml_style_t(yaml_FLOW_SEQUENCE_STYLE),
+               }
+               yaml_parser_set_event_comments(parser, event)
+               return true
+       }
+       if token.typ == yaml_FLOW_MAPPING_START_TOKEN {
+               end_mark = token.end_mark
+               parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE
+               *event = yaml_event_t{
+                       typ:        yaml_MAPPING_START_EVENT,
+                       start_mark: start_mark,
+                       end_mark:   end_mark,
+                       anchor:     anchor,
+                       tag:        tag,
+                       implicit:   implicit,
+                       style:      yaml_style_t(yaml_FLOW_MAPPING_STYLE),
+               }
+               yaml_parser_set_event_comments(parser, event)
+               return true
+       }
+       if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN {
+               end_mark = token.end_mark
+               parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE
+               *event = yaml_event_t{
+                       typ:        yaml_SEQUENCE_START_EVENT,
+                       start_mark: start_mark,
+                       end_mark:   end_mark,
+                       anchor:     anchor,
+                       tag:        tag,
+                       implicit:   implicit,
+                       style:      yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
+               }
+               return true
+       }
+       if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN {
+               end_mark = token.end_mark
+               parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE
+               *event = yaml_event_t{
+                       typ:        yaml_MAPPING_START_EVENT,
+                       start_mark: start_mark,
+                       end_mark:   end_mark,
+                       anchor:     anchor,
+                       tag:        tag,
+                       implicit:   implicit,
+                       style:      yaml_style_t(yaml_BLOCK_MAPPING_STYLE),
+               }
+               return true
+       }
+       if len(anchor) > 0 || len(tag) > 0 {
+               parser.state = parser.states[len(parser.states)-1]
+               parser.states = parser.states[:len(parser.states)-1]
+
+               *event = yaml_event_t{
+                       typ:             yaml_SCALAR_EVENT,
+                       start_mark:      start_mark,
+                       end_mark:        end_mark,
+                       anchor:          anchor,
+                       tag:             tag,
+                       implicit:        implicit,
+                       quoted_implicit: false,
+                       style:           yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
+               }
+               return true
+       }
+
+       context := "while parsing a flow node"
+       if block {
+               context = "while parsing a block node"
+       }
+       yaml_parser_set_parser_error_context(parser, context, start_mark,
+               "did not find expected node content", token.start_mark)
+       return false
+}
+
+// Parse the productions:
+// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+//                    ********************  *********** *             *********
+//
+func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+       if first {
+               token := peek_token(parser)
+               parser.marks = append(parser.marks, token.start_mark)
+               skip_token(parser)
+       }
+
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+
+       if token.typ == yaml_BLOCK_ENTRY_TOKEN {
+               mark := token.end_mark
+               skip_token(parser)
+               token = peek_token(parser)
+               if token == nil {
+                       return false
+               }
+               if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN {
+                       parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)
+                       return yaml_parser_parse_node(parser, event, true, false)
+               } else {
+                       parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE
+                       return yaml_parser_process_empty_scalar(parser, event, mark)
+               }
+       }
+       if token.typ == yaml_BLOCK_END_TOKEN {
+               parser.state = parser.states[len(parser.states)-1]
+               parser.states = parser.states[:len(parser.states)-1]
+               parser.marks = parser.marks[:len(parser.marks)-1]
+
+               *event = yaml_event_t{
+                       typ:        yaml_SEQUENCE_END_EVENT,
+                       start_mark: token.start_mark,
+                       end_mark:   token.end_mark,
+               }
+
+               skip_token(parser)
+               return true
+       }
+
+       context_mark := parser.marks[len(parser.marks)-1]
+       parser.marks = parser.marks[:len(parser.marks)-1]
+       return yaml_parser_set_parser_error_context(parser,
+               "while parsing a block collection", context_mark,
+               "did not find expected '-' indicator", token.start_mark)
+}
+
+// Parse the productions:
+// indentless_sequence  ::= (BLOCK-ENTRY block_node?)+
+//                           *********** *
+func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool {
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+
+       if token.typ == yaml_BLOCK_ENTRY_TOKEN {
+               mark := token.end_mark
+               skip_token(parser)
+               token = peek_token(parser)
+               if token == nil {
+                       return false
+               }
+               if token.typ != yaml_BLOCK_ENTRY_TOKEN &&
+                       token.typ != yaml_KEY_TOKEN &&
+                       token.typ != yaml_VALUE_TOKEN &&
+                       token.typ != yaml_BLOCK_END_TOKEN {
+                       parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)
+                       return yaml_parser_parse_node(parser, event, true, false)
+               }
+               parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
+               return yaml_parser_process_empty_scalar(parser, event, mark)
+       }
+       parser.state = parser.states[len(parser.states)-1]
+       parser.states = parser.states[:len(parser.states)-1]
+
+       *event = yaml_event_t{
+               typ:        yaml_SEQUENCE_END_EVENT,
+               start_mark: token.start_mark,
+               end_mark:   token.start_mark, // [Go] Shouldn't this be token.end_mark?
+       }
+       return true
+}
+
+// Parse the productions:
+// block_mapping        ::= BLOCK-MAPPING_START
+//                          *******************
+//                          ((KEY block_node_or_indentless_sequence?)?
+//                            *** *
+//                          (VALUE block_node_or_indentless_sequence?)?)*
+//
+//                          BLOCK-END
+//                          *********
+//
+func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+       if first {
+               token := peek_token(parser)
+               parser.marks = append(parser.marks, token.start_mark)
+               skip_token(parser)
+       }
+
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+
+       if token.typ == yaml_KEY_TOKEN {
+               mark := token.end_mark
+               skip_token(parser)
+               token = peek_token(parser)
+               if token == nil {
+                       return false
+               }
+               if token.typ != yaml_KEY_TOKEN &&
+                       token.typ != yaml_VALUE_TOKEN &&
+                       token.typ != yaml_BLOCK_END_TOKEN {
+                       parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE)
+                       return yaml_parser_parse_node(parser, event, true, true)
+               } else {
+                       parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE
+                       return yaml_parser_process_empty_scalar(parser, event, mark)
+               }
+       } else if token.typ == yaml_BLOCK_END_TOKEN {
+               parser.state = parser.states[len(parser.states)-1]
+               parser.states = parser.states[:len(parser.states)-1]
+               parser.marks = parser.marks[:len(parser.marks)-1]
+               *event = yaml_event_t{
+                       typ:        yaml_MAPPING_END_EVENT,
+                       start_mark: token.start_mark,
+                       end_mark:   token.end_mark,
+               }
+               skip_token(parser)
+               return true
+       }
+
+       context_mark := parser.marks[len(parser.marks)-1]
+       parser.marks = parser.marks[:len(parser.marks)-1]
+       return yaml_parser_set_parser_error_context(parser,
+               "while parsing a block mapping", context_mark,
+               "did not find expected key", token.start_mark)
+}
+
+// Parse the productions:
+// block_mapping        ::= BLOCK-MAPPING_START
+//
+//                          ((KEY block_node_or_indentless_sequence?)?
+//
+//                          (VALUE block_node_or_indentless_sequence?)?)*
+//                           ***** *
+//                          BLOCK-END
+//
+//
+func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+       if token.typ == yaml_VALUE_TOKEN {
+               mark := token.end_mark
+               skip_token(parser)
+               token = peek_token(parser)
+               if token == nil {
+                       return false
+               }
+               if token.typ != yaml_KEY_TOKEN &&
+                       token.typ != yaml_VALUE_TOKEN &&
+                       token.typ != yaml_BLOCK_END_TOKEN {
+                       parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE)
+                       return yaml_parser_parse_node(parser, event, true, true)
+               }
+               parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
+               return yaml_parser_process_empty_scalar(parser, event, mark)
+       }
+       parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
+       return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Parse the productions:
+// flow_sequence        ::= FLOW-SEQUENCE-START
+//                          *******************
+//                          (flow_sequence_entry FLOW-ENTRY)*
+//                           *                   **********
+//                          flow_sequence_entry?
+//                          *
+//                          FLOW-SEQUENCE-END
+//                          *****************
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                          *
+//
+func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+       if first {
+               token := peek_token(parser)
+               parser.marks = append(parser.marks, token.start_mark)
+               skip_token(parser)
+       }
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+       if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+               if !first {
+                       if token.typ == yaml_FLOW_ENTRY_TOKEN {
+                               skip_token(parser)
+                               token = peek_token(parser)
+                               if token == nil {
+                                       return false
+                               }
+                       } else {
+                               context_mark := parser.marks[len(parser.marks)-1]
+                               parser.marks = parser.marks[:len(parser.marks)-1]
+                               return yaml_parser_set_parser_error_context(parser,
+                                       "while parsing a flow sequence", context_mark,
+                                       "did not find expected ',' or ']'", token.start_mark)
+                       }
+               }
+
+               if token.typ == yaml_KEY_TOKEN {
+                       parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE
+                       *event = yaml_event_t{
+                               typ:        yaml_MAPPING_START_EVENT,
+                               start_mark: token.start_mark,
+                               end_mark:   token.end_mark,
+                               implicit:   true,
+                               style:      yaml_style_t(yaml_FLOW_MAPPING_STYLE),
+                       }
+                       skip_token(parser)
+                       return true
+               } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+                       parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE)
+                       return yaml_parser_parse_node(parser, event, false, false)
+               }
+       }
+
+       parser.state = parser.states[len(parser.states)-1]
+       parser.states = parser.states[:len(parser.states)-1]
+       parser.marks = parser.marks[:len(parser.marks)-1]
+
+       *event = yaml_event_t{
+               typ:        yaml_SEQUENCE_END_EVENT,
+               start_mark: token.start_mark,
+               end_mark:   token.end_mark,
+       }
+       yaml_parser_set_event_comments(parser, event)
+
+       skip_token(parser)
+       return true
+}
+
+//
+// Parse the productions:
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                      *** *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool {
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+       if token.typ != yaml_VALUE_TOKEN &&
+               token.typ != yaml_FLOW_ENTRY_TOKEN &&
+               token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+               parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)
+               return yaml_parser_parse_node(parser, event, false, false)
+       }
+       mark := token.end_mark
+       skip_token(parser)
+       parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE
+       return yaml_parser_process_empty_scalar(parser, event, mark)
+}
+
+// Parse the productions:
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                                      ***** *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+       if token.typ == yaml_VALUE_TOKEN {
+               skip_token(parser)
+               token := peek_token(parser)
+               if token == nil {
+                       return false
+               }
+               if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+                       parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)
+                       return yaml_parser_parse_node(parser, event, false, false)
+               }
+       }
+       parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE
+       return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Parse the productions:
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                                                      *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool {
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+       parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE
+       *event = yaml_event_t{
+               typ:        yaml_MAPPING_END_EVENT,
+               start_mark: token.start_mark,
+               end_mark:   token.start_mark, // [Go] Shouldn't this be end_mark?
+       }
+       return true
+}
+
+// Parse the productions:
+// flow_mapping         ::= FLOW-MAPPING-START
+//                          ******************
+//                          (flow_mapping_entry FLOW-ENTRY)*
+//                           *                  **********
+//                          flow_mapping_entry?
+//                          ******************
+//                          FLOW-MAPPING-END
+//                          ****************
+// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                          *           *** *
+//
+func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+       if first {
+               token := peek_token(parser)
+               parser.marks = append(parser.marks, token.start_mark)
+               skip_token(parser)
+       }
+
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+
+       if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+               if !first {
+                       if token.typ == yaml_FLOW_ENTRY_TOKEN {
+                               skip_token(parser)
+                               token = peek_token(parser)
+                               if token == nil {
+                                       return false
+                               }
+                       } else {
+                               context_mark := parser.marks[len(parser.marks)-1]
+                               parser.marks = parser.marks[:len(parser.marks)-1]
+                               return yaml_parser_set_parser_error_context(parser,
+                                       "while parsing a flow mapping", context_mark,
+                                       "did not find expected ',' or '}'", token.start_mark)
+                       }
+               }
+
+               if token.typ == yaml_KEY_TOKEN {
+                       skip_token(parser)
+                       token = peek_token(parser)
+                       if token == nil {
+                               return false
+                       }
+                       if token.typ != yaml_VALUE_TOKEN &&
+                               token.typ != yaml_FLOW_ENTRY_TOKEN &&
+                               token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+                               parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE)
+                               return yaml_parser_parse_node(parser, event, false, false)
+                       } else {
+                               parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE
+                               return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+                       }
+               } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+                       parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)
+                       return yaml_parser_parse_node(parser, event, false, false)
+               }
+       }
+
+       parser.state = parser.states[len(parser.states)-1]
+       parser.states = parser.states[:len(parser.states)-1]
+       parser.marks = parser.marks[:len(parser.marks)-1]
+       *event = yaml_event_t{
+               typ:        yaml_MAPPING_END_EVENT,
+               start_mark: token.start_mark,
+               end_mark:   token.end_mark,
+       }
+       yaml_parser_set_event_comments(parser, event)
+       skip_token(parser)
+       return true
+}
+
+// Parse the productions:
+// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                   *                  ***** *
+//
+func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool {
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+       if empty {
+               parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
+               return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+       }
+       if token.typ == yaml_VALUE_TOKEN {
+               skip_token(parser)
+               token = peek_token(parser)
+               if token == nil {
+                       return false
+               }
+               if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+                       parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE)
+                       return yaml_parser_parse_node(parser, event, false, false)
+               }
+       }
+       parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
+       return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Generate an empty scalar event.
+func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool {
+       *event = yaml_event_t{
+               typ:        yaml_SCALAR_EVENT,
+               start_mark: mark,
+               end_mark:   mark,
+               value:      nil, // Empty
+               implicit:   true,
+               style:      yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
+       }
+       return true
+}
+
+var default_tag_directives = []yaml_tag_directive_t{
+       {[]byte("!"), []byte("!")},
+       {[]byte("!!"), []byte("tag:yaml.org,2002:")},
+}
+
+// Parse directives.
+func yaml_parser_process_directives(parser *yaml_parser_t,
+       version_directive_ref **yaml_version_directive_t,
+       tag_directives_ref *[]yaml_tag_directive_t) bool {
+
+       var version_directive *yaml_version_directive_t
+       var tag_directives []yaml_tag_directive_t
+
+       token := peek_token(parser)
+       if token == nil {
+               return false
+       }
+
+       for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN {
+               if token.typ == yaml_VERSION_DIRECTIVE_TOKEN {
+                       if version_directive != nil {
+                               yaml_parser_set_parser_error(parser,
+                                       "found duplicate %YAML directive", token.start_mark)
+                               return false
+                       }
+                       if token.major != 1 || token.minor != 1 {
+                               yaml_parser_set_parser_error(parser,
+                                       "found incompatible YAML document", token.start_mark)
+                               return false
+                       }
+                       version_directive = &yaml_version_directive_t{
+                               major: token.major,
+                               minor: token.minor,
+                       }
+               } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN {
+                       value := yaml_tag_directive_t{
+                               handle: token.value,
+                               prefix: token.prefix,
+                       }
+                       if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) {
+                               return false
+                       }
+                       tag_directives = append(tag_directives, value)
+               }
+
+               skip_token(parser)
+               token = peek_token(parser)
+               if token == nil {
+                       return false
+               }
+       }
+
+       for i := range default_tag_directives {
+               if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) {
+                       return false
+               }
+       }
+
+       if version_directive_ref != nil {
+               *version_directive_ref = version_directive
+       }
+       if tag_directives_ref != nil {
+               *tag_directives_ref = tag_directives
+       }
+       return true
+}
+
+// Append a tag directive to the directives stack.
+func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool {
+       for i := range parser.tag_directives {
+               if bytes.Equal(value.handle, parser.tag_directives[i].handle) {
+                       if allow_duplicates {
+                               return true
+                       }
+                       return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark)
+               }
+       }
+
+       // [Go] I suspect the copy is unnecessary. This was likely done
+       // because there was no way to track ownership of the data.
+       value_copy := yaml_tag_directive_t{
+               handle: make([]byte, len(value.handle)),
+               prefix: make([]byte, len(value.prefix)),
+       }
+       copy(value_copy.handle, value.handle)
+       copy(value_copy.prefix, value.prefix)
+       parser.tag_directives = append(parser.tag_directives, value_copy)
+       return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/readerc.go b/vendor/gopkg.in/yaml.v3/readerc.go
new file mode 100644 (file)
index 0000000..b7de0a8
--- /dev/null
@@ -0,0 +1,434 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+       "io"
+)
+
+// Set the reader error and return 0.
+func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
+       parser.error = yaml_READER_ERROR
+       parser.problem = problem
+       parser.problem_offset = offset
+       parser.problem_value = value
+       return false
+}
+
+// Byte order marks.
+const (
+       bom_UTF8    = "\xef\xbb\xbf"
+       bom_UTF16LE = "\xff\xfe"
+       bom_UTF16BE = "\xfe\xff"
+)
+
+// Determine the input stream encoding by checking the BOM symbol. If no BOM is
+// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
+func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
+       // Ensure that we had enough bytes in the raw buffer.
+       for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
+               if !yaml_parser_update_raw_buffer(parser) {
+                       return false
+               }
+       }
+
+       // Determine the encoding.
+       buf := parser.raw_buffer
+       pos := parser.raw_buffer_pos
+       avail := len(buf) - pos
+       if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
+               parser.encoding = yaml_UTF16LE_ENCODING
+               parser.raw_buffer_pos += 2
+               parser.offset += 2
+       } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
+               parser.encoding = yaml_UTF16BE_ENCODING
+               parser.raw_buffer_pos += 2
+               parser.offset += 2
+       } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
+               parser.encoding = yaml_UTF8_ENCODING
+               parser.raw_buffer_pos += 3
+               parser.offset += 3
+       } else {
+               parser.encoding = yaml_UTF8_ENCODING
+       }
+       return true
+}
+
+// Update the raw buffer.
+func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
+       size_read := 0
+
+       // Return if the raw buffer is full.
+       if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
+               return true
+       }
+
+       // Return on EOF.
+       if parser.eof {
+               return true
+       }
+
+       // Move the remaining bytes in the raw buffer to the beginning.
+       if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
+               copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
+       }
+       parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
+       parser.raw_buffer_pos = 0
+
+       // Call the read handler to fill the buffer.
+       size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
+       parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
+       if err == io.EOF {
+               parser.eof = true
+       } else if err != nil {
+               return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
+       }
+       return true
+}
+
+// Ensure that the buffer contains at least `length` characters.
+// Return true on success, false on failure.
+//
+// The length is supposed to be significantly less that the buffer size.
+func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
+       if parser.read_handler == nil {
+               panic("read handler must be set")
+       }
+
+       // [Go] This function was changed to guarantee the requested length size at EOF.
+       // The fact we need to do this is pretty awful, but the description above implies
+       // for that to be the case, and there are tests
+
+       // If the EOF flag is set and the raw buffer is empty, do nothing.
+       if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
+               // [Go] ACTUALLY! Read the documentation of this function above.
+               // This is just broken. To return true, we need to have the
+               // given length in the buffer. Not doing that means every single
+               // check that calls this function to make sure the buffer has a
+               // given length is Go) panicking; or C) accessing invalid memory.
+               //return true
+       }
+
+       // Return if the buffer contains enough characters.
+       if parser.unread >= length {
+               return true
+       }
+
+       // Determine the input encoding if it is not known yet.
+       if parser.encoding == yaml_ANY_ENCODING {
+               if !yaml_parser_determine_encoding(parser) {
+                       return false
+               }
+       }
+
+       // Move the unread characters to the beginning of the buffer.
+       buffer_len := len(parser.buffer)
+       if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len {
+               copy(parser.buffer, parser.buffer[parser.buffer_pos:])
+               buffer_len -= parser.buffer_pos
+               parser.buffer_pos = 0
+       } else if parser.buffer_pos == buffer_len {
+               buffer_len = 0
+               parser.buffer_pos = 0
+       }
+
+       // Open the whole buffer for writing, and cut it before returning.
+       parser.buffer = parser.buffer[:cap(parser.buffer)]
+
+       // Fill the buffer until it has enough characters.
+       first := true
+       for parser.unread < length {
+
+               // Fill the raw buffer if necessary.
+               if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
+                       if !yaml_parser_update_raw_buffer(parser) {
+                               parser.buffer = parser.buffer[:buffer_len]
+                               return false
+                       }
+               }
+               first = false
+
+               // Decode the raw buffer.
+       inner:
+               for parser.raw_buffer_pos != len(parser.raw_buffer) {
+                       var value rune
+                       var width int
+
+                       raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
+
+                       // Decode the next character.
+                       switch parser.encoding {
+                       case yaml_UTF8_ENCODING:
+                               // Decode a UTF-8 character.  Check RFC 3629
+                               // (http://www.ietf.org/rfc/rfc3629.txt) for more details.
+                               //
+                               // The following table (taken from the RFC) is used for
+                               // decoding.
+                               //
+                               //    Char. number range |        UTF-8 octet sequence
+                               //      (hexadecimal)    |              (binary)
+                               //   --------------------+------------------------------------
+                               //   0000 0000-0000 007F | 0xxxxxxx
+                               //   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+                               //   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+                               //   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+                               //
+                               // Additionally, the characters in the range 0xD800-0xDFFF
+                               // are prohibited as they are reserved for use with UTF-16
+                               // surrogate pairs.
+
+                               // Determine the length of the UTF-8 sequence.
+                               octet := parser.raw_buffer[parser.raw_buffer_pos]
+                               switch {
+                               case octet&0x80 == 0x00:
+                                       width = 1
+                               case octet&0xE0 == 0xC0:
+                                       width = 2
+                               case octet&0xF0 == 0xE0:
+                                       width = 3
+                               case octet&0xF8 == 0xF0:
+                                       width = 4
+                               default:
+                                       // The leading octet is invalid.
+                                       return yaml_parser_set_reader_error(parser,
+                                               "invalid leading UTF-8 octet",
+                                               parser.offset, int(octet))
+                               }
+
+                               // Check if the raw buffer contains an incomplete character.
+                               if width > raw_unread {
+                                       if parser.eof {
+                                               return yaml_parser_set_reader_error(parser,
+                                                       "incomplete UTF-8 octet sequence",
+                                                       parser.offset, -1)
+                                       }
+                                       break inner
+                               }
+
+                               // Decode the leading octet.
+                               switch {
+                               case octet&0x80 == 0x00:
+                                       value = rune(octet & 0x7F)
+                               case octet&0xE0 == 0xC0:
+                                       value = rune(octet & 0x1F)
+                               case octet&0xF0 == 0xE0:
+                                       value = rune(octet & 0x0F)
+                               case octet&0xF8 == 0xF0:
+                                       value = rune(octet & 0x07)
+                               default:
+                                       value = 0
+                               }
+
+                               // Check and decode the trailing octets.
+                               for k := 1; k < width; k++ {
+                                       octet = parser.raw_buffer[parser.raw_buffer_pos+k]
+
+                                       // Check if the octet is valid.
+                                       if (octet & 0xC0) != 0x80 {
+                                               return yaml_parser_set_reader_error(parser,
+                                                       "invalid trailing UTF-8 octet",
+                                                       parser.offset+k, int(octet))
+                                       }
+
+                                       // Decode the octet.
+                                       value = (value << 6) + rune(octet&0x3F)
+                               }
+
+                               // Check the length of the sequence against the value.
+                               switch {
+                               case width == 1:
+                               case width == 2 && value >= 0x80:
+                               case width == 3 && value >= 0x800:
+                               case width == 4 && value >= 0x10000:
+                               default:
+                                       return yaml_parser_set_reader_error(parser,
+                                               "invalid length of a UTF-8 sequence",
+                                               parser.offset, -1)
+                               }
+
+                               // Check the range of the value.
+                               if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
+                                       return yaml_parser_set_reader_error(parser,
+                                               "invalid Unicode character",
+                                               parser.offset, int(value))
+                               }
+
+                       case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
+                               var low, high int
+                               if parser.encoding == yaml_UTF16LE_ENCODING {
+                                       low, high = 0, 1
+                               } else {
+                                       low, high = 1, 0
+                               }
+
+                               // The UTF-16 encoding is not as simple as one might
+                               // naively think.  Check RFC 2781
+                               // (http://www.ietf.org/rfc/rfc2781.txt).
+                               //
+                               // Normally, two subsequent bytes describe a Unicode
+                               // character.  However a special technique (called a
+                               // surrogate pair) is used for specifying character
+                               // values larger than 0xFFFF.
+                               //
+                               // A surrogate pair consists of two pseudo-characters:
+                               //      high surrogate area (0xD800-0xDBFF)
+                               //      low surrogate area (0xDC00-0xDFFF)
+                               //
+                               // The following formulas are used for decoding
+                               // and encoding characters using surrogate pairs:
+                               //
+                               //  U  = U' + 0x10000   (0x01 00 00 <= U <= 0x10 FF FF)
+                               //  U' = yyyyyyyyyyxxxxxxxxxx   (0 <= U' <= 0x0F FF FF)
+                               //  W1 = 110110yyyyyyyyyy
+                               //  W2 = 110111xxxxxxxxxx
+                               //
+                               // where U is the character value, W1 is the high surrogate
+                               // area, W2 is the low surrogate area.
+
+                               // Check for incomplete UTF-16 character.
+                               if raw_unread < 2 {
+                                       if parser.eof {
+                                               return yaml_parser_set_reader_error(parser,
+                                                       "incomplete UTF-16 character",
+                                                       parser.offset, -1)
+                                       }
+                                       break inner
+                               }
+
+                               // Get the character.
+                               value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
+                                       (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
+
+                               // Check for unexpected low surrogate area.
+                               if value&0xFC00 == 0xDC00 {
+                                       return yaml_parser_set_reader_error(parser,
+                                               "unexpected low surrogate area",
+                                               parser.offset, int(value))
+                               }
+
+                               // Check for a high surrogate area.
+                               if value&0xFC00 == 0xD800 {
+                                       width = 4
+
+                                       // Check for incomplete surrogate pair.
+                                       if raw_unread < 4 {
+                                               if parser.eof {
+                                                       return yaml_parser_set_reader_error(parser,
+                                                               "incomplete UTF-16 surrogate pair",
+                                                               parser.offset, -1)
+                                               }
+                                               break inner
+                                       }
+
+                                       // Get the next character.
+                                       value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
+                                               (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
+
+                                       // Check for a low surrogate area.
+                                       if value2&0xFC00 != 0xDC00 {
+                                               return yaml_parser_set_reader_error(parser,
+                                                       "expected low surrogate area",
+                                                       parser.offset+2, int(value2))
+                                       }
+
+                                       // Generate the value of the surrogate pair.
+                                       value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
+                               } else {
+                                       width = 2
+                               }
+
+                       default:
+                               panic("impossible")
+                       }
+
+                       // Check if the character is in the allowed range:
+                       //      #x9 | #xA | #xD | [#x20-#x7E]               (8 bit)
+                       //      | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD]    (16 bit)
+                       //      | [#x10000-#x10FFFF]                        (32 bit)
+                       switch {
+                       case value == 0x09:
+                       case value == 0x0A:
+                       case value == 0x0D:
+                       case value >= 0x20 && value <= 0x7E:
+                       case value == 0x85:
+                       case value >= 0xA0 && value <= 0xD7FF:
+                       case value >= 0xE000 && value <= 0xFFFD:
+                       case value >= 0x10000 && value <= 0x10FFFF:
+                       default:
+                               return yaml_parser_set_reader_error(parser,
+                                       "control characters are not allowed",
+                                       parser.offset, int(value))
+                       }
+
+                       // Move the raw pointers.
+                       parser.raw_buffer_pos += width
+                       parser.offset += width
+
+                       // Finally put the character into the buffer.
+                       if value <= 0x7F {
+                               // 0000 0000-0000 007F . 0xxxxxxx
+                               parser.buffer[buffer_len+0] = byte(value)
+                               buffer_len += 1
+                       } else if value <= 0x7FF {
+                               // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
+                               parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6))
+                               parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F))
+                               buffer_len += 2
+                       } else if value <= 0xFFFF {
+                               // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
+                               parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12))
+                               parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F))
+                               parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F))
+                               buffer_len += 3
+                       } else {
+                               // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+                               parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18))
+                               parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F))
+                               parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F))
+                               parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F))
+                               buffer_len += 4
+                       }
+
+                       parser.unread++
+               }
+
+               // On EOF, put NUL into the buffer and return.
+               if parser.eof {
+                       parser.buffer[buffer_len] = 0
+                       buffer_len++
+                       parser.unread++
+                       break
+               }
+       }
+       // [Go] Read the documentation of this function above. To return true,
+       // we need to have the given length in the buffer. Not doing that means
+       // every single check that calls this function to make sure the buffer
+       // has a given length is Go) panicking; or C) accessing invalid memory.
+       // This happens here due to the EOF above breaking early.
+       for buffer_len < length {
+               parser.buffer[buffer_len] = 0
+               buffer_len++
+       }
+       parser.buffer = parser.buffer[:buffer_len]
+       return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/resolve.go b/vendor/gopkg.in/yaml.v3/resolve.go
new file mode 100644 (file)
index 0000000..64ae888
--- /dev/null
@@ -0,0 +1,326 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package yaml
+
+import (
+       "encoding/base64"
+       "math"
+       "regexp"
+       "strconv"
+       "strings"
+       "time"
+)
+
+type resolveMapItem struct {
+       value interface{}
+       tag   string
+}
+
+var resolveTable = make([]byte, 256)
+var resolveMap = make(map[string]resolveMapItem)
+
+func init() {
+       t := resolveTable
+       t[int('+')] = 'S' // Sign
+       t[int('-')] = 'S'
+       for _, c := range "0123456789" {
+               t[int(c)] = 'D' // Digit
+       }
+       for _, c := range "yYnNtTfFoO~" {
+               t[int(c)] = 'M' // In map
+       }
+       t[int('.')] = '.' // Float (potentially in map)
+
+       var resolveMapList = []struct {
+               v   interface{}
+               tag string
+               l   []string
+       }{
+               {true, boolTag, []string{"true", "True", "TRUE"}},
+               {false, boolTag, []string{"false", "False", "FALSE"}},
+               {nil, nullTag, []string{"", "~", "null", "Null", "NULL"}},
+               {math.NaN(), floatTag, []string{".nan", ".NaN", ".NAN"}},
+               {math.Inf(+1), floatTag, []string{".inf", ".Inf", ".INF"}},
+               {math.Inf(+1), floatTag, []string{"+.inf", "+.Inf", "+.INF"}},
+               {math.Inf(-1), floatTag, []string{"-.inf", "-.Inf", "-.INF"}},
+               {"<<", mergeTag, []string{"<<"}},
+       }
+
+       m := resolveMap
+       for _, item := range resolveMapList {
+               for _, s := range item.l {
+                       m[s] = resolveMapItem{item.v, item.tag}
+               }
+       }
+}
+
+const (
+       nullTag      = "!!null"
+       boolTag      = "!!bool"
+       strTag       = "!!str"
+       intTag       = "!!int"
+       floatTag     = "!!float"
+       timestampTag = "!!timestamp"
+       seqTag       = "!!seq"
+       mapTag       = "!!map"
+       binaryTag    = "!!binary"
+       mergeTag     = "!!merge"
+)
+
+var longTags = make(map[string]string)
+var shortTags = make(map[string]string)
+
+func init() {
+       for _, stag := range []string{nullTag, boolTag, strTag, intTag, floatTag, timestampTag, seqTag, mapTag, binaryTag, mergeTag} {
+               ltag := longTag(stag)
+               longTags[stag] = ltag
+               shortTags[ltag] = stag
+       }
+}
+
+const longTagPrefix = "tag:yaml.org,2002:"
+
+func shortTag(tag string) string {
+       if strings.HasPrefix(tag, longTagPrefix) {
+               if stag, ok := shortTags[tag]; ok {
+                       return stag
+               }
+               return "!!" + tag[len(longTagPrefix):]
+       }
+       return tag
+}
+
+func longTag(tag string) string {
+       if strings.HasPrefix(tag, "!!") {
+               if ltag, ok := longTags[tag]; ok {
+                       return ltag
+               }
+               return longTagPrefix + tag[2:]
+       }
+       return tag
+}
+
+func resolvableTag(tag string) bool {
+       switch tag {
+       case "", strTag, boolTag, intTag, floatTag, nullTag, timestampTag:
+               return true
+       }
+       return false
+}
+
+var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
+
+func resolve(tag string, in string) (rtag string, out interface{}) {
+       tag = shortTag(tag)
+       if !resolvableTag(tag) {
+               return tag, in
+       }
+
+       defer func() {
+               switch tag {
+               case "", rtag, strTag, binaryTag:
+                       return
+               case floatTag:
+                       if rtag == intTag {
+                               switch v := out.(type) {
+                               case int64:
+                                       rtag = floatTag
+                                       out = float64(v)
+                                       return
+                               case int:
+                                       rtag = floatTag
+                                       out = float64(v)
+                                       return
+                               }
+                       }
+               }
+               failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
+       }()
+
+       // Any data is accepted as a !!str or !!binary.
+       // Otherwise, the prefix is enough of a hint about what it might be.
+       hint := byte('N')
+       if in != "" {
+               hint = resolveTable[in[0]]
+       }
+       if hint != 0 && tag != strTag && tag != binaryTag {
+               // Handle things we can lookup in a map.
+               if item, ok := resolveMap[in]; ok {
+                       return item.tag, item.value
+               }
+
+               // Base 60 floats are a bad idea, were dropped in YAML 1.2, and
+               // are purposefully unsupported here. They're still quoted on
+               // the way out for compatibility with other parser, though.
+
+               switch hint {
+               case 'M':
+                       // We've already checked the map above.
+
+               case '.':
+                       // Not in the map, so maybe a normal float.
+                       floatv, err := strconv.ParseFloat(in, 64)
+                       if err == nil {
+                               return floatTag, floatv
+                       }
+
+               case 'D', 'S':
+                       // Int, float, or timestamp.
+                       // Only try values as a timestamp if the value is unquoted or there's an explicit
+                       // !!timestamp tag.
+                       if tag == "" || tag == timestampTag {
+                               t, ok := parseTimestamp(in)
+                               if ok {
+                                       return timestampTag, t
+                               }
+                       }
+
+                       plain := strings.Replace(in, "_", "", -1)
+                       intv, err := strconv.ParseInt(plain, 0, 64)
+                       if err == nil {
+                               if intv == int64(int(intv)) {
+                                       return intTag, int(intv)
+                               } else {
+                                       return intTag, intv
+                               }
+                       }
+                       uintv, err := strconv.ParseUint(plain, 0, 64)
+                       if err == nil {
+                               return intTag, uintv
+                       }
+                       if yamlStyleFloat.MatchString(plain) {
+                               floatv, err := strconv.ParseFloat(plain, 64)
+                               if err == nil {
+                                       return floatTag, floatv
+                               }
+                       }
+                       if strings.HasPrefix(plain, "0b") {
+                               intv, err := strconv.ParseInt(plain[2:], 2, 64)
+                               if err == nil {
+                                       if intv == int64(int(intv)) {
+                                               return intTag, int(intv)
+                                       } else {
+                                               return intTag, intv
+                                       }
+                               }
+                               uintv, err := strconv.ParseUint(plain[2:], 2, 64)
+                               if err == nil {
+                                       return intTag, uintv
+                               }
+                       } else if strings.HasPrefix(plain, "-0b") {
+                               intv, err := strconv.ParseInt("-"+plain[3:], 2, 64)
+                               if err == nil {
+                                       if true || intv == int64(int(intv)) {
+                                               return intTag, int(intv)
+                                       } else {
+                                               return intTag, intv
+                                       }
+                               }
+                       }
+                       // Octals as introduced in version 1.2 of the spec.
+                       // Octals from the 1.1 spec, spelled as 0777, are still
+                       // decoded by default in v3 as well for compatibility.
+                       // May be dropped in v4 depending on how usage evolves.
+                       if strings.HasPrefix(plain, "0o") {
+                               intv, err := strconv.ParseInt(plain[2:], 8, 64)
+                               if err == nil {
+                                       if intv == int64(int(intv)) {
+                                               return intTag, int(intv)
+                                       } else {
+                                               return intTag, intv
+                                       }
+                               }
+                               uintv, err := strconv.ParseUint(plain[2:], 8, 64)
+                               if err == nil {
+                                       return intTag, uintv
+                               }
+                       } else if strings.HasPrefix(plain, "-0o") {
+                               intv, err := strconv.ParseInt("-"+plain[3:], 8, 64)
+                               if err == nil {
+                                       if true || intv == int64(int(intv)) {
+                                               return intTag, int(intv)
+                                       } else {
+                                               return intTag, intv
+                                       }
+                               }
+                       }
+               default:
+                       panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")")
+               }
+       }
+       return strTag, in
+}
+
+// encodeBase64 encodes s as base64 that is broken up into multiple lines
+// as appropriate for the resulting length.
+func encodeBase64(s string) string {
+       const lineLen = 70
+       encLen := base64.StdEncoding.EncodedLen(len(s))
+       lines := encLen/lineLen + 1
+       buf := make([]byte, encLen*2+lines)
+       in := buf[0:encLen]
+       out := buf[encLen:]
+       base64.StdEncoding.Encode(in, []byte(s))
+       k := 0
+       for i := 0; i < len(in); i += lineLen {
+               j := i + lineLen
+               if j > len(in) {
+                       j = len(in)
+               }
+               k += copy(out[k:], in[i:j])
+               if lines > 1 {
+                       out[k] = '\n'
+                       k++
+               }
+       }
+       return string(out[:k])
+}
+
+// This is a subset of the formats allowed by the regular expression
+// defined at http://yaml.org/type/timestamp.html.
+var allowedTimestampFormats = []string{
+       "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
+       "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
+       "2006-1-2 15:4:5.999999999",       // space separated with no time zone
+       "2006-1-2",                        // date only
+       // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5"
+       // from the set of examples.
+}
+
+// parseTimestamp parses s as a timestamp string and
+// returns the timestamp and reports whether it succeeded.
+// Timestamp formats are defined at http://yaml.org/type/timestamp.html
+func parseTimestamp(s string) (time.Time, bool) {
+       // TODO write code to check all the formats supported by
+       // http://yaml.org/type/timestamp.html instead of using time.Parse.
+
+       // Quick check: all date formats start with YYYY-.
+       i := 0
+       for ; i < len(s); i++ {
+               if c := s[i]; c < '0' || c > '9' {
+                       break
+               }
+       }
+       if i != 4 || i == len(s) || s[i] != '-' {
+               return time.Time{}, false
+       }
+       for _, format := range allowedTimestampFormats {
+               if t, err := time.Parse(format, s); err == nil {
+                       return t, true
+               }
+       }
+       return time.Time{}, false
+}
diff --git a/vendor/gopkg.in/yaml.v3/scannerc.go b/vendor/gopkg.in/yaml.v3/scannerc.go
new file mode 100644 (file)
index 0000000..d28969b
--- /dev/null
@@ -0,0 +1,2895 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+       "bytes"
+       "fmt"
+)
+
+// Introduction
+// ************
+//
+// The following notes assume that you are familiar with the YAML specification
+// (http://yaml.org/spec/1.2/spec.html).  We mostly follow it, although in
+// some cases we are less restrictive that it requires.
+//
+// The process of transforming a YAML stream into a sequence of events is
+// divided on two steps: Scanning and Parsing.
+//
+// The Scanner transforms the input stream into a sequence of tokens, while the
+// parser transform the sequence of tokens produced by the Scanner into a
+// sequence of parsing events.
+//
+// The Scanner is rather clever and complicated. The Parser, on the contrary,
+// is a straightforward implementation of a recursive-descendant parser (or,
+// LL(1) parser, as it is usually called).
+//
+// Actually there are two issues of Scanning that might be called "clever", the
+// rest is quite straightforward.  The issues are "block collection start" and
+// "simple keys".  Both issues are explained below in details.
+//
+// Here the Scanning step is explained and implemented.  We start with the list
+// of all the tokens produced by the Scanner together with short descriptions.
+//
+// Now, tokens:
+//
+//      STREAM-START(encoding)          # The stream start.
+//      STREAM-END                      # The stream end.
+//      VERSION-DIRECTIVE(major,minor)  # The '%YAML' directive.
+//      TAG-DIRECTIVE(handle,prefix)    # The '%TAG' directive.
+//      DOCUMENT-START                  # '---'
+//      DOCUMENT-END                    # '...'
+//      BLOCK-SEQUENCE-START            # Indentation increase denoting a block
+//      BLOCK-MAPPING-START             # sequence or a block mapping.
+//      BLOCK-END                       # Indentation decrease.
+//      FLOW-SEQUENCE-START             # '['
+//      FLOW-SEQUENCE-END               # ']'
+//      BLOCK-SEQUENCE-START            # '{'
+//      BLOCK-SEQUENCE-END              # '}'
+//      BLOCK-ENTRY                     # '-'
+//      FLOW-ENTRY                      # ','
+//      KEY                             # '?' or nothing (simple keys).
+//      VALUE                           # ':'
+//      ALIAS(anchor)                   # '*anchor'
+//      ANCHOR(anchor)                  # '&anchor'
+//      TAG(handle,suffix)              # '!handle!suffix'
+//      SCALAR(value,style)             # A scalar.
+//
+// The following two tokens are "virtual" tokens denoting the beginning and the
+// end of the stream:
+//
+//      STREAM-START(encoding)
+//      STREAM-END
+//
+// We pass the information about the input stream encoding with the
+// STREAM-START token.
+//
+// The next two tokens are responsible for tags:
+//
+//      VERSION-DIRECTIVE(major,minor)
+//      TAG-DIRECTIVE(handle,prefix)
+//
+// Example:
+//
+//      %YAML   1.1
+//      %TAG    !   !foo
+//      %TAG    !yaml!  tag:yaml.org,2002:
+//      ---
+//
+// The correspoding sequence of tokens:
+//
+//      STREAM-START(utf-8)
+//      VERSION-DIRECTIVE(1,1)
+//      TAG-DIRECTIVE("!","!foo")
+//      TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
+//      DOCUMENT-START
+//      STREAM-END
+//
+// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
+// line.
+//
+// The document start and end indicators are represented by:
+//
+//      DOCUMENT-START
+//      DOCUMENT-END
+//
+// Note that if a YAML stream contains an implicit document (without '---'
+// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
+// produced.
+//
+// In the following examples, we present whole documents together with the
+// produced tokens.
+//
+//      1. An implicit document:
+//
+//          'a scalar'
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          SCALAR("a scalar",single-quoted)
+//          STREAM-END
+//
+//      2. An explicit document:
+//
+//          ---
+//          'a scalar'
+//          ...
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          DOCUMENT-START
+//          SCALAR("a scalar",single-quoted)
+//          DOCUMENT-END
+//          STREAM-END
+//
+//      3. Several documents in a stream:
+//
+//          'a scalar'
+//          ---
+//          'another scalar'
+//          ---
+//          'yet another scalar'
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          SCALAR("a scalar",single-quoted)
+//          DOCUMENT-START
+//          SCALAR("another scalar",single-quoted)
+//          DOCUMENT-START
+//          SCALAR("yet another scalar",single-quoted)
+//          STREAM-END
+//
+// We have already introduced the SCALAR token above.  The following tokens are
+// used to describe aliases, anchors, tag, and scalars:
+//
+//      ALIAS(anchor)
+//      ANCHOR(anchor)
+//      TAG(handle,suffix)
+//      SCALAR(value,style)
+//
+// The following series of examples illustrate the usage of these tokens:
+//
+//      1. A recursive sequence:
+//
+//          &A [ *A ]
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          ANCHOR("A")
+//          FLOW-SEQUENCE-START
+//          ALIAS("A")
+//          FLOW-SEQUENCE-END
+//          STREAM-END
+//
+//      2. A tagged scalar:
+//
+//          !!float "3.14"  # A good approximation.
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          TAG("!!","float")
+//          SCALAR("3.14",double-quoted)
+//          STREAM-END
+//
+//      3. Various scalar styles:
+//
+//          --- # Implicit empty plain scalars do not produce tokens.
+//          --- a plain scalar
+//          --- 'a single-quoted scalar'
+//          --- "a double-quoted scalar"
+//          --- |-
+//            a literal scalar
+//          --- >-
+//            a folded
+//            scalar
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          DOCUMENT-START
+//          DOCUMENT-START
+//          SCALAR("a plain scalar",plain)
+//          DOCUMENT-START
+//          SCALAR("a single-quoted scalar",single-quoted)
+//          DOCUMENT-START
+//          SCALAR("a double-quoted scalar",double-quoted)
+//          DOCUMENT-START
+//          SCALAR("a literal scalar",literal)
+//          DOCUMENT-START
+//          SCALAR("a folded scalar",folded)
+//          STREAM-END
+//
+// Now it's time to review collection-related tokens. We will start with
+// flow collections:
+//
+//      FLOW-SEQUENCE-START
+//      FLOW-SEQUENCE-END
+//      FLOW-MAPPING-START
+//      FLOW-MAPPING-END
+//      FLOW-ENTRY
+//      KEY
+//      VALUE
+//
+// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
+// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
+// correspondingly.  FLOW-ENTRY represent the ',' indicator.  Finally the
+// indicators '?' and ':', which are used for denoting mapping keys and values,
+// are represented by the KEY and VALUE tokens.
+//
+// The following examples show flow collections:
+//
+//      1. A flow sequence:
+//
+//          [item 1, item 2, item 3]
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          FLOW-SEQUENCE-START
+//          SCALAR("item 1",plain)
+//          FLOW-ENTRY
+//          SCALAR("item 2",plain)
+//          FLOW-ENTRY
+//          SCALAR("item 3",plain)
+//          FLOW-SEQUENCE-END
+//          STREAM-END
+//
+//      2. A flow mapping:
+//
+//          {
+//              a simple key: a value,  # Note that the KEY token is produced.
+//              ? a complex key: another value,
+//          }
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          FLOW-MAPPING-START
+//          KEY
+//          SCALAR("a simple key",plain)
+//          VALUE
+//          SCALAR("a value",plain)
+//          FLOW-ENTRY
+//          KEY
+//          SCALAR("a complex key",plain)
+//          VALUE
+//          SCALAR("another value",plain)
+//          FLOW-ENTRY
+//          FLOW-MAPPING-END
+//          STREAM-END
+//
+// A simple key is a key which is not denoted by the '?' indicator.  Note that
+// the Scanner still produce the KEY token whenever it encounters a simple key.
+//
+// For scanning block collections, the following tokens are used (note that we
+// repeat KEY and VALUE here):
+//
+//      BLOCK-SEQUENCE-START
+//      BLOCK-MAPPING-START
+//      BLOCK-END
+//      BLOCK-ENTRY
+//      KEY
+//      VALUE
+//
+// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
+// increase that precedes a block collection (cf. the INDENT token in Python).
+// The token BLOCK-END denote indentation decrease that ends a block collection
+// (cf. the DEDENT token in Python).  However YAML has some syntax pecularities
+// that makes detections of these tokens more complex.
+//
+// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
+// '-', '?', and ':' correspondingly.
+//
+// The following examples show how the tokens BLOCK-SEQUENCE-START,
+// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
+//
+//      1. Block sequences:
+//
+//          - item 1
+//          - item 2
+//          -
+//            - item 3.1
+//            - item 3.2
+//          -
+//            key 1: value 1
+//            key 2: value 2
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-ENTRY
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 3.1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 3.2",plain)
+//          BLOCK-END
+//          BLOCK-ENTRY
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+//      2. Block mappings:
+//
+//          a simple key: a value   # The KEY token is produced here.
+//          ? a complex key
+//          : another value
+//          a mapping:
+//            key 1: value 1
+//            key 2: value 2
+//          a sequence:
+//            - item 1
+//            - item 2
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("a simple key",plain)
+//          VALUE
+//          SCALAR("a value",plain)
+//          KEY
+//          SCALAR("a complex key",plain)
+//          VALUE
+//          SCALAR("another value",plain)
+//          KEY
+//          SCALAR("a mapping",plain)
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          KEY
+//          SCALAR("a sequence",plain)
+//          VALUE
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+// YAML does not always require to start a new block collection from a new
+// line.  If the current line contains only '-', '?', and ':' indicators, a new
+// block collection may start at the current line.  The following examples
+// illustrate this case:
+//
+//      1. Collections in a sequence:
+//
+//          - - item 1
+//            - item 2
+//          - key 1: value 1
+//            key 2: value 2
+//          - ? complex key
+//            : complex value
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-END
+//          BLOCK-ENTRY
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          BLOCK-ENTRY
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("complex key")
+//          VALUE
+//          SCALAR("complex value")
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+//      2. Collections in a mapping:
+//
+//          ? a sequence
+//          : - item 1
+//            - item 2
+//          ? a mapping
+//          : key 1: value 1
+//            key 2: value 2
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("a sequence",plain)
+//          VALUE
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-END
+//          KEY
+//          SCALAR("a mapping",plain)
+//          VALUE
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+// YAML also permits non-indented sequences if they are included into a block
+// mapping.  In this case, the token BLOCK-SEQUENCE-START is not produced:
+//
+//      key:
+//      - item 1    # BLOCK-SEQUENCE-START is NOT produced here.
+//      - item 2
+//
+// Tokens:
+//
+//      STREAM-START(utf-8)
+//      BLOCK-MAPPING-START
+//      KEY
+//      SCALAR("key",plain)
+//      VALUE
+//      BLOCK-ENTRY
+//      SCALAR("item 1",plain)
+//      BLOCK-ENTRY
+//      SCALAR("item 2",plain)
+//      BLOCK-END
+//
+
+// Ensure that the buffer contains the required number of characters.
+// Return true on success, false on failure (reader error or memory error).
+func cache(parser *yaml_parser_t, length int) bool {
+       // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B)
+       return parser.unread >= length || yaml_parser_update_buffer(parser, length)
+}
+
+// Advance the buffer pointer.
+func skip(parser *yaml_parser_t) {
+       parser.mark.index++
+       parser.mark.column++
+       parser.unread--
+       parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
+}
+
+func skip_line(parser *yaml_parser_t) {
+       if is_crlf(parser.buffer, parser.buffer_pos) {
+               parser.mark.index += 2
+               parser.mark.column = 0
+               parser.mark.line++
+               parser.unread -= 2
+               parser.buffer_pos += 2
+       } else if is_break(parser.buffer, parser.buffer_pos) {
+               parser.mark.index++
+               parser.mark.column = 0
+               parser.mark.line++
+               parser.unread--
+               parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
+       }
+}
+
+// Copy a character to a string buffer and advance pointers.
+func read(parser *yaml_parser_t, s []byte) []byte {
+       w := width(parser.buffer[parser.buffer_pos])
+       if w == 0 {
+               panic("invalid character sequence")
+       }
+       if len(s) == 0 {
+               s = make([]byte, 0, 32)
+       }
+       if w == 1 && len(s)+w <= cap(s) {
+               s = s[:len(s)+1]
+               s[len(s)-1] = parser.buffer[parser.buffer_pos]
+               parser.buffer_pos++
+       } else {
+               s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...)
+               parser.buffer_pos += w
+       }
+       parser.mark.index++
+       parser.mark.column++
+       parser.unread--
+       return s
+}
+
+// Copy a line break character to a string buffer and advance pointers.
+func read_line(parser *yaml_parser_t, s []byte) []byte {
+       buf := parser.buffer
+       pos := parser.buffer_pos
+       switch {
+       case buf[pos] == '\r' && buf[pos+1] == '\n':
+               // CR LF . LF
+               s = append(s, '\n')
+               parser.buffer_pos += 2
+               parser.mark.index++
+               parser.unread--
+       case buf[pos] == '\r' || buf[pos] == '\n':
+               // CR|LF . LF
+               s = append(s, '\n')
+               parser.buffer_pos += 1
+       case buf[pos] == '\xC2' && buf[pos+1] == '\x85':
+               // NEL . LF
+               s = append(s, '\n')
+               parser.buffer_pos += 2
+       case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'):
+               // LS|PS . LS|PS
+               s = append(s, buf[parser.buffer_pos:pos+3]...)
+               parser.buffer_pos += 3
+       default:
+               return s
+       }
+       parser.mark.index++
+       parser.mark.column = 0
+       parser.mark.line++
+       parser.unread--
+       return s
+}
+
+// Get the next token.
+func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool {
+       // Erase the token object.
+       *token = yaml_token_t{} // [Go] Is this necessary?
+
+       // No tokens after STREAM-END or error.
+       if parser.stream_end_produced || parser.error != yaml_NO_ERROR {
+               return true
+       }
+
+       // Ensure that the tokens queue contains enough tokens.
+       if !parser.token_available {
+               if !yaml_parser_fetch_more_tokens(parser) {
+                       return false
+               }
+       }
+
+       // Fetch the next token from the queue.
+       *token = parser.tokens[parser.tokens_head]
+       parser.tokens_head++
+       parser.tokens_parsed++
+       parser.token_available = false
+
+       if token.typ == yaml_STREAM_END_TOKEN {
+               parser.stream_end_produced = true
+       }
+       return true
+}
+
+// Set the scanner error and return false.
+func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool {
+       parser.error = yaml_SCANNER_ERROR
+       parser.context = context
+       parser.context_mark = context_mark
+       parser.problem = problem
+       parser.problem_mark = parser.mark
+       return false
+}
+
+func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool {
+       context := "while parsing a tag"
+       if directive {
+               context = "while parsing a %TAG directive"
+       }
+       return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
+}
+
+func trace(args ...interface{}) func() {
+       pargs := append([]interface{}{"+++"}, args...)
+       fmt.Println(pargs...)
+       pargs = append([]interface{}{"---"}, args...)
+       return func() { fmt.Println(pargs...) }
+}
+
+// Ensure that the tokens queue contains at least one token which can be
+// returned to the Parser.
+func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
+       // While we need more tokens to fetch, do it.
+       for {
+               // Check if we really need to fetch more tokens.
+               need_more_tokens := false
+
+               // [Go] When parsing flow items, force the queue to have at least
+               // two items so that comments after commas may be associated
+               // with the value being parsed before them.
+               if parser.tokens_head == len(parser.tokens) || parser.flow_level > 0 && parser.tokens_head >= len(parser.tokens)-1 {
+                       // Queue is empty or has just one element inside a flow context.
+                       need_more_tokens = true
+               } else {
+                       // Check if any potential simple key may occupy the head position.
+                       if !yaml_parser_stale_simple_keys(parser) {
+                               return false
+                       }
+
+                       for i := range parser.simple_keys {
+                               simple_key := &parser.simple_keys[i]
+                               if simple_key.possible && simple_key.token_number == parser.tokens_parsed {
+                                       need_more_tokens = true
+                                       break
+                               }
+                       }
+               }
+
+               // We are finished.
+               if !need_more_tokens {
+                       break
+               }
+               // Fetch the next token.
+               if !yaml_parser_fetch_next_token(parser) {
+                       return false
+               }
+       }
+
+       parser.token_available = true
+       return true
+}
+
+// The dispatcher for token fetchers.
+func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) {
+       // Ensure that the buffer is initialized.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+
+       // Check if we just started scanning.  Fetch STREAM-START then.
+       if !parser.stream_start_produced {
+               return yaml_parser_fetch_stream_start(parser)
+       }
+
+       // Eat whitespaces and comments until we reach the next token.
+       if !yaml_parser_scan_to_next_token(parser) {
+               return false
+       }
+
+       // Remove obsolete potential simple keys.
+       if !yaml_parser_stale_simple_keys(parser) {
+               return false
+       }
+
+       // Check the indentation level against the current column.
+       if !yaml_parser_unroll_indent(parser, parser.mark.column) {
+               return false
+       }
+
+       // Ensure that the buffer contains at least 4 characters.  4 is the length
+       // of the longest indicators ('--- ' and '... ').
+       if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
+               return false
+       }
+
+       // Is it the end of the stream?
+       if is_z(parser.buffer, parser.buffer_pos) {
+               return yaml_parser_fetch_stream_end(parser)
+       }
+
+       // Is it a directive?
+       if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' {
+               return yaml_parser_fetch_directive(parser)
+       }
+
+       buf := parser.buffer
+       pos := parser.buffer_pos
+
+       // Is it the document start indicator?
+       if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) {
+               return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN)
+       }
+
+       // Is it the document end indicator?
+       if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) {
+               return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN)
+       }
+
+       comment_mark := parser.mark
+       if parser.flow_level > 0 && buf[pos] == ',' && len(parser.tokens) > 0 {
+               // Associate any following comments with the prior token.
+               comment_mark = parser.tokens[len(parser.tokens)-1].start_mark
+       }
+       defer func() {
+               if !ok {
+                       return
+               }
+               if !yaml_parser_scan_line_comment(parser, comment_mark) {
+                       ok = false
+                       return
+               }
+               if !yaml_parser_scan_foot_comment(parser, comment_mark) {
+                       ok = false
+                       return
+               }
+       }()
+
+       // Is it the flow sequence start indicator?
+       if buf[pos] == '[' {
+               return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN)
+       }
+
+       // Is it the flow mapping start indicator?
+       if parser.buffer[parser.buffer_pos] == '{' {
+               return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN)
+       }
+
+       // Is it the flow sequence end indicator?
+       if parser.buffer[parser.buffer_pos] == ']' {
+               return yaml_parser_fetch_flow_collection_end(parser,
+                       yaml_FLOW_SEQUENCE_END_TOKEN)
+       }
+
+       // Is it the flow mapping end indicator?
+       if parser.buffer[parser.buffer_pos] == '}' {
+               return yaml_parser_fetch_flow_collection_end(parser,
+                       yaml_FLOW_MAPPING_END_TOKEN)
+       }
+
+       // Is it the flow entry indicator?
+       if parser.buffer[parser.buffer_pos] == ',' {
+               return yaml_parser_fetch_flow_entry(parser)
+       }
+
+       // Is it the block entry indicator?
+       if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) {
+               return yaml_parser_fetch_block_entry(parser)
+       }
+
+       // Is it the key indicator?
+       if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
+               return yaml_parser_fetch_key(parser)
+       }
+
+       // Is it the value indicator?
+       if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
+               return yaml_parser_fetch_value(parser)
+       }
+
+       // Is it an alias?
+       if parser.buffer[parser.buffer_pos] == '*' {
+               return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN)
+       }
+
+       // Is it an anchor?
+       if parser.buffer[parser.buffer_pos] == '&' {
+               return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN)
+       }
+
+       // Is it a tag?
+       if parser.buffer[parser.buffer_pos] == '!' {
+               return yaml_parser_fetch_tag(parser)
+       }
+
+       // Is it a literal scalar?
+       if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 {
+               return yaml_parser_fetch_block_scalar(parser, true)
+       }
+
+       // Is it a folded scalar?
+       if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 {
+               return yaml_parser_fetch_block_scalar(parser, false)
+       }
+
+       // Is it a single-quoted scalar?
+       if parser.buffer[parser.buffer_pos] == '\'' {
+               return yaml_parser_fetch_flow_scalar(parser, true)
+       }
+
+       // Is it a double-quoted scalar?
+       if parser.buffer[parser.buffer_pos] == '"' {
+               return yaml_parser_fetch_flow_scalar(parser, false)
+       }
+
+       // Is it a plain scalar?
+       //
+       // A plain scalar may start with any non-blank characters except
+       //
+       //      '-', '?', ':', ',', '[', ']', '{', '}',
+       //      '#', '&', '*', '!', '|', '>', '\'', '\"',
+       //      '%', '@', '`'.
+       //
+       // In the block context (and, for the '-' indicator, in the flow context
+       // too), it may also start with the characters
+       //
+       //      '-', '?', ':'
+       //
+       // if it is followed by a non-space character.
+       //
+       // The last rule is more restrictive than the specification requires.
+       // [Go] TODO Make this logic more reasonable.
+       //switch parser.buffer[parser.buffer_pos] {
+       //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`':
+       //}
+       if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' ||
+               parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' ||
+               parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' ||
+               parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
+               parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' ||
+               parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' ||
+               parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' ||
+               parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' ||
+               parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' ||
+               parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') ||
+               (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) ||
+               (parser.flow_level == 0 &&
+                       (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') &&
+                       !is_blankz(parser.buffer, parser.buffer_pos+1)) {
+               return yaml_parser_fetch_plain_scalar(parser)
+       }
+
+       // If we don't determine the token type so far, it is an error.
+       return yaml_parser_set_scanner_error(parser,
+               "while scanning for the next token", parser.mark,
+               "found character that cannot start any token")
+}
+
+// Check the list of potential simple keys and remove the positions that
+// cannot contain simple keys anymore.
+func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool {
+       // Check for a potential simple key for each flow level.
+       for i := range parser.simple_keys {
+               simple_key := &parser.simple_keys[i]
+
+               // The specification requires that a simple key
+               //
+               //  - is limited to a single line,
+               //  - is shorter than 1024 characters.
+               if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) {
+
+                       // Check if the potential simple key to be removed is required.
+                       if simple_key.required {
+                               return yaml_parser_set_scanner_error(parser,
+                                       "while scanning a simple key", simple_key.mark,
+                                       "could not find expected ':'")
+                       }
+                       simple_key.possible = false
+               }
+       }
+       return true
+}
+
+// Check if a simple key may start at the current position and add it if
+// needed.
+func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
+       // A simple key is required at the current position if the scanner is in
+       // the block context and the current column coincides with the indentation
+       // level.
+
+       required := parser.flow_level == 0 && parser.indent == parser.mark.column
+
+       //
+       // If the current position may start a simple key, save it.
+       //
+       if parser.simple_key_allowed {
+               simple_key := yaml_simple_key_t{
+                       possible:     true,
+                       required:     required,
+                       token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
+               }
+               simple_key.mark = parser.mark
+
+               if !yaml_parser_remove_simple_key(parser) {
+                       return false
+               }
+               parser.simple_keys[len(parser.simple_keys)-1] = simple_key
+       }
+       return true
+}
+
+// Remove a potential simple key at the current flow level.
+func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
+       i := len(parser.simple_keys) - 1
+       if parser.simple_keys[i].possible {
+               // If the key is required, it is an error.
+               if parser.simple_keys[i].required {
+                       return yaml_parser_set_scanner_error(parser,
+                               "while scanning a simple key", parser.simple_keys[i].mark,
+                               "could not find expected ':'")
+               }
+       }
+       // Remove the key from the stack.
+       parser.simple_keys[i].possible = false
+       return true
+}
+
+// Increase the flow level and resize the simple key list if needed.
+func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
+       // Reset the simple key on the next level.
+       parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
+
+       // Increase the flow level.
+       parser.flow_level++
+       return true
+}
+
+// Decrease the flow level.
+func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
+       if parser.flow_level > 0 {
+               parser.flow_level--
+               parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1]
+       }
+       return true
+}
+
+// Push the current indentation level to the stack and set the new level
+// the current column is greater than the indentation level.  In this case,
+// append or insert the specified token into the token queue.
+func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool {
+       // In the flow context, do nothing.
+       if parser.flow_level > 0 {
+               return true
+       }
+
+       if parser.indent < column {
+               // Push the current indentation level to the stack and set the new
+               // indentation level.
+               parser.indents = append(parser.indents, parser.indent)
+               parser.indent = column
+
+               // Create a token and insert it into the queue.
+               token := yaml_token_t{
+                       typ:        typ,
+                       start_mark: mark,
+                       end_mark:   mark,
+               }
+               if number > -1 {
+                       number -= parser.tokens_parsed
+               }
+               yaml_insert_token(parser, number, &token)
+       }
+       return true
+}
+
+// Pop indentation levels from the indents stack until the current level
+// becomes less or equal to the column.  For each indentation level, append
+// the BLOCK-END token.
+func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool {
+       // In the flow context, do nothing.
+       if parser.flow_level > 0 {
+               return true
+       }
+
+       // Loop through the indentation levels in the stack.
+       for parser.indent > column {
+               // Create a token and append it to the queue.
+               token := yaml_token_t{
+                       typ:        yaml_BLOCK_END_TOKEN,
+                       start_mark: parser.mark,
+                       end_mark:   parser.mark,
+               }
+               yaml_insert_token(parser, -1, &token)
+
+               // Pop the indentation level.
+               parser.indent = parser.indents[len(parser.indents)-1]
+               parser.indents = parser.indents[:len(parser.indents)-1]
+       }
+       return true
+}
+
+// Initialize the scanner and produce the STREAM-START token.
+func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
+
+       // Set the initial indentation.
+       parser.indent = -1
+
+       // Initialize the simple key stack.
+       parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
+
+       // A simple key is allowed at the beginning of the stream.
+       parser.simple_key_allowed = true
+
+       // We have started.
+       parser.stream_start_produced = true
+
+       // Create the STREAM-START token and append it to the queue.
+       token := yaml_token_t{
+               typ:        yaml_STREAM_START_TOKEN,
+               start_mark: parser.mark,
+               end_mark:   parser.mark,
+               encoding:   parser.encoding,
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the STREAM-END token and shut down the scanner.
+func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool {
+
+       // Force new line.
+       if parser.mark.column != 0 {
+               parser.mark.column = 0
+               parser.mark.line++
+       }
+
+       // Reset the indentation level.
+       if !yaml_parser_unroll_indent(parser, -1) {
+               return false
+       }
+
+       // Reset simple keys.
+       if !yaml_parser_remove_simple_key(parser) {
+               return false
+       }
+
+       parser.simple_key_allowed = false
+
+       // Create the STREAM-END token and append it to the queue.
+       token := yaml_token_t{
+               typ:        yaml_STREAM_END_TOKEN,
+               start_mark: parser.mark,
+               end_mark:   parser.mark,
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
+func yaml_parser_fetch_directive(parser *yaml_parser_t) bool {
+       // Reset the indentation level.
+       if !yaml_parser_unroll_indent(parser, -1) {
+               return false
+       }
+
+       // Reset simple keys.
+       if !yaml_parser_remove_simple_key(parser) {
+               return false
+       }
+
+       parser.simple_key_allowed = false
+
+       // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token.
+       token := yaml_token_t{}
+       if !yaml_parser_scan_directive(parser, &token) {
+               return false
+       }
+       // Append the token to the queue.
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the DOCUMENT-START or DOCUMENT-END token.
+func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+       // Reset the indentation level.
+       if !yaml_parser_unroll_indent(parser, -1) {
+               return false
+       }
+
+       // Reset simple keys.
+       if !yaml_parser_remove_simple_key(parser) {
+               return false
+       }
+
+       parser.simple_key_allowed = false
+
+       // Consume the token.
+       start_mark := parser.mark
+
+       skip(parser)
+       skip(parser)
+       skip(parser)
+
+       end_mark := parser.mark
+
+       // Create the DOCUMENT-START or DOCUMENT-END token.
+       token := yaml_token_t{
+               typ:        typ,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+       }
+       // Append the token to the queue.
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
+func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+
+       // The indicators '[' and '{' may start a simple key.
+       if !yaml_parser_save_simple_key(parser) {
+               return false
+       }
+
+       // Increase the flow level.
+       if !yaml_parser_increase_flow_level(parser) {
+               return false
+       }
+
+       // A simple key may follow the indicators '[' and '{'.
+       parser.simple_key_allowed = true
+
+       // Consume the token.
+       start_mark := parser.mark
+       skip(parser)
+       end_mark := parser.mark
+
+       // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token.
+       token := yaml_token_t{
+               typ:        typ,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+       }
+       // Append the token to the queue.
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
+func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+       // Reset any potential simple key on the current flow level.
+       if !yaml_parser_remove_simple_key(parser) {
+               return false
+       }
+
+       // Decrease the flow level.
+       if !yaml_parser_decrease_flow_level(parser) {
+               return false
+       }
+
+       // No simple keys after the indicators ']' and '}'.
+       parser.simple_key_allowed = false
+
+       // Consume the token.
+
+       start_mark := parser.mark
+       skip(parser)
+       end_mark := parser.mark
+
+       // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token.
+       token := yaml_token_t{
+               typ:        typ,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+       }
+       // Append the token to the queue.
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the FLOW-ENTRY token.
+func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool {
+       // Reset any potential simple keys on the current flow level.
+       if !yaml_parser_remove_simple_key(parser) {
+               return false
+       }
+
+       // Simple keys are allowed after ','.
+       parser.simple_key_allowed = true
+
+       // Consume the token.
+       start_mark := parser.mark
+       skip(parser)
+       end_mark := parser.mark
+
+       // Create the FLOW-ENTRY token and append it to the queue.
+       token := yaml_token_t{
+               typ:        yaml_FLOW_ENTRY_TOKEN,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the BLOCK-ENTRY token.
+func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool {
+       // Check if the scanner is in the block context.
+       if parser.flow_level == 0 {
+               // Check if we are allowed to start a new entry.
+               if !parser.simple_key_allowed {
+                       return yaml_parser_set_scanner_error(parser, "", parser.mark,
+                               "block sequence entries are not allowed in this context")
+               }
+               // Add the BLOCK-SEQUENCE-START token if needed.
+               if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) {
+                       return false
+               }
+       } else {
+               // It is an error for the '-' indicator to occur in the flow context,
+               // but we let the Parser detect and report about it because the Parser
+               // is able to point to the context.
+       }
+
+       // Reset any potential simple keys on the current flow level.
+       if !yaml_parser_remove_simple_key(parser) {
+               return false
+       }
+
+       // Simple keys are allowed after '-'.
+       parser.simple_key_allowed = true
+
+       // Consume the token.
+       start_mark := parser.mark
+       skip(parser)
+       end_mark := parser.mark
+
+       // Create the BLOCK-ENTRY token and append it to the queue.
+       token := yaml_token_t{
+               typ:        yaml_BLOCK_ENTRY_TOKEN,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the KEY token.
+func yaml_parser_fetch_key(parser *yaml_parser_t) bool {
+
+       // In the block context, additional checks are required.
+       if parser.flow_level == 0 {
+               // Check if we are allowed to start a new key (not nessesary simple).
+               if !parser.simple_key_allowed {
+                       return yaml_parser_set_scanner_error(parser, "", parser.mark,
+                               "mapping keys are not allowed in this context")
+               }
+               // Add the BLOCK-MAPPING-START token if needed.
+               if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
+                       return false
+               }
+       }
+
+       // Reset any potential simple keys on the current flow level.
+       if !yaml_parser_remove_simple_key(parser) {
+               return false
+       }
+
+       // Simple keys are allowed after '?' in the block context.
+       parser.simple_key_allowed = parser.flow_level == 0
+
+       // Consume the token.
+       start_mark := parser.mark
+       skip(parser)
+       end_mark := parser.mark
+
+       // Create the KEY token and append it to the queue.
+       token := yaml_token_t{
+               typ:        yaml_KEY_TOKEN,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the VALUE token.
+func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
+
+       simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
+
+       // Have we found a simple key?
+       if simple_key.possible {
+               // Create the KEY token and insert it into the queue.
+               token := yaml_token_t{
+                       typ:        yaml_KEY_TOKEN,
+                       start_mark: simple_key.mark,
+                       end_mark:   simple_key.mark,
+               }
+               yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token)
+
+               // In the block context, we may need to add the BLOCK-MAPPING-START token.
+               if !yaml_parser_roll_indent(parser, simple_key.mark.column,
+                       simple_key.token_number,
+                       yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) {
+                       return false
+               }
+
+               // Remove the simple key.
+               simple_key.possible = false
+
+               // A simple key cannot follow another simple key.
+               parser.simple_key_allowed = false
+
+       } else {
+               // The ':' indicator follows a complex key.
+
+               // In the block context, extra checks are required.
+               if parser.flow_level == 0 {
+
+                       // Check if we are allowed to start a complex value.
+                       if !parser.simple_key_allowed {
+                               return yaml_parser_set_scanner_error(parser, "", parser.mark,
+                                       "mapping values are not allowed in this context")
+                       }
+
+                       // Add the BLOCK-MAPPING-START token if needed.
+                       if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
+                               return false
+                       }
+               }
+
+               // Simple keys after ':' are allowed in the block context.
+               parser.simple_key_allowed = parser.flow_level == 0
+       }
+
+       // Consume the token.
+       start_mark := parser.mark
+       skip(parser)
+       end_mark := parser.mark
+
+       // Create the VALUE token and append it to the queue.
+       token := yaml_token_t{
+               typ:        yaml_VALUE_TOKEN,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the ALIAS or ANCHOR token.
+func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+       // An anchor or an alias could be a simple key.
+       if !yaml_parser_save_simple_key(parser) {
+               return false
+       }
+
+       // A simple key cannot follow an anchor or an alias.
+       parser.simple_key_allowed = false
+
+       // Create the ALIAS or ANCHOR token and append it to the queue.
+       var token yaml_token_t
+       if !yaml_parser_scan_anchor(parser, &token, typ) {
+               return false
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the TAG token.
+func yaml_parser_fetch_tag(parser *yaml_parser_t) bool {
+       // A tag could be a simple key.
+       if !yaml_parser_save_simple_key(parser) {
+               return false
+       }
+
+       // A simple key cannot follow a tag.
+       parser.simple_key_allowed = false
+
+       // Create the TAG token and append it to the queue.
+       var token yaml_token_t
+       if !yaml_parser_scan_tag(parser, &token) {
+               return false
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
+func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool {
+       // Remove any potential simple keys.
+       if !yaml_parser_remove_simple_key(parser) {
+               return false
+       }
+
+       // A simple key may follow a block scalar.
+       parser.simple_key_allowed = true
+
+       // Create the SCALAR token and append it to the queue.
+       var token yaml_token_t
+       if !yaml_parser_scan_block_scalar(parser, &token, literal) {
+               return false
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
+func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool {
+       // A plain scalar could be a simple key.
+       if !yaml_parser_save_simple_key(parser) {
+               return false
+       }
+
+       // A simple key cannot follow a flow scalar.
+       parser.simple_key_allowed = false
+
+       // Create the SCALAR token and append it to the queue.
+       var token yaml_token_t
+       if !yaml_parser_scan_flow_scalar(parser, &token, single) {
+               return false
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Produce the SCALAR(...,plain) token.
+func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool {
+       // A plain scalar could be a simple key.
+       if !yaml_parser_save_simple_key(parser) {
+               return false
+       }
+
+       // A simple key cannot follow a flow scalar.
+       parser.simple_key_allowed = false
+
+       // Create the SCALAR token and append it to the queue.
+       var token yaml_token_t
+       if !yaml_parser_scan_plain_scalar(parser, &token) {
+               return false
+       }
+       yaml_insert_token(parser, -1, &token)
+       return true
+}
+
+// Eat whitespaces and comments until the next token is found.
+func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {
+
+       // Until the next token is not found.
+       for {
+               // Allow the BOM mark to start a line.
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+               if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) {
+                       skip(parser)
+               }
+
+               // Eat whitespaces.
+               // Tabs are allowed:
+               //  - in the flow context
+               //  - in the block context, but not at the beginning of the line or
+               //  after '-', '?', or ':' (complex value).
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+
+               for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') {
+                       skip(parser)
+                       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                               return false
+                       }
+               }
+
+               // Eat a comment until a line break.
+               if parser.buffer[parser.buffer_pos] == '#' {
+                       if !yaml_parser_scan_head_comment(parser, parser.mark) {
+                               return false
+                       }
+               }
+
+               // If it is a line break, eat it.
+               if is_break(parser.buffer, parser.buffer_pos) {
+                       if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                               return false
+                       }
+                       skip_line(parser)
+
+                       // In the block context, a new line may start a simple key.
+                       if parser.flow_level == 0 {
+                               parser.simple_key_allowed = true
+                       }
+               } else {
+                       break // We have found a token.
+               }
+       }
+
+       return true
+}
+
+// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
+//
+// Scope:
+//      %YAML    1.1    # a comment \n
+//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//      %TAG    !yaml!  tag:yaml.org,2002:  \n
+//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {
+       // Eat '%'.
+       start_mark := parser.mark
+       skip(parser)
+
+       // Scan the directive name.
+       var name []byte
+       if !yaml_parser_scan_directive_name(parser, start_mark, &name) {
+               return false
+       }
+
+       // Is it a YAML directive?
+       if bytes.Equal(name, []byte("YAML")) {
+               // Scan the VERSION directive value.
+               var major, minor int8
+               if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) {
+                       return false
+               }
+               end_mark := parser.mark
+
+               // Create a VERSION-DIRECTIVE token.
+               *token = yaml_token_t{
+                       typ:        yaml_VERSION_DIRECTIVE_TOKEN,
+                       start_mark: start_mark,
+                       end_mark:   end_mark,
+                       major:      major,
+                       minor:      minor,
+               }
+
+               // Is it a TAG directive?
+       } else if bytes.Equal(name, []byte("TAG")) {
+               // Scan the TAG directive value.
+               var handle, prefix []byte
+               if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) {
+                       return false
+               }
+               end_mark := parser.mark
+
+               // Create a TAG-DIRECTIVE token.
+               *token = yaml_token_t{
+                       typ:        yaml_TAG_DIRECTIVE_TOKEN,
+                       start_mark: start_mark,
+                       end_mark:   end_mark,
+                       value:      handle,
+                       prefix:     prefix,
+               }
+
+               // Unknown directive.
+       } else {
+               yaml_parser_set_scanner_error(parser, "while scanning a directive",
+                       start_mark, "found unknown directive name")
+               return false
+       }
+
+       // Eat the rest of the line including any comments.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+
+       for is_blank(parser.buffer, parser.buffer_pos) {
+               skip(parser)
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+       }
+
+       if parser.buffer[parser.buffer_pos] == '#' {
+               // [Go] Discard this inline comment for the time being.
+               //if !yaml_parser_scan_line_comment(parser, start_mark) {
+               //      return false
+               //}
+               for !is_breakz(parser.buffer, parser.buffer_pos) {
+                       skip(parser)
+                       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                               return false
+                       }
+               }
+       }
+
+       // Check if we are at the end of the line.
+       if !is_breakz(parser.buffer, parser.buffer_pos) {
+               yaml_parser_set_scanner_error(parser, "while scanning a directive",
+                       start_mark, "did not find expected comment or line break")
+               return false
+       }
+
+       // Eat a line break.
+       if is_break(parser.buffer, parser.buffer_pos) {
+               if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                       return false
+               }
+               skip_line(parser)
+       }
+
+       return true
+}
+
+// Scan the directive name.
+//
+// Scope:
+//      %YAML   1.1     # a comment \n
+//       ^^^^
+//      %TAG    !yaml!  tag:yaml.org,2002:  \n
+//       ^^^
+//
+func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {
+       // Consume the directive name.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+
+       var s []byte
+       for is_alpha(parser.buffer, parser.buffer_pos) {
+               s = read(parser, s)
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+       }
+
+       // Check if the name is empty.
+       if len(s) == 0 {
+               yaml_parser_set_scanner_error(parser, "while scanning a directive",
+                       start_mark, "could not find expected directive name")
+               return false
+       }
+
+       // Check for an blank character after the name.
+       if !is_blankz(parser.buffer, parser.buffer_pos) {
+               yaml_parser_set_scanner_error(parser, "while scanning a directive",
+                       start_mark, "found unexpected non-alphabetical character")
+               return false
+       }
+       *name = s
+       return true
+}
+
+// Scan the value of VERSION-DIRECTIVE.
+//
+// Scope:
+//      %YAML   1.1     # a comment \n
+//           ^^^^^^
+func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool {
+       // Eat whitespaces.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+       for is_blank(parser.buffer, parser.buffer_pos) {
+               skip(parser)
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+       }
+
+       // Consume the major version number.
+       if !yaml_parser_scan_version_directive_number(parser, start_mark, major) {
+               return false
+       }
+
+       // Eat '.'.
+       if parser.buffer[parser.buffer_pos] != '.' {
+               return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+                       start_mark, "did not find expected digit or '.' character")
+       }
+
+       skip(parser)
+
+       // Consume the minor version number.
+       if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) {
+               return false
+       }
+       return true
+}
+
+const max_number_length = 2
+
+// Scan the version number of VERSION-DIRECTIVE.
+//
+// Scope:
+//      %YAML   1.1     # a comment \n
+//              ^
+//      %YAML   1.1     # a comment \n
+//                ^
+func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool {
+
+       // Repeat while the next character is digit.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+       var value, length int8
+       for is_digit(parser.buffer, parser.buffer_pos) {
+               // Check if the number is too long.
+               length++
+               if length > max_number_length {
+                       return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+                               start_mark, "found extremely long version number")
+               }
+               value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos))
+               skip(parser)
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+       }
+
+       // Check if the number was present.
+       if length == 0 {
+               return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+                       start_mark, "did not find expected version number")
+       }
+       *number = value
+       return true
+}
+
+// Scan the value of a TAG-DIRECTIVE token.
+//
+// Scope:
+//      %TAG    !yaml!  tag:yaml.org,2002:  \n
+//          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {
+       var handle_value, prefix_value []byte
+
+       // Eat whitespaces.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+
+       for is_blank(parser.buffer, parser.buffer_pos) {
+               skip(parser)
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+       }
+
+       // Scan a handle.
+       if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) {
+               return false
+       }
+
+       // Expect a whitespace.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+       if !is_blank(parser.buffer, parser.buffer_pos) {
+               yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
+                       start_mark, "did not find expected whitespace")
+               return false
+       }
+
+       // Eat whitespaces.
+       for is_blank(parser.buffer, parser.buffer_pos) {
+               skip(parser)
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+       }
+
+       // Scan a prefix.
+       if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) {
+               return false
+       }
+
+       // Expect a whitespace or line break.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+       if !is_blankz(parser.buffer, parser.buffer_pos) {
+               yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
+                       start_mark, "did not find expected whitespace or line break")
+               return false
+       }
+
+       *handle = handle_value
+       *prefix = prefix_value
+       return true
+}
+
+func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool {
+       var s []byte
+
+       // Eat the indicator character.
+       start_mark := parser.mark
+       skip(parser)
+
+       // Consume the value.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+
+       for is_alpha(parser.buffer, parser.buffer_pos) {
+               s = read(parser, s)
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+       }
+
+       end_mark := parser.mark
+
+       /*
+        * Check if length of the anchor is greater than 0 and it is followed by
+        * a whitespace character or one of the indicators:
+        *
+        *      '?', ':', ',', ']', '}', '%', '@', '`'.
+        */
+
+       if len(s) == 0 ||
+               !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' ||
+                       parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' ||
+                       parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' ||
+                       parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' ||
+                       parser.buffer[parser.buffer_pos] == '`') {
+               context := "while scanning an alias"
+               if typ == yaml_ANCHOR_TOKEN {
+                       context = "while scanning an anchor"
+               }
+               yaml_parser_set_scanner_error(parser, context, start_mark,
+                       "did not find expected alphabetic or numeric character")
+               return false
+       }
+
+       // Create a token.
+       *token = yaml_token_t{
+               typ:        typ,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+               value:      s,
+       }
+
+       return true
+}
+
+/*
+ * Scan a TAG token.
+ */
+
+func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool {
+       var handle, suffix []byte
+
+       start_mark := parser.mark
+
+       // Check if the tag is in the canonical form.
+       if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+               return false
+       }
+
+       if parser.buffer[parser.buffer_pos+1] == '<' {
+               // Keep the handle as ''
+
+               // Eat '!<'
+               skip(parser)
+               skip(parser)
+
+               // Consume the tag value.
+               if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
+                       return false
+               }
+
+               // Check for '>' and eat it.
+               if parser.buffer[parser.buffer_pos] != '>' {
+                       yaml_parser_set_scanner_error(parser, "while scanning a tag",
+                               start_mark, "did not find the expected '>'")
+                       return false
+               }
+
+               skip(parser)
+       } else {
+               // The tag has either the '!suffix' or the '!handle!suffix' form.
+
+               // First, try to scan a handle.
+               if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) {
+                       return false
+               }
+
+               // Check if it is, indeed, handle.
+               if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' {
+                       // Scan the suffix now.
+                       if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
+                               return false
+                       }
+               } else {
+                       // It wasn't a handle after all.  Scan the rest of the tag.
+                       if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) {
+                               return false
+                       }
+
+                       // Set the handle to '!'.
+                       handle = []byte{'!'}
+
+                       // A special case: the '!' tag.  Set the handle to '' and the
+                       // suffix to '!'.
+                       if len(suffix) == 0 {
+                               handle, suffix = suffix, handle
+                       }
+               }
+       }
+
+       // Check the character which ends the tag.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+       if !is_blankz(parser.buffer, parser.buffer_pos) {
+               yaml_parser_set_scanner_error(parser, "while scanning a tag",
+                       start_mark, "did not find expected whitespace or line break")
+               return false
+       }
+
+       end_mark := parser.mark
+
+       // Create a token.
+       *token = yaml_token_t{
+               typ:        yaml_TAG_TOKEN,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+               value:      handle,
+               suffix:     suffix,
+       }
+       return true
+}
+
+// Scan a tag handle.
+func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool {
+       // Check the initial '!' character.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+       if parser.buffer[parser.buffer_pos] != '!' {
+               yaml_parser_set_scanner_tag_error(parser, directive,
+                       start_mark, "did not find expected '!'")
+               return false
+       }
+
+       var s []byte
+
+       // Copy the '!' character.
+       s = read(parser, s)
+
+       // Copy all subsequent alphabetical and numerical characters.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+       for is_alpha(parser.buffer, parser.buffer_pos) {
+               s = read(parser, s)
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+       }
+
+       // Check if the trailing character is '!' and copy it.
+       if parser.buffer[parser.buffer_pos] == '!' {
+               s = read(parser, s)
+       } else {
+               // It's either the '!' tag or not really a tag handle.  If it's a %TAG
+               // directive, it's an error.  If it's a tag token, it must be a part of URI.
+               if directive && string(s) != "!" {
+                       yaml_parser_set_scanner_tag_error(parser, directive,
+                               start_mark, "did not find expected '!'")
+                       return false
+               }
+       }
+
+       *handle = s
+       return true
+}
+
+// Scan a tag.
+func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
+       //size_t length = head ? strlen((char *)head) : 0
+       var s []byte
+       hasTag := len(head) > 0
+
+       // Copy the head if needed.
+       //
+       // Note that we don't copy the leading '!' character.
+       if len(head) > 1 {
+               s = append(s, head[1:]...)
+       }
+
+       // Scan the tag.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+
+       // The set of characters that may appear in URI is as follows:
+       //
+       //      '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
+       //      '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
+       //      '%'.
+       // [Go] TODO Convert this into more reasonable logic.
+       for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' ||
+               parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' ||
+               parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' ||
+               parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' ||
+               parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' ||
+               parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' ||
+               parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' ||
+               parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' ||
+               parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' ||
+               parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' ||
+               parser.buffer[parser.buffer_pos] == '%' {
+               // Check if it is a URI-escape sequence.
+               if parser.buffer[parser.buffer_pos] == '%' {
+                       if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) {
+                               return false
+                       }
+               } else {
+                       s = read(parser, s)
+               }
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+               hasTag = true
+       }
+
+       if !hasTag {
+               yaml_parser_set_scanner_tag_error(parser, directive,
+                       start_mark, "did not find expected tag URI")
+               return false
+       }
+       *uri = s
+       return true
+}
+
+// Decode an URI-escape sequence corresponding to a single UTF-8 character.
+func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool {
+
+       // Decode the required number of characters.
+       w := 1024
+       for w > 0 {
+               // Check for a URI-escaped octet.
+               if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
+                       return false
+               }
+
+               if !(parser.buffer[parser.buffer_pos] == '%' &&
+                       is_hex(parser.buffer, parser.buffer_pos+1) &&
+                       is_hex(parser.buffer, parser.buffer_pos+2)) {
+                       return yaml_parser_set_scanner_tag_error(parser, directive,
+                               start_mark, "did not find URI escaped octet")
+               }
+
+               // Get the octet.
+               octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2))
+
+               // If it is the leading octet, determine the length of the UTF-8 sequence.
+               if w == 1024 {
+                       w = width(octet)
+                       if w == 0 {
+                               return yaml_parser_set_scanner_tag_error(parser, directive,
+                                       start_mark, "found an incorrect leading UTF-8 octet")
+                       }
+               } else {
+                       // Check if the trailing octet is correct.
+                       if octet&0xC0 != 0x80 {
+                               return yaml_parser_set_scanner_tag_error(parser, directive,
+                                       start_mark, "found an incorrect trailing UTF-8 octet")
+                       }
+               }
+
+               // Copy the octet and move the pointers.
+               *s = append(*s, octet)
+               skip(parser)
+               skip(parser)
+               skip(parser)
+               w--
+       }
+       return true
+}
+
+// Scan a block scalar.
+func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool {
+       // Eat the indicator '|' or '>'.
+       start_mark := parser.mark
+       skip(parser)
+
+       // Scan the additional block scalar indicators.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+
+       // Check for a chomping indicator.
+       var chomping, increment int
+       if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
+               // Set the chomping method and eat the indicator.
+               if parser.buffer[parser.buffer_pos] == '+' {
+                       chomping = +1
+               } else {
+                       chomping = -1
+               }
+               skip(parser)
+
+               // Check for an indentation indicator.
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+               if is_digit(parser.buffer, parser.buffer_pos) {
+                       // Check that the indentation is greater than 0.
+                       if parser.buffer[parser.buffer_pos] == '0' {
+                               yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+                                       start_mark, "found an indentation indicator equal to 0")
+                               return false
+                       }
+
+                       // Get the indentation level and eat the indicator.
+                       increment = as_digit(parser.buffer, parser.buffer_pos)
+                       skip(parser)
+               }
+
+       } else if is_digit(parser.buffer, parser.buffer_pos) {
+               // Do the same as above, but in the opposite order.
+
+               if parser.buffer[parser.buffer_pos] == '0' {
+                       yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+                               start_mark, "found an indentation indicator equal to 0")
+                       return false
+               }
+               increment = as_digit(parser.buffer, parser.buffer_pos)
+               skip(parser)
+
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+               if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
+                       if parser.buffer[parser.buffer_pos] == '+' {
+                               chomping = +1
+                       } else {
+                               chomping = -1
+                       }
+                       skip(parser)
+               }
+       }
+
+       // Eat whitespaces and comments to the end of the line.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+       for is_blank(parser.buffer, parser.buffer_pos) {
+               skip(parser)
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+       }
+       if parser.buffer[parser.buffer_pos] == '#' {
+               if !yaml_parser_scan_line_comment(parser, start_mark) {
+                       return false
+               }
+       }
+
+       // Check if we are at the end of the line.
+       if !is_breakz(parser.buffer, parser.buffer_pos) {
+               yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+                       start_mark, "did not find expected comment or line break")
+               return false
+       }
+
+       // Eat a line break.
+       if is_break(parser.buffer, parser.buffer_pos) {
+               if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                       return false
+               }
+               skip_line(parser)
+       }
+
+       end_mark := parser.mark
+
+       // Set the indentation level if it was specified.
+       var indent int
+       if increment > 0 {
+               if parser.indent >= 0 {
+                       indent = parser.indent + increment
+               } else {
+                       indent = increment
+               }
+       }
+
+       // Scan the leading line breaks and determine the indentation level if needed.
+       var s, leading_break, trailing_breaks []byte
+       if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
+               return false
+       }
+
+       // Scan the block scalar content.
+       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+               return false
+       }
+       var leading_blank, trailing_blank bool
+       for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) {
+               // We are at the beginning of a non-empty line.
+
+               // Is it a trailing whitespace?
+               trailing_blank = is_blank(parser.buffer, parser.buffer_pos)
+
+               // Check if we need to fold the leading line break.
+               if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' {
+                       // Do we need to join the lines by space?
+                       if len(trailing_breaks) == 0 {
+                               s = append(s, ' ')
+                       }
+               } else {
+                       s = append(s, leading_break...)
+               }
+               leading_break = leading_break[:0]
+
+               // Append the remaining line breaks.
+               s = append(s, trailing_breaks...)
+               trailing_breaks = trailing_breaks[:0]
+
+               // Is it a leading whitespace?
+               leading_blank = is_blank(parser.buffer, parser.buffer_pos)
+
+               // Consume the current line.
+               for !is_breakz(parser.buffer, parser.buffer_pos) {
+                       s = read(parser, s)
+                       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                               return false
+                       }
+               }
+
+               // Consume the line break.
+               if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                       return false
+               }
+
+               leading_break = read_line(parser, leading_break)
+
+               // Eat the following indentation spaces and line breaks.
+               if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
+                       return false
+               }
+       }
+
+       // Chomp the tail.
+       if chomping != -1 {
+               s = append(s, leading_break...)
+       }
+       if chomping == 1 {
+               s = append(s, trailing_breaks...)
+       }
+
+       // Create a token.
+       *token = yaml_token_t{
+               typ:        yaml_SCALAR_TOKEN,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+               value:      s,
+               style:      yaml_LITERAL_SCALAR_STYLE,
+       }
+       if !literal {
+               token.style = yaml_FOLDED_SCALAR_STYLE
+       }
+       return true
+}
+
+// Scan indentation spaces and line breaks for a block scalar.  Determine the
+// indentation level if needed.
+func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool {
+       *end_mark = parser.mark
+
+       // Eat the indentation spaces and line breaks.
+       max_indent := 0
+       for {
+               // Eat the indentation spaces.
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+               for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) {
+                       skip(parser)
+                       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                               return false
+                       }
+               }
+               if parser.mark.column > max_indent {
+                       max_indent = parser.mark.column
+               }
+
+               // Check for a tab character messing the indentation.
+               if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) {
+                       return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+                               start_mark, "found a tab character where an indentation space is expected")
+               }
+
+               // Have we found a non-empty line?
+               if !is_break(parser.buffer, parser.buffer_pos) {
+                       break
+               }
+
+               // Consume the line break.
+               if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                       return false
+               }
+               // [Go] Should really be returning breaks instead.
+               *breaks = read_line(parser, *breaks)
+               *end_mark = parser.mark
+       }
+
+       // Determine the indentation level if needed.
+       if *indent == 0 {
+               *indent = max_indent
+               if *indent < parser.indent+1 {
+                       *indent = parser.indent + 1
+               }
+               if *indent < 1 {
+                       *indent = 1
+               }
+       }
+       return true
+}
+
+// Scan a quoted scalar.
+func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool {
+       // Eat the left quote.
+       start_mark := parser.mark
+       skip(parser)
+
+       // Consume the content of the quoted scalar.
+       var s, leading_break, trailing_breaks, whitespaces []byte
+       for {
+               // Check that there are no document indicators at the beginning of the line.
+               if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
+                       return false
+               }
+
+               if parser.mark.column == 0 &&
+                       ((parser.buffer[parser.buffer_pos+0] == '-' &&
+                               parser.buffer[parser.buffer_pos+1] == '-' &&
+                               parser.buffer[parser.buffer_pos+2] == '-') ||
+                               (parser.buffer[parser.buffer_pos+0] == '.' &&
+                                       parser.buffer[parser.buffer_pos+1] == '.' &&
+                                       parser.buffer[parser.buffer_pos+2] == '.')) &&
+                       is_blankz(parser.buffer, parser.buffer_pos+3) {
+                       yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
+                               start_mark, "found unexpected document indicator")
+                       return false
+               }
+
+               // Check for EOF.
+               if is_z(parser.buffer, parser.buffer_pos) {
+                       yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
+                               start_mark, "found unexpected end of stream")
+                       return false
+               }
+
+               // Consume non-blank characters.
+               leading_blanks := false
+               for !is_blankz(parser.buffer, parser.buffer_pos) {
+                       if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' {
+                               // Is is an escaped single quote.
+                               s = append(s, '\'')
+                               skip(parser)
+                               skip(parser)
+
+                       } else if single && parser.buffer[parser.buffer_pos] == '\'' {
+                               // It is a right single quote.
+                               break
+                       } else if !single && parser.buffer[parser.buffer_pos] == '"' {
+                               // It is a right double quote.
+                               break
+
+                       } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) {
+                               // It is an escaped line break.
+                               if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
+                                       return false
+                               }
+                               skip(parser)
+                               skip_line(parser)
+                               leading_blanks = true
+                               break
+
+                       } else if !single && parser.buffer[parser.buffer_pos] == '\\' {
+                               // It is an escape sequence.
+                               code_length := 0
+
+                               // Check the escape character.
+                               switch parser.buffer[parser.buffer_pos+1] {
+                               case '0':
+                                       s = append(s, 0)
+                               case 'a':
+                                       s = append(s, '\x07')
+                               case 'b':
+                                       s = append(s, '\x08')
+                               case 't', '\t':
+                                       s = append(s, '\x09')
+                               case 'n':
+                                       s = append(s, '\x0A')
+                               case 'v':
+                                       s = append(s, '\x0B')
+                               case 'f':
+                                       s = append(s, '\x0C')
+                               case 'r':
+                                       s = append(s, '\x0D')
+                               case 'e':
+                                       s = append(s, '\x1B')
+                               case ' ':
+                                       s = append(s, '\x20')
+                               case '"':
+                                       s = append(s, '"')
+                               case '\'':
+                                       s = append(s, '\'')
+                               case '\\':
+                                       s = append(s, '\\')
+                               case 'N': // NEL (#x85)
+                                       s = append(s, '\xC2')
+                                       s = append(s, '\x85')
+                               case '_': // #xA0
+                                       s = append(s, '\xC2')
+                                       s = append(s, '\xA0')
+                               case 'L': // LS (#x2028)
+                                       s = append(s, '\xE2')
+                                       s = append(s, '\x80')
+                                       s = append(s, '\xA8')
+                               case 'P': // PS (#x2029)
+                                       s = append(s, '\xE2')
+                                       s = append(s, '\x80')
+                                       s = append(s, '\xA9')
+                               case 'x':
+                                       code_length = 2
+                               case 'u':
+                                       code_length = 4
+                               case 'U':
+                                       code_length = 8
+                               default:
+                                       yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+                                               start_mark, "found unknown escape character")
+                                       return false
+                               }
+
+                               skip(parser)
+                               skip(parser)
+
+                               // Consume an arbitrary escape code.
+                               if code_length > 0 {
+                                       var value int
+
+                                       // Scan the character value.
+                                       if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) {
+                                               return false
+                                       }
+                                       for k := 0; k < code_length; k++ {
+                                               if !is_hex(parser.buffer, parser.buffer_pos+k) {
+                                                       yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+                                                               start_mark, "did not find expected hexdecimal number")
+                                                       return false
+                                               }
+                                               value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k)
+                                       }
+
+                                       // Check the value and write the character.
+                                       if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {
+                                               yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+                                                       start_mark, "found invalid Unicode character escape code")
+                                               return false
+                                       }
+                                       if value <= 0x7F {
+                                               s = append(s, byte(value))
+                                       } else if value <= 0x7FF {
+                                               s = append(s, byte(0xC0+(value>>6)))
+                                               s = append(s, byte(0x80+(value&0x3F)))
+                                       } else if value <= 0xFFFF {
+                                               s = append(s, byte(0xE0+(value>>12)))
+                                               s = append(s, byte(0x80+((value>>6)&0x3F)))
+                                               s = append(s, byte(0x80+(value&0x3F)))
+                                       } else {
+                                               s = append(s, byte(0xF0+(value>>18)))
+                                               s = append(s, byte(0x80+((value>>12)&0x3F)))
+                                               s = append(s, byte(0x80+((value>>6)&0x3F)))
+                                               s = append(s, byte(0x80+(value&0x3F)))
+                                       }
+
+                                       // Advance the pointer.
+                                       for k := 0; k < code_length; k++ {
+                                               skip(parser)
+                                       }
+                               }
+                       } else {
+                               // It is a non-escaped non-blank character.
+                               s = read(parser, s)
+                       }
+                       if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                               return false
+                       }
+               }
+
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+
+               // Check if we are at the end of the scalar.
+               if single {
+                       if parser.buffer[parser.buffer_pos] == '\'' {
+                               break
+                       }
+               } else {
+                       if parser.buffer[parser.buffer_pos] == '"' {
+                               break
+                       }
+               }
+
+               // Consume blank characters.
+               for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
+                       if is_blank(parser.buffer, parser.buffer_pos) {
+                               // Consume a space or a tab character.
+                               if !leading_blanks {
+                                       whitespaces = read(parser, whitespaces)
+                               } else {
+                                       skip(parser)
+                               }
+                       } else {
+                               if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                                       return false
+                               }
+
+                               // Check if it is a first line break.
+                               if !leading_blanks {
+                                       whitespaces = whitespaces[:0]
+                                       leading_break = read_line(parser, leading_break)
+                                       leading_blanks = true
+                               } else {
+                                       trailing_breaks = read_line(parser, trailing_breaks)
+                               }
+                       }
+                       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                               return false
+                       }
+               }
+
+               // Join the whitespaces or fold line breaks.
+               if leading_blanks {
+                       // Do we need to fold line breaks?
+                       if len(leading_break) > 0 && leading_break[0] == '\n' {
+                               if len(trailing_breaks) == 0 {
+                                       s = append(s, ' ')
+                               } else {
+                                       s = append(s, trailing_breaks...)
+                               }
+                       } else {
+                               s = append(s, leading_break...)
+                               s = append(s, trailing_breaks...)
+                       }
+                       trailing_breaks = trailing_breaks[:0]
+                       leading_break = leading_break[:0]
+               } else {
+                       s = append(s, whitespaces...)
+                       whitespaces = whitespaces[:0]
+               }
+       }
+
+       // Eat the right quote.
+       skip(parser)
+       end_mark := parser.mark
+
+       // Create a token.
+       *token = yaml_token_t{
+               typ:        yaml_SCALAR_TOKEN,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+               value:      s,
+               style:      yaml_SINGLE_QUOTED_SCALAR_STYLE,
+       }
+       if !single {
+               token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+       }
+       return true
+}
+
+// Scan a plain scalar.
+func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool {
+
+       var s, leading_break, trailing_breaks, whitespaces []byte
+       var leading_blanks bool
+       var indent = parser.indent + 1
+
+       start_mark := parser.mark
+       end_mark := parser.mark
+
+       // Consume the content of the plain scalar.
+       for {
+               // Check for a document indicator.
+               if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
+                       return false
+               }
+               if parser.mark.column == 0 &&
+                       ((parser.buffer[parser.buffer_pos+0] == '-' &&
+                               parser.buffer[parser.buffer_pos+1] == '-' &&
+                               parser.buffer[parser.buffer_pos+2] == '-') ||
+                               (parser.buffer[parser.buffer_pos+0] == '.' &&
+                                       parser.buffer[parser.buffer_pos+1] == '.' &&
+                                       parser.buffer[parser.buffer_pos+2] == '.')) &&
+                       is_blankz(parser.buffer, parser.buffer_pos+3) {
+                       break
+               }
+
+               // Check for a comment.
+               if parser.buffer[parser.buffer_pos] == '#' {
+                       break
+               }
+
+               // Consume non-blank characters.
+               for !is_blankz(parser.buffer, parser.buffer_pos) {
+
+                       // Check for indicators that may end a plain scalar.
+                       if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||
+                               (parser.flow_level > 0 &&
+                                       (parser.buffer[parser.buffer_pos] == ',' ||
+                                               parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' ||
+                                               parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
+                                               parser.buffer[parser.buffer_pos] == '}')) {
+                               break
+                       }
+
+                       // Check if we need to join whitespaces and breaks.
+                       if leading_blanks || len(whitespaces) > 0 {
+                               if leading_blanks {
+                                       // Do we need to fold line breaks?
+                                       if leading_break[0] == '\n' {
+                                               if len(trailing_breaks) == 0 {
+                                                       s = append(s, ' ')
+                                               } else {
+                                                       s = append(s, trailing_breaks...)
+                                               }
+                                       } else {
+                                               s = append(s, leading_break...)
+                                               s = append(s, trailing_breaks...)
+                                       }
+                                       trailing_breaks = trailing_breaks[:0]
+                                       leading_break = leading_break[:0]
+                                       leading_blanks = false
+                               } else {
+                                       s = append(s, whitespaces...)
+                                       whitespaces = whitespaces[:0]
+                               }
+                       }
+
+                       // Copy the character.
+                       s = read(parser, s)
+
+                       end_mark = parser.mark
+                       if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                               return false
+                       }
+               }
+
+               // Is it the end?
+               if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) {
+                       break
+               }
+
+               // Consume blank characters.
+               if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                       return false
+               }
+
+               for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
+                       if is_blank(parser.buffer, parser.buffer_pos) {
+
+                               // Check for tab characters that abuse indentation.
+                               if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {
+                                       yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
+                                               start_mark, "found a tab character that violates indentation")
+                                       return false
+                               }
+
+                               // Consume a space or a tab character.
+                               if !leading_blanks {
+                                       whitespaces = read(parser, whitespaces)
+                               } else {
+                                       skip(parser)
+                               }
+                       } else {
+                               if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                                       return false
+                               }
+
+                               // Check if it is a first line break.
+                               if !leading_blanks {
+                                       whitespaces = whitespaces[:0]
+                                       leading_break = read_line(parser, leading_break)
+                                       leading_blanks = true
+                               } else {
+                                       trailing_breaks = read_line(parser, trailing_breaks)
+                               }
+                       }
+                       if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+                               return false
+                       }
+               }
+
+               // Check indentation level.
+               if parser.flow_level == 0 && parser.mark.column < indent {
+                       break
+               }
+       }
+
+       // Create a token.
+       *token = yaml_token_t{
+               typ:        yaml_SCALAR_TOKEN,
+               start_mark: start_mark,
+               end_mark:   end_mark,
+               value:      s,
+               style:      yaml_PLAIN_SCALAR_STYLE,
+       }
+
+       // Note that we change the 'simple_key_allowed' flag.
+       if leading_blanks {
+               parser.simple_key_allowed = true
+       }
+       return true
+}
+
+func yaml_parser_scan_line_comment(parser *yaml_parser_t, after yaml_mark_t) bool {
+       if parser.mark.column == 0 {
+               return true
+       }
+
+       parser.comments = append(parser.comments, yaml_comment_t{after: after})
+       comment := &parser.comments[len(parser.comments)-1].line
+
+       for peek := 0; peek < 512; peek++ {
+               if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
+                       break
+               }
+               if is_blank(parser.buffer, parser.buffer_pos+peek) {
+                       continue
+               }
+               if parser.buffer[parser.buffer_pos+peek] == '#' {
+                       if len(*comment) > 0 {
+                               *comment = append(*comment, '\n')
+                       }
+                       for !is_breakz(parser.buffer, parser.buffer_pos+peek) {
+                               *comment = append(*comment, parser.buffer[parser.buffer_pos+peek])
+                               peek++
+                               if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
+                                       return false
+                               }
+                       }
+
+                       // Skip until after the consumed comment line.
+                       until := parser.buffer_pos + peek
+                       for parser.buffer_pos < until {
+                               if is_break(parser.buffer, parser.buffer_pos) {
+                                       //break // Leave the break in the buffer so calling this function twice is safe.
+                                       if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                                               return false
+                                       }
+                                       skip_line(parser)
+                               } else {
+                                       skip(parser)
+                               }
+                       }
+               }
+               break
+       }
+       return true
+}
+
+func yaml_parser_scan_head_comment(parser *yaml_parser_t, after yaml_mark_t) bool {
+       parser.comments = append(parser.comments, yaml_comment_t{after: after})
+       comment := &parser.comments[len(parser.comments)-1].head
+       breaks := false
+       for peek := 0; peek < 512; peek++ {
+               if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
+                       break
+               }
+               if parser.buffer[parser.buffer_pos+peek] == 0 {
+                       break
+               }
+               if is_blank(parser.buffer, parser.buffer_pos+peek) {
+                       continue
+               }
+               if is_break(parser.buffer, parser.buffer_pos+peek) {
+                       if !breaks {
+                               *comment = append(*comment, '\n')
+                       }
+                       breaks = true
+               } else if parser.buffer[parser.buffer_pos+peek] == '#' {
+                       if len(*comment) > 0 {
+                               *comment = append(*comment, '\n')
+                       }
+                       breaks = false
+                       for !is_breakz(parser.buffer, parser.buffer_pos+peek) {
+                               *comment = append(*comment, parser.buffer[parser.buffer_pos+peek])
+                               peek++
+                               if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
+                                       return false
+                               }
+                       }
+
+                       // Skip until after the consumed comment line.
+                       until := parser.buffer_pos + peek
+                       for parser.buffer_pos < until {
+                               if is_break(parser.buffer, parser.buffer_pos) {
+                                       if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                                               return false
+                                       }
+                                       skip_line(parser)
+                               } else {
+                                       skip(parser)
+                               }
+                       }
+                       peek = 0
+               } else {
+                       break
+               }
+       }
+       return true
+}
+
+func yaml_parser_scan_foot_comment(parser *yaml_parser_t, after yaml_mark_t) bool {
+       parser.comments = append(parser.comments, yaml_comment_t{after: after})
+       comment := &parser.comments[len(parser.comments)-1].foot
+       original := *comment
+       breaks := false
+       peek := 0
+       for ; peek < 32768; peek++ {
+               if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
+                       break
+               }
+               c := parser.buffer[parser.buffer_pos+peek]
+               if c == 0 {
+                       break
+               }
+               if is_blank(parser.buffer, parser.buffer_pos+peek) {
+                       continue
+               }
+               if is_break(parser.buffer, parser.buffer_pos+peek) {
+                       if breaks {
+                               break
+                       }
+                       breaks = true
+               } else if c == '#' {
+                       if len(*comment) > 0 {
+                               *comment = append(*comment, '\n')
+                       }
+                       for !is_breakz(parser.buffer, parser.buffer_pos+peek) {
+                               *comment = append(*comment, parser.buffer[parser.buffer_pos+peek])
+                               peek++
+                               if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
+                                       return false
+                               }
+                       }
+                       breaks = true
+               } else if c == ']' || c == '}' {
+                       break
+               } else {
+                       // Abort and allow that next line to have the comment as its header.
+                       *comment = original
+                       return true
+               }
+       }
+
+       // Skip until after the consumed comment lines.
+       until := parser.buffer_pos + peek
+       for parser.buffer_pos < until {
+               if is_break(parser.buffer, parser.buffer_pos) {
+                       if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+                               return false
+                       }
+                       skip_line(parser)
+               } else {
+                       skip(parser)
+               }
+       }
+       return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/sorter.go b/vendor/gopkg.in/yaml.v3/sorter.go
new file mode 100644 (file)
index 0000000..cfeab75
--- /dev/null
@@ -0,0 +1,128 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package yaml
+
+import (
+       "reflect"
+       "unicode"
+)
+
+type keyList []reflect.Value
+
+func (l keyList) Len() int      { return len(l) }
+func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+func (l keyList) Less(i, j int) bool {
+       a := l[i]
+       b := l[j]
+       ak := a.Kind()
+       bk := b.Kind()
+       for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() {
+               a = a.Elem()
+               ak = a.Kind()
+       }
+       for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() {
+               b = b.Elem()
+               bk = b.Kind()
+       }
+       af, aok := keyFloat(a)
+       bf, bok := keyFloat(b)
+       if aok && bok {
+               if af != bf {
+                       return af < bf
+               }
+               if ak != bk {
+                       return ak < bk
+               }
+               return numLess(a, b)
+       }
+       if ak != reflect.String || bk != reflect.String {
+               return ak < bk
+       }
+       ar, br := []rune(a.String()), []rune(b.String())
+       for i := 0; i < len(ar) && i < len(br); i++ {
+               if ar[i] == br[i] {
+                       continue
+               }
+               al := unicode.IsLetter(ar[i])
+               bl := unicode.IsLetter(br[i])
+               if al && bl {
+                       return ar[i] < br[i]
+               }
+               if al || bl {
+                       return bl
+               }
+               var ai, bi int
+               var an, bn int64
+               if ar[i] == '0' || br[i] == '0' {
+                       for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- {
+                               if ar[j] != '0' {
+                                       an = 1
+                                       bn = 1
+                                       break
+                               }
+                       }
+               }
+               for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
+                       an = an*10 + int64(ar[ai]-'0')
+               }
+               for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ {
+                       bn = bn*10 + int64(br[bi]-'0')
+               }
+               if an != bn {
+                       return an < bn
+               }
+               if ai != bi {
+                       return ai < bi
+               }
+               return ar[i] < br[i]
+       }
+       return len(ar) < len(br)
+}
+
+// keyFloat returns a float value for v if it is a number/bool
+// and whether it is a number/bool or not.
+func keyFloat(v reflect.Value) (f float64, ok bool) {
+       switch v.Kind() {
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               return float64(v.Int()), true
+       case reflect.Float32, reflect.Float64:
+               return v.Float(), true
+       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+               return float64(v.Uint()), true
+       case reflect.Bool:
+               if v.Bool() {
+                       return 1, true
+               }
+               return 0, true
+       }
+       return 0, false
+}
+
+// numLess returns whether a < b.
+// a and b must necessarily have the same kind.
+func numLess(a, b reflect.Value) bool {
+       switch a.Kind() {
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               return a.Int() < b.Int()
+       case reflect.Float32, reflect.Float64:
+               return a.Float() < b.Float()
+       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+               return a.Uint() < b.Uint()
+       case reflect.Bool:
+               return !a.Bool() && b.Bool()
+       }
+       panic("not a number")
+}
diff --git a/vendor/gopkg.in/yaml.v3/writerc.go b/vendor/gopkg.in/yaml.v3/writerc.go
new file mode 100644 (file)
index 0000000..b8a116b
--- /dev/null
@@ -0,0 +1,48 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+// Set the writer error and return false.
+func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
+       emitter.error = yaml_WRITER_ERROR
+       emitter.problem = problem
+       return false
+}
+
+// Flush the output buffer.
+func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
+       if emitter.write_handler == nil {
+               panic("write handler not set")
+       }
+
+       // Check if the buffer is empty.
+       if emitter.buffer_pos == 0 {
+               return true
+       }
+
+       if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
+               return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
+       }
+       emitter.buffer_pos = 0
+       return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/yaml.go b/vendor/gopkg.in/yaml.v3/yaml.go
new file mode 100644 (file)
index 0000000..b5d35a5
--- /dev/null
@@ -0,0 +1,662 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package yaml implements YAML support for the Go language.
+//
+// Source code and other details for the project are available at GitHub:
+//
+//   https://github.com/go-yaml/yaml
+//
+package yaml
+
+import (
+       "errors"
+       "fmt"
+       "io"
+       "reflect"
+       "strings"
+       "sync"
+       "unicode/utf8"
+)
+
+// The Unmarshaler interface may be implemented by types to customize their
+// behavior when being unmarshaled from a YAML document.
+type Unmarshaler interface {
+       UnmarshalYAML(value *Node) error
+}
+
+type obsoleteUnmarshaler interface {
+       UnmarshalYAML(unmarshal func(interface{}) error) error
+}
+
+// The Marshaler interface may be implemented by types to customize their
+// behavior when being marshaled into a YAML document. The returned value
+// is marshaled in place of the original value implementing Marshaler.
+//
+// If an error is returned by MarshalYAML, the marshaling procedure stops
+// and returns with the provided error.
+type Marshaler interface {
+       MarshalYAML() (interface{}, error)
+}
+
+// Unmarshal decodes the first document found within the in byte slice
+// and assigns decoded values into the out value.
+//
+// Maps and pointers (to a struct, string, int, etc) are accepted as out
+// values. If an internal pointer within a struct is not initialized,
+// the yaml package will initialize it if necessary for unmarshalling
+// the provided data. The out parameter must not be nil.
+//
+// The type of the decoded values should be compatible with the respective
+// values in out. If one or more values cannot be decoded due to a type
+// mismatches, decoding continues partially until the end of the YAML
+// content, and a *yaml.TypeError is returned with details for all
+// missed values.
+//
+// Struct fields are only unmarshalled if they are exported (have an
+// upper case first letter), and are unmarshalled using the field name
+// lowercased as the default key. Custom keys may be defined via the
+// "yaml" name in the field tag: the content preceding the first comma
+// is used as the key, and the following comma-separated options are
+// used to tweak the marshalling process (see Marshal).
+// Conflicting names result in a runtime error.
+//
+// For example:
+//
+//     type T struct {
+//         F int `yaml:"a,omitempty"`
+//         B int
+//     }
+//     var t T
+//     yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
+//
+// See the documentation of Marshal for the format of tags and a list of
+// supported tag options.
+//
+func Unmarshal(in []byte, out interface{}) (err error) {
+       return unmarshal(in, out, false)
+}
+
+// A Decorder reads and decodes YAML values from an input stream.
+type Decoder struct {
+       parser      *parser
+       knownFields bool
+}
+
+// NewDecoder returns a new decoder that reads from r.
+//
+// The decoder introduces its own buffering and may read
+// data from r beyond the YAML values requested.
+func NewDecoder(r io.Reader) *Decoder {
+       return &Decoder{
+               parser: newParserFromReader(r),
+       }
+}
+
+// KnownFields ensures that the keys in decoded mappings to
+// exist as fields in the struct being decoded into.
+func (dec *Decoder) KnownFields(enable bool) {
+       dec.knownFields = enable
+}
+
+// Decode reads the next YAML-encoded value from its input
+// and stores it in the value pointed to by v.
+//
+// See the documentation for Unmarshal for details about the
+// conversion of YAML into a Go value.
+func (dec *Decoder) Decode(v interface{}) (err error) {
+       d := newDecoder()
+       d.knownFields = dec.knownFields
+       defer handleErr(&err)
+       node := dec.parser.parse()
+       if node == nil {
+               return io.EOF
+       }
+       out := reflect.ValueOf(v)
+       if out.Kind() == reflect.Ptr && !out.IsNil() {
+               out = out.Elem()
+       }
+       d.unmarshal(node, out)
+       if len(d.terrors) > 0 {
+               return &TypeError{d.terrors}
+       }
+       return nil
+}
+
+// Decode decodes the node and stores its data into the value pointed to by v.
+//
+// See the documentation for Unmarshal for details about the
+// conversion of YAML into a Go value.
+func (n *Node) Decode(v interface{}) (err error) {
+       d := newDecoder()
+       defer handleErr(&err)
+       out := reflect.ValueOf(v)
+       if out.Kind() == reflect.Ptr && !out.IsNil() {
+               out = out.Elem()
+       }
+       d.unmarshal(n, out)
+       if len(d.terrors) > 0 {
+               return &TypeError{d.terrors}
+       }
+       return nil
+}
+
+func unmarshal(in []byte, out interface{}, strict bool) (err error) {
+       defer handleErr(&err)
+       d := newDecoder()
+       p := newParser(in)
+       defer p.destroy()
+       node := p.parse()
+       if node != nil {
+               v := reflect.ValueOf(out)
+               if v.Kind() == reflect.Ptr && !v.IsNil() {
+                       v = v.Elem()
+               }
+               d.unmarshal(node, v)
+       }
+       if len(d.terrors) > 0 {
+               return &TypeError{d.terrors}
+       }
+       return nil
+}
+
+// Marshal serializes the value provided into a YAML document. The structure
+// of the generated document will reflect the structure of the value itself.
+// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
+//
+// Struct fields are only marshalled if they are exported (have an upper case
+// first letter), and are marshalled using the field name lowercased as the
+// default key. Custom keys may be defined via the "yaml" name in the field
+// tag: the content preceding the first comma is used as the key, and the
+// following comma-separated options are used to tweak the marshalling process.
+// Conflicting names result in a runtime error.
+//
+// The field tag format accepted is:
+//
+//     `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
+//
+// The following flags are currently supported:
+//
+//     omitempty    Only include the field if it's not set to the zero
+//                  value for the type or to empty slices or maps.
+//                  Zero valued structs will be omitted if all their public
+//                  fields are zero, unless they implement an IsZero
+//                  method (see the IsZeroer interface type), in which
+//                  case the field will be included if that method returns true.
+//
+//     flow         Marshal using a flow style (useful for structs,
+//                  sequences and maps).
+//
+//     inline       Inline the field, which must be a struct or a map,
+//                  causing all of its fields or keys to be processed as if
+//                  they were part of the outer struct. For maps, keys must
+//                  not conflict with the yaml keys of other struct fields.
+//
+// In addition, if the key is "-", the field is ignored.
+//
+// For example:
+//
+//     type T struct {
+//         F int `yaml:"a,omitempty"`
+//         B int
+//     }
+//     yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
+//     yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
+//
+func Marshal(in interface{}) (out []byte, err error) {
+       defer handleErr(&err)
+       e := newEncoder()
+       defer e.destroy()
+       e.marshalDoc("", reflect.ValueOf(in))
+       e.finish()
+       out = e.out
+       return
+}
+
+// An Encoder writes YAML values to an output stream.
+type Encoder struct {
+       encoder *encoder
+}
+
+// NewEncoder returns a new encoder that writes to w.
+// The Encoder should be closed after use to flush all data
+// to w.
+func NewEncoder(w io.Writer) *Encoder {
+       return &Encoder{
+               encoder: newEncoderWithWriter(w),
+       }
+}
+
+// Encode writes the YAML encoding of v to the stream.
+// If multiple items are encoded to the stream, the
+// second and subsequent document will be preceded
+// with a "---" document separator, but the first will not.
+//
+// See the documentation for Marshal for details about the conversion of Go
+// values to YAML.
+func (e *Encoder) Encode(v interface{}) (err error) {
+       defer handleErr(&err)
+       e.encoder.marshalDoc("", reflect.ValueOf(v))
+       return nil
+}
+
+// SetIndent changes the used indentation used when encoding.
+func (e *Encoder) SetIndent(spaces int) {
+       if spaces < 0 {
+               panic("yaml: cannot indent to a negative number of spaces")
+       }
+       e.encoder.indent = spaces
+}
+
+// Close closes the encoder by writing any remaining data.
+// It does not write a stream terminating string "...".
+func (e *Encoder) Close() (err error) {
+       defer handleErr(&err)
+       e.encoder.finish()
+       return nil
+}
+
+func handleErr(err *error) {
+       if v := recover(); v != nil {
+               if e, ok := v.(yamlError); ok {
+                       *err = e.err
+               } else {
+                       panic(v)
+               }
+       }
+}
+
+type yamlError struct {
+       err error
+}
+
+func fail(err error) {
+       panic(yamlError{err})
+}
+
+func failf(format string, args ...interface{}) {
+       panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
+}
+
+// A TypeError is returned by Unmarshal when one or more fields in
+// the YAML document cannot be properly decoded into the requested
+// types. When this error is returned, the value is still
+// unmarshaled partially.
+type TypeError struct {
+       Errors []string
+}
+
+func (e *TypeError) Error() string {
+       return fmt.Sprintf("yaml: unmarshal errors:\n  %s", strings.Join(e.Errors, "\n  "))
+}
+
+type Kind uint32
+
+const (
+       DocumentNode Kind = 1 << iota
+       SequenceNode
+       MappingNode
+       ScalarNode
+       AliasNode
+)
+
+type Style uint32
+
+const (
+       TaggedStyle Style = 1 << iota
+       DoubleQuotedStyle
+       SingleQuotedStyle
+       LiteralStyle
+       FoldedStyle
+       FlowStyle
+)
+
+// Node represents an element in the YAML document hierarchy. While documents
+// are typically encoded and decoded into higher level types, such as structs
+// and maps, Node is an intermediate representation that allows detailed
+// control over the content being decoded or encoded.
+//
+// Values that make use of the Node type interact with the yaml package in the
+// same way any other type would do, by encoding and decoding yaml data
+// directly or indirectly into them.
+//
+// For example:
+//
+//     var person struct {
+//             Name    string
+//             Address yaml.Node
+//     }
+//     err := yaml.Unmarshal(data, &person)
+// 
+// Or by itself:
+//
+//     var person Node
+//     err := yaml.Unmarshal(data, &person)
+//
+type Node struct {
+       // Kind defines whether the node is a document, a mapping, a sequence,
+       // a scalar value, or an alias to another node. The specific data type of
+       // scalar nodes may be obtained via the ShortTag and LongTag methods.
+       Kind  Kind
+
+       // Style allows customizing the apperance of the node in the tree.
+       Style Style
+
+       // Tag holds the YAML tag defining the data type for the value.
+       // When decoding, this field will always be set to the resolved tag,
+       // even when it wasn't explicitly provided in the YAML content.
+       // When encoding, if this field is unset the value type will be
+       // implied from the node properties, and if it is set, it will only
+       // be serialized into the representation if TaggedStyle is used or
+       // the implicit tag diverges from the provided one.
+       Tag string
+
+       // Value holds the unescaped and unquoted represenation of the value.
+       Value string
+
+       // Anchor holds the anchor name for this node, which allows aliases to point to it.
+       Anchor string
+
+       // Alias holds the node that this alias points to. Only valid when Kind is AliasNode.
+       Alias *Node
+
+       // Content holds contained nodes for documents, mappings, and sequences.
+       Content []*Node
+
+       // HeadComment holds any comments in the lines preceding the node and
+       // not separated by an empty line.
+       HeadComment string
+
+       // LineComment holds any comments at the end of the line where the node is in.
+       LineComment string
+
+       // FootComment holds any comments following the node and before empty lines.
+       FootComment string
+
+       // Line and Column hold the node position in the decoded YAML text.
+       // These fields are not respected when encoding the node.
+       Line   int
+       Column int
+}
+
+// LongTag returns the long form of the tag that indicates the data type for
+// the node. If the Tag field isn't explicitly defined, one will be computed
+// based on the node properties.
+func (n *Node) LongTag() string {
+       return longTag(n.ShortTag())
+}
+
+// ShortTag returns the short form of the YAML tag that indicates data type for
+// the node. If the Tag field isn't explicitly defined, one will be computed
+// based on the node properties.
+func (n *Node) ShortTag() string {
+       if n.indicatedString() {
+               return strTag
+       }
+       if n.Tag == "" || n.Tag == "!" {
+               switch n.Kind {
+               case MappingNode:
+                       return mapTag
+               case SequenceNode:
+                       return seqTag
+               case AliasNode:
+                       if n.Alias != nil {
+                               return n.Alias.ShortTag()
+                       }
+               case ScalarNode:
+                       tag, _ := resolve("", n.Value)
+                       return tag
+               }
+               return ""
+       }
+       return shortTag(n.Tag)
+}
+
+func (n *Node) indicatedString() bool {
+       return n.Kind == ScalarNode &&
+               (shortTag(n.Tag) == strTag ||
+                       (n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)
+}
+
+// SetString is a convenience function that sets the node to a string value
+// and defines its style in a pleasant way depending on its content.
+func (n *Node) SetString(s string) {
+       n.Kind = ScalarNode
+       if utf8.ValidString(s) {
+               n.Value = s
+               n.Tag = strTag
+       } else {
+               n.Value = encodeBase64(s)
+               n.Tag = binaryTag
+       }
+       if strings.Contains(n.Value, "\n") {
+               n.Style = LiteralStyle
+       }
+}
+
+// --------------------------------------------------------------------------
+// Maintain a mapping of keys to structure field indexes
+
+// The code in this section was copied from mgo/bson.
+
+// structInfo holds details for the serialization of fields of
+// a given struct.
+type structInfo struct {
+       FieldsMap  map[string]fieldInfo
+       FieldsList []fieldInfo
+
+       // InlineMap is the number of the field in the struct that
+       // contains an ,inline map, or -1 if there's none.
+       InlineMap int
+
+       // InlineUnmarshalers holds indexes to inlined fields that
+       // contain unmarshaler values.
+       InlineUnmarshalers [][]int
+}
+
+type fieldInfo struct {
+       Key       string
+       Num       int
+       OmitEmpty bool
+       Flow      bool
+       // Id holds the unique field identifier, so we can cheaply
+       // check for field duplicates without maintaining an extra map.
+       Id int
+
+       // Inline holds the field index if the field is part of an inlined struct.
+       Inline []int
+}
+
+var structMap = make(map[reflect.Type]*structInfo)
+var fieldMapMutex sync.RWMutex
+var unmarshalerType reflect.Type
+
+func init() {
+       var v Unmarshaler
+       unmarshalerType = reflect.ValueOf(&v).Elem().Type()
+}
+
+func getStructInfo(st reflect.Type) (*structInfo, error) {
+       fieldMapMutex.RLock()
+       sinfo, found := structMap[st]
+       fieldMapMutex.RUnlock()
+       if found {
+               return sinfo, nil
+       }
+
+       n := st.NumField()
+       fieldsMap := make(map[string]fieldInfo)
+       fieldsList := make([]fieldInfo, 0, n)
+       inlineMap := -1
+       inlineUnmarshalers := [][]int(nil)
+       for i := 0; i != n; i++ {
+               field := st.Field(i)
+               if field.PkgPath != "" && !field.Anonymous {
+                       continue // Private field
+               }
+
+               info := fieldInfo{Num: i}
+
+               tag := field.Tag.Get("yaml")
+               if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
+                       tag = string(field.Tag)
+               }
+               if tag == "-" {
+                       continue
+               }
+
+               inline := false
+               fields := strings.Split(tag, ",")
+               if len(fields) > 1 {
+                       for _, flag := range fields[1:] {
+                               switch flag {
+                               case "omitempty":
+                                       info.OmitEmpty = true
+                               case "flow":
+                                       info.Flow = true
+                               case "inline":
+                                       inline = true
+                               default:
+                                       return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))
+                               }
+                       }
+                       tag = fields[0]
+               }
+
+               if inline {
+                       switch field.Type.Kind() {
+                       case reflect.Map:
+                               if inlineMap >= 0 {
+                                       return nil, errors.New("multiple ,inline maps in struct " + st.String())
+                               }
+                               if field.Type.Key() != reflect.TypeOf("") {
+                                       return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())
+                               }
+                               inlineMap = info.Num
+                       case reflect.Struct, reflect.Ptr:
+                               ftype := field.Type
+                               for ftype.Kind() == reflect.Ptr {
+                                       ftype = ftype.Elem()
+                               }
+                               if ftype.Kind() != reflect.Struct {
+                                       return nil, errors.New("option ,inline may only be used on a struct or map field")
+                               }
+                               if reflect.PtrTo(ftype).Implements(unmarshalerType) {
+                                       inlineUnmarshalers = append(inlineUnmarshalers, []int{i})
+                               } else {
+                                       sinfo, err := getStructInfo(ftype)
+                                       if err != nil {
+                                               return nil, err
+                                       }
+                                       for _, index := range sinfo.InlineUnmarshalers {
+                                               inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))
+                                       }
+                                       for _, finfo := range sinfo.FieldsList {
+                                               if _, found := fieldsMap[finfo.Key]; found {
+                                                       msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()
+                                                       return nil, errors.New(msg)
+                                               }
+                                               if finfo.Inline == nil {
+                                                       finfo.Inline = []int{i, finfo.Num}
+                                               } else {
+                                                       finfo.Inline = append([]int{i}, finfo.Inline...)
+                                               }
+                                               finfo.Id = len(fieldsList)
+                                               fieldsMap[finfo.Key] = finfo
+                                               fieldsList = append(fieldsList, finfo)
+                                       }
+                               }
+                       default:
+                               return nil, errors.New("option ,inline may only be used on a struct or map field")
+                       }
+                       continue
+               }
+
+               if tag != "" {
+                       info.Key = tag
+               } else {
+                       info.Key = strings.ToLower(field.Name)
+               }
+
+               if _, found = fieldsMap[info.Key]; found {
+                       msg := "duplicated key '" + info.Key + "' in struct " + st.String()
+                       return nil, errors.New(msg)
+               }
+
+               info.Id = len(fieldsList)
+               fieldsList = append(fieldsList, info)
+               fieldsMap[info.Key] = info
+       }
+
+       sinfo = &structInfo{
+               FieldsMap:          fieldsMap,
+               FieldsList:         fieldsList,
+               InlineMap:          inlineMap,
+               InlineUnmarshalers: inlineUnmarshalers,
+       }
+
+       fieldMapMutex.Lock()
+       structMap[st] = sinfo
+       fieldMapMutex.Unlock()
+       return sinfo, nil
+}
+
+// IsZeroer is used to check whether an object is zero to
+// determine whether it should be omitted when marshaling
+// with the omitempty flag. One notable implementation
+// is time.Time.
+type IsZeroer interface {
+       IsZero() bool
+}
+
+func isZero(v reflect.Value) bool {
+       kind := v.Kind()
+       if z, ok := v.Interface().(IsZeroer); ok {
+               if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
+                       return true
+               }
+               return z.IsZero()
+       }
+       switch kind {
+       case reflect.String:
+               return len(v.String()) == 0
+       case reflect.Interface, reflect.Ptr:
+               return v.IsNil()
+       case reflect.Slice:
+               return v.Len() == 0
+       case reflect.Map:
+               return v.Len() == 0
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               return v.Int() == 0
+       case reflect.Float32, reflect.Float64:
+               return v.Float() == 0
+       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+               return v.Uint() == 0
+       case reflect.Bool:
+               return !v.Bool()
+       case reflect.Struct:
+               vt := v.Type()
+               for i := v.NumField() - 1; i >= 0; i-- {
+                       if vt.Field(i).PkgPath != "" {
+                               continue // Private field
+                       }
+                       if !isZero(v.Field(i)) {
+                               return false
+                       }
+               }
+               return true
+       }
+       return false
+}
diff --git a/vendor/gopkg.in/yaml.v3/yamlh.go b/vendor/gopkg.in/yaml.v3/yamlh.go
new file mode 100644 (file)
index 0000000..edba38f
--- /dev/null
@@ -0,0 +1,790 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+       "fmt"
+       "io"
+)
+
+// The version directive data.
+type yaml_version_directive_t struct {
+       major int8 // The major version number.
+       minor int8 // The minor version number.
+}
+
+// The tag directive data.
+type yaml_tag_directive_t struct {
+       handle []byte // The tag handle.
+       prefix []byte // The tag prefix.
+}
+
+type yaml_encoding_t int
+
+// The stream encoding.
+const (
+       // Let the parser choose the encoding.
+       yaml_ANY_ENCODING yaml_encoding_t = iota
+
+       yaml_UTF8_ENCODING    // The default UTF-8 encoding.
+       yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
+       yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
+)
+
+type yaml_break_t int
+
+// Line break types.
+const (
+       // Let the parser choose the break type.
+       yaml_ANY_BREAK yaml_break_t = iota
+
+       yaml_CR_BREAK   // Use CR for line breaks (Mac style).
+       yaml_LN_BREAK   // Use LN for line breaks (Unix style).
+       yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
+)
+
+type yaml_error_type_t int
+
+// Many bad things could happen with the parser and emitter.
+const (
+       // No error is produced.
+       yaml_NO_ERROR yaml_error_type_t = iota
+
+       yaml_MEMORY_ERROR   // Cannot allocate or reallocate a block of memory.
+       yaml_READER_ERROR   // Cannot read or decode the input stream.
+       yaml_SCANNER_ERROR  // Cannot scan the input stream.
+       yaml_PARSER_ERROR   // Cannot parse the input stream.
+       yaml_COMPOSER_ERROR // Cannot compose a YAML document.
+       yaml_WRITER_ERROR   // Cannot write to the output stream.
+       yaml_EMITTER_ERROR  // Cannot emit a YAML stream.
+)
+
+// The pointer position.
+type yaml_mark_t struct {
+       index  int // The position index.
+       line   int // The position line.
+       column int // The position column.
+}
+
+// Node Styles
+
+type yaml_style_t int8
+
+type yaml_scalar_style_t yaml_style_t
+
+// Scalar styles.
+const (
+       // Let the emitter choose the style.
+       yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = 0
+
+       yaml_PLAIN_SCALAR_STYLE         yaml_scalar_style_t = 1 << iota // The plain scalar style.
+       yaml_SINGLE_QUOTED_SCALAR_STYLE                                 // The single-quoted scalar style.
+       yaml_DOUBLE_QUOTED_SCALAR_STYLE                                 // The double-quoted scalar style.
+       yaml_LITERAL_SCALAR_STYLE                                       // The literal scalar style.
+       yaml_FOLDED_SCALAR_STYLE                                        // The folded scalar style.
+)
+
+type yaml_sequence_style_t yaml_style_t
+
+// Sequence styles.
+const (
+       // Let the emitter choose the style.
+       yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
+
+       yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
+       yaml_FLOW_SEQUENCE_STYLE  // The flow sequence style.
+)
+
+type yaml_mapping_style_t yaml_style_t
+
+// Mapping styles.
+const (
+       // Let the emitter choose the style.
+       yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
+
+       yaml_BLOCK_MAPPING_STYLE // The block mapping style.
+       yaml_FLOW_MAPPING_STYLE  // The flow mapping style.
+)
+
+// Tokens
+
+type yaml_token_type_t int
+
+// Token types.
+const (
+       // An empty token.
+       yaml_NO_TOKEN yaml_token_type_t = iota
+
+       yaml_STREAM_START_TOKEN // A STREAM-START token.
+       yaml_STREAM_END_TOKEN   // A STREAM-END token.
+
+       yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
+       yaml_TAG_DIRECTIVE_TOKEN     // A TAG-DIRECTIVE token.
+       yaml_DOCUMENT_START_TOKEN    // A DOCUMENT-START token.
+       yaml_DOCUMENT_END_TOKEN      // A DOCUMENT-END token.
+
+       yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
+       yaml_BLOCK_MAPPING_START_TOKEN  // A BLOCK-SEQUENCE-END token.
+       yaml_BLOCK_END_TOKEN            // A BLOCK-END token.
+
+       yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
+       yaml_FLOW_SEQUENCE_END_TOKEN   // A FLOW-SEQUENCE-END token.
+       yaml_FLOW_MAPPING_START_TOKEN  // A FLOW-MAPPING-START token.
+       yaml_FLOW_MAPPING_END_TOKEN    // A FLOW-MAPPING-END token.
+
+       yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
+       yaml_FLOW_ENTRY_TOKEN  // A FLOW-ENTRY token.
+       yaml_KEY_TOKEN         // A KEY token.
+       yaml_VALUE_TOKEN       // A VALUE token.
+
+       yaml_ALIAS_TOKEN  // An ALIAS token.
+       yaml_ANCHOR_TOKEN // An ANCHOR token.
+       yaml_TAG_TOKEN    // A TAG token.
+       yaml_SCALAR_TOKEN // A SCALAR token.
+)
+
+func (tt yaml_token_type_t) String() string {
+       switch tt {
+       case yaml_NO_TOKEN:
+               return "yaml_NO_TOKEN"
+       case yaml_STREAM_START_TOKEN:
+               return "yaml_STREAM_START_TOKEN"
+       case yaml_STREAM_END_TOKEN:
+               return "yaml_STREAM_END_TOKEN"
+       case yaml_VERSION_DIRECTIVE_TOKEN:
+               return "yaml_VERSION_DIRECTIVE_TOKEN"
+       case yaml_TAG_DIRECTIVE_TOKEN:
+               return "yaml_TAG_DIRECTIVE_TOKEN"
+       case yaml_DOCUMENT_START_TOKEN:
+               return "yaml_DOCUMENT_START_TOKEN"
+       case yaml_DOCUMENT_END_TOKEN:
+               return "yaml_DOCUMENT_END_TOKEN"
+       case yaml_BLOCK_SEQUENCE_START_TOKEN:
+               return "yaml_BLOCK_SEQUENCE_START_TOKEN"
+       case yaml_BLOCK_MAPPING_START_TOKEN:
+               return "yaml_BLOCK_MAPPING_START_TOKEN"
+       case yaml_BLOCK_END_TOKEN:
+               return "yaml_BLOCK_END_TOKEN"
+       case yaml_FLOW_SEQUENCE_START_TOKEN:
+               return "yaml_FLOW_SEQUENCE_START_TOKEN"
+       case yaml_FLOW_SEQUENCE_END_TOKEN:
+               return "yaml_FLOW_SEQUENCE_END_TOKEN"
+       case yaml_FLOW_MAPPING_START_TOKEN:
+               return "yaml_FLOW_MAPPING_START_TOKEN"
+       case yaml_FLOW_MAPPING_END_TOKEN:
+               return "yaml_FLOW_MAPPING_END_TOKEN"
+       case yaml_BLOCK_ENTRY_TOKEN:
+               return "yaml_BLOCK_ENTRY_TOKEN"
+       case yaml_FLOW_ENTRY_TOKEN:
+               return "yaml_FLOW_ENTRY_TOKEN"
+       case yaml_KEY_TOKEN:
+               return "yaml_KEY_TOKEN"
+       case yaml_VALUE_TOKEN:
+               return "yaml_VALUE_TOKEN"
+       case yaml_ALIAS_TOKEN:
+               return "yaml_ALIAS_TOKEN"
+       case yaml_ANCHOR_TOKEN:
+               return "yaml_ANCHOR_TOKEN"
+       case yaml_TAG_TOKEN:
+               return "yaml_TAG_TOKEN"
+       case yaml_SCALAR_TOKEN:
+               return "yaml_SCALAR_TOKEN"
+       }
+       return "<unknown token>"
+}
+
+// The token structure.
+type yaml_token_t struct {
+       // The token type.
+       typ yaml_token_type_t
+
+       // The start/end of the token.
+       start_mark, end_mark yaml_mark_t
+
+       // The stream encoding (for yaml_STREAM_START_TOKEN).
+       encoding yaml_encoding_t
+
+       // The alias/anchor/scalar value or tag/tag directive handle
+       // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN).
+       value []byte
+
+       // The tag suffix (for yaml_TAG_TOKEN).
+       suffix []byte
+
+       // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN).
+       prefix []byte
+
+       // The scalar style (for yaml_SCALAR_TOKEN).
+       style yaml_scalar_style_t
+
+       // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN).
+       major, minor int8
+}
+
+// Events
+
+type yaml_event_type_t int8
+
+// Event types.
+const (
+       // An empty event.
+       yaml_NO_EVENT yaml_event_type_t = iota
+
+       yaml_STREAM_START_EVENT   // A STREAM-START event.
+       yaml_STREAM_END_EVENT     // A STREAM-END event.
+       yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
+       yaml_DOCUMENT_END_EVENT   // A DOCUMENT-END event.
+       yaml_ALIAS_EVENT          // An ALIAS event.
+       yaml_SCALAR_EVENT         // A SCALAR event.
+       yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
+       yaml_SEQUENCE_END_EVENT   // A SEQUENCE-END event.
+       yaml_MAPPING_START_EVENT  // A MAPPING-START event.
+       yaml_MAPPING_END_EVENT    // A MAPPING-END event.
+)
+
+var eventStrings = []string{
+       yaml_NO_EVENT:             "none",
+       yaml_STREAM_START_EVENT:   "stream start",
+       yaml_STREAM_END_EVENT:     "stream end",
+       yaml_DOCUMENT_START_EVENT: "document start",
+       yaml_DOCUMENT_END_EVENT:   "document end",
+       yaml_ALIAS_EVENT:          "alias",
+       yaml_SCALAR_EVENT:         "scalar",
+       yaml_SEQUENCE_START_EVENT: "sequence start",
+       yaml_SEQUENCE_END_EVENT:   "sequence end",
+       yaml_MAPPING_START_EVENT:  "mapping start",
+       yaml_MAPPING_END_EVENT:    "mapping end",
+}
+
+func (e yaml_event_type_t) String() string {
+       if e < 0 || int(e) >= len(eventStrings) {
+               return fmt.Sprintf("unknown event %d", e)
+       }
+       return eventStrings[e]
+}
+
+// The event structure.
+type yaml_event_t struct {
+
+       // The event type.
+       typ yaml_event_type_t
+
+       // The start and end of the event.
+       start_mark, end_mark yaml_mark_t
+
+       // The document encoding (for yaml_STREAM_START_EVENT).
+       encoding yaml_encoding_t
+
+       // The version directive (for yaml_DOCUMENT_START_EVENT).
+       version_directive *yaml_version_directive_t
+
+       // The list of tag directives (for yaml_DOCUMENT_START_EVENT).
+       tag_directives []yaml_tag_directive_t
+
+       // The comments
+       head_comment []byte
+       line_comment []byte
+       foot_comment []byte
+
+       // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT).
+       anchor []byte
+
+       // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
+       tag []byte
+
+       // The scalar value (for yaml_SCALAR_EVENT).
+       value []byte
+
+       // Is the document start/end indicator implicit, or the tag optional?
+       // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT).
+       implicit bool
+
+       // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT).
+       quoted_implicit bool
+
+       // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
+       style yaml_style_t
+}
+
+func (e *yaml_event_t) scalar_style() yaml_scalar_style_t     { return yaml_scalar_style_t(e.style) }
+func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) }
+func (e *yaml_event_t) mapping_style() yaml_mapping_style_t   { return yaml_mapping_style_t(e.style) }
+
+// Nodes
+
+const (
+       yaml_NULL_TAG      = "tag:yaml.org,2002:null"      // The tag !!null with the only possible value: null.
+       yaml_BOOL_TAG      = "tag:yaml.org,2002:bool"      // The tag !!bool with the values: true and false.
+       yaml_STR_TAG       = "tag:yaml.org,2002:str"       // The tag !!str for string values.
+       yaml_INT_TAG       = "tag:yaml.org,2002:int"       // The tag !!int for integer values.
+       yaml_FLOAT_TAG     = "tag:yaml.org,2002:float"     // The tag !!float for float values.
+       yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
+
+       yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
+       yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
+
+       // Not in original libyaml.
+       yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
+       yaml_MERGE_TAG  = "tag:yaml.org,2002:merge"
+
+       yaml_DEFAULT_SCALAR_TAG   = yaml_STR_TAG // The default scalar tag is !!str.
+       yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
+       yaml_DEFAULT_MAPPING_TAG  = yaml_MAP_TAG // The default mapping tag is !!map.
+)
+
+type yaml_node_type_t int
+
+// Node types.
+const (
+       // An empty node.
+       yaml_NO_NODE yaml_node_type_t = iota
+
+       yaml_SCALAR_NODE   // A scalar node.
+       yaml_SEQUENCE_NODE // A sequence node.
+       yaml_MAPPING_NODE  // A mapping node.
+)
+
+// An element of a sequence node.
+type yaml_node_item_t int
+
+// An element of a mapping node.
+type yaml_node_pair_t struct {
+       key   int // The key of the element.
+       value int // The value of the element.
+}
+
+// The node structure.
+type yaml_node_t struct {
+       typ yaml_node_type_t // The node type.
+       tag []byte           // The node tag.
+
+       // The node data.
+
+       // The scalar parameters (for yaml_SCALAR_NODE).
+       scalar struct {
+               value  []byte              // The scalar value.
+               length int                 // The length of the scalar value.
+               style  yaml_scalar_style_t // The scalar style.
+       }
+
+       // The sequence parameters (for YAML_SEQUENCE_NODE).
+       sequence struct {
+               items_data []yaml_node_item_t    // The stack of sequence items.
+               style      yaml_sequence_style_t // The sequence style.
+       }
+
+       // The mapping parameters (for yaml_MAPPING_NODE).
+       mapping struct {
+               pairs_data  []yaml_node_pair_t   // The stack of mapping pairs (key, value).
+               pairs_start *yaml_node_pair_t    // The beginning of the stack.
+               pairs_end   *yaml_node_pair_t    // The end of the stack.
+               pairs_top   *yaml_node_pair_t    // The top of the stack.
+               style       yaml_mapping_style_t // The mapping style.
+       }
+
+       start_mark yaml_mark_t // The beginning of the node.
+       end_mark   yaml_mark_t // The end of the node.
+
+}
+
+// The document structure.
+type yaml_document_t struct {
+
+       // The document nodes.
+       nodes []yaml_node_t
+
+       // The version directive.
+       version_directive *yaml_version_directive_t
+
+       // The list of tag directives.
+       tag_directives_data  []yaml_tag_directive_t
+       tag_directives_start int // The beginning of the tag directives list.
+       tag_directives_end   int // The end of the tag directives list.
+
+       start_implicit int // Is the document start indicator implicit?
+       end_implicit   int // Is the document end indicator implicit?
+
+       // The start/end of the document.
+       start_mark, end_mark yaml_mark_t
+}
+
+// The prototype of a read handler.
+//
+// The read handler is called when the parser needs to read more bytes from the
+// source. The handler should write not more than size bytes to the buffer.
+// The number of written bytes should be set to the size_read variable.
+//
+// [in,out]   data        A pointer to an application data specified by
+//                        yaml_parser_set_input().
+// [out]      buffer      The buffer to write the data from the source.
+// [in]       size        The size of the buffer.
+// [out]      size_read   The actual number of bytes read from the source.
+//
+// On success, the handler should return 1.  If the handler failed,
+// the returned value should be 0. On EOF, the handler should set the
+// size_read to 0 and return 1.
+type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
+
+// This structure holds information about a potential simple key.
+type yaml_simple_key_t struct {
+       possible     bool        // Is a simple key possible?
+       required     bool        // Is a simple key required?
+       token_number int         // The number of the token.
+       mark         yaml_mark_t // The position mark.
+}
+
+// The states of the parser.
+type yaml_parser_state_t int
+
+const (
+       yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
+
+       yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE           // Expect the beginning of an implicit document.
+       yaml_PARSE_DOCUMENT_START_STATE                    // Expect DOCUMENT-START.
+       yaml_PARSE_DOCUMENT_CONTENT_STATE                  // Expect the content of a document.
+       yaml_PARSE_DOCUMENT_END_STATE                      // Expect DOCUMENT-END.
+       yaml_PARSE_BLOCK_NODE_STATE                        // Expect a block node.
+       yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
+       yaml_PARSE_FLOW_NODE_STATE                         // Expect a flow node.
+       yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE        // Expect the first entry of a block sequence.
+       yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE              // Expect an entry of a block sequence.
+       yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE         // Expect an entry of an indentless sequence.
+       yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE           // Expect the first key of a block mapping.
+       yaml_PARSE_BLOCK_MAPPING_KEY_STATE                 // Expect a block mapping key.
+       yaml_PARSE_BLOCK_MAPPING_VALUE_STATE               // Expect a block mapping value.
+       yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE         // Expect the first entry of a flow sequence.
+       yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE               // Expect an entry of a flow sequence.
+       yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE   // Expect a key of an ordered mapping.
+       yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
+       yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE   // Expect the and of an ordered mapping entry.
+       yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE            // Expect the first key of a flow mapping.
+       yaml_PARSE_FLOW_MAPPING_KEY_STATE                  // Expect a key of a flow mapping.
+       yaml_PARSE_FLOW_MAPPING_VALUE_STATE                // Expect a value of a flow mapping.
+       yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE          // Expect an empty value of a flow mapping.
+       yaml_PARSE_END_STATE                               // Expect nothing.
+)
+
+func (ps yaml_parser_state_t) String() string {
+       switch ps {
+       case yaml_PARSE_STREAM_START_STATE:
+               return "yaml_PARSE_STREAM_START_STATE"
+       case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
+               return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE"
+       case yaml_PARSE_DOCUMENT_START_STATE:
+               return "yaml_PARSE_DOCUMENT_START_STATE"
+       case yaml_PARSE_DOCUMENT_CONTENT_STATE:
+               return "yaml_PARSE_DOCUMENT_CONTENT_STATE"
+       case yaml_PARSE_DOCUMENT_END_STATE:
+               return "yaml_PARSE_DOCUMENT_END_STATE"
+       case yaml_PARSE_BLOCK_NODE_STATE:
+               return "yaml_PARSE_BLOCK_NODE_STATE"
+       case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
+               return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE"
+       case yaml_PARSE_FLOW_NODE_STATE:
+               return "yaml_PARSE_FLOW_NODE_STATE"
+       case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
+               return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE"
+       case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
+               return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE"
+       case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
+               return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE"
+       case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
+               return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE"
+       case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
+               return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE"
+       case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
+               return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE"
+       case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
+               return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE"
+       case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
+               return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE"
+       case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
+               return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE"
+       case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
+               return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE"
+       case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
+               return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE"
+       case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
+               return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE"
+       case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
+               return "yaml_PARSE_FLOW_MAPPING_KEY_STATE"
+       case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
+               return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE"
+       case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
+               return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE"
+       case yaml_PARSE_END_STATE:
+               return "yaml_PARSE_END_STATE"
+       }
+       return "<unknown parser state>"
+}
+
+// This structure holds aliases data.
+type yaml_alias_data_t struct {
+       anchor []byte      // The anchor.
+       index  int         // The node id.
+       mark   yaml_mark_t // The anchor mark.
+}
+
+// The parser structure.
+//
+// All members are internal. Manage the structure using the
+// yaml_parser_ family of functions.
+type yaml_parser_t struct {
+
+       // Error handling
+
+       error yaml_error_type_t // Error type.
+
+       problem string // Error description.
+
+       // The byte about which the problem occurred.
+       problem_offset int
+       problem_value  int
+       problem_mark   yaml_mark_t
+
+       // The error context.
+       context      string
+       context_mark yaml_mark_t
+
+       // Reader stuff
+
+       read_handler yaml_read_handler_t // Read handler.
+
+       input_reader io.Reader // File input data.
+       input        []byte    // String input data.
+       input_pos    int
+
+       eof bool // EOF flag
+
+       buffer     []byte // The working buffer.
+       buffer_pos int    // The current position of the buffer.
+
+       unread int // The number of unread characters in the buffer.
+
+       raw_buffer     []byte // The raw buffer.
+       raw_buffer_pos int    // The current position of the buffer.
+
+       encoding yaml_encoding_t // The input encoding.
+
+       offset int         // The offset of the current position (in bytes).
+       mark   yaml_mark_t // The mark of the current position.
+
+       // Comments
+
+       head_comment []byte // The current head comments
+       line_comment []byte // The current line comments
+       foot_comment []byte // The current foot comments
+
+       comments      []yaml_comment_t // The folded comments for all parsed tokens
+       comments_head int
+
+       // Scanner stuff
+
+       stream_start_produced bool // Have we started to scan the input stream?
+       stream_end_produced   bool // Have we reached the end of the input stream?
+
+       flow_level int // The number of unclosed '[' and '{' indicators.
+
+       tokens          []yaml_token_t // The tokens queue.
+       tokens_head     int            // The head of the tokens queue.
+       tokens_parsed   int            // The number of tokens fetched from the queue.
+       token_available bool           // Does the tokens queue contain a token ready for dequeueing.
+
+       indent  int   // The current indentation level.
+       indents []int // The indentation levels stack.
+
+       simple_key_allowed bool                // May a simple key occur at the current position?
+       simple_keys        []yaml_simple_key_t // The stack of simple keys.
+
+       // Parser stuff
+
+       state          yaml_parser_state_t    // The current parser state.
+       states         []yaml_parser_state_t  // The parser states stack.
+       marks          []yaml_mark_t          // The stack of marks.
+       tag_directives []yaml_tag_directive_t // The list of TAG directives.
+
+       // Dumper stuff
+
+       aliases []yaml_alias_data_t // The alias data.
+
+       document *yaml_document_t // The currently parsed document.
+}
+
+type yaml_comment_t struct {
+       after yaml_mark_t
+       head  []byte
+       line  []byte
+       foot  []byte
+}
+
+// Emitter Definitions
+
+// The prototype of a write handler.
+//
+// The write handler is called when the emitter needs to flush the accumulated
+// characters to the output.  The handler should write @a size bytes of the
+// @a buffer to the output.
+//
+// @param[in,out]   data        A pointer to an application data specified by
+//                              yaml_emitter_set_output().
+// @param[in]       buffer      The buffer with bytes to be written.
+// @param[in]       size        The size of the buffer.
+//
+// @returns On success, the handler should return @c 1.  If the handler failed,
+// the returned value should be @c 0.
+//
+type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
+
+type yaml_emitter_state_t int
+
+// The emitter states.
+const (
+       // Expect STREAM-START.
+       yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
+
+       yaml_EMIT_FIRST_DOCUMENT_START_STATE       // Expect the first DOCUMENT-START or STREAM-END.
+       yaml_EMIT_DOCUMENT_START_STATE             // Expect DOCUMENT-START or STREAM-END.
+       yaml_EMIT_DOCUMENT_CONTENT_STATE           // Expect the content of a document.
+       yaml_EMIT_DOCUMENT_END_STATE               // Expect DOCUMENT-END.
+       yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE   // Expect the first item of a flow sequence.
+       yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE   // Expect the next item of a flow sequence, with the comma already written out
+       yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE         // Expect an item of a flow sequence.
+       yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE     // Expect the first key of a flow mapping.
+       yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE     // Expect the next key of a flow mapping, with the comma already written out
+       yaml_EMIT_FLOW_MAPPING_KEY_STATE           // Expect a key of a flow mapping.
+       yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE  // Expect a value for a simple key of a flow mapping.
+       yaml_EMIT_FLOW_MAPPING_VALUE_STATE         // Expect a value of a flow mapping.
+       yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE  // Expect the first item of a block sequence.
+       yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE        // Expect an item of a block sequence.
+       yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE    // Expect the first key of a block mapping.
+       yaml_EMIT_BLOCK_MAPPING_KEY_STATE          // Expect the key of a block mapping.
+       yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
+       yaml_EMIT_BLOCK_MAPPING_VALUE_STATE        // Expect a value of a block mapping.
+       yaml_EMIT_END_STATE                        // Expect nothing.
+)
+
+// The emitter structure.
+//
+// All members are internal.  Manage the structure using the @c yaml_emitter_
+// family of functions.
+type yaml_emitter_t struct {
+
+       // Error handling
+
+       error   yaml_error_type_t // Error type.
+       problem string            // Error description.
+
+       // Writer stuff
+
+       write_handler yaml_write_handler_t // Write handler.
+
+       output_buffer *[]byte   // String output data.
+       output_writer io.Writer // File output data.
+
+       buffer     []byte // The working buffer.
+       buffer_pos int    // The current position of the buffer.
+
+       raw_buffer     []byte // The raw buffer.
+       raw_buffer_pos int    // The current position of the buffer.
+
+       encoding yaml_encoding_t // The stream encoding.
+
+       // Emitter stuff
+
+       canonical   bool         // If the output is in the canonical style?
+       best_indent int          // The number of indentation spaces.
+       best_width  int          // The preferred width of the output lines.
+       unicode     bool         // Allow unescaped non-ASCII characters?
+       line_break  yaml_break_t // The preferred line break.
+
+       state  yaml_emitter_state_t   // The current emitter state.
+       states []yaml_emitter_state_t // The stack of states.
+
+       events      []yaml_event_t // The event queue.
+       events_head int            // The head of the event queue.
+
+       indents []int // The stack of indentation levels.
+
+       tag_directives []yaml_tag_directive_t // The list of tag directives.
+
+       indent int // The current indentation level.
+
+       flow_level int // The current flow level.
+
+       root_context       bool // Is it the document root context?
+       sequence_context   bool // Is it a sequence context?
+       mapping_context    bool // Is it a mapping context?
+       simple_key_context bool // Is it a simple mapping key context?
+
+       line       int  // The current line.
+       column     int  // The current column.
+       whitespace bool // If the last character was a whitespace?
+       indention  bool // If the last character was an indentation character (' ', '-', '?', ':')?
+       open_ended bool // If an explicit document end is required?
+
+       space_above bool // If there's an empty line right above?
+
+       // Anchor analysis.
+       anchor_data struct {
+               anchor []byte // The anchor value.
+               alias  bool   // Is it an alias?
+       }
+
+       // Tag analysis.
+       tag_data struct {
+               handle []byte // The tag handle.
+               suffix []byte // The tag suffix.
+       }
+
+       // Scalar analysis.
+       scalar_data struct {
+               value                 []byte              // The scalar value.
+               multiline             bool                // Does the scalar contain line breaks?
+               flow_plain_allowed    bool                // Can the scalar be expessed in the flow plain style?
+               block_plain_allowed   bool                // Can the scalar be expressed in the block plain style?
+               single_quoted_allowed bool                // Can the scalar be expressed in the single quoted style?
+               block_allowed         bool                // Can the scalar be expressed in the literal or folded styles?
+               style                 yaml_scalar_style_t // The output style.
+       }
+
+       // Comments
+       head_comment []byte
+       line_comment []byte
+       foot_comment []byte
+
+       // Dumper stuff
+
+       opened bool // If the stream was already opened?
+       closed bool // If the stream was already closed?
+
+       // The information associated with the document nodes.
+       anchors *struct {
+               references int  // The number of references.
+               anchor     int  // The anchor id.
+               serialized bool // If the node has been emitted?
+       }
+
+       last_anchor_id int // The last assigned anchor id.
+
+       document *yaml_document_t // The currently emitted document.
+}
diff --git a/vendor/gopkg.in/yaml.v3/yamlprivateh.go b/vendor/gopkg.in/yaml.v3/yamlprivateh.go
new file mode 100644 (file)
index 0000000..02428c2
--- /dev/null
@@ -0,0 +1,195 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+const (
+       // The size of the input raw buffer.
+       input_raw_buffer_size = 512
+
+       // The size of the input buffer.
+       // It should be possible to decode the whole raw buffer.
+       input_buffer_size = input_raw_buffer_size * 3
+
+       // The size of the output buffer.
+       output_buffer_size = 128
+
+       // The size of the output raw buffer.
+       // It should be possible to encode the whole output buffer.
+       output_raw_buffer_size = (output_buffer_size*2 + 2)
+
+       // The size of other stacks and queues.
+       initial_stack_size  = 16
+       initial_queue_size  = 16
+       initial_string_size = 16
+)
+
+// Check if the character at the specified position is an alphabetical
+// character, a digit, '_', or '-'.
+func is_alpha(b []byte, i int) bool {
+       return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-'
+}
+
+// Check if the character at the specified position is a digit.
+func is_digit(b []byte, i int) bool {
+       return b[i] >= '0' && b[i] <= '9'
+}
+
+// Get the value of a digit.
+func as_digit(b []byte, i int) int {
+       return int(b[i]) - '0'
+}
+
+// Check if the character at the specified position is a hex-digit.
+func is_hex(b []byte, i int) bool {
+       return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f'
+}
+
+// Get the value of a hex-digit.
+func as_hex(b []byte, i int) int {
+       bi := b[i]
+       if bi >= 'A' && bi <= 'F' {
+               return int(bi) - 'A' + 10
+       }
+       if bi >= 'a' && bi <= 'f' {
+               return int(bi) - 'a' + 10
+       }
+       return int(bi) - '0'
+}
+
+// Check if the character is ASCII.
+func is_ascii(b []byte, i int) bool {
+       return b[i] <= 0x7F
+}
+
+// Check if the character at the start of the buffer can be printed unescaped.
+func is_printable(b []byte, i int) bool {
+       return ((b[i] == 0x0A) || // . == #x0A
+               (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
+               (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF
+               (b[i] > 0xC2 && b[i] < 0xED) ||
+               (b[i] == 0xED && b[i+1] < 0xA0) ||
+               (b[i] == 0xEE) ||
+               (b[i] == 0xEF && // #xE000 <= . <= #xFFFD
+                       !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF
+                       !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
+}
+
+// Check if the character at the specified position is NUL.
+func is_z(b []byte, i int) bool {
+       return b[i] == 0x00
+}
+
+// Check if the beginning of the buffer is a BOM.
+func is_bom(b []byte, i int) bool {
+       return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
+}
+
+// Check if the character at the specified position is space.
+func is_space(b []byte, i int) bool {
+       return b[i] == ' '
+}
+
+// Check if the character at the specified position is tab.
+func is_tab(b []byte, i int) bool {
+       return b[i] == '\t'
+}
+
+// Check if the character at the specified position is blank (space or tab).
+func is_blank(b []byte, i int) bool {
+       //return is_space(b, i) || is_tab(b, i)
+       return b[i] == ' ' || b[i] == '\t'
+}
+
+// Check if the character at the specified position is a line break.
+func is_break(b []byte, i int) bool {
+       return (b[i] == '\r' || // CR (#xD)
+               b[i] == '\n' || // LF (#xA)
+               b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+               b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+               b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029)
+}
+
+func is_crlf(b []byte, i int) bool {
+       return b[i] == '\r' && b[i+1] == '\n'
+}
+
+// Check if the character is a line break or NUL.
+func is_breakz(b []byte, i int) bool {
+       //return is_break(b, i) || is_z(b, i)
+       return (        // is_break:
+       b[i] == '\r' || // CR (#xD)
+               b[i] == '\n' || // LF (#xA)
+               b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+               b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+               b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
+               // is_z:
+               b[i] == 0)
+}
+
+// Check if the character is a line break, space, or NUL.
+func is_spacez(b []byte, i int) bool {
+       //return is_space(b, i) || is_breakz(b, i)
+       return ( // is_space:
+       b[i] == ' ' ||
+               // is_breakz:
+               b[i] == '\r' || // CR (#xD)
+               b[i] == '\n' || // LF (#xA)
+               b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+               b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+               b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
+               b[i] == 0)
+}
+
+// Check if the character is a line break, space, tab, or NUL.
+func is_blankz(b []byte, i int) bool {
+       //return is_blank(b, i) || is_breakz(b, i)
+       return ( // is_blank:
+       b[i] == ' ' || b[i] == '\t' ||
+               // is_breakz:
+               b[i] == '\r' || // CR (#xD)
+               b[i] == '\n' || // LF (#xA)
+               b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+               b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+               b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
+               b[i] == 0)
+}
+
+// Determine the width of the character.
+func width(b byte) int {
+       // Don't replace these by a switch without first
+       // confirming that it is being inlined.
+       if b&0x80 == 0x00 {
+               return 1
+       }
+       if b&0xE0 == 0xC0 {
+               return 2
+       }
+       if b&0xF0 == 0xE0 {
+               return 3
+       }
+       if b&0xF8 == 0xF0 {
+               return 4
+       }
+       return 0
+
+}
index a8bb7442ee3b8d4020d470836a0fa41bd8c4a7ad..dd6d449c5f3e9e9351308862d496c32e41b79ffc 100644 (file)
@@ -52,5 +52,7 @@ golang.org/x/net/internal/socket
 golang.org/x/net/bpf
 # gopkg.in/alecthomas/kingpin.v2 v2.2.5
 gopkg.in/alecthomas/kingpin.v2
-# gopkg.in/yaml.v2 v2.2.1
+# gopkg.in/yaml.v2 v2.2.2
 gopkg.in/yaml.v2
+# gopkg.in/yaml.v3 v3.0.0-20190405144635-389beb8b7082
+gopkg.in/yaml.v3