diff --git a/vendor/github.com/tidwall/sjson/README.md b/vendor/github.com/tidwall/sjson/README.md index 1a7c5c420..aeb940e9a 100644 --- a/vendor/github.com/tidwall/sjson/README.md +++ b/vendor/github.com/tidwall/sjson/README.md @@ -7,12 +7,12 @@ GoDoc

-

set a json value quickly

+

set a json value quickly

SJSON is a Go package that provides a [very fast](#performance) and simple way to set a value in a json document. The purpose for this library is to provide efficient json updating for the [SummitDB](https://github.com/tidwall/summitdb) project. For quickly retrieving json values check out [GJSON](https://github.com/tidwall/gjson). -For a command line interface check out [JSONed](https://github.com/tidwall/jsoned). +For a command line interface check out [JJ](https://github.com/tidwall/jj). Getting Started =============== @@ -59,7 +59,7 @@ Path syntax ----------- A path is a series of keys separated by a dot. -The dot and colon characters can be escaped with '\'. +The dot and colon characters can be escaped with ``\``. ```json { @@ -268,7 +268,7 @@ widget.image.hOffset widget.text.onMouseUp ``` -*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7.* +*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7 and can be be found [here](https://github.com/tidwall/sjson-benchmarks)*. ## Contact Josh Baker [@tidwall](http://twitter.com/tidwall) diff --git a/vendor/github.com/tidwall/sjson/sjson.go b/vendor/github.com/tidwall/sjson/sjson.go index 7f1d3588c..9f2d5c88c 100644 --- a/vendor/github.com/tidwall/sjson/sjson.go +++ b/vendor/github.com/tidwall/sjson/sjson.go @@ -3,9 +3,7 @@ package sjson import ( jsongo "encoding/json" - "reflect" "strconv" - "unsafe" "github.com/tidwall/gjson" ) @@ -36,6 +34,7 @@ type Options struct { type pathResult struct { part string // current key part + gpart string // gjson get part path string // remaining path force bool // force a string key more bool // there is more path to parse @@ -50,6 +49,7 @@ func parsePath(path string) (pathResult, error) { for i := 0; i < len(path); i++ { if path[i] == '.' { r.part = path[:i] + r.gpart = path[:i] r.path = path[i+1:] r.more = true return r, nil @@ -63,19 +63,24 @@ func parsePath(path string) (pathResult, error) { // go into escape mode. this is a slower path that // strips off the escape character from the part. epart := []byte(path[:i]) + gpart := []byte(path[:i+1]) i++ if i < len(path) { epart = append(epart, path[i]) + gpart = append(gpart, path[i]) i++ for ; i < len(path); i++ { if path[i] == '\\' { + gpart = append(gpart, '\\') i++ if i < len(path) { epart = append(epart, path[i]) + gpart = append(gpart, path[i]) } continue } else if path[i] == '.' { r.part = string(epart) + r.gpart = string(gpart) r.path = path[i+1:] r.more = true return r, nil @@ -87,20 +92,23 @@ func parsePath(path string) (pathResult, error) { "array access character not allowed in path"} } epart = append(epart, path[i]) + gpart = append(gpart, path[i]) } } // append the last part r.part = string(epart) + r.gpart = string(gpart) return r, nil } } r.part = path + r.gpart = path return r, nil } func mustMarshalString(s string) bool { for i := 0; i < len(s); i++ { - if s[i] < ' ' || s[i] > 0x7f || s[i] == '"' { + if s[i] < ' ' || s[i] > 0x7f || s[i] == '"' || s[i] == '\\' { return true } } @@ -208,7 +216,7 @@ loop: for ; i >= 0; i-- { if buf[i] == '"' { i-- - if i >= 0 && i == '\\' { + if i >= 0 && buf[i] == '\\' { i-- continue } @@ -249,7 +257,7 @@ func appendRawPaths(buf []byte, jstr string, paths []pathResult, raw string, } } if !found { - res = gjson.Get(jstr, paths[0].part) + res = gjson.Get(jstr, paths[0].gpart) } if res.Index > 0 { if len(paths) > 1 { @@ -400,72 +408,6 @@ func isOptimisticPath(path string) bool { return true } -func set(jstr, path, raw string, - stringify, del, optimistic, inplace bool) ([]byte, error) { - if path == "" { - return nil, &errorType{"path cannot be empty"} - } - if !del && optimistic && isOptimisticPath(path) { - res := gjson.Get(jstr, path) - if res.Exists() && res.Index > 0 { - sz := len(jstr) - len(res.Raw) + len(raw) - if stringify { - sz += 2 - } - if inplace && sz <= len(jstr) { - if !stringify || !mustMarshalString(raw) { - jsonh := *(*reflect.StringHeader)(unsafe.Pointer(&jstr)) - jsonbh := reflect.SliceHeader{ - Data: jsonh.Data, Len: jsonh.Len, Cap: jsonh.Len} - jbytes := *(*[]byte)(unsafe.Pointer(&jsonbh)) - if stringify { - jbytes[res.Index] = '"' - copy(jbytes[res.Index+1:], []byte(raw)) - jbytes[res.Index+1+len(raw)] = '"' - copy(jbytes[res.Index+1+len(raw)+1:], - jbytes[res.Index+len(res.Raw):]) - } else { - copy(jbytes[res.Index:], []byte(raw)) - copy(jbytes[res.Index+len(raw):], - jbytes[res.Index+len(res.Raw):]) - } - return jbytes[:sz], nil - } - return nil, nil - } - buf := make([]byte, 0, sz) - buf = append(buf, jstr[:res.Index]...) - if stringify { - buf = appendStringify(buf, raw) - } else { - buf = append(buf, raw...) - } - buf = append(buf, jstr[res.Index+len(res.Raw):]...) - return buf, nil - } - } - // parse the path, make sure that it does not contain invalid characters - // such as '#', '?', '*' - paths := make([]pathResult, 0, 4) - r, err := parsePath(path) - if err != nil { - return nil, err - } - paths = append(paths, r) - for r.more { - if r, err = parsePath(r.path); err != nil { - return nil, err - } - paths = append(paths, r) - } - - njson, err := appendRawPaths(nil, jstr, paths, raw, stringify, del) - if err != nil { - return nil, err - } - return njson, nil -} - // Set sets a json value for the specified path. // A path is in dot syntax, such as "name.last" or "age". // This function expects that the json is well-formed, and does not validate. @@ -491,29 +433,6 @@ func Set(json, path string, value interface{}) (string, error) { return SetOptions(json, path, value, nil) } -// SetOptions sets a json value for the specified path with options. -// A path is in dot syntax, such as "name.last" or "age". -// This function expects that the json is well-formed, and does not validate. -// Invalid json will not panic, but it may return back unexpected results. -// An error is returned if the path is not valid. -func SetOptions(json, path string, value interface{}, - opts *Options) (string, error) { - if opts != nil { - if opts.ReplaceInPlace { - // it's not safe to replace bytes in-place for strings - // copy the Options and set options.ReplaceInPlace to false. - nopts := *opts - opts = &nopts - opts.ReplaceInPlace = false - } - } - jsonh := *(*reflect.StringHeader)(unsafe.Pointer(&json)) - jsonbh := reflect.SliceHeader{Data: jsonh.Data, Len: jsonh.Len} - jsonb := *(*[]byte)(unsafe.Pointer(&jsonbh)) - res, err := SetBytesOptions(jsonb, path, value, opts) - return string(res), err -} - // SetBytes sets a json value for the specified path. // If working with bytes, this method preferred over // Set(string(data), path, value) @@ -521,77 +440,6 @@ func SetBytes(json []byte, path string, value interface{}) ([]byte, error) { return SetBytesOptions(json, path, value, nil) } -// SetBytesOptions sets a json value for the specified path with options. -// If working with bytes, this method preferred over -// SetOptions(string(data), path, value) -func SetBytesOptions(json []byte, path string, value interface{}, - opts *Options) ([]byte, error) { - var optimistic, inplace bool - if opts != nil { - optimistic = opts.Optimistic - inplace = opts.ReplaceInPlace - } - jstr := *(*string)(unsafe.Pointer(&json)) - var res []byte - var err error - switch v := value.(type) { - default: - b, err := jsongo.Marshal(value) - if err != nil { - return nil, err - } - raw := *(*string)(unsafe.Pointer(&b)) - res, err = set(jstr, path, raw, false, false, optimistic, inplace) - case dtype: - res, err = set(jstr, path, "", false, true, optimistic, inplace) - case string: - res, err = set(jstr, path, v, true, false, optimistic, inplace) - case []byte: - raw := *(*string)(unsafe.Pointer(&v)) - res, err = set(jstr, path, raw, true, false, optimistic, inplace) - case bool: - if v { - res, err = set(jstr, path, "true", false, false, optimistic, inplace) - } else { - res, err = set(jstr, path, "false", false, false, optimistic, inplace) - } - case int8: - res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), - false, false, optimistic, inplace) - case int16: - res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), - false, false, optimistic, inplace) - case int32: - res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), - false, false, optimistic, inplace) - case int64: - res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), - false, false, optimistic, inplace) - case uint8: - res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), - false, false, optimistic, inplace) - case uint16: - res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), - false, false, optimistic, inplace) - case uint32: - res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), - false, false, optimistic, inplace) - case uint64: - res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), - false, false, optimistic, inplace) - case float32: - res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64), - false, false, optimistic, inplace) - case float64: - res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64), - false, false, optimistic, inplace) - } - if err == errNoChange { - return json, nil - } - return res, err -} - // SetRaw sets a raw json value for the specified path. // This function works the same as Set except that the value is set as a // raw block of json. This allows for setting premarshalled json objects. @@ -621,25 +469,6 @@ func SetRawBytes(json []byte, path string, value []byte) ([]byte, error) { return SetRawBytesOptions(json, path, value, nil) } -// SetRawBytesOptions sets a raw json value for the specified path with options. -// If working with bytes, this method preferred over -// SetRawOptions(string(data), path, value, opts) -func SetRawBytesOptions(json []byte, path string, value []byte, - opts *Options) ([]byte, error) { - jstr := *(*string)(unsafe.Pointer(&json)) - vstr := *(*string)(unsafe.Pointer(&value)) - var optimistic, inplace bool - if opts != nil { - optimistic = opts.Optimistic - inplace = opts.ReplaceInPlace - } - res, err := set(jstr, path, vstr, false, false, optimistic, inplace) - if err == errNoChange { - return json, nil - } - return res, err -} - type dtype struct{} // Delete deletes a value from json for the specified path. diff --git a/vendor/github.com/tidwall/sjson/sjson_gae.go b/vendor/github.com/tidwall/sjson/sjson_gae.go new file mode 100644 index 000000000..eaba00e85 --- /dev/null +++ b/vendor/github.com/tidwall/sjson/sjson_gae.go @@ -0,0 +1,196 @@ +//+build appengine + +package sjson + +import ( + jsongo "encoding/json" + "strconv" + + "github.com/tidwall/gjson" +) + +func set(jstr, path, raw string, + stringify, del, optimistic, inplace bool) ([]byte, error) { + if path == "" { + return nil, &errorType{"path cannot be empty"} + } + if !del && optimistic && isOptimisticPath(path) { + res := gjson.Get(jstr, path) + if res.Exists() && res.Index > 0 { + sz := len(jstr) - len(res.Raw) + len(raw) + if stringify { + sz += 2 + } + if inplace && sz <= len(jstr) { + if !stringify || !mustMarshalString(raw) { + // jsonh := *(*reflect.StringHeader)(unsafe.Pointer(&jstr)) + // jsonbh := reflect.SliceHeader{ + // Data: jsonh.Data, Len: jsonh.Len, Cap: jsonh.Len} + // jbytes := *(*[]byte)(unsafe.Pointer(&jsonbh)) + jbytes := []byte(jstr) + if stringify { + jbytes[res.Index] = '"' + copy(jbytes[res.Index+1:], []byte(raw)) + jbytes[res.Index+1+len(raw)] = '"' + copy(jbytes[res.Index+1+len(raw)+1:], + jbytes[res.Index+len(res.Raw):]) + } else { + copy(jbytes[res.Index:], []byte(raw)) + copy(jbytes[res.Index+len(raw):], + jbytes[res.Index+len(res.Raw):]) + } + return jbytes[:sz], nil + } + return nil, nil + } + buf := make([]byte, 0, sz) + buf = append(buf, jstr[:res.Index]...) + if stringify { + buf = appendStringify(buf, raw) + } else { + buf = append(buf, raw...) + } + buf = append(buf, jstr[res.Index+len(res.Raw):]...) + return buf, nil + } + } + // parse the path, make sure that it does not contain invalid characters + // such as '#', '?', '*' + paths := make([]pathResult, 0, 4) + r, err := parsePath(path) + if err != nil { + return nil, err + } + paths = append(paths, r) + for r.more { + if r, err = parsePath(r.path); err != nil { + return nil, err + } + paths = append(paths, r) + } + + njson, err := appendRawPaths(nil, jstr, paths, raw, stringify, del) + if err != nil { + return nil, err + } + return njson, nil +} + +// SetOptions sets a json value for the specified path with options. +// A path is in dot syntax, such as "name.last" or "age". +// This function expects that the json is well-formed, and does not validate. +// Invalid json will not panic, but it may return back unexpected results. +// An error is returned if the path is not valid. +func SetOptions(json, path string, value interface{}, + opts *Options) (string, error) { + if opts != nil { + if opts.ReplaceInPlace { + // it's not safe to replace bytes in-place for strings + // copy the Options and set options.ReplaceInPlace to false. + nopts := *opts + opts = &nopts + opts.ReplaceInPlace = false + } + } + // jsonh := *(*reflect.StringHeader)(unsafe.Pointer(&json)) + // jsonbh := reflect.SliceHeader{Data: jsonh.Data, Len: jsonh.Len} + // jsonb := *(*[]byte)(unsafe.Pointer(&jsonbh)) + jsonb := []byte(json) + res, err := SetBytesOptions(jsonb, path, value, opts) + return string(res), err +} + +// SetBytesOptions sets a json value for the specified path with options. +// If working with bytes, this method preferred over +// SetOptions(string(data), path, value) +func SetBytesOptions(json []byte, path string, value interface{}, + opts *Options) ([]byte, error) { + var optimistic, inplace bool + if opts != nil { + optimistic = opts.Optimistic + inplace = opts.ReplaceInPlace + } + // jstr := *(*string)(unsafe.Pointer(&json)) + jstr := string(json) + var res []byte + var err error + switch v := value.(type) { + default: + b, merr := jsongo.Marshal(value) + if merr != nil { + return nil, merr + } + // raw := *(*string)(unsafe.Pointer(&b)) + raw := string(b) + res, err = set(jstr, path, raw, false, false, optimistic, inplace) + case dtype: + res, err = set(jstr, path, "", false, true, optimistic, inplace) + case string: + res, err = set(jstr, path, v, true, false, optimistic, inplace) + case []byte: + // raw := *(*string)(unsafe.Pointer(&v)) + raw := string(v) + res, err = set(jstr, path, raw, true, false, optimistic, inplace) + case bool: + if v { + res, err = set(jstr, path, "true", false, false, optimistic, inplace) + } else { + res, err = set(jstr, path, "false", false, false, optimistic, inplace) + } + case int8: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case int16: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case int32: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case int64: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case uint8: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case uint16: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case uint32: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case uint64: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case float32: + res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64), + false, false, optimistic, inplace) + case float64: + res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64), + false, false, optimistic, inplace) + } + if err == errNoChange { + return json, nil + } + return res, err +} + +// SetRawBytesOptions sets a raw json value for the specified path with options. +// If working with bytes, this method preferred over +// SetRawOptions(string(data), path, value, opts) +func SetRawBytesOptions(json []byte, path string, value []byte, + opts *Options) ([]byte, error) { + // jstr := *(*string)(unsafe.Pointer(&json)) + // vstr := *(*string)(unsafe.Pointer(&value)) + jstr := string(json) + vstr := string(value) + var optimistic, inplace bool + if opts != nil { + optimistic = opts.Optimistic + inplace = opts.ReplaceInPlace + } + res, err := set(jstr, path, vstr, false, false, optimistic, inplace) + if err == errNoChange { + return json, nil + } + return res, err +} diff --git a/vendor/github.com/tidwall/sjson/sjson_ngae.go b/vendor/github.com/tidwall/sjson/sjson_ngae.go new file mode 100644 index 000000000..6f47a047e --- /dev/null +++ b/vendor/github.com/tidwall/sjson/sjson_ngae.go @@ -0,0 +1,191 @@ +//+build !appengine + +package sjson + +import ( + jsongo "encoding/json" + "reflect" + "strconv" + "unsafe" + + "github.com/tidwall/gjson" +) + +func set(jstr, path, raw string, + stringify, del, optimistic, inplace bool) ([]byte, error) { + if path == "" { + return nil, &errorType{"path cannot be empty"} + } + if !del && optimistic && isOptimisticPath(path) { + res := gjson.Get(jstr, path) + if res.Exists() && res.Index > 0 { + sz := len(jstr) - len(res.Raw) + len(raw) + if stringify { + sz += 2 + } + if inplace && sz <= len(jstr) { + if !stringify || !mustMarshalString(raw) { + jsonh := *(*reflect.StringHeader)(unsafe.Pointer(&jstr)) + jsonbh := reflect.SliceHeader{ + Data: jsonh.Data, Len: jsonh.Len, Cap: jsonh.Len} + jbytes := *(*[]byte)(unsafe.Pointer(&jsonbh)) + if stringify { + jbytes[res.Index] = '"' + copy(jbytes[res.Index+1:], []byte(raw)) + jbytes[res.Index+1+len(raw)] = '"' + copy(jbytes[res.Index+1+len(raw)+1:], + jbytes[res.Index+len(res.Raw):]) + } else { + copy(jbytes[res.Index:], []byte(raw)) + copy(jbytes[res.Index+len(raw):], + jbytes[res.Index+len(res.Raw):]) + } + return jbytes[:sz], nil + } + return nil, nil + } + buf := make([]byte, 0, sz) + buf = append(buf, jstr[:res.Index]...) + if stringify { + buf = appendStringify(buf, raw) + } else { + buf = append(buf, raw...) + } + buf = append(buf, jstr[res.Index+len(res.Raw):]...) + return buf, nil + } + } + // parse the path, make sure that it does not contain invalid characters + // such as '#', '?', '*' + paths := make([]pathResult, 0, 4) + r, err := parsePath(path) + if err != nil { + return nil, err + } + paths = append(paths, r) + for r.more { + if r, err = parsePath(r.path); err != nil { + return nil, err + } + paths = append(paths, r) + } + + njson, err := appendRawPaths(nil, jstr, paths, raw, stringify, del) + if err != nil { + return nil, err + } + return njson, nil +} + +// SetOptions sets a json value for the specified path with options. +// A path is in dot syntax, such as "name.last" or "age". +// This function expects that the json is well-formed, and does not validate. +// Invalid json will not panic, but it may return back unexpected results. +// An error is returned if the path is not valid. +func SetOptions(json, path string, value interface{}, + opts *Options) (string, error) { + if opts != nil { + if opts.ReplaceInPlace { + // it's not safe to replace bytes in-place for strings + // copy the Options and set options.ReplaceInPlace to false. + nopts := *opts + opts = &nopts + opts.ReplaceInPlace = false + } + } + jsonh := *(*reflect.StringHeader)(unsafe.Pointer(&json)) + jsonbh := reflect.SliceHeader{Data: jsonh.Data, Len: jsonh.Len} + jsonb := *(*[]byte)(unsafe.Pointer(&jsonbh)) + res, err := SetBytesOptions(jsonb, path, value, opts) + return string(res), err +} + +// SetBytesOptions sets a json value for the specified path with options. +// If working with bytes, this method preferred over +// SetOptions(string(data), path, value) +func SetBytesOptions(json []byte, path string, value interface{}, + opts *Options) ([]byte, error) { + var optimistic, inplace bool + if opts != nil { + optimistic = opts.Optimistic + inplace = opts.ReplaceInPlace + } + jstr := *(*string)(unsafe.Pointer(&json)) + var res []byte + var err error + switch v := value.(type) { + default: + b, merr := jsongo.Marshal(value) + if merr != nil { + return nil, merr + } + raw := *(*string)(unsafe.Pointer(&b)) + res, err = set(jstr, path, raw, false, false, optimistic, inplace) + case dtype: + res, err = set(jstr, path, "", false, true, optimistic, inplace) + case string: + res, err = set(jstr, path, v, true, false, optimistic, inplace) + case []byte: + raw := *(*string)(unsafe.Pointer(&v)) + res, err = set(jstr, path, raw, true, false, optimistic, inplace) + case bool: + if v { + res, err = set(jstr, path, "true", false, false, optimistic, inplace) + } else { + res, err = set(jstr, path, "false", false, false, optimistic, inplace) + } + case int8: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case int16: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case int32: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case int64: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case uint8: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case uint16: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case uint32: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case uint64: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case float32: + res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64), + false, false, optimistic, inplace) + case float64: + res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64), + false, false, optimistic, inplace) + } + if err == errNoChange { + return json, nil + } + return res, err +} + +// SetRawBytesOptions sets a raw json value for the specified path with options. +// If working with bytes, this method preferred over +// SetRawOptions(string(data), path, value, opts) +func SetRawBytesOptions(json []byte, path string, value []byte, + opts *Options) ([]byte, error) { + jstr := *(*string)(unsafe.Pointer(&json)) + vstr := *(*string)(unsafe.Pointer(&value)) + var optimistic, inplace bool + if opts != nil { + optimistic = opts.Optimistic + inplace = opts.ReplaceInPlace + } + res, err := set(jstr, path, vstr, false, false, optimistic, inplace) + if err == errNoChange { + return json, nil + } + return res, err +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 0b94f5ffa..72ab0c8d8 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -897,10 +897,10 @@ "revisionTime": "2016-08-30T17:39:30Z" }, { - "checksumSHA1": "j1wNJXkZyuFKjYFpPawESOaXYxk=", + "checksumSHA1": "IeRoFAG92dA1jUX27nMz1qczlOw=", "path": "github.com/tidwall/sjson", - "revision": "6a22caf2fd45d5e2119bfc3717e984f15a7eb7ee", - "revisionTime": "2016-12-12T16:53:56Z" + "revision": "25fb082a20e29e83fb7b7ef5f5919166aad1f084", + "revisionTime": "2019-02-28T20:39:17Z" }, { "checksumSHA1": "R/Mpe0uUp5HeqWrdrH5qE2qZuE8=",