From 22aed182576a1ee21e046d786d982ea9af2ee2a4 Mon Sep 17 00:00:00 2001 From: Maxim Lebedev Date: Thu, 23 May 2019 19:52:58 +0500 Subject: [PATCH] :construction: Created worked version of the package Need documenting source code, checks by linters, add CI config --- fetch_embed.go | 53 + fetch_embed_test.go | 58 + find_provider.go | 74 ++ find_provider_test.go | 44 + is_valid_url.go | 8 + is_valid_url_test.go | 17 + oembed.go | 24 + oembed_test.go | 46 + sync.go | 49 + types.go | 106 ++ types_ffjson.go | 2497 +++++++++++++++++++++++++++++++++++++++++ 11 files changed, 2976 insertions(+) create mode 100644 fetch_embed.go create mode 100644 fetch_embed_test.go create mode 100644 find_provider.go create mode 100644 find_provider_test.go create mode 100644 is_valid_url.go create mode 100644 is_valid_url_test.go create mode 100644 oembed.go create mode 100644 oembed_test.go create mode 100644 sync.go create mode 100644 types.go create mode 100644 types_ffjson.go diff --git a/fetch_embed.go b/fetch_embed.go new file mode 100644 index 0000000..c4a6e88 --- /dev/null +++ b/fetch_embed.go @@ -0,0 +1,53 @@ +package oembed + +import ( + "strconv" + + json "github.com/pquerna/ffjson/ffjson" + http "github.com/valyala/fasthttp" + template "github.com/valyala/fasttemplate" +) + +type Params struct { + MaxWidth int + MaxHeight int +} + +func fetchEmbed(url string, provider providerCandidate, params *Params) (*Response, error) { + resourceUrl := provider.URL + resourceUrl = template.ExecuteString(resourceUrl, "{", "}", map[string]interface{}{"format": "json"}) + + link := http.AcquireURI() + defer http.ReleaseURI(link) + link.Update(resourceUrl) + qa := link.QueryArgs() + qa.Add("format", "json") + qa.Add("url", url) + + if params != nil && params.MaxWidth != 0 { + qa.Add("maxwidth", strconv.Itoa(params.MaxWidth)) + } + if params != nil && params.MaxHeight != 0 { + qa.Add("maxheight", strconv.Itoa(params.MaxHeight)) + } + link.SetQueryStringBytes(qa.QueryString()) + + req := http.AcquireRequest() + defer http.ReleaseRequest(req) + req.SetRequestURIBytes(link.FullURI()) + + resp := http.AcquireResponse() + defer http.ReleaseResponse(resp) + + if err := http.Do(req, resp); err != nil { + return nil, err + } + + var response Response + if err := json.Unmarshal(resp.Body(), &response); err != nil { + return nil, err + } + response.ProviderName = provider.ProviderName + response.ProviderURL = provider.ProviderURL + return &response, nil +} diff --git a/fetch_embed_test.go b/fetch_embed_test.go new file mode 100644 index 0000000..7d51a8a --- /dev/null +++ b/fetch_embed_test.go @@ -0,0 +1,58 @@ +package oembed + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFetchEmbed(t *testing.T) { + assert := assert.New(t) + t.Run("valid", func(t *testing.T) { + resp, err := fetchEmbed( + "https://www.youtube.com/watch?v=8jPQjjsBbIc", + makeCandidate(Provider{ + Name: "YouTube", + URL: "https://www.youtube.com/", + Endpoints: []Endpoint{Endpoint{ + Schemes: []string{ + "https://*.youtube.com/watch*", + "https://*.youtube.com/v/*\"", + "https://youtu.be/*", + }, + URL: "https://www.youtube.com/oembed", + Discovery: true, + }}, + }), + &Params{ + MaxWidth: 250, + MaxHeight: 250, + }, + ) + assert.NoError(err) + assert.NotNil(resp) + }) + t.Run("invalid", func(t *testing.T) { + for _, url := range []string{ + "", + "htt:/abc.com/failed-none-sense", + "https://abc.com/failed-none-sense", + "http://badcom/146753785", + "https://674458092126388225", + "http://www.ted.com/talks/something-does-not-exist", + "https://soundcloud^(*%%$%^$$%$$*&(&)())", + "https://www.flickr.com/services/oembed/?url=http%3A//www.flickr.com/photos/bees/23416sa/", + } { + url := url + t.Run(url, func(t *testing.T) { + c := findProvider(url) + if c == nil { + c = new(providerCandidate) + } + + _, err := fetchEmbed(url, *c, nil) + assert.Error(err) + }) + } + }) +} diff --git a/find_provider.go b/find_provider.go new file mode 100644 index 0000000..fdec3c4 --- /dev/null +++ b/find_provider.go @@ -0,0 +1,74 @@ +package oembed + +import ( + "regexp" + "strings" + + http "github.com/valyala/fasthttp" +) + +type providerCandidate struct { + Domain string + ProviderName string + ProviderURL string + Schemes []string + URL string +} + +func getHostname(url string) string { + u := http.AcquireURI() + defer http.ReleaseURI(u) + u.Update(url) + if u.Host() != nil { + return strings.TrimPrefix(string(u.Host()), "www.") + } + return "" +} + +func makeCandidate(p Provider) providerCandidate { + endpoint := p.Endpoints[0] + domain := getHostname(endpoint.URL) + if domain != "" { + domain = strings.TrimPrefix(domain, "www.") + } else { + domain = "" + } + + return providerCandidate{ + ProviderName: p.Name, + ProviderURL: p.URL, + Schemes: endpoint.Schemes, + URL: endpoint.URL, + Domain: domain, + } + +} + +func findProvider(url string) *providerCandidate { + var candidates []providerCandidate + for _, provider := range providersList { + provider := provider + candidate := makeCandidate(provider) + if len(candidate.Schemes) == 0 { + if !strings.Contains(url, candidate.Domain) { + continue + } + candidates = append(candidates, candidate) + continue + } + for _, scheme := range candidate.Schemes { + scheme := scheme + reg := regexp.MustCompile(strings.Replace(scheme, "*", "(.*)", -1)) + if !reg.MatchString(url) { + continue + } + + candidates = append(candidates, candidate) + break + } + } + if len(candidates) == 0 { + return nil + } + return &candidates[0] +} diff --git a/find_provider_test.go b/find_provider_test.go new file mode 100644 index 0000000..691c273 --- /dev/null +++ b/find_provider_test.go @@ -0,0 +1,44 @@ +package oembed + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetHostname(t *testing.T) { + assert := assert.New(t) + for k, v := range map[string]string{ + "https://mais.uol.com.br/": "mais.uol.com.br", + "http://www.wootled.com/": "wootled.com", + "http://yfrog.com": "yfrog.com", + "https://www.youtube.com": "youtube.com", + "https://www.znipe.tv": "znipe.tv", + "http://": "", + "": "", + } { + t.Run(k, func(t *testing.T) { assert.Equal(v, getHostname(k)) }) + } +} + +func TestMakeCandidate(t *testing.T) { + assert.NotNil(t, makeCandidate(Provider{ + Name: "YouTube", + URL: "https://www.youtube.com/", + Endpoints: []Endpoint{ + Endpoint{ + Schemes: []string{ + "https://*.youtube.com/watch*", + "https://*.youtube.com/v/*\"", + "https://youtu.be/*", + }, + URL: "https://www.youtube.com/oembed", + Discovery: true, + }, + }, + })) +} + +func TestFindProvider(t *testing.T) { + assert.NotNil(t, findProvider("https://www.beautiful.ai/")) +} diff --git a/is_valid_url.go b/is_valid_url.go new file mode 100644 index 0000000..902ea47 --- /dev/null +++ b/is_valid_url.go @@ -0,0 +1,8 @@ +package oembed + +import "net/url" + +func isValidURL(src string) bool { + _, err := url.ParseRequestURI(src) + return err == nil +} diff --git a/is_valid_url_test.go b/is_valid_url_test.go new file mode 100644 index 0000000..d6e456a --- /dev/null +++ b/is_valid_url_test.go @@ -0,0 +1,17 @@ +package oembed + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_IsValidURL(t *testing.T) { + assert := assert.New(t) + t.Run("invalid", func(t *testing.T) { + assert.False(isValidURL("str")) + }) + t.Run("valid", func(t *testing.T) { + assert.True(isValidURL("http://www.kickstarter.com")) + }) +} diff --git a/oembed.go b/oembed.go new file mode 100644 index 0000000..f8dd3c5 --- /dev/null +++ b/oembed.go @@ -0,0 +1,24 @@ +package oembed + +import ( + "golang.org/x/xerrors" +) + +var ( + ErrInvalidInputURL = xerrors.New("invalid input url") + ErrNoProviderFound = xerrors.New("no provider found with given url") +) + +func Extract(url string, params *Params) (*Response, error) { + if !isValidURL(url) { + return nil, ErrInvalidInputURL + } + if c := findProvider(url); c != nil { + return fetchEmbed(url, *c, params) + } + return nil, ErrNoProviderFound +} + +func HasProvider(url string) bool { + return findProvider(url) != nil +} diff --git a/oembed_test.go b/oembed_test.go new file mode 100644 index 0000000..6172d2d --- /dev/null +++ b/oembed_test.go @@ -0,0 +1,46 @@ +package oembed + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestExtract(t *testing.T) { + assert := assert.New(t) + t.Run("valid", func(t *testing.T) { + resp, err := Extract("https://www.youtube.com/watch?v=8jPQjjsBbIc", &Params{ + MaxWidth: 250, + MaxHeight: 250, + }) + assert.NoError(err) + assert.NotNil(resp) + }) + t.Run("invalid", func(t *testing.T) { + for _, url := range []string{ + "", + "htt:/abc.com/failed-none-sense", + "https://abc.com/failed-none-sense", + "http://badcom/146753785", + "https://674458092126388225", + "http://www.ted.com/talks/something-does-not-exist", + "https://soundcloud^(*%%$%^$$%$$*&(&)())", + "https://www.flickr.com/services/oembed/?url=http%3A//www.flickr.com/photos/bees/23416sa/", + } { + url := url + t.Run(url, func(t *testing.T) { + _, err := Extract(url, nil) + assert.Error(err) + }) + } + }) +} + +func TestHasProvider(t *testing.T) { + t.Run("true", func(t *testing.T) { + assert.True(t, HasProvider("https://www.youtube.com/watch?v=8jPQjjsBbIc")) + }) + t.Run("false", func(t *testing.T) { + assert.False(t, HasProvider("https://blog.toby3d.me/")) + }) +} diff --git a/sync.go b/sync.go new file mode 100644 index 0000000..7d0ba2d --- /dev/null +++ b/sync.go @@ -0,0 +1,49 @@ +package oembed + +import ( + "io/ioutil" + "log" + "os" + "path/filepath" + + json "github.com/pquerna/ffjson/ffjson" + http "github.com/valyala/fasthttp" +) + +const source string = "https://oembed.com/providers.json" + +var ( + providersList []Provider + + target = filepath.Join( + os.Getenv("GOPATH"), "src", "gitlab.com", "toby3d", "oembed", "assets", "providers.json", + ) +) + +func init() { + if err := fetch(source, target); err != nil { + panic(err) + } +} + +func fetch(url, target string) error { + status, src, err := http.Get(nil, url) + if err != nil || status != http.StatusOK { + if src, err = ioutil.ReadFile(target); err != nil { + return err + } + } + + if err := json.Unmarshal(src, &providersList); err != nil { + return err + } + + if status == http.StatusOK { + if err = ioutil.WriteFile(target, src, os.ModePerm); err != nil { + return err + } + } + + log.Println("providers.json has been updated") + return nil +} diff --git a/types.go b/types.go new file mode 100644 index 0000000..0c7841d --- /dev/null +++ b/types.go @@ -0,0 +1,106 @@ +//go:generate ffjson $GOFILE +package oembed + +type ( + Provider struct { + Name string `json:"provider_name"` + URL string `json:"provider_url"` + Endpoints []Endpoint `json:"endpoints"` + } + + Endpoint struct { + Schemes []string `json:"schemes,omitempty"` + URL string `json:"url"` + Discovery bool `json:"discovery,omitempty"` + Formats []string `json:"formats,omitempty"` + } + + // Response can specify a resource type, such as photo or video. + // Each type has specific parameters associated with it. + Response struct { + // The resource type. + Type string `json:"type"` // required + + // The oEmbed version number. + Version string `json:"version"` // required + + // A text title, describing the resource. + Title string `json:"title,omitempty"` + + // The name of the author/owner of the resource. + AuthorName string `json:"author_name,omitempty"` + + // A URL for the author/owner of the resource. + AuthorURL string `json:"author_url,omitempty"` + + // The name of the resource provider. + ProviderName string `json:"provider_name,omitempty"` + + // The url of the resource provider. + ProviderURL string `json:"provider_url,omitempty"` + + // The suggested cache lifetime for this resource, in seconds. + // Consumers may choose to use this value or not. + CacheAge int `json:"cache_age,omitempty"` + + // A URL to a thumbnail image representing the resource. + // The thumbnail must respect any maxwidth and maxheight parameters. + // If this parameter is present, thumbnail_width and thumbnail_height must also be present. + ThumbnailURL string `json:"thumbnail_url,omitempty"` + + // The width of the optional thumbnail. + // If this parameter is present, thumbnail_url and thumbnail_height must also be present. + ThumbnailWidth int `json:"thumbnail_width,omitempty"` + + // The height of the optional thumbnail. + // If this parameter is present, thumbnail_url and thumbnail_width must also be present. + ThumbnailHeight int `json:"thumbnail_height,omitempty"` + + URL string `json:"url,omitempty"` + } + + // Photo is used for representing static photos. + Photo struct { + // The source URL of the image. Consumers should be able to insert this URL into an element. + // Only HTTP and HTTPS URLs are valid. + URL string `json:"url"` // required + + // The width in pixels of the image specified in the url parameter. + Width int `json:"width"` // required + + // The height in pixels of the image specified in the url parameter. + Height int `json:"height"` // required + } + + // Video is used for representing playable videos. + Video struct { + // The HTML required to embed a video player. The HTML should have no padding or margins. + // Consumers may wish to load the HTML in an off-domain iframe to avoid XSS vulnerabilities. + HTML string `json:"html"` // required + + // The width in pixels required to display the HTML. + Width int `json:"width"` // required + + // The height in pixels required to display the HTML. + Height int `json:"height"` // required + } + + // Link type allow a provider to return any generic embed data (such as title and author_name), without + // providing either the url or html parameters. The consumer may then link to the resource, using the URL + // specified in the original request. + Link string + + // Rich is used for rich HTML content that does not fall under one of the other categories. + Rich struct { + // The HTML required to display the resource. The HTML should have no padding or margins. + // Consumers may wish to load the HTML in an off-domain iframe to avoid XSS vulnerabilities. + // The markup should be valid XHTML 1.0 Basic. + HTML string `json:"html"` // required + + // The width in pixels required to display the HTML. + Width int `json:"width"` // required + + // The height in pixels required to display the HTML. + Height int `json:"height"` // required + } +) diff --git a/types_ffjson.go b/types_ffjson.go new file mode 100644 index 0000000..d24413d --- /dev/null +++ b/types_ffjson.go @@ -0,0 +1,2497 @@ +// Code generated by ffjson . DO NOT EDIT. +// source: types.go + +package oembed + +import ( + "bytes" + "errors" + "fmt" + fflib "github.com/pquerna/ffjson/fflib/v1" +) + +// MarshalJSON marshal bytes to json - template +func (j *Endpoint) MarshalJSON() ([]byte, error) { + var buf fflib.Buffer + if j == nil { + buf.WriteString("null") + return buf.Bytes(), nil + } + err := j.MarshalJSONBuf(&buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// MarshalJSONBuf marshal buff to json - template +func (j *Endpoint) MarshalJSONBuf(buf fflib.EncodingBuffer) error { + if j == nil { + buf.WriteString("null") + return nil + } + var err error + var obj []byte + _ = obj + _ = err + buf.WriteString(`{ `) + if len(j.Schemes) != 0 { + buf.WriteString(`"schemes":`) + if j.Schemes != nil { + buf.WriteString(`[`) + for i, v := range j.Schemes { + if i != 0 { + buf.WriteString(`,`) + } + fflib.WriteJsonString(buf, string(v)) + } + buf.WriteString(`]`) + } else { + buf.WriteString(`null`) + } + buf.WriteByte(',') + } + buf.WriteString(`"url":`) + fflib.WriteJsonString(buf, string(j.URL)) + buf.WriteByte(',') + if j.Discovery != false { + if j.Discovery { + buf.WriteString(`"discovery":true`) + } else { + buf.WriteString(`"discovery":false`) + } + buf.WriteByte(',') + } + if len(j.Formats) != 0 { + buf.WriteString(`"formats":`) + if j.Formats != nil { + buf.WriteString(`[`) + for i, v := range j.Formats { + if i != 0 { + buf.WriteString(`,`) + } + fflib.WriteJsonString(buf, string(v)) + } + buf.WriteString(`]`) + } else { + buf.WriteString(`null`) + } + buf.WriteByte(',') + } + buf.Rewind(1) + buf.WriteByte('}') + return nil +} + +const ( + ffjtEndpointbase = iota + ffjtEndpointnosuchkey + + ffjtEndpointSchemes + + ffjtEndpointURL + + ffjtEndpointDiscovery + + ffjtEndpointFormats +) + +var ffjKeyEndpointSchemes = []byte("schemes") + +var ffjKeyEndpointURL = []byte("url") + +var ffjKeyEndpointDiscovery = []byte("discovery") + +var ffjKeyEndpointFormats = []byte("formats") + +// UnmarshalJSON umarshall json - template of ffjson +func (j *Endpoint) UnmarshalJSON(input []byte) error { + fs := fflib.NewFFLexer(input) + return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start) +} + +// UnmarshalJSONFFLexer fast json unmarshall - template ffjson +func (j *Endpoint) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error { + var err error + currentKey := ffjtEndpointbase + _ = currentKey + tok := fflib.FFTok_init + wantedTok := fflib.FFTok_init + +mainparse: + for { + tok = fs.Scan() + // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state)) + if tok == fflib.FFTok_error { + goto tokerror + } + + switch state { + + case fflib.FFParse_map_start: + if tok != fflib.FFTok_left_bracket { + wantedTok = fflib.FFTok_left_bracket + goto wrongtokenerror + } + state = fflib.FFParse_want_key + continue + + case fflib.FFParse_after_value: + if tok == fflib.FFTok_comma { + state = fflib.FFParse_want_key + } else if tok == fflib.FFTok_right_bracket { + goto done + } else { + wantedTok = fflib.FFTok_comma + goto wrongtokenerror + } + + case fflib.FFParse_want_key: + // json {} ended. goto exit. woo. + if tok == fflib.FFTok_right_bracket { + goto done + } + if tok != fflib.FFTok_string { + wantedTok = fflib.FFTok_string + goto wrongtokenerror + } + + kn := fs.Output.Bytes() + if len(kn) <= 0 { + // "" case. hrm. + currentKey = ffjtEndpointnosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } else { + switch kn[0] { + + case 'd': + + if bytes.Equal(ffjKeyEndpointDiscovery, kn) { + currentKey = ffjtEndpointDiscovery + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'f': + + if bytes.Equal(ffjKeyEndpointFormats, kn) { + currentKey = ffjtEndpointFormats + state = fflib.FFParse_want_colon + goto mainparse + } + + case 's': + + if bytes.Equal(ffjKeyEndpointSchemes, kn) { + currentKey = ffjtEndpointSchemes + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'u': + + if bytes.Equal(ffjKeyEndpointURL, kn) { + currentKey = ffjtEndpointURL + state = fflib.FFParse_want_colon + goto mainparse + } + + } + + if fflib.EqualFoldRight(ffjKeyEndpointFormats, kn) { + currentKey = ffjtEndpointFormats + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.EqualFoldRight(ffjKeyEndpointDiscovery, kn) { + currentKey = ffjtEndpointDiscovery + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.SimpleLetterEqualFold(ffjKeyEndpointURL, kn) { + currentKey = ffjtEndpointURL + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.EqualFoldRight(ffjKeyEndpointSchemes, kn) { + currentKey = ffjtEndpointSchemes + state = fflib.FFParse_want_colon + goto mainparse + } + + currentKey = ffjtEndpointnosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } + + case fflib.FFParse_want_colon: + if tok != fflib.FFTok_colon { + wantedTok = fflib.FFTok_colon + goto wrongtokenerror + } + state = fflib.FFParse_want_value + continue + case fflib.FFParse_want_value: + + if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null { + switch currentKey { + + case ffjtEndpointSchemes: + goto handle_Schemes + + case ffjtEndpointURL: + goto handle_URL + + case ffjtEndpointDiscovery: + goto handle_Discovery + + case ffjtEndpointFormats: + goto handle_Formats + + case ffjtEndpointnosuchkey: + err = fs.SkipField(tok) + if err != nil { + return fs.WrapErr(err) + } + state = fflib.FFParse_after_value + goto mainparse + } + } else { + goto wantedvalue + } + } + } + +handle_Schemes: + + /* handler: j.Schemes type=[]string kind=slice quoted=false*/ + + { + + { + if tok != fflib.FFTok_left_brace && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok)) + } + } + + if tok == fflib.FFTok_null { + j.Schemes = nil + } else { + + j.Schemes = []string{} + + wantVal := true + + for { + + var tmpJSchemes string + + tok = fs.Scan() + if tok == fflib.FFTok_error { + goto tokerror + } + if tok == fflib.FFTok_right_brace { + break + } + + if tok == fflib.FFTok_comma { + if wantVal == true { + // TODO(pquerna): this isn't an ideal error message, this handles + // things like [,,,] as an array value. + return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) + } + continue + } else { + wantVal = true + } + + /* handler: tmpJSchemes type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + tmpJSchemes = string(string(outBuf)) + + } + } + + j.Schemes = append(j.Schemes, tmpJSchemes) + + wantVal = false + } + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_URL: + + /* handler: j.URL type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.URL = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Discovery: + + /* handler: j.Discovery type=bool kind=bool quoted=false*/ + + { + if tok != fflib.FFTok_bool && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok)) + } + } + + { + if tok == fflib.FFTok_null { + + } else { + tmpb := fs.Output.Bytes() + + if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 { + + j.Discovery = true + + } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 { + + j.Discovery = false + + } else { + err = errors.New("unexpected bytes for true/false value") + return fs.WrapErr(err) + } + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Formats: + + /* handler: j.Formats type=[]string kind=slice quoted=false*/ + + { + + { + if tok != fflib.FFTok_left_brace && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok)) + } + } + + if tok == fflib.FFTok_null { + j.Formats = nil + } else { + + j.Formats = []string{} + + wantVal := true + + for { + + var tmpJFormats string + + tok = fs.Scan() + if tok == fflib.FFTok_error { + goto tokerror + } + if tok == fflib.FFTok_right_brace { + break + } + + if tok == fflib.FFTok_comma { + if wantVal == true { + // TODO(pquerna): this isn't an ideal error message, this handles + // things like [,,,] as an array value. + return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) + } + continue + } else { + wantVal = true + } + + /* handler: tmpJFormats type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + tmpJFormats = string(string(outBuf)) + + } + } + + j.Formats = append(j.Formats, tmpJFormats) + + wantVal = false + } + } + } + + state = fflib.FFParse_after_value + goto mainparse + +wantedvalue: + return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) +wrongtokenerror: + return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String())) +tokerror: + if fs.BigError != nil { + return fs.WrapErr(fs.BigError) + } + err = fs.Error.ToError() + if err != nil { + return fs.WrapErr(err) + } + panic("ffjson-generated: unreachable, please report bug.") +done: + + return nil +} + +// MarshalJSON marshal bytes to json - template +func (j *Photo) MarshalJSON() ([]byte, error) { + var buf fflib.Buffer + if j == nil { + buf.WriteString("null") + return buf.Bytes(), nil + } + err := j.MarshalJSONBuf(&buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// MarshalJSONBuf marshal buff to json - template +func (j *Photo) MarshalJSONBuf(buf fflib.EncodingBuffer) error { + if j == nil { + buf.WriteString("null") + return nil + } + var err error + var obj []byte + _ = obj + _ = err + buf.WriteString(`{"url":`) + fflib.WriteJsonString(buf, string(j.URL)) + buf.WriteString(`,"width":`) + fflib.FormatBits2(buf, uint64(j.Width), 10, j.Width < 0) + buf.WriteString(`,"height":`) + fflib.FormatBits2(buf, uint64(j.Height), 10, j.Height < 0) + buf.WriteByte('}') + return nil +} + +const ( + ffjtPhotobase = iota + ffjtPhotonosuchkey + + ffjtPhotoURL + + ffjtPhotoWidth + + ffjtPhotoHeight +) + +var ffjKeyPhotoURL = []byte("url") + +var ffjKeyPhotoWidth = []byte("width") + +var ffjKeyPhotoHeight = []byte("height") + +// UnmarshalJSON umarshall json - template of ffjson +func (j *Photo) UnmarshalJSON(input []byte) error { + fs := fflib.NewFFLexer(input) + return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start) +} + +// UnmarshalJSONFFLexer fast json unmarshall - template ffjson +func (j *Photo) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error { + var err error + currentKey := ffjtPhotobase + _ = currentKey + tok := fflib.FFTok_init + wantedTok := fflib.FFTok_init + +mainparse: + for { + tok = fs.Scan() + // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state)) + if tok == fflib.FFTok_error { + goto tokerror + } + + switch state { + + case fflib.FFParse_map_start: + if tok != fflib.FFTok_left_bracket { + wantedTok = fflib.FFTok_left_bracket + goto wrongtokenerror + } + state = fflib.FFParse_want_key + continue + + case fflib.FFParse_after_value: + if tok == fflib.FFTok_comma { + state = fflib.FFParse_want_key + } else if tok == fflib.FFTok_right_bracket { + goto done + } else { + wantedTok = fflib.FFTok_comma + goto wrongtokenerror + } + + case fflib.FFParse_want_key: + // json {} ended. goto exit. woo. + if tok == fflib.FFTok_right_bracket { + goto done + } + if tok != fflib.FFTok_string { + wantedTok = fflib.FFTok_string + goto wrongtokenerror + } + + kn := fs.Output.Bytes() + if len(kn) <= 0 { + // "" case. hrm. + currentKey = ffjtPhotonosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } else { + switch kn[0] { + + case 'h': + + if bytes.Equal(ffjKeyPhotoHeight, kn) { + currentKey = ffjtPhotoHeight + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'u': + + if bytes.Equal(ffjKeyPhotoURL, kn) { + currentKey = ffjtPhotoURL + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'w': + + if bytes.Equal(ffjKeyPhotoWidth, kn) { + currentKey = ffjtPhotoWidth + state = fflib.FFParse_want_colon + goto mainparse + } + + } + + if fflib.SimpleLetterEqualFold(ffjKeyPhotoHeight, kn) { + currentKey = ffjtPhotoHeight + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.SimpleLetterEqualFold(ffjKeyPhotoWidth, kn) { + currentKey = ffjtPhotoWidth + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.SimpleLetterEqualFold(ffjKeyPhotoURL, kn) { + currentKey = ffjtPhotoURL + state = fflib.FFParse_want_colon + goto mainparse + } + + currentKey = ffjtPhotonosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } + + case fflib.FFParse_want_colon: + if tok != fflib.FFTok_colon { + wantedTok = fflib.FFTok_colon + goto wrongtokenerror + } + state = fflib.FFParse_want_value + continue + case fflib.FFParse_want_value: + + if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null { + switch currentKey { + + case ffjtPhotoURL: + goto handle_URL + + case ffjtPhotoWidth: + goto handle_Width + + case ffjtPhotoHeight: + goto handle_Height + + case ffjtPhotonosuchkey: + err = fs.SkipField(tok) + if err != nil { + return fs.WrapErr(err) + } + state = fflib.FFParse_after_value + goto mainparse + } + } else { + goto wantedvalue + } + } + } + +handle_URL: + + /* handler: j.URL type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.URL = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Width: + + /* handler: j.Width type=int kind=int quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + j.Width = int(tval) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Height: + + /* handler: j.Height type=int kind=int quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + j.Height = int(tval) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +wantedvalue: + return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) +wrongtokenerror: + return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String())) +tokerror: + if fs.BigError != nil { + return fs.WrapErr(fs.BigError) + } + err = fs.Error.ToError() + if err != nil { + return fs.WrapErr(err) + } + panic("ffjson-generated: unreachable, please report bug.") +done: + + return nil +} + +// MarshalJSON marshal bytes to json - template +func (j *Provider) MarshalJSON() ([]byte, error) { + var buf fflib.Buffer + if j == nil { + buf.WriteString("null") + return buf.Bytes(), nil + } + err := j.MarshalJSONBuf(&buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// MarshalJSONBuf marshal buff to json - template +func (j *Provider) MarshalJSONBuf(buf fflib.EncodingBuffer) error { + if j == nil { + buf.WriteString("null") + return nil + } + var err error + var obj []byte + _ = obj + _ = err + buf.WriteString(`{"provider_name":`) + fflib.WriteJsonString(buf, string(j.Name)) + buf.WriteString(`,"provider_url":`) + fflib.WriteJsonString(buf, string(j.URL)) + buf.WriteString(`,"endpoints":`) + if j.Endpoints != nil { + buf.WriteString(`[`) + for i, v := range j.Endpoints { + if i != 0 { + buf.WriteString(`,`) + } + + { + + err = v.MarshalJSONBuf(buf) + if err != nil { + return err + } + + } + } + buf.WriteString(`]`) + } else { + buf.WriteString(`null`) + } + buf.WriteByte('}') + return nil +} + +const ( + ffjtProviderbase = iota + ffjtProvidernosuchkey + + ffjtProviderName + + ffjtProviderURL + + ffjtProviderEndpoints +) + +var ffjKeyProviderName = []byte("provider_name") + +var ffjKeyProviderURL = []byte("provider_url") + +var ffjKeyProviderEndpoints = []byte("endpoints") + +// UnmarshalJSON umarshall json - template of ffjson +func (j *Provider) UnmarshalJSON(input []byte) error { + fs := fflib.NewFFLexer(input) + return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start) +} + +// UnmarshalJSONFFLexer fast json unmarshall - template ffjson +func (j *Provider) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error { + var err error + currentKey := ffjtProviderbase + _ = currentKey + tok := fflib.FFTok_init + wantedTok := fflib.FFTok_init + +mainparse: + for { + tok = fs.Scan() + // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state)) + if tok == fflib.FFTok_error { + goto tokerror + } + + switch state { + + case fflib.FFParse_map_start: + if tok != fflib.FFTok_left_bracket { + wantedTok = fflib.FFTok_left_bracket + goto wrongtokenerror + } + state = fflib.FFParse_want_key + continue + + case fflib.FFParse_after_value: + if tok == fflib.FFTok_comma { + state = fflib.FFParse_want_key + } else if tok == fflib.FFTok_right_bracket { + goto done + } else { + wantedTok = fflib.FFTok_comma + goto wrongtokenerror + } + + case fflib.FFParse_want_key: + // json {} ended. goto exit. woo. + if tok == fflib.FFTok_right_bracket { + goto done + } + if tok != fflib.FFTok_string { + wantedTok = fflib.FFTok_string + goto wrongtokenerror + } + + kn := fs.Output.Bytes() + if len(kn) <= 0 { + // "" case. hrm. + currentKey = ffjtProvidernosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } else { + switch kn[0] { + + case 'e': + + if bytes.Equal(ffjKeyProviderEndpoints, kn) { + currentKey = ffjtProviderEndpoints + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'p': + + if bytes.Equal(ffjKeyProviderName, kn) { + currentKey = ffjtProviderName + state = fflib.FFParse_want_colon + goto mainparse + + } else if bytes.Equal(ffjKeyProviderURL, kn) { + currentKey = ffjtProviderURL + state = fflib.FFParse_want_colon + goto mainparse + } + + } + + if fflib.EqualFoldRight(ffjKeyProviderEndpoints, kn) { + currentKey = ffjtProviderEndpoints + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyProviderURL, kn) { + currentKey = ffjtProviderURL + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyProviderName, kn) { + currentKey = ffjtProviderName + state = fflib.FFParse_want_colon + goto mainparse + } + + currentKey = ffjtProvidernosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } + + case fflib.FFParse_want_colon: + if tok != fflib.FFTok_colon { + wantedTok = fflib.FFTok_colon + goto wrongtokenerror + } + state = fflib.FFParse_want_value + continue + case fflib.FFParse_want_value: + + if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null { + switch currentKey { + + case ffjtProviderName: + goto handle_Name + + case ffjtProviderURL: + goto handle_URL + + case ffjtProviderEndpoints: + goto handle_Endpoints + + case ffjtProvidernosuchkey: + err = fs.SkipField(tok) + if err != nil { + return fs.WrapErr(err) + } + state = fflib.FFParse_after_value + goto mainparse + } + } else { + goto wantedvalue + } + } + } + +handle_Name: + + /* handler: j.Name type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.Name = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_URL: + + /* handler: j.URL type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.URL = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Endpoints: + + /* handler: j.Endpoints type=[]oembed.Endpoint kind=slice quoted=false*/ + + { + + { + if tok != fflib.FFTok_left_brace && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok)) + } + } + + if tok == fflib.FFTok_null { + j.Endpoints = nil + } else { + + j.Endpoints = []Endpoint{} + + wantVal := true + + for { + + var tmpJEndpoints Endpoint + + tok = fs.Scan() + if tok == fflib.FFTok_error { + goto tokerror + } + if tok == fflib.FFTok_right_brace { + break + } + + if tok == fflib.FFTok_comma { + if wantVal == true { + // TODO(pquerna): this isn't an ideal error message, this handles + // things like [,,,] as an array value. + return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) + } + continue + } else { + wantVal = true + } + + /* handler: tmpJEndpoints type=oembed.Endpoint kind=struct quoted=false*/ + + { + if tok == fflib.FFTok_null { + + } else { + + err = tmpJEndpoints.UnmarshalJSONFFLexer(fs, fflib.FFParse_want_key) + if err != nil { + return err + } + } + state = fflib.FFParse_after_value + } + + j.Endpoints = append(j.Endpoints, tmpJEndpoints) + + wantVal = false + } + } + } + + state = fflib.FFParse_after_value + goto mainparse + +wantedvalue: + return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) +wrongtokenerror: + return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String())) +tokerror: + if fs.BigError != nil { + return fs.WrapErr(fs.BigError) + } + err = fs.Error.ToError() + if err != nil { + return fs.WrapErr(err) + } + panic("ffjson-generated: unreachable, please report bug.") +done: + + return nil +} + +// MarshalJSON marshal bytes to json - template +func (j *Response) MarshalJSON() ([]byte, error) { + var buf fflib.Buffer + if j == nil { + buf.WriteString("null") + return buf.Bytes(), nil + } + err := j.MarshalJSONBuf(&buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// MarshalJSONBuf marshal buff to json - template +func (j *Response) MarshalJSONBuf(buf fflib.EncodingBuffer) error { + if j == nil { + buf.WriteString("null") + return nil + } + var err error + var obj []byte + _ = obj + _ = err + buf.WriteString(`{ "type":`) + fflib.WriteJsonString(buf, string(j.Type)) + buf.WriteString(`,"version":`) + fflib.WriteJsonString(buf, string(j.Version)) + buf.WriteByte(',') + if len(j.Title) != 0 { + buf.WriteString(`"title":`) + fflib.WriteJsonString(buf, string(j.Title)) + buf.WriteByte(',') + } + if len(j.AuthorName) != 0 { + buf.WriteString(`"author_name":`) + fflib.WriteJsonString(buf, string(j.AuthorName)) + buf.WriteByte(',') + } + if len(j.AuthorURL) != 0 { + buf.WriteString(`"author_url":`) + fflib.WriteJsonString(buf, string(j.AuthorURL)) + buf.WriteByte(',') + } + if len(j.ProviderName) != 0 { + buf.WriteString(`"provider_name":`) + fflib.WriteJsonString(buf, string(j.ProviderName)) + buf.WriteByte(',') + } + if len(j.ProviderURL) != 0 { + buf.WriteString(`"provider_url":`) + fflib.WriteJsonString(buf, string(j.ProviderURL)) + buf.WriteByte(',') + } + if j.CacheAge != 0 { + buf.WriteString(`"cache_age":`) + fflib.FormatBits2(buf, uint64(j.CacheAge), 10, j.CacheAge < 0) + buf.WriteByte(',') + } + if len(j.ThumbnailURL) != 0 { + buf.WriteString(`"thumbnail_url":`) + fflib.WriteJsonString(buf, string(j.ThumbnailURL)) + buf.WriteByte(',') + } + if j.ThumbnailWidth != 0 { + buf.WriteString(`"thumbnail_width":`) + fflib.FormatBits2(buf, uint64(j.ThumbnailWidth), 10, j.ThumbnailWidth < 0) + buf.WriteByte(',') + } + if j.ThumbnailHeight != 0 { + buf.WriteString(`"thumbnail_height":`) + fflib.FormatBits2(buf, uint64(j.ThumbnailHeight), 10, j.ThumbnailHeight < 0) + buf.WriteByte(',') + } + if len(j.URL) != 0 { + buf.WriteString(`"url":`) + fflib.WriteJsonString(buf, string(j.URL)) + buf.WriteByte(',') + } + buf.Rewind(1) + buf.WriteByte('}') + return nil +} + +const ( + ffjtResponsebase = iota + ffjtResponsenosuchkey + + ffjtResponseType + + ffjtResponseVersion + + ffjtResponseTitle + + ffjtResponseAuthorName + + ffjtResponseAuthorURL + + ffjtResponseProviderName + + ffjtResponseProviderURL + + ffjtResponseCacheAge + + ffjtResponseThumbnailURL + + ffjtResponseThumbnailWidth + + ffjtResponseThumbnailHeight + + ffjtResponseURL +) + +var ffjKeyResponseType = []byte("type") + +var ffjKeyResponseVersion = []byte("version") + +var ffjKeyResponseTitle = []byte("title") + +var ffjKeyResponseAuthorName = []byte("author_name") + +var ffjKeyResponseAuthorURL = []byte("author_url") + +var ffjKeyResponseProviderName = []byte("provider_name") + +var ffjKeyResponseProviderURL = []byte("provider_url") + +var ffjKeyResponseCacheAge = []byte("cache_age") + +var ffjKeyResponseThumbnailURL = []byte("thumbnail_url") + +var ffjKeyResponseThumbnailWidth = []byte("thumbnail_width") + +var ffjKeyResponseThumbnailHeight = []byte("thumbnail_height") + +var ffjKeyResponseURL = []byte("url") + +// UnmarshalJSON umarshall json - template of ffjson +func (j *Response) UnmarshalJSON(input []byte) error { + fs := fflib.NewFFLexer(input) + return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start) +} + +// UnmarshalJSONFFLexer fast json unmarshall - template ffjson +func (j *Response) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error { + var err error + currentKey := ffjtResponsebase + _ = currentKey + tok := fflib.FFTok_init + wantedTok := fflib.FFTok_init + +mainparse: + for { + tok = fs.Scan() + // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state)) + if tok == fflib.FFTok_error { + goto tokerror + } + + switch state { + + case fflib.FFParse_map_start: + if tok != fflib.FFTok_left_bracket { + wantedTok = fflib.FFTok_left_bracket + goto wrongtokenerror + } + state = fflib.FFParse_want_key + continue + + case fflib.FFParse_after_value: + if tok == fflib.FFTok_comma { + state = fflib.FFParse_want_key + } else if tok == fflib.FFTok_right_bracket { + goto done + } else { + wantedTok = fflib.FFTok_comma + goto wrongtokenerror + } + + case fflib.FFParse_want_key: + // json {} ended. goto exit. woo. + if tok == fflib.FFTok_right_bracket { + goto done + } + if tok != fflib.FFTok_string { + wantedTok = fflib.FFTok_string + goto wrongtokenerror + } + + kn := fs.Output.Bytes() + if len(kn) <= 0 { + // "" case. hrm. + currentKey = ffjtResponsenosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } else { + switch kn[0] { + + case 'a': + + if bytes.Equal(ffjKeyResponseAuthorName, kn) { + currentKey = ffjtResponseAuthorName + state = fflib.FFParse_want_colon + goto mainparse + + } else if bytes.Equal(ffjKeyResponseAuthorURL, kn) { + currentKey = ffjtResponseAuthorURL + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'c': + + if bytes.Equal(ffjKeyResponseCacheAge, kn) { + currentKey = ffjtResponseCacheAge + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'p': + + if bytes.Equal(ffjKeyResponseProviderName, kn) { + currentKey = ffjtResponseProviderName + state = fflib.FFParse_want_colon + goto mainparse + + } else if bytes.Equal(ffjKeyResponseProviderURL, kn) { + currentKey = ffjtResponseProviderURL + state = fflib.FFParse_want_colon + goto mainparse + } + + case 't': + + if bytes.Equal(ffjKeyResponseType, kn) { + currentKey = ffjtResponseType + state = fflib.FFParse_want_colon + goto mainparse + + } else if bytes.Equal(ffjKeyResponseTitle, kn) { + currentKey = ffjtResponseTitle + state = fflib.FFParse_want_colon + goto mainparse + + } else if bytes.Equal(ffjKeyResponseThumbnailURL, kn) { + currentKey = ffjtResponseThumbnailURL + state = fflib.FFParse_want_colon + goto mainparse + + } else if bytes.Equal(ffjKeyResponseThumbnailWidth, kn) { + currentKey = ffjtResponseThumbnailWidth + state = fflib.FFParse_want_colon + goto mainparse + + } else if bytes.Equal(ffjKeyResponseThumbnailHeight, kn) { + currentKey = ffjtResponseThumbnailHeight + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'u': + + if bytes.Equal(ffjKeyResponseURL, kn) { + currentKey = ffjtResponseURL + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'v': + + if bytes.Equal(ffjKeyResponseVersion, kn) { + currentKey = ffjtResponseVersion + state = fflib.FFParse_want_colon + goto mainparse + } + + } + + if fflib.SimpleLetterEqualFold(ffjKeyResponseURL, kn) { + currentKey = ffjtResponseURL + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyResponseThumbnailHeight, kn) { + currentKey = ffjtResponseThumbnailHeight + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyResponseThumbnailWidth, kn) { + currentKey = ffjtResponseThumbnailWidth + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyResponseThumbnailURL, kn) { + currentKey = ffjtResponseThumbnailURL + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyResponseCacheAge, kn) { + currentKey = ffjtResponseCacheAge + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyResponseProviderURL, kn) { + currentKey = ffjtResponseProviderURL + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyResponseProviderName, kn) { + currentKey = ffjtResponseProviderName + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyResponseAuthorURL, kn) { + currentKey = ffjtResponseAuthorURL + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.AsciiEqualFold(ffjKeyResponseAuthorName, kn) { + currentKey = ffjtResponseAuthorName + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.SimpleLetterEqualFold(ffjKeyResponseTitle, kn) { + currentKey = ffjtResponseTitle + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.EqualFoldRight(ffjKeyResponseVersion, kn) { + currentKey = ffjtResponseVersion + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.SimpleLetterEqualFold(ffjKeyResponseType, kn) { + currentKey = ffjtResponseType + state = fflib.FFParse_want_colon + goto mainparse + } + + currentKey = ffjtResponsenosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } + + case fflib.FFParse_want_colon: + if tok != fflib.FFTok_colon { + wantedTok = fflib.FFTok_colon + goto wrongtokenerror + } + state = fflib.FFParse_want_value + continue + case fflib.FFParse_want_value: + + if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null { + switch currentKey { + + case ffjtResponseType: + goto handle_Type + + case ffjtResponseVersion: + goto handle_Version + + case ffjtResponseTitle: + goto handle_Title + + case ffjtResponseAuthorName: + goto handle_AuthorName + + case ffjtResponseAuthorURL: + goto handle_AuthorURL + + case ffjtResponseProviderName: + goto handle_ProviderName + + case ffjtResponseProviderURL: + goto handle_ProviderURL + + case ffjtResponseCacheAge: + goto handle_CacheAge + + case ffjtResponseThumbnailURL: + goto handle_ThumbnailURL + + case ffjtResponseThumbnailWidth: + goto handle_ThumbnailWidth + + case ffjtResponseThumbnailHeight: + goto handle_ThumbnailHeight + + case ffjtResponseURL: + goto handle_URL + + case ffjtResponsenosuchkey: + err = fs.SkipField(tok) + if err != nil { + return fs.WrapErr(err) + } + state = fflib.FFParse_after_value + goto mainparse + } + } else { + goto wantedvalue + } + } + } + +handle_Type: + + /* handler: j.Type type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.Type = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Version: + + /* handler: j.Version type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.Version = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Title: + + /* handler: j.Title type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.Title = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_AuthorName: + + /* handler: j.AuthorName type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.AuthorName = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_AuthorURL: + + /* handler: j.AuthorURL type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.AuthorURL = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_ProviderName: + + /* handler: j.ProviderName type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.ProviderName = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_ProviderURL: + + /* handler: j.ProviderURL type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.ProviderURL = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_CacheAge: + + /* handler: j.CacheAge type=int kind=int quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + j.CacheAge = int(tval) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_ThumbnailURL: + + /* handler: j.ThumbnailURL type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.ThumbnailURL = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_ThumbnailWidth: + + /* handler: j.ThumbnailWidth type=int kind=int quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + j.ThumbnailWidth = int(tval) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_ThumbnailHeight: + + /* handler: j.ThumbnailHeight type=int kind=int quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + j.ThumbnailHeight = int(tval) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_URL: + + /* handler: j.URL type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.URL = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +wantedvalue: + return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) +wrongtokenerror: + return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String())) +tokerror: + if fs.BigError != nil { + return fs.WrapErr(fs.BigError) + } + err = fs.Error.ToError() + if err != nil { + return fs.WrapErr(err) + } + panic("ffjson-generated: unreachable, please report bug.") +done: + + return nil +} + +// MarshalJSON marshal bytes to json - template +func (j *Rich) MarshalJSON() ([]byte, error) { + var buf fflib.Buffer + if j == nil { + buf.WriteString("null") + return buf.Bytes(), nil + } + err := j.MarshalJSONBuf(&buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// MarshalJSONBuf marshal buff to json - template +func (j *Rich) MarshalJSONBuf(buf fflib.EncodingBuffer) error { + if j == nil { + buf.WriteString("null") + return nil + } + var err error + var obj []byte + _ = obj + _ = err + buf.WriteString(`{"html":`) + fflib.WriteJsonString(buf, string(j.HTML)) + buf.WriteString(`,"width":`) + fflib.FormatBits2(buf, uint64(j.Width), 10, j.Width < 0) + buf.WriteString(`,"height":`) + fflib.FormatBits2(buf, uint64(j.Height), 10, j.Height < 0) + buf.WriteByte('}') + return nil +} + +const ( + ffjtRichbase = iota + ffjtRichnosuchkey + + ffjtRichHTML + + ffjtRichWidth + + ffjtRichHeight +) + +var ffjKeyRichHTML = []byte("html") + +var ffjKeyRichWidth = []byte("width") + +var ffjKeyRichHeight = []byte("height") + +// UnmarshalJSON umarshall json - template of ffjson +func (j *Rich) UnmarshalJSON(input []byte) error { + fs := fflib.NewFFLexer(input) + return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start) +} + +// UnmarshalJSONFFLexer fast json unmarshall - template ffjson +func (j *Rich) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error { + var err error + currentKey := ffjtRichbase + _ = currentKey + tok := fflib.FFTok_init + wantedTok := fflib.FFTok_init + +mainparse: + for { + tok = fs.Scan() + // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state)) + if tok == fflib.FFTok_error { + goto tokerror + } + + switch state { + + case fflib.FFParse_map_start: + if tok != fflib.FFTok_left_bracket { + wantedTok = fflib.FFTok_left_bracket + goto wrongtokenerror + } + state = fflib.FFParse_want_key + continue + + case fflib.FFParse_after_value: + if tok == fflib.FFTok_comma { + state = fflib.FFParse_want_key + } else if tok == fflib.FFTok_right_bracket { + goto done + } else { + wantedTok = fflib.FFTok_comma + goto wrongtokenerror + } + + case fflib.FFParse_want_key: + // json {} ended. goto exit. woo. + if tok == fflib.FFTok_right_bracket { + goto done + } + if tok != fflib.FFTok_string { + wantedTok = fflib.FFTok_string + goto wrongtokenerror + } + + kn := fs.Output.Bytes() + if len(kn) <= 0 { + // "" case. hrm. + currentKey = ffjtRichnosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } else { + switch kn[0] { + + case 'h': + + if bytes.Equal(ffjKeyRichHTML, kn) { + currentKey = ffjtRichHTML + state = fflib.FFParse_want_colon + goto mainparse + + } else if bytes.Equal(ffjKeyRichHeight, kn) { + currentKey = ffjtRichHeight + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'w': + + if bytes.Equal(ffjKeyRichWidth, kn) { + currentKey = ffjtRichWidth + state = fflib.FFParse_want_colon + goto mainparse + } + + } + + if fflib.SimpleLetterEqualFold(ffjKeyRichHeight, kn) { + currentKey = ffjtRichHeight + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.SimpleLetterEqualFold(ffjKeyRichWidth, kn) { + currentKey = ffjtRichWidth + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.SimpleLetterEqualFold(ffjKeyRichHTML, kn) { + currentKey = ffjtRichHTML + state = fflib.FFParse_want_colon + goto mainparse + } + + currentKey = ffjtRichnosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } + + case fflib.FFParse_want_colon: + if tok != fflib.FFTok_colon { + wantedTok = fflib.FFTok_colon + goto wrongtokenerror + } + state = fflib.FFParse_want_value + continue + case fflib.FFParse_want_value: + + if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null { + switch currentKey { + + case ffjtRichHTML: + goto handle_HTML + + case ffjtRichWidth: + goto handle_Width + + case ffjtRichHeight: + goto handle_Height + + case ffjtRichnosuchkey: + err = fs.SkipField(tok) + if err != nil { + return fs.WrapErr(err) + } + state = fflib.FFParse_after_value + goto mainparse + } + } else { + goto wantedvalue + } + } + } + +handle_HTML: + + /* handler: j.HTML type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.HTML = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Width: + + /* handler: j.Width type=int kind=int quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + j.Width = int(tval) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Height: + + /* handler: j.Height type=int kind=int quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + j.Height = int(tval) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +wantedvalue: + return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) +wrongtokenerror: + return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String())) +tokerror: + if fs.BigError != nil { + return fs.WrapErr(fs.BigError) + } + err = fs.Error.ToError() + if err != nil { + return fs.WrapErr(err) + } + panic("ffjson-generated: unreachable, please report bug.") +done: + + return nil +} + +// MarshalJSON marshal bytes to json - template +func (j *Video) MarshalJSON() ([]byte, error) { + var buf fflib.Buffer + if j == nil { + buf.WriteString("null") + return buf.Bytes(), nil + } + err := j.MarshalJSONBuf(&buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// MarshalJSONBuf marshal buff to json - template +func (j *Video) MarshalJSONBuf(buf fflib.EncodingBuffer) error { + if j == nil { + buf.WriteString("null") + return nil + } + var err error + var obj []byte + _ = obj + _ = err + buf.WriteString(`{"html":`) + fflib.WriteJsonString(buf, string(j.HTML)) + buf.WriteString(`,"width":`) + fflib.FormatBits2(buf, uint64(j.Width), 10, j.Width < 0) + buf.WriteString(`,"height":`) + fflib.FormatBits2(buf, uint64(j.Height), 10, j.Height < 0) + buf.WriteByte('}') + return nil +} + +const ( + ffjtVideobase = iota + ffjtVideonosuchkey + + ffjtVideoHTML + + ffjtVideoWidth + + ffjtVideoHeight +) + +var ffjKeyVideoHTML = []byte("html") + +var ffjKeyVideoWidth = []byte("width") + +var ffjKeyVideoHeight = []byte("height") + +// UnmarshalJSON umarshall json - template of ffjson +func (j *Video) UnmarshalJSON(input []byte) error { + fs := fflib.NewFFLexer(input) + return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start) +} + +// UnmarshalJSONFFLexer fast json unmarshall - template ffjson +func (j *Video) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error { + var err error + currentKey := ffjtVideobase + _ = currentKey + tok := fflib.FFTok_init + wantedTok := fflib.FFTok_init + +mainparse: + for { + tok = fs.Scan() + // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state)) + if tok == fflib.FFTok_error { + goto tokerror + } + + switch state { + + case fflib.FFParse_map_start: + if tok != fflib.FFTok_left_bracket { + wantedTok = fflib.FFTok_left_bracket + goto wrongtokenerror + } + state = fflib.FFParse_want_key + continue + + case fflib.FFParse_after_value: + if tok == fflib.FFTok_comma { + state = fflib.FFParse_want_key + } else if tok == fflib.FFTok_right_bracket { + goto done + } else { + wantedTok = fflib.FFTok_comma + goto wrongtokenerror + } + + case fflib.FFParse_want_key: + // json {} ended. goto exit. woo. + if tok == fflib.FFTok_right_bracket { + goto done + } + if tok != fflib.FFTok_string { + wantedTok = fflib.FFTok_string + goto wrongtokenerror + } + + kn := fs.Output.Bytes() + if len(kn) <= 0 { + // "" case. hrm. + currentKey = ffjtVideonosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } else { + switch kn[0] { + + case 'h': + + if bytes.Equal(ffjKeyVideoHTML, kn) { + currentKey = ffjtVideoHTML + state = fflib.FFParse_want_colon + goto mainparse + + } else if bytes.Equal(ffjKeyVideoHeight, kn) { + currentKey = ffjtVideoHeight + state = fflib.FFParse_want_colon + goto mainparse + } + + case 'w': + + if bytes.Equal(ffjKeyVideoWidth, kn) { + currentKey = ffjtVideoWidth + state = fflib.FFParse_want_colon + goto mainparse + } + + } + + if fflib.SimpleLetterEqualFold(ffjKeyVideoHeight, kn) { + currentKey = ffjtVideoHeight + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.SimpleLetterEqualFold(ffjKeyVideoWidth, kn) { + currentKey = ffjtVideoWidth + state = fflib.FFParse_want_colon + goto mainparse + } + + if fflib.SimpleLetterEqualFold(ffjKeyVideoHTML, kn) { + currentKey = ffjtVideoHTML + state = fflib.FFParse_want_colon + goto mainparse + } + + currentKey = ffjtVideonosuchkey + state = fflib.FFParse_want_colon + goto mainparse + } + + case fflib.FFParse_want_colon: + if tok != fflib.FFTok_colon { + wantedTok = fflib.FFTok_colon + goto wrongtokenerror + } + state = fflib.FFParse_want_value + continue + case fflib.FFParse_want_value: + + if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null { + switch currentKey { + + case ffjtVideoHTML: + goto handle_HTML + + case ffjtVideoWidth: + goto handle_Width + + case ffjtVideoHeight: + goto handle_Height + + case ffjtVideonosuchkey: + err = fs.SkipField(tok) + if err != nil { + return fs.WrapErr(err) + } + state = fflib.FFParse_after_value + goto mainparse + } + } else { + goto wantedvalue + } + } + } + +handle_HTML: + + /* handler: j.HTML type=string kind=string quoted=false*/ + + { + + { + if tok != fflib.FFTok_string && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) + } + } + + if tok == fflib.FFTok_null { + + } else { + + outBuf := fs.Output.Bytes() + + j.HTML = string(string(outBuf)) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Width: + + /* handler: j.Width type=int kind=int quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + j.Width = int(tval) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +handle_Height: + + /* handler: j.Height type=int kind=int quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for int", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + j.Height = int(tval) + + } + } + + state = fflib.FFParse_after_value + goto mainparse + +wantedvalue: + return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) +wrongtokenerror: + return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String())) +tokerror: + if fs.BigError != nil { + return fs.WrapErr(fs.BigError) + } + err = fs.Error.ToError() + if err != nil { + return fs.WrapErr(err) + } + panic("ffjson-generated: unreachable, please report bug.") +done: + + return nil +}