From 9bda7f56f545736e3e1904a219c567deec041956 Mon Sep 17 00:00:00 2001
From: APAHE <kiselev@gismeteo.ru>
Date: Tue, 13 Feb 2024 19:51:26 +0300
Subject: [PATCH 01/10] add easyjson

---
 .idea/.gitignore                     |    8 +
 README.md                            |    2 +-
 banner_easyjson.go                   |   16 +
 bid_easyjson.go                      |  403 +++
 bidrequest.go                        |   11 +-
 bidrequest_easyjson.go               | 4542 ++++++++++++++++++++++++++
 bidresponse_easyjson.go              |   16 +
 content_easyjson.go                  |  687 ++++
 device_easyjson.go                   |  488 +++
 doc_easyjson.go                      |   18 +
 go.mod                               |    2 +
 go.sum                               |    4 +
 impression_easyjson.go               | 1113 +++++++
 inventory_easyjson.go                | 1147 +++++++
 native/request/asset_easyjson.go     |  571 ++++
 native/request/data_easyjson.go      |  101 +
 native/request/image_easyjson.go     |  190 ++
 native/request/request_easyjson.go   |  223 ++
 native/request/title_easyjson.go     |   94 +
 native/request/video_easyjson.go     |  197 ++
 native/response/asset_easyjson.go    |  509 +++
 native/response/data_easyjson.go     |  107 +
 native/response/image_easyjson.go    |  124 +
 native/response/link_easyjson.go     |  138 +
 native/response/response_easyjson.go |  192 ++
 native/response/title_easyjson.go    |   94 +
 native/response/video_easyjson.go    |   85 +
 native_easyjson.go                   |  177 +
 numbers_easyjson.go                  |   18 +
 openrtb_easyjson.go                  | 1161 +++++++
 quantity_easyjson.go                 |   16 +
 seatbid_easyjson.go                  |  140 +
 source_easyjson.go                   |   16 +
 sua_easyjson.go                      |  325 ++
 video_easyjson.go                    |   16 +
 35 files changed, 12948 insertions(+), 3 deletions(-)
 create mode 100644 .idea/.gitignore
 create mode 100644 banner_easyjson.go
 create mode 100644 bid_easyjson.go
 create mode 100644 bidrequest_easyjson.go
 create mode 100644 bidresponse_easyjson.go
 create mode 100644 content_easyjson.go
 create mode 100644 device_easyjson.go
 create mode 100644 doc_easyjson.go
 create mode 100644 impression_easyjson.go
 create mode 100644 inventory_easyjson.go
 create mode 100644 native/request/asset_easyjson.go
 create mode 100644 native/request/data_easyjson.go
 create mode 100644 native/request/image_easyjson.go
 create mode 100644 native/request/request_easyjson.go
 create mode 100644 native/request/title_easyjson.go
 create mode 100644 native/request/video_easyjson.go
 create mode 100644 native/response/asset_easyjson.go
 create mode 100644 native/response/data_easyjson.go
 create mode 100644 native/response/image_easyjson.go
 create mode 100644 native/response/link_easyjson.go
 create mode 100644 native/response/response_easyjson.go
 create mode 100644 native/response/title_easyjson.go
 create mode 100644 native/response/video_easyjson.go
 create mode 100644 native_easyjson.go
 create mode 100644 numbers_easyjson.go
 create mode 100644 openrtb_easyjson.go
 create mode 100644 quantity_easyjson.go
 create mode 100644 seatbid_easyjson.go
 create mode 100644 source_easyjson.go
 create mode 100644 sua_easyjson.go
 create mode 100644 video_easyjson.go

diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/README.md b/README.md
index 73cb6be..c891844 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ Requires Go 1.8+ for proper `json.RawMessage` marshaling.
 To install, use `go get`:
 
 ```shell
-go get github.com/bsm/openrtb/v3
+go get github.com/octoclick/openrtb-easyjson
 ```
 
 ## Usage
diff --git a/banner_easyjson.go b/banner_easyjson.go
new file mode 100644
index 0000000..f421dc0
--- /dev/null
+++ b/banner_easyjson.go
@@ -0,0 +1,16 @@
+// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
+// compilable during generation.
+
+package  openrtb
+
+import (
+  "github.com/mailru/easyjson/jwriter"
+  "github.com/mailru/easyjson/jlexer"
+)
+
+func ( Banner ) MarshalJSON() ([]byte, error) { return nil, nil }
+func (* Banner ) UnmarshalJSON([]byte) error { return nil }
+func ( Banner ) MarshalEasyJSON(w *jwriter.Writer) {}
+func (* Banner ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
+
+type EasyJSON_exporter_Banner *Banner
diff --git a/bid_easyjson.go b/bid_easyjson.go
new file mode 100644
index 0000000..103d630
--- /dev/null
+++ b/bid_easyjson.go
@@ -0,0 +1,403 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson31527abDecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *Bid) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "impid":
+			out.ImpID = string(in.String())
+		case "price":
+			out.Price = float64(in.Float64())
+		case "adid":
+			out.AdID = string(in.String())
+		case "nurl":
+			out.NoticeURL = string(in.String())
+		case "burl":
+			out.BillingURL = string(in.String())
+		case "lurl":
+			out.LossURL = string(in.String())
+		case "adm":
+			out.AdMarkup = string(in.String())
+		case "adomain":
+			if in.IsNull() {
+				in.Skip()
+				out.AdvDomains = nil
+			} else {
+				in.Delim('[')
+				if out.AdvDomains == nil {
+					if !in.IsDelim(']') {
+						out.AdvDomains = make([]string, 0, 4)
+					} else {
+						out.AdvDomains = []string{}
+					}
+				} else {
+					out.AdvDomains = (out.AdvDomains)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 string
+					v1 = string(in.String())
+					out.AdvDomains = append(out.AdvDomains, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "bundle":
+			out.Bundle = string(in.String())
+		case "iurl":
+			out.ImageURL = string(in.String())
+		case "cid":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.CampaignID).UnmarshalJSON(data))
+			}
+		case "crid":
+			out.CreativeID = string(in.String())
+		case "tactic":
+			out.Tactic = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v2 ContentCategory
+					v2 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v2)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "attr":
+			if in.IsNull() {
+				in.Skip()
+				out.Attrs = nil
+			} else {
+				in.Delim('[')
+				if out.Attrs == nil {
+					if !in.IsDelim(']') {
+						out.Attrs = make([]CreativeAttribute, 0, 8)
+					} else {
+						out.Attrs = []CreativeAttribute{}
+					}
+				} else {
+					out.Attrs = (out.Attrs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v3 CreativeAttribute
+					v3 = CreativeAttribute(in.Int())
+					out.Attrs = append(out.Attrs, v3)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "api":
+			out.API = APIFramework(in.Int())
+		case "protocol":
+			out.Protocol = Protocol(in.Int())
+		case "qagmediarating":
+			out.MediaRating = IQGRating(in.Int())
+		case "language":
+			out.Language = string(in.String())
+		case "dealid":
+			out.DealID = string(in.String())
+		case "w":
+			out.Width = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "wratio":
+			out.WidthRatio = int(in.Int())
+		case "hratio":
+			out.HeightRatio = int(in.Int())
+		case "apis":
+			out.APIS = APIFramework(in.Int())
+		case "langb":
+			out.LangB = string(in.String())
+		case "dur":
+			out.Duration = int(in.Int())
+		case "mtype":
+			out.MarkupType = MarkupType(in.Int())
+		case "slotinpod":
+			out.SlotInPod = SlotPositionInPod(in.Int())
+		case "cattax":
+			out.CategoryTaxonomy = CategoryTaxonomy(in.Int())
+		case "exp":
+			out.Exp = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson31527abEncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in Bid) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"id\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	{
+		const prefix string = ",\"impid\":"
+		out.RawString(prefix)
+		out.String(string(in.ImpID))
+	}
+	{
+		const prefix string = ",\"price\":"
+		out.RawString(prefix)
+		out.Float64(float64(in.Price))
+	}
+	if in.AdID != "" {
+		const prefix string = ",\"adid\":"
+		out.RawString(prefix)
+		out.String(string(in.AdID))
+	}
+	if in.NoticeURL != "" {
+		const prefix string = ",\"nurl\":"
+		out.RawString(prefix)
+		out.String(string(in.NoticeURL))
+	}
+	if in.BillingURL != "" {
+		const prefix string = ",\"burl\":"
+		out.RawString(prefix)
+		out.String(string(in.BillingURL))
+	}
+	if in.LossURL != "" {
+		const prefix string = ",\"lurl\":"
+		out.RawString(prefix)
+		out.String(string(in.LossURL))
+	}
+	if in.AdMarkup != "" {
+		const prefix string = ",\"adm\":"
+		out.RawString(prefix)
+		out.String(string(in.AdMarkup))
+	}
+	if len(in.AdvDomains) != 0 {
+		const prefix string = ",\"adomain\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v4, v5 := range in.AdvDomains {
+				if v4 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v5))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Bundle != "" {
+		const prefix string = ",\"bundle\":"
+		out.RawString(prefix)
+		out.String(string(in.Bundle))
+	}
+	if in.ImageURL != "" {
+		const prefix string = ",\"iurl\":"
+		out.RawString(prefix)
+		out.String(string(in.ImageURL))
+	}
+	if in.CampaignID != "" {
+		const prefix string = ",\"cid\":"
+		out.RawString(prefix)
+		out.String(string(in.CampaignID))
+	}
+	if in.CreativeID != "" {
+		const prefix string = ",\"crid\":"
+		out.RawString(prefix)
+		out.String(string(in.CreativeID))
+	}
+	if in.Tactic != "" {
+		const prefix string = ",\"tactic\":"
+		out.RawString(prefix)
+		out.String(string(in.Tactic))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v6, v7 := range in.Categories {
+				if v6 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v7))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Attrs) != 0 {
+		const prefix string = ",\"attr\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v8, v9 := range in.Attrs {
+				if v8 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v9))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.API != 0 {
+		const prefix string = ",\"api\":"
+		out.RawString(prefix)
+		out.Int(int(in.API))
+	}
+	if in.Protocol != 0 {
+		const prefix string = ",\"protocol\":"
+		out.RawString(prefix)
+		out.Int(int(in.Protocol))
+	}
+	if in.MediaRating != 0 {
+		const prefix string = ",\"qagmediarating\":"
+		out.RawString(prefix)
+		out.Int(int(in.MediaRating))
+	}
+	if in.Language != "" {
+		const prefix string = ",\"language\":"
+		out.RawString(prefix)
+		out.String(string(in.Language))
+	}
+	if in.DealID != "" {
+		const prefix string = ",\"dealid\":"
+		out.RawString(prefix)
+		out.String(string(in.DealID))
+	}
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		out.RawString(prefix)
+		out.Int(int(in.Width))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		out.RawString(prefix)
+		out.Int(int(in.Height))
+	}
+	if in.WidthRatio != 0 {
+		const prefix string = ",\"wratio\":"
+		out.RawString(prefix)
+		out.Int(int(in.WidthRatio))
+	}
+	if in.HeightRatio != 0 {
+		const prefix string = ",\"hratio\":"
+		out.RawString(prefix)
+		out.Int(int(in.HeightRatio))
+	}
+	if in.APIS != 0 {
+		const prefix string = ",\"apis\":"
+		out.RawString(prefix)
+		out.Int(int(in.APIS))
+	}
+	if in.LangB != "" {
+		const prefix string = ",\"langb\":"
+		out.RawString(prefix)
+		out.String(string(in.LangB))
+	}
+	if in.Duration != 0 {
+		const prefix string = ",\"dur\":"
+		out.RawString(prefix)
+		out.Int(int(in.Duration))
+	}
+	if in.MarkupType != 0 {
+		const prefix string = ",\"mtype\":"
+		out.RawString(prefix)
+		out.Int(int(in.MarkupType))
+	}
+	if in.SlotInPod != 0 {
+		const prefix string = ",\"slotinpod\":"
+		out.RawString(prefix)
+		out.Int(int(in.SlotInPod))
+	}
+	if in.CategoryTaxonomy != 0 {
+		const prefix string = ",\"cattax\":"
+		out.RawString(prefix)
+		out.Int(int(in.CategoryTaxonomy))
+	}
+	if in.Exp != 0 {
+		const prefix string = ",\"exp\":"
+		out.RawString(prefix)
+		out.Int(int(in.Exp))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Bid) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson31527abEncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Bid) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson31527abEncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Bid) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson31527abDecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Bid) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson31527abDecodeGithubComBsmOpenrtbV3(l, v)
+}
diff --git a/bidrequest.go b/bidrequest.go
index 48bfc65..73ad591 100644
--- a/bidrequest.go
+++ b/bidrequest.go
@@ -3,6 +3,7 @@ package openrtb
 import (
 	"encoding/json"
 	"errors"
+	"net"
 )
 
 // Validation errors
@@ -10,6 +11,8 @@ var (
 	ErrInvalidReqNoID     = errors.New("openrtb: request ID missing")
 	ErrInvalidReqNoImps   = errors.New("openrtb: request has no impressions")
 	ErrInvalidReqMultiInv = errors.New("openrtb: request has multiple inventory sources") // has site and app
+	ErrInvalidSitePage    = errors.New("openrtb: request hasn't site.page")
+	ErrInvalidDeviceIP    = errors.New("openrtb: request has invalid device.ip")
 )
 
 // BidRequest is the top-level bid request object contains a globally unique bid request or auction ID.  This "id"
@@ -48,13 +51,17 @@ func (req *BidRequest) Validate() error {
 	} else if req.Site != nil && req.App != nil {
 		return ErrInvalidReqMultiInv
 	}
-
+	if req.Site != nil && len(req.Site.Page) == 0 {
+		return ErrInvalidSitePage
+	}
+	if net.ParseIP(req.Device.IP) == nil {
+		return ErrInvalidDeviceIP
+	}
 	for i := range req.Impressions {
 		imp := req.Impressions[i]
 		if err := (&imp).Validate(); err != nil {
 			return err
 		}
 	}
-
 	return nil
 }
diff --git a/bidrequest_easyjson.go b/bidrequest_easyjson.go
new file mode 100644
index 0000000..16f33c2
--- /dev/null
+++ b/bidrequest_easyjson.go
@@ -0,0 +1,4542 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *BidRequest) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "imp":
+			if in.IsNull() {
+				in.Skip()
+				out.Impressions = nil
+			} else {
+				in.Delim('[')
+				if out.Impressions == nil {
+					if !in.IsDelim(']') {
+						out.Impressions = make([]Impression, 0, 0)
+					} else {
+						out.Impressions = []Impression{}
+					}
+				} else {
+					out.Impressions = (out.Impressions)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 Impression
+					easyjson89fe9b30DecodeGithubComBsmOpenrtbV31(in, &v1)
+					out.Impressions = append(out.Impressions, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "site":
+			if in.IsNull() {
+				in.Skip()
+				out.Site = nil
+			} else {
+				if out.Site == nil {
+					out.Site = new(Site)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV32(in, out.Site)
+			}
+		case "app":
+			if in.IsNull() {
+				in.Skip()
+				out.App = nil
+			} else {
+				if out.App == nil {
+					out.App = new(App)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV33(in, out.App)
+			}
+		case "device":
+			if in.IsNull() {
+				in.Skip()
+				out.Device = nil
+			} else {
+				if out.Device == nil {
+					out.Device = new(Device)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV34(in, out.Device)
+			}
+		case "user":
+			if in.IsNull() {
+				in.Skip()
+				out.User = nil
+			} else {
+				if out.User == nil {
+					out.User = new(User)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV35(in, out.User)
+			}
+		case "test":
+			out.Test = int(in.Int())
+		case "at":
+			out.AuctionType = int(in.Int())
+		case "tmax":
+			out.TimeMax = int(in.Int())
+		case "wseat":
+			if in.IsNull() {
+				in.Skip()
+				out.Seats = nil
+			} else {
+				in.Delim('[')
+				if out.Seats == nil {
+					if !in.IsDelim(']') {
+						out.Seats = make([]string, 0, 4)
+					} else {
+						out.Seats = []string{}
+					}
+				} else {
+					out.Seats = (out.Seats)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v2 string
+					v2 = string(in.String())
+					out.Seats = append(out.Seats, v2)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "bseat":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedSeats = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedSeats == nil {
+					if !in.IsDelim(']') {
+						out.BlockedSeats = make([]string, 0, 4)
+					} else {
+						out.BlockedSeats = []string{}
+					}
+				} else {
+					out.BlockedSeats = (out.BlockedSeats)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v3 string
+					v3 = string(in.String())
+					out.BlockedSeats = append(out.BlockedSeats, v3)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "wlang":
+			if in.IsNull() {
+				in.Skip()
+				out.Languages = nil
+			} else {
+				in.Delim('[')
+				if out.Languages == nil {
+					if !in.IsDelim(']') {
+						out.Languages = make([]string, 0, 4)
+					} else {
+						out.Languages = []string{}
+					}
+				} else {
+					out.Languages = (out.Languages)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v4 string
+					v4 = string(in.String())
+					out.Languages = append(out.Languages, v4)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "wlangb":
+			if in.IsNull() {
+				in.Skip()
+				out.LanguagesB = nil
+			} else {
+				in.Delim('[')
+				if out.LanguagesB == nil {
+					if !in.IsDelim(']') {
+						out.LanguagesB = make([]string, 0, 4)
+					} else {
+						out.LanguagesB = []string{}
+					}
+				} else {
+					out.LanguagesB = (out.LanguagesB)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v5 string
+					v5 = string(in.String())
+					out.LanguagesB = append(out.LanguagesB, v5)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "allimps":
+			out.AllImpressions = int(in.Int())
+		case "cur":
+			if in.IsNull() {
+				in.Skip()
+				out.Currencies = nil
+			} else {
+				in.Delim('[')
+				if out.Currencies == nil {
+					if !in.IsDelim(']') {
+						out.Currencies = make([]string, 0, 4)
+					} else {
+						out.Currencies = []string{}
+					}
+				} else {
+					out.Currencies = (out.Currencies)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v6 string
+					v6 = string(in.String())
+					out.Currencies = append(out.Currencies, v6)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "bcat":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedCategories = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedCategories == nil {
+					if !in.IsDelim(']') {
+						out.BlockedCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.BlockedCategories = []ContentCategory{}
+					}
+				} else {
+					out.BlockedCategories = (out.BlockedCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v7 ContentCategory
+					v7 = ContentCategory(in.String())
+					out.BlockedCategories = append(out.BlockedCategories, v7)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "badv":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedAdvDomains = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedAdvDomains == nil {
+					if !in.IsDelim(']') {
+						out.BlockedAdvDomains = make([]string, 0, 4)
+					} else {
+						out.BlockedAdvDomains = []string{}
+					}
+				} else {
+					out.BlockedAdvDomains = (out.BlockedAdvDomains)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v8 string
+					v8 = string(in.String())
+					out.BlockedAdvDomains = append(out.BlockedAdvDomains, v8)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "bapp":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedApps = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedApps == nil {
+					if !in.IsDelim(']') {
+						out.BlockedApps = make([]string, 0, 4)
+					} else {
+						out.BlockedApps = []string{}
+					}
+				} else {
+					out.BlockedApps = (out.BlockedApps)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v9 string
+					v9 = string(in.String())
+					out.BlockedApps = append(out.BlockedApps, v9)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "source":
+			if in.IsNull() {
+				in.Skip()
+				out.Source = nil
+			} else {
+				if out.Source == nil {
+					out.Source = new(Source)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV36(in, out.Source)
+			}
+		case "regs":
+			if in.IsNull() {
+				in.Skip()
+				out.Regulations = nil
+			} else {
+				if out.Regulations == nil {
+					out.Regulations = new(Regulations)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV37(in, out.Regulations)
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in BidRequest) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"id\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if len(in.Impressions) != 0 {
+		const prefix string = ",\"imp\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v10, v11 := range in.Impressions {
+				if v10 > 0 {
+					out.RawByte(',')
+				}
+				easyjson89fe9b30EncodeGithubComBsmOpenrtbV31(out, v11)
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Site != nil {
+		const prefix string = ",\"site\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV32(out, *in.Site)
+	}
+	if in.App != nil {
+		const prefix string = ",\"app\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV33(out, *in.App)
+	}
+	if in.Device != nil {
+		const prefix string = ",\"device\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV34(out, *in.Device)
+	}
+	if in.User != nil {
+		const prefix string = ",\"user\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV35(out, *in.User)
+	}
+	if in.Test != 0 {
+		const prefix string = ",\"test\":"
+		out.RawString(prefix)
+		out.Int(int(in.Test))
+	}
+	{
+		const prefix string = ",\"at\":"
+		out.RawString(prefix)
+		out.Int(int(in.AuctionType))
+	}
+	if in.TimeMax != 0 {
+		const prefix string = ",\"tmax\":"
+		out.RawString(prefix)
+		out.Int(int(in.TimeMax))
+	}
+	if len(in.Seats) != 0 {
+		const prefix string = ",\"wseat\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v12, v13 := range in.Seats {
+				if v12 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v13))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.BlockedSeats) != 0 {
+		const prefix string = ",\"bseat\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v14, v15 := range in.BlockedSeats {
+				if v14 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v15))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Languages) != 0 {
+		const prefix string = ",\"wlang\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v16, v17 := range in.Languages {
+				if v16 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v17))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.LanguagesB) != 0 {
+		const prefix string = ",\"wlangb\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v18, v19 := range in.LanguagesB {
+				if v18 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v19))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.AllImpressions != 0 {
+		const prefix string = ",\"allimps\":"
+		out.RawString(prefix)
+		out.Int(int(in.AllImpressions))
+	}
+	if len(in.Currencies) != 0 {
+		const prefix string = ",\"cur\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v20, v21 := range in.Currencies {
+				if v20 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v21))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.BlockedCategories) != 0 {
+		const prefix string = ",\"bcat\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v22, v23 := range in.BlockedCategories {
+				if v22 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v23))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.BlockedAdvDomains) != 0 {
+		const prefix string = ",\"badv\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v24, v25 := range in.BlockedAdvDomains {
+				if v24 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v25))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.BlockedApps) != 0 {
+		const prefix string = ",\"bapp\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v26, v27 := range in.BlockedApps {
+				if v26 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v27))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Source != nil {
+		const prefix string = ",\"source\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV36(out, *in.Source)
+	}
+	if in.Regulations != nil {
+		const prefix string = ",\"regs\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV37(out, *in.Regulations)
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v BidRequest) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson89fe9b30EncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v BidRequest) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson89fe9b30EncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *BidRequest) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson89fe9b30DecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *BidRequest) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson89fe9b30DecodeGithubComBsmOpenrtbV3(l, v)
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV37(in *jlexer.Lexer, out *Regulations) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "coppa":
+			out.COPPA = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV37(out *jwriter.Writer, in Regulations) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.COPPA != 0 {
+		const prefix string = ",\"coppa\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.COPPA))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV36(in *jlexer.Lexer, out *Source) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "fd":
+			out.FinalSaleDecision = int(in.Int())
+		case "tid":
+			out.TransactionID = string(in.String())
+		case "pchain":
+			out.PaymentChain = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV36(out *jwriter.Writer, in Source) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.FinalSaleDecision != 0 {
+		const prefix string = ",\"fd\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.FinalSaleDecision))
+	}
+	if in.TransactionID != "" {
+		const prefix string = ",\"tid\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.TransactionID))
+	}
+	if in.PaymentChain != "" {
+		const prefix string = ",\"pchain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.PaymentChain))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV35(in *jlexer.Lexer, out *User) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "buyerid":
+			out.BuyerID = string(in.String())
+		case "buyeruid":
+			out.BuyerUID = string(in.String())
+		case "yob":
+			out.YearOfBirth = int(in.Int())
+		case "gender":
+			out.Gender = string(in.String())
+		case "keywords":
+			out.Keywords = string(in.String())
+		case "customdata":
+			out.CustomData = string(in.String())
+		case "geo":
+			if in.IsNull() {
+				in.Skip()
+				out.Geo = nil
+			} else {
+				if out.Geo == nil {
+					out.Geo = new(Geo)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV38(in, out.Geo)
+			}
+		case "data":
+			if in.IsNull() {
+				in.Skip()
+				out.Data = nil
+			} else {
+				in.Delim('[')
+				if out.Data == nil {
+					if !in.IsDelim(']') {
+						out.Data = make([]Data, 0, 0)
+					} else {
+						out.Data = []Data{}
+					}
+				} else {
+					out.Data = (out.Data)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v28 Data
+					easyjson89fe9b30DecodeGithubComBsmOpenrtbV39(in, &v28)
+					out.Data = append(out.Data, v28)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV35(out *jwriter.Writer, in User) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.BuyerID != "" {
+		const prefix string = ",\"buyerid\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.BuyerID))
+	}
+	if in.BuyerUID != "" {
+		const prefix string = ",\"buyeruid\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.BuyerUID))
+	}
+	if in.YearOfBirth != 0 {
+		const prefix string = ",\"yob\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.YearOfBirth))
+	}
+	if in.Gender != "" {
+		const prefix string = ",\"gender\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Gender))
+	}
+	if in.Keywords != "" {
+		const prefix string = ",\"keywords\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Keywords))
+	}
+	if in.CustomData != "" {
+		const prefix string = ",\"customdata\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.CustomData))
+	}
+	if in.Geo != nil {
+		const prefix string = ",\"geo\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV38(out, *in.Geo)
+	}
+	if len(in.Data) != 0 {
+		const prefix string = ",\"data\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v29, v30 := range in.Data {
+				if v29 > 0 {
+					out.RawByte(',')
+				}
+				easyjson89fe9b30EncodeGithubComBsmOpenrtbV39(out, v30)
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV39(in *jlexer.Lexer, out *Data) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "segment":
+			if in.IsNull() {
+				in.Skip()
+				out.Segment = nil
+			} else {
+				in.Delim('[')
+				if out.Segment == nil {
+					if !in.IsDelim(']') {
+						out.Segment = make([]Segment, 0, 0)
+					} else {
+						out.Segment = []Segment{}
+					}
+				} else {
+					out.Segment = (out.Segment)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v31 Segment
+					easyjson89fe9b30DecodeGithubComBsmOpenrtbV310(in, &v31)
+					out.Segment = append(out.Segment, v31)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV39(out *jwriter.Writer, in Data) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if len(in.Segment) != 0 {
+		const prefix string = ",\"segment\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v32, v33 := range in.Segment {
+				if v32 > 0 {
+					out.RawByte(',')
+				}
+				easyjson89fe9b30EncodeGithubComBsmOpenrtbV310(out, v33)
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV310(in *jlexer.Lexer, out *Segment) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "value":
+			out.Value = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV310(out *jwriter.Writer, in Segment) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if in.Value != "" {
+		const prefix string = ",\"value\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Value))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV38(in *jlexer.Lexer, out *Geo) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "lat":
+			out.Latitude = float64(in.Float64())
+		case "lon":
+			out.Longitude = float64(in.Float64())
+		case "type":
+			out.Type = LocationType(in.Int())
+		case "accuracy":
+			out.Accuracy = int(in.Int())
+		case "lastfix":
+			out.LastFix = int(in.Int())
+		case "ipservice":
+			out.IPService = IPLocation(in.Int())
+		case "country":
+			out.Country = string(in.String())
+		case "region":
+			out.Region = string(in.String())
+		case "regionFIPS104":
+			out.RegionFIPS104 = string(in.String())
+		case "metro":
+			out.Metro = string(in.String())
+		case "city":
+			out.City = string(in.String())
+		case "zip":
+			out.ZIP = string(in.String())
+		case "utcoffset":
+			out.UTCOffset = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV38(out *jwriter.Writer, in Geo) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Latitude != 0 {
+		const prefix string = ",\"lat\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Float64(float64(in.Latitude))
+	}
+	if in.Longitude != 0 {
+		const prefix string = ",\"lon\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Float64(float64(in.Longitude))
+	}
+	if in.Type != 0 {
+		const prefix string = ",\"type\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Type))
+	}
+	if in.Accuracy != 0 {
+		const prefix string = ",\"accuracy\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Accuracy))
+	}
+	if in.LastFix != 0 {
+		const prefix string = ",\"lastfix\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.LastFix))
+	}
+	if in.IPService != 0 {
+		const prefix string = ",\"ipservice\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.IPService))
+	}
+	if in.Country != "" {
+		const prefix string = ",\"country\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Country))
+	}
+	if in.Region != "" {
+		const prefix string = ",\"region\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Region))
+	}
+	if in.RegionFIPS104 != "" {
+		const prefix string = ",\"regionFIPS104\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.RegionFIPS104))
+	}
+	if in.Metro != "" {
+		const prefix string = ",\"metro\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Metro))
+	}
+	if in.City != "" {
+		const prefix string = ",\"city\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.City))
+	}
+	if in.ZIP != "" {
+		const prefix string = ",\"zip\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ZIP))
+	}
+	if in.UTCOffset != 0 {
+		const prefix string = ",\"utcoffset\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.UTCOffset))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV34(in *jlexer.Lexer, out *Device) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "ua":
+			out.UA = string(in.String())
+		case "sua":
+			if in.IsNull() {
+				in.Skip()
+				out.Sua = nil
+			} else {
+				if out.Sua == nil {
+					out.Sua = new(UserAgent)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV311(in, out.Sua)
+			}
+		case "geo":
+			if in.IsNull() {
+				in.Skip()
+				out.Geo = nil
+			} else {
+				if out.Geo == nil {
+					out.Geo = new(Geo)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV38(in, out.Geo)
+			}
+		case "dnt":
+			out.DNT = int(in.Int())
+		case "lmt":
+			out.LMT = int(in.Int())
+		case "ip":
+			out.IP = string(in.String())
+		case "ipv6":
+			out.IPv6 = string(in.String())
+		case "devicetype":
+			out.DeviceType = DeviceType(in.Int())
+		case "make":
+			out.Make = string(in.String())
+		case "model":
+			out.Model = string(in.String())
+		case "os":
+			out.OS = string(in.String())
+		case "osv":
+			out.OSVersion = string(in.String())
+		case "hwv":
+			out.HWVersion = string(in.String())
+		case "h":
+			out.Height = int(in.Int())
+		case "w":
+			out.Width = int(in.Int())
+		case "ppi":
+			out.PPI = int(in.Int())
+		case "pxratio":
+			out.PixelRatio = float64(in.Float64())
+		case "js":
+			out.JS = int(in.Int())
+		case "geofetch":
+			out.GeoFetch = int(in.Int())
+		case "flashver":
+			out.FlashVersion = string(in.String())
+		case "language":
+			out.Language = string(in.String())
+		case "langb":
+			out.LanguageB = string(in.String())
+		case "carrier":
+			out.Carrier = string(in.String())
+		case "mccmnc":
+			out.MCCMNC = string(in.String())
+		case "connectiontype":
+			out.ConnType = ConnType(in.Int())
+		case "ifa":
+			out.IFA = string(in.String())
+		case "didsha1":
+			out.IDSHA1 = string(in.String())
+		case "didmd5":
+			out.IDMD5 = string(in.String())
+		case "dpidsha1":
+			out.PIDSHA1 = string(in.String())
+		case "dpidmd5":
+			out.PIDMD5 = string(in.String())
+		case "macsha1":
+			out.MacSHA1 = string(in.String())
+		case "macmd5":
+			out.MacMD5 = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV34(out *jwriter.Writer, in Device) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.UA != "" {
+		const prefix string = ",\"ua\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.UA))
+	}
+	if in.Sua != nil {
+		const prefix string = ",\"sua\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV311(out, *in.Sua)
+	}
+	if in.Geo != nil {
+		const prefix string = ",\"geo\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV38(out, *in.Geo)
+	}
+	if in.DNT != 0 {
+		const prefix string = ",\"dnt\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.DNT))
+	}
+	if in.LMT != 0 {
+		const prefix string = ",\"lmt\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.LMT))
+	}
+	if in.IP != "" {
+		const prefix string = ",\"ip\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IP))
+	}
+	if in.IPv6 != "" {
+		const prefix string = ",\"ipv6\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IPv6))
+	}
+	if in.DeviceType != 0 {
+		const prefix string = ",\"devicetype\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.DeviceType))
+	}
+	if in.Make != "" {
+		const prefix string = ",\"make\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Make))
+	}
+	if in.Model != "" {
+		const prefix string = ",\"model\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Model))
+	}
+	if in.OS != "" {
+		const prefix string = ",\"os\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.OS))
+	}
+	if in.OSVersion != "" {
+		const prefix string = ",\"osv\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.OSVersion))
+	}
+	if in.HWVersion != "" {
+		const prefix string = ",\"hwv\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.HWVersion))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Width))
+	}
+	if in.PPI != 0 {
+		const prefix string = ",\"ppi\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.PPI))
+	}
+	if in.PixelRatio != 0 {
+		const prefix string = ",\"pxratio\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Float64(float64(in.PixelRatio))
+	}
+	if in.JS != 0 {
+		const prefix string = ",\"js\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.JS))
+	}
+	if in.GeoFetch != 0 {
+		const prefix string = ",\"geofetch\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.GeoFetch))
+	}
+	if in.FlashVersion != "" {
+		const prefix string = ",\"flashver\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.FlashVersion))
+	}
+	if in.Language != "" {
+		const prefix string = ",\"language\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Language))
+	}
+	if in.LanguageB != "" {
+		const prefix string = ",\"langb\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.LanguageB))
+	}
+	if in.Carrier != "" {
+		const prefix string = ",\"carrier\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Carrier))
+	}
+	if in.MCCMNC != "" {
+		const prefix string = ",\"mccmnc\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.MCCMNC))
+	}
+	if in.ConnType != 0 {
+		const prefix string = ",\"connectiontype\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.ConnType))
+	}
+	if in.IFA != "" {
+		const prefix string = ",\"ifa\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IFA))
+	}
+	if in.IDSHA1 != "" {
+		const prefix string = ",\"didsha1\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IDSHA1))
+	}
+	if in.IDMD5 != "" {
+		const prefix string = ",\"didmd5\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IDMD5))
+	}
+	if in.PIDSHA1 != "" {
+		const prefix string = ",\"dpidsha1\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.PIDSHA1))
+	}
+	if in.PIDMD5 != "" {
+		const prefix string = ",\"dpidmd5\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.PIDMD5))
+	}
+	if in.MacSHA1 != "" {
+		const prefix string = ",\"macsha1\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.MacSHA1))
+	}
+	if in.MacMD5 != "" {
+		const prefix string = ",\"macmd5\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.MacMD5))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV311(in *jlexer.Lexer, out *UserAgent) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "browsers":
+			if in.IsNull() {
+				in.Skip()
+				out.Browsers = nil
+			} else {
+				in.Delim('[')
+				if out.Browsers == nil {
+					if !in.IsDelim(']') {
+						out.Browsers = make([]BrandVersion, 0, 1)
+					} else {
+						out.Browsers = []BrandVersion{}
+					}
+				} else {
+					out.Browsers = (out.Browsers)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v34 BrandVersion
+					easyjson89fe9b30DecodeGithubComBsmOpenrtbV312(in, &v34)
+					out.Browsers = append(out.Browsers, v34)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "platform":
+			easyjson89fe9b30DecodeGithubComBsmOpenrtbV312(in, &out.Platform)
+		case "mobile":
+			out.Mobile = int(in.Int())
+		case "architecture":
+			out.Architecture = string(in.String())
+		case "bitness":
+			out.Bitness = string(in.String())
+		case "model":
+			out.Model = string(in.String())
+		case "source":
+			out.Source = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV311(out *jwriter.Writer, in UserAgent) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if len(in.Browsers) != 0 {
+		const prefix string = ",\"browsers\":"
+		first = false
+		out.RawString(prefix[1:])
+		{
+			out.RawByte('[')
+			for v35, v36 := range in.Browsers {
+				if v35 > 0 {
+					out.RawByte(',')
+				}
+				easyjson89fe9b30EncodeGithubComBsmOpenrtbV312(out, v36)
+			}
+			out.RawByte(']')
+		}
+	}
+	if true {
+		const prefix string = ",\"platform\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV312(out, in.Platform)
+	}
+	if in.Mobile != 0 {
+		const prefix string = ",\"mobile\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Mobile))
+	}
+	if in.Architecture != "" {
+		const prefix string = ",\"architecture\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Architecture))
+	}
+	if in.Bitness != "" {
+		const prefix string = ",\"bitness\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Bitness))
+	}
+	if in.Model != "" {
+		const prefix string = ",\"model\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Model))
+	}
+	if in.Source != 0 {
+		const prefix string = ",\"source\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Source))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV312(in *jlexer.Lexer, out *BrandVersion) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "brand":
+			out.Brand = string(in.String())
+		case "version":
+			if in.IsNull() {
+				in.Skip()
+				out.Version = nil
+			} else {
+				in.Delim('[')
+				if out.Version == nil {
+					if !in.IsDelim(']') {
+						out.Version = make([]string, 0, 4)
+					} else {
+						out.Version = []string{}
+					}
+				} else {
+					out.Version = (out.Version)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v37 string
+					v37 = string(in.String())
+					out.Version = append(out.Version, v37)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV312(out *jwriter.Writer, in BrandVersion) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Brand != "" {
+		const prefix string = ",\"brand\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Brand))
+	}
+	if len(in.Version) != 0 {
+		const prefix string = ",\"version\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v38, v39 := range in.Version {
+				if v38 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v39))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV33(in *jlexer.Lexer, out *App) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "bundle":
+			out.Bundle = string(in.String())
+		case "storeurl":
+			out.StoreURL = string(in.String())
+		case "ver":
+			out.Version = string(in.String())
+		case "paid":
+			out.Paid = int(in.Int())
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "domain":
+			out.Domain = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v40 ContentCategory
+					v40 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v40)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "sectioncat":
+			if in.IsNull() {
+				in.Skip()
+				out.SectionCategories = nil
+			} else {
+				in.Delim('[')
+				if out.SectionCategories == nil {
+					if !in.IsDelim(']') {
+						out.SectionCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.SectionCategories = []ContentCategory{}
+					}
+				} else {
+					out.SectionCategories = (out.SectionCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v41 ContentCategory
+					v41 = ContentCategory(in.String())
+					out.SectionCategories = append(out.SectionCategories, v41)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "pagecat":
+			if in.IsNull() {
+				in.Skip()
+				out.PageCategories = nil
+			} else {
+				in.Delim('[')
+				if out.PageCategories == nil {
+					if !in.IsDelim(']') {
+						out.PageCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.PageCategories = []ContentCategory{}
+					}
+				} else {
+					out.PageCategories = (out.PageCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v42 ContentCategory
+					v42 = ContentCategory(in.String())
+					out.PageCategories = append(out.PageCategories, v42)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "privacypolicy":
+			if in.IsNull() {
+				in.Skip()
+				out.PrivacyPolicy = nil
+			} else {
+				if out.PrivacyPolicy == nil {
+					out.PrivacyPolicy = new(int)
+				}
+				*out.PrivacyPolicy = int(in.Int())
+			}
+		case "publisher":
+			if in.IsNull() {
+				in.Skip()
+				out.Publisher = nil
+			} else {
+				if out.Publisher == nil {
+					out.Publisher = new(Publisher)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV313(in, out.Publisher)
+			}
+		case "content":
+			if in.IsNull() {
+				in.Skip()
+				out.Content = nil
+			} else {
+				if out.Content == nil {
+					out.Content = new(Content)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV314(in, out.Content)
+			}
+		case "keywords":
+			out.Keywords = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV33(out *jwriter.Writer, in App) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Bundle != "" {
+		const prefix string = ",\"bundle\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Bundle))
+	}
+	if in.StoreURL != "" {
+		const prefix string = ",\"storeurl\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.StoreURL))
+	}
+	if in.Version != "" {
+		const prefix string = ",\"ver\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Version))
+	}
+	if in.Paid != 0 {
+		const prefix string = ",\"paid\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Paid))
+	}
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v43, v44 := range in.Categories {
+				if v43 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v44))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.SectionCategories) != 0 {
+		const prefix string = ",\"sectioncat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v45, v46 := range in.SectionCategories {
+				if v45 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v46))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.PageCategories) != 0 {
+		const prefix string = ",\"pagecat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v47, v48 := range in.PageCategories {
+				if v47 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v48))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.PrivacyPolicy != nil {
+		const prefix string = ",\"privacypolicy\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(*in.PrivacyPolicy))
+	}
+	if in.Publisher != nil {
+		const prefix string = ",\"publisher\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV313(out, *in.Publisher)
+	}
+	if in.Content != nil {
+		const prefix string = ",\"content\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV314(out, *in.Content)
+	}
+	if in.Keywords != "" {
+		const prefix string = ",\"keywords\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Keywords))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV314(in *jlexer.Lexer, out *Content) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "episode":
+			out.Episode = int(in.Int())
+		case "title":
+			out.Title = string(in.String())
+		case "series":
+			out.Series = string(in.String())
+		case "season":
+			out.Season = string(in.String())
+		case "artist":
+			out.Artist = string(in.String())
+		case "genre":
+			out.Genre = string(in.String())
+		case "album":
+			out.Album = string(in.String())
+		case "isrc":
+			out.ISRC = string(in.String())
+		case "producer":
+			if in.IsNull() {
+				in.Skip()
+				out.Producer = nil
+			} else {
+				if out.Producer == nil {
+					out.Producer = new(Producer)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV315(in, out.Producer)
+			}
+		case "url":
+			out.URL = string(in.String())
+		case "cattax":
+			out.CategoryTaxonomy = CategoryTaxonomy(in.Int())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v49 ContentCategory
+					v49 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v49)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "prodq":
+			out.ProductionQuality = ProductionQuality(in.Int())
+		case "videoquality":
+			out.VideoQuality = ProductionQuality(in.Int())
+		case "context":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Context).UnmarshalJSON(data))
+			}
+		case "contentrating":
+			out.ContentRating = string(in.String())
+		case "userrating":
+			out.UserRating = string(in.String())
+		case "qagmediarating":
+			out.MediaRating = IQGRating(in.Int())
+		case "keywords":
+			out.Keywords = string(in.String())
+		case "livestream":
+			out.LiveStream = int(in.Int())
+		case "sourcerelationship":
+			out.SourceRelationship = int(in.Int())
+		case "len":
+			out.Length = int(in.Int())
+		case "language":
+			out.Language = string(in.String())
+		case "langb":
+			out.LanguageB = string(in.String())
+		case "embeddable":
+			out.Embeddable = int(in.Int())
+		case "data":
+			if in.IsNull() {
+				in.Skip()
+				out.Data = nil
+			} else {
+				in.Delim('[')
+				if out.Data == nil {
+					if !in.IsDelim(']') {
+						out.Data = make([]Data, 0, 0)
+					} else {
+						out.Data = []Data{}
+					}
+				} else {
+					out.Data = (out.Data)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v50 Data
+					easyjson89fe9b30DecodeGithubComBsmOpenrtbV39(in, &v50)
+					out.Data = append(out.Data, v50)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "network":
+			if in.IsNull() {
+				in.Skip()
+				out.Network = nil
+			} else {
+				if out.Network == nil {
+					out.Network = new(ChannelEntity)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV316(in, out.Network)
+			}
+		case "channel":
+			if in.IsNull() {
+				in.Skip()
+				out.Channel = nil
+			} else {
+				if out.Channel == nil {
+					out.Channel = new(ChannelEntity)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV316(in, out.Channel)
+			}
+		case "kwarray":
+			if in.IsNull() {
+				in.Skip()
+				out.KwArray = nil
+			} else {
+				in.Delim('[')
+				if out.KwArray == nil {
+					if !in.IsDelim(']') {
+						out.KwArray = make([]string, 0, 4)
+					} else {
+						out.KwArray = []string{}
+					}
+				} else {
+					out.KwArray = (out.KwArray)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v51 string
+					v51 = string(in.String())
+					out.KwArray = append(out.KwArray, v51)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV314(out *jwriter.Writer, in Content) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Episode != 0 {
+		const prefix string = ",\"episode\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Episode))
+	}
+	if in.Title != "" {
+		const prefix string = ",\"title\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Title))
+	}
+	if in.Series != "" {
+		const prefix string = ",\"series\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Series))
+	}
+	if in.Season != "" {
+		const prefix string = ",\"season\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Season))
+	}
+	if in.Artist != "" {
+		const prefix string = ",\"artist\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Artist))
+	}
+	if in.Genre != "" {
+		const prefix string = ",\"genre\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Genre))
+	}
+	if in.Album != "" {
+		const prefix string = ",\"album\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Album))
+	}
+	if in.ISRC != "" {
+		const prefix string = ",\"isrc\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ISRC))
+	}
+	if in.Producer != nil {
+		const prefix string = ",\"producer\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV315(out, *in.Producer)
+	}
+	if in.URL != "" {
+		const prefix string = ",\"url\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.URL))
+	}
+	if in.CategoryTaxonomy != 0 {
+		const prefix string = ",\"cattax\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.CategoryTaxonomy))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v52, v53 := range in.Categories {
+				if v52 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v53))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.ProductionQuality != 0 {
+		const prefix string = ",\"prodq\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.ProductionQuality))
+	}
+	if in.VideoQuality != 0 {
+		const prefix string = ",\"videoquality\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.VideoQuality))
+	}
+	if in.Context != 0 {
+		const prefix string = ",\"context\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Context))
+	}
+	if in.ContentRating != "" {
+		const prefix string = ",\"contentrating\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ContentRating))
+	}
+	if in.UserRating != "" {
+		const prefix string = ",\"userrating\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.UserRating))
+	}
+	if in.MediaRating != 0 {
+		const prefix string = ",\"qagmediarating\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.MediaRating))
+	}
+	if in.Keywords != "" {
+		const prefix string = ",\"keywords\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Keywords))
+	}
+	if in.LiveStream != 0 {
+		const prefix string = ",\"livestream\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.LiveStream))
+	}
+	if in.SourceRelationship != 0 {
+		const prefix string = ",\"sourcerelationship\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.SourceRelationship))
+	}
+	if in.Length != 0 {
+		const prefix string = ",\"len\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Length))
+	}
+	if in.Language != "" {
+		const prefix string = ",\"language\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Language))
+	}
+	if in.LanguageB != "" {
+		const prefix string = ",\"langb\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.LanguageB))
+	}
+	if in.Embeddable != 0 {
+		const prefix string = ",\"embeddable\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Embeddable))
+	}
+	if len(in.Data) != 0 {
+		const prefix string = ",\"data\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v54, v55 := range in.Data {
+				if v54 > 0 {
+					out.RawByte(',')
+				}
+				easyjson89fe9b30EncodeGithubComBsmOpenrtbV39(out, v55)
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Network != nil {
+		const prefix string = ",\"network\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV316(out, *in.Network)
+	}
+	if in.Channel != nil {
+		const prefix string = ",\"channel\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV316(out, *in.Channel)
+	}
+	if len(in.KwArray) != 0 {
+		const prefix string = ",\"kwarray\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v56, v57 := range in.KwArray {
+				if v56 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v57))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV316(in *jlexer.Lexer, out *ChannelEntity) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "domain":
+			out.Domain = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV316(out *jwriter.Writer, in ChannelEntity) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV315(in *jlexer.Lexer, out *Producer) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v58 ContentCategory
+					v58 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v58)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "domain":
+			out.Domain = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV315(out *jwriter.Writer, in Producer) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v59, v60 := range in.Categories {
+				if v59 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v60))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV313(in *jlexer.Lexer, out *Publisher) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v61 ContentCategory
+					v61 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v61)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "domain":
+			out.Domain = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV313(out *jwriter.Writer, in Publisher) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v62, v63 := range in.Categories {
+				if v62 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v63))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV32(in *jlexer.Lexer, out *Site) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "page":
+			out.Page = string(in.String())
+		case "ref":
+			out.Referrer = string(in.String())
+		case "search":
+			out.Search = string(in.String())
+		case "mobile":
+			out.Mobile = int(in.Int())
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "domain":
+			out.Domain = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v64 ContentCategory
+					v64 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v64)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "sectioncat":
+			if in.IsNull() {
+				in.Skip()
+				out.SectionCategories = nil
+			} else {
+				in.Delim('[')
+				if out.SectionCategories == nil {
+					if !in.IsDelim(']') {
+						out.SectionCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.SectionCategories = []ContentCategory{}
+					}
+				} else {
+					out.SectionCategories = (out.SectionCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v65 ContentCategory
+					v65 = ContentCategory(in.String())
+					out.SectionCategories = append(out.SectionCategories, v65)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "pagecat":
+			if in.IsNull() {
+				in.Skip()
+				out.PageCategories = nil
+			} else {
+				in.Delim('[')
+				if out.PageCategories == nil {
+					if !in.IsDelim(']') {
+						out.PageCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.PageCategories = []ContentCategory{}
+					}
+				} else {
+					out.PageCategories = (out.PageCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v66 ContentCategory
+					v66 = ContentCategory(in.String())
+					out.PageCategories = append(out.PageCategories, v66)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "privacypolicy":
+			if in.IsNull() {
+				in.Skip()
+				out.PrivacyPolicy = nil
+			} else {
+				if out.PrivacyPolicy == nil {
+					out.PrivacyPolicy = new(int)
+				}
+				*out.PrivacyPolicy = int(in.Int())
+			}
+		case "publisher":
+			if in.IsNull() {
+				in.Skip()
+				out.Publisher = nil
+			} else {
+				if out.Publisher == nil {
+					out.Publisher = new(Publisher)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV313(in, out.Publisher)
+			}
+		case "content":
+			if in.IsNull() {
+				in.Skip()
+				out.Content = nil
+			} else {
+				if out.Content == nil {
+					out.Content = new(Content)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV314(in, out.Content)
+			}
+		case "keywords":
+			out.Keywords = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV32(out *jwriter.Writer, in Site) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Page != "" {
+		const prefix string = ",\"page\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Page))
+	}
+	if in.Referrer != "" {
+		const prefix string = ",\"ref\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Referrer))
+	}
+	if in.Search != "" {
+		const prefix string = ",\"search\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Search))
+	}
+	if in.Mobile != 0 {
+		const prefix string = ",\"mobile\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Mobile))
+	}
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v67, v68 := range in.Categories {
+				if v67 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v68))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.SectionCategories) != 0 {
+		const prefix string = ",\"sectioncat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v69, v70 := range in.SectionCategories {
+				if v69 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v70))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.PageCategories) != 0 {
+		const prefix string = ",\"pagecat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v71, v72 := range in.PageCategories {
+				if v71 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v72))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.PrivacyPolicy != nil {
+		const prefix string = ",\"privacypolicy\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(*in.PrivacyPolicy))
+	}
+	if in.Publisher != nil {
+		const prefix string = ",\"publisher\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV313(out, *in.Publisher)
+	}
+	if in.Content != nil {
+		const prefix string = ",\"content\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV314(out, *in.Content)
+	}
+	if in.Keywords != "" {
+		const prefix string = ",\"keywords\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Keywords))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV31(in *jlexer.Lexer, out *Impression) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "banner":
+			if in.IsNull() {
+				in.Skip()
+				out.Banner = nil
+			} else {
+				if out.Banner == nil {
+					out.Banner = new(Banner)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV317(in, out.Banner)
+			}
+		case "video":
+			if in.IsNull() {
+				in.Skip()
+				out.Video = nil
+			} else {
+				if out.Video == nil {
+					out.Video = new(Video)
+				}
+				if data := in.Raw(); in.Ok() {
+					in.AddError((*out.Video).UnmarshalJSON(data))
+				}
+			}
+		case "audio":
+			if in.IsNull() {
+				in.Skip()
+				out.Audio = nil
+			} else {
+				if out.Audio == nil {
+					out.Audio = new(Audio)
+				}
+				if data := in.Raw(); in.Ok() {
+					in.AddError((*out.Audio).UnmarshalJSON(data))
+				}
+			}
+		case "native":
+			if in.IsNull() {
+				in.Skip()
+				out.Native = nil
+			} else {
+				if out.Native == nil {
+					out.Native = new(Native)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV318(in, out.Native)
+			}
+		case "pmp":
+			if in.IsNull() {
+				in.Skip()
+				out.PMP = nil
+			} else {
+				if out.PMP == nil {
+					out.PMP = new(PMP)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV319(in, out.PMP)
+			}
+		case "displaymanager":
+			out.DisplayManager = string(in.String())
+		case "displaymanagerver":
+			out.DisplayManagerVersion = string(in.String())
+		case "instl":
+			out.Interstitial = int(in.Int())
+		case "tagid":
+			out.TagID = string(in.String())
+		case "bidfloor":
+			out.BidFloor = float64(in.Float64())
+		case "bidfloorcur":
+			out.BidFloorCurrency = string(in.String())
+		case "secure":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Secure).UnmarshalJSON(data))
+			}
+		case "qty":
+			if in.IsNull() {
+				in.Skip()
+				out.Quantity = nil
+			} else {
+				if out.Quantity == nil {
+					out.Quantity = new(Quantity)
+				}
+				easyjson89fe9b30DecodeGithubComBsmOpenrtbV320(in, out.Quantity)
+			}
+		case "exp":
+			out.Exp = int(in.Int())
+		case "iframebuster":
+			if in.IsNull() {
+				in.Skip()
+				out.IFrameBusters = nil
+			} else {
+				in.Delim('[')
+				if out.IFrameBusters == nil {
+					if !in.IsDelim(']') {
+						out.IFrameBusters = make([]string, 0, 4)
+					} else {
+						out.IFrameBusters = []string{}
+					}
+				} else {
+					out.IFrameBusters = (out.IFrameBusters)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v73 string
+					v73 = string(in.String())
+					out.IFrameBusters = append(out.IFrameBusters, v73)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV31(out *jwriter.Writer, in Impression) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"id\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Banner != nil {
+		const prefix string = ",\"banner\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV317(out, *in.Banner)
+	}
+	if in.Video != nil {
+		const prefix string = ",\"video\":"
+		out.RawString(prefix)
+		out.Raw((*in.Video).MarshalJSON())
+	}
+	if in.Audio != nil {
+		const prefix string = ",\"audio\":"
+		out.RawString(prefix)
+		out.Raw((*in.Audio).MarshalJSON())
+	}
+	if in.Native != nil {
+		const prefix string = ",\"native\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV318(out, *in.Native)
+	}
+	if in.PMP != nil {
+		const prefix string = ",\"pmp\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV319(out, *in.PMP)
+	}
+	if in.DisplayManager != "" {
+		const prefix string = ",\"displaymanager\":"
+		out.RawString(prefix)
+		out.String(string(in.DisplayManager))
+	}
+	if in.DisplayManagerVersion != "" {
+		const prefix string = ",\"displaymanagerver\":"
+		out.RawString(prefix)
+		out.String(string(in.DisplayManagerVersion))
+	}
+	if in.Interstitial != 0 {
+		const prefix string = ",\"instl\":"
+		out.RawString(prefix)
+		out.Int(int(in.Interstitial))
+	}
+	if in.TagID != "" {
+		const prefix string = ",\"tagid\":"
+		out.RawString(prefix)
+		out.String(string(in.TagID))
+	}
+	if in.BidFloor != 0 {
+		const prefix string = ",\"bidfloor\":"
+		out.RawString(prefix)
+		out.Float64(float64(in.BidFloor))
+	}
+	if in.BidFloorCurrency != "" {
+		const prefix string = ",\"bidfloorcur\":"
+		out.RawString(prefix)
+		out.String(string(in.BidFloorCurrency))
+	}
+	if in.Secure != 0 {
+		const prefix string = ",\"secure\":"
+		out.RawString(prefix)
+		out.Int(int(in.Secure))
+	}
+	if in.Quantity != nil {
+		const prefix string = ",\"qty\":"
+		out.RawString(prefix)
+		easyjson89fe9b30EncodeGithubComBsmOpenrtbV320(out, *in.Quantity)
+	}
+	if in.Exp != 0 {
+		const prefix string = ",\"exp\":"
+		out.RawString(prefix)
+		out.Int(int(in.Exp))
+	}
+	if len(in.IFrameBusters) != 0 {
+		const prefix string = ",\"iframebuster\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v74, v75 := range in.IFrameBusters {
+				if v74 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v75))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV320(in *jlexer.Lexer, out *Quantity) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "multiplier":
+			out.Multiplier = float64(in.Float64())
+		case "sourcetype":
+			out.SourceType = MeasurementSourceType(in.Int())
+		case "vendor":
+			out.Vendor = string(in.String())
+		case "ext":
+			if in.IsNull() {
+				in.Skip()
+				out.Ext = nil
+			} else {
+				if out.Ext == nil {
+					out.Ext = new(json.RawMessage)
+				}
+				if data := in.Raw(); in.Ok() {
+					in.AddError((*out.Ext).UnmarshalJSON(data))
+				}
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV320(out *jwriter.Writer, in Quantity) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"multiplier\":"
+		out.RawString(prefix[1:])
+		out.Float64(float64(in.Multiplier))
+	}
+	if in.SourceType != 0 {
+		const prefix string = ",\"sourcetype\":"
+		out.RawString(prefix)
+		out.Int(int(in.SourceType))
+	}
+	if in.Vendor != "" {
+		const prefix string = ",\"vendor\":"
+		out.RawString(prefix)
+		out.String(string(in.Vendor))
+	}
+	if in.Ext != nil {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((*in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV319(in *jlexer.Lexer, out *PMP) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "private_auction":
+			out.Private = int(in.Int())
+		case "deals":
+			if in.IsNull() {
+				in.Skip()
+				out.Deals = nil
+			} else {
+				in.Delim('[')
+				if out.Deals == nil {
+					if !in.IsDelim(']') {
+						out.Deals = make([]Deal, 0, 0)
+					} else {
+						out.Deals = []Deal{}
+					}
+				} else {
+					out.Deals = (out.Deals)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v76 Deal
+					if data := in.Raw(); in.Ok() {
+						in.AddError((v76).UnmarshalJSON(data))
+					}
+					out.Deals = append(out.Deals, v76)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV319(out *jwriter.Writer, in PMP) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Private != 0 {
+		const prefix string = ",\"private_auction\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.Private))
+	}
+	if len(in.Deals) != 0 {
+		const prefix string = ",\"deals\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v77, v78 := range in.Deals {
+				if v77 > 0 {
+					out.RawByte(',')
+				}
+				out.Raw((v78).MarshalJSON())
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV318(in *jlexer.Lexer, out *Native) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "request":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Request).UnmarshalJSON(data))
+			}
+		case "ver":
+			out.Version = string(in.String())
+		case "api":
+			if in.IsNull() {
+				in.Skip()
+				out.APIs = nil
+			} else {
+				in.Delim('[')
+				if out.APIs == nil {
+					if !in.IsDelim(']') {
+						out.APIs = make([]APIFramework, 0, 8)
+					} else {
+						out.APIs = []APIFramework{}
+					}
+				} else {
+					out.APIs = (out.APIs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v79 APIFramework
+					v79 = APIFramework(in.Int())
+					out.APIs = append(out.APIs, v79)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "battr":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedAttrs = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedAttrs == nil {
+					if !in.IsDelim(']') {
+						out.BlockedAttrs = make([]CreativeAttribute, 0, 8)
+					} else {
+						out.BlockedAttrs = []CreativeAttribute{}
+					}
+				} else {
+					out.BlockedAttrs = (out.BlockedAttrs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v80 CreativeAttribute
+					v80 = CreativeAttribute(in.Int())
+					out.BlockedAttrs = append(out.BlockedAttrs, v80)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV318(out *jwriter.Writer, in Native) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"request\":"
+		out.RawString(prefix[1:])
+		out.Raw((in.Request).MarshalJSON())
+	}
+	if in.Version != "" {
+		const prefix string = ",\"ver\":"
+		out.RawString(prefix)
+		out.String(string(in.Version))
+	}
+	if len(in.APIs) != 0 {
+		const prefix string = ",\"api\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v81, v82 := range in.APIs {
+				if v81 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v82))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.BlockedAttrs) != 0 {
+		const prefix string = ",\"battr\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v83, v84 := range in.BlockedAttrs {
+				if v83 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v84))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV317(in *jlexer.Lexer, out *Banner) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "w":
+			out.Width = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "format":
+			if in.IsNull() {
+				in.Skip()
+				out.Formats = nil
+			} else {
+				in.Delim('[')
+				if out.Formats == nil {
+					if !in.IsDelim(']') {
+						out.Formats = make([]Format, 0, 1)
+					} else {
+						out.Formats = []Format{}
+					}
+				} else {
+					out.Formats = (out.Formats)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v85 Format
+					easyjson89fe9b30DecodeGithubComBsmOpenrtbV321(in, &v85)
+					out.Formats = append(out.Formats, v85)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "wmax":
+			out.WidthMax = int(in.Int())
+		case "hmax":
+			out.HeightMax = int(in.Int())
+		case "wmin":
+			out.WidthMin = int(in.Int())
+		case "hmin":
+			out.HeightMin = int(in.Int())
+		case "id":
+			out.ID = string(in.String())
+		case "btype":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedTypes = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedTypes == nil {
+					if !in.IsDelim(']') {
+						out.BlockedTypes = make([]BannerType, 0, 8)
+					} else {
+						out.BlockedTypes = []BannerType{}
+					}
+				} else {
+					out.BlockedTypes = (out.BlockedTypes)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v86 BannerType
+					v86 = BannerType(in.Int())
+					out.BlockedTypes = append(out.BlockedTypes, v86)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "battr":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedAttrs = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedAttrs == nil {
+					if !in.IsDelim(']') {
+						out.BlockedAttrs = make([]CreativeAttribute, 0, 8)
+					} else {
+						out.BlockedAttrs = []CreativeAttribute{}
+					}
+				} else {
+					out.BlockedAttrs = (out.BlockedAttrs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v87 CreativeAttribute
+					v87 = CreativeAttribute(in.Int())
+					out.BlockedAttrs = append(out.BlockedAttrs, v87)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "pos":
+			out.Position = AdPosition(in.Int())
+		case "mimes":
+			if in.IsNull() {
+				in.Skip()
+				out.MIMEs = nil
+			} else {
+				in.Delim('[')
+				if out.MIMEs == nil {
+					if !in.IsDelim(']') {
+						out.MIMEs = make([]string, 0, 4)
+					} else {
+						out.MIMEs = []string{}
+					}
+				} else {
+					out.MIMEs = (out.MIMEs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v88 string
+					v88 = string(in.String())
+					out.MIMEs = append(out.MIMEs, v88)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "topframe":
+			out.TopFrame = int(in.Int())
+		case "expdir":
+			if in.IsNull() {
+				in.Skip()
+				out.ExpDirs = nil
+			} else {
+				in.Delim('[')
+				if out.ExpDirs == nil {
+					if !in.IsDelim(']') {
+						out.ExpDirs = make([]ExpDir, 0, 8)
+					} else {
+						out.ExpDirs = []ExpDir{}
+					}
+				} else {
+					out.ExpDirs = (out.ExpDirs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v89 ExpDir
+					v89 = ExpDir(in.Int())
+					out.ExpDirs = append(out.ExpDirs, v89)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "api":
+			if in.IsNull() {
+				in.Skip()
+				out.APIs = nil
+			} else {
+				in.Delim('[')
+				if out.APIs == nil {
+					if !in.IsDelim(']') {
+						out.APIs = make([]APIFramework, 0, 8)
+					} else {
+						out.APIs = []APIFramework{}
+					}
+				} else {
+					out.APIs = (out.APIs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v90 APIFramework
+					v90 = APIFramework(in.Int())
+					out.APIs = append(out.APIs, v90)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "vcm":
+			out.VCM = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV317(out *jwriter.Writer, in Banner) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.Width))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if len(in.Formats) != 0 {
+		const prefix string = ",\"format\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v91, v92 := range in.Formats {
+				if v91 > 0 {
+					out.RawByte(',')
+				}
+				easyjson89fe9b30EncodeGithubComBsmOpenrtbV321(out, v92)
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.WidthMax != 0 {
+		const prefix string = ",\"wmax\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthMax))
+	}
+	if in.HeightMax != 0 {
+		const prefix string = ",\"hmax\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.HeightMax))
+	}
+	if in.WidthMin != 0 {
+		const prefix string = ",\"wmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthMin))
+	}
+	if in.HeightMin != 0 {
+		const prefix string = ",\"hmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.HeightMin))
+	}
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ID))
+	}
+	if len(in.BlockedTypes) != 0 {
+		const prefix string = ",\"btype\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v93, v94 := range in.BlockedTypes {
+				if v93 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v94))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.BlockedAttrs) != 0 {
+		const prefix string = ",\"battr\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v95, v96 := range in.BlockedAttrs {
+				if v95 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v96))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Position != 0 {
+		const prefix string = ",\"pos\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Position))
+	}
+	if len(in.MIMEs) != 0 {
+		const prefix string = ",\"mimes\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v97, v98 := range in.MIMEs {
+				if v97 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v98))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.TopFrame != 0 {
+		const prefix string = ",\"topframe\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.TopFrame))
+	}
+	if len(in.ExpDirs) != 0 {
+		const prefix string = ",\"expdir\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v99, v100 := range in.ExpDirs {
+				if v99 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v100))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.APIs) != 0 {
+		const prefix string = ",\"api\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v101, v102 := range in.APIs {
+				if v101 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v102))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.VCM != 0 {
+		const prefix string = ",\"vcm\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.VCM))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson89fe9b30DecodeGithubComBsmOpenrtbV321(in *jlexer.Lexer, out *Format) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "w":
+			out.Width = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "wratio":
+			out.WidthRatio = int(in.Int())
+		case "hration":
+			out.HeightRatio = int(in.Int())
+		case "wmin":
+			out.WidthMin = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson89fe9b30EncodeGithubComBsmOpenrtbV321(out *jwriter.Writer, in Format) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.Width))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if in.WidthRatio != 0 {
+		const prefix string = ",\"wratio\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthRatio))
+	}
+	if in.HeightRatio != 0 {
+		const prefix string = ",\"hration\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.HeightRatio))
+	}
+	if in.WidthMin != 0 {
+		const prefix string = ",\"wmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthMin))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
diff --git a/bidresponse_easyjson.go b/bidresponse_easyjson.go
new file mode 100644
index 0000000..3e60b1a
--- /dev/null
+++ b/bidresponse_easyjson.go
@@ -0,0 +1,16 @@
+// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
+// compilable during generation.
+
+package  openrtb
+
+import (
+  "github.com/mailru/easyjson/jwriter"
+  "github.com/mailru/easyjson/jlexer"
+)
+
+func ( BidResponse ) MarshalJSON() ([]byte, error) { return nil, nil }
+func (* BidResponse ) UnmarshalJSON([]byte) error { return nil }
+func ( BidResponse ) MarshalEasyJSON(w *jwriter.Writer) {}
+func (* BidResponse ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
+
+type EasyJSON_exporter_BidResponse *BidResponse
diff --git a/content_easyjson.go b/content_easyjson.go
new file mode 100644
index 0000000..50b9317
--- /dev/null
+++ b/content_easyjson.go
@@ -0,0 +1,687 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson344736e9DecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *Content) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "episode":
+			out.Episode = int(in.Int())
+		case "title":
+			out.Title = string(in.String())
+		case "series":
+			out.Series = string(in.String())
+		case "season":
+			out.Season = string(in.String())
+		case "artist":
+			out.Artist = string(in.String())
+		case "genre":
+			out.Genre = string(in.String())
+		case "album":
+			out.Album = string(in.String())
+		case "isrc":
+			out.ISRC = string(in.String())
+		case "producer":
+			if in.IsNull() {
+				in.Skip()
+				out.Producer = nil
+			} else {
+				if out.Producer == nil {
+					out.Producer = new(Producer)
+				}
+				easyjson344736e9DecodeGithubComBsmOpenrtbV31(in, out.Producer)
+			}
+		case "url":
+			out.URL = string(in.String())
+		case "cattax":
+			out.CategoryTaxonomy = CategoryTaxonomy(in.Int())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 ContentCategory
+					v1 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "prodq":
+			out.ProductionQuality = ProductionQuality(in.Int())
+		case "videoquality":
+			out.VideoQuality = ProductionQuality(in.Int())
+		case "context":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Context).UnmarshalJSON(data))
+			}
+		case "contentrating":
+			out.ContentRating = string(in.String())
+		case "userrating":
+			out.UserRating = string(in.String())
+		case "qagmediarating":
+			out.MediaRating = IQGRating(in.Int())
+		case "keywords":
+			out.Keywords = string(in.String())
+		case "livestream":
+			out.LiveStream = int(in.Int())
+		case "sourcerelationship":
+			out.SourceRelationship = int(in.Int())
+		case "len":
+			out.Length = int(in.Int())
+		case "language":
+			out.Language = string(in.String())
+		case "langb":
+			out.LanguageB = string(in.String())
+		case "embeddable":
+			out.Embeddable = int(in.Int())
+		case "data":
+			if in.IsNull() {
+				in.Skip()
+				out.Data = nil
+			} else {
+				in.Delim('[')
+				if out.Data == nil {
+					if !in.IsDelim(']') {
+						out.Data = make([]Data, 0, 0)
+					} else {
+						out.Data = []Data{}
+					}
+				} else {
+					out.Data = (out.Data)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v2 Data
+					(v2).UnmarshalEasyJSON(in)
+					out.Data = append(out.Data, v2)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "network":
+			if in.IsNull() {
+				in.Skip()
+				out.Network = nil
+			} else {
+				if out.Network == nil {
+					out.Network = new(ChannelEntity)
+				}
+				(*out.Network).UnmarshalEasyJSON(in)
+			}
+		case "channel":
+			if in.IsNull() {
+				in.Skip()
+				out.Channel = nil
+			} else {
+				if out.Channel == nil {
+					out.Channel = new(ChannelEntity)
+				}
+				(*out.Channel).UnmarshalEasyJSON(in)
+			}
+		case "kwarray":
+			if in.IsNull() {
+				in.Skip()
+				out.KwArray = nil
+			} else {
+				in.Delim('[')
+				if out.KwArray == nil {
+					if !in.IsDelim(']') {
+						out.KwArray = make([]string, 0, 4)
+					} else {
+						out.KwArray = []string{}
+					}
+				} else {
+					out.KwArray = (out.KwArray)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v3 string
+					v3 = string(in.String())
+					out.KwArray = append(out.KwArray, v3)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson344736e9EncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in Content) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Episode != 0 {
+		const prefix string = ",\"episode\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Episode))
+	}
+	if in.Title != "" {
+		const prefix string = ",\"title\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Title))
+	}
+	if in.Series != "" {
+		const prefix string = ",\"series\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Series))
+	}
+	if in.Season != "" {
+		const prefix string = ",\"season\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Season))
+	}
+	if in.Artist != "" {
+		const prefix string = ",\"artist\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Artist))
+	}
+	if in.Genre != "" {
+		const prefix string = ",\"genre\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Genre))
+	}
+	if in.Album != "" {
+		const prefix string = ",\"album\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Album))
+	}
+	if in.ISRC != "" {
+		const prefix string = ",\"isrc\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ISRC))
+	}
+	if in.Producer != nil {
+		const prefix string = ",\"producer\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson344736e9EncodeGithubComBsmOpenrtbV31(out, *in.Producer)
+	}
+	if in.URL != "" {
+		const prefix string = ",\"url\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.URL))
+	}
+	if in.CategoryTaxonomy != 0 {
+		const prefix string = ",\"cattax\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.CategoryTaxonomy))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v4, v5 := range in.Categories {
+				if v4 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v5))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.ProductionQuality != 0 {
+		const prefix string = ",\"prodq\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.ProductionQuality))
+	}
+	if in.VideoQuality != 0 {
+		const prefix string = ",\"videoquality\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.VideoQuality))
+	}
+	if in.Context != 0 {
+		const prefix string = ",\"context\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Context))
+	}
+	if in.ContentRating != "" {
+		const prefix string = ",\"contentrating\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ContentRating))
+	}
+	if in.UserRating != "" {
+		const prefix string = ",\"userrating\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.UserRating))
+	}
+	if in.MediaRating != 0 {
+		const prefix string = ",\"qagmediarating\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.MediaRating))
+	}
+	if in.Keywords != "" {
+		const prefix string = ",\"keywords\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Keywords))
+	}
+	if in.LiveStream != 0 {
+		const prefix string = ",\"livestream\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.LiveStream))
+	}
+	if in.SourceRelationship != 0 {
+		const prefix string = ",\"sourcerelationship\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.SourceRelationship))
+	}
+	if in.Length != 0 {
+		const prefix string = ",\"len\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Length))
+	}
+	if in.Language != "" {
+		const prefix string = ",\"language\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Language))
+	}
+	if in.LanguageB != "" {
+		const prefix string = ",\"langb\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.LanguageB))
+	}
+	if in.Embeddable != 0 {
+		const prefix string = ",\"embeddable\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Embeddable))
+	}
+	if len(in.Data) != 0 {
+		const prefix string = ",\"data\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v6, v7 := range in.Data {
+				if v6 > 0 {
+					out.RawByte(',')
+				}
+				(v7).MarshalEasyJSON(out)
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Network != nil {
+		const prefix string = ",\"network\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		(*in.Network).MarshalEasyJSON(out)
+	}
+	if in.Channel != nil {
+		const prefix string = ",\"channel\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		(*in.Channel).MarshalEasyJSON(out)
+	}
+	if len(in.KwArray) != 0 {
+		const prefix string = ",\"kwarray\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v8, v9 := range in.KwArray {
+				if v8 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v9))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Content) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson344736e9EncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Content) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson344736e9EncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Content) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson344736e9DecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Content) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson344736e9DecodeGithubComBsmOpenrtbV3(l, v)
+}
+func easyjson344736e9DecodeGithubComBsmOpenrtbV31(in *jlexer.Lexer, out *Producer) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v10 ContentCategory
+					v10 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v10)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "domain":
+			out.Domain = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson344736e9EncodeGithubComBsmOpenrtbV31(out *jwriter.Writer, in Producer) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v11, v12 := range in.Categories {
+				if v11 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v12))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
diff --git a/device_easyjson.go b/device_easyjson.go
new file mode 100644
index 0000000..b4d9b9e
--- /dev/null
+++ b/device_easyjson.go
@@ -0,0 +1,488 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson3073ac56DecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *Device) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "ua":
+			out.UA = string(in.String())
+		case "sua":
+			if in.IsNull() {
+				in.Skip()
+				out.Sua = nil
+			} else {
+				if out.Sua == nil {
+					out.Sua = new(UserAgent)
+				}
+				(*out.Sua).UnmarshalEasyJSON(in)
+			}
+		case "geo":
+			if in.IsNull() {
+				in.Skip()
+				out.Geo = nil
+			} else {
+				if out.Geo == nil {
+					out.Geo = new(Geo)
+				}
+				(*out.Geo).UnmarshalEasyJSON(in)
+			}
+		case "dnt":
+			out.DNT = int(in.Int())
+		case "lmt":
+			out.LMT = int(in.Int())
+		case "ip":
+			out.IP = string(in.String())
+		case "ipv6":
+			out.IPv6 = string(in.String())
+		case "devicetype":
+			out.DeviceType = DeviceType(in.Int())
+		case "make":
+			out.Make = string(in.String())
+		case "model":
+			out.Model = string(in.String())
+		case "os":
+			out.OS = string(in.String())
+		case "osv":
+			out.OSVersion = string(in.String())
+		case "hwv":
+			out.HWVersion = string(in.String())
+		case "h":
+			out.Height = int(in.Int())
+		case "w":
+			out.Width = int(in.Int())
+		case "ppi":
+			out.PPI = int(in.Int())
+		case "pxratio":
+			out.PixelRatio = float64(in.Float64())
+		case "js":
+			out.JS = int(in.Int())
+		case "geofetch":
+			out.GeoFetch = int(in.Int())
+		case "flashver":
+			out.FlashVersion = string(in.String())
+		case "language":
+			out.Language = string(in.String())
+		case "langb":
+			out.LanguageB = string(in.String())
+		case "carrier":
+			out.Carrier = string(in.String())
+		case "mccmnc":
+			out.MCCMNC = string(in.String())
+		case "connectiontype":
+			out.ConnType = ConnType(in.Int())
+		case "ifa":
+			out.IFA = string(in.String())
+		case "didsha1":
+			out.IDSHA1 = string(in.String())
+		case "didmd5":
+			out.IDMD5 = string(in.String())
+		case "dpidsha1":
+			out.PIDSHA1 = string(in.String())
+		case "dpidmd5":
+			out.PIDMD5 = string(in.String())
+		case "macsha1":
+			out.MacSHA1 = string(in.String())
+		case "macmd5":
+			out.MacMD5 = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3073ac56EncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in Device) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.UA != "" {
+		const prefix string = ",\"ua\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.UA))
+	}
+	if in.Sua != nil {
+		const prefix string = ",\"sua\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		(*in.Sua).MarshalEasyJSON(out)
+	}
+	if in.Geo != nil {
+		const prefix string = ",\"geo\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		(*in.Geo).MarshalEasyJSON(out)
+	}
+	if in.DNT != 0 {
+		const prefix string = ",\"dnt\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.DNT))
+	}
+	if in.LMT != 0 {
+		const prefix string = ",\"lmt\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.LMT))
+	}
+	if in.IP != "" {
+		const prefix string = ",\"ip\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IP))
+	}
+	if in.IPv6 != "" {
+		const prefix string = ",\"ipv6\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IPv6))
+	}
+	if in.DeviceType != 0 {
+		const prefix string = ",\"devicetype\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.DeviceType))
+	}
+	if in.Make != "" {
+		const prefix string = ",\"make\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Make))
+	}
+	if in.Model != "" {
+		const prefix string = ",\"model\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Model))
+	}
+	if in.OS != "" {
+		const prefix string = ",\"os\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.OS))
+	}
+	if in.OSVersion != "" {
+		const prefix string = ",\"osv\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.OSVersion))
+	}
+	if in.HWVersion != "" {
+		const prefix string = ",\"hwv\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.HWVersion))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Width))
+	}
+	if in.PPI != 0 {
+		const prefix string = ",\"ppi\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.PPI))
+	}
+	if in.PixelRatio != 0 {
+		const prefix string = ",\"pxratio\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Float64(float64(in.PixelRatio))
+	}
+	if in.JS != 0 {
+		const prefix string = ",\"js\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.JS))
+	}
+	if in.GeoFetch != 0 {
+		const prefix string = ",\"geofetch\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.GeoFetch))
+	}
+	if in.FlashVersion != "" {
+		const prefix string = ",\"flashver\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.FlashVersion))
+	}
+	if in.Language != "" {
+		const prefix string = ",\"language\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Language))
+	}
+	if in.LanguageB != "" {
+		const prefix string = ",\"langb\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.LanguageB))
+	}
+	if in.Carrier != "" {
+		const prefix string = ",\"carrier\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Carrier))
+	}
+	if in.MCCMNC != "" {
+		const prefix string = ",\"mccmnc\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.MCCMNC))
+	}
+	if in.ConnType != 0 {
+		const prefix string = ",\"connectiontype\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.ConnType))
+	}
+	if in.IFA != "" {
+		const prefix string = ",\"ifa\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IFA))
+	}
+	if in.IDSHA1 != "" {
+		const prefix string = ",\"didsha1\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IDSHA1))
+	}
+	if in.IDMD5 != "" {
+		const prefix string = ",\"didmd5\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.IDMD5))
+	}
+	if in.PIDSHA1 != "" {
+		const prefix string = ",\"dpidsha1\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.PIDSHA1))
+	}
+	if in.PIDMD5 != "" {
+		const prefix string = ",\"dpidmd5\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.PIDMD5))
+	}
+	if in.MacSHA1 != "" {
+		const prefix string = ",\"macsha1\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.MacSHA1))
+	}
+	if in.MacMD5 != "" {
+		const prefix string = ",\"macmd5\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.MacMD5))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Device) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson3073ac56EncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Device) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson3073ac56EncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Device) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson3073ac56DecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Device) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson3073ac56DecodeGithubComBsmOpenrtbV3(l, v)
+}
diff --git a/doc_easyjson.go b/doc_easyjson.go
new file mode 100644
index 0000000..793d66c
--- /dev/null
+++ b/doc_easyjson.go
@@ -0,0 +1,18 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
diff --git a/go.mod b/go.mod
index 5d8e195..860d8e2 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,5 @@
 module github.com/bsm/openrtb/v3
 
 go 1.13
+
+require github.com/mailru/easyjson v0.7.7 // indirect
diff --git a/go.sum b/go.sum
index e69de29..7707cb6 100644
--- a/go.sum
+++ b/go.sum
@@ -0,0 +1,4 @@
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
diff --git a/impression_easyjson.go b/impression_easyjson.go
new file mode 100644
index 0000000..05dc84d
--- /dev/null
+++ b/impression_easyjson.go
@@ -0,0 +1,1113 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson7ebaa60bDecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *Impression) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "banner":
+			if in.IsNull() {
+				in.Skip()
+				out.Banner = nil
+			} else {
+				if out.Banner == nil {
+					out.Banner = new(Banner)
+				}
+				easyjson7ebaa60bDecodeGithubComBsmOpenrtbV31(in, out.Banner)
+			}
+		case "video":
+			if in.IsNull() {
+				in.Skip()
+				out.Video = nil
+			} else {
+				if out.Video == nil {
+					out.Video = new(Video)
+				}
+				if data := in.Raw(); in.Ok() {
+					in.AddError((*out.Video).UnmarshalJSON(data))
+				}
+			}
+		case "audio":
+			if in.IsNull() {
+				in.Skip()
+				out.Audio = nil
+			} else {
+				if out.Audio == nil {
+					out.Audio = new(Audio)
+				}
+				if data := in.Raw(); in.Ok() {
+					in.AddError((*out.Audio).UnmarshalJSON(data))
+				}
+			}
+		case "native":
+			if in.IsNull() {
+				in.Skip()
+				out.Native = nil
+			} else {
+				if out.Native == nil {
+					out.Native = new(Native)
+				}
+				easyjson7ebaa60bDecodeGithubComBsmOpenrtbV32(in, out.Native)
+			}
+		case "pmp":
+			if in.IsNull() {
+				in.Skip()
+				out.PMP = nil
+			} else {
+				if out.PMP == nil {
+					out.PMP = new(PMP)
+				}
+				easyjson7ebaa60bDecodeGithubComBsmOpenrtbV33(in, out.PMP)
+			}
+		case "displaymanager":
+			out.DisplayManager = string(in.String())
+		case "displaymanagerver":
+			out.DisplayManagerVersion = string(in.String())
+		case "instl":
+			out.Interstitial = int(in.Int())
+		case "tagid":
+			out.TagID = string(in.String())
+		case "bidfloor":
+			out.BidFloor = float64(in.Float64())
+		case "bidfloorcur":
+			out.BidFloorCurrency = string(in.String())
+		case "secure":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Secure).UnmarshalJSON(data))
+			}
+		case "qty":
+			if in.IsNull() {
+				in.Skip()
+				out.Quantity = nil
+			} else {
+				if out.Quantity == nil {
+					out.Quantity = new(Quantity)
+				}
+				easyjson7ebaa60bDecodeGithubComBsmOpenrtbV34(in, out.Quantity)
+			}
+		case "exp":
+			out.Exp = int(in.Int())
+		case "iframebuster":
+			if in.IsNull() {
+				in.Skip()
+				out.IFrameBusters = nil
+			} else {
+				in.Delim('[')
+				if out.IFrameBusters == nil {
+					if !in.IsDelim(']') {
+						out.IFrameBusters = make([]string, 0, 4)
+					} else {
+						out.IFrameBusters = []string{}
+					}
+				} else {
+					out.IFrameBusters = (out.IFrameBusters)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 string
+					v1 = string(in.String())
+					out.IFrameBusters = append(out.IFrameBusters, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson7ebaa60bEncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in Impression) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"id\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Banner != nil {
+		const prefix string = ",\"banner\":"
+		out.RawString(prefix)
+		easyjson7ebaa60bEncodeGithubComBsmOpenrtbV31(out, *in.Banner)
+	}
+	if in.Video != nil {
+		const prefix string = ",\"video\":"
+		out.RawString(prefix)
+		out.Raw((*in.Video).MarshalJSON())
+	}
+	if in.Audio != nil {
+		const prefix string = ",\"audio\":"
+		out.RawString(prefix)
+		out.Raw((*in.Audio).MarshalJSON())
+	}
+	if in.Native != nil {
+		const prefix string = ",\"native\":"
+		out.RawString(prefix)
+		easyjson7ebaa60bEncodeGithubComBsmOpenrtbV32(out, *in.Native)
+	}
+	if in.PMP != nil {
+		const prefix string = ",\"pmp\":"
+		out.RawString(prefix)
+		easyjson7ebaa60bEncodeGithubComBsmOpenrtbV33(out, *in.PMP)
+	}
+	if in.DisplayManager != "" {
+		const prefix string = ",\"displaymanager\":"
+		out.RawString(prefix)
+		out.String(string(in.DisplayManager))
+	}
+	if in.DisplayManagerVersion != "" {
+		const prefix string = ",\"displaymanagerver\":"
+		out.RawString(prefix)
+		out.String(string(in.DisplayManagerVersion))
+	}
+	if in.Interstitial != 0 {
+		const prefix string = ",\"instl\":"
+		out.RawString(prefix)
+		out.Int(int(in.Interstitial))
+	}
+	if in.TagID != "" {
+		const prefix string = ",\"tagid\":"
+		out.RawString(prefix)
+		out.String(string(in.TagID))
+	}
+	if in.BidFloor != 0 {
+		const prefix string = ",\"bidfloor\":"
+		out.RawString(prefix)
+		out.Float64(float64(in.BidFloor))
+	}
+	if in.BidFloorCurrency != "" {
+		const prefix string = ",\"bidfloorcur\":"
+		out.RawString(prefix)
+		out.String(string(in.BidFloorCurrency))
+	}
+	if in.Secure != 0 {
+		const prefix string = ",\"secure\":"
+		out.RawString(prefix)
+		out.Int(int(in.Secure))
+	}
+	if in.Quantity != nil {
+		const prefix string = ",\"qty\":"
+		out.RawString(prefix)
+		easyjson7ebaa60bEncodeGithubComBsmOpenrtbV34(out, *in.Quantity)
+	}
+	if in.Exp != 0 {
+		const prefix string = ",\"exp\":"
+		out.RawString(prefix)
+		out.Int(int(in.Exp))
+	}
+	if len(in.IFrameBusters) != 0 {
+		const prefix string = ",\"iframebuster\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v2, v3 := range in.IFrameBusters {
+				if v2 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v3))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Impression) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson7ebaa60bEncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Impression) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson7ebaa60bEncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Impression) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson7ebaa60bDecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Impression) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson7ebaa60bDecodeGithubComBsmOpenrtbV3(l, v)
+}
+func easyjson7ebaa60bDecodeGithubComBsmOpenrtbV34(in *jlexer.Lexer, out *Quantity) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "multiplier":
+			out.Multiplier = float64(in.Float64())
+		case "sourcetype":
+			out.SourceType = MeasurementSourceType(in.Int())
+		case "vendor":
+			out.Vendor = string(in.String())
+		case "ext":
+			if in.IsNull() {
+				in.Skip()
+				out.Ext = nil
+			} else {
+				if out.Ext == nil {
+					out.Ext = new(json.RawMessage)
+				}
+				if data := in.Raw(); in.Ok() {
+					in.AddError((*out.Ext).UnmarshalJSON(data))
+				}
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson7ebaa60bEncodeGithubComBsmOpenrtbV34(out *jwriter.Writer, in Quantity) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"multiplier\":"
+		out.RawString(prefix[1:])
+		out.Float64(float64(in.Multiplier))
+	}
+	if in.SourceType != 0 {
+		const prefix string = ",\"sourcetype\":"
+		out.RawString(prefix)
+		out.Int(int(in.SourceType))
+	}
+	if in.Vendor != "" {
+		const prefix string = ",\"vendor\":"
+		out.RawString(prefix)
+		out.String(string(in.Vendor))
+	}
+	if in.Ext != nil {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((*in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson7ebaa60bDecodeGithubComBsmOpenrtbV33(in *jlexer.Lexer, out *PMP) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "private_auction":
+			out.Private = int(in.Int())
+		case "deals":
+			if in.IsNull() {
+				in.Skip()
+				out.Deals = nil
+			} else {
+				in.Delim('[')
+				if out.Deals == nil {
+					if !in.IsDelim(']') {
+						out.Deals = make([]Deal, 0, 0)
+					} else {
+						out.Deals = []Deal{}
+					}
+				} else {
+					out.Deals = (out.Deals)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v4 Deal
+					if data := in.Raw(); in.Ok() {
+						in.AddError((v4).UnmarshalJSON(data))
+					}
+					out.Deals = append(out.Deals, v4)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson7ebaa60bEncodeGithubComBsmOpenrtbV33(out *jwriter.Writer, in PMP) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Private != 0 {
+		const prefix string = ",\"private_auction\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.Private))
+	}
+	if len(in.Deals) != 0 {
+		const prefix string = ",\"deals\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v5, v6 := range in.Deals {
+				if v5 > 0 {
+					out.RawByte(',')
+				}
+				out.Raw((v6).MarshalJSON())
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson7ebaa60bDecodeGithubComBsmOpenrtbV32(in *jlexer.Lexer, out *Native) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "request":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Request).UnmarshalJSON(data))
+			}
+		case "ver":
+			out.Version = string(in.String())
+		case "api":
+			if in.IsNull() {
+				in.Skip()
+				out.APIs = nil
+			} else {
+				in.Delim('[')
+				if out.APIs == nil {
+					if !in.IsDelim(']') {
+						out.APIs = make([]APIFramework, 0, 8)
+					} else {
+						out.APIs = []APIFramework{}
+					}
+				} else {
+					out.APIs = (out.APIs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v7 APIFramework
+					v7 = APIFramework(in.Int())
+					out.APIs = append(out.APIs, v7)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "battr":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedAttrs = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedAttrs == nil {
+					if !in.IsDelim(']') {
+						out.BlockedAttrs = make([]CreativeAttribute, 0, 8)
+					} else {
+						out.BlockedAttrs = []CreativeAttribute{}
+					}
+				} else {
+					out.BlockedAttrs = (out.BlockedAttrs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v8 CreativeAttribute
+					v8 = CreativeAttribute(in.Int())
+					out.BlockedAttrs = append(out.BlockedAttrs, v8)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson7ebaa60bEncodeGithubComBsmOpenrtbV32(out *jwriter.Writer, in Native) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"request\":"
+		out.RawString(prefix[1:])
+		out.Raw((in.Request).MarshalJSON())
+	}
+	if in.Version != "" {
+		const prefix string = ",\"ver\":"
+		out.RawString(prefix)
+		out.String(string(in.Version))
+	}
+	if len(in.APIs) != 0 {
+		const prefix string = ",\"api\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v9, v10 := range in.APIs {
+				if v9 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v10))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.BlockedAttrs) != 0 {
+		const prefix string = ",\"battr\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v11, v12 := range in.BlockedAttrs {
+				if v11 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v12))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson7ebaa60bDecodeGithubComBsmOpenrtbV31(in *jlexer.Lexer, out *Banner) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "w":
+			out.Width = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "format":
+			if in.IsNull() {
+				in.Skip()
+				out.Formats = nil
+			} else {
+				in.Delim('[')
+				if out.Formats == nil {
+					if !in.IsDelim(']') {
+						out.Formats = make([]Format, 0, 1)
+					} else {
+						out.Formats = []Format{}
+					}
+				} else {
+					out.Formats = (out.Formats)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v13 Format
+					easyjson7ebaa60bDecodeGithubComBsmOpenrtbV35(in, &v13)
+					out.Formats = append(out.Formats, v13)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "wmax":
+			out.WidthMax = int(in.Int())
+		case "hmax":
+			out.HeightMax = int(in.Int())
+		case "wmin":
+			out.WidthMin = int(in.Int())
+		case "hmin":
+			out.HeightMin = int(in.Int())
+		case "id":
+			out.ID = string(in.String())
+		case "btype":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedTypes = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedTypes == nil {
+					if !in.IsDelim(']') {
+						out.BlockedTypes = make([]BannerType, 0, 8)
+					} else {
+						out.BlockedTypes = []BannerType{}
+					}
+				} else {
+					out.BlockedTypes = (out.BlockedTypes)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v14 BannerType
+					v14 = BannerType(in.Int())
+					out.BlockedTypes = append(out.BlockedTypes, v14)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "battr":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedAttrs = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedAttrs == nil {
+					if !in.IsDelim(']') {
+						out.BlockedAttrs = make([]CreativeAttribute, 0, 8)
+					} else {
+						out.BlockedAttrs = []CreativeAttribute{}
+					}
+				} else {
+					out.BlockedAttrs = (out.BlockedAttrs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v15 CreativeAttribute
+					v15 = CreativeAttribute(in.Int())
+					out.BlockedAttrs = append(out.BlockedAttrs, v15)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "pos":
+			out.Position = AdPosition(in.Int())
+		case "mimes":
+			if in.IsNull() {
+				in.Skip()
+				out.MIMEs = nil
+			} else {
+				in.Delim('[')
+				if out.MIMEs == nil {
+					if !in.IsDelim(']') {
+						out.MIMEs = make([]string, 0, 4)
+					} else {
+						out.MIMEs = []string{}
+					}
+				} else {
+					out.MIMEs = (out.MIMEs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v16 string
+					v16 = string(in.String())
+					out.MIMEs = append(out.MIMEs, v16)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "topframe":
+			out.TopFrame = int(in.Int())
+		case "expdir":
+			if in.IsNull() {
+				in.Skip()
+				out.ExpDirs = nil
+			} else {
+				in.Delim('[')
+				if out.ExpDirs == nil {
+					if !in.IsDelim(']') {
+						out.ExpDirs = make([]ExpDir, 0, 8)
+					} else {
+						out.ExpDirs = []ExpDir{}
+					}
+				} else {
+					out.ExpDirs = (out.ExpDirs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v17 ExpDir
+					v17 = ExpDir(in.Int())
+					out.ExpDirs = append(out.ExpDirs, v17)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "api":
+			if in.IsNull() {
+				in.Skip()
+				out.APIs = nil
+			} else {
+				in.Delim('[')
+				if out.APIs == nil {
+					if !in.IsDelim(']') {
+						out.APIs = make([]APIFramework, 0, 8)
+					} else {
+						out.APIs = []APIFramework{}
+					}
+				} else {
+					out.APIs = (out.APIs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v18 APIFramework
+					v18 = APIFramework(in.Int())
+					out.APIs = append(out.APIs, v18)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "vcm":
+			out.VCM = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson7ebaa60bEncodeGithubComBsmOpenrtbV31(out *jwriter.Writer, in Banner) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.Width))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if len(in.Formats) != 0 {
+		const prefix string = ",\"format\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v19, v20 := range in.Formats {
+				if v19 > 0 {
+					out.RawByte(',')
+				}
+				easyjson7ebaa60bEncodeGithubComBsmOpenrtbV35(out, v20)
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.WidthMax != 0 {
+		const prefix string = ",\"wmax\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthMax))
+	}
+	if in.HeightMax != 0 {
+		const prefix string = ",\"hmax\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.HeightMax))
+	}
+	if in.WidthMin != 0 {
+		const prefix string = ",\"wmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthMin))
+	}
+	if in.HeightMin != 0 {
+		const prefix string = ",\"hmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.HeightMin))
+	}
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ID))
+	}
+	if len(in.BlockedTypes) != 0 {
+		const prefix string = ",\"btype\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v21, v22 := range in.BlockedTypes {
+				if v21 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v22))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.BlockedAttrs) != 0 {
+		const prefix string = ",\"battr\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v23, v24 := range in.BlockedAttrs {
+				if v23 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v24))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Position != 0 {
+		const prefix string = ",\"pos\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Position))
+	}
+	if len(in.MIMEs) != 0 {
+		const prefix string = ",\"mimes\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v25, v26 := range in.MIMEs {
+				if v25 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v26))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.TopFrame != 0 {
+		const prefix string = ",\"topframe\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.TopFrame))
+	}
+	if len(in.ExpDirs) != 0 {
+		const prefix string = ",\"expdir\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v27, v28 := range in.ExpDirs {
+				if v27 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v28))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.APIs) != 0 {
+		const prefix string = ",\"api\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v29, v30 := range in.APIs {
+				if v29 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v30))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.VCM != 0 {
+		const prefix string = ",\"vcm\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.VCM))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson7ebaa60bDecodeGithubComBsmOpenrtbV35(in *jlexer.Lexer, out *Format) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "w":
+			out.Width = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "wratio":
+			out.WidthRatio = int(in.Int())
+		case "hration":
+			out.HeightRatio = int(in.Int())
+		case "wmin":
+			out.WidthMin = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson7ebaa60bEncodeGithubComBsmOpenrtbV35(out *jwriter.Writer, in Format) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.Width))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if in.WidthRatio != 0 {
+		const prefix string = ",\"wratio\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthRatio))
+	}
+	if in.HeightRatio != 0 {
+		const prefix string = ",\"hration\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.HeightRatio))
+	}
+	if in.WidthMin != 0 {
+		const prefix string = ",\"wmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthMin))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
diff --git a/inventory_easyjson.go b/inventory_easyjson.go
new file mode 100644
index 0000000..cd44e32
--- /dev/null
+++ b/inventory_easyjson.go
@@ -0,0 +1,1147 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson6f8bf452DecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *Site) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "page":
+			out.Page = string(in.String())
+		case "ref":
+			out.Referrer = string(in.String())
+		case "search":
+			out.Search = string(in.String())
+		case "mobile":
+			out.Mobile = int(in.Int())
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "domain":
+			out.Domain = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 ContentCategory
+					v1 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "sectioncat":
+			if in.IsNull() {
+				in.Skip()
+				out.SectionCategories = nil
+			} else {
+				in.Delim('[')
+				if out.SectionCategories == nil {
+					if !in.IsDelim(']') {
+						out.SectionCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.SectionCategories = []ContentCategory{}
+					}
+				} else {
+					out.SectionCategories = (out.SectionCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v2 ContentCategory
+					v2 = ContentCategory(in.String())
+					out.SectionCategories = append(out.SectionCategories, v2)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "pagecat":
+			if in.IsNull() {
+				in.Skip()
+				out.PageCategories = nil
+			} else {
+				in.Delim('[')
+				if out.PageCategories == nil {
+					if !in.IsDelim(']') {
+						out.PageCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.PageCategories = []ContentCategory{}
+					}
+				} else {
+					out.PageCategories = (out.PageCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v3 ContentCategory
+					v3 = ContentCategory(in.String())
+					out.PageCategories = append(out.PageCategories, v3)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "privacypolicy":
+			if in.IsNull() {
+				in.Skip()
+				out.PrivacyPolicy = nil
+			} else {
+				if out.PrivacyPolicy == nil {
+					out.PrivacyPolicy = new(int)
+				}
+				*out.PrivacyPolicy = int(in.Int())
+			}
+		case "publisher":
+			if in.IsNull() {
+				in.Skip()
+				out.Publisher = nil
+			} else {
+				if out.Publisher == nil {
+					out.Publisher = new(Publisher)
+				}
+				easyjson6f8bf452DecodeGithubComBsmOpenrtbV31(in, out.Publisher)
+			}
+		case "content":
+			if in.IsNull() {
+				in.Skip()
+				out.Content = nil
+			} else {
+				if out.Content == nil {
+					out.Content = new(Content)
+				}
+				(*out.Content).UnmarshalEasyJSON(in)
+			}
+		case "keywords":
+			out.Keywords = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson6f8bf452EncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in Site) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Page != "" {
+		const prefix string = ",\"page\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Page))
+	}
+	if in.Referrer != "" {
+		const prefix string = ",\"ref\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Referrer))
+	}
+	if in.Search != "" {
+		const prefix string = ",\"search\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Search))
+	}
+	if in.Mobile != 0 {
+		const prefix string = ",\"mobile\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Mobile))
+	}
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v4, v5 := range in.Categories {
+				if v4 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v5))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.SectionCategories) != 0 {
+		const prefix string = ",\"sectioncat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v6, v7 := range in.SectionCategories {
+				if v6 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v7))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.PageCategories) != 0 {
+		const prefix string = ",\"pagecat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v8, v9 := range in.PageCategories {
+				if v8 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v9))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.PrivacyPolicy != nil {
+		const prefix string = ",\"privacypolicy\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(*in.PrivacyPolicy))
+	}
+	if in.Publisher != nil {
+		const prefix string = ",\"publisher\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson6f8bf452EncodeGithubComBsmOpenrtbV31(out, *in.Publisher)
+	}
+	if in.Content != nil {
+		const prefix string = ",\"content\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		(*in.Content).MarshalEasyJSON(out)
+	}
+	if in.Keywords != "" {
+		const prefix string = ",\"keywords\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Keywords))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Site) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson6f8bf452EncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Site) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson6f8bf452EncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Site) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson6f8bf452DecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Site) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson6f8bf452DecodeGithubComBsmOpenrtbV3(l, v)
+}
+func easyjson6f8bf452DecodeGithubComBsmOpenrtbV31(in *jlexer.Lexer, out *Publisher) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v10 ContentCategory
+					v10 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v10)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "domain":
+			out.Domain = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson6f8bf452EncodeGithubComBsmOpenrtbV31(out *jwriter.Writer, in Publisher) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v11, v12 := range in.Categories {
+				if v11 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v12))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson6f8bf452DecodeGithubComBsmOpenrtbV32(in *jlexer.Lexer, out *Inventory) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "domain":
+			out.Domain = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v13 ContentCategory
+					v13 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v13)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "sectioncat":
+			if in.IsNull() {
+				in.Skip()
+				out.SectionCategories = nil
+			} else {
+				in.Delim('[')
+				if out.SectionCategories == nil {
+					if !in.IsDelim(']') {
+						out.SectionCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.SectionCategories = []ContentCategory{}
+					}
+				} else {
+					out.SectionCategories = (out.SectionCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v14 ContentCategory
+					v14 = ContentCategory(in.String())
+					out.SectionCategories = append(out.SectionCategories, v14)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "pagecat":
+			if in.IsNull() {
+				in.Skip()
+				out.PageCategories = nil
+			} else {
+				in.Delim('[')
+				if out.PageCategories == nil {
+					if !in.IsDelim(']') {
+						out.PageCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.PageCategories = []ContentCategory{}
+					}
+				} else {
+					out.PageCategories = (out.PageCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v15 ContentCategory
+					v15 = ContentCategory(in.String())
+					out.PageCategories = append(out.PageCategories, v15)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "privacypolicy":
+			if in.IsNull() {
+				in.Skip()
+				out.PrivacyPolicy = nil
+			} else {
+				if out.PrivacyPolicy == nil {
+					out.PrivacyPolicy = new(int)
+				}
+				*out.PrivacyPolicy = int(in.Int())
+			}
+		case "publisher":
+			if in.IsNull() {
+				in.Skip()
+				out.Publisher = nil
+			} else {
+				if out.Publisher == nil {
+					out.Publisher = new(Publisher)
+				}
+				easyjson6f8bf452DecodeGithubComBsmOpenrtbV31(in, out.Publisher)
+			}
+		case "content":
+			if in.IsNull() {
+				in.Skip()
+				out.Content = nil
+			} else {
+				if out.Content == nil {
+					out.Content = new(Content)
+				}
+				(*out.Content).UnmarshalEasyJSON(in)
+			}
+		case "keywords":
+			out.Keywords = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson6f8bf452EncodeGithubComBsmOpenrtbV32(out *jwriter.Writer, in Inventory) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v16, v17 := range in.Categories {
+				if v16 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v17))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.SectionCategories) != 0 {
+		const prefix string = ",\"sectioncat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v18, v19 := range in.SectionCategories {
+				if v18 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v19))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.PageCategories) != 0 {
+		const prefix string = ",\"pagecat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v20, v21 := range in.PageCategories {
+				if v20 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v21))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.PrivacyPolicy != nil {
+		const prefix string = ",\"privacypolicy\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(*in.PrivacyPolicy))
+	}
+	if in.Publisher != nil {
+		const prefix string = ",\"publisher\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson6f8bf452EncodeGithubComBsmOpenrtbV31(out, *in.Publisher)
+	}
+	if in.Content != nil {
+		const prefix string = ",\"content\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		(*in.Content).MarshalEasyJSON(out)
+	}
+	if in.Keywords != "" {
+		const prefix string = ",\"keywords\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Keywords))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Inventory) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson6f8bf452EncodeGithubComBsmOpenrtbV32(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Inventory) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson6f8bf452EncodeGithubComBsmOpenrtbV32(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Inventory) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson6f8bf452DecodeGithubComBsmOpenrtbV32(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Inventory) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson6f8bf452DecodeGithubComBsmOpenrtbV32(l, v)
+}
+func easyjson6f8bf452DecodeGithubComBsmOpenrtbV33(in *jlexer.Lexer, out *App) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "bundle":
+			out.Bundle = string(in.String())
+		case "storeurl":
+			out.StoreURL = string(in.String())
+		case "ver":
+			out.Version = string(in.String())
+		case "paid":
+			out.Paid = int(in.Int())
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "domain":
+			out.Domain = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v22 ContentCategory
+					v22 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v22)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "sectioncat":
+			if in.IsNull() {
+				in.Skip()
+				out.SectionCategories = nil
+			} else {
+				in.Delim('[')
+				if out.SectionCategories == nil {
+					if !in.IsDelim(']') {
+						out.SectionCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.SectionCategories = []ContentCategory{}
+					}
+				} else {
+					out.SectionCategories = (out.SectionCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v23 ContentCategory
+					v23 = ContentCategory(in.String())
+					out.SectionCategories = append(out.SectionCategories, v23)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "pagecat":
+			if in.IsNull() {
+				in.Skip()
+				out.PageCategories = nil
+			} else {
+				in.Delim('[')
+				if out.PageCategories == nil {
+					if !in.IsDelim(']') {
+						out.PageCategories = make([]ContentCategory, 0, 4)
+					} else {
+						out.PageCategories = []ContentCategory{}
+					}
+				} else {
+					out.PageCategories = (out.PageCategories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v24 ContentCategory
+					v24 = ContentCategory(in.String())
+					out.PageCategories = append(out.PageCategories, v24)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "privacypolicy":
+			if in.IsNull() {
+				in.Skip()
+				out.PrivacyPolicy = nil
+			} else {
+				if out.PrivacyPolicy == nil {
+					out.PrivacyPolicy = new(int)
+				}
+				*out.PrivacyPolicy = int(in.Int())
+			}
+		case "publisher":
+			if in.IsNull() {
+				in.Skip()
+				out.Publisher = nil
+			} else {
+				if out.Publisher == nil {
+					out.Publisher = new(Publisher)
+				}
+				easyjson6f8bf452DecodeGithubComBsmOpenrtbV31(in, out.Publisher)
+			}
+		case "content":
+			if in.IsNull() {
+				in.Skip()
+				out.Content = nil
+			} else {
+				if out.Content == nil {
+					out.Content = new(Content)
+				}
+				(*out.Content).UnmarshalEasyJSON(in)
+			}
+		case "keywords":
+			out.Keywords = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson6f8bf452EncodeGithubComBsmOpenrtbV33(out *jwriter.Writer, in App) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Bundle != "" {
+		const prefix string = ",\"bundle\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Bundle))
+	}
+	if in.StoreURL != "" {
+		const prefix string = ",\"storeurl\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.StoreURL))
+	}
+	if in.Version != "" {
+		const prefix string = ",\"ver\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Version))
+	}
+	if in.Paid != 0 {
+		const prefix string = ",\"paid\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Paid))
+	}
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v25, v26 := range in.Categories {
+				if v25 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v26))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.SectionCategories) != 0 {
+		const prefix string = ",\"sectioncat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v27, v28 := range in.SectionCategories {
+				if v27 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v28))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.PageCategories) != 0 {
+		const prefix string = ",\"pagecat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v29, v30 := range in.PageCategories {
+				if v29 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v30))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.PrivacyPolicy != nil {
+		const prefix string = ",\"privacypolicy\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(*in.PrivacyPolicy))
+	}
+	if in.Publisher != nil {
+		const prefix string = ",\"publisher\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		easyjson6f8bf452EncodeGithubComBsmOpenrtbV31(out, *in.Publisher)
+	}
+	if in.Content != nil {
+		const prefix string = ",\"content\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		(*in.Content).MarshalEasyJSON(out)
+	}
+	if in.Keywords != "" {
+		const prefix string = ",\"keywords\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Keywords))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v App) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson6f8bf452EncodeGithubComBsmOpenrtbV33(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v App) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson6f8bf452EncodeGithubComBsmOpenrtbV33(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *App) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson6f8bf452DecodeGithubComBsmOpenrtbV33(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *App) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson6f8bf452DecodeGithubComBsmOpenrtbV33(l, v)
+}
diff --git a/native/request/asset_easyjson.go b/native/request/asset_easyjson.go
new file mode 100644
index 0000000..a97f298
--- /dev/null
+++ b/native/request/asset_easyjson.go
@@ -0,0 +1,571 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package request
+
+import (
+	json "encoding/json"
+	_v3 "github.com/bsm/openrtb/v3"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest(in *jlexer.Lexer, out *Asset) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = int(in.Int())
+		case "required":
+			out.Required = int(in.Int())
+		case "title":
+			if in.IsNull() {
+				in.Skip()
+				out.Title = nil
+			} else {
+				if out.Title == nil {
+					out.Title = new(Title)
+				}
+				easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest1(in, out.Title)
+			}
+		case "img":
+			if in.IsNull() {
+				in.Skip()
+				out.Image = nil
+			} else {
+				if out.Image == nil {
+					out.Image = new(Image)
+				}
+				easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest2(in, out.Image)
+			}
+		case "video":
+			if in.IsNull() {
+				in.Skip()
+				out.Video = nil
+			} else {
+				if out.Video == nil {
+					out.Video = new(Video)
+				}
+				easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest3(in, out.Video)
+			}
+		case "data":
+			if in.IsNull() {
+				in.Skip()
+				out.Data = nil
+			} else {
+				if out.Data == nil {
+					out.Data = new(Data)
+				}
+				easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest4(in, out.Data)
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest(out *jwriter.Writer, in Asset) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"id\":"
+		out.RawString(prefix[1:])
+		out.Int(int(in.ID))
+	}
+	if in.Required != 0 {
+		const prefix string = ",\"required\":"
+		out.RawString(prefix)
+		out.Int(int(in.Required))
+	}
+	if in.Title != nil {
+		const prefix string = ",\"title\":"
+		out.RawString(prefix)
+		easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest1(out, *in.Title)
+	}
+	if in.Image != nil {
+		const prefix string = ",\"img\":"
+		out.RawString(prefix)
+		easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest2(out, *in.Image)
+	}
+	if in.Video != nil {
+		const prefix string = ",\"video\":"
+		out.RawString(prefix)
+		easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest3(out, *in.Video)
+	}
+	if in.Data != nil {
+		const prefix string = ",\"data\":"
+		out.RawString(prefix)
+		easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest4(out, *in.Data)
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Asset) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Asset) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Asset) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Asset) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest(l, v)
+}
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest4(in *jlexer.Lexer, out *Data) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "type":
+			out.TypeID = DataTypeID(in.Int())
+		case "len":
+			out.Length = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest4(out *jwriter.Writer, in Data) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"type\":"
+		out.RawString(prefix[1:])
+		out.Int(int(in.TypeID))
+	}
+	{
+		const prefix string = ",\"len\":"
+		out.RawString(prefix)
+		out.Int(int(in.Length))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest3(in *jlexer.Lexer, out *Video) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "mimes":
+			if in.IsNull() {
+				in.Skip()
+				out.MIMEs = nil
+			} else {
+				in.Delim('[')
+				if out.MIMEs == nil {
+					if !in.IsDelim(']') {
+						out.MIMEs = make([]string, 0, 4)
+					} else {
+						out.MIMEs = []string{}
+					}
+				} else {
+					out.MIMEs = (out.MIMEs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 string
+					v1 = string(in.String())
+					out.MIMEs = append(out.MIMEs, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "minduration":
+			out.MinDuration = int(in.Int())
+		case "maxduration":
+			out.MaxDuration = int(in.Int())
+		case "protocols":
+			if in.IsNull() {
+				in.Skip()
+				out.Protocols = nil
+			} else {
+				in.Delim('[')
+				if out.Protocols == nil {
+					if !in.IsDelim(']') {
+						out.Protocols = make([]_v3.Protocol, 0, 8)
+					} else {
+						out.Protocols = []_v3.Protocol{}
+					}
+				} else {
+					out.Protocols = (out.Protocols)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v2 _v3.Protocol
+					v2 = _v3.Protocol(in.Int())
+					out.Protocols = append(out.Protocols, v2)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest3(out *jwriter.Writer, in Video) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if len(in.MIMEs) != 0 {
+		const prefix string = ",\"mimes\":"
+		first = false
+		out.RawString(prefix[1:])
+		{
+			out.RawByte('[')
+			for v3, v4 := range in.MIMEs {
+				if v3 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v4))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.MinDuration != 0 {
+		const prefix string = ",\"minduration\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.MinDuration))
+	}
+	if in.MaxDuration != 0 {
+		const prefix string = ",\"maxduration\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.MaxDuration))
+	}
+	if len(in.Protocols) != 0 {
+		const prefix string = ",\"protocols\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v5, v6 := range in.Protocols {
+				if v5 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v6))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest2(in *jlexer.Lexer, out *Image) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "type":
+			out.TypeID = ImageTypeID(in.Int())
+		case "w":
+			out.Width = int(in.Int())
+		case "wmin":
+			out.WidthMin = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "hmin":
+			out.HeightMin = int(in.Int())
+		case "mimes":
+			if in.IsNull() {
+				in.Skip()
+				out.MIMEs = nil
+			} else {
+				in.Delim('[')
+				if out.MIMEs == nil {
+					if !in.IsDelim(']') {
+						out.MIMEs = make([]string, 0, 4)
+					} else {
+						out.MIMEs = []string{}
+					}
+				} else {
+					out.MIMEs = (out.MIMEs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v7 string
+					v7 = string(in.String())
+					out.MIMEs = append(out.MIMEs, v7)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest2(out *jwriter.Writer, in Image) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.TypeID != 0 {
+		const prefix string = ",\"type\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.TypeID))
+	}
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Width))
+	}
+	if in.WidthMin != 0 {
+		const prefix string = ",\"wmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthMin))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if in.HeightMin != 0 {
+		const prefix string = ",\"hmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.HeightMin))
+	}
+	if len(in.MIMEs) != 0 {
+		const prefix string = ",\"mimes\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v8, v9 := range in.MIMEs {
+				if v8 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v9))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeRequest1(in *jlexer.Lexer, out *Title) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "len":
+			out.Length = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeRequest1(out *jwriter.Writer, in Title) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"len\":"
+		out.RawString(prefix[1:])
+		out.Int(int(in.Length))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
diff --git a/native/request/data_easyjson.go b/native/request/data_easyjson.go
new file mode 100644
index 0000000..b1c56fe
--- /dev/null
+++ b/native/request/data_easyjson.go
@@ -0,0 +1,101 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package request
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson794297d0DecodeGithubComBsmOpenrtbV3NativeRequest(in *jlexer.Lexer, out *Data) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "type":
+			out.TypeID = DataTypeID(in.Int())
+		case "len":
+			out.Length = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson794297d0EncodeGithubComBsmOpenrtbV3NativeRequest(out *jwriter.Writer, in Data) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"type\":"
+		out.RawString(prefix[1:])
+		out.Int(int(in.TypeID))
+	}
+	{
+		const prefix string = ",\"len\":"
+		out.RawString(prefix)
+		out.Int(int(in.Length))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Data) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson794297d0EncodeGithubComBsmOpenrtbV3NativeRequest(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Data) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson794297d0EncodeGithubComBsmOpenrtbV3NativeRequest(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Data) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson794297d0DecodeGithubComBsmOpenrtbV3NativeRequest(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Data) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson794297d0DecodeGithubComBsmOpenrtbV3NativeRequest(l, v)
+}
diff --git a/native/request/image_easyjson.go b/native/request/image_easyjson.go
new file mode 100644
index 0000000..e7407fd
--- /dev/null
+++ b/native/request/image_easyjson.go
@@ -0,0 +1,190 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package request
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson220accf5DecodeGithubComBsmOpenrtbV3NativeRequest(in *jlexer.Lexer, out *Image) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "type":
+			out.TypeID = ImageTypeID(in.Int())
+		case "w":
+			out.Width = int(in.Int())
+		case "wmin":
+			out.WidthMin = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "hmin":
+			out.HeightMin = int(in.Int())
+		case "mimes":
+			if in.IsNull() {
+				in.Skip()
+				out.MIMEs = nil
+			} else {
+				in.Delim('[')
+				if out.MIMEs == nil {
+					if !in.IsDelim(']') {
+						out.MIMEs = make([]string, 0, 4)
+					} else {
+						out.MIMEs = []string{}
+					}
+				} else {
+					out.MIMEs = (out.MIMEs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 string
+					v1 = string(in.String())
+					out.MIMEs = append(out.MIMEs, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson220accf5EncodeGithubComBsmOpenrtbV3NativeRequest(out *jwriter.Writer, in Image) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.TypeID != 0 {
+		const prefix string = ",\"type\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.TypeID))
+	}
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Width))
+	}
+	if in.WidthMin != 0 {
+		const prefix string = ",\"wmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthMin))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if in.HeightMin != 0 {
+		const prefix string = ",\"hmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.HeightMin))
+	}
+	if len(in.MIMEs) != 0 {
+		const prefix string = ",\"mimes\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v2, v3 := range in.MIMEs {
+				if v2 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v3))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Image) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson220accf5EncodeGithubComBsmOpenrtbV3NativeRequest(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Image) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson220accf5EncodeGithubComBsmOpenrtbV3NativeRequest(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Image) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson220accf5DecodeGithubComBsmOpenrtbV3NativeRequest(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Image) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson220accf5DecodeGithubComBsmOpenrtbV3NativeRequest(l, v)
+}
diff --git a/native/request/request_easyjson.go b/native/request/request_easyjson.go
new file mode 100644
index 0000000..7e88858
--- /dev/null
+++ b/native/request/request_easyjson.go
@@ -0,0 +1,223 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package request
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson3c9d2b01DecodeGithubComBsmOpenrtbV3NativeRequest(in *jlexer.Lexer, out *Request) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "ver":
+			out.Version = string(in.String())
+		case "layout":
+			out.LayoutID = LayoutID(in.Int())
+		case "adunit":
+			out.AdUnitID = AdUnitID(in.Int())
+		case "context":
+			out.ContextTypeID = ContextTypeID(in.Int())
+		case "contextsubtype":
+			out.ContextSubTypeID = ContextTypeID(in.Int())
+		case "plcmttype":
+			out.PlacementTypeID = PlacementTypeID(in.Int())
+		case "plcmtcnt":
+			out.PlacementCount = int(in.Int())
+		case "seq":
+			out.Sequence = int(in.Int())
+		case "assets":
+			if in.IsNull() {
+				in.Skip()
+				out.Assets = nil
+			} else {
+				in.Delim('[')
+				if out.Assets == nil {
+					if !in.IsDelim(']') {
+						out.Assets = make([]Asset, 0, 0)
+					} else {
+						out.Assets = []Asset{}
+					}
+				} else {
+					out.Assets = (out.Assets)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 Asset
+					(v1).UnmarshalEasyJSON(in)
+					out.Assets = append(out.Assets, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3c9d2b01EncodeGithubComBsmOpenrtbV3NativeRequest(out *jwriter.Writer, in Request) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Version != "" {
+		const prefix string = ",\"ver\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Version))
+	}
+	if in.LayoutID != 0 {
+		const prefix string = ",\"layout\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.LayoutID))
+	}
+	if in.AdUnitID != 0 {
+		const prefix string = ",\"adunit\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.AdUnitID))
+	}
+	if in.ContextTypeID != 0 {
+		const prefix string = ",\"context\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.ContextTypeID))
+	}
+	if in.ContextSubTypeID != 0 {
+		const prefix string = ",\"contextsubtype\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.ContextSubTypeID))
+	}
+	if in.PlacementTypeID != 0 {
+		const prefix string = ",\"plcmttype\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.PlacementTypeID))
+	}
+	if in.PlacementCount != 0 {
+		const prefix string = ",\"plcmtcnt\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.PlacementCount))
+	}
+	if in.Sequence != 0 {
+		const prefix string = ",\"seq\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Sequence))
+	}
+	{
+		const prefix string = ",\"assets\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		if in.Assets == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
+			out.RawString("null")
+		} else {
+			out.RawByte('[')
+			for v2, v3 := range in.Assets {
+				if v2 > 0 {
+					out.RawByte(',')
+				}
+				(v3).MarshalEasyJSON(out)
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Request) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson3c9d2b01EncodeGithubComBsmOpenrtbV3NativeRequest(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Request) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson3c9d2b01EncodeGithubComBsmOpenrtbV3NativeRequest(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Request) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson3c9d2b01DecodeGithubComBsmOpenrtbV3NativeRequest(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Request) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson3c9d2b01DecodeGithubComBsmOpenrtbV3NativeRequest(l, v)
+}
diff --git a/native/request/title_easyjson.go b/native/request/title_easyjson.go
new file mode 100644
index 0000000..682b7b6
--- /dev/null
+++ b/native/request/title_easyjson.go
@@ -0,0 +1,94 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package request
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjsonE7952480DecodeGithubComBsmOpenrtbV3NativeRequest(in *jlexer.Lexer, out *Title) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "len":
+			out.Length = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonE7952480EncodeGithubComBsmOpenrtbV3NativeRequest(out *jwriter.Writer, in Title) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"len\":"
+		out.RawString(prefix[1:])
+		out.Int(int(in.Length))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Title) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonE7952480EncodeGithubComBsmOpenrtbV3NativeRequest(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Title) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonE7952480EncodeGithubComBsmOpenrtbV3NativeRequest(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Title) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonE7952480DecodeGithubComBsmOpenrtbV3NativeRequest(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Title) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonE7952480DecodeGithubComBsmOpenrtbV3NativeRequest(l, v)
+}
diff --git a/native/request/video_easyjson.go b/native/request/video_easyjson.go
new file mode 100644
index 0000000..6029d4c
--- /dev/null
+++ b/native/request/video_easyjson.go
@@ -0,0 +1,197 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package request
+
+import (
+	json "encoding/json"
+	_v3 "github.com/bsm/openrtb/v3"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson3c9ce8c3DecodeGithubComBsmOpenrtbV3NativeRequest(in *jlexer.Lexer, out *Video) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "mimes":
+			if in.IsNull() {
+				in.Skip()
+				out.MIMEs = nil
+			} else {
+				in.Delim('[')
+				if out.MIMEs == nil {
+					if !in.IsDelim(']') {
+						out.MIMEs = make([]string, 0, 4)
+					} else {
+						out.MIMEs = []string{}
+					}
+				} else {
+					out.MIMEs = (out.MIMEs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 string
+					v1 = string(in.String())
+					out.MIMEs = append(out.MIMEs, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "minduration":
+			out.MinDuration = int(in.Int())
+		case "maxduration":
+			out.MaxDuration = int(in.Int())
+		case "protocols":
+			if in.IsNull() {
+				in.Skip()
+				out.Protocols = nil
+			} else {
+				in.Delim('[')
+				if out.Protocols == nil {
+					if !in.IsDelim(']') {
+						out.Protocols = make([]_v3.Protocol, 0, 8)
+					} else {
+						out.Protocols = []_v3.Protocol{}
+					}
+				} else {
+					out.Protocols = (out.Protocols)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v2 _v3.Protocol
+					v2 = _v3.Protocol(in.Int())
+					out.Protocols = append(out.Protocols, v2)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3c9ce8c3EncodeGithubComBsmOpenrtbV3NativeRequest(out *jwriter.Writer, in Video) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if len(in.MIMEs) != 0 {
+		const prefix string = ",\"mimes\":"
+		first = false
+		out.RawString(prefix[1:])
+		{
+			out.RawByte('[')
+			for v3, v4 := range in.MIMEs {
+				if v3 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v4))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.MinDuration != 0 {
+		const prefix string = ",\"minduration\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.MinDuration))
+	}
+	if in.MaxDuration != 0 {
+		const prefix string = ",\"maxduration\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.MaxDuration))
+	}
+	if len(in.Protocols) != 0 {
+		const prefix string = ",\"protocols\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v5, v6 := range in.Protocols {
+				if v5 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v6))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Video) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson3c9ce8c3EncodeGithubComBsmOpenrtbV3NativeRequest(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Video) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson3c9ce8c3EncodeGithubComBsmOpenrtbV3NativeRequest(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Video) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson3c9ce8c3DecodeGithubComBsmOpenrtbV3NativeRequest(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Video) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson3c9ce8c3DecodeGithubComBsmOpenrtbV3NativeRequest(l, v)
+}
diff --git a/native/response/asset_easyjson.go b/native/response/asset_easyjson.go
new file mode 100644
index 0000000..eb2b182
--- /dev/null
+++ b/native/response/asset_easyjson.go
@@ -0,0 +1,509 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package response
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer, out *Asset) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = int(in.Int())
+		case "required":
+			out.Required = int(in.Int())
+		case "title":
+			if in.IsNull() {
+				in.Skip()
+				out.Title = nil
+			} else {
+				if out.Title == nil {
+					out.Title = new(Title)
+				}
+				easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse1(in, out.Title)
+			}
+		case "img":
+			if in.IsNull() {
+				in.Skip()
+				out.Image = nil
+			} else {
+				if out.Image == nil {
+					out.Image = new(Image)
+				}
+				easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse2(in, out.Image)
+			}
+		case "video":
+			if in.IsNull() {
+				in.Skip()
+				out.Video = nil
+			} else {
+				if out.Video == nil {
+					out.Video = new(Video)
+				}
+				easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse3(in, out.Video)
+			}
+		case "data":
+			if in.IsNull() {
+				in.Skip()
+				out.Data = nil
+			} else {
+				if out.Data == nil {
+					out.Data = new(Data)
+				}
+				easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse4(in, out.Data)
+			}
+		case "link":
+			if in.IsNull() {
+				in.Skip()
+				out.Link = nil
+			} else {
+				if out.Link == nil {
+					out.Link = new(Link)
+				}
+				easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse5(in, out.Link)
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writer, in Asset) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"id\":"
+		out.RawString(prefix[1:])
+		out.Int(int(in.ID))
+	}
+	if in.Required != 0 {
+		const prefix string = ",\"required\":"
+		out.RawString(prefix)
+		out.Int(int(in.Required))
+	}
+	if in.Title != nil {
+		const prefix string = ",\"title\":"
+		out.RawString(prefix)
+		easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse1(out, *in.Title)
+	}
+	if in.Image != nil {
+		const prefix string = ",\"img\":"
+		out.RawString(prefix)
+		easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse2(out, *in.Image)
+	}
+	if in.Video != nil {
+		const prefix string = ",\"video\":"
+		out.RawString(prefix)
+		easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse3(out, *in.Video)
+	}
+	if in.Data != nil {
+		const prefix string = ",\"data\":"
+		out.RawString(prefix)
+		easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse4(out, *in.Data)
+	}
+	if in.Link != nil {
+		const prefix string = ",\"link\":"
+		out.RawString(prefix)
+		easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse5(out, *in.Link)
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Asset) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Asset) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Asset) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Asset) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse(l, v)
+}
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse5(in *jlexer.Lexer, out *Link) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "url":
+			out.URL = string(in.String())
+		case "clicktrackers":
+			if in.IsNull() {
+				in.Skip()
+				out.ClickTrackers = nil
+			} else {
+				in.Delim('[')
+				if out.ClickTrackers == nil {
+					if !in.IsDelim(']') {
+						out.ClickTrackers = make([]string, 0, 4)
+					} else {
+						out.ClickTrackers = []string{}
+					}
+				} else {
+					out.ClickTrackers = (out.ClickTrackers)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 string
+					v1 = string(in.String())
+					out.ClickTrackers = append(out.ClickTrackers, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "fallback":
+			out.FallbackURL = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse5(out *jwriter.Writer, in Link) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"url\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.URL))
+	}
+	if len(in.ClickTrackers) != 0 {
+		const prefix string = ",\"clicktrackers\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v2, v3 := range in.ClickTrackers {
+				if v2 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v3))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.FallbackURL != "" {
+		const prefix string = ",\"fallback\":"
+		out.RawString(prefix)
+		out.String(string(in.FallbackURL))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse4(in *jlexer.Lexer, out *Data) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "label":
+			out.Label = string(in.String())
+		case "value":
+			out.Value = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse4(out *jwriter.Writer, in Data) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Label != "" {
+		const prefix string = ",\"label\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Label))
+	}
+	{
+		const prefix string = ",\"value\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Value))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse3(in *jlexer.Lexer, out *Video) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "vasttag":
+			out.VASTTag = string(in.String())
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse3(out *jwriter.Writer, in Video) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"vasttag\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.VASTTag))
+	}
+	out.RawByte('}')
+}
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse2(in *jlexer.Lexer, out *Image) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "url":
+			out.URL = string(in.String())
+		case "w":
+			out.Width = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse2(out *jwriter.Writer, in Image) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.URL != "" {
+		const prefix string = ",\"url\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.URL))
+	}
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Width))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+func easyjson3b94576aDecodeGithubComBsmOpenrtbV3NativeResponse1(in *jlexer.Lexer, out *Title) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "text":
+			out.Text = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3b94576aEncodeGithubComBsmOpenrtbV3NativeResponse1(out *jwriter.Writer, in Title) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"text\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.Text))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
diff --git a/native/response/data_easyjson.go b/native/response/data_easyjson.go
new file mode 100644
index 0000000..4c6e916
--- /dev/null
+++ b/native/response/data_easyjson.go
@@ -0,0 +1,107 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package response
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson794297d0DecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer, out *Data) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "label":
+			out.Label = string(in.String())
+		case "value":
+			out.Value = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson794297d0EncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writer, in Data) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Label != "" {
+		const prefix string = ",\"label\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Label))
+	}
+	{
+		const prefix string = ",\"value\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Value))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Data) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson794297d0EncodeGithubComBsmOpenrtbV3NativeResponse(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Data) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson794297d0EncodeGithubComBsmOpenrtbV3NativeResponse(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Data) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson794297d0DecodeGithubComBsmOpenrtbV3NativeResponse(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Data) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson794297d0DecodeGithubComBsmOpenrtbV3NativeResponse(l, v)
+}
diff --git a/native/response/image_easyjson.go b/native/response/image_easyjson.go
new file mode 100644
index 0000000..6a9829c
--- /dev/null
+++ b/native/response/image_easyjson.go
@@ -0,0 +1,124 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package response
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson220accf5DecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer, out *Image) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "url":
+			out.URL = string(in.String())
+		case "w":
+			out.Width = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson220accf5EncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writer, in Image) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.URL != "" {
+		const prefix string = ",\"url\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.URL))
+	}
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Width))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Image) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson220accf5EncodeGithubComBsmOpenrtbV3NativeResponse(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Image) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson220accf5EncodeGithubComBsmOpenrtbV3NativeResponse(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Image) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson220accf5DecodeGithubComBsmOpenrtbV3NativeResponse(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Image) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson220accf5DecodeGithubComBsmOpenrtbV3NativeResponse(l, v)
+}
diff --git a/native/response/link_easyjson.go b/native/response/link_easyjson.go
new file mode 100644
index 0000000..9569e5d
--- /dev/null
+++ b/native/response/link_easyjson.go
@@ -0,0 +1,138 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package response
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson16eb09bcDecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer, out *Link) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "url":
+			out.URL = string(in.String())
+		case "clicktrackers":
+			if in.IsNull() {
+				in.Skip()
+				out.ClickTrackers = nil
+			} else {
+				in.Delim('[')
+				if out.ClickTrackers == nil {
+					if !in.IsDelim(']') {
+						out.ClickTrackers = make([]string, 0, 4)
+					} else {
+						out.ClickTrackers = []string{}
+					}
+				} else {
+					out.ClickTrackers = (out.ClickTrackers)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 string
+					v1 = string(in.String())
+					out.ClickTrackers = append(out.ClickTrackers, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "fallback":
+			out.FallbackURL = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson16eb09bcEncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writer, in Link) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"url\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.URL))
+	}
+	if len(in.ClickTrackers) != 0 {
+		const prefix string = ",\"clicktrackers\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v2, v3 := range in.ClickTrackers {
+				if v2 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v3))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.FallbackURL != "" {
+		const prefix string = ",\"fallback\":"
+		out.RawString(prefix)
+		out.String(string(in.FallbackURL))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Link) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson16eb09bcEncodeGithubComBsmOpenrtbV3NativeResponse(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Link) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson16eb09bcEncodeGithubComBsmOpenrtbV3NativeResponse(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Link) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson16eb09bcDecodeGithubComBsmOpenrtbV3NativeResponse(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Link) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson16eb09bcDecodeGithubComBsmOpenrtbV3NativeResponse(l, v)
+}
diff --git a/native/response/response_easyjson.go b/native/response/response_easyjson.go
new file mode 100644
index 0000000..edf6adc
--- /dev/null
+++ b/native/response/response_easyjson.go
@@ -0,0 +1,192 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package response
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson6ff3ac1dDecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer, out *Response) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "ver":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Version).UnmarshalJSON(data))
+			}
+		case "assets":
+			if in.IsNull() {
+				in.Skip()
+				out.Assets = nil
+			} else {
+				in.Delim('[')
+				if out.Assets == nil {
+					if !in.IsDelim(']') {
+						out.Assets = make([]Asset, 0, 0)
+					} else {
+						out.Assets = []Asset{}
+					}
+				} else {
+					out.Assets = (out.Assets)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 Asset
+					(v1).UnmarshalEasyJSON(in)
+					out.Assets = append(out.Assets, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "link":
+			(out.Link).UnmarshalEasyJSON(in)
+		case "imptrackers":
+			if in.IsNull() {
+				in.Skip()
+				out.ImpTrackers = nil
+			} else {
+				in.Delim('[')
+				if out.ImpTrackers == nil {
+					if !in.IsDelim(']') {
+						out.ImpTrackers = make([]string, 0, 4)
+					} else {
+						out.ImpTrackers = []string{}
+					}
+				} else {
+					out.ImpTrackers = (out.ImpTrackers)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v2 string
+					v2 = string(in.String())
+					out.ImpTrackers = append(out.ImpTrackers, v2)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "jstracker":
+			out.JSTracker = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writer, in Response) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Version != "" {
+		const prefix string = ",\"ver\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Version))
+	}
+	{
+		const prefix string = ",\"assets\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		if in.Assets == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
+			out.RawString("null")
+		} else {
+			out.RawByte('[')
+			for v3, v4 := range in.Assets {
+				if v3 > 0 {
+					out.RawByte(',')
+				}
+				(v4).MarshalEasyJSON(out)
+			}
+			out.RawByte(']')
+		}
+	}
+	{
+		const prefix string = ",\"link\":"
+		out.RawString(prefix)
+		(in.Link).MarshalEasyJSON(out)
+	}
+	if len(in.ImpTrackers) != 0 {
+		const prefix string = ",\"imptrackers\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v5, v6 := range in.ImpTrackers {
+				if v5 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v6))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.JSTracker != "" {
+		const prefix string = ",\"jstracker\":"
+		out.RawString(prefix)
+		out.String(string(in.JSTracker))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Response) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Response) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Response) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson6ff3ac1dDecodeGithubComBsmOpenrtbV3NativeResponse(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Response) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson6ff3ac1dDecodeGithubComBsmOpenrtbV3NativeResponse(l, v)
+}
diff --git a/native/response/title_easyjson.go b/native/response/title_easyjson.go
new file mode 100644
index 0000000..72281a9
--- /dev/null
+++ b/native/response/title_easyjson.go
@@ -0,0 +1,94 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package response
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjsonE7952480DecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer, out *Title) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "text":
+			out.Text = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonE7952480EncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writer, in Title) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"text\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.Text))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Title) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonE7952480EncodeGithubComBsmOpenrtbV3NativeResponse(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Title) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonE7952480EncodeGithubComBsmOpenrtbV3NativeResponse(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Title) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonE7952480DecodeGithubComBsmOpenrtbV3NativeResponse(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Title) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonE7952480DecodeGithubComBsmOpenrtbV3NativeResponse(l, v)
+}
diff --git a/native/response/video_easyjson.go b/native/response/video_easyjson.go
new file mode 100644
index 0000000..e9d052a
--- /dev/null
+++ b/native/response/video_easyjson.go
@@ -0,0 +1,85 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package response
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson3c9ce8c3DecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer, out *Video) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "vasttag":
+			out.VASTTag = string(in.String())
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3c9ce8c3EncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writer, in Video) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"vasttag\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.VASTTag))
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Video) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson3c9ce8c3EncodeGithubComBsmOpenrtbV3NativeResponse(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Video) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson3c9ce8c3EncodeGithubComBsmOpenrtbV3NativeResponse(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Video) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson3c9ce8c3DecodeGithubComBsmOpenrtbV3NativeResponse(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Video) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson3c9ce8c3DecodeGithubComBsmOpenrtbV3NativeResponse(l, v)
+}
diff --git a/native_easyjson.go b/native_easyjson.go
new file mode 100644
index 0000000..a15730d
--- /dev/null
+++ b/native_easyjson.go
@@ -0,0 +1,177 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson3eeb1cddDecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *Native) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "request":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Request).UnmarshalJSON(data))
+			}
+		case "ver":
+			out.Version = string(in.String())
+		case "api":
+			if in.IsNull() {
+				in.Skip()
+				out.APIs = nil
+			} else {
+				in.Delim('[')
+				if out.APIs == nil {
+					if !in.IsDelim(']') {
+						out.APIs = make([]APIFramework, 0, 8)
+					} else {
+						out.APIs = []APIFramework{}
+					}
+				} else {
+					out.APIs = (out.APIs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 APIFramework
+					v1 = APIFramework(in.Int())
+					out.APIs = append(out.APIs, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "battr":
+			if in.IsNull() {
+				in.Skip()
+				out.BlockedAttrs = nil
+			} else {
+				in.Delim('[')
+				if out.BlockedAttrs == nil {
+					if !in.IsDelim(']') {
+						out.BlockedAttrs = make([]CreativeAttribute, 0, 8)
+					} else {
+						out.BlockedAttrs = []CreativeAttribute{}
+					}
+				} else {
+					out.BlockedAttrs = (out.BlockedAttrs)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v2 CreativeAttribute
+					v2 = CreativeAttribute(in.Int())
+					out.BlockedAttrs = append(out.BlockedAttrs, v2)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson3eeb1cddEncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in Native) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"request\":"
+		out.RawString(prefix[1:])
+		out.Raw((in.Request).MarshalJSON())
+	}
+	if in.Version != "" {
+		const prefix string = ",\"ver\":"
+		out.RawString(prefix)
+		out.String(string(in.Version))
+	}
+	if len(in.APIs) != 0 {
+		const prefix string = ",\"api\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v3, v4 := range in.APIs {
+				if v3 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v4))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.BlockedAttrs) != 0 {
+		const prefix string = ",\"battr\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v5, v6 := range in.BlockedAttrs {
+				if v5 > 0 {
+					out.RawByte(',')
+				}
+				out.Int(int(v6))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Native) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson3eeb1cddEncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Native) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson3eeb1cddEncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Native) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson3eeb1cddDecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Native) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson3eeb1cddDecodeGithubComBsmOpenrtbV3(l, v)
+}
diff --git a/numbers_easyjson.go b/numbers_easyjson.go
new file mode 100644
index 0000000..793d66c
--- /dev/null
+++ b/numbers_easyjson.go
@@ -0,0 +1,18 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
diff --git a/openrtb_easyjson.go b/openrtb_easyjson.go
new file mode 100644
index 0000000..1e5e174
--- /dev/null
+++ b/openrtb_easyjson.go
@@ -0,0 +1,1161 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjsonB27eec76DecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *User) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "buyerid":
+			out.BuyerID = string(in.String())
+		case "buyeruid":
+			out.BuyerUID = string(in.String())
+		case "yob":
+			out.YearOfBirth = int(in.Int())
+		case "gender":
+			out.Gender = string(in.String())
+		case "keywords":
+			out.Keywords = string(in.String())
+		case "customdata":
+			out.CustomData = string(in.String())
+		case "geo":
+			if in.IsNull() {
+				in.Skip()
+				out.Geo = nil
+			} else {
+				if out.Geo == nil {
+					out.Geo = new(Geo)
+				}
+				(*out.Geo).UnmarshalEasyJSON(in)
+			}
+		case "data":
+			if in.IsNull() {
+				in.Skip()
+				out.Data = nil
+			} else {
+				in.Delim('[')
+				if out.Data == nil {
+					if !in.IsDelim(']') {
+						out.Data = make([]Data, 0, 0)
+					} else {
+						out.Data = []Data{}
+					}
+				} else {
+					out.Data = (out.Data)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 Data
+					(v1).UnmarshalEasyJSON(in)
+					out.Data = append(out.Data, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonB27eec76EncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in User) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.BuyerID != "" {
+		const prefix string = ",\"buyerid\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.BuyerID))
+	}
+	if in.BuyerUID != "" {
+		const prefix string = ",\"buyeruid\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.BuyerUID))
+	}
+	if in.YearOfBirth != 0 {
+		const prefix string = ",\"yob\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.YearOfBirth))
+	}
+	if in.Gender != "" {
+		const prefix string = ",\"gender\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Gender))
+	}
+	if in.Keywords != "" {
+		const prefix string = ",\"keywords\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Keywords))
+	}
+	if in.CustomData != "" {
+		const prefix string = ",\"customdata\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.CustomData))
+	}
+	if in.Geo != nil {
+		const prefix string = ",\"geo\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		(*in.Geo).MarshalEasyJSON(out)
+	}
+	if len(in.Data) != 0 {
+		const prefix string = ",\"data\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v2, v3 := range in.Data {
+				if v2 > 0 {
+					out.RawByte(',')
+				}
+				(v3).MarshalEasyJSON(out)
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v User) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v User) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *User) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *User) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV3(l, v)
+}
+func easyjsonB27eec76DecodeGithubComBsmOpenrtbV31(in *jlexer.Lexer, out *ThirdParty) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "cat":
+			if in.IsNull() {
+				in.Skip()
+				out.Categories = nil
+			} else {
+				in.Delim('[')
+				if out.Categories == nil {
+					if !in.IsDelim(']') {
+						out.Categories = make([]ContentCategory, 0, 4)
+					} else {
+						out.Categories = []ContentCategory{}
+					}
+				} else {
+					out.Categories = (out.Categories)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v4 ContentCategory
+					v4 = ContentCategory(in.String())
+					out.Categories = append(out.Categories, v4)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "domain":
+			out.Domain = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonB27eec76EncodeGithubComBsmOpenrtbV31(out *jwriter.Writer, in ThirdParty) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if len(in.Categories) != 0 {
+		const prefix string = ",\"cat\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v5, v6 := range in.Categories {
+				if v5 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v6))
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v ThirdParty) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV31(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v ThirdParty) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV31(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *ThirdParty) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV31(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *ThirdParty) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV31(l, v)
+}
+func easyjsonB27eec76DecodeGithubComBsmOpenrtbV32(in *jlexer.Lexer, out *Segment) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "value":
+			out.Value = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonB27eec76EncodeGithubComBsmOpenrtbV32(out *jwriter.Writer, in Segment) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if in.Value != "" {
+		const prefix string = ",\"value\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Value))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Segment) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV32(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Segment) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV32(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Segment) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV32(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Segment) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV32(l, v)
+}
+func easyjsonB27eec76DecodeGithubComBsmOpenrtbV33(in *jlexer.Lexer, out *Regulations) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "coppa":
+			out.COPPA = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonB27eec76EncodeGithubComBsmOpenrtbV33(out *jwriter.Writer, in Regulations) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.COPPA != 0 {
+		const prefix string = ",\"coppa\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.COPPA))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Regulations) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV33(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Regulations) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV33(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Regulations) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV33(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Regulations) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV33(l, v)
+}
+func easyjsonB27eec76DecodeGithubComBsmOpenrtbV34(in *jlexer.Lexer, out *Geo) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "lat":
+			out.Latitude = float64(in.Float64())
+		case "lon":
+			out.Longitude = float64(in.Float64())
+		case "type":
+			out.Type = LocationType(in.Int())
+		case "accuracy":
+			out.Accuracy = int(in.Int())
+		case "lastfix":
+			out.LastFix = int(in.Int())
+		case "ipservice":
+			out.IPService = IPLocation(in.Int())
+		case "country":
+			out.Country = string(in.String())
+		case "region":
+			out.Region = string(in.String())
+		case "regionFIPS104":
+			out.RegionFIPS104 = string(in.String())
+		case "metro":
+			out.Metro = string(in.String())
+		case "city":
+			out.City = string(in.String())
+		case "zip":
+			out.ZIP = string(in.String())
+		case "utcoffset":
+			out.UTCOffset = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonB27eec76EncodeGithubComBsmOpenrtbV34(out *jwriter.Writer, in Geo) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Latitude != 0 {
+		const prefix string = ",\"lat\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Float64(float64(in.Latitude))
+	}
+	if in.Longitude != 0 {
+		const prefix string = ",\"lon\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Float64(float64(in.Longitude))
+	}
+	if in.Type != 0 {
+		const prefix string = ",\"type\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Type))
+	}
+	if in.Accuracy != 0 {
+		const prefix string = ",\"accuracy\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Accuracy))
+	}
+	if in.LastFix != 0 {
+		const prefix string = ",\"lastfix\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.LastFix))
+	}
+	if in.IPService != 0 {
+		const prefix string = ",\"ipservice\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.IPService))
+	}
+	if in.Country != "" {
+		const prefix string = ",\"country\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Country))
+	}
+	if in.Region != "" {
+		const prefix string = ",\"region\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Region))
+	}
+	if in.RegionFIPS104 != "" {
+		const prefix string = ",\"regionFIPS104\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.RegionFIPS104))
+	}
+	if in.Metro != "" {
+		const prefix string = ",\"metro\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Metro))
+	}
+	if in.City != "" {
+		const prefix string = ",\"city\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.City))
+	}
+	if in.ZIP != "" {
+		const prefix string = ",\"zip\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.ZIP))
+	}
+	if in.UTCOffset != 0 {
+		const prefix string = ",\"utcoffset\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.UTCOffset))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Geo) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV34(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Geo) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV34(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Geo) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV34(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Geo) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV34(l, v)
+}
+func easyjsonB27eec76DecodeGithubComBsmOpenrtbV35(in *jlexer.Lexer, out *Format) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "w":
+			out.Width = int(in.Int())
+		case "h":
+			out.Height = int(in.Int())
+		case "wratio":
+			out.WidthRatio = int(in.Int())
+		case "hration":
+			out.HeightRatio = int(in.Int())
+		case "wmin":
+			out.WidthMin = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonB27eec76EncodeGithubComBsmOpenrtbV35(out *jwriter.Writer, in Format) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Width != 0 {
+		const prefix string = ",\"w\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.Int(int(in.Width))
+	}
+	if in.Height != 0 {
+		const prefix string = ",\"h\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Height))
+	}
+	if in.WidthRatio != 0 {
+		const prefix string = ",\"wratio\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthRatio))
+	}
+	if in.HeightRatio != 0 {
+		const prefix string = ",\"hration\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.HeightRatio))
+	}
+	if in.WidthMin != 0 {
+		const prefix string = ",\"wmin\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.WidthMin))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Format) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV35(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Format) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV35(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Format) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV35(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Format) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV35(l, v)
+}
+func easyjsonB27eec76DecodeGithubComBsmOpenrtbV36(in *jlexer.Lexer, out *Data) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "segment":
+			if in.IsNull() {
+				in.Skip()
+				out.Segment = nil
+			} else {
+				in.Delim('[')
+				if out.Segment == nil {
+					if !in.IsDelim(']') {
+						out.Segment = make([]Segment, 0, 0)
+					} else {
+						out.Segment = []Segment{}
+					}
+				} else {
+					out.Segment = (out.Segment)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v7 Segment
+					(v7).UnmarshalEasyJSON(in)
+					out.Segment = append(out.Segment, v7)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonB27eec76EncodeGithubComBsmOpenrtbV36(out *jwriter.Writer, in Data) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if len(in.Segment) != 0 {
+		const prefix string = ",\"segment\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v8, v9 := range in.Segment {
+				if v8 > 0 {
+					out.RawByte(',')
+				}
+				(v9).MarshalEasyJSON(out)
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v Data) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV36(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v Data) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV36(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *Data) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV36(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *Data) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV36(l, v)
+}
+func easyjsonB27eec76DecodeGithubComBsmOpenrtbV37(in *jlexer.Lexer, out *ChannelEntity) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "name":
+			out.Name = string(in.String())
+		case "domain":
+			out.Domain = string(in.String())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonB27eec76EncodeGithubComBsmOpenrtbV37(out *jwriter.Writer, in ChannelEntity) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.ID != "" {
+		const prefix string = ",\"id\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	if in.Name != "" {
+		const prefix string = ",\"name\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Name))
+	}
+	if in.Domain != "" {
+		const prefix string = ",\"domain\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Domain))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v ChannelEntity) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV37(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v ChannelEntity) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonB27eec76EncodeGithubComBsmOpenrtbV37(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *ChannelEntity) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV37(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *ChannelEntity) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonB27eec76DecodeGithubComBsmOpenrtbV37(l, v)
+}
diff --git a/quantity_easyjson.go b/quantity_easyjson.go
new file mode 100644
index 0000000..b0a6294
--- /dev/null
+++ b/quantity_easyjson.go
@@ -0,0 +1,16 @@
+// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
+// compilable during generation.
+
+package  openrtb
+
+import (
+  "github.com/mailru/easyjson/jwriter"
+  "github.com/mailru/easyjson/jlexer"
+)
+
+func ( Quantity ) MarshalJSON() ([]byte, error) { return nil, nil }
+func (* Quantity ) UnmarshalJSON([]byte) error { return nil }
+func ( Quantity ) MarshalEasyJSON(w *jwriter.Writer) {}
+func (* Quantity ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
+
+type EasyJSON_exporter_Quantity *Quantity
diff --git a/seatbid_easyjson.go b/seatbid_easyjson.go
new file mode 100644
index 0000000..156b60f
--- /dev/null
+++ b/seatbid_easyjson.go
@@ -0,0 +1,140 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson526ccff2DecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *SeatBid) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "bid":
+			if in.IsNull() {
+				in.Skip()
+				out.Bids = nil
+			} else {
+				in.Delim('[')
+				if out.Bids == nil {
+					if !in.IsDelim(']') {
+						out.Bids = make([]Bid, 0, 0)
+					} else {
+						out.Bids = []Bid{}
+					}
+				} else {
+					out.Bids = (out.Bids)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 Bid
+					(v1).UnmarshalEasyJSON(in)
+					out.Bids = append(out.Bids, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "seat":
+			out.Seat = string(in.String())
+		case "group":
+			out.Group = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson526ccff2EncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in SeatBid) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"bid\":"
+		out.RawString(prefix[1:])
+		if in.Bids == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
+			out.RawString("null")
+		} else {
+			out.RawByte('[')
+			for v2, v3 := range in.Bids {
+				if v2 > 0 {
+					out.RawByte(',')
+				}
+				(v3).MarshalEasyJSON(out)
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.Seat != "" {
+		const prefix string = ",\"seat\":"
+		out.RawString(prefix)
+		out.String(string(in.Seat))
+	}
+	if in.Group != 0 {
+		const prefix string = ",\"group\":"
+		out.RawString(prefix)
+		out.Int(int(in.Group))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v SeatBid) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson526ccff2EncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v SeatBid) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson526ccff2EncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *SeatBid) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson526ccff2DecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *SeatBid) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson526ccff2DecodeGithubComBsmOpenrtbV3(l, v)
+}
diff --git a/source_easyjson.go b/source_easyjson.go
new file mode 100644
index 0000000..35a385d
--- /dev/null
+++ b/source_easyjson.go
@@ -0,0 +1,16 @@
+// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
+// compilable during generation.
+
+package  openrtb
+
+import (
+  "github.com/mailru/easyjson/jwriter"
+  "github.com/mailru/easyjson/jlexer"
+)
+
+func ( Source ) MarshalJSON() ([]byte, error) { return nil, nil }
+func (* Source ) UnmarshalJSON([]byte) error { return nil }
+func ( Source ) MarshalEasyJSON(w *jwriter.Writer) {}
+func (* Source ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
+
+type EasyJSON_exporter_Source *Source
diff --git a/sua_easyjson.go b/sua_easyjson.go
new file mode 100644
index 0000000..b270246
--- /dev/null
+++ b/sua_easyjson.go
@@ -0,0 +1,325 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package openrtb
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjsonFa8885e7DecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *UserAgent) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "browsers":
+			if in.IsNull() {
+				in.Skip()
+				out.Browsers = nil
+			} else {
+				in.Delim('[')
+				if out.Browsers == nil {
+					if !in.IsDelim(']') {
+						out.Browsers = make([]BrandVersion, 0, 1)
+					} else {
+						out.Browsers = []BrandVersion{}
+					}
+				} else {
+					out.Browsers = (out.Browsers)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 BrandVersion
+					(v1).UnmarshalEasyJSON(in)
+					out.Browsers = append(out.Browsers, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "platform":
+			(out.Platform).UnmarshalEasyJSON(in)
+		case "mobile":
+			out.Mobile = int(in.Int())
+		case "architecture":
+			out.Architecture = string(in.String())
+		case "bitness":
+			out.Bitness = string(in.String())
+		case "model":
+			out.Model = string(in.String())
+		case "source":
+			out.Source = int(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonFa8885e7EncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in UserAgent) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if len(in.Browsers) != 0 {
+		const prefix string = ",\"browsers\":"
+		first = false
+		out.RawString(prefix[1:])
+		{
+			out.RawByte('[')
+			for v2, v3 := range in.Browsers {
+				if v2 > 0 {
+					out.RawByte(',')
+				}
+				(v3).MarshalEasyJSON(out)
+			}
+			out.RawByte(']')
+		}
+	}
+	if true {
+		const prefix string = ",\"platform\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		(in.Platform).MarshalEasyJSON(out)
+	}
+	if in.Mobile != 0 {
+		const prefix string = ",\"mobile\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Mobile))
+	}
+	if in.Architecture != "" {
+		const prefix string = ",\"architecture\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Architecture))
+	}
+	if in.Bitness != "" {
+		const prefix string = ",\"bitness\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Bitness))
+	}
+	if in.Model != "" {
+		const prefix string = ",\"model\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.String(string(in.Model))
+	}
+	if in.Source != 0 {
+		const prefix string = ",\"source\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Int(int(in.Source))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v UserAgent) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonFa8885e7EncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v UserAgent) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonFa8885e7EncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *UserAgent) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonFa8885e7DecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *UserAgent) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonFa8885e7DecodeGithubComBsmOpenrtbV3(l, v)
+}
+func easyjsonFa8885e7DecodeGithubComBsmOpenrtbV31(in *jlexer.Lexer, out *BrandVersion) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "brand":
+			out.Brand = string(in.String())
+		case "version":
+			if in.IsNull() {
+				in.Skip()
+				out.Version = nil
+			} else {
+				in.Delim('[')
+				if out.Version == nil {
+					if !in.IsDelim(']') {
+						out.Version = make([]string, 0, 4)
+					} else {
+						out.Version = []string{}
+					}
+				} else {
+					out.Version = (out.Version)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v4 string
+					v4 = string(in.String())
+					out.Version = append(out.Version, v4)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjsonFa8885e7EncodeGithubComBsmOpenrtbV31(out *jwriter.Writer, in BrandVersion) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	if in.Brand != "" {
+		const prefix string = ",\"brand\":"
+		first = false
+		out.RawString(prefix[1:])
+		out.String(string(in.Brand))
+	}
+	if len(in.Version) != 0 {
+		const prefix string = ",\"version\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		{
+			out.RawByte('[')
+			for v5, v6 := range in.Version {
+				if v5 > 0 {
+					out.RawByte(',')
+				}
+				out.String(string(v6))
+			}
+			out.RawByte(']')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		if first {
+			first = false
+			out.RawString(prefix[1:])
+		} else {
+			out.RawString(prefix)
+		}
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v BrandVersion) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjsonFa8885e7EncodeGithubComBsmOpenrtbV31(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v BrandVersion) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjsonFa8885e7EncodeGithubComBsmOpenrtbV31(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *BrandVersion) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjsonFa8885e7DecodeGithubComBsmOpenrtbV31(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *BrandVersion) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjsonFa8885e7DecodeGithubComBsmOpenrtbV31(l, v)
+}
diff --git a/video_easyjson.go b/video_easyjson.go
new file mode 100644
index 0000000..4739179
--- /dev/null
+++ b/video_easyjson.go
@@ -0,0 +1,16 @@
+// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
+// compilable during generation.
+
+package  openrtb
+
+import (
+  "github.com/mailru/easyjson/jwriter"
+  "github.com/mailru/easyjson/jlexer"
+)
+
+func ( Video ) MarshalJSON() ([]byte, error) { return nil, nil }
+func (* Video ) UnmarshalJSON([]byte) error { return nil }
+func ( Video ) MarshalEasyJSON(w *jwriter.Writer) {}
+func (* Video ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
+
+type EasyJSON_exporter_Video *Video

From 9d72d93d06ca16c4cd0c0797a03048d602916cfc Mon Sep 17 00:00:00 2001
From: APAHE <kiselev@gismeteo.ru>
Date: Tue, 13 Feb 2024 19:53:14 +0300
Subject: [PATCH 02/10] fix

---
 banner_easyjson.go | 16 ----------------
 source_easyjson.go | 16 ----------------
 video_easyjson.go  | 16 ----------------
 3 files changed, 48 deletions(-)
 delete mode 100644 banner_easyjson.go
 delete mode 100644 source_easyjson.go
 delete mode 100644 video_easyjson.go

diff --git a/banner_easyjson.go b/banner_easyjson.go
deleted file mode 100644
index f421dc0..0000000
--- a/banner_easyjson.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
-// compilable during generation.
-
-package  openrtb
-
-import (
-  "github.com/mailru/easyjson/jwriter"
-  "github.com/mailru/easyjson/jlexer"
-)
-
-func ( Banner ) MarshalJSON() ([]byte, error) { return nil, nil }
-func (* Banner ) UnmarshalJSON([]byte) error { return nil }
-func ( Banner ) MarshalEasyJSON(w *jwriter.Writer) {}
-func (* Banner ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
-
-type EasyJSON_exporter_Banner *Banner
diff --git a/source_easyjson.go b/source_easyjson.go
deleted file mode 100644
index 35a385d..0000000
--- a/source_easyjson.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
-// compilable during generation.
-
-package  openrtb
-
-import (
-  "github.com/mailru/easyjson/jwriter"
-  "github.com/mailru/easyjson/jlexer"
-)
-
-func ( Source ) MarshalJSON() ([]byte, error) { return nil, nil }
-func (* Source ) UnmarshalJSON([]byte) error { return nil }
-func ( Source ) MarshalEasyJSON(w *jwriter.Writer) {}
-func (* Source ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
-
-type EasyJSON_exporter_Source *Source
diff --git a/video_easyjson.go b/video_easyjson.go
deleted file mode 100644
index 4739179..0000000
--- a/video_easyjson.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
-// compilable during generation.
-
-package  openrtb
-
-import (
-  "github.com/mailru/easyjson/jwriter"
-  "github.com/mailru/easyjson/jlexer"
-)
-
-func ( Video ) MarshalJSON() ([]byte, error) { return nil, nil }
-func (* Video ) UnmarshalJSON([]byte) error { return nil }
-func ( Video ) MarshalEasyJSON(w *jwriter.Writer) {}
-func (* Video ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
-
-type EasyJSON_exporter_Video *Video

From b159e5456c8758dc7e319c062e1a664cbe99b36c Mon Sep 17 00:00:00 2001
From: APAHE <kiselev@gismeteo.ru>
Date: Tue, 13 Feb 2024 19:55:05 +0300
Subject: [PATCH 03/10] fix bid responce

---
 bidresponse_easyjson.go | 165 +++++++++++++++++++++++++++++++++++++---
 quantity_easyjson.go    |  16 ----
 2 files changed, 155 insertions(+), 26 deletions(-)
 delete mode 100644 quantity_easyjson.go

diff --git a/bidresponse_easyjson.go b/bidresponse_easyjson.go
index 3e60b1a..b8d911e 100644
--- a/bidresponse_easyjson.go
+++ b/bidresponse_easyjson.go
@@ -1,16 +1,161 @@
-// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
-// compilable during generation.
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
 
-package  openrtb
+package openrtb
 
 import (
-  "github.com/mailru/easyjson/jwriter"
-  "github.com/mailru/easyjson/jlexer"
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
 )
 
-func ( BidResponse ) MarshalJSON() ([]byte, error) { return nil, nil }
-func (* BidResponse ) UnmarshalJSON([]byte) error { return nil }
-func ( BidResponse ) MarshalEasyJSON(w *jwriter.Writer) {}
-func (* BidResponse ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson10eb023eDecodeGithubComBsmOpenrtbV3(in *jlexer.Lexer, out *BidResponse) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "id":
+			out.ID = string(in.String())
+		case "seatbid":
+			if in.IsNull() {
+				in.Skip()
+				out.SeatBids = nil
+			} else {
+				in.Delim('[')
+				if out.SeatBids == nil {
+					if !in.IsDelim(']') {
+						out.SeatBids = make([]SeatBid, 0, 0)
+					} else {
+						out.SeatBids = []SeatBid{}
+					}
+				} else {
+					out.SeatBids = (out.SeatBids)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v1 SeatBid
+					(v1).UnmarshalEasyJSON(in)
+					out.SeatBids = append(out.SeatBids, v1)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
+		case "bidid":
+			out.BidID = string(in.String())
+		case "cur":
+			out.Currency = string(in.String())
+		case "customdata":
+			out.CustomData = string(in.String())
+		case "nbr":
+			out.NBR = NBR(in.Int())
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson10eb023eEncodeGithubComBsmOpenrtbV3(out *jwriter.Writer, in BidResponse) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"id\":"
+		out.RawString(prefix[1:])
+		out.String(string(in.ID))
+	}
+	{
+		const prefix string = ",\"seatbid\":"
+		out.RawString(prefix)
+		if in.SeatBids == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
+			out.RawString("null")
+		} else {
+			out.RawByte('[')
+			for v2, v3 := range in.SeatBids {
+				if v2 > 0 {
+					out.RawByte(',')
+				}
+				(v3).MarshalEasyJSON(out)
+			}
+			out.RawByte(']')
+		}
+	}
+	if in.BidID != "" {
+		const prefix string = ",\"bidid\":"
+		out.RawString(prefix)
+		out.String(string(in.BidID))
+	}
+	if in.Currency != "" {
+		const prefix string = ",\"cur\":"
+		out.RawString(prefix)
+		out.String(string(in.Currency))
+	}
+	if in.CustomData != "" {
+		const prefix string = ",\"customdata\":"
+		out.RawString(prefix)
+		out.String(string(in.CustomData))
+	}
+	if in.NBR != 0 {
+		const prefix string = ",\"nbr\":"
+		out.RawString(prefix)
+		out.Int(int(in.NBR))
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v BidResponse) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson10eb023eEncodeGithubComBsmOpenrtbV3(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v BidResponse) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson10eb023eEncodeGithubComBsmOpenrtbV3(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *BidResponse) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson10eb023eDecodeGithubComBsmOpenrtbV3(&r, v)
+	return r.Error()
+}
 
-type EasyJSON_exporter_BidResponse *BidResponse
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *BidResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson10eb023eDecodeGithubComBsmOpenrtbV3(l, v)
+}
diff --git a/quantity_easyjson.go b/quantity_easyjson.go
deleted file mode 100644
index b0a6294..0000000
--- a/quantity_easyjson.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
-// compilable during generation.
-
-package  openrtb
-
-import (
-  "github.com/mailru/easyjson/jwriter"
-  "github.com/mailru/easyjson/jlexer"
-)
-
-func ( Quantity ) MarshalJSON() ([]byte, error) { return nil, nil }
-func (* Quantity ) UnmarshalJSON([]byte) error { return nil }
-func ( Quantity ) MarshalEasyJSON(w *jwriter.Writer) {}
-func (* Quantity ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
-
-type EasyJSON_exporter_Quantity *Quantity

From c092d99a20667910906d38358f9b831f95a47991 Mon Sep 17 00:00:00 2001
From: APAHE <kiselev@gismeteo.ru>
Date: Tue, 13 Feb 2024 19:59:34 +0300
Subject: [PATCH 04/10] fix version

---
 go.mod | 11 ++++++++---
 go.sum |  2 ++
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/go.mod b/go.mod
index 860d8e2..43aa83e 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,10 @@
-module github.com/bsm/openrtb/v3
+module github.com/octoclick/openrtb-easyjson
 
-go 1.13
+go 1.21.0
 
-require github.com/mailru/easyjson v0.7.7 // indirect
+require (
+	github.com/bsm/openrtb/v3 v3.2.1
+	github.com/mailru/easyjson v0.7.7
+)
+
+require github.com/josharian/intern v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index 7707cb6..26bf388 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,5 @@
+github.com/bsm/openrtb/v3 v3.2.1 h1:3ogxFJmWQORtg1ZWm7KKypvQ8wL/LCpgJv7pfByHNRg=
+github.com/bsm/openrtb/v3 v3.2.1/go.mod h1:ViYutFEaDuMBeumlvMFV8dGaeaHZWDiEAJNhB7JCSE8=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=

From eaa2b26da0dee35f61702b7d31434017d885fa89 Mon Sep 17 00:00:00 2001
From: APAHE <kiselev@gismeteo.ru>
Date: Wed, 14 Feb 2024 13:00:01 +0300
Subject: [PATCH 05/10] fix mod

---
 README.md                        | 2 +-
 audio_test.go                    | 2 +-
 banner_test.go                   | 2 +-
 bid_test.go                      | 2 +-
 bidrequest_test.go               | 2 +-
 bidresponse_test.go              | 2 +-
 content_test.go                  | 2 +-
 device_test.go                   | 2 +-
 go.mod                           | 5 +----
 go.sum                           | 2 --
 impression_test.go               | 2 +-
 inventory_test.go                | 2 +-
 native/request/asset_easyjson.go | 2 +-
 native/request/request_test.go   | 4 ++--
 native/request/video.go          | 2 +-
 native/request/video_easyjson.go | 2 +-
 native/response/response.go      | 2 +-
 native/response/response_test.go | 2 +-
 native_test.go                   | 2 +-
 numbers_test.go                  | 2 +-
 pmp_test.go                      | 2 +-
 quantity_test.go                 | 2 +-
 seatbid_test.go                  | 2 +-
 source_test.go                   | 2 +-
 video_test.go                    | 2 +-
 25 files changed, 25 insertions(+), 30 deletions(-)

diff --git a/README.md b/README.md
index c891844..8a1dca1 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ package main
 
 import (
   "log"
-  "github.com/bsm/openrtb/v3"
+  "github.com/octoclick/openrtb-easyjson"
 )
 
 func main() {
diff --git a/audio_test.go b/audio_test.go
index 1c7c9a8..618ba17 100644
--- a/audio_test.go
+++ b/audio_test.go
@@ -5,7 +5,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestAudio(t *testing.T) {
diff --git a/banner_test.go b/banner_test.go
index 669d80f..e1999bb 100644
--- a/banner_test.go
+++ b/banner_test.go
@@ -4,7 +4,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestBanner(t *testing.T) {
diff --git a/bid_test.go b/bid_test.go
index 9b1d0f9..599ae4e 100644
--- a/bid_test.go
+++ b/bid_test.go
@@ -5,7 +5,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestBid(t *testing.T) {
diff --git a/bidrequest_test.go b/bidrequest_test.go
index 33ff7a4..365ad25 100644
--- a/bidrequest_test.go
+++ b/bidrequest_test.go
@@ -5,7 +5,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestBidRequest(t *testing.T) {
diff --git a/bidresponse_test.go b/bidresponse_test.go
index 39fb075..0252427 100644
--- a/bidresponse_test.go
+++ b/bidresponse_test.go
@@ -5,7 +5,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestBidResponse(t *testing.T) {
diff --git a/content_test.go b/content_test.go
index 2e414fd..a3d3d53 100644
--- a/content_test.go
+++ b/content_test.go
@@ -4,7 +4,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestContent(t *testing.T) {
diff --git a/device_test.go b/device_test.go
index 988043d..c316c4c 100644
--- a/device_test.go
+++ b/device_test.go
@@ -4,7 +4,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestDevice(t *testing.T) {
diff --git a/go.mod b/go.mod
index 43aa83e..3389f3d 100644
--- a/go.mod
+++ b/go.mod
@@ -2,9 +2,6 @@ module github.com/octoclick/openrtb-easyjson
 
 go 1.21.0
 
-require (
-	github.com/bsm/openrtb/v3 v3.2.1
-	github.com/mailru/easyjson v0.7.7
-)
+require github.com/mailru/easyjson v0.7.7
 
 require github.com/josharian/intern v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index 26bf388..7707cb6 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,3 @@
-github.com/bsm/openrtb/v3 v3.2.1 h1:3ogxFJmWQORtg1ZWm7KKypvQ8wL/LCpgJv7pfByHNRg=
-github.com/bsm/openrtb/v3 v3.2.1/go.mod h1:ViYutFEaDuMBeumlvMFV8dGaeaHZWDiEAJNhB7JCSE8=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
diff --git a/impression_test.go b/impression_test.go
index 95046a3..d96366d 100644
--- a/impression_test.go
+++ b/impression_test.go
@@ -5,7 +5,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestImpression(t *testing.T) {
diff --git a/inventory_test.go b/inventory_test.go
index c5a011f..5ee91df 100644
--- a/inventory_test.go
+++ b/inventory_test.go
@@ -4,7 +4,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestApp(t *testing.T) {
diff --git a/native/request/asset_easyjson.go b/native/request/asset_easyjson.go
index a97f298..c521109 100644
--- a/native/request/asset_easyjson.go
+++ b/native/request/asset_easyjson.go
@@ -4,7 +4,7 @@ package request
 
 import (
 	json "encoding/json"
-	_v3 "github.com/bsm/openrtb/v3"
+	_v3 "github.com/octoclick/openrtb-easyjson"
 	easyjson "github.com/mailru/easyjson"
 	jlexer "github.com/mailru/easyjson/jlexer"
 	jwriter "github.com/mailru/easyjson/jwriter"
diff --git a/native/request/request_test.go b/native/request/request_test.go
index a96b847..288f0f0 100644
--- a/native/request/request_test.go
+++ b/native/request/request_test.go
@@ -6,8 +6,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/bsm/openrtb/v3"
-	. "github.com/bsm/openrtb/v3/native/request"
+	"github.com/octoclick/openrtb-easyjson"
+	. "github.com/octoclick/openrtb-easyjson/native/request"
 )
 
 func TestRequest(t *testing.T) {
diff --git a/native/request/video.go b/native/request/video.go
index f9b3a4c..d289d09 100644
--- a/native/request/video.go
+++ b/native/request/video.go
@@ -3,7 +3,7 @@ package request
 import (
 	"encoding/json"
 
-	"github.com/bsm/openrtb/v3"
+	"github.com/octoclick/openrtb-easyjson"
 )
 
 // Video is the native video object.
diff --git a/native/request/video_easyjson.go b/native/request/video_easyjson.go
index 6029d4c..46e543c 100644
--- a/native/request/video_easyjson.go
+++ b/native/request/video_easyjson.go
@@ -4,7 +4,7 @@ package request
 
 import (
 	json "encoding/json"
-	_v3 "github.com/bsm/openrtb/v3"
+	_v3 "github.com/octoclick/openrtb-easyjson"
 	easyjson "github.com/mailru/easyjson"
 	jlexer "github.com/mailru/easyjson/jlexer"
 	jwriter "github.com/mailru/easyjson/jwriter"
diff --git a/native/response/response.go b/native/response/response.go
index 500464d..e02a141 100644
--- a/native/response/response.go
+++ b/native/response/response.go
@@ -3,7 +3,7 @@ package response
 import (
 	"encoding/json"
 
-	"github.com/bsm/openrtb/v3"
+	"github.com/octoclick/openrtb-easyjson"
 )
 
 // Response is the native object is the top level JSON object which identifies a native response.
diff --git a/native/response/response_test.go b/native/response/response_test.go
index c257bc0..99c86a8 100644
--- a/native/response/response_test.go
+++ b/native/response/response_test.go
@@ -6,7 +6,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3/native/response"
+	. "github.com/octoclick/openrtb-easyjson/native/response"
 )
 
 func TestResponse(t *testing.T) {
diff --git a/native_test.go b/native_test.go
index 4ff6315..407dcbf 100644
--- a/native_test.go
+++ b/native_test.go
@@ -5,7 +5,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestNative(t *testing.T) {
diff --git a/numbers_test.go b/numbers_test.go
index a5d8549..40230ae 100644
--- a/numbers_test.go
+++ b/numbers_test.go
@@ -4,7 +4,7 @@ import (
 	"encoding/json"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestNumberOrString(t *testing.T) {
diff --git a/pmp_test.go b/pmp_test.go
index 876c2a7..7e32e65 100644
--- a/pmp_test.go
+++ b/pmp_test.go
@@ -6,7 +6,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestPMP(t *testing.T) {
diff --git a/quantity_test.go b/quantity_test.go
index 2206437..fd559e8 100644
--- a/quantity_test.go
+++ b/quantity_test.go
@@ -4,7 +4,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestQuantity(t *testing.T) {
diff --git a/seatbid_test.go b/seatbid_test.go
index 9f73349..4d30042 100644
--- a/seatbid_test.go
+++ b/seatbid_test.go
@@ -4,7 +4,7 @@ import (
 	"errors"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestSeatBid_Validate(t *testing.T) {
diff --git a/source_test.go b/source_test.go
index 82401ea..a597232 100644
--- a/source_test.go
+++ b/source_test.go
@@ -5,7 +5,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestSource(t *testing.T) {
diff --git a/video_test.go b/video_test.go
index 4b9cbda..9b5be41 100644
--- a/video_test.go
+++ b/video_test.go
@@ -5,7 +5,7 @@ import (
 	"reflect"
 	"testing"
 
-	. "github.com/bsm/openrtb/v3"
+	. "github.com/octoclick/openrtb-easyjson"
 )
 
 func TestVideo(t *testing.T) {

From 8a887dabb913f05a5f0eaa93abc5177a0383e8bf Mon Sep 17 00:00:00 2001
From: APAHE <kiselev@gismeteo.ru>
Date: Wed, 14 Feb 2024 14:43:00 +0300
Subject: [PATCH 06/10] fix validate

---
 bidrequest.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bidrequest.go b/bidrequest.go
index 73ad591..2e05d29 100644
--- a/bidrequest.go
+++ b/bidrequest.go
@@ -12,7 +12,7 @@ var (
 	ErrInvalidReqNoImps   = errors.New("openrtb: request has no impressions")
 	ErrInvalidReqMultiInv = errors.New("openrtb: request has multiple inventory sources") // has site and app
 	ErrInvalidSitePage    = errors.New("openrtb: request hasn't site.page")
-	ErrInvalidDeviceIP    = errors.New("openrtb: request has invalid device.ip")
+	ErrInvalidDeviceIP    = errors.New("openrtb: request has invalid device.ip || device.ipv6")
 )
 
 // BidRequest is the top-level bid request object contains a globally unique bid request or auction ID.  This "id"
@@ -54,7 +54,7 @@ func (req *BidRequest) Validate() error {
 	if req.Site != nil && len(req.Site.Page) == 0 {
 		return ErrInvalidSitePage
 	}
-	if net.ParseIP(req.Device.IP) == nil {
+	if net.ParseIP(req.Device.IP) == nil && net.ParseIP(req.Device.IPv6) == nil {
 		return ErrInvalidDeviceIP
 	}
 	for i := range req.Impressions {

From a86b7568b5d74ee27351e2d82540f7aa2d05860d Mon Sep 17 00:00:00 2001
From: Artem Kiselev <kiselev@gismeteo.ru>
Date: Tue, 16 Apr 2024 14:11:19 +0300
Subject: [PATCH 07/10] add CB-2823

---
 .gitignore                       |  1 +
 .idea/.gitignore                 |  8 --------
 native/response/eventtrackers.go | 30 ++++++++++++++++++++++++++++++
 native/response/response.go      | 13 +++++++------
 4 files changed, 38 insertions(+), 14 deletions(-)
 delete mode 100644 .idea/.gitignore
 create mode 100644 native/response/eventtrackers.go

diff --git a/.gitignore b/.gitignore
index 6aa8b3a..b27ad13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 *.makefile
+.idea
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 13566b8..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/native/response/eventtrackers.go b/native/response/eventtrackers.go
new file mode 100644
index 0000000..1d42ff6
--- /dev/null
+++ b/native/response/eventtrackers.go
@@ -0,0 +1,30 @@
+package response
+
+import "encoding/json"
+
+// EventTrackers object contains response data.
+type EventTrackers struct {
+	Event      EventType           `json:"event"`
+	Method     EventTrackingMethod `json:"method"`
+	Url        string              `json:"url,omitempty"`        //The URL of the image or js. Required for image or js, optional for custom.
+	CustomData map[string]any      `json:"customdata,omitempty"` //To be agreed individually with the exchange, an array of key:value objects for custom tracking, for example the account number of the DSP with a tracking company. IE {“accountnumber”:”123”}
+	Ext        json.RawMessage     `json:"ext,omitempty"`
+}
+
+// EventType ...
+type EventType int
+
+const (
+	ImpressionEvent = iota + 1 // Impression
+	ViewableMRC50              // Visible impression using MRC definition at 50% in view for 1 second
+	ViewableMRC100             // 100% in view for 1 second (ie GroupMstandard)
+	ViewableVideo50            // Visible impression for video using MRC definition at 50% in view for 2 seconds
+)
+
+// EventTrackingMethod ...
+type EventTrackingMethod int
+
+const (
+	ImageMethod      = iota + 1 // Image-pixel tracking - URL provided will be inserted as a 1x1 pixel at the time of the event
+	JavaScriptMethod            // Javascript-based tracking - URL provided will be inserted as a js tag at the time of the event.
+)
diff --git a/native/response/response.go b/native/response/response.go
index e02a141..4a119ac 100644
--- a/native/response/response.go
+++ b/native/response/response.go
@@ -8,10 +8,11 @@ import (
 
 // Response is the native object is the top level JSON object which identifies a native response.
 type Response struct {
-	Version     openrtb.StringOrNumber `json:"ver,omitempty"`         // Version of the Native Markup
-	Assets      []Asset                `json:"assets"`                // An array of Asset Objects
-	Link        Link                   `json:"link"`                  // Destination Link. This is default link object for the ad
-	ImpTrackers []string               `json:"imptrackers,omitempty"` // Array of impression tracking URLs, expected to return a 1x1 image or 204 response
-	JSTracker   string                 `json:"jstracker,omitempty"`   // Optional JavaScript impression tracker. This is a valid HTML, Javascript is already wrapped in <script> tags. It should be executed at impression time where it can be supported
-	Ext         json.RawMessage        `json:"ext,omitempty"`
+	Version       openrtb.StringOrNumber `json:"ver,omitempty"`           // Version of the Native Markup
+	Assets        []Asset                `json:"assets"`                  // An array of Asset Objects
+	Link          Link                   `json:"link"`                    // Destination Link. This is default link object for the ad
+	ImpTrackers   []string               `json:"imptrackers,omitempty"`   // Array of impression tracking URLs, expected to return a 1x1 image or 204 response
+	JSTracker     string                 `json:"jstracker,omitempty"`     // Optional JavaScript impression tracker. This is a valid HTML, Javascript is already wrapped in <script> tags. It should be executed at impression time where it can be supported
+	EventTrackers []EventTrackers        `json:"eventtrackers,omitempty"` // Array of tracking objects to run with the ad, in response to the declared supported methods in the request. Replaces imptrackers and jstracker, to be deprecated.
+	Ext           json.RawMessage        `json:"ext,omitempty"`
 }

From 7d50e99a5a56569390b217e1340d238de70846c6 Mon Sep 17 00:00:00 2001
From: Artem Kiselev <kiselev@gismeteo.ru>
Date: Tue, 16 Apr 2024 14:24:43 +0300
Subject: [PATCH 08/10] add event tracking

---
 native/response/eventtrackers_easyjson.go | 159 ++++++++++++++++++++++
 native/response/response_easyjson.go      |  61 +++++++--
 2 files changed, 208 insertions(+), 12 deletions(-)
 create mode 100644 native/response/eventtrackers_easyjson.go

diff --git a/native/response/eventtrackers_easyjson.go b/native/response/eventtrackers_easyjson.go
new file mode 100644
index 0000000..03f2968
--- /dev/null
+++ b/native/response/eventtrackers_easyjson.go
@@ -0,0 +1,159 @@
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+
+package response
+
+import (
+	json "encoding/json"
+	easyjson "github.com/mailru/easyjson"
+	jlexer "github.com/mailru/easyjson/jlexer"
+	jwriter "github.com/mailru/easyjson/jwriter"
+)
+
+// suppress unused package warning
+var (
+	_ *json.RawMessage
+	_ *jlexer.Lexer
+	_ *jwriter.Writer
+	_ easyjson.Marshaler
+)
+
+func easyjson99896f1DecodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(in *jlexer.Lexer, out *EventTrackers) {
+	isTopLevel := in.IsStart()
+	if in.IsNull() {
+		if isTopLevel {
+			in.Consumed()
+		}
+		in.Skip()
+		return
+	}
+	in.Delim('{')
+	for !in.IsDelim('}') {
+		key := in.UnsafeFieldName(false)
+		in.WantColon()
+		if in.IsNull() {
+			in.Skip()
+			in.WantComma()
+			continue
+		}
+		switch key {
+		case "event":
+			out.Event = EventType(in.Int())
+		case "method":
+			out.Method = EventTrackingMethod(in.Int())
+		case "url":
+			out.Url = string(in.String())
+		case "customdata":
+			if in.IsNull() {
+				in.Skip()
+			} else {
+				in.Delim('{')
+				if !in.IsDelim('}') {
+					out.CustomData = make(map[string]interface{})
+				} else {
+					out.CustomData = nil
+				}
+				for !in.IsDelim('}') {
+					key := string(in.String())
+					in.WantColon()
+					var v1 interface{}
+					if m, ok := v1.(easyjson.Unmarshaler); ok {
+						m.UnmarshalEasyJSON(in)
+					} else if m, ok := v1.(json.Unmarshaler); ok {
+						_ = m.UnmarshalJSON(in.Raw())
+					} else {
+						v1 = in.Interface()
+					}
+					(out.CustomData)[key] = v1
+					in.WantComma()
+				}
+				in.Delim('}')
+			}
+		case "ext":
+			if data := in.Raw(); in.Ok() {
+				in.AddError((out.Ext).UnmarshalJSON(data))
+			}
+		default:
+			in.SkipRecursive()
+		}
+		in.WantComma()
+	}
+	in.Delim('}')
+	if isTopLevel {
+		in.Consumed()
+	}
+}
+func easyjson99896f1EncodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(out *jwriter.Writer, in EventTrackers) {
+	out.RawByte('{')
+	first := true
+	_ = first
+	{
+		const prefix string = ",\"event\":"
+		out.RawString(prefix[1:])
+		out.Int(int(in.Event))
+	}
+	{
+		const prefix string = ",\"method\":"
+		out.RawString(prefix)
+		out.Int(int(in.Method))
+	}
+	if in.Url != "" {
+		const prefix string = ",\"url\":"
+		out.RawString(prefix)
+		out.String(string(in.Url))
+	}
+	if len(in.CustomData) != 0 {
+		const prefix string = ",\"customdata\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('{')
+			v2First := true
+			for v2Name, v2Value := range in.CustomData {
+				if v2First {
+					v2First = false
+				} else {
+					out.RawByte(',')
+				}
+				out.String(string(v2Name))
+				out.RawByte(':')
+				if m, ok := v2Value.(easyjson.Marshaler); ok {
+					m.MarshalEasyJSON(out)
+				} else if m, ok := v2Value.(json.Marshaler); ok {
+					out.Raw(m.MarshalJSON())
+				} else {
+					out.Raw(json.Marshal(v2Value))
+				}
+			}
+			out.RawByte('}')
+		}
+	}
+	if len(in.Ext) != 0 {
+		const prefix string = ",\"ext\":"
+		out.RawString(prefix)
+		out.Raw((in.Ext).MarshalJSON())
+	}
+	out.RawByte('}')
+}
+
+// MarshalJSON supports json.Marshaler interface
+func (v EventTrackers) MarshalJSON() ([]byte, error) {
+	w := jwriter.Writer{}
+	easyjson99896f1EncodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(&w, v)
+	return w.Buffer.BuildBytes(), w.Error
+}
+
+// MarshalEasyJSON supports easyjson.Marshaler interface
+func (v EventTrackers) MarshalEasyJSON(w *jwriter.Writer) {
+	easyjson99896f1EncodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(w, v)
+}
+
+// UnmarshalJSON supports json.Unmarshaler interface
+func (v *EventTrackers) UnmarshalJSON(data []byte) error {
+	r := jlexer.Lexer{Data: data}
+	easyjson99896f1DecodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(&r, v)
+	return r.Error()
+}
+
+// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
+func (v *EventTrackers) UnmarshalEasyJSON(l *jlexer.Lexer) {
+	easyjson99896f1DecodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(l, v)
+}
diff --git a/native/response/response_easyjson.go b/native/response/response_easyjson.go
index edf6adc..bf070ae 100644
--- a/native/response/response_easyjson.go
+++ b/native/response/response_easyjson.go
@@ -17,7 +17,7 @@ var (
 	_ easyjson.Marshaler
 )
 
-func easyjson6ff3ac1dDecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer, out *Response) {
+func easyjson6ff3ac1dDecodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(in *jlexer.Lexer, out *Response) {
 	isTopLevel := in.IsStart()
 	if in.IsNull() {
 		if isTopLevel {
@@ -90,6 +90,29 @@ func easyjson6ff3ac1dDecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer,
 			}
 		case "jstracker":
 			out.JSTracker = string(in.String())
+		case "eventtrackers":
+			if in.IsNull() {
+				in.Skip()
+				out.EventTrackers = nil
+			} else {
+				in.Delim('[')
+				if out.EventTrackers == nil {
+					if !in.IsDelim(']') {
+						out.EventTrackers = make([]EventTrackers, 0, 1)
+					} else {
+						out.EventTrackers = []EventTrackers{}
+					}
+				} else {
+					out.EventTrackers = (out.EventTrackers)[:0]
+				}
+				for !in.IsDelim(']') {
+					var v3 EventTrackers
+					(v3).UnmarshalEasyJSON(in)
+					out.EventTrackers = append(out.EventTrackers, v3)
+					in.WantComma()
+				}
+				in.Delim(']')
+			}
 		case "ext":
 			if data := in.Raw(); in.Ok() {
 				in.AddError((out.Ext).UnmarshalJSON(data))
@@ -104,7 +127,7 @@ func easyjson6ff3ac1dDecodeGithubComBsmOpenrtbV3NativeResponse(in *jlexer.Lexer,
 		in.Consumed()
 	}
 }
-func easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writer, in Response) {
+func easyjson6ff3ac1dEncodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(out *jwriter.Writer, in Response) {
 	out.RawByte('{')
 	first := true
 	_ = first
@@ -126,11 +149,11 @@ func easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writ
 			out.RawString("null")
 		} else {
 			out.RawByte('[')
-			for v3, v4 := range in.Assets {
-				if v3 > 0 {
+			for v4, v5 := range in.Assets {
+				if v4 > 0 {
 					out.RawByte(',')
 				}
-				(v4).MarshalEasyJSON(out)
+				(v5).MarshalEasyJSON(out)
 			}
 			out.RawByte(']')
 		}
@@ -145,11 +168,11 @@ func easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writ
 		out.RawString(prefix)
 		{
 			out.RawByte('[')
-			for v5, v6 := range in.ImpTrackers {
-				if v5 > 0 {
+			for v6, v7 := range in.ImpTrackers {
+				if v6 > 0 {
 					out.RawByte(',')
 				}
-				out.String(string(v6))
+				out.String(string(v7))
 			}
 			out.RawByte(']')
 		}
@@ -159,6 +182,20 @@ func easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writ
 		out.RawString(prefix)
 		out.String(string(in.JSTracker))
 	}
+	if len(in.EventTrackers) != 0 {
+		const prefix string = ",\"eventtrackers\":"
+		out.RawString(prefix)
+		{
+			out.RawByte('[')
+			for v8, v9 := range in.EventTrackers {
+				if v8 > 0 {
+					out.RawByte(',')
+				}
+				(v9).MarshalEasyJSON(out)
+			}
+			out.RawByte(']')
+		}
+	}
 	if len(in.Ext) != 0 {
 		const prefix string = ",\"ext\":"
 		out.RawString(prefix)
@@ -170,23 +207,23 @@ func easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(out *jwriter.Writ
 // MarshalJSON supports json.Marshaler interface
 func (v Response) MarshalJSON() ([]byte, error) {
 	w := jwriter.Writer{}
-	easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(&w, v)
+	easyjson6ff3ac1dEncodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(&w, v)
 	return w.Buffer.BuildBytes(), w.Error
 }
 
 // MarshalEasyJSON supports easyjson.Marshaler interface
 func (v Response) MarshalEasyJSON(w *jwriter.Writer) {
-	easyjson6ff3ac1dEncodeGithubComBsmOpenrtbV3NativeResponse(w, v)
+	easyjson6ff3ac1dEncodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(w, v)
 }
 
 // UnmarshalJSON supports json.Unmarshaler interface
 func (v *Response) UnmarshalJSON(data []byte) error {
 	r := jlexer.Lexer{Data: data}
-	easyjson6ff3ac1dDecodeGithubComBsmOpenrtbV3NativeResponse(&r, v)
+	easyjson6ff3ac1dDecodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(&r, v)
 	return r.Error()
 }
 
 // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
 func (v *Response) UnmarshalEasyJSON(l *jlexer.Lexer) {
-	easyjson6ff3ac1dDecodeGithubComBsmOpenrtbV3NativeResponse(l, v)
+	easyjson6ff3ac1dDecodeGithubComOctoclickOpenrtbEasyjsonNativeResponse(l, v)
 }

From 41f1cb30818bf9d6bf289375f36e39ce506d99c8 Mon Sep 17 00:00:00 2001
From: Artem Kiselev <kiselev@gismeteo.ru>
Date: Thu, 2 May 2024 12:58:55 +0300
Subject: [PATCH 09/10] add check site.domain

---
 bidrequest.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bidrequest.go b/bidrequest.go
index 2e05d29..6f749f1 100644
--- a/bidrequest.go
+++ b/bidrequest.go
@@ -11,7 +11,7 @@ var (
 	ErrInvalidReqNoID     = errors.New("openrtb: request ID missing")
 	ErrInvalidReqNoImps   = errors.New("openrtb: request has no impressions")
 	ErrInvalidReqMultiInv = errors.New("openrtb: request has multiple inventory sources") // has site and app
-	ErrInvalidSitePage    = errors.New("openrtb: request hasn't site.page")
+	ErrInvalidSitePage    = errors.New("openrtb: request hasn't site.page or site.domain")
 	ErrInvalidDeviceIP    = errors.New("openrtb: request has invalid device.ip || device.ipv6")
 )
 
@@ -51,7 +51,7 @@ func (req *BidRequest) Validate() error {
 	} else if req.Site != nil && req.App != nil {
 		return ErrInvalidReqMultiInv
 	}
-	if req.Site != nil && len(req.Site.Page) == 0 {
+	if req.Site != nil && len(req.Site.Page) == 0 && len(req.Site.Domain) == 0 {
 		return ErrInvalidSitePage
 	}
 	if net.ParseIP(req.Device.IP) == nil && net.ParseIP(req.Device.IPv6) == nil {

From 9874c9525d25adbed55ce9b13a4d9d0c55f990b3 Mon Sep 17 00:00:00 2001
From: agolovev <agolovev@gmail.com>
Date: Fri, 9 Aug 2024 15:06:54 +0300
Subject: [PATCH 10/10] :zap: Validate User.ID

---
 bidrequest.go | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/bidrequest.go b/bidrequest.go
index 6f749f1..47e24c4 100644
--- a/bidrequest.go
+++ b/bidrequest.go
@@ -13,6 +13,7 @@ var (
 	ErrInvalidReqMultiInv = errors.New("openrtb: request has multiple inventory sources") // has site and app
 	ErrInvalidSitePage    = errors.New("openrtb: request hasn't site.page or site.domain")
 	ErrInvalidDeviceIP    = errors.New("openrtb: request has invalid device.ip || device.ipv6")
+	ErrInvalidUserID      = errors.New("openrtb: request has invalid user.id")
 )
 
 // BidRequest is the top-level bid request object contains a globally unique bid request or auction ID.  This "id"
@@ -63,5 +64,10 @@ func (req *BidRequest) Validate() error {
 			return err
 		}
 	}
+
+	if req.User == nil || len(req.User.ID) == 0 {
+		return ErrInvalidUserID
+	}
+
 	return nil
 }