From 50721c8aa4a29a7f7b31de57f729c691c8e876b0 Mon Sep 17 00:00:00 2001
From: abermanov-zeta <95416296+abermanov-zeta@users.noreply.github.com>
Date: Mon, 10 Mar 2025 17:51:23 +0100
Subject: [PATCH 01/40] Zeta Global SSP: Add sid parameter and audio support
(#3939)
---
adapters/zeta_global_ssp/params_test.go | 53 +++++++
.../zeta_global_ssp-test/exemplary/audio.json | 140 +++++++++++++++++
.../exemplary/banner.json | 7 +-
.../exemplary/no-bid.json | 7 +-
.../zeta_global_ssp-test/exemplary/video.json | 7 +-
.../supplemental/bad-request.json | 7 +-
.../supplemental/invalid-bid-type.json | 7 +-
.../supplemental/invalid-imp-ext-bidder.json | 42 +++++
.../supplemental/invalid-imp-ext.json | 40 +++++
.../supplemental/no-bid-type.json.json | 7 +-
.../supplemental/no-sid-param.json | 144 ++++++++++++++++++
.../supplemental/server-error.json | 7 +-
adapters/zeta_global_ssp/zeta_global_ssp.go | 50 +++++-
.../zeta_global_ssp/zeta_global_ssp_test.go | 11 +-
openrtb_ext/imp_zeta_global_ssp.go | 5 +
static/bidder-info/zeta_global_ssp.yaml | 9 +-
static/bidder-params/zeta_global_ssp.json | 7 +-
17 files changed, 513 insertions(+), 37 deletions(-)
create mode 100644 adapters/zeta_global_ssp/params_test.go
create mode 100644 adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/audio.json
create mode 100644 adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-imp-ext-bidder.json
create mode 100644 adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-imp-ext.json
create mode 100644 adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/no-sid-param.json
create mode 100644 openrtb_ext/imp_zeta_global_ssp.go
diff --git a/adapters/zeta_global_ssp/params_test.go b/adapters/zeta_global_ssp/params_test.go
new file mode 100644
index 00000000000..d665d3da0f7
--- /dev/null
+++ b/adapters/zeta_global_ssp/params_test.go
@@ -0,0 +1,53 @@
+package zeta_global_ssp_test
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+)
+
+func TestValidParams(t *testing.T) {
+ validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+ if err != nil {
+ t.Fatalf("Failed to fetch the json-schemas. %v", err)
+ }
+
+ for _, validParam := range validParams {
+ if err := validator.Validate(openrtb_ext.BidderZetaGlobalSsp, json.RawMessage(validParam)); err != nil {
+ t.Errorf("Schema rejected valid params: %s", validParam)
+ }
+ }
+}
+
+func TestInvalidParams(t *testing.T) {
+ validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+ if err != nil {
+ t.Fatalf("Failed to fetch the json-schemas. %v", err)
+ }
+
+ for _, invalidParam := range invalidParams {
+ if err := validator.Validate(openrtb_ext.BidderZetaGlobalSsp, json.RawMessage(invalidParam)); err == nil {
+ t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+ }
+ }
+}
+
+var validParams = []string{
+ `{"sid": 123}`,
+ `{}`,
+}
+
+var invalidParams = []string{
+ ``,
+ `null`,
+ `true`,
+ `5`,
+ `4.2`,
+ `[]`,
+ `some_string`,
+ `{"sid": ""}`,
+ `{"sid": "some_string"}`,
+ `{"sid": "4.2"}`,
+ `{"sid": "123"}`,
+}
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/audio.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/audio.json
new file mode 100644
index 00000000000..c1f1653f169
--- /dev/null
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/audio.json
@@ -0,0 +1,140 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "site": {
+ "page": "http://www.example.com",
+ "domain": "www.example.com"
+ },
+ "device": {
+ "ip": "123.123.123.123"
+ },
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "audio": {
+ "minduration": 5,
+ "maxduration": 30,
+ "minbitrate": 300,
+ "maxbitrate": 1500,
+ "api": [1, 2],
+ "protocols": [9, 10],
+ "mimes": [
+ "audio/aac",
+ "audio/mp4",
+ "audio/mpeg"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "sid": 11
+ }
+ }
+ }
+ ],
+ "test": 1,
+ "tmax": 500
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ]
+ },
+ "uri": "https://ssp.disqus.com/bid/prebid-server?sid=11",
+ "body": {
+ "id": "some-request-id",
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "audio": {
+ "minduration": 5,
+ "maxduration": 30,
+ "minbitrate": 300,
+ "maxbitrate": 1500,
+ "api": [1, 2],
+ "protocols": [9, 10],
+ "mimes": [
+ "audio/aac",
+ "audio/mp4",
+ "audio/mpeg"
+ ]
+ }
+ }
+ ],
+ "site": {
+ "domain": "www.example.com",
+ "page": "http://www.example.com"
+ },
+ "device": {
+ "ip": "123.123.123.123"
+ },
+ "test": 1,
+ "tmax": 500
+ },
+ "impIDs":["some-impression-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "some-request-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "1",
+ "impid": "some-impression-id",
+ "price": 1.234,
+ "adm": "TAG",
+ "adomain": [
+ "some-adomain"
+ ],
+ "cid": "1234",
+ "crid": "2345",
+ "ext": {
+ "prebid": {
+ "type": "audio"
+ }
+ }
+ }
+ ],
+ "seat": "zeta_global_ssp"
+ }
+ ],
+ "bidid": "some-bidid",
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "1",
+ "impid": "some-impression-id",
+ "price": 1.234,
+ "adm": "TAG",
+ "adomain": [
+ "some-adomain"
+ ],
+ "cid": "1234",
+ "crid": "2345",
+ "ext": {
+ "prebid": {
+ "type": "audio"
+ }
+ }
+ },
+ "type": "audio"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/banner.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/banner.json
index 3b0918e6858..620c4d2c2e9 100644
--- a/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/banner.json
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/banner.json
@@ -26,7 +26,9 @@
]
},
"ext": {
- "bidder": {}
+ "bidder": {
+ "sid": 11
+ }
}
}
],
@@ -63,9 +65,6 @@
],
"w": 300,
"h": 250
- },
- "ext": {
- "bidder": {}
}
}
],
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/no-bid.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/no-bid.json
index ebb85839138..535cd524240 100644
--- a/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/no-bid.json
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/no-bid.json
@@ -26,7 +26,9 @@
]
},
"ext": {
- "bidder": {}
+ "bidder": {
+ "sid": 11
+ }
}
}
],
@@ -63,9 +65,6 @@
],
"w": 300,
"h": 250
- },
- "ext": {
- "bidder": {}
}
}
],
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/video.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/video.json
index 2677ea5f1ca..1a6f5e571d7 100644
--- a/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/video.json
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/exemplary/video.json
@@ -6,7 +6,9 @@
{
"id": "some-impression-id",
"ext": {
- "bidder": {}
+ "bidder": {
+ "sid": 11
+ }
},
"video": {
"w": 640,
@@ -49,9 +51,6 @@
"imp": [
{
"id": "some-impression-id",
- "ext": {
- "bidder": {}
- },
"video": {
"w": 640,
"h": 480,
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/bad-request.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/bad-request.json
index 88215a085a3..bd3654b1c68 100644
--- a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/bad-request.json
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/bad-request.json
@@ -26,7 +26,9 @@
]
},
"ext": {
- "bidder": {}
+ "bidder": {
+ "sid": 11
+ }
}
}
],
@@ -63,9 +65,6 @@
],
"w": 300,
"h": 250
- },
- "ext": {
- "bidder": {}
}
}
],
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-bid-type.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-bid-type.json
index 5ed9230e949..5f1e4047798 100644
--- a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-bid-type.json
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-bid-type.json
@@ -26,7 +26,9 @@
]
},
"ext": {
- "bidder": {}
+ "bidder": {
+ "sid": 11
+ }
}
}
],
@@ -63,9 +65,6 @@
],
"w": 300,
"h": 250
- },
- "ext": {
- "bidder": {}
}
}
],
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-imp-ext-bidder.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-imp-ext-bidder.json
new file mode 100644
index 00000000000..86c7b99341f
--- /dev/null
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-imp-ext-bidder.json
@@ -0,0 +1,42 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "site": {
+ "page": "http://www.example.com",
+ "domain": "www.example.com"
+ },
+ "device": {
+ "ip": "123.123.123.123"
+ },
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "banner": {
+ "w": 300,
+ "h": 250,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": ""
+ }
+ }
+ ],
+ "test": 1,
+ "tmax": 500
+ },
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "imp.ext.bidder not provided or cannot be unmarshalled",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-imp-ext.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-imp-ext.json
new file mode 100644
index 00000000000..36dfb29599d
--- /dev/null
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/invalid-imp-ext.json
@@ -0,0 +1,40 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "site": {
+ "page": "http://www.example.com",
+ "domain": "www.example.com"
+ },
+ "device": {
+ "ip": "123.123.123.123"
+ },
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "banner": {
+ "w": 300,
+ "h": 250,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": ""
+ }
+ ],
+ "test": 1,
+ "tmax": 500
+ },
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "imp.ext not provided or cannot be unmarshalled",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/no-bid-type.json.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/no-bid-type.json.json
index f0065941df0..193923dbb61 100644
--- a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/no-bid-type.json.json
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/no-bid-type.json.json
@@ -26,7 +26,9 @@
]
},
"ext": {
- "bidder": {}
+ "bidder": {
+ "sid": 11
+ }
}
}
],
@@ -63,9 +65,6 @@
],
"w": 300,
"h": 250
- },
- "ext": {
- "bidder": {}
}
}
],
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/no-sid-param.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/no-sid-param.json
new file mode 100644
index 00000000000..66f20396720
--- /dev/null
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/no-sid-param.json
@@ -0,0 +1,144 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "site": {
+ "page": "http://www.example.com",
+ "domain": "www.example.com"
+ },
+ "device": {
+ "ip": "123.123.123.123"
+ },
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "banner": {
+ "w": 300,
+ "h": 250,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {}
+ }
+ }
+ ],
+ "test": 1,
+ "tmax": 500
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ]
+ },
+ "uri": "https://ssp.disqus.com/bid/prebid-server?sid=0",
+ "body": {
+ "id": "some-request-id",
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ],
+ "w": 300,
+ "h": 250
+ }
+ }
+ ],
+ "site": {
+ "domain": "www.example.com",
+ "page": "http://www.example.com"
+ },
+ "device": {
+ "ip": "123.123.123.123"
+ },
+ "test": 1,
+ "tmax": 500
+ },
+ "impIDs":["some-impression-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "some-request-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "1",
+ "impid": "some-impression-id",
+ "price": 1.234,
+ "adm": "",
+ "adomain": [
+ "some-adomain"
+ ],
+ "cid": "1234",
+ "crid": "2345",
+ "h": 1,
+ "w": 1,
+ "ext": {
+ "prebid": {
+ "type": "banner"
+ }
+ }
+ }
+ ],
+ "seat": "zeta_global_ssp"
+ }
+ ],
+ "bidid": "some-bidid",
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "1",
+ "impid": "some-impression-id",
+ "price": 1.234,
+ "adm": "",
+ "adomain": [
+ "some-adomain"
+ ],
+ "cid": "1234",
+ "crid": "2345",
+ "h": 1,
+ "w": 1,
+ "ext": {
+ "prebid": {
+ "type": "banner"
+ }
+ }
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/server-error.json b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/server-error.json
index 0ec1555ffb7..a06b3741cb0 100644
--- a/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/server-error.json
+++ b/adapters/zeta_global_ssp/zeta_global_ssp-test/supplemental/server-error.json
@@ -26,7 +26,9 @@
]
},
"ext": {
- "bidder": {}
+ "bidder": {
+ "sid": 11
+ }
}
}
],
@@ -63,9 +65,6 @@
],
"w": 300,
"h": 250
- },
- "ext": {
- "bidder": {}
}
}
],
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp.go b/adapters/zeta_global_ssp/zeta_global_ssp.go
index e06c6f05eff..59a912c1629 100644
--- a/adapters/zeta_global_ssp/zeta_global_ssp.go
+++ b/adapters/zeta_global_ssp/zeta_global_ssp.go
@@ -4,28 +4,46 @@ import (
"encoding/json"
"fmt"
"net/http"
+ "strconv"
+ "text/template"
"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v3/adapters"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/errortypes"
+ "github.com/prebid/prebid-server/v3/macros"
"github.com/prebid/prebid-server/v3/openrtb_ext"
"github.com/prebid/prebid-server/v3/util/jsonutil"
)
type adapter struct {
- endpoint string
+ endpoint *template.Template
}
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
+ endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint)
+ if err != nil {
+ return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
+ }
+
bidder := &adapter{
- endpoint: config.Endpoint,
+ endpoint: endpointTemplate,
}
return bidder, nil
}
func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
- requestJson, err := json.Marshal(request)
+ zetaSspImpExt, err := a.getImpressionExt(&request.Imp[0])
+ if err != nil {
+ return nil, []error{err}
+ }
+
+ endpointURL, err := a.buildEndpointURL(zetaSspImpExt)
+ if err != nil {
+ return nil, []error{err}
+ }
+
+ requestJSON, err := json.Marshal(request)
if err != nil {
return nil, []error{err}
}
@@ -36,8 +54,8 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte
requestData := &adapters.RequestData{
Method: "POST",
- Uri: a.endpoint,
- Body: requestJson,
+ Uri: endpointURL,
+ Body: requestJSON,
Headers: headers,
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
}
@@ -45,6 +63,28 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte
return []*adapters.RequestData{requestData}, nil
}
+func (a *adapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ImpExtZetaGlobalSsp, error) {
+ var bidderExt adapters.ExtImpBidder
+ if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+ return nil, &errortypes.BadInput{
+ Message: "imp.ext not provided or cannot be unmarshalled",
+ }
+ }
+ var zetaSspImpExt openrtb_ext.ImpExtZetaGlobalSsp
+ if err := json.Unmarshal(bidderExt.Bidder, &zetaSspImpExt); err != nil {
+ return nil, &errortypes.BadInput{
+ Message: "imp.ext.bidder not provided or cannot be unmarshalled",
+ }
+ }
+ imp.Ext = nil
+ return &zetaSspImpExt, nil
+}
+
+func (a *adapter) buildEndpointURL(params *openrtb_ext.ImpExtZetaGlobalSsp) (string, error) {
+ endpointParams := macros.EndpointTemplateParams{AccountID: strconv.Itoa(params.Sid)}
+ return macros.ResolveMacros(a.endpoint, endpointParams)
+}
+
func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if adapters.IsResponseStatusCodeNoContent(responseData) {
return nil, nil
diff --git a/adapters/zeta_global_ssp/zeta_global_ssp_test.go b/adapters/zeta_global_ssp/zeta_global_ssp_test.go
index f2b51409165..f7e9b36698d 100644
--- a/adapters/zeta_global_ssp/zeta_global_ssp_test.go
+++ b/adapters/zeta_global_ssp/zeta_global_ssp_test.go
@@ -6,11 +6,12 @@ import (
"github.com/prebid/prebid-server/v3/adapters/adapterstest"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/openrtb_ext"
+ "github.com/stretchr/testify/assert"
)
func TestJsonSamples(t *testing.T) {
bidder, buildErr := Builder(openrtb_ext.BidderZetaGlobalSsp, config.Adapter{
- Endpoint: "https://ssp.disqus.com/bid/prebid-server?sid=11"},
+ Endpoint: "https://ssp.disqus.com/bid/prebid-server?sid={{.AccountID}}"},
config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
if buildErr != nil {
@@ -19,3 +20,11 @@ func TestJsonSamples(t *testing.T) {
adapterstest.RunJSONBidderTest(t, "zeta_global_ssp-test", bidder)
}
+
+func TestEndpointTemplateMalformed(t *testing.T) {
+ _, buildErr := Builder(openrtb_ext.BidderZetaGlobalSsp, config.Adapter{
+ Endpoint: "{{Malformed}}"},
+ config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+
+ assert.Error(t, buildErr)
+}
diff --git a/openrtb_ext/imp_zeta_global_ssp.go b/openrtb_ext/imp_zeta_global_ssp.go
new file mode 100644
index 00000000000..e721523da11
--- /dev/null
+++ b/openrtb_ext/imp_zeta_global_ssp.go
@@ -0,0 +1,5 @@
+package openrtb_ext
+
+type ImpExtZetaGlobalSsp struct {
+ Sid int `json:"sid"`
+}
diff --git a/static/bidder-info/zeta_global_ssp.yaml b/static/bidder-info/zeta_global_ssp.yaml
index 479f024c1b7..f4f50d94b7d 100644
--- a/static/bidder-info/zeta_global_ssp.yaml
+++ b/static/bidder-info/zeta_global_ssp.yaml
@@ -1,5 +1,8 @@
-endpoint: https://ssp.disqus.com/bid/prebid-server?sid=GET_SID_FROM_ZETA
+disabled: true
+endpoint: https://ssp.disqus.com/bid/prebid-server?sid={{.AccountID}}
endpointCompression: gzip
+geoscope:
+ - global
maintainer:
email: DL-Zeta-SSP@zetaglobal.com
gvlVendorID: 833
@@ -9,12 +12,14 @@ capabilities:
mediaTypes:
- banner
- video
+ - audio
site:
mediaTypes:
- banner
- video
+ - audio
userSync:
redirect:
- url: https://ssp.disqus.com/redirectuser?sid=GET_SID_FROM_ZETA&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r={{.RedirectURL}}
+ url: https://ssp.disqus.com/redirectuser?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r={{.RedirectURL}}
userMacro: 'BUYERUID'
diff --git a/static/bidder-params/zeta_global_ssp.json b/static/bidder-params/zeta_global_ssp.json
index acfaa9c1988..8a6d1d0a060 100644
--- a/static/bidder-params/zeta_global_ssp.json
+++ b/static/bidder-params/zeta_global_ssp.json
@@ -4,5 +4,10 @@
"description": "A schema which validates params accepted by the Zeta Global SSP adapter",
"type": "object",
- "properties": {}
+ "properties": {
+ "sid": {
+ "type": "integer",
+ "description": "An ID which identifies the publisher"
+ }
+ }
}
From 09006e7fee71342242755af541e74e49a717314b Mon Sep 17 00:00:00 2001
From: Alexander Pykhteyev
Date: Tue, 11 Mar 2025 04:11:34 +0700
Subject: [PATCH 02/40] New Adapter: OCM Media - Limelight Alias (#4210)
Co-authored-by: apykhteyev
---
static/bidder-info/orangeclickmedia.yaml | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 static/bidder-info/orangeclickmedia.yaml
diff --git a/static/bidder-info/orangeclickmedia.yaml b/static/bidder-info/orangeclickmedia.yaml
new file mode 100644
index 00000000000..841c4cd49e6
--- /dev/null
+++ b/static/bidder-info/orangeclickmedia.yaml
@@ -0,0 +1,2 @@
+endpoint: "http://ads-pbs.scotty.orangeclickmedia.com/openrtb/{{.PublisherID}}?host={{.Host}}"
+aliasOf: "limelightDigital"
From ce862087ac80c795ef81f999f9338c0ea4d29d26 Mon Sep 17 00:00:00 2001
From: Deivydas
Date: Tue, 11 Mar 2025 16:45:23 +0000
Subject: [PATCH 03/40] Aidem: Support only banner and video formats (#4203)
---
adapters/aidem/aidem.go | 4 ----
static/bidder-info/aidem.yaml | 2 --
static/bidder-params/aidem.json | 7 +++++--
3 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/adapters/aidem/aidem.go b/adapters/aidem/aidem.go
index d644d83cdf2..6e8a7409594 100644
--- a/adapters/aidem/aidem.go
+++ b/adapters/aidem/aidem.go
@@ -112,10 +112,6 @@ func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
return openrtb_ext.BidTypeBanner, nil
case openrtb2.MarkupVideo:
return openrtb_ext.BidTypeVideo, nil
- case openrtb2.MarkupAudio:
- return openrtb_ext.BidTypeAudio, nil
- case openrtb2.MarkupNative:
- return openrtb_ext.BidTypeNative, nil
default:
return "", fmt.Errorf("Unable to fetch mediaType in multi-format: %s", bid.ImpID)
}
diff --git a/static/bidder-info/aidem.yaml b/static/bidder-info/aidem.yaml
index 70f63526879..5cf6aac80c1 100644
--- a/static/bidder-info/aidem.yaml
+++ b/static/bidder-info/aidem.yaml
@@ -7,12 +7,10 @@ capabilities:
mediaTypes:
- banner
- video
- - native
site:
mediaTypes:
- banner
- video
- - native
userSync:
redirect:
url: https://gum.aidemsrv.com/prebid_sync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}
diff --git a/static/bidder-params/aidem.json b/static/bidder-params/aidem.json
index 221e5ff7a92..0483dc4da25 100644
--- a/static/bidder-params/aidem.json
+++ b/static/bidder-params/aidem.json
@@ -17,7 +17,7 @@
"placementId": {
"type": "string",
"minLength": 1,
- "description": "Unique publisher ttag ID"
+ "description": "Unique publisher tag ID"
},
"rateLimit": {
"type": "number",
@@ -25,5 +25,8 @@
"maximum": 1
}
},
- "required": ["siteId", "publisherId"]
+ "required": [
+ "siteId",
+ "publisherId"
+ ]
}
\ No newline at end of file
From aa0edd4a87347b468e875e148bbfc853fa42735f Mon Sep 17 00:00:00 2001
From: Alexander Pykhteyev
Date: Wed, 12 Mar 2025 00:32:31 +0700
Subject: [PATCH 04/40] New Adapter: Velonium - Limelight Alias (#4212)
Co-authored-by: apykhteyev
---
static/bidder-info/velonium.yaml | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 static/bidder-info/velonium.yaml
diff --git a/static/bidder-info/velonium.yaml b/static/bidder-info/velonium.yaml
new file mode 100644
index 00000000000..0a90a983267
--- /dev/null
+++ b/static/bidder-info/velonium.yaml
@@ -0,0 +1,2 @@
+endpoint: "http://ads-pbs.adxvel.com/openrtb/{{.PublisherID}}?host={{.Host}}"
+aliasOf: "limelightDigital"
From 3eb74d65678579f22a6cc97566fc5a73e0ae6628 Mon Sep 17 00:00:00 2001
From: kalidas-alkimi <92875788+kalidas-alkimi@users.noreply.github.com>
Date: Tue, 11 Mar 2025 18:11:11 +0000
Subject: [PATCH 05/40] Alkimi: Add imp extension support (#4213)
---
adapters/alkimi/alkimi.go | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go
index 4f924bb15e6..c85b7933158 100644
--- a/adapters/alkimi/alkimi.go
+++ b/adapters/alkimi/alkimi.go
@@ -24,10 +24,6 @@ type adapter struct {
endpoint string
}
-type extObj struct {
- AlkimiBidderExt openrtb_ext.ExtImpAlkimi `json:"bidder"`
-}
-
// Builder builds a new instance of the Alkimi adapter for the given bidder with the given config.
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
endpointURL, err := url.Parse(config.Endpoint)
@@ -67,7 +63,7 @@ func updateImps(bidRequest openrtb2.BidRequest) ([]openrtb2.Imp, []error) {
updatedImps := make([]openrtb2.Imp, 0, len(bidRequest.Imp))
for _, imp := range bidRequest.Imp {
- var bidderExt adapters.ExtImpBidder
+ var bidderExt = make(map[string]json.RawMessage)
var extImpAlkimi openrtb_ext.ExtImpAlkimi
if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil {
@@ -75,7 +71,7 @@ func updateImps(bidRequest openrtb2.BidRequest) ([]openrtb2.Imp, []error) {
continue
}
- if err := jsonutil.Unmarshal(bidderExt.Bidder, &extImpAlkimi); err != nil {
+ if err := jsonutil.Unmarshal(bidderExt["bidder"], &extImpAlkimi); err != nil {
errs = append(errs, err)
continue
}
@@ -92,15 +88,24 @@ func updateImps(bidRequest openrtb2.BidRequest) ([]openrtb2.Imp, []error) {
imp.Instl = extImpAlkimi.Instl
imp.Exp = extImpAlkimi.Exp
- temp := extObj{AlkimiBidderExt: extImpAlkimi}
- temp.AlkimiBidderExt.AdUnitCode = imp.ID
+ temp := extImpAlkimi
+ temp.AdUnitCode = imp.ID
+
+ tempJson, err := jsonutil.Marshal(temp)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+
+ newExt := bidderExt
+ newExt["bidder"] = tempJson
- extJson, err := json.Marshal(temp)
+ newExtJson, err := jsonutil.Marshal(newExt)
if err != nil {
errs = append(errs, err)
continue
}
- imp.Ext = extJson
+ imp.Ext = newExtJson
updatedImps = append(updatedImps, imp)
}
From 777408c7cbc1b95c1357b0bfd3e8a1c22e729ecc Mon Sep 17 00:00:00 2001
From: product-trustedstack
<141160331+product-trustedstack@users.noreply.github.com>
Date: Wed, 12 Mar 2025 00:11:03 +0530
Subject: [PATCH 06/40] Trustedstack: Add iframe usersync (#4222)
---
static/bidder-info/trustedstack.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/static/bidder-info/trustedstack.yaml b/static/bidder-info/trustedstack.yaml
index ffa48d261d4..09bb3313327 100644
--- a/static/bidder-info/trustedstack.yaml
+++ b/static/bidder-info/trustedstack.yaml
@@ -19,6 +19,9 @@ capabilities:
- video
- native
userSync:
+ iframe:
+ url: https://hb.trustedstack.com/checksync.php?cid=TS2Q14L8J&cs=87&type=mpbc&cv=37&vsSync=1&uspstring={{.USPrivacy}}&gdpr={{.GDPR}}&gdprstring={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}
+ userMacro: ""
redirect:
url: https://hb.trustedstack.com/cksync?cs=1&type=pbs&ovsid=setstatuscode&bidder=trustedstack&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}
userMacro: ""
\ No newline at end of file
From d9ca30f36d8dafd91268cdaebd1d22ad284d8de1 Mon Sep 17 00:00:00 2001
From: Alexander Pykhteyev
Date: Wed, 12 Mar 2025 01:54:15 +0700
Subject: [PATCH 07/40] IIon: Add GVL ID (#4253)
---
static/bidder-info/iionads.yaml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/static/bidder-info/iionads.yaml b/static/bidder-info/iionads.yaml
index 1dc154a358d..b782cc96116 100644
--- a/static/bidder-info/iionads.yaml
+++ b/static/bidder-info/iionads.yaml
@@ -1,2 +1,3 @@
endpoint: "http://ads-pbs.iionads.com/openrtb/{{.PublisherID}}?host={{.Host}}"
-aliasOf: "limelightDigital"
\ No newline at end of file
+aliasOf: "limelightDigital"
+gvlVendorID: 1358
From b130a5c26bf2fe491b28837526111fb3a0751502 Mon Sep 17 00:00:00 2001
From: bretg
Date: Wed, 12 Mar 2025 13:27:50 -0400
Subject: [PATCH 08/40] codepath-notification adapter updates (#4245)
---
.github/workflows/scripts/codepath-notification | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.github/workflows/scripts/codepath-notification b/.github/workflows/scripts/codepath-notification
index c59eaf2e41c..5a029531403 100644
--- a/.github/workflows/scripts/codepath-notification
+++ b/.github/workflows/scripts/codepath-notification
@@ -13,3 +13,7 @@
# The aim is to find a minimal set of regex patterns that matches any file in these paths
rubicon: header-bidding@magnite.com
+pubmatic: header-bidding@pubmatic.com
+openx: prebid@openx.com
+adapters/ix|imp_ix|ix.json|ix.yaml: pdu-supply-prebid@indexexchange.com
+medianet: prebid-support@media.net
From b2efcdf9d98f02b0383214452cfdd5b1ef3bd3fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Abdulbaki=20=C3=87am?=
<71071893+bakicam@users.noreply.github.com>
Date: Thu, 13 Mar 2025 16:31:30 +0300
Subject: [PATCH 09/40] New Adapter: Pixad - Admatic alias (#4214)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Faruk Çam
---
static/bidder-info/pixad.yaml | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 static/bidder-info/pixad.yaml
diff --git a/static/bidder-info/pixad.yaml b/static/bidder-info/pixad.yaml
new file mode 100644
index 00000000000..d08230bfbc3
--- /dev/null
+++ b/static/bidder-info/pixad.yaml
@@ -0,0 +1,3 @@
+aliasOf: "admatic"
+maintainer:
+ email: "prebid@pixad.com.tr"
\ No newline at end of file
From dbe41e45cdc04097e1fd0877ce529231b6adeef9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Abdulbaki=20=C3=87am?=
<71071893+bakicam@users.noreply.github.com>
Date: Thu, 13 Mar 2025 17:24:27 +0300
Subject: [PATCH 10/40] New Adapter: Monetix Ads - Admatic alias (#4215)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Faruk Çam
---
static/bidder-info/monetixads.yaml | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 static/bidder-info/monetixads.yaml
diff --git a/static/bidder-info/monetixads.yaml b/static/bidder-info/monetixads.yaml
new file mode 100644
index 00000000000..95beda701f0
--- /dev/null
+++ b/static/bidder-info/monetixads.yaml
@@ -0,0 +1,3 @@
+aliasOf: "admatic"
+maintainer:
+ email: "team@monetixads.com"
\ No newline at end of file
From 6a654e1f40df829beaff6bac5b3bc1c9430977ae Mon Sep 17 00:00:00 2001
From: Sheridan C Rawlins <41922797+scr-oath@users.noreply.github.com>
Date: Thu, 13 Mar 2025 07:36:38 -0700
Subject: [PATCH 11/40] Upgrade jsonpatch to v5 (#4071)
---
adapters/relevantdigital/relevantdigital.go | 2 +-
adservertargeting/respdataprocessor.go | 2 +-
endpoints/openrtb2/amp_auction.go | 2 +-
endpoints/openrtb2/auction.go | 2 +-
endpoints/openrtb2/test_utils.go | 2 +-
endpoints/openrtb2/video_auction.go | 2 +-
exchange/events.go | 2 +-
exchange/exchange_test.go | 2 +-
firstpartydata/first_party_data.go | 2 +-
go.mod | 2 +-
go.sum | 4 ++--
hooks/hookexecution/enricher.go | 2 +-
stored_requests/backends/file_fetcher/fetcher.go | 5 ++++-
stored_requests/backends/file_fetcher/fetcher_test.go | 4 ++++
stored_requests/backends/http_fetcher/fetcher.go | 5 ++++-
util/jsonutil/merge.go | 2 +-
16 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/adapters/relevantdigital/relevantdigital.go b/adapters/relevantdigital/relevantdigital.go
index 35789f3b841..702dca6b271 100644
--- a/adapters/relevantdigital/relevantdigital.go
+++ b/adapters/relevantdigital/relevantdigital.go
@@ -16,7 +16,7 @@ import (
"github.com/prebid/prebid-server/v3/macros"
"github.com/prebid/prebid-server/v3/openrtb_ext"
"github.com/prebid/prebid-server/v3/util/jsonutil"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
)
type adapter struct {
diff --git a/adservertargeting/respdataprocessor.go b/adservertargeting/respdataprocessor.go
index c3ad25aa62a..529abcfd15a 100644
--- a/adservertargeting/respdataprocessor.go
+++ b/adservertargeting/respdataprocessor.go
@@ -8,7 +8,7 @@ import (
"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v3/openrtb_ext"
"github.com/prebid/prebid-server/v3/util/jsonutil"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
)
const MaxKeyLength = 20
diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go
index b596ec793c6..6f37d49fca5 100644
--- a/endpoints/openrtb2/amp_auction.go
+++ b/endpoints/openrtb2/amp_auction.go
@@ -19,7 +19,7 @@ import (
"github.com/prebid/prebid-server/v3/hooks/hookexecution"
"github.com/prebid/prebid-server/v3/ortb"
"github.com/prebid/prebid-server/v3/util/uuidutil"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
accountService "github.com/prebid/prebid-server/v3/account"
"github.com/prebid/prebid-server/v3/amp"
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index e4faa7e9cb8..0a1aa450cfe 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -29,7 +29,7 @@ import (
"github.com/prebid/prebid-server/v3/privacysandbox"
"github.com/prebid/prebid-server/v3/schain"
"golang.org/x/net/publicsuffix"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
accountService "github.com/prebid/prebid-server/v3/account"
"github.com/prebid/prebid-server/v3/analytics"
diff --git a/endpoints/openrtb2/test_utils.go b/endpoints/openrtb2/test_utils.go
index e869ded80b8..92e54ed3ed4 100644
--- a/endpoints/openrtb2/test_utils.go
+++ b/endpoints/openrtb2/test_utils.go
@@ -41,7 +41,7 @@ import (
"github.com/prebid/prebid-server/v3/util/iputil"
"github.com/prebid/prebid-server/v3/util/jsonutil"
"github.com/prebid/prebid-server/v3/util/uuidutil"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
)
// In this file we define:
diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go
index cf18840fbd6..f3dbd2246c0 100644
--- a/endpoints/openrtb2/video_auction.go
+++ b/endpoints/openrtb2/video_auction.go
@@ -21,7 +21,7 @@ import (
"github.com/prebid/prebid-server/v3/hooks/hookexecution"
"github.com/prebid/prebid-server/v3/ortb"
"github.com/prebid/prebid-server/v3/privacy"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
accountService "github.com/prebid/prebid-server/v3/account"
"github.com/prebid/prebid-server/v3/analytics"
diff --git a/exchange/events.go b/exchange/events.go
index d52db53aac6..20150f90b97 100644
--- a/exchange/events.go
+++ b/exchange/events.go
@@ -4,7 +4,7 @@ import (
"time"
"github.com/prebid/prebid-server/v3/exchange/entities"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
"github.com/prebid/prebid-server/v3/analytics"
"github.com/prebid/prebid-server/v3/config"
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 7edbec64d7e..1370065f1f8 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -46,7 +46,7 @@ import (
"github.com/prebid/prebid-server/v3/util/ptrutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
)
func TestNewExchange(t *testing.T) {
diff --git a/firstpartydata/first_party_data.go b/firstpartydata/first_party_data.go
index 44a3241a53c..a9107efa6fc 100644
--- a/firstpartydata/first_party_data.go
+++ b/firstpartydata/first_party_data.go
@@ -7,7 +7,7 @@ import (
"strings"
"github.com/prebid/openrtb/v20/openrtb2"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
"github.com/prebid/prebid-server/v3/errortypes"
"github.com/prebid/prebid-server/v3/openrtb_ext"
diff --git a/go.mod b/go.mod
index c8e1d25d309..37c169a2c2e 100644
--- a/go.mod
+++ b/go.mod
@@ -43,7 +43,7 @@ require (
golang.org/x/net v0.33.0
golang.org/x/text v0.21.0
google.golang.org/grpc v1.56.3
- gopkg.in/evanphx/json-patch.v4 v4.12.0
+ gopkg.in/evanphx/json-patch.v5 v5.9.0
gopkg.in/yaml.v3 v3.0.1
)
diff --git a/go.sum b/go.sum
index cd2900708bf..f3541a92f08 100644
--- a/go.sum
+++ b/go.sum
@@ -987,8 +987,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
-gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
+gopkg.in/evanphx/json-patch.v5 v5.9.0 h1:hx1VU2SGj4F8r9b8GUwJLdc8DNO8sy79ZGui0G05GLo=
+gopkg.in/evanphx/json-patch.v5 v5.9.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
diff --git a/hooks/hookexecution/enricher.go b/hooks/hookexecution/enricher.go
index 7ca9f65f176..17a2eb9cc96 100644
--- a/hooks/hookexecution/enricher.go
+++ b/hooks/hookexecution/enricher.go
@@ -7,7 +7,7 @@ import (
"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/util/jsonutil"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
)
const (
diff --git a/stored_requests/backends/file_fetcher/fetcher.go b/stored_requests/backends/file_fetcher/fetcher.go
index 1c51a353fb8..6bb8bc1447b 100644
--- a/stored_requests/backends/file_fetcher/fetcher.go
+++ b/stored_requests/backends/file_fetcher/fetcher.go
@@ -10,7 +10,7 @@ import (
"github.com/prebid/prebid-server/v3/stored_requests"
"github.com/prebid/prebid-server/v3/util/jsonutil"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
)
// NewFileFetcher _immediately_ loads stored request data from local files.
@@ -60,6 +60,9 @@ func (fetcher *eagerFetcher) FetchAccount(ctx context.Context, accountDefaultsJS
}}
}
+ if accountDefaultsJSON == nil {
+ return accountJSON, nil
+ }
completeJSON, err := jsonpatch.MergePatch(accountDefaultsJSON, accountJSON)
if err != nil {
return nil, []error{err}
diff --git a/stored_requests/backends/file_fetcher/fetcher_test.go b/stored_requests/backends/file_fetcher/fetcher_test.go
index 80e45bb9445..735045dd9fe 100644
--- a/stored_requests/backends/file_fetcher/fetcher_test.go
+++ b/stored_requests/backends/file_fetcher/fetcher_test.go
@@ -83,6 +83,10 @@ func TestAccountFetcher(t *testing.T) {
assertErrorCount(t, 0, errs)
assert.JSONEq(t, `{"disabled":false, "events_enabled":true, "id":"valid" }`, string(account))
+ account, errs = fetcher.FetchAccount(context.Background(), nil, "valid")
+ assertErrorCount(t, 0, errs)
+ assert.JSONEq(t, `{"disabled":false, "id":"valid" }`, string(account))
+
_, errs = fetcher.FetchAccount(context.Background(), json.RawMessage(`{"events_enabled":true}`), "nonexistent")
assertErrorCount(t, 1, errs)
assert.Error(t, errs[0])
diff --git a/stored_requests/backends/http_fetcher/fetcher.go b/stored_requests/backends/http_fetcher/fetcher.go
index dc4dd03a1fe..7f765b99327 100644
--- a/stored_requests/backends/http_fetcher/fetcher.go
+++ b/stored_requests/backends/http_fetcher/fetcher.go
@@ -11,7 +11,7 @@ import (
"github.com/prebid/prebid-server/v3/stored_requests"
"github.com/prebid/prebid-server/v3/util/jsonutil"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
"github.com/golang/glog"
"golang.org/x/net/context/ctxhttp"
@@ -164,6 +164,9 @@ func (fetcher *HttpFetcher) FetchAccount(ctx context.Context, accountDefaultsJSO
DataType: "Account",
}}
}
+ if accountDefaultsJSON == nil {
+ return accountJSON, nil
+ }
completeJSON, err := jsonpatch.MergePatch(accountDefaultsJSON, accountJSON)
if err != nil {
return nil, []error{err}
diff --git a/util/jsonutil/merge.go b/util/jsonutil/merge.go
index 2b7edc6ee25..6dff8afca64 100644
--- a/util/jsonutil/merge.go
+++ b/util/jsonutil/merge.go
@@ -8,7 +8,7 @@ import (
jsoniter "github.com/json-iterator/go"
"github.com/modern-go/reflect2"
- jsonpatch "gopkg.in/evanphx/json-patch.v4"
+ jsonpatch "gopkg.in/evanphx/json-patch.v5"
"github.com/prebid/prebid-server/v3/errortypes"
)
From 57ebb19bc8192474ff59285a6f842a13406fa853 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Abdulbaki=20=C3=87am?=
<71071893+bakicam@users.noreply.github.com>
Date: Thu, 13 Mar 2025 18:08:59 +0300
Subject: [PATCH 12/40] New Adapter: Admatic GMBH - Admatic alias (#4216)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Faruk Çam
---
static/bidder-info/admaticde.yaml | 1 +
1 file changed, 1 insertion(+)
create mode 100644 static/bidder-info/admaticde.yaml
diff --git a/static/bidder-info/admaticde.yaml b/static/bidder-info/admaticde.yaml
new file mode 100644
index 00000000000..562aa183695
--- /dev/null
+++ b/static/bidder-info/admaticde.yaml
@@ -0,0 +1 @@
+aliasOf: "admatic"
\ No newline at end of file
From eb13b8bf99f4173de8919ce288a967ea29ea4956 Mon Sep 17 00:00:00 2001
From: monicaroxanabota <55977025+monicaroxanabota@users.noreply.github.com>
Date: Fri, 14 Mar 2025 16:01:31 +0200
Subject: [PATCH 13/40] Connatix: Enhance endpoint with DC (#4219)
---
adapters/connatix/connatix.go | 27 ++-
.../supplemental/bid-request-eu-user.json | 176 ++++++++++++++++++
.../supplemental/bid-request-no-user.json | 170 +++++++++++++++++
.../bid-request-us-east-user.json | 176 ++++++++++++++++++
.../bid-request-us-west-user.json | 176 ++++++++++++++++++
5 files changed, 724 insertions(+), 1 deletion(-)
create mode 100644 adapters/connatix/connatixtest/supplemental/bid-request-eu-user.json
create mode 100644 adapters/connatix/connatixtest/supplemental/bid-request-no-user.json
create mode 100644 adapters/connatix/connatixtest/supplemental/bid-request-us-east-user.json
create mode 100644 adapters/connatix/connatixtest/supplemental/bid-request-us-west-user.json
diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go
index d2f900d9c22..11cf7a146ab 100644
--- a/adapters/connatix/connatix.go
+++ b/adapters/connatix/connatix.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"net/http"
+ "net/url"
"strings"
"github.com/buger/jsonparser"
@@ -155,9 +156,33 @@ func splitRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, uri string
return nil, errs
}
+ endpoint, err := url.Parse(uri)
+ if err != nil {
+ errs = append(errs, err)
+ return nil, errs
+ }
+
+ if request.User != nil {
+ userID := strings.TrimSpace(request.User.BuyerUID)
+
+ if len(userID) > 0 {
+ queryParams := url.Values{}
+
+ if strings.HasPrefix(userID, "1-") {
+ queryParams.Add("dc", "us-east-2")
+ } else if strings.HasPrefix(userID, "2-") {
+ queryParams.Add("dc", "us-west-2")
+ } else if strings.HasPrefix(userID, "3-") {
+ queryParams.Add("dc", "eu-west-1")
+ }
+
+ endpoint.RawQuery = queryParams.Encode()
+ }
+ }
+
resArr = append(resArr, &adapters.RequestData{
Method: "POST",
- Uri: uri,
+ Uri: endpoint.String(),
Body: reqJSON,
Headers: headers,
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
diff --git a/adapters/connatix/connatixtest/supplemental/bid-request-eu-user.json b/adapters/connatix/connatixtest/supplemental/bid-request-eu-user.json
new file mode 100644
index 00000000000..a5bb8550aba
--- /dev/null
+++ b/adapters/connatix/connatixtest/supplemental/bid-request-eu-user.json
@@ -0,0 +1,176 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 500,
+ "user": {
+ "buyeruid": "3-some-user"
+ },
+ "app": {
+ "publisher": {
+ "id": "123456789"
+ },
+ "cat": [
+ "IAB22-1"
+ ],
+ "bundle": "com.app.awesome",
+ "name": "Awesome App",
+ "domain": "awesomeapp.com",
+ "id": "123456789",
+ "ext": {
+ "prebid": {
+ "source": "test",
+ "version": "1.0.0"
+ }
+ }
+ },
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "tagid": "some-tag-id",
+ "banner": {
+ "format":[
+ {
+ "w": 320,
+ "h": 50
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "some-placement-id",
+ "viewabilityPercentage": 0.6
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://example.com?dc=eu-west-1",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "tagid": "some-tag-id",
+ "banner": {
+ "w": 320,
+ "h": 50,
+ "format": [
+ {
+ "w": 320,
+ "h": 50
+ }
+ ]
+ },
+ "displaymanagerver": "test-1.0.0",
+ "ext": {
+ "connatix": {
+ "placementId": "some-placement-id",
+ "viewabilityPercentage": 0.6
+ }
+ }
+ }
+ ],
+ "app": {
+ "id": "123456789",
+ "name": "Awesome App",
+ "bundle": "com.app.awesome",
+ "domain": "awesomeapp.com",
+ "cat": [
+ "IAB22-1"
+ ],
+ "publisher": {
+ "id": "123456789"
+ },
+ "ext": {
+ "prebid": {
+ "source": "test",
+ "version": "1.0.0"
+ }
+ }
+ },
+ "user": {
+ "buyeruid": "3-some-user"
+ },
+ "tmax": 500
+ },
+ "impIDs": [
+ "some-imp-id"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-response-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "some-bid-id",
+ "impid": "some-imp-id",
+ "price": 0.52,
+ "adm": "some-test-ad",
+ "adomain": [
+ "test.com"
+ ],
+ "crid": "112233",
+ "w": 320,
+ "h": 50,
+ "ext": {
+ "connatix": {
+ "mediaType": "banner"
+ }
+ }
+ }
+ ],
+ "seat": "connatix",
+ "group": 0
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "some-bid-id",
+ "impid": "some-imp-id",
+ "price": 0.52,
+ "adm": "some-test-ad",
+ "crid": "112233",
+ "adomain": [
+ "test.com"
+ ],
+ "w": 320,
+ "h": 50,
+ "ext": {
+ "connatix": {
+ "mediaType": "banner"
+ }
+ }
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/adapters/connatix/connatixtest/supplemental/bid-request-no-user.json b/adapters/connatix/connatixtest/supplemental/bid-request-no-user.json
new file mode 100644
index 00000000000..75ddabdef7c
--- /dev/null
+++ b/adapters/connatix/connatixtest/supplemental/bid-request-no-user.json
@@ -0,0 +1,170 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 500,
+ "app": {
+ "publisher": {
+ "id": "123456789"
+ },
+ "cat": [
+ "IAB22-1"
+ ],
+ "bundle": "com.app.awesome",
+ "name": "Awesome App",
+ "domain": "awesomeapp.com",
+ "id": "123456789",
+ "ext": {
+ "prebid": {
+ "source": "test",
+ "version": "1.0.0"
+ }
+ }
+ },
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "tagid": "some-tag-id",
+ "banner": {
+ "format":[
+ {
+ "w": 320,
+ "h": 50
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "some-placement-id",
+ "viewabilityPercentage": 0.6
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://example.com",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "tagid": "some-tag-id",
+ "banner": {
+ "w": 320,
+ "h": 50,
+ "format": [
+ {
+ "w": 320,
+ "h": 50
+ }
+ ]
+ },
+ "displaymanagerver": "test-1.0.0",
+ "ext": {
+ "connatix": {
+ "placementId": "some-placement-id",
+ "viewabilityPercentage": 0.6
+ }
+ }
+ }
+ ],
+ "app": {
+ "id": "123456789",
+ "name": "Awesome App",
+ "bundle": "com.app.awesome",
+ "domain": "awesomeapp.com",
+ "cat": [
+ "IAB22-1"
+ ],
+ "publisher": {
+ "id": "123456789"
+ },
+ "ext": {
+ "prebid": {
+ "source": "test",
+ "version": "1.0.0"
+ }
+ }
+ },
+ "tmax": 500
+ },
+ "impIDs": [
+ "some-imp-id"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-response-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "some-bid-id",
+ "impid": "some-imp-id",
+ "price": 0.52,
+ "adm": "some-test-ad",
+ "adomain": [
+ "test.com"
+ ],
+ "crid": "112233",
+ "w": 320,
+ "h": 50,
+ "ext": {
+ "connatix": {
+ "mediaType": "banner"
+ }
+ }
+ }
+ ],
+ "seat": "connatix",
+ "group": 0
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "some-bid-id",
+ "impid": "some-imp-id",
+ "price": 0.52,
+ "adm": "some-test-ad",
+ "crid": "112233",
+ "adomain": [
+ "test.com"
+ ],
+ "w": 320,
+ "h": 50,
+ "ext": {
+ "connatix": {
+ "mediaType": "banner"
+ }
+ }
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/adapters/connatix/connatixtest/supplemental/bid-request-us-east-user.json b/adapters/connatix/connatixtest/supplemental/bid-request-us-east-user.json
new file mode 100644
index 00000000000..279047b168e
--- /dev/null
+++ b/adapters/connatix/connatixtest/supplemental/bid-request-us-east-user.json
@@ -0,0 +1,176 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 500,
+ "user": {
+ "buyeruid": "1-some-user"
+ },
+ "app": {
+ "publisher": {
+ "id": "123456789"
+ },
+ "cat": [
+ "IAB22-1"
+ ],
+ "bundle": "com.app.awesome",
+ "name": "Awesome App",
+ "domain": "awesomeapp.com",
+ "id": "123456789",
+ "ext": {
+ "prebid": {
+ "source": "test",
+ "version": "1.0.0"
+ }
+ }
+ },
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "tagid": "some-tag-id",
+ "banner": {
+ "format":[
+ {
+ "w": 320,
+ "h": 50
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "some-placement-id",
+ "viewabilityPercentage": 0.6
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://example.com?dc=us-east-2",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "tagid": "some-tag-id",
+ "banner": {
+ "w": 320,
+ "h": 50,
+ "format": [
+ {
+ "w": 320,
+ "h": 50
+ }
+ ]
+ },
+ "displaymanagerver": "test-1.0.0",
+ "ext": {
+ "connatix": {
+ "placementId": "some-placement-id",
+ "viewabilityPercentage": 0.6
+ }
+ }
+ }
+ ],
+ "app": {
+ "id": "123456789",
+ "name": "Awesome App",
+ "bundle": "com.app.awesome",
+ "domain": "awesomeapp.com",
+ "cat": [
+ "IAB22-1"
+ ],
+ "publisher": {
+ "id": "123456789"
+ },
+ "ext": {
+ "prebid": {
+ "source": "test",
+ "version": "1.0.0"
+ }
+ }
+ },
+ "user": {
+ "buyeruid": "1-some-user"
+ },
+ "tmax": 500
+ },
+ "impIDs": [
+ "some-imp-id"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-response-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "some-bid-id",
+ "impid": "some-imp-id",
+ "price": 0.52,
+ "adm": "some-test-ad",
+ "adomain": [
+ "test.com"
+ ],
+ "crid": "112233",
+ "w": 320,
+ "h": 50,
+ "ext": {
+ "connatix": {
+ "mediaType": "banner"
+ }
+ }
+ }
+ ],
+ "seat": "connatix",
+ "group": 0
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "some-bid-id",
+ "impid": "some-imp-id",
+ "price": 0.52,
+ "adm": "some-test-ad",
+ "crid": "112233",
+ "adomain": [
+ "test.com"
+ ],
+ "w": 320,
+ "h": 50,
+ "ext": {
+ "connatix": {
+ "mediaType": "banner"
+ }
+ }
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/adapters/connatix/connatixtest/supplemental/bid-request-us-west-user.json b/adapters/connatix/connatixtest/supplemental/bid-request-us-west-user.json
new file mode 100644
index 00000000000..6b12ebda6cf
--- /dev/null
+++ b/adapters/connatix/connatixtest/supplemental/bid-request-us-west-user.json
@@ -0,0 +1,176 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 500,
+ "user": {
+ "buyeruid": "2-some-user"
+ },
+ "app": {
+ "publisher": {
+ "id": "123456789"
+ },
+ "cat": [
+ "IAB22-1"
+ ],
+ "bundle": "com.app.awesome",
+ "name": "Awesome App",
+ "domain": "awesomeapp.com",
+ "id": "123456789",
+ "ext": {
+ "prebid": {
+ "source": "test",
+ "version": "1.0.0"
+ }
+ }
+ },
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "tagid": "some-tag-id",
+ "banner": {
+ "format":[
+ {
+ "w": 320,
+ "h": 50
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "some-placement-id",
+ "viewabilityPercentage": 0.6
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://example.com?dc=us-west-2",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "tagid": "some-tag-id",
+ "banner": {
+ "w": 320,
+ "h": 50,
+ "format": [
+ {
+ "w": 320,
+ "h": 50
+ }
+ ]
+ },
+ "displaymanagerver": "test-1.0.0",
+ "ext": {
+ "connatix": {
+ "placementId": "some-placement-id",
+ "viewabilityPercentage": 0.6
+ }
+ }
+ }
+ ],
+ "app": {
+ "id": "123456789",
+ "name": "Awesome App",
+ "bundle": "com.app.awesome",
+ "domain": "awesomeapp.com",
+ "cat": [
+ "IAB22-1"
+ ],
+ "publisher": {
+ "id": "123456789"
+ },
+ "ext": {
+ "prebid": {
+ "source": "test",
+ "version": "1.0.0"
+ }
+ }
+ },
+ "user": {
+ "buyeruid": "2-some-user"
+ },
+ "tmax": 500
+ },
+ "impIDs": [
+ "some-imp-id"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-response-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "some-bid-id",
+ "impid": "some-imp-id",
+ "price": 0.52,
+ "adm": "some-test-ad",
+ "adomain": [
+ "test.com"
+ ],
+ "crid": "112233",
+ "w": 320,
+ "h": 50,
+ "ext": {
+ "connatix": {
+ "mediaType": "banner"
+ }
+ }
+ }
+ ],
+ "seat": "connatix",
+ "group": 0
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "some-bid-id",
+ "impid": "some-imp-id",
+ "price": 0.52,
+ "adm": "some-test-ad",
+ "crid": "112233",
+ "adomain": [
+ "test.com"
+ ],
+ "w": 320,
+ "h": 50,
+ "ext": {
+ "connatix": {
+ "mediaType": "banner"
+ }
+ }
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+ }
\ No newline at end of file
From 50d25182fb2b0acf51f65702168a4ff124da2923 Mon Sep 17 00:00:00 2001
From: Sigma Software
Date: Thu, 20 Mar 2025 20:37:30 +0200
Subject: [PATCH 14/40] Currency: Common currency reference conversion (#4205)
---
currency/aggregate_conversions_test.go | 11 +++-
currency/rates.go | 20 ++++++-
currency/rates_test.go | 77 ++++++++++++++++++++++++++
3 files changed, 105 insertions(+), 3 deletions(-)
diff --git a/currency/aggregate_conversions_test.go b/currency/aggregate_conversions_test.go
index d2ac961a8a7..d31422737d6 100644
--- a/currency/aggregate_conversions_test.go
+++ b/currency/aggregate_conversions_test.go
@@ -64,9 +64,16 @@ func TestGroupedGetRate(t *testing.T) {
},
},
{
- expectedError: ConversionNotFoundError{FromCur: "GBP", ToCur: "EUR"},
+ expectedError: ConversionNotFoundError{FromCur: "RON", ToCur: "EUR"},
testCases: []aTest{
- {"Valid three-digit currency codes, but conversion rate not found", "GBP", "EUR", 0},
+ {"Valid three-digit currency codes, but conversion from-currency rate not found", "RON", "EUR", 0},
+ {"Valid three-digit currency codes, but conversion to-currency rate not found", "EUR", "RON", 0},
+ },
+ },
+ {
+ expectedError: nil,
+ testCases: []aTest{
+ {"Valid three-digit currency codes, intermediate conversion rate has been used", "GBP", "EUR", 2 / 3.0},
},
},
}
diff --git a/currency/rates.go b/currency/rates.go
index f36eddfac81..87d40469627 100644
--- a/currency/rates.go
+++ b/currency/rates.go
@@ -20,6 +20,22 @@ func NewRates(conversions map[string]map[string]float64) *Rates {
}
}
+// FindIntermediateConversionRate returns the conversion rate between two currencies
+// if a valid conversion exists in the provided rates container.
+// Otherwise, it returns a ConversionNotFoundError.
+func FindIntermediateConversionRate(r *Rates, from, to currency.Unit) (float64, error) {
+ for _, conversions := range r.Conversions {
+ toRate, hasToRate := conversions[to.String()]
+ fromRate, hasFromRate := conversions[from.String()]
+
+ if hasToRate && hasFromRate {
+ return toRate / fromRate, nil
+ }
+ }
+
+ return 0, ConversionNotFoundError{FromCur: from.String(), ToCur: to.String()}
+}
+
// GetRate returns the conversion rate between two currencies or:
// - An error if one of the currency strings is not well-formed
// - An error if any of the currency strings is not a recognized currency code.
@@ -46,7 +62,9 @@ func (r *Rates) GetRate(from, to string) (float64, error) {
// In case we have an entry TO -> FROM
return 1 / conversion, nil
}
- return 0, ConversionNotFoundError{FromCur: fromUnit.String(), ToCur: toUnit.String()}
+
+ // Try to find currency rates via intermediate currency
+ return FindIntermediateConversionRate(r, fromUnit, toUnit)
}
return 0, errors.New("rates are nil")
}
diff --git a/currency/rates_test.go b/currency/rates_test.go
index 6fb444f32c4..555d299d212 100644
--- a/currency/rates_test.go
+++ b/currency/rates_test.go
@@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/prebid/prebid-server/v3/util/jsonutil"
+ "golang.org/x/text/currency"
)
func TestUnMarshallRates(t *testing.T) {
@@ -186,6 +187,82 @@ func TestGetRate_ReverseConversion(t *testing.T) {
}
}
+func TestGetRate_FindIntermediateConversionRate(t *testing.T) {
+ rates := NewRates(map[string]map[string]float64{
+ "USD": {
+ "SEK": 10.23842,
+ "NOK": 10.47089,
+ },
+ "EUR": {
+ "THB": 35.23842,
+ "ZAR": 18.47089,
+ },
+ })
+
+ testCases := []struct {
+ description string
+ from string
+ to string
+ expectedRate float64
+ hasError bool
+ }{
+ {
+ description: "in_same_intermediate_USD_currency",
+ from: "NOK",
+ to: "SEK",
+ expectedRate: 0.9777984488424574,
+ },
+ {
+ description: "in_same_intermediate_USD_currency_inverse",
+ from: "SEK",
+ to: "NOK",
+ expectedRate: 1 / 0.9777984488424574,
+ },
+ {
+ description: "in_same_intermediate_EUR_currency",
+ from: "THB",
+ to: "ZAR",
+ expectedRate: 0.5241690745498806,
+ },
+ {
+ description: "in_same_intermediate_EUR_currency_inverse",
+ from: "ZAR",
+ to: "THB",
+ expectedRate: 1 / 0.5241690745498806,
+ },
+ {
+ description: "in_different_intermediate_currencies",
+ from: "NOK",
+ to: "ZAR",
+ expectedRate: 0,
+ hasError: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.description, func(t *testing.T) {
+ fromUnit, err := currency.ParseISO(tc.from)
+ if err != nil {
+ t.Errorf("Expected no error, but got: %v", err)
+ }
+ toUnit, err := currency.ParseISO(tc.to)
+ if err != nil {
+ t.Errorf("Expected no error, but got: %v", err)
+ }
+
+ rate, err := FindIntermediateConversionRate(rates, fromUnit, toUnit)
+
+ if tc.hasError {
+ assert.NotNil(t, err)
+ assert.Equal(t, float64(0), rate)
+ } else {
+ assert.Nil(t, err)
+ assert.Equal(t, tc.expectedRate, rate)
+ }
+ })
+ }
+}
+
func TestGetRate_EmptyRates(t *testing.T) {
// Setup:
From da46ed2f31fdb34c9e88b3c5128cd0908fe489c9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 20 Mar 2025 15:20:08 -0400
Subject: [PATCH 15/40] Bump golang.org/x/net from 0.33.0 to 0.36.0 (#4259)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Scott Kay
---
go.mod | 10 +++++-----
go.sum | 16 ++++++++--------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/go.mod b/go.mod
index 37c169a2c2e..e04389784fe 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/prebid/prebid-server/v3
-go 1.23
+go 1.23.0
retract v3.0.0 // Forgot to update major version in import path and module name
@@ -40,8 +40,8 @@ require (
github.com/vrischmann/go-metrics-influxdb v0.1.1
github.com/xeipuuv/gojsonschema v1.2.0
github.com/yudai/gojsondiff v1.0.0
- golang.org/x/net v0.33.0
- golang.org/x/text v0.21.0
+ golang.org/x/net v0.36.0
+ golang.org/x/text v0.22.0
google.golang.org/grpc v1.56.3
gopkg.in/evanphx/json-patch.v5 v5.9.0
gopkg.in/yaml.v3 v3.0.1
@@ -78,8 +78,8 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/yudai/pp v2.0.1+incompatible // indirect
- golang.org/x/crypto v0.31.0 // indirect
- golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/crypto v0.35.0 // indirect
+ golang.org/x/sys v0.30.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
diff --git a/go.sum b/go.sum
index f3541a92f08..1c03a4d375b 100644
--- a/go.sum
+++ b/go.sum
@@ -546,8 +546,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
-golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
+golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -632,8 +632,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
-golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
+golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
+golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -744,8 +744,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
-golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -758,8 +758,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
From 8499a08d181ec777401b1b150e89462192d7d3e3 Mon Sep 17 00:00:00 2001
From: Pubmatic-Supriya-Patil
<131644110+Pubmatic-Supriya-Patil@users.noreply.github.com>
Date: Mon, 24 Mar 2025 19:29:23 +0530
Subject: [PATCH 16/40] Remove invalid user EIDs and UIDs from bid request
(#3891)
---
endpoints/openrtb2/auction.go | 59 ++-
endpoints/openrtb2/auction_test.go | 379 ++++++++++++++++++
.../invalid-whole/user-eids-uids-missing.json | 47 ---
.../user-eids-empty-uids-removed.json | 101 +++++
.../user-eids-source-empty.json | 11 +-
.../user-eids-uids-empty.json} | 12 +-
.../valid-whole/user-eids-uids-missing.json | 65 +++
errortypes/code.go | 2 +
8 files changed, 612 insertions(+), 64 deletions(-)
delete mode 100644 endpoints/openrtb2/sample-requests/invalid-whole/user-eids-uids-missing.json
create mode 100644 endpoints/openrtb2/sample-requests/valid-whole/user-eids-empty-uids-removed.json
rename endpoints/openrtb2/sample-requests/{invalid-whole => valid-whole}/user-eids-source-empty.json (76%)
rename endpoints/openrtb2/sample-requests/{invalid-whole/user-eids-uids-id-empty.json => valid-whole/user-eids-uids-empty.json} (77%)
create mode 100644 endpoints/openrtb2/sample-requests/valid-whole/user-eids-uids-missing.json
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 0a1aa450cfe..84835f0bf12 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -1277,23 +1277,64 @@ func (deps *endpointDeps) validateUser(req *openrtb_ext.RequestWrapper, aliases
}
// Check Universal User ID
- for eidIndex, eid := range req.User.EIDs {
+ if len(req.User.EIDs) > 0 {
+
+ validEids, eidErrors := validateEIDs(req.User.EIDs)
+
+ if len(eidErrors) > 0 {
+ errL = append(errL, eidErrors...)
+ }
+ req.User.EIDs = validEids
+ }
+
+ return errL
+}
+
+func validateEIDs(eids []openrtb2.EID) ([]openrtb2.EID, []error) {
+ var errorsList []error
+ validEIDs := make([]openrtb2.EID, 0, len(eids))
+
+ for eidIndex, eid := range eids {
if eid.Source == "" {
- return append(errL, fmt.Errorf("request.user.eids[%d] missing required field: \"source\"", eidIndex))
+ errorsList = append(errorsList, &errortypes.Warning{
+ Message: fmt.Sprintf("request.user.eids[%d] removed due to missing source", eidIndex),
+ WarningCode: errortypes.InvalidUserEIDsWarningCode,
+ })
+ continue
}
+ validUIDs, uidErrors := validateUIDs(eid.UIDs, eidIndex)
+ errorsList = append(errorsList, uidErrors...)
- if len(eid.UIDs) == 0 {
- return append(errL, fmt.Errorf("request.user.eids[%d].uids must contain at least one element or be undefined", eidIndex))
+ if len(validUIDs) > 0 {
+ eid.UIDs = validUIDs
+ validEIDs = append(validEIDs, eid)
+ } else {
+ errorsList = append(errorsList, &errortypes.Warning{
+ Message: fmt.Sprintf("request.user.eids[%d] (source: %s) removed due to empty uids", eidIndex, eid.Source),
+ WarningCode: errortypes.InvalidUserEIDsWarningCode,
+ })
}
+ }
- for uidIndex, uid := range eid.UIDs {
- if uid.ID == "" {
- return append(errL, fmt.Errorf("request.user.eids[%d].uids[%d] missing required field: \"id\"", eidIndex, uidIndex))
- }
+ return validEIDs, errorsList
+}
+
+func validateUIDs(uids []openrtb2.UID, eidIndex int) ([]openrtb2.UID, []error) {
+ var validUIDs []openrtb2.UID
+ var uidErrors []error
+
+ for uidIndex, uid := range uids {
+ if uid.ID != "" {
+ validUIDs = append(validUIDs, uid)
+ } else {
+ uidErrors = append(uidErrors, &errortypes.Warning{
+ Message: fmt.Sprintf("request.user.eids[%d].uids[%d] removed due to empty ids", eidIndex, uidIndex),
+ WarningCode: errortypes.InvalidUserUIDsWarningCode,
+ })
}
}
- return errL
+ return validUIDs, uidErrors
}
func validateRegs(req *openrtb_ext.RequestWrapper, gpp gpplib.GppContainer) []error {
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index dfc4f441cfe..c4de9a33e07 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -21,6 +21,7 @@ import (
"github.com/buger/jsonparser"
jsoniter "github.com/json-iterator/go"
"github.com/julienschmidt/httprouter"
+ gpplib "github.com/prebid/go-gpp"
"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v3/analytics"
analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build"
@@ -5998,3 +5999,381 @@ func sortUserData(user *openrtb2.User) {
}
}
}
+func TestValidateEIDs(t *testing.T) {
+ testCases := []struct {
+ name string
+ input []openrtb2.EID
+ expected []openrtb2.EID
+ numErrors int
+ expectedErrorMessages []string
+ }{
+ {
+ name: "one-eid-one-uid-valid",
+ input: []openrtb2.EID{
+ {Source: "src1", UIDs: []openrtb2.UID{{ID: "id1"}}},
+ },
+ expected: []openrtb2.EID{
+ {Source: "src1", UIDs: []openrtb2.UID{{ID: "id1"}}},
+ },
+ numErrors: 0,
+ expectedErrorMessages: nil,
+ },
+ {
+ name: "one-eid-one-uid-empty",
+ input: []openrtb2.EID{
+ {Source: "src2", UIDs: []openrtb2.UID{{ID: ""}}},
+ },
+ expected: []openrtb2.EID{},
+ numErrors: 2,
+ expectedErrorMessages: []string{
+ "request.user.eids[0].uids[0] removed due to empty ids",
+ "request.user.eids[0] (source: src2) removed due to empty uids",
+ },
+ },
+ {
+ name: "many-mixed",
+ input: []openrtb2.EID{
+ {Source: "src3", UIDs: []openrtb2.UID{{ID: "ID1"}, {ID: "ID2"}}},
+ {Source: "src4", UIDs: []openrtb2.UID{{ID: ""}, {ID: "ID1"}}},
+ {Source: "src5", UIDs: []openrtb2.UID{{ID: ""}, {ID: ""}}},
+ },
+ expected: []openrtb2.EID{
+ {Source: "src3", UIDs: []openrtb2.UID{{ID: "ID1"}, {ID: "ID2"}}},
+ {Source: "src4", UIDs: []openrtb2.UID{{ID: "ID1"}}},
+ },
+ numErrors: 4,
+ expectedErrorMessages: []string{
+ "request.user.eids[1].uids[0] removed due to empty ids",
+ "request.user.eids[2].uids[0] removed due to empty ids",
+ "request.user.eids[2].uids[1] removed due to empty ids",
+ "request.user.eids[2] (source: src5) removed due to empty uids",
+ },
+ },
+ {
+ name: "one-eid-many-uid-empty",
+ input: []openrtb2.EID{
+ {Source: "src6", UIDs: []openrtb2.UID{{ID: ""}, {ID: ""}}},
+ },
+ expected: []openrtb2.EID{},
+ numErrors: 3,
+ expectedErrorMessages: []string{
+ "request.user.eids[0].uids[0] removed due to empty ids",
+ "request.user.eids[0].uids[1] removed due to empty ids",
+ "request.user.eids[0] (source: src6) removed due to empty uids",
+ },
+ },
+ {
+ name: "eid_nil",
+ input: nil,
+ expected: nil,
+ numErrors: 0,
+ expectedErrorMessages: nil,
+ },
+ {
+ name: "eid_uid_nil",
+ input: []openrtb2.EID{
+ {Source: "src7", UIDs: nil},
+ },
+ expected: []openrtb2.EID{},
+ numErrors: 1,
+ expectedErrorMessages: []string{
+ "request.user.eids[0] (source: src7) removed due to empty uids",
+ },
+ },
+ {
+ name: "source_missing",
+ input: []openrtb2.EID{
+ {UIDs: []openrtb2.UID{{ID: "id1"}}},
+ },
+ expected: []openrtb2.EID{},
+ numErrors: 1,
+ expectedErrorMessages: []string{
+ "request.user.eids[0] removed due to missing source",
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ validEIDs, errorsList := validateEIDs(tc.input)
+
+ assert.ElementsMatch(t, tc.expected, validEIDs)
+ assert.Equal(t, tc.numErrors, len(errorsList))
+
+ // Assert error messages
+ assert.Equal(t, len(tc.expectedErrorMessages), len(errorsList))
+ for _, err := range errorsList {
+ assert.Contains(t, tc.expectedErrorMessages, err.Error())
+ }
+
+ })
+ }
+}
+
+func TestValidateUIDs(t *testing.T) {
+ testCases := []struct {
+ name string
+ input []openrtb2.UID
+ expectedValidUIDs []openrtb2.UID
+ expectedErrors []error
+ }{
+ {
+ name: "many-uid-valid",
+ input: []openrtb2.UID{
+ {ID: "id1"},
+ {ID: "id2"},
+ },
+ expectedValidUIDs: []openrtb2.UID{
+ {ID: "id1"},
+ {ID: "id2"},
+ },
+ expectedErrors: nil,
+ },
+ {
+ name: "many-uid-empty",
+ input: []openrtb2.UID{
+ {ID: ""},
+ {ID: ""},
+ },
+ expectedValidUIDs: nil,
+ expectedErrors: []error{
+ &errortypes.Warning{
+ Message: "request.user.eids[0].uids[0] removed due to empty ids",
+ WarningCode: errortypes.InvalidUserUIDsWarningCode,
+ },
+ &errortypes.Warning{
+ Message: "request.user.eids[0].uids[1] removed due to empty ids",
+ WarningCode: errortypes.InvalidUserUIDsWarningCode,
+ },
+ },
+ },
+ {
+ name: "many-mixed",
+ input: []openrtb2.UID{
+ {ID: "id1"},
+ {ID: ""},
+ {ID: "id2"},
+ {ID: ""},
+ },
+ expectedValidUIDs: []openrtb2.UID{
+ {ID: "id1"},
+ {ID: "id2"},
+ },
+ expectedErrors: []error{
+ &errortypes.Warning{
+ Message: "request.user.eids[0].uids[1] removed due to empty ids",
+ WarningCode: errortypes.InvalidUserUIDsWarningCode,
+ },
+ &errortypes.Warning{
+ Message: "request.user.eids[0].uids[3] removed due to empty ids",
+ WarningCode: errortypes.InvalidUserUIDsWarningCode,
+ },
+ },
+ },
+ {
+ name: "empty-uid",
+ input: []openrtb2.UID{},
+ expectedValidUIDs: nil,
+ expectedErrors: nil,
+ },
+ {
+ name: "nil-uid",
+ input: nil,
+ expectedValidUIDs: nil,
+ expectedErrors: nil,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ validUIDs, errorsList := validateUIDs(tc.input, 0)
+
+ assert.ElementsMatch(t, tc.expectedValidUIDs, validUIDs)
+ assert.ElementsMatch(t, tc.expectedErrors, errorsList)
+ })
+ }
+}
+func TestValidateUser(t *testing.T) {
+
+ testCases := []struct {
+ name string
+ req *openrtb_ext.RequestWrapper
+ expectedErr []error
+ expectedEids []openrtb2.EID
+ }{
+ {
+ name: "Valid_user_with_Geo_accuracy",
+ req: &openrtb_ext.RequestWrapper{
+ BidRequest: &openrtb2.BidRequest{
+ User: &openrtb2.User{
+ Geo: &openrtb2.Geo{
+ Accuracy: 10,
+ },
+ },
+ },
+ },
+ expectedErr: nil,
+ },
+ {
+ name: "Invalid_user_with_negative_Geo_accuracy",
+ req: &openrtb_ext.RequestWrapper{
+ BidRequest: &openrtb2.BidRequest{
+ User: &openrtb2.User{
+ Geo: &openrtb2.Geo{
+ Accuracy: -10,
+ },
+ },
+ },
+ },
+ expectedErr: []error{errors.New("request.user.geo.accuracy must be a positive number")},
+ },
+ {
+ name: "Invalid_user.ext.prebid_with_empty_buyeruids",
+ req: &openrtb_ext.RequestWrapper{
+ BidRequest: &openrtb2.BidRequest{
+ User: &openrtb2.User{
+ Ext: json.RawMessage(`{"prebid": {"buyeruids": {}}}`),
+ },
+ },
+ },
+ expectedErr: []error{errors.New(`request.user.ext.prebid requires a "buyeruids" property with at least one ID defined. If none exist, then request.user.ext.prebid should not be defined.`)},
+ },
+ {
+ name: "Invalid_user.eids_with_empty_id",
+ req: &openrtb_ext.RequestWrapper{
+ BidRequest: &openrtb2.BidRequest{
+ User: &openrtb2.User{
+ EIDs: []openrtb2.EID{
+ {
+ Source: "source",
+ UIDs: []openrtb2.UID{
+ {ID: ""},
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedErr: []error{&errortypes.Warning{
+ Message: "request.user.eids[0].uids[0] removed due to empty ids",
+ WarningCode: errortypes.InvalidUserUIDsWarningCode,
+ }, &errortypes.Warning{
+ Message: "request.user.eids[0] (source: source) removed due to empty uids",
+ WarningCode: errortypes.InvalidUserEIDsWarningCode,
+ }},
+ expectedEids: nil,
+ },
+ {
+ name: "Valid_user.eids_with_UID1_id",
+ req: &openrtb_ext.RequestWrapper{
+ BidRequest: &openrtb2.BidRequest{
+ User: &openrtb2.User{
+ EIDs: []openrtb2.EID{
+ {
+ Source: "source",
+ UIDs: []openrtb2.UID{
+ {ID: "UID1"},
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedErr: nil,
+ expectedEids: []openrtb2.EID{
+ {
+ Source: "source",
+ UIDs: []openrtb2.UID{
+ {ID: "UID1"},
+ },
+ },
+ },
+ },
+ {
+ name: "user.eids_with_empty_UIDs",
+ req: &openrtb_ext.RequestWrapper{
+ BidRequest: &openrtb2.BidRequest{
+ User: &openrtb2.User{
+ EIDs: []openrtb2.EID{
+ {
+ Source: "source",
+ UIDs: []openrtb2.UID{
+ {},
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedErr: []error{
+ &errortypes.Warning{
+ Message: "request.user.eids[0].uids[0] removed due to empty ids",
+ WarningCode: errortypes.InvalidUserUIDsWarningCode,
+ },
+ &errortypes.Warning{
+ Message: "request.user.eids[0] (source: source) removed due to empty uids",
+ WarningCode: errortypes.InvalidUserEIDsWarningCode,
+ },
+ },
+ expectedEids: nil,
+ },
+ {
+ name: "user.eids_with_empty_UIDs",
+ req: &openrtb_ext.RequestWrapper{
+ BidRequest: &openrtb2.BidRequest{
+ User: &openrtb2.User{
+ EIDs: []openrtb2.EID{
+ {
+ Source: "source",
+ UIDs: []openrtb2.UID{},
+ },
+ },
+ },
+ },
+ },
+ expectedErr: []error{
+ &errortypes.Warning{
+ Message: "request.user.eids[0] (source: source) removed due to empty uids",
+ WarningCode: errortypes.InvalidUserEIDsWarningCode,
+ },
+ },
+ expectedEids: nil,
+ },
+ {
+ name: "user.eids_with_No_UIDs",
+ req: &openrtb_ext.RequestWrapper{
+ BidRequest: &openrtb2.BidRequest{
+ User: &openrtb2.User{
+ EIDs: []openrtb2.EID{
+ {
+ Source: "source",
+ },
+ },
+ },
+ },
+ },
+ expectedErr: []error{
+ &errortypes.Warning{
+ Message: "request.user.eids[0] (source: source) removed due to empty uids",
+ WarningCode: errortypes.InvalidUserEIDsWarningCode,
+ },
+ },
+ expectedEids: nil,
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ deps := &endpointDeps{
+ bidderMap: map[string]openrtb_ext.BidderName{
+ "appnexus": "appnexus",
+ },
+ }
+ errs := deps.validateUser(test.req, nil, gpplib.GppContainer{})
+ assert.Equal(t, test.expectedErr, errs)
+ if test.req.User != nil {
+ assert.ElementsMatch(t, test.expectedEids, test.req.User.EIDs)
+ }
+ })
+ }
+}
diff --git a/endpoints/openrtb2/sample-requests/invalid-whole/user-eids-uids-missing.json b/endpoints/openrtb2/sample-requests/invalid-whole/user-eids-uids-missing.json
deleted file mode 100644
index 3e55c33b849..00000000000
--- a/endpoints/openrtb2/sample-requests/invalid-whole/user-eids-uids-missing.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "description": "Bid request with user.eids array element array element that does not contain uids",
- "mockBidRequest": {
- "id": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5",
- "site": {
- "page": "prebid.org",
- "publisher": {
- "id": "a3de7af2-a86a-4043-a77b-c7e86744155e"
- }
- },
- "source": {
- "tid": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5"
- },
- "tmax": 1000,
- "imp": [{
- "id": "/19968336/header-bid-tag-0",
- "ext": {
- "appnexus": {
- "placementId": 12883451
- }
- },
- "banner": {
- "format": [{
- "w": 300,
- "h": 250
- },
- {
- "w": 300,
- "h": 300
- }
- ]
- }
- }],
- "regs": {
- "ext": {
- "gdpr": 1
- }
- },
- "user": {
- "eids": [{
- "source": "source1"
- }]
- }
- },
- "expectedReturnCode": 400,
- "expectedErrorMessage": "Invalid request: request.user.eids[0].uids must contain at least one element or be undefined\n"
-}
\ No newline at end of file
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/user-eids-empty-uids-removed.json b/endpoints/openrtb2/sample-requests/valid-whole/user-eids-empty-uids-removed.json
new file mode 100644
index 00000000000..9a4e1373d1f
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/valid-whole/user-eids-empty-uids-removed.json
@@ -0,0 +1,101 @@
+{
+ "description": "Bid request where a request.user.eids.uids are removed when uid is empty, ensuring no bids are returned.",
+ "mockBidRequest": {
+ "id": "anyRequestID",
+ "site": {
+ "page": "prebid.org",
+ "publisher": {
+ "id": "anyPublisher"
+ }
+ },
+ "imp": [
+ {
+ "id": "anyImpID",
+ "ext": {
+ "appnexus": {
+ "placementId": 42
+ }
+ },
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 300
+ }
+ ]
+ }
+ }
+ ],
+ "tmax": 1000,
+ "user": {
+ "eids": [
+ {
+ "source": "source-1",
+ "uids": [
+ {
+ "id": ""
+ },
+ {
+ "id": "id-a"
+ }
+ ]
+ },
+ {
+ "source": "source-2",
+ "uids": [
+ {
+ "id": "id-b"
+ }
+ ]
+ },
+ {
+ "source": "source-3",
+ "uids": [
+ {
+ "id": ""
+ },
+ {
+ "id": ""
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "expectedReturnCode": 200,
+ "expectedBidResponse": {
+ "id": "anyRequestID",
+ "cur": "USD",
+ "seatbid": [],
+ "ext": {
+ "warnings": {
+ "general": [
+ {
+ "code": 10013,
+ "message": "debug turned off for account"
+ },
+ {
+ "code": 10013,
+ "message": "request.user.eids[0].uids[0] removed due to empty ids"
+ },
+ {
+ "code": 10013,
+ "message": "request.user.eids[2].uids[0] removed due to empty ids"
+ },
+ {
+ "code": 10013,
+ "message": "request.user.eids[2].uids[1] removed due to empty ids"
+ },
+ {
+ "code": 10013,
+ "message": "request.user.eids[2] (source: source-3) removed due to empty uids"
+ }
+ ]
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/endpoints/openrtb2/sample-requests/invalid-whole/user-eids-source-empty.json b/endpoints/openrtb2/sample-requests/valid-whole/user-eids-source-empty.json
similarity index 76%
rename from endpoints/openrtb2/sample-requests/invalid-whole/user-eids-source-empty.json
rename to endpoints/openrtb2/sample-requests/valid-whole/user-eids-source-empty.json
index 902a2d9c1b6..fc770b5d9ae 100644
--- a/endpoints/openrtb2/sample-requests/invalid-whole/user-eids-source-empty.json
+++ b/endpoints/openrtb2/sample-requests/valid-whole/user-eids-source-empty.json
@@ -36,6 +36,13 @@
}]
}
},
- "expectedReturnCode": 400,
- "expectedErrorMessage": "Invalid request: request.user.eids[0] missing required field: \"source\"\n"
+ "expectedReturnCode": 200,
+ "expectedBidResponse": {
+ "ext": {
+ "warnings": {
+ "source": "prebid-server",
+ "message": "request.user.eids[0] missing required field: source"
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/endpoints/openrtb2/sample-requests/invalid-whole/user-eids-uids-id-empty.json b/endpoints/openrtb2/sample-requests/valid-whole/user-eids-uids-empty.json
similarity index 77%
rename from endpoints/openrtb2/sample-requests/invalid-whole/user-eids-uids-id-empty.json
rename to endpoints/openrtb2/sample-requests/valid-whole/user-eids-uids-empty.json
index c8eb07aa335..64d55492d9d 100644
--- a/endpoints/openrtb2/sample-requests/invalid-whole/user-eids-uids-id-empty.json
+++ b/endpoints/openrtb2/sample-requests/valid-whole/user-eids-uids-empty.json
@@ -29,12 +29,12 @@
}],
"tmax": 1000,
"user": {
- "eids": [{
+ "eids": [{
"source": "source1",
- "uids": [{}]
- }]
- }
+ "uids": []
+ }]
+}
},
- "expectedReturnCode": 400,
- "expectedErrorMessage": "Invalid request: request.user.eids[0].uids[0] missing required field: \"id\"\n"
+ "expectedReturnCode": 200,
+ "expectedErrorMessage": "request.user.eids[0] (source: source1) removed due to empty uids"
}
\ No newline at end of file
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/user-eids-uids-missing.json b/endpoints/openrtb2/sample-requests/valid-whole/user-eids-uids-missing.json
new file mode 100644
index 00000000000..e33a8495a2a
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/valid-whole/user-eids-uids-missing.json
@@ -0,0 +1,65 @@
+{
+ "description": "Bid request with user.eids array element array element that does not contain uids",
+ "mockBidRequest": {
+ "id": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5",
+ "site": {
+ "page": "prebid.org",
+ "publisher": {
+ "id": "a3de7af2-a86a-4043-a77b-c7e86744155e"
+ }
+ },
+ "source": {
+ "tid": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5"
+ },
+ "tmax": 1000,
+ "imp": [
+ {
+ "id": "/19968336/header-bid-tag-0",
+ "ext": {
+ "appnexus": {
+ "placementId": 12883451
+ }
+ },
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 300
+ }
+ ]
+ }
+ }
+ ],
+ "regs": {
+ "ext": {
+ "gdpr": 1
+ }
+ },
+ "user": {
+ "eids": [
+ {
+ "source": "source1"
+ }
+ ]
+ }
+ },
+ "expectedReturnCode": 200,
+ "expectedBidResponse": {
+ "id": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5",
+ "cur": "USD",
+ "ext": {
+ "warnings": {
+ "general": [
+ {
+ "code": 10013,
+ "message": "request.user.eids[0] (source: source1) removed due to empty uids"
+ }
+ ]
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/errortypes/code.go b/errortypes/code.go
index 49cb6d4bcf9..0b194d0830d 100644
--- a/errortypes/code.go
+++ b/errortypes/code.go
@@ -35,6 +35,8 @@ const (
InvalidBidResponseDSAWarningCode
SecCookieDeprecationLenWarningCode
SecBrowsingTopicsWarningCode
+ InvalidUserEIDsWarningCode
+ InvalidUserUIDsWarningCode
)
// Coder provides an error or warning code with severity.
From 40d1668b6f5eeba38b2edc4e709fbb8f9a1300cc Mon Sep 17 00:00:00 2001
From: Quentin Gallard
Date: Mon, 24 Mar 2025 16:50:36 +0100
Subject: [PATCH 17/40] Smilewanted: change endpoint to HTTPS (#4269)
---
static/bidder-info/smilewanted.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/static/bidder-info/smilewanted.yaml b/static/bidder-info/smilewanted.yaml
index 44aff8a055a..e0648d417f9 100644
--- a/static/bidder-info/smilewanted.yaml
+++ b/static/bidder-info/smilewanted.yaml
@@ -1,4 +1,4 @@
-endpoint: "http://prebid-server.smilewanted.com"
+endpoint: "https://prebid-server.smilewanted.com"
maintainer:
email: "tech@smilewanted.com"
gvlVendorID: 639
@@ -14,4 +14,4 @@ capabilities:
userSync:
redirect:
url: "https://csync.smilewanted.com/getuid?source=prebid-server&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}"
- userMacro: "$UID"
\ No newline at end of file
+ userMacro: "$UID"
From 13766061a26b1652bd5c4ccfcb4f9802faa08ad7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Abdulbaki=20=C3=87am?=
<71071893+bakicam@users.noreply.github.com>
Date: Mon, 24 Mar 2025 19:30:58 +0300
Subject: [PATCH 18/40] New Adapter: Yobee - Admatic alias (#4217)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Faruk Çam
---
static/bidder-info/yobee.yaml | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 static/bidder-info/yobee.yaml
diff --git a/static/bidder-info/yobee.yaml b/static/bidder-info/yobee.yaml
new file mode 100644
index 00000000000..28ce00e79d0
--- /dev/null
+++ b/static/bidder-info/yobee.yaml
@@ -0,0 +1,3 @@
+aliasOf: "admatic"
+maintainer:
+ email: "adops@yobee.it"
\ No newline at end of file
From 3e2e74a24ff6536f895b3f64ce0ed93bb192aa0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gabriela=20Mi=C4=99dlar?=
<155444733+gmiedlar-ox@users.noreply.github.com>
Date: Mon, 24 Mar 2025 17:42:21 +0100
Subject: [PATCH 19/40] OpenX: Determine bid type from bid.mtype (#4241)
---
adapters/openx/openx.go | 15 +-
.../openx/openxtest/exemplary/fledge.json | 6 +-
.../openxtest/exemplary/simple-banner.json | 6 +-
.../openxtest/exemplary/simple-native.json | 8 +-
.../openxtest/exemplary/simple-video.json | 6 +-
.../openxtest/exemplary/video-rewarded.json | 6 +-
.../openxtest/supplemental/missing-mtype.json | 312 ++++++++++++++++++
.../openxtest/supplemental/multi-imp.json | 54 +--
8 files changed, 382 insertions(+), 31 deletions(-)
create mode 100644 adapters/openx/openxtest/supplemental/missing-mtype.json
diff --git a/adapters/openx/openx.go b/adapters/openx/openx.go
index 11b5268b9bf..f10985f3085 100644
--- a/adapters/openx/openx.go
+++ b/adapters/openx/openx.go
@@ -236,7 +236,7 @@ func (a *OpenxAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRe
for i := range sb.Bid {
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: &sb.Bid[i],
- BidType: getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp),
+ BidType: getBidType(sb.Bid[i].MType, sb.Bid[i].ImpID, internalRequest.Imp),
BidVideo: getBidVideo(&sb.Bid[i]),
})
}
@@ -255,6 +255,19 @@ func getBidVideo(bid *openrtb2.Bid) *openrtb_ext.ExtBidPrebidVideo {
}
}
+func getBidType(mtype openrtb2.MarkupType, impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
+ switch mtype {
+ case openrtb2.MarkupBanner:
+ return openrtb_ext.BidTypeBanner
+ case openrtb2.MarkupVideo:
+ return openrtb_ext.BidTypeVideo
+ case openrtb2.MarkupNative:
+ return openrtb_ext.BidTypeNative
+ default:
+ return getMediaTypeForImp(impId, imps)
+ }
+}
+
// getMediaTypeForImp figures out which media type this bid is for.
//
// OpenX doesn't support multi-type impressions.
diff --git a/adapters/openx/openxtest/exemplary/fledge.json b/adapters/openx/openxtest/exemplary/fledge.json
index 256408eb850..dc559d3a0be 100644
--- a/adapters/openx/openxtest/exemplary/fledge.json
+++ b/adapters/openx/openxtest/exemplary/fledge.json
@@ -57,7 +57,8 @@
"adm": "some-test-ad",
"crid": "crid_10",
"h": 90,
- "w": 728
+ "w": 728,
+ "mtype": 1
}]
}
],
@@ -91,7 +92,8 @@
"adm": "some-test-ad",
"crid": "crid_10",
"w": 728,
- "h": 90
+ "h": 90,
+ "mtype": 1
},
"type": "banner"
}
diff --git a/adapters/openx/openxtest/exemplary/simple-banner.json b/adapters/openx/openxtest/exemplary/simple-banner.json
index aa9f9476dcf..59d540ebc4a 100644
--- a/adapters/openx/openxtest/exemplary/simple-banner.json
+++ b/adapters/openx/openxtest/exemplary/simple-banner.json
@@ -53,7 +53,8 @@
"adm": "{\"ver\": \"1.2\", \"assets\": [{\"id\": 1, \"required\": 1,\"title\": {\"text\": \"OpenX (Title)\"}}], \"link\": {\"url\": \"https://www.openx.com/\"}, \"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"http://example.com/impression\"}]}",
"crid": "crid_10",
"h": 90,
- "w": 728
+ "w": 728,
+ "mtype": 1
}]
}
],
@@ -75,7 +76,8 @@
"adm": "{\"ver\": \"1.2\", \"assets\": [{\"id\": 1, \"required\": 1,\"title\": {\"text\": \"OpenX (Title)\"}}], \"link\": {\"url\": \"https://www.openx.com/\"}, \"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"http://example.com/impression\"}]}",
"crid": "crid_10",
"w": 728,
- "h": 90
+ "h": 90,
+ "mtype": 1
},
"type": "banner"
}
diff --git a/adapters/openx/openxtest/exemplary/simple-native.json b/adapters/openx/openxtest/exemplary/simple-native.json
index e9975b0b182..a7add01ba11 100644
--- a/adapters/openx/openxtest/exemplary/simple-native.json
+++ b/adapters/openx/openxtest/exemplary/simple-native.json
@@ -56,7 +56,8 @@
"adm": "{\"ver\": \"1.2\", \"assets\": [{\"id\": 1, \"required\": 1,\"title\": {\"text\": \"OpenX (Title)\"}}], \"link\": {\"url\": \"https://www.openx.com/\"}, \"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"http://example.com/impression\"}]}",
"crid": "crid_10",
"w": 300,
- "h": 200
+ "h": 200,
+ "mtype": 4
}]
}
]
@@ -77,11 +78,12 @@
"adm": "{\"ver\": \"1.2\", \"assets\": [{\"id\": 1, \"required\": 1,\"title\": {\"text\": \"OpenX (Title)\"}}], \"link\": {\"url\": \"https://www.openx.com/\"}, \"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"http://example.com/impression\"}]}",
"crid": "crid_10",
"w": 300,
- "h": 200
+ "h": 200,
+ "mtype": 4
},
"type": "native"
}
]
}
]
-}
\ No newline at end of file
+}
diff --git a/adapters/openx/openxtest/exemplary/simple-video.json b/adapters/openx/openxtest/exemplary/simple-video.json
index e6b67775999..19beb1ae7db 100644
--- a/adapters/openx/openxtest/exemplary/simple-video.json
+++ b/adapters/openx/openxtest/exemplary/simple-video.json
@@ -63,7 +63,8 @@
"h": 576,
"cattax": 1,
"cat": ["IAB20"],
- "dur": 30
+ "dur": 30,
+ "mtype": 2
}]
}
]
@@ -88,7 +89,8 @@
"h": 576,
"cattax": 1,
"cat": ["IAB20"],
- "dur": 30
+ "dur": 30,
+ "mtype": 2
},
"video": {
"duration": 30,
diff --git a/adapters/openx/openxtest/exemplary/video-rewarded.json b/adapters/openx/openxtest/exemplary/video-rewarded.json
index 58eadd7df9f..eb51e10debf 100644
--- a/adapters/openx/openxtest/exemplary/video-rewarded.json
+++ b/adapters/openx/openxtest/exemplary/video-rewarded.json
@@ -70,7 +70,8 @@
"adm": "some-test-ad",
"crid": "crid_10",
"w": 1024,
- "h": 576
+ "h": 576,
+ "mtype": 2
}]
}
]
@@ -92,7 +93,8 @@
"adm": "some-test-ad",
"crid": "crid_10",
"w": 1024,
- "h": 576
+ "h": 576,
+ "mtype": 2
},
"type": "video"
}
diff --git a/adapters/openx/openxtest/supplemental/missing-mtype.json b/adapters/openx/openxtest/supplemental/missing-mtype.json
new file mode 100644
index 00000000000..69fec729ef9
--- /dev/null
+++ b/adapters/openx/openxtest/supplemental/missing-mtype.json
@@ -0,0 +1,312 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "banner-imp-1",
+ "banner": {},
+ "ext": {
+ "bidder": {
+ "unit": "111",
+ "delDomain": "se-demo-d.openx.net"
+ }
+ }
+ },
+ {
+ "id": "video-imp-1",
+ "video": {"mimes": ["video/mp4"]},
+ "ext": {
+ "bidder": {
+ "unit": "333",
+ "delDomain": "se-demo-d.openx.net"
+ }
+ }
+ },
+ {
+ "id": "native-imp-1",
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}]}",
+ "ver": "1.2"
+ },
+ "ext": {
+ "bidder": {
+ "unit": "666",
+ "delDomain": "se-demo-d.openx.net"
+ }
+ }
+ },
+ {
+ "id": "banner-native-imp-1",
+ "banner": {},
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}]}",
+ "ver": "1.2"
+ },
+ "ext": {
+ "bidder": {
+ "unit": "777",
+ "delDomain": "se-demo-d.openx.net"
+ }
+ }
+ },
+ {
+ "id": "video-native-imp-1",
+ "video": {"mimes": ["video/mp4"]},
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}]}",
+ "ver": "1.2"
+ },
+ "ext": {
+ "bidder": {
+ "unit": "888",
+ "delDomain": "se-demo-d.openx.net"
+ }
+ }
+ },
+ {
+ "id": "multi-type-imp",
+ "banner": {},
+ "video": {"mimes": ["video/mp4"]},
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}]}",
+ "ver": "1.2"
+ },
+ "ext": {
+ "bidder": {
+ "unit": "555",
+ "delDomain": "se-demo-d.openx.net"
+ }
+ }
+ }
+ ]
+ },
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://rtb.openx.net/prebid",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "banner-imp-1",
+ "banner": {},
+ "tagid": "111"
+ },
+ {
+ "id": "native-imp-1",
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}]}",
+ "ver": "1.2"
+ },
+ "tagid": "666"
+ },
+ {
+ "id": "banner-native-imp-1",
+ "banner": {},
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}]}",
+ "ver": "1.2"
+ },
+ "tagid": "777"
+ },
+ {
+ "id": "multi-type-imp",
+ "banner": {},
+ "video": {"mimes": ["video/mp4"]},
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}]}",
+ "ver": "1.2"
+ },
+ "tagid": "555"
+ }
+ ],
+ "ext": {
+ "bc": "hb_pbs_1.0.0",
+ "delDomain": "se-demo-d.openx.net"
+ }
+ },
+ "impIDs":["banner-imp-1","native-imp-1","banner-native-imp-1","multi-type-imp"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "seat": "openx",
+ "bid": [
+ {
+ "id": "banner-bid-1",
+ "impid": "banner-imp-1",
+ "price": 0.1
+ },
+ {
+ "id": "native-bid-1",
+ "impid": "native-imp-1",
+ "price": 0.1
+ },
+ {
+ "id": "banner-native-bid-1",
+ "impid": "banner-native-imp-1",
+ "price": 0
+ },
+ {
+ "id": "multi-type-bid",
+ "impid": "multi-type-imp",
+ "price": 0
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "expectedRequest": {
+ "uri": "http://rtb.openx.net/prebid",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "video-imp-1",
+ "video": {"mimes": ["video/mp4"]},
+ "tagid": "333"
+ }
+ ],
+ "ext": {
+ "bc": "hb_pbs_1.0.0",
+ "delDomain": "se-demo-d.openx.net"
+ }
+ },
+ "impIDs":["video-imp-1"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "seat": "openx",
+ "bid": [
+ {
+ "id": "video-bid-1",
+ "impid": "video-imp-1",
+ "price": 0.1
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "expectedRequest": {
+ "uri": "http://rtb.openx.net/prebid",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "video-native-imp-1",
+ "video": {"mimes": ["video/mp4"]},
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1200,\"hmin\":627}}],\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}]}",
+ "ver": "1.2"
+ },
+ "tagid": "888"
+ }
+ ],
+ "ext": {
+ "bc": "hb_pbs_1.0.0",
+ "delDomain": "se-demo-d.openx.net"
+ }
+ },
+ "impIDs":["video-native-imp-1"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "seat": "openx",
+ "bid": [
+ {
+ "id": "video-native-bid-1",
+ "impid": "video-native-imp-1",
+ "price": 0.0
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ],
+
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "banner-bid-1",
+ "impid": "banner-imp-1",
+ "price": 0.1
+ },
+ "type": "banner"
+ },
+ {
+ "bid": {
+ "id": "native-bid-1",
+ "impid": "native-imp-1",
+ "price": 0.1
+ },
+ "type": "native"
+ },
+ {
+ "bid": {
+ "id": "banner-native-bid-1",
+ "impid": "banner-native-imp-1",
+ "price": 0
+ },
+ "type": "banner"
+ },
+ {
+ "bid": {
+ "id": "multi-type-bid",
+ "impid": "multi-type-imp",
+ "price": 0
+ },
+ "type": "banner"
+ }
+ ]
+ },
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "video-bid-1",
+ "impid": "video-imp-1",
+ "price": 0.1
+ },
+ "type": "video"
+ }
+ ]
+ },
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "video-native-bid-1",
+ "impid": "video-native-imp-1",
+ "price": 0.0
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/openx/openxtest/supplemental/multi-imp.json b/adapters/openx/openxtest/supplemental/multi-imp.json
index a8c9be59513..6d20a5ea89b 100644
--- a/adapters/openx/openxtest/supplemental/multi-imp.json
+++ b/adapters/openx/openxtest/supplemental/multi-imp.json
@@ -164,27 +164,32 @@
{
"id": "banner-bid-1",
"impid": "banner-imp-1",
- "price": 0.1
+ "price": 0.1,
+ "mtype": 1
},
{
"id": "native-bid-1",
"impid": "native-imp-1",
- "price": 0.1
+ "price": 0.1,
+ "mtype": 4
},
{
"id": "banner-bid-2",
"impid": "banner-imp-2",
- "price": 0.2
+ "price": 0.2,
+ "mtype": 1
},
{
"id": "banner-native-bid-1",
"impid": "banner-native-imp-1",
- "price": 0
+ "price": 0,
+ "mtype": 4
},
{
"id": "multi-type-bid",
"impid": "multi-type-imp",
- "price": 0
+ "price": 0,
+ "mtype": 2
}
]
}
@@ -222,7 +227,8 @@
{
"id": "video-bid-1",
"impid": "video-imp-1",
- "price": 0.1
+ "price": 0.1,
+ "mtype": 2
}
]
}
@@ -266,7 +272,8 @@
{
"id": "video-bid-2",
"impid": "video-imp-2",
- "price": 0.2
+ "price": 0.2,
+ "mtype": 2
}
]
}
@@ -308,7 +315,8 @@
{
"id": "video-native-bid-1",
"impid": "video-native-imp-1",
- "price": 0.0
+ "price": 0.0,
+ "mtype": 4
}
]
}
@@ -326,7 +334,8 @@
"bid": {
"id": "banner-bid-1",
"impid": "banner-imp-1",
- "price": 0.1
+ "price": 0.1,
+ "mtype": 1
},
"type": "banner"
},
@@ -334,7 +343,8 @@
"bid": {
"id": "native-bid-1",
"impid": "native-imp-1",
- "price": 0.1
+ "price": 0.1,
+ "mtype": 4
},
"type": "native"
},
@@ -342,7 +352,8 @@
"bid": {
"id": "banner-bid-2",
"impid": "banner-imp-2",
- "price": 0.2
+ "price": 0.2,
+ "mtype": 1
},
"type": "banner"
},
@@ -350,17 +361,19 @@
"bid": {
"id": "banner-native-bid-1",
"impid": "banner-native-imp-1",
- "price": 0
+ "price": 0,
+ "mtype": 4
},
- "type": "banner"
+ "type": "native"
},
{
"bid": {
"id": "multi-type-bid",
"impid": "multi-type-imp",
- "price": 0
+ "price": 0,
+ "mtype": 2
},
- "type": "banner"
+ "type": "video"
}
]
},
@@ -371,7 +384,8 @@
"bid": {
"id": "video-bid-1",
"impid": "video-imp-1",
- "price": 0.1
+ "price": 0.1,
+ "mtype": 2
},
"type": "video"
}
@@ -384,7 +398,8 @@
"bid": {
"id": "video-bid-2",
"impid": "video-imp-2",
- "price": 0.2
+ "price": 0.2,
+ "mtype": 2
},
"type": "video"
}
@@ -397,9 +412,10 @@
"bid": {
"id": "video-native-bid-1",
"impid": "video-native-imp-1",
- "price": 0.0
+ "price": 0.0,
+ "mtype": 4
},
- "type": "video"
+ "type": "native"
}
]
}
From 8b38a0c60561656da171033b54354c5269c44978 Mon Sep 17 00:00:00 2001
From: JacobKlein26 <42449375+JacobKlein26@users.noreply.github.com>
Date: Mon, 24 Mar 2025 12:50:55 -0400
Subject: [PATCH 20/40] Nextmillennium: Add gzip compression (#4261)
Co-authored-by: Yakov Klein
---
static/bidder-info/nextmillennium.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/static/bidder-info/nextmillennium.yaml b/static/bidder-info/nextmillennium.yaml
index 11182ac271c..42b3bc082e5 100644
--- a/static/bidder-info/nextmillennium.yaml
+++ b/static/bidder-info/nextmillennium.yaml
@@ -1,4 +1,5 @@
endpoint: "https://pbs.nextmillmedia.com/openrtb2/auction"
+endpointCompression: GZIP
maintainer:
email: "accountmanagers@nextmillennium.io"
gvlVendorID: 1060
From c127eff5e44703a574edd202bc8b8fd66ba692c5 Mon Sep 17 00:00:00 2001
From: Veronika Solovei
Date: Mon, 24 Mar 2025 10:07:37 -0700
Subject: [PATCH 21/40] Dockerfile vulnerabilities fixes (#4270)
---
.devcontainer/Dockerfile | 3 +++
Dockerfile | 10 +++++-----
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index d8373fd4c57..f9db48b54cf 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -16,3 +16,6 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1
+
+RUN addgroup --system --gid 2001 prebidgroup && adduser --system --uid 1001 --ingroup prebidgroup prebid
+USER prebid
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index c2e8e4d9cf8..c4d0b908cec 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,7 @@
FROM ubuntu:20.04 AS build
RUN apt-get update && \
apt-get -y upgrade && \
- apt-get install -y wget
+ apt-get install -y --no-install-recommends wget ca-certificates
WORKDIR /tmp
RUN wget https://dl.google.com/go/go1.24.0.linux-amd64.tar.gz && \
tar -xf go1.24.0.linux-amd64.tar.gz && \
@@ -14,7 +14,7 @@ ENV GOPROXY="https://proxy.golang.org"
# Installing gcc as cgo uses it to build native code of some modules
RUN apt-get update && \
- apt-get install -y git gcc && \
+ apt-get install -y --no-install-recommends git gcc build-essential && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# CGO must be enabled because some modules depend on native C code
@@ -37,10 +37,10 @@ RUN chmod -R a+r static/ stored_requests/data
# Installing libatomic1 as it is a runtime dependency for some modules
RUN apt-get update && \
- apt-get install -y ca-certificates mtr libatomic1 && \
+ apt-get install -y --no-install-recommends ca-certificates mtr libatomic1 && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
-RUN adduser prebid_user
-USER prebid_user
+RUN addgroup --system --gid 2001 prebidgroup && adduser --system --uid 1001 --ingroup prebidgroup prebid
+USER prebid
EXPOSE 8000
EXPOSE 6060
ENTRYPOINT ["/usr/local/bin/prebid-server"]
From 7cf39276b76c8270e46bc89223d8729001a34223 Mon Sep 17 00:00:00 2001
From: Brian Sardo <1168933+bsardo@users.noreply.github.com>
Date: Mon, 24 Mar 2025 16:47:35 -0400
Subject: [PATCH 22/40] Update dockerfile to use Ubuntu 22.04 as base image
(#4252)
---
Dockerfile | 4 +-
server/ssl/ssl.go | 2700 ++++++++++++++++++++++++---------------------
2 files changed, 1453 insertions(+), 1251 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index c4d0b908cec..fe7cec5e169 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:20.04 AS build
+FROM ubuntu:22.04 AS build
RUN apt-get update && \
apt-get -y upgrade && \
apt-get install -y --no-install-recommends wget ca-certificates
@@ -26,7 +26,7 @@ ARG TEST="true"
RUN if [ "$TEST" != "false" ]; then ./validate.sh ; fi
RUN go build -mod=vendor -ldflags "-X github.com/prebid/prebid-server/v3/version.Ver=`git describe --tags | sed 's/^v//'` -X github.com/prebid/prebid-server/v3/version.Rev=`git rev-parse HEAD`" .
-FROM ubuntu:20.04 AS release
+FROM ubuntu:22.04 AS release
LABEL maintainer="hans.hjort@xandr.com"
WORKDIR /usr/local/bin/
COPY --from=build /app/prebid-server .
diff --git a/server/ssl/ssl.go b/server/ssl/ssl.go
index f206fb7beed..8b00b7d191b 100644
--- a/server/ssl/ssl.go
+++ b/server/ssl/ssl.go
@@ -116,6 +116,56 @@ RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv
uu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw
+CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw
+FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S
+Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5
+MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL
+DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS
+QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH
+sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK
+Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu
+SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC
+MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy
+v+c=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV
+BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk
+YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV
+BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN
+MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF
+UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD
+VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v
+dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj
+cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q
+yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH
+2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX
+H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL
+zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR
+p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz
+W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/
+SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn
+LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3
+n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B
+u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj
+o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
+AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L
+9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej
+rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK
+pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0
+vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq
+OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ
+/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9
+2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI
++PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2
+MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo
+tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
@@ -149,31 +199,6 @@ LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
-IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
-MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
-FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
-bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
-H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
-uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
-mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
-a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
-E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
-WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
-VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
-Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
-cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
-IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
-AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
-YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
-6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
-Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
-c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
-mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
@@ -355,10 +380,55 @@ lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE
+MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w
+LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w
+CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0
+MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF
+Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI
+zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X
+tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4
+AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2
+KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD
+aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu
+CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo
+9H1/IISpQuQo
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM
+MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx
+MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00
+MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD
+QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z
+4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv
+Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ
+kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs
+GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln
+nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh
+3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD
+0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy
+geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8
+ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB
+c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI
+pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
+dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS
+4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs
+o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ
+qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw
+xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM
+rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4
+AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR
+0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY
+o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5
+dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE
+oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE
BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h
-cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy
-MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg
+cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1
+MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg
Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9
thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM
@@ -371,23 +441,69 @@ Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja
EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T
KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF
6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh
-OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD
-VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD
-VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
-cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv
-ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl
-AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF
-661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9
-am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1
-ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481
-PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS
-3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k
-SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF
-3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM
-ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g
-StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz
-Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB
-jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
+OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc
+tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd
+IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j
+b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC
+AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw
+ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m
+iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF
+Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ
+hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P
+Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE
+EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV
+1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t
+CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR
+5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw
+f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9
+ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK
+GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBU
+MQswCQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRI
+T1JJVFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAz
+MTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJF
+SUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2Jh
+bCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFmCL3Z
+xRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZ
+spDyRhySsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O5
+58dnJCNPYwpj9mZ9S1WnP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgR
+at7GGPZHOiJBhyL8xIkoVNiMpTAK+BcWyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll
+5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRjeulumijWML3mG90Vr4Tq
+nMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNnMoH1V6XK
+V0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/
+pj+bOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZO
+z2nxbkRs1CTqjSShGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXn
+jSXWgXSHRtQpdaJCbPdzied9v3pKH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+
+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMBAAGjQjBAMB0GA1UdDgQWBBTF
+7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4
+YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3Kli
+awLwQ8hOnThJdMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u
++2D2/VnGKhs/I0qUJDAnyIm860Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88
+X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuhTaRjAv04l5U/BXCga99igUOLtFkN
+SoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW4AB+dAb/OMRyHdOo
+P2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmpGQrI
++pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRz
+znfSxqxx4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9
+eVzYH6Eze9mCUAyTF6ps3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2
+YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4SSPfSKcOYKMryMguTjClPPGAyzQWWYezy
+r/6zcCwupvI=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw
+CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ
+VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy
+MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ
+TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS
+b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B
+IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+
++kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK
+sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA
+94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B
+43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
@@ -611,6 +727,50 @@ QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
NVOFBkpdn627G190
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw
+CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu
+bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ
+BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s
+eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK
++IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2
+QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4
+hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm
+ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG
+BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw
+PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy
+dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9
+MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0
+YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2
+1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT
+vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed
+aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0
+1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5
+r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5
+cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ
+wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ
+6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA
+2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH
+Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR
+eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB
+/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u
+d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr
+PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d
+8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi
+1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd
+rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di
+taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7
+lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj
+yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn
+Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy
+yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n
+wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6
+OV+KmalBWQewLK8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X
DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ
@@ -633,103 +793,55 @@ t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET
-MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb
-BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz
-MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx
-FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g
-Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2
-fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl
-LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV
-WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF
-TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb
-5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc
-CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri
-wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ
-wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG
-m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4
-F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng
-WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0
-2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF
-AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/
-0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw
-F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS
-g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj
-qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN
-h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/
-ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V
-btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj
-Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ
-8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW
-gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw
-PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz
-cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9
-MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz
-IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ
-ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR
-VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL
-kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd
-EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas
-H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0
-HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud
-DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4
-QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu
-Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/
-AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8
-yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR
-FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA
-ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB
-kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
-l7+ijrRU
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUA
-MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy
-dHBsdXMgUm9vdCBDQSBHMTAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBa
-MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy
-dHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
-ANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHNr49a
-iZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt
-6kuJPKNxQv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP
-0FG7Yn2ksYyy/yARujVjBYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f
-6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTvLRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDE
-EW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2z4QTd28n6v+WZxcIbekN
-1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc4nBvCGrc
-h2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCT
-mehd4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV
-4EJQeIQEQWGw9CEjjy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPO
-WftwenMGE9nTdDckQQoRb5fc5+R+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1Ud
-DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSowcCbkahDFXxd
-Bie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHYlwuBsTANBgkq
-hkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh
-66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7
-/SMNkPX0XtPGYX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BS
-S7CTKtQ+FjPlnsZlFT5kOwQ/2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j
-2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F6ALEUz65noe8zDUa3qHpimOHZR4R
-Kttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilXCNQ314cnrUlZp5Gr
-RHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWetUNy
-6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEV
-V/xuZDDCVRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5
-g4VCXA9DO2pJNdWY9BW/+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl
-++O/QmueD6i9a5jc2NvLi6Td11n0bt3+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4x
-CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs
-dXMgUm9vdCBDQSBHMjAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4x
-CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs
-dXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABM0PW1aC3/BFGtat
-93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uNAm8x
-Ik0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0P
-AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwj
-FNiPwyCrKGBZMB8GA1UdIwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqG
-SM49BAMDA2gAMGUCMHD+sAvZ94OX7PNVHdTcswYO/jOYnYs5kGuUIe22113WTNch
-p+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjlvPl5adytRSv3tjFzzAal
-U5ORGpOucGpnutee5WEaXw==
+MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw
+WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw
+MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x
+MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD
+VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX
+BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO
+ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M
+CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu
+I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm
+TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh
+C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf
+ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz
+IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT
+Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k
+JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5
+hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB
+GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
+1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov
+L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo
+dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr
+aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq
+hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L
+6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG
+HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6
+0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB
+lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi
+o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1
+gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v
+faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63
+Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh
+jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw
+3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw
+CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw
+JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT
+EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0
+WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT
+LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX
+BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE
+KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm
+Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8
+EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J
+UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn
+nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM
@@ -788,46 +900,127 @@ XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P
DrW5viSP
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD
-VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
-IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3
-MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz
-IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz
-MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj
-dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw
-EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp
-MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G
-CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9
-28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq
-VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q
-DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR
-5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL
-ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a
-Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl
-UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s
-+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5
-Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
-ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx
-hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV
-HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1
-+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN
-YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t
-L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy
-ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt
-IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV
-HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w
-DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW
-PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF
-5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1
-glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH
-FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2
-pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD
-xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG
-tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq
-jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De
-fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
-OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ
-d0jQ
+MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6
+MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu
+MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV
+BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw
+MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg
+U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ
+n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q
+p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq
+NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF
+8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3
+HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa
+mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi
+7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF
+ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P
+qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ
+v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6
+Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1
+vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD
+ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4
+WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo
+zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR
+5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ
+GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf
+5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq
+0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D
+P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM
+qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP
+0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf
+E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw
+TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t
+bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa
+Fw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv
+cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEw
+djAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLxeP0C
+flfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJE
+hRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq
+hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg
+2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS
+Um9poIyNStDuiw7LR47QjRE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw
+TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t
+bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa
+Fw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv
+cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIw
+djAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/MMDAL
+j2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmU
+v4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq
+hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n
+ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV
+mkzw5l4lIhVtwodZ0LKOag==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQEL
+BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi
+Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1
+NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t
+U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt
+MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45FtnYSk
+YZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslh
+suitQDy6uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0al
+DrJLpA6lfO741GIDuZNqihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3Oj
+WiE260f6GBfZumbCk6SP/F2krfxQapWsvCQz0b2If4b19bJzKo98rwjyGpg/qYFl
+P8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/cZip8UlF1y5mO6D1cv547
+KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTifBSeolz7p
+UcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/
+kQO9lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JO
+Hg9O5j9ZpSPcPYeoKFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkB
+Ea801M/XrmLTBQe0MXXgDW1XT2mH+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6U
+CBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm45P3luG0wDQYJ
+KoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6
+NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQ
+nmhUQo8mUuJM3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+
+QgvfKNmwrZggvkN80V4aCRckjXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2v
+trV0KnahP/t1MJ+UXjulYPPLXAziDslg+MkfFoom3ecnf+slpoq9uC02EJqxWE2a
+aE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/WNyVntHKLr4W96ioD
+j8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+o/E4
+Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0w
+lREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn
+YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVoc
+icCMb3SgazNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQEL
+BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi
+Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2
+NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t
+U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt
+MDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3VrCLE
+NQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0
+kyI9p+Kx7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1C
+rWDaSWqVcN3SAOLMV2MCe5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxz
+hkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2WWy09X6GDRl224yW4fKcZgBzqZUPckXk2
+LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rpM9kzXzehxfCrPfp4sOcs
+n/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIfhs1w/tku
+FT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5
+kQMreyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3
+wNemKfrb3vOTlycEVS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6v
+wQcQeKwRoi9C8DfF8rhW3Q5iLc4tVn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs
+5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7GxcJXvYXowDQYJ
+KoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB
+KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3
++VGXu6TwYofF1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbyme
+APnCKfWxkxlSaRosTKCL4BWaMS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3Nyq
+pgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xdgSGn2rtO/+YHqP65DSdsu3BaVXoT
+6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2OHG1QAk8mGEPej1WF
+sQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+NmYWvt
+PjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2d
+lklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670
+v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17O
+rg3bhzjlP1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
@@ -855,26 +1048,40 @@ l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG
-A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh
-bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE
-ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS
-b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5
-7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS
-J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y
-HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP
-t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz
-FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY
-XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
-MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw
-hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js
-MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA
-A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj
-Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx
-XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o
-omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc
-A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
-WL1WMRJOEcgh4LMRkWXbtKaIOM5V
+MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw
+CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS
+VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5
+NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG
+A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS
+zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0
+QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/
+VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g
+PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf
+Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l
+dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1
+c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO
+PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW
+wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV
+dWNbFJWcHwHP2NVypw87
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw
+CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS
+VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5
+NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG
+A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC
+/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD
+wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3
+OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g
+PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf
+Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l
+dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1
+c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO
+PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA
+y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb
+gfM0agPnIjhQW+0ZT0MW
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
@@ -927,48 +1134,6 @@ xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX
KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
-PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
-Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
-rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
-OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
-xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
-7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
-aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
-SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
-ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
-AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
-R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
-JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
-Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc
-MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj
-IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB
-IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE
-RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl
-U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290
-IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU
-ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC
-QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr
-rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S
-NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc
-QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH
-txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP
-BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
-AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp
-tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa
-IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl
-6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+
-xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
-Cm26OWMohpLzGITY+9HPBVZkVw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
@@ -1110,6 +1275,51 @@ vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
+OkuE6N36B9K
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp
+Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2
+MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
+bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG
+ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS
+7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp
+0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS
+B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49
+BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ
+LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4
+DXZDjC5Ty3zfDBeWUA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN
+MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT
+HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN
+NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs
+IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+
+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0
+2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp
+wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM
+pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD
+nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po
+sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx
+Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd
+Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX
+KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe
+XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL
+tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv
+TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw
+GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H
+PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF
+O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ
+REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik
+AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv
+/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+
+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw
+MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF
+qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK
+ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg
@@ -1142,97 +1352,6 @@ r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1
gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV
-BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC
-aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV
-BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1
-Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz
-MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+
-BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp
-em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
-ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
-MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY
-B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH
-D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF
-Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo
-q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D
-k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH
-fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut
-dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM
-ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8
-zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
-rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX
-U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6
-Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5
-XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF
-Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR
-HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY
-GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c
-77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3
-+GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK
-vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6
-FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl
-yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P
-AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD
-y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d
-NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB
-8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy
-dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1
-YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3
-dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh
-IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD
-LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG
-EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g
-KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD
-ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu
-bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg
-ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R
-85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm
-4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV
-HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd
-QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t
-lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB
-o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
-BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4
-opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo
-dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW
-ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN
-AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y
-/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k
-SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy
-Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS
-Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl
-nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1
-MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
-czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
-CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy
-MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl
-ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS
-b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB
-AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy
-euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO
-bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw
-WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d
-MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE
-1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD
-VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/
-zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB
-BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF
-BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV
-v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG
-E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
-uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW
-iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v
-GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
@@ -1328,6 +1447,42 @@ nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH
VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw
+gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL
+Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg
+MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw
+BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0
+MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1
+c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ
+bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg
+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ
+2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E
+T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j
+5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM
+C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T
+DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX
+wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A
+2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm
+nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8
+dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl
+N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj
+c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS
+5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS
+Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr
+hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/
+B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI
+AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw
+H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+
+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk
+2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol
+IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk
+5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY
+n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE
BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0
@@ -1360,161 +1515,136 @@ T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe
MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
-MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
-YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
-EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
-R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
-9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
-fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
-iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
-1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
-bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
-MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
-ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
-uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
-Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
-tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
-PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
-hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
-5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
-MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
-R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
-MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
-Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
-AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
-ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
-7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
-kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
-mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
-KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
-6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
-4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
-oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
-UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
-AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
-MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
-KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
-MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
-eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
-BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
-NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
-BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
-MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
-So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
-tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
-BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
-CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
-qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
-rD6ogRLQy7rQkgu2npaqBA+K
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
-mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
-MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
-eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ
-BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
-MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0
-BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
-LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz
-+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm
-hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn
-5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W
-JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL
-DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC
-huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
-HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB
-AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB
-zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN
-kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
-AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
-SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
-spki4cErx5z481+oghLrGREt
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
-MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
-c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
-BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
-IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
-VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
-cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
-QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
-F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
-c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
-mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
-VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
-teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
-f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
-Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
-nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
-/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
-MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
-9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
-aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
-IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
-ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
-uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
-Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
-QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
-koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
-ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
-DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
-bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
-MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
-c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
-VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
-c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
-AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
-WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
-FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
-XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
-se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
-KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
-IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
-y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
-hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
-QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
-Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
-HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
-KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
-dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
-L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
-Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
-ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
-T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
-GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
-1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
-OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
-6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
-QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
-MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
-bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
-DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
-QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
-FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
-DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
-uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
-kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
-ewv4n4Q=
+MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG
+A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw
+FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx
+MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u
+aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b
+RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z
+YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3
+QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw
+yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+
+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ
+SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH
+r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0
+4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me
+dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw
+q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2
+nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu
+H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA
+VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC
+XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd
+6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf
++I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi
+kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7
+wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB
+TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C
+MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn
+4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I
+aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy
+qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
+27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
+Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
+TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
+qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
+szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
+Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
+MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
+wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
+aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
+VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
+AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
+C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
+QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
+h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
+7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
+ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
+MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
+Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
+6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
+0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
+2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
+bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt
+nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY
+6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu
+MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k
+RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg
+f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV
++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo
+dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW
+Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa
+G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq
+gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID
+AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H
+vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8
+0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC
+B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u
+NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg
+yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev
+HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6
+xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR
+TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg
+JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV
+7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl
+6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD
+VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
+A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
+WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
+IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
+AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G
+jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2
+4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7
+VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm
+ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD
+VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
+A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
+WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
+IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
+AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi
+QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR
+HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D
+9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8
+p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD
+VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh
+bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw
+MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g
+UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT
+BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx
+uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV
+HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/
++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147
+bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk
@@ -1552,28 +1682,6 @@ DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
-A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
-Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
-MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
-A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
-v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
-eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
-tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
-C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
-zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
-mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
-V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
-bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
-3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
-J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
-291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
-ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
-AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
-TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
@@ -1595,45 +1703,80 @@ Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
WD9f
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD
-VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
-IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3
-MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
-aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx
-MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy
-cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG
-A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl
-BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI
-hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed
-KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7
-G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2
-zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4
-ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG
-HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2
-Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V
-yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e
-beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r
-6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
-wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog
-zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW
-BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr
-ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp
-ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk
-cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt
-YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC
-CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow
-KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI
-hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ
-UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz
-X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x
-fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz
-a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd
-Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd
-SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O
-AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso
-M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge
-v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
-09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
+MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg
+MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh
+bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx
+MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET
+MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI
+xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k
+ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD
+aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw
+LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw
+1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX
+k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2
+SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h
+bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n
+WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY
+rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce
+MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu
+bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
+nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt
+Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61
+55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj
+vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf
+cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz
+oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp
+nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs
+pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v
+JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R
+8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4
+5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx
+CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD
+ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw
+MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex
+HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq
+R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd
+yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ
+7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8
++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA
+MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD
+VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy
+MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt
+c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ
+OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG
+vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud
+316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo
+0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE
+y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF
+zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE
++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN
+I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs
+x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa
+ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC
+4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4
+7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg
+JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti
+2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk
+pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF
+FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt
+rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk
+ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5
+u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP
+4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6
+N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3
+vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
@@ -1683,6 +1826,54 @@ LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
4uJEvlz36hz1
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw
+CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh
+cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v
+dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG
+A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
+aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg
+Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7
+KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y
+STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD
+AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw
+SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN
+nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs
+MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
+c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg
+Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL
+MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
+YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv
+b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l
+mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE
+4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv
+a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M
+pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw
+Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b
+LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY
+AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB
+AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq
+E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr
+W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ
+CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU
+X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3
+f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja
+H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP
+JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P
+zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt
+jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0
+/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT
+BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79
+aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW
+xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU
+63ZTGI0RmLo=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN
BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl
@@ -1700,31 +1891,6 @@ lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof
TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix
-RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1
-dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p
-YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw
-NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK
-EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl
-cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
-c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz
-dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ
-fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns
-bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD
-75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP
-FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV
-HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp
-5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu
-b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA
-A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p
-6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
-TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7
-dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys
-Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI
-l7WdmplNsDz4SgCbZN2fOUvRJ9e4
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix
DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k
IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT
@@ -1760,24 +1926,69 @@ e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0
vm9qp/UsQu0yrbYhnr68
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx
-FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg
-Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG
-A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr
-b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ
-jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn
-PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh
-ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9
-nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h
-q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED
-MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC
-mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3
-7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB
-oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs
-EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO
-fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi
-AmvZWg==
+MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP
+MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
+ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa
+Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3
+YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw
+qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv
+Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6
+lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz
+Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ
+KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK
+FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj
+HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr
+y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ
+/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM
+a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6
+fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG
+SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi
+7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc
+SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza
+ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc
+XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg
+iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho
+L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF
+Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr
+kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+
+vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU
+YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL
+BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ
+SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n
+a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5
+NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT
+CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u
+Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO
+dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI
+VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV
+9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY
+2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY
+vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt
+bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb
+x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+
+l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK
+TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj
+Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e
+i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw
+DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG
+7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk
+MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr
+gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk
+GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS
+3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm
+Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+
+l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c
+JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP
+L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa
+LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG
+mpv0
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
@@ -1811,6 +2022,20 @@ mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw
+CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg
+R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00
+MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT
+ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw
+EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW
++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9
+ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI
+zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW
+tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1
+/q4AaOeMSQ+2b1tbFfLn
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK
MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu
VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw
@@ -1907,39 +2132,6 @@ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQEL
-BQAwRjELMAkGA1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNV
-BAMMFkx1eFRydXN0IEdsb2JhbCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUw
-MzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEWMBQGA1UECgwNTHV4VHJ1c3QgUy5B
-LjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCCAiIwDQYJKoZIhvcN
-AQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wmKb3F
-ibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTem
-hfY7RBi2xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1
-EMShduxq3sVs35a0VkBCwGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsn
-Xpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4
-zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkmFRseTJIpgp7VkoGSQXAZ
-96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niFwpN6cj5m
-j5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4g
-DEa/a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+
-8kPREd8vZS9kzl8UubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2j
-X5t/Lax5Gw5CMZdjpPuKadUiDTSQMC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmH
-hFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGByuB
-KwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5Lmx1eHRydXN0
-Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT
-+Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQEL
-BQADggIBAGoZFO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9
-BzZAcg4atmpZ1gDlaCDdLnINH2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTO
-jFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW7MM3LGVYvlcAGvI1+ut7MV3CwRI9
-loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIuZY+kt9J/Z93I055c
-qqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWAVWe+
-2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/
-JEAdemrRTxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKre
-zrnK+T+Tb/mjuuqlPpmt/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQf
-LSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+
-x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31IiyBMz2TWuJdGsE7RKlY6
-oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0
ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G
@@ -1964,6 +2156,87 @@ tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c
HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw
+CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD
+VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw
+MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV
+UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy
+b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR
+ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb
+hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3
+FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV
+L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB
+iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl
+MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw
+NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG
+EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N
+aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ
+Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0
+ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1
+HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm
+gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ
+jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc
+aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG
+YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6
+W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K
+UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH
++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q
+W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC
+NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC
+LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC
+gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6
+tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh
+SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2
+TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3
+pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR
+xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp
+GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9
+dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN
+AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB
+RA+GsCyRxj3qrg+E
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM
+BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG
+T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx
+CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD
+b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA
+iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH
+38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE
+HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz
+kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP
+szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq
+vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf
+nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG
+YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo
+0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a
+CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K
+AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I
+36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
+Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN
+qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj
+cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm
++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL
+hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe
+lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7
+p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8
+piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR
+LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX
+5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO
+dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul
+9XXeifdy
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG
EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3
MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl
@@ -1988,53 +2261,6 @@ uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2
XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi
-MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
-MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp
-dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV
-UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO
-ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz
-c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP
-OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl
-mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF
-BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4
-qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw
-gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu
-bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp
-dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8
-6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/
-h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH
-/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
-wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN
-pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB
-ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly
-aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
-ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w
-NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G
-A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD
-VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX
-SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR
-VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2
-w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF
-mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg
-4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9
-4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw
-DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw
-EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx
-SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2
-ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8
-vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
-hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi
-Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ
-/L7fCg0=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt
MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg
Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i
@@ -2057,116 +2283,19 @@ aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUA
-MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w
-ZW5UcnVzdCBSb290IENBIEcxMB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAw
-MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU
-T3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
-AoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7faYp6b
-wiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX
-/uMftk87ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR0
-77F9jAHiOH3BX2pfJLKOYheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGP
-uY4zbGneWK2gDqdkVBFpRGZPTBKnjix9xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLx
-p2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO9z0M+Yo0FMT7MzUj8czx
-Kselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq3ywgsNw2
-TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+W
-G+Oin6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPw
-vFEVVJSmdz7QdFG9URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYY
-EQRVzXR7z2FwefR7LFxckvzluFqrTJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAO
-BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUl0YhVyE1
-2jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/PxN3DlCPaTKbYw
-DQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E
-PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kf
-gLMtMrpkZ2CvuVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbS
-FXJfLkur1J1juONI5f6ELlgKn0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0
-V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLhX4SPgPL0DTatdrOjteFkdjpY3H1P
-XlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80nR14SohWZ25g/4/I
-i+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcmGS3t
-TAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L91
-09S5zvE/bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/Ky
-Pu1svf0OnWZzsD2097+o4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJ
-AwSQiumPv+i2tCqjI40cHLI5kqiPAlxAOXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj
-1oxx
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUA
-MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w
-ZW5UcnVzdCBSb290IENBIEcyMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAw
-MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU
-T3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
-AoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+Ntmh
-/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78e
-CbY2albz4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/6
-1UWY0jUJ9gNDlP7ZvyCVeYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fE
-FY8ElggGQgT4hNYdvJGmQr5J1WqIP7wtUdGejeBSzFfdNTVY27SPJIjki9/ca1TS
-gSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz3GIZ38i1MH/1PCZ1Eb3X
-G7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj3CzMpSZy
-YhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaH
-vGOz9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4
-t/bQWVyJ98LVtZR00dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/
-gh7PU3+06yzbXfZqfUAkBXKJOAGTy3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAO
-BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUajn6QiL3
-5okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59M4PLuG53hq8w
-DQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz
-Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0
-nXGEL8pZ0keImUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qT
-RmTFAHneIWv2V6CG1wZy7HBGS4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpT
-wm+bREx50B1ws9efAvSyB7DH5fitIw6mVskpEndI2S9G/Tvw/HRwkqWOOAgfZDC2
-t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ6e18CL13zSdkzJTa
-TkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97krgCf2
-o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU
-3jg9CcCoSmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eA
-iN1nE28daCSLT7d0geX0YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14f
-WKGVyasvc0rQLW6aWQ9VGHgtPFGml4vmu7JwqkwR3v98KzfUetF3NI/n+UL3PIEM
-S1IK
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAx
-CzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5U
-cnVzdCBSb290IENBIEczMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFow
-QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwUT3Bl
-blRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARK7liuTcpm
-3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5Bta1d
-oYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4G
-A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5
-DMlv4VBN0BBY3JWIbTAfBgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAK
-BggqhkjOPQQDAwNpADBmAjEAj6jcnboMBBf6Fek9LykBl7+BFjNAk2z8+e2AcG+q
-j9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta3U1fJAuwACEl74+nBCZx
-4nxp5V2a+EEfOzmTk51V6s2N8fvB
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
-TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
-aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
-aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz
-MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw
-IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR
-dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp
-li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D
-rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ
-WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug
-F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU
-xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC
-Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv
-dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
-ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl
-IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
-c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
-ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
-Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI
-KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T
-KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq
-y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p
-dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD
-VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL
-MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk
-fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8
-7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R
-cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y
-mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
-xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
-SnQ2+Q==
+MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw
+CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91
+bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg
+Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ
+BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu
+ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS
+b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni
+eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W
+p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T
+rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV
+57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg
+Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL
@@ -2433,6 +2562,52 @@ oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY
Ic2wBlX7Jz9TkHCpBB5XJ7k=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw
+CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT
+U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2
+MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh
+dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG
+ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm
+acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN
+SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME
+GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW
+uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp
+15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN
+b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO
+MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD
+DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX
+DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw
+b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC
+AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP
+L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY
+t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins
+S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3
+PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO
+L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3
+R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w
+dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS
++YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS
+d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG
+AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f
+gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
+BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z
+NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt
+hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM
+QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf
+R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ
+DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW
+P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy
+lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq
+bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w
+AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q
+r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji
+Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU
+98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL
BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6
ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw
@@ -2454,6 +2629,52 @@ d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg
LvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw
+CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
+ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN
+MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG
+A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT
+ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC
+WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+
+6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B
+Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa
+qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q
+4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf
+MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD
+Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw
+HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY
+MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp
+YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa
+ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz
+SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf
+iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X
+ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3
+IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS
+VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE
+SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu
++Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt
+8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L
+HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt
+zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P
+AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c
+mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ
+YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52
+gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA
+Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB
+JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX
+DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui
+TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5
+dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65
+LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp
+0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY
+QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr
MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG
A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0
@@ -2519,6 +2740,20 @@ iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT
+AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD
+VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx
+NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT
+HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5
+IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
+AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl
+dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK
+ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu
+9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O
+be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl
MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe
U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX
@@ -2540,6 +2775,38 @@ t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy
SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNV
+BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw
+JQYDVQQDEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2
+MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UEAxMeU2VjdXJpdHkg
+Q29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4r
+CmDvu20rhvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzA
+lrenfna84xtSGc4RHwsENPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MG
+TfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF7
+9+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGmnpjKIG58u4iFW/vAEGK7
+8vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtYXLVqAvO4
+g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3we
+GVPKp7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst
++3A7caoreyYn8xrC3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M
+0V9hvqG8OmpI6iZVIhZdXw3/JzOfGAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQ
+T9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0VcwCBEF/VfR2ccCAwEAAaNCMEAw
+HQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS
+YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PA
+FNr0Y/Dq9HHuTofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd
+9XbXv8S2gVj/yP9kaWJ5rW4OH3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQI
+UYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASxYfQAW0q3nHE3GYV5v4GwxxMOdnE+
+OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZXSEIx2C/pHF7uNke
+gr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml+LLf
+iAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUV
+nuiZIesnKwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD
+2NCcnWXL0CsnMQMeNuE9dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI//
+1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm6Vwdp6POXiUyK+OVrCoHzrQoeIY8Laad
+TdJ0MN1kURXbg4NR16/9M51NZg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY
MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t
dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5
@@ -2560,122 +2827,6 @@ JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
-MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
-MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
-BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
-Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
-5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
-3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
-vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
-8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
-DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
-MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
-zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
-3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
-FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
-Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
-ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO
-TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh
-dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y
-MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg
-TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS
-b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS
-M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC
-UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d
-Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p
-rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l
-pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb
-j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC
-KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS
-/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X
-cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH
-1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP
-px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
-/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7
-MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI
-eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u
-2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS
-v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC
-wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy
-CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e
-vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6
-Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa
-Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL
-eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8
-FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc
-7uzXLg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
-TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
-dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX
-DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl
-ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv
-b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291
-qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp
-uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU
-Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE
-pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp
-5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M
-UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN
-GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy
-5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv
-6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK
-eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6
-B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/
-BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov
-L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
-HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG
-SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS
-CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen
-5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897
-IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK
-gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL
-+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL
-vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm
-bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk
-N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC
-Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z
-ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
-TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
-dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX
-DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl
-ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv
-b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP
-cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW
-IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX
-xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy
-KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR
-9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az
-5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8
-6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7
-Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP
-bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt
-BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt
-XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF
-MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd
-INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD
-U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp
-LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8
-Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp
-gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh
-/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw
-0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A
-fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq
-4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR
-1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/
-QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM
-94B7IWcnMFk=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
@@ -2937,38 +3088,6 @@ aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ
YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/
-MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow
-PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp
-Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
-AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR
-IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q
-gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy
-yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts
-F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2
-jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx
-ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC
-VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK
-YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH
-EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN
-Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud
-DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE
-MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK
-UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
-TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf
-qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK
-ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE
-JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7
-hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1
-EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm
-nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX
-udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz
-ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe
-LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl
-pYYsfPQS
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw
NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv
b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD
@@ -2999,136 +3118,245 @@ HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx
SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD
-VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk
-MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
-cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y
-IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV
-BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw
-IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy
-dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig
-RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb
-3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA
-BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5
-3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou
-owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/
-wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF
-ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf
-BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/
-MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv
-civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2
-AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F
-hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50
-soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI
-WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi
-tJ/X5g==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD
-VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk
-MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
-cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y
-IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB
-pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h
-IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG
-A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU
-cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid
-RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V
-seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme
-9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV
-EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW
-hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/
-DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw
-DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD
-ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I
-/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf
-ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ
-yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts
-L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN
-zl/HHk484IkzlQsPpTLWPFp5LBk=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV
-BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw
-IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy
-dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig
-Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk
-MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg
-Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD
-VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy
-dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
-AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+
-QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq
-1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp
-2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK
-DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape
-az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF
-3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88
-oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM
-g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3
-mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh
-8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd
-BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U
-nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw
-DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX
-dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+
-MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL
-/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX
-CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa
-ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW
-2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7
-N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3
-Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB
-As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp
-5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu
-1uwJ
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF
-MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL
-ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx
-MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc
-MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+
-AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH
-iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj
-vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA
-0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB
-OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/
-BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E
-FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01
-GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW
-zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4
-1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE
-f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F
-jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN
-ZetX2fNXlrtIzYE=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UE
-BhMCVFIxDzANBgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxn
-aSDEsGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkg
-QS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1QgRWxla3Ryb25payBTZXJ0aWZpa2Eg
-SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAwODA3MDFaFw0yMzA0
-MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYD
-VQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8
-dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF
-bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApCUZ4WWe60ghUEoI5RHwWrom
-/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537jVJp45wnEFPzpALFp/kR
-Gml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1mep5Fimh3
-4khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z
-5UNP9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0
-hO8EuPbJbKoCPrZV4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QID
-AQABo0IwQDAdBgNVHQ4EFgQUVpkHHtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/
-BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ5FdnsX
-SDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPoBP5yCccLqh0l
-VX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq
-URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nf
-peYVhDfwwvJllpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CF
-Yv4HAqGEVka+lgqaE9chTLd8B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW
-+qtB4Uu2NQvAmxU=
+MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx
+CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE
+AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1
+NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ
+MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq
+AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9
+vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9
+lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD
+n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT
+7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o
+6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC
+TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6
+WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R
+DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI
+pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj
+YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy
+rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ
+8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi
+0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM
+A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS
+SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K
+TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF
+6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er
+3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt
+Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT
+VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW
+ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA
+rBPuUBQemMc=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM
+BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp
+ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe
+Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw
+IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU
+cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS
+T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK
+AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1
+nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep
+qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA
+yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs
+hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX
+zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv
+kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT
+f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA
+uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB
+o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih
+MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E
+BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4
+wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2
+XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1
+JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j
+ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV
+VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx
+xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on
+AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d
+7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj
+gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV
++Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo
+FGWsJwt0ivKH
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw
+WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs
+IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y
+MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD
+VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz
+dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx
+s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw
+LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij
+YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD
+pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE
+AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR
+UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj
+/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw
+CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x
+ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1
+c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx
+OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI
+SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI
+b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn
+swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu
+7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8
+1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW
+80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP
+JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l
+RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw
+hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10
+coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc
+BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n
+twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud
+DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W
+0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe
+uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q
+lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB
+aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE
+sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT
+MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe
+qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh
+VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8
+h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9
+EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK
+yeC2nOnOcXHebD8WpHk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf
+BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3
+YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x
+NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G
+A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0
+d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF
+Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG
+SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN
+FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w
+DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw
+CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh
+DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf
+BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3
+YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x
+NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G
+A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0
+d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF
+Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ
+j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF
+1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G
+A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3
+AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC
+MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu
+Sw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL
+BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg
+Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv
+b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG
+EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u
+IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ
+n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd
+2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF
+VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ
+GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF
+li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU
+r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2
+eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb
+MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg
+jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB
+7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW
+5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE
+ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0
+90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z
+xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu
+QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4
+FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH
+22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP
+xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn
+dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5
+Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b
+nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ
+CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH
+u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj
+d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH
+MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF
+eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx
+MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV
+BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog
+D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS
+sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop
+O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk
+sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi
+c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj
+VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz
+KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/
+TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G
+sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs
+1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD
+fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN
+l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
+ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ
+VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5
+c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp
+4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s
+t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj
+2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO
+vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C
+xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx
+cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM
+fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9
+MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH
+bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x
+CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds
+b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr
+b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9
+kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm
+VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R
+VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc
+C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj
+tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY
+D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv
+j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl
+NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6
+iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP
+O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV
+ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj
+L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
+1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl
+1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU
+b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV
+PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj
+y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb
+EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg
+DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI
++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy
+YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX
+UB+K+wb1whnw0A==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL
@@ -3181,129 +3409,6 @@ L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
-ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln
-biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
-U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp
-U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg
-SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln
-biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
-IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm
-GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve
-fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw
-AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
-aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj
-aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW
-kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
-4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
-FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
-yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
-ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
-U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
-ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
-ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
-biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
-U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
-nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
-t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
-SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
-BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
-rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
-NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
-BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
-BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
-aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
-MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
-p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
-5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
-WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
-4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
-hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
-vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
-ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
-U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
-ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
-Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
-MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
-IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
-IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
-bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
-9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
-H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
-LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
-/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
-rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
-WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
-exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
-DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
-sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
-seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
-4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
-BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
-lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
-7M2CYfE45k+XmCpajQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
-CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
-cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
-LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
-aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
-VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
-aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
-bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
-IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
-LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
-N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
-KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
-kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
-CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
-Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
-imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
-2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
-DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
-/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
-F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
-TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr
-MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl
-cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
-bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw
-CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h
-dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l
-cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h
-2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E
-lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV
-ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq
-299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t
-vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL
-dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
-AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF
-AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR
-zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3
-LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd
-7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw
-++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
-398znM/jra6O1I7mT1GvFpLgXPYHDw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
@@ -3349,6 +3454,52 @@ i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN
9u6wWk5JRFRYX0KD
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
+MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV
+BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g
+Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ
+BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ
+R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF
+dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw
+vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ
+uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp
+n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs
+cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW
+xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P
+rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF
+DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx
+DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy
+LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C
+eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ
+d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq
+kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC
+b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl
+qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0
+OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c
+NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk
+ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO
+pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj
+03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk
+PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE
+1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX
+QRBdJ3NghVdJIgc=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV
+BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk
+LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv
+b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ
+BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg
+THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v
+IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv
+xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H
+Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB
+eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo
+jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ
++efcMQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe
MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
@@ -3382,69 +3533,120 @@ W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D
hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
-qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
-Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
-MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
-BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
-NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
-LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
-A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
-IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
-W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
-3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
-6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
-Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
-NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
-MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
-r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
-DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
-YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
-xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
-/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
-LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
-jVaMaA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
-IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
-BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
-MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
-d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
-YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
-dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
-BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
-papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
-BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
-DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
-KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
-XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
-rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
-Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
-MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
-BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
-Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
-LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
-MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
-ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
-gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
-YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
-b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
-9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
-zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
-OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
-HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
-2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
-oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
-t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
-KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
-m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
-MdRAGmI0Nj81Aa6sY6A=
+MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG
+EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx
+IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw
+MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln
+biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND
+IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci
+MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti
+sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O
+BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
+Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c
+3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J
+0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG
+EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo
+bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g
+RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ
+TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s
+b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw
+djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0
+WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS
+fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB
+zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq
+hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB
+CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD
++JbNR6iC8hZVdyR+EhCVBCyj
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG
+A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg
+SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw
+MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln
+biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v
+dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ
+BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ
+HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH
+3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH
+GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c
+xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1
+aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq
+TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87
+/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4
+kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG
+YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT
++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo
+WXzhriKi4gp6D/piq1JM4fHfyr6DDUI=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD
+VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU
+ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH
+MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO
+MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv
+Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz
+f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO
+8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq
+d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM
+tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt
+Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB
+o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD
+AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x
+PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM
+wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d
+GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH
+6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby
+RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx
+iN66zB+Afko=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw
+RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY
+BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz
+MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u
+LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF
+K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0
+v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd
+e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw
+V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA
+AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG
+GJTO
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL
+BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x
+FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx
+MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s
+THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc
+IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU
+AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+
+GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9
+8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH
+flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt
+J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim
+0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN
+pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ
+UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW
+OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB
+AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet
+8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd
+nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j
+bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM
+Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv
+TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS
+S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr
+I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9
+b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB
+UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P
+Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven
+sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s=
-----END CERTIFICATE-----
`)
From 48e0ba02b7db830ac0f1a7b237658dbb076fa5ed Mon Sep 17 00:00:00 2001
From: Brian Sardo <1168933+bsardo@users.noreply.github.com>
Date: Tue, 25 Mar 2025 08:15:47 -0400
Subject: [PATCH 23/40] Run actions workflow jobs on ubuntu-latest (#4251)
---
.github/workflows/security.yml | 2 +-
.github/workflows/validate-merge.yml | 2 +-
.github/workflows/validate.yml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml
index 09a0fd56791..d3831d8044f 100644
--- a/.github/workflows/security.yml
+++ b/.github/workflows/security.yml
@@ -11,7 +11,7 @@ on:
jobs:
build:
name: Trivy
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
diff --git a/.github/workflows/validate-merge.yml b/.github/workflows/validate-merge.yml
index 729a17114e1..ca633d47465 100644
--- a/.github/workflows/validate-merge.yml
+++ b/.github/workflows/validate-merge.yml
@@ -6,7 +6,7 @@ on:
jobs:
validate-merge:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Install Go
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 3c1e3fac4ea..df71d61612a 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
go-version: [1.23.x, 1.24.x]
- os: [ubuntu-20.04]
+ os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
From e1427242e3c156d7a6d9e6270f72217a7295f278 Mon Sep 17 00:00:00 2001
From: Isha Bharti
Date: Thu, 3 Apr 2025 18:42:38 +0530
Subject: [PATCH 24/40] Filter Multi-Format Requests (#4162)
---
adapters/bidder.go | 1 +
adapters/infoawarebidder.go | 218 +++++--
adapters/infoawarebidder_test.go | 616 +++++++++++++++++-
config/account.go | 1 +
config/bidderinfo.go | 5 +-
config/bidderinfo_test.go | 34 +-
endpoints/openrtb2/amp_auction_test.go | 3 +-
endpoints/openrtb2/auction_benchmark_test.go | 3 +-
endpoints/openrtb2/auction_test.go | 4 +-
.../preferred-media-type-not-defined.json | 148 +++++
.../valid-whole/exemplary/all-ext.json | 11 +
.../valid-whole/exemplary/dooh.json | 11 +-
.../exemplary/preferred-media-type.json | 206 ++++++
endpoints/openrtb2/test_utils.go | 63 +-
exchange/adapter_util.go | 16 +-
exchange/adapter_util_test.go | 49 +-
exchange/exchange.go | 53 +-
exchange/exchange_test.go | 222 ++++++-
openrtb_ext/preferredmediatype.go | 3 +
openrtb_ext/request.go | 6 +
router/router.go | 4 +-
21 files changed, 1537 insertions(+), 140 deletions(-)
create mode 100644 endpoints/openrtb2/sample-requests/invalid-whole/preferred-media-type-not-defined.json
create mode 100644 endpoints/openrtb2/sample-requests/valid-whole/exemplary/preferred-media-type.json
create mode 100644 openrtb_ext/preferredmediatype.go
diff --git a/adapters/bidder.go b/adapters/bidder.go
index 0818120b783..e4862cb2df5 100644
--- a/adapters/bidder.go
+++ b/adapters/bidder.go
@@ -148,6 +148,7 @@ type ExtraRequestInfo struct {
PbsEntryPoint metrics.RequestType
GlobalPrivacyControlHeader string
CurrencyConversions currency.Conversions
+ PreferredMediaType openrtb_ext.BidType
}
func NewExtraRequestInfo(c currency.Conversions) ExtraRequestInfo {
diff --git a/adapters/infoawarebidder.go b/adapters/infoawarebidder.go
index e7b82c96a31..6ccc039b48f 100644
--- a/adapters/infoawarebidder.go
+++ b/adapters/infoawarebidder.go
@@ -54,55 +54,84 @@ func (i *InfoAwareBidder) MakeRequests(request *openrtb2.BidRequest, reqInfo *Ex
allowedMediaTypes = i.info.dooh
}
- // Filtering imps is quite expensive (array filter with large, non-pointer elements)... but should be rare,
- // because it only happens if the publisher makes a really bad request.
- //
- // To avoid allocating new arrays and copying in the normal case, we'll make one pass to
- // see if any imps need to be removed, and another to do the removing if necessary.
- numToFilter, errs := pruneImps(request.Imp, allowedMediaTypes)
-
- // If all imps in bid request come with unsupported media types, exit
- if numToFilter == len(request.Imp) {
- return nil, append(errs, &errortypes.Warning{Message: "Bid request didn't contain media types supported by the bidder"})
+ updated, updatedImps, errs := pruneImps(request.Imp, allowedMediaTypes, i.info.multiformat, reqInfo.PreferredMediaType)
+ if updated {
+ request.Imp = updatedImps
}
- if numToFilter != 0 {
- // Filter out imps with unsupported media types
- filteredImps, newErrs := filterImps(request.Imp, numToFilter)
- request.Imp = filteredImps
- errs = append(errs, newErrs...)
+ // If all imps in bid request are invalid, exit
+ if len(request.Imp) == 0 {
+ return nil, append(errs, &errortypes.Warning{Message: "Bid request didn't contain media types supported by the bidder"})
}
+
reqs, delegateErrs := i.Bidder.MakeRequests(request, reqInfo)
return reqs, append(errs, delegateErrs...)
}
-// pruneImps trims invalid media types from each imp, and returns true if any of the
-// Imps have _no_ valid Media Types left.
-func pruneImps(imps []openrtb2.Imp, allowedTypes parsedSupports) (int, []error) {
- numToFilter := 0
+// pruneImps trims imps that don't match the allowed types and removes imps that don't have the allowed types.
+// It also handles multi-format restrictions if the bidder doesn't support multi-format impressions.
+func pruneImps(imps []openrtb2.Imp, allowedTypes parsedSupports, multiformatSupport bool, preferredMediaType openrtb_ext.BidType) (bool, []openrtb2.Imp, []error) {
+ var updated bool
var errs []error
+ writeIndex := 0
+
for i := 0; i < len(imps); i++ {
- if !allowedTypes.banner && imps[i].Banner != nil {
- imps[i].Banner = nil
+ imp := &imps[i] // Work with pointer to avoid copying
+
+ // Prune unsupported media types
+ if !allowedTypes.banner && imp.Banner != nil {
+ imp.Banner = nil
errs = append(errs, &errortypes.Warning{Message: fmt.Sprintf("request.imp[%d] uses banner, but this bidder doesn't support it", i)})
}
- if !allowedTypes.video && imps[i].Video != nil {
- imps[i].Video = nil
+ if !allowedTypes.video && imp.Video != nil {
+ imp.Video = nil
errs = append(errs, &errortypes.Warning{Message: fmt.Sprintf("request.imp[%d] uses video, but this bidder doesn't support it", i)})
}
- if !allowedTypes.audio && imps[i].Audio != nil {
- imps[i].Audio = nil
+ if !allowedTypes.audio && imp.Audio != nil {
+ imp.Audio = nil
errs = append(errs, &errortypes.Warning{Message: fmt.Sprintf("request.imp[%d] uses audio, but this bidder doesn't support it", i)})
}
- if !allowedTypes.native && imps[i].Native != nil {
- imps[i].Native = nil
+ if !allowedTypes.native && imp.Native != nil {
+ imp.Native = nil
errs = append(errs, &errortypes.Warning{Message: fmt.Sprintf("request.imp[%d] uses native, but this bidder doesn't support it", i)})
}
- if !hasAnyTypes(&imps[i]) {
- numToFilter = numToFilter + 1
+
+ // Skip if all media types are gone
+ numOfFormats := countNumberOfFormats(imp)
+ if numOfFormats == 0 {
+ errs = append(errs, &errortypes.BadInput{Message: fmt.Sprintf("request.imp[%d] has no supported MediaTypes. It will be ignored", i)})
+ updated = true
+ continue
+ }
+
+ // Handle multi-format restrictions for bidders that don't support multi-format impressions
+ if !multiformatSupport && numOfFormats > 1 {
+
+ removeImp, multiformatErrs := adjustImpForPreferredMediaType(imp, preferredMediaType)
+
+ //remove the Imp if the bidder doesn't support the preferred media type or preferred media type is not defined
+ if removeImp {
+ errs = append(errs, multiformatErrs...)
+ updated = true
+ continue
+ }
+
+ if multiformatErrs != nil {
+ errs = append(errs, multiformatErrs...)
+ }
+ }
+
+ // Move valid imp to the correct position
+ if updated {
+ imps[writeIndex] = imps[i]
}
+ writeIndex++
}
- return numToFilter, errs
+ // If updated, return the modified slice; otherwise, return the original slice
+ if updated {
+ return true, imps[:writeIndex], errs
+ }
+ return false, imps, errs
}
func parseAllowedTypes(allowedTypes []openrtb_ext.BidType) (allowBanner bool, allowVideo bool, allowAudio bool, allowNative bool) {
@@ -121,28 +150,29 @@ func parseAllowedTypes(allowedTypes []openrtb_ext.BidType) (allowBanner bool, al
return
}
-func hasAnyTypes(imp *openrtb2.Imp) bool {
- return imp.Banner != nil || imp.Video != nil || imp.Audio != nil || imp.Native != nil
-}
-
-func filterImps(imps []openrtb2.Imp, numToFilter int) ([]openrtb2.Imp, []error) {
- newImps := make([]openrtb2.Imp, 0, len(imps)-numToFilter)
- errs := make([]error, 0, numToFilter)
- for i := 0; i < len(imps); i++ {
- if hasAnyTypes(&imps[i]) {
- newImps = append(newImps, imps[i])
- } else {
- errs = append(errs, &errortypes.BadInput{Message: fmt.Sprintf("request.imp[%d] has no supported MediaTypes. It will be ignored", i)})
- }
+func countNumberOfFormats(imp *openrtb2.Imp) int {
+ count := 0
+ if imp.Banner != nil {
+ count++
}
- return newImps, errs
+ if imp.Video != nil {
+ count++
+ }
+ if imp.Audio != nil {
+ count++
+ }
+ if imp.Native != nil {
+ count++
+ }
+ return count
}
// Structs to handle parsed bidder info, so we aren't reparsing every request
type parsedBidderInfo struct {
- app parsedSupports
- site parsedSupports
- dooh parsedSupports
+ app parsedSupports
+ site parsedSupports
+ dooh parsedSupports
+ multiformat bool
}
type parsedSupports struct {
@@ -172,5 +202,99 @@ func parseBidderInfo(info config.BidderInfo) parsedBidderInfo {
parsedInfo.dooh.enabled = true
parsedInfo.dooh.banner, parsedInfo.dooh.video, parsedInfo.dooh.audio, parsedInfo.dooh.native = parseAllowedTypes(info.Capabilities.DOOH.MediaTypes)
}
+ parsedInfo.multiformat = IsMultiFormatSupported(info)
+
return parsedInfo
}
+
+// adjustImpForPreferredMediaType modifies the given impression to retain only the preferred media type.
+// It returns the updated impression and any error encountered during the adjustment process.
+func adjustImpForPreferredMediaType(imp *openrtb2.Imp, preferredMediaType openrtb_ext.BidType) (bool, []error) {
+ var errors []error
+ var removeImp bool
+ // Clear irrelevant media types based on the preferred media type.
+ switch preferredMediaType {
+ case openrtb_ext.BidTypeBanner:
+ if imp.Banner != nil {
+ removeVideo(imp, &errors)
+ removeAudio(imp, &errors)
+ removeNative(imp, &errors)
+ } else {
+ return true, []error{&errortypes.BadInput{Message: fmt.Sprintf("Imp %s does not have a preferred BANNER media type. It will be ignored.", imp.ID)}}
+ }
+ case openrtb_ext.BidTypeVideo:
+ if imp.Video != nil {
+ removeBanner(imp, &errors)
+ removeAudio(imp, &errors)
+ removeNative(imp, &errors)
+ } else {
+ return true, []error{&errortypes.BadInput{Message: fmt.Sprintf("Imp %s does not have a preferred VIDEO media type. It will be ignored.", imp.ID)}}
+ }
+ case openrtb_ext.BidTypeAudio:
+ if imp.Audio != nil {
+ removeBanner(imp, &errors)
+ removeVideo(imp, &errors)
+ removeNative(imp, &errors)
+ } else {
+ return true, []error{&errortypes.BadInput{Message: fmt.Sprintf("Imp %s does not have a preferred AUDIO media type. It will be ignored.", imp.ID)}}
+ }
+ case openrtb_ext.BidTypeNative:
+ if imp.Native != nil {
+ removeBanner(imp, &errors)
+ removeVideo(imp, &errors)
+ removeAudio(imp, &errors)
+ } else {
+ return true, []error{&errortypes.BadInput{Message: fmt.Sprintf("Imp %s does not have a preferred NATIVE media type. It will be ignored.", imp.ID)}}
+ }
+ case "":
+ return true, []error{&errortypes.BadInput{Message: fmt.Sprintf("Removing the imp %s as the bidder does not support multi-format and preferred media type is not defined for the bidder", imp.ID)}}
+ default:
+ return true, []error{&errortypes.BadInput{Message: fmt.Sprintf("Imp %s has an invalid preferred media type: %s. It will be ignored.", imp.ID, preferredMediaType)}}
+ }
+
+ return removeImp, errors
+}
+
+// Function to remove the banner media type from the impression and add a warning.
+func removeBanner(imp *openrtb2.Imp, errors *[]error) {
+ if imp.Banner != nil {
+ addWarning(errors, imp.ID, openrtb_ext.BidTypeBanner)
+ imp.Banner = nil
+ }
+}
+
+// Function to remove the video media type from the impression and add a warning.
+func removeVideo(imp *openrtb2.Imp, errors *[]error) {
+ if imp.Video != nil {
+ addWarning(errors, imp.ID, openrtb_ext.BidTypeVideo)
+ imp.Video = nil
+ }
+}
+
+// Function to remove the Native media type from the impression and add a warning.
+func removeNative(imp *openrtb2.Imp, errors *[]error) {
+ if imp.Native != nil {
+ addWarning(errors, imp.ID, openrtb_ext.BidTypeNative)
+ imp.Native = nil
+ }
+}
+
+// Function to remove the Audio media type from the impression and add a warning.
+func removeAudio(imp *openrtb2.Imp, errors *[]error) {
+ if imp.Audio != nil {
+ addWarning(errors, imp.ID, openrtb_ext.BidTypeAudio)
+ imp.Audio = nil
+ }
+}
+
+// Function to add a warning message to the list.
+func addWarning(errors *[]error, impID string, mediaTypeName openrtb_ext.BidType) {
+ *errors = append(*errors, &errortypes.Warning{Message: fmt.Sprintf("Imp %s uses %s, removing %s as the bidder doesn't support multi-format", impID, mediaTypeName, mediaTypeName)})
+}
+
+func IsMultiFormatSupported(bidderInfo config.BidderInfo) bool {
+ if bidderInfo.OpenRTB != nil && bidderInfo.OpenRTB.MultiformatSupported != nil {
+ return *bidderInfo.OpenRTB.MultiformatSupported
+ }
+ return true
+}
diff --git a/adapters/infoawarebidder_test.go b/adapters/infoawarebidder_test.go
index 4eb2dbffe30..5a28e506cc5 100644
--- a/adapters/infoawarebidder_test.go
+++ b/adapters/infoawarebidder_test.go
@@ -1,11 +1,10 @@
-package adapters_test
+package adapters
import (
"errors"
"testing"
"github.com/prebid/openrtb/v20/openrtb2"
- "github.com/prebid/prebid-server/v3/adapters"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/errortypes"
"github.com/prebid/prebid-server/v3/openrtb_ext"
@@ -22,11 +21,11 @@ func TestAppNotSupported(t *testing.T) {
},
},
}
- constrained := adapters.BuildInfoAwareBidder(bidder, info)
+ constrained := BuildInfoAwareBidder(bidder, info)
bids, errs := constrained.MakeRequests(&openrtb2.BidRequest{
Imp: []openrtb2.Imp{{ID: "imp-1", Banner: &openrtb2.Banner{}}},
App: &openrtb2.App{},
- }, &adapters.ExtraRequestInfo{})
+ }, &ExtraRequestInfo{})
if !assert.Len(t, errs, 1) {
return
}
@@ -44,11 +43,11 @@ func TestSiteNotSupported(t *testing.T) {
},
},
}
- constrained := adapters.BuildInfoAwareBidder(bidder, info)
+ constrained := BuildInfoAwareBidder(bidder, info)
bids, errs := constrained.MakeRequests(&openrtb2.BidRequest{
Imp: []openrtb2.Imp{{ID: "imp-1", Banner: &openrtb2.Banner{}}},
Site: &openrtb2.Site{},
- }, &adapters.ExtraRequestInfo{})
+ }, &ExtraRequestInfo{})
if !assert.Len(t, errs, 1) {
return
}
@@ -66,11 +65,11 @@ func TestDOOHNotSupported(t *testing.T) {
},
},
}
- constrained := adapters.BuildInfoAwareBidder(bidder, info)
+ constrained := BuildInfoAwareBidder(bidder, info)
bids, errs := constrained.MakeRequests(&openrtb2.BidRequest{
Imp: []openrtb2.Imp{{ID: "imp-1", Banner: &openrtb2.Banner{}}},
DOOH: &openrtb2.DOOH{},
- }, &adapters.ExtraRequestInfo{})
+ }, &ExtraRequestInfo{})
require.Len(t, errs, 1)
assert.EqualError(t, errs[0], "this bidder does not support dooh requests")
assert.IsType(t, &errortypes.Warning{}, errs[0])
@@ -93,7 +92,7 @@ func TestImpFiltering(t *testing.T) {
},
}
- constrained := adapters.BuildInfoAwareBidder(bidder, info)
+ constrained := BuildInfoAwareBidder(bidder, info)
testCases := []struct {
description string
@@ -120,6 +119,7 @@ func TestImpFiltering(t *testing.T) {
},
expectedErrors: []error{
&errortypes.BadInput{Message: "request.imp[0] uses video, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[0] has no supported MediaTypes. It will be ignored"},
&errortypes.BadInput{Message: "Bid request didn't contain media types supported by the bidder"},
},
expectedImpLen: 0,
@@ -136,8 +136,11 @@ func TestImpFiltering(t *testing.T) {
},
expectedErrors: []error{
&errortypes.BadInput{Message: "request.imp[0] uses video, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[0] has no supported MediaTypes. It will be ignored"},
&errortypes.BadInput{Message: "request.imp[1] uses native, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[1] has no supported MediaTypes. It will be ignored"},
&errortypes.BadInput{Message: "request.imp[2] uses audio, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[2] has no supported MediaTypes. It will be ignored"},
&errortypes.BadInput{Message: "Bid request didn't contain media types supported by the bidder"},
},
expectedImpLen: 0,
@@ -166,9 +169,9 @@ func TestImpFiltering(t *testing.T) {
},
expectedErrors: []error{
&errortypes.BadInput{Message: "request.imp[1] uses native, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[1] has no supported MediaTypes. It will be ignored"},
&errortypes.BadInput{Message: "request.imp[2] uses native, but this bidder doesn't support it"},
&errortypes.BadInput{Message: "request.imp[3] uses banner, but this bidder doesn't support it"},
- &errortypes.BadInput{Message: "request.imp[1] has no supported MediaTypes. It will be ignored"},
&errortypes.BadInput{Message: "request.imp[3] has no supported MediaTypes. It will be ignored"},
},
expectedImpLen: 2,
@@ -188,7 +191,7 @@ func TestImpFiltering(t *testing.T) {
}
for _, test := range testCases {
- actualAdapterRequests, actualErrs := constrained.MakeRequests(test.inBidRequest, &adapters.ExtraRequestInfo{})
+ actualAdapterRequests, actualErrs := constrained.MakeRequests(test.inBidRequest, &ExtraRequestInfo{})
// Assert the request.Imp slice was correctly filtered and if MakeRequest() was called by asserting
// the corresponding error messages were returned
@@ -201,19 +204,602 @@ func TestImpFiltering(t *testing.T) {
}
}
+func TestImpFilteringForMultiFormatRequests(t *testing.T) {
+ bidder := &mockBidder{}
+ var falseValue bool
+ info := config.BidderInfo{
+ Capabilities: &config.CapabilitiesInfo{
+ Site: &config.PlatformInfo{
+ MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative, openrtb_ext.BidTypeAudio},
+ },
+ App: &config.PlatformInfo{
+ MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner},
+ },
+ DOOH: &config.PlatformInfo{
+ MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeNative},
+ },
+ },
+ OpenRTB: &config.OpenRTBInfo{
+ MultiformatSupported: &falseValue,
+ },
+ }
+
+ constrained := BuildInfoAwareBidder(bidder, info)
+
+ testCases := []struct {
+ description string
+ inBidRequest *openrtb2.BidRequest
+ inExtraRequestInfo *ExtraRequestInfo
+ expectedErrors []error
+ expectedImpLen int
+ }{
+ {
+ description: "All imps with preferred media type, MakeRequest() call expected",
+ inBidRequest: &openrtb2.BidRequest{
+ Imp: []openrtb2.Imp{
+ {
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ Video: &openrtb2.Video{},
+ },
+ {
+ ID: "imp-2",
+ Banner: &openrtb2.Banner{},
+ Native: &openrtb2.Native{},
+ },
+ },
+ Site: &openrtb2.Site{},
+ },
+ inExtraRequestInfo: &ExtraRequestInfo{
+ PreferredMediaType: openrtb_ext.BidTypeBanner,
+ },
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "Imp imp-1 uses video, removing video as the bidder doesn't support multi-format"},
+ &errortypes.Warning{Message: "Imp imp-2 uses native, removing native as the bidder doesn't support multi-format"},
+ },
+ expectedImpLen: 2,
+ },
+ {
+ description: "Some imps with preferred media type, MakeRequest() call expected",
+ inBidRequest: &openrtb2.BidRequest{
+ Imp: []openrtb2.Imp{
+ {
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ Video: &openrtb2.Video{},
+ },
+ {
+ ID: "imp-2",
+ Video: &openrtb2.Video{},
+ Native: &openrtb2.Native{},
+ },
+ {
+ ID: "imp-3",
+ Video: &openrtb2.Video{},
+ Audio: &openrtb2.Audio{},
+ },
+ },
+ Site: &openrtb2.Site{},
+ },
+ inExtraRequestInfo: &ExtraRequestInfo{
+ PreferredMediaType: openrtb_ext.BidTypeBanner,
+ },
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "Imp imp-1 uses video, removing video as the bidder doesn't support multi-format"},
+ &errortypes.BadInput{Message: "Imp imp-2 does not have a preferred BANNER media type. It will be ignored."},
+ &errortypes.BadInput{Message: "Imp imp-3 does not have a preferred BANNER media type. It will be ignored."},
+ },
+ expectedImpLen: 1,
+ },
+ {
+ description: "No imps with preferred media type, MakeRequest() call not expected",
+ inBidRequest: &openrtb2.BidRequest{
+ Imp: []openrtb2.Imp{
+ {
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ Video: &openrtb2.Video{},
+ },
+ {
+ ID: "imp-2",
+ Video: &openrtb2.Video{},
+ Native: &openrtb2.Native{},
+ },
+ },
+ Site: &openrtb2.Site{},
+ },
+ inExtraRequestInfo: &ExtraRequestInfo{
+ PreferredMediaType: openrtb_ext.BidTypeAudio,
+ },
+ expectedErrors: []error{
+ &errortypes.BadInput{Message: "Imp imp-1 does not have a preferred AUDIO media type. It will be ignored."},
+ &errortypes.BadInput{Message: "Imp imp-2 does not have a preferred AUDIO media type. It will be ignored."},
+ &errortypes.BadInput{Message: "Bid request didn't contain media types supported by the bidder"},
+ },
+ expectedImpLen: 0,
+ },
+ {
+ description: "preferred media type not defined, MakeRequest() call not expected",
+ inBidRequest: &openrtb2.BidRequest{
+ Imp: []openrtb2.Imp{
+ {
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ Video: &openrtb2.Video{},
+ },
+ },
+ Site: &openrtb2.Site{},
+ },
+ inExtraRequestInfo: &ExtraRequestInfo{
+ PreferredMediaType: "",
+ },
+ expectedErrors: []error{
+ &errortypes.BadInput{Message: "Removing the imp imp-1 as the bidder does not support multi-format and preferred media type is not defined for the bidder"},
+ },
+ expectedImpLen: 0,
+ },
+ }
+
+ for _, test := range testCases {
+ actualAdapterRequests, actualErrs := constrained.MakeRequests(test.inBidRequest, test.inExtraRequestInfo)
+
+ for i, expectedErr := range test.expectedErrors {
+ assert.EqualError(t, expectedErr, actualErrs[i].Error(), "Test failed. Error[%d] in error list mismatch: %s", i, test.description)
+ }
+ assert.Len(t, actualAdapterRequests, test.expectedImpLen, "Test failed. Incorrect length of filtered imps: %s", test.description)
+ }
+}
+
+func TestAdjustImpForPreferredMediaType(t *testing.T) {
+ testCases := []struct {
+ description string
+ inImp openrtb2.Imp
+ preferredMediaType openrtb_ext.BidType
+ expectedImp openrtb2.Imp
+ expectedErrors []error
+ }{
+ {
+ description: "Multiformat impression with all media types and preferred media type Banner",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ Video: &openrtb2.Video{},
+ Audio: &openrtb2.Audio{},
+ Native: &openrtb2.Native{},
+ },
+ preferredMediaType: openrtb_ext.BidTypeBanner,
+ expectedImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ },
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "Imp imp-1 uses video, removing video as the bidder doesn't support multi-format"},
+ &errortypes.Warning{Message: "Imp imp-1 uses audio, removing audio as the bidder doesn't support multi-format"},
+ &errortypes.Warning{Message: "Imp imp-1 uses native, removing native as the bidder doesn't support multi-format"},
+ },
+ },
+ {
+ description: "Multiformat impression with all media types and preferred media type Video",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ Video: &openrtb2.Video{},
+ Audio: &openrtb2.Audio{},
+ Native: &openrtb2.Native{},
+ },
+ preferredMediaType: openrtb_ext.BidTypeVideo,
+ expectedImp: openrtb2.Imp{
+ ID: "imp-1",
+ Video: &openrtb2.Video{},
+ },
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "Imp imp-1 uses banner, removing banner as the bidder doesn't support multi-format"},
+ &errortypes.Warning{Message: "Imp imp-1 uses audio, removing audio as the bidder doesn't support multi-format"},
+ &errortypes.Warning{Message: "Imp imp-1 uses native, removing native as the bidder doesn't support multi-format"},
+ },
+ },
+ {
+ description: "Multiformat impression with all media types and preferred media type Audio",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ Video: &openrtb2.Video{},
+ Audio: &openrtb2.Audio{},
+ Native: &openrtb2.Native{},
+ },
+ preferredMediaType: openrtb_ext.BidTypeAudio,
+ expectedImp: openrtb2.Imp{
+ ID: "imp-1",
+ Audio: &openrtb2.Audio{},
+ },
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "Imp imp-1 uses banner, removing banner as the bidder doesn't support multi-format"},
+ &errortypes.Warning{Message: "Imp imp-1 uses video, removing video as the bidder doesn't support multi-format"},
+ &errortypes.Warning{Message: "Imp imp-1 uses native, removing native as the bidder doesn't support multi-format"},
+ },
+ },
+ {
+ description: "Multiformat impression with all media types and preferred media type Native",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ Video: &openrtb2.Video{},
+ Audio: &openrtb2.Audio{},
+ Native: &openrtb2.Native{},
+ },
+ preferredMediaType: openrtb_ext.BidTypeNative,
+ expectedImp: openrtb2.Imp{
+ ID: "imp-1",
+ Native: &openrtb2.Native{},
+ },
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "Imp imp-1 uses banner, removing banner as the bidder doesn't support multi-format"},
+ &errortypes.Warning{Message: "Imp imp-1 uses video, removing video as the bidder doesn't support multi-format"},
+ &errortypes.Warning{Message: "Imp imp-1 uses audio, removing audio as the bidder doesn't support multi-format"},
+ },
+ },
+ {
+ description: "Invalid Banner media type",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Video: &openrtb2.Video{},
+ },
+ preferredMediaType: openrtb_ext.BidTypeBanner,
+ expectedImp: openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.BadInput{Message: "Imp imp-1 does not have a preferred BANNER media type. It will be ignored."},
+ },
+ },
+ {
+ description: "Invalid Video media type",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ },
+ preferredMediaType: openrtb_ext.BidTypeVideo,
+ expectedImp: openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.BadInput{Message: "Imp imp-1 does not have a preferred VIDEO media type. It will be ignored."},
+ },
+ },
+ {
+ description: "Invalid Audio media type",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ },
+ preferredMediaType: openrtb_ext.BidTypeAudio,
+ expectedImp: openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.BadInput{Message: "Imp imp-1 does not have a preferred AUDIO media type. It will be ignored."},
+ },
+ },
+ {
+ description: "Invalid Native media type",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ },
+ preferredMediaType: openrtb_ext.BidTypeNative,
+ expectedImp: openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.BadInput{Message: "Imp imp-1 does not have a preferred NATIVE media type. It will be ignored."},
+ },
+ },
+ {
+ description: "Invalid preferred media type",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ },
+ preferredMediaType: "invalid",
+ expectedImp: openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.BadInput{Message: "Imp imp-1 has an invalid preferred media type: invalid. It will be ignored."},
+ },
+ },
+ {
+ description: "Multiformat impression with preferred media type not defined",
+ inImp: openrtb2.Imp{
+ ID: "imp-1",
+ Banner: &openrtb2.Banner{},
+ Video: &openrtb2.Video{},
+ Audio: &openrtb2.Audio{},
+ Native: &openrtb2.Native{},
+ },
+ preferredMediaType: "",
+ expectedImp: openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.BadInput{Message: "Removing the imp imp-1 as the bidder does not support multi-format and preferred media type is not defined for the bidder"},
+ },
+ },
+ }
+
+ for _, test := range testCases {
+ _, actualErrs := adjustImpForPreferredMediaType(&test.inImp, test.preferredMediaType)
+ if test.expectedErrors != nil {
+ for i, expectedErr := range test.expectedErrors {
+ assert.EqualError(t, expectedErr, actualErrs[i].Error(), "Test failed. Error[%d] in error list mismatch: %s", i, test.description)
+ }
+ } else {
+ assert.Equal(t, test.expectedImp, test.inImp, test.description)
+ }
+ }
+}
+
+func TestIsMultiFormatSupported(t *testing.T) {
+ trueValue, falseValue := true, false
+ testCases := []struct {
+ description string
+ bidderInfo config.BidderInfo
+ expected bool
+ }{
+ {
+ description: "MultiformatSupported is true",
+ bidderInfo: config.BidderInfo{
+ OpenRTB: &config.OpenRTBInfo{
+ MultiformatSupported: &trueValue,
+ },
+ },
+ expected: true,
+ },
+ {
+ description: "MultiformatSupported is false",
+ bidderInfo: config.BidderInfo{
+ OpenRTB: &config.OpenRTBInfo{
+ MultiformatSupported: &falseValue,
+ },
+ },
+ expected: false,
+ },
+ {
+ description: "MultiformatSupported is nil",
+ bidderInfo: config.BidderInfo{
+ OpenRTB: &config.OpenRTBInfo{
+ MultiformatSupported: nil,
+ },
+ },
+ expected: true,
+ },
+ {
+ description: "OpenRTB is nil",
+ bidderInfo: config.BidderInfo{},
+ expected: true,
+ },
+ }
+
+ for _, test := range testCases {
+ result := IsMultiFormatSupported(test.bidderInfo)
+ assert.Equal(t, test.expected, result, test.description)
+ }
+}
+
+func TestPruneImps(t *testing.T) {
+ testCases := []struct {
+ description string
+ imps []openrtb2.Imp
+ allowedTypes parsedSupports
+ multiformatSupport bool
+ preferredMediaType openrtb_ext.BidType
+ expectedUpdated bool
+ expectedImps []openrtb2.Imp
+ expectedErrors []error
+ }{
+ {
+ description: "No imps to filter",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Banner: &openrtb2.Banner{}},
+ },
+ allowedTypes: parsedSupports{
+ banner: true,
+ },
+ multiformatSupport: true,
+ expectedUpdated: false,
+ expectedImps: []openrtb2.Imp{
+ {ID: "imp-1", Banner: &openrtb2.Banner{}},
+ },
+ expectedErrors: nil,
+ },
+ {
+ description: "Filter out unsupported banner",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Banner: &openrtb2.Banner{}},
+ },
+ allowedTypes: parsedSupports{
+ banner: false,
+ },
+ multiformatSupport: true,
+ expectedUpdated: true,
+ expectedImps: []openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "request.imp[0] uses banner, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[0] has no supported MediaTypes. It will be ignored"},
+ },
+ },
+ {
+ description: "Filter out unsupported video",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Video: &openrtb2.Video{}},
+ },
+ allowedTypes: parsedSupports{
+ video: false,
+ },
+ multiformatSupport: true,
+ expectedUpdated: true,
+ expectedImps: []openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "request.imp[0] uses video, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[0] has no supported MediaTypes. It will be ignored"},
+ },
+ },
+ {
+ description: "Filter out unsupported audio",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Audio: &openrtb2.Audio{}},
+ },
+ allowedTypes: parsedSupports{
+ audio: false,
+ },
+ multiformatSupport: true,
+ expectedUpdated: true,
+ expectedImps: []openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "request.imp[0] uses audio, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[0] has no supported MediaTypes. It will be ignored"},
+ },
+ },
+ {
+ description: "Filter out unsupported native",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Native: &openrtb2.Native{}},
+ },
+ allowedTypes: parsedSupports{
+ native: false,
+ },
+ multiformatSupport: true,
+ expectedUpdated: true,
+ expectedImps: []openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "request.imp[0] uses native, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[0] has no supported MediaTypes. It will be ignored"},
+ },
+ },
+ {
+ description: "Filter out all unsupported types",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Banner: &openrtb2.Banner{}, Video: &openrtb2.Video{}, Audio: &openrtb2.Audio{}, Native: &openrtb2.Native{}},
+ },
+ allowedTypes: parsedSupports{
+ banner: false,
+ video: false,
+ audio: false,
+ native: false,
+ },
+ multiformatSupport: true,
+ expectedUpdated: true,
+ expectedImps: []openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "request.imp[0] uses banner, but this bidder doesn't support it"},
+ &errortypes.Warning{Message: "request.imp[0] uses video, but this bidder doesn't support it"},
+ &errortypes.Warning{Message: "request.imp[0] uses audio, but this bidder doesn't support it"},
+ &errortypes.Warning{Message: "request.imp[0] uses native, but this bidder doesn't support it"},
+ &errortypes.BadInput{Message: "request.imp[0] has no supported MediaTypes. It will be ignored"},
+ },
+ },
+ {
+ description: "Filter out unsupported multiformat, preferred media type is banner",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Banner: &openrtb2.Banner{}, Video: &openrtb2.Video{}},
+ },
+ allowedTypes: parsedSupports{
+ banner: true,
+ video: true,
+ },
+ multiformatSupport: false,
+ preferredMediaType: openrtb_ext.BidTypeBanner,
+ expectedUpdated: false,
+ expectedImps: []openrtb2.Imp{{ID: "imp-1", Banner: &openrtb2.Banner{}}},
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "Imp imp-1 uses video, removing video as the bidder doesn't support multi-format"},
+ },
+ },
+ {
+ description: "Filter out unsupported multiformat, preferred media type is video",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Banner: &openrtb2.Banner{}, Video: &openrtb2.Video{}},
+ },
+ allowedTypes: parsedSupports{
+ banner: true,
+ video: true,
+ },
+ multiformatSupport: false,
+ preferredMediaType: openrtb_ext.BidTypeVideo,
+ expectedUpdated: false,
+ expectedImps: []openrtb2.Imp{{ID: "imp-1", Video: &openrtb2.Video{}}},
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "Imp imp-1 uses banner, removing banner as the bidder doesn't support multi-format"},
+ },
+ },
+ {
+ description: "Filter out unsupported multiformat, preferred media type is video and not present in any imp",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Banner: &openrtb2.Banner{}, Native: &openrtb2.Native{}},
+ },
+ allowedTypes: parsedSupports{
+ banner: true,
+ video: true,
+ native: true,
+ },
+ multiformatSupport: false,
+ preferredMediaType: openrtb_ext.BidTypeVideo,
+ expectedUpdated: true,
+ expectedImps: []openrtb2.Imp{},
+ expectedErrors: []error{
+ &errortypes.BadInput{Message: "Imp imp-1 does not have a preferred VIDEO media type. It will be ignored."},
+ },
+ },
+ {
+ description: "Multi-imp, Filter out unsupported multiformat, preferred media type is video and present in one imp",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Banner: &openrtb2.Banner{}, Video: &openrtb2.Video{}},
+ {ID: "imp-2", Banner: &openrtb2.Banner{}, Native: &openrtb2.Native{}},
+ },
+ allowedTypes: parsedSupports{
+ banner: true,
+ video: true,
+ native: true,
+ },
+ multiformatSupport: false,
+ preferredMediaType: openrtb_ext.BidTypeVideo,
+ expectedUpdated: true,
+ expectedImps: []openrtb2.Imp{{ID: "imp-1", Video: &openrtb2.Video{}}},
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "Imp imp-1 uses banner, removing banner as the bidder doesn't support multi-format"},
+ &errortypes.BadInput{Message: "Imp imp-2 does not have a preferred VIDEO media type. It will be ignored."},
+ },
+ },
+ {
+ description: "Filter out unsupported type and unsupported multiformat, preferred media type is video",
+ imps: []openrtb2.Imp{
+ {ID: "imp-1", Banner: &openrtb2.Banner{}, Video: &openrtb2.Video{}, Native: &openrtb2.Native{}},
+ },
+ allowedTypes: parsedSupports{
+ banner: true,
+ video: true,
+ native: false,
+ },
+ multiformatSupport: false,
+ preferredMediaType: openrtb_ext.BidTypeVideo,
+ expectedUpdated: false,
+ expectedImps: []openrtb2.Imp{{ID: "imp-1", Video: &openrtb2.Video{}}},
+ expectedErrors: []error{
+ &errortypes.Warning{Message: "request.imp[0] uses native, but this bidder doesn't support it"},
+ &errortypes.Warning{Message: "Imp imp-1 uses banner, removing banner as the bidder doesn't support multi-format"},
+ },
+ },
+ }
+
+ for _, test := range testCases {
+ updated, imps, errs := pruneImps(test.imps, test.allowedTypes, test.multiformatSupport, test.preferredMediaType)
+ assert.Equal(t, test.expectedUpdated, updated, test.description+":Updated")
+ assert.Equal(t, test.expectedImps, imps, test.description+":Imps")
+ assert.Equal(t, test.expectedErrors, errs, test.description+":Errors")
+ }
+}
+
type mockBidder struct {
}
-func (m *mockBidder) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
- var adapterRequests []*adapters.RequestData
+func (m *mockBidder) MakeRequests(request *openrtb2.BidRequest, reqInfo *ExtraRequestInfo) ([]*RequestData, []error) {
+ var adapterRequests []*RequestData
for i := 0; i < len(request.Imp); i++ {
- adapterRequests = append(adapterRequests, &adapters.RequestData{})
+ adapterRequests = append(adapterRequests, &RequestData{})
}
return adapterRequests, nil
}
-func (m *mockBidder) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+func (m *mockBidder) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *RequestData, response *ResponseData) (*BidderResponse, []error) {
return nil, []error{errors.New("mock MakeBids error")}
}
diff --git a/config/account.go b/config/account.go
index 310fd021dce..3d7e0f8c804 100644
--- a/config/account.go
+++ b/config/account.go
@@ -42,6 +42,7 @@ type Account struct {
DefaultBidLimit int `mapstructure:"default_bid_limit" json:"default_bid_limit"`
BidAdjustments *openrtb_ext.ExtRequestPrebidBidAdjustments `mapstructure:"bidadjustments" json:"bidadjustments"`
Privacy AccountPrivacy `mapstructure:"privacy" json:"privacy"`
+ PreferredMediaType openrtb_ext.PreferredMediaType `mapstructure:"preferredmediatype" json:"preferredmediatype"`
}
// CookieSync represents the account-level defaults for the cookie sync endpoint.
diff --git a/config/bidderinfo.go b/config/bidderinfo.go
index d553df1f4e5..87771b402e1 100644
--- a/config/bidderinfo.go
+++ b/config/bidderinfo.go
@@ -96,8 +96,9 @@ type AdapterXAPI struct {
// Version is not yet actively supported
// GPPSupported is not yet actively supported
type OpenRTBInfo struct {
- Version string `yaml:"version" mapstructure:"version"`
- GPPSupported bool `yaml:"gpp-supported" mapstructure:"gpp-supported"`
+ Version string `yaml:"version" mapstructure:"version"`
+ GPPSupported bool `yaml:"gpp-supported" mapstructure:"gpp-supported"`
+ MultiformatSupported *bool `yaml:"multiformat-supported" mapstructure:"multiformat-supported"`
}
// Syncer specifies the user sync settings for a bidder. This struct is shared by the account config,
diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go
index 9ad64ee213f..0b9547d0d67 100644
--- a/config/bidderinfo_test.go
+++ b/config/bidderinfo_test.go
@@ -47,6 +47,7 @@ endpointCompression: GZIP
openrtb:
version: 2.6
gpp-supported: true
+ multiformat-supported: false
endpoint: https://endpoint.com
disabled: false
extra_info: extra-info
@@ -122,12 +123,15 @@ func TestLoadBidderInfoFromDisk(t *testing.T) {
}
func TestProcessBidderInfo(t *testing.T) {
+ falseValue := false
+
testCases := []struct {
description string
bidderInfos map[string][]byte
expectedBidderInfos BidderInfos
expectError string
}{
+
{
description: "Valid bidder info",
bidderInfos: map[string][]byte{
@@ -205,8 +209,9 @@ func TestProcessBidderInfo(t *testing.T) {
},
ModifyingVastXmlAllowed: true,
OpenRTB: &OpenRTBInfo{
- GPPSupported: true,
- Version: "2.6",
+ GPPSupported: true,
+ Version: "2.6",
+ MultiformatSupported: &falseValue,
},
PlatformID: "123",
Syncer: &Syncer{
@@ -256,8 +261,9 @@ func TestProcessBidderInfo(t *testing.T) {
},
ModifyingVastXmlAllowed: true,
OpenRTB: &OpenRTBInfo{
- GPPSupported: true,
- Version: "2.6",
+ GPPSupported: true,
+ Version: "2.6",
+ MultiformatSupported: &falseValue,
},
PlatformID: "123",
Syncer: &Syncer{
@@ -285,6 +291,9 @@ func TestProcessBidderInfo(t *testing.T) {
}
func TestProcessAliasBidderInfo(t *testing.T) {
+
+ trueValue := true
+
parentWithSyncerKey := BidderInfo{
AppSecret: "app-secret",
Capabilities: &CapabilitiesInfo{
@@ -313,8 +322,9 @@ func TestProcessAliasBidderInfo(t *testing.T) {
},
ModifyingVastXmlAllowed: true,
OpenRTB: &OpenRTBInfo{
- GPPSupported: true,
- Version: "2.6",
+ GPPSupported: true,
+ Version: "2.6",
+ MultiformatSupported: &trueValue,
},
PlatformID: "123",
Syncer: &Syncer{
@@ -360,8 +370,9 @@ func TestProcessAliasBidderInfo(t *testing.T) {
},
ModifyingVastXmlAllowed: false,
OpenRTB: &OpenRTBInfo{
- GPPSupported: false,
- Version: "2.5",
+ GPPSupported: false,
+ Version: "2.5",
+ MultiformatSupported: &trueValue,
},
PlatformID: "456",
Syncer: &Syncer{
@@ -1887,7 +1898,7 @@ func TestApplyBidderInfoConfigOverridesInvalid(t *testing.T) {
func TestReadFullYamlBidderConfig(t *testing.T) {
bidder := "bidderA"
bidderInf := BidderInfo{}
-
+ falseValue := false
err := yaml.Unmarshal([]byte(fullBidderYAMLConfig), &bidderInf)
require.NoError(t, err)
@@ -1934,8 +1945,9 @@ func TestReadFullYamlBidderConfig(t *testing.T) {
},
EndpointCompression: "GZIP",
OpenRTB: &OpenRTBInfo{
- GPPSupported: true,
- Version: "2.6",
+ GPPSupported: true,
+ Version: "2.6",
+ MultiformatSupported: &falseValue,
},
Disabled: false,
ExtraAdapterInfo: "extra-info",
diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go
index 3fe8a629f02..78a967facec 100644
--- a/endpoints/openrtb2/amp_auction_test.go
+++ b/endpoints/openrtb2/amp_auction_test.go
@@ -19,6 +19,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "github.com/prebid/prebid-server/v3/adapters"
"github.com/prebid/prebid-server/v3/amp"
"github.com/prebid/prebid-server/v3/analytics"
analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build"
@@ -146,7 +147,7 @@ func TestGoodAmpRequests(t *testing.T) {
t.Fatalf("Unexpected bidder %s has an expected mock bidder request. Test file: %s", bidder, filename)
}
aa := a.(*exchange.BidderAdapter)
- ma := aa.Bidder.(*mockAdapter)
+ ma := aa.Bidder.(*adapters.InfoAwareBidder).Bidder.(*mockAdapter)
assert.JSONEq(t, string(req), string(ma.requestData[0]), "Not the expected mock bidder request for bidder %s. Test file: %s", bidder, filename)
}
}
diff --git a/endpoints/openrtb2/auction_benchmark_test.go b/endpoints/openrtb2/auction_benchmark_test.go
index 9697687407e..5dfaecdda91 100644
--- a/endpoints/openrtb2/auction_benchmark_test.go
+++ b/endpoints/openrtb2/auction_benchmark_test.go
@@ -76,7 +76,7 @@ func BenchmarkOpenrtbEndpoint(b *testing.B) {
nilMetrics := &metricsConfig.NilMetricsEngine{}
- adapters, adaptersErr := exchange.BuildAdapters(server.Client(), &config.Configuration{}, infos, nilMetrics)
+ adapters, singleFormatBidders, adaptersErr := exchange.BuildAdapters(server.Client(), &config.Configuration{}, infos, nilMetrics)
if adaptersErr != nil {
b.Fatal("unable to build adapters")
}
@@ -99,6 +99,7 @@ func BenchmarkOpenrtbEndpoint(b *testing.B) {
&adscert.NilSigner{},
macros.NewStringIndexBasedReplacer(),
nil,
+ singleFormatBidders,
)
endpoint, _ := NewEndpoint(
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index c4de9a33e07..1fc6e50346d 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -23,6 +23,7 @@ import (
"github.com/julienschmidt/httprouter"
gpplib "github.com/prebid/go-gpp"
"github.com/prebid/openrtb/v20/openrtb2"
+ "github.com/prebid/prebid-server/v3/adapters"
"github.com/prebid/prebid-server/v3/analytics"
analyticsBuild "github.com/prebid/prebid-server/v3/analytics/build"
"github.com/prebid/prebid-server/v3/config"
@@ -173,6 +174,7 @@ func runJsonBasedTest(t *testing.T, filename, desc string) {
cfg.BlockedApps = test.Config.BlockedApps
cfg.BlockedAppsLookup = test.Config.getBlockedAppLookup()
cfg.AccountRequired = test.Config.AccountRequired
+ cfg.AccountDefaults.PreferredMediaType = test.Config.PreferredMediaType
}
cfg.MarshalAccountDefaults()
test.endpointType = OPENRTB_ENDPOINT
@@ -196,7 +198,7 @@ func runJsonBasedTest(t *testing.T, filename, desc string) {
t.Fatalf("Unexpected bidder %s has an expected mock bidder request. Test file: %s", bidder, filename)
}
aa := a.(*exchange.BidderAdapter)
- ma := aa.Bidder.(*mockAdapter)
+ ma := aa.Bidder.(*adapters.InfoAwareBidder).Bidder.(*mockAdapter)
assert.JSONEq(t, string(req), string(ma.requestData[0]), "Not the expected mock bidder request for bidder %s. Test file: %s", bidder, filename)
}
}
diff --git a/endpoints/openrtb2/sample-requests/invalid-whole/preferred-media-type-not-defined.json b/endpoints/openrtb2/sample-requests/invalid-whole/preferred-media-type-not-defined.json
new file mode 100644
index 00000000000..dbf006e7612
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/invalid-whole/preferred-media-type-not-defined.json
@@ -0,0 +1,148 @@
+{
+ "description": "multiformat request with preferred media type",
+ "config": {
+ "mockBidders": [
+ {
+ "bidderName": "appnexus",
+ "currency": "USD",
+ "price": 1.00
+ },
+ {
+ "bidderName": "pubmatic",
+ "currency": "USD",
+ "price": 2.00
+ }
+ ],
+ "bidderInfoOverrides": {
+ "appnexus": {
+ "openrtb": {
+ "multiformat-supported": false
+ }
+ },
+ "pubmatic": {
+ "openrtb": {
+ "multiformat-supported": false
+ }
+ }
+ }
+ },
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "site": {
+ "page": "prebid.org"
+ },
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "video": {
+ "w": 640,
+ "h": 480,
+ "mimes": [
+ "video/mp4"
+ ],
+ "protocols": [
+ 2, 3, 5, 6
+ ]
+ },
+ "ext": {
+ "appnexus": {
+ "placementId": 12883451
+ },
+ "pubmatic": {
+ "publisherId": "123"
+ }
+ }
+ }
+ ],
+ "tmax": 500,
+ "ext": {
+ "prebid": {
+ "biddercontrols":{
+ "appnexus":{
+ "prefmtype":"banner"
+ }
+ }
+ }
+ }
+ },
+ "expectedMockBidderRequests": {
+ "appnexus": {
+ "id": "some-request-id",
+ "site": {
+ "page": "prebid.org",
+ "ext": {
+ "amp": 0
+ }
+ },
+ "at": 1,
+ "device": {
+ "ip": "192.0.2.1"
+ },
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "placementId": 12883451
+ }
+ },
+ "secure": 1
+ }
+ ],
+ "tmax": 500
+ }
+ },
+ "expectedBidResponse": {
+ "id": "some-request-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "appnexus-bid",
+ "impid": "some-impression-id",
+ "price": 1.0,
+ "ext": {
+ "origbidcpm": 1.0,
+ "origbidcur": "USD",
+ "prebid": {
+ "meta": {
+ "adaptercode": "appnexus"
+ },
+ "type": "banner"
+ }
+ }
+ }
+ ],
+ "seat": "appnexus"
+ }
+ ],
+ "bidid": "test bid id",
+ "cur": "USD",
+ "nbr": 0
+ },
+ "expectedReturnCode": 200
+ }
\ No newline at end of file
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/exemplary/all-ext.json b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/all-ext.json
index 556a04fbec8..98a05bfb788 100644
--- a/endpoints/openrtb2/sample-requests/valid-whole/exemplary/all-ext.json
+++ b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/all-ext.json
@@ -96,6 +96,17 @@
}
]
}
+ },
+ "biddercontrols":{
+ "appnexus": {
+ "prefmtype": "banner"
+ },
+ "districtm": {
+ "prefmtype": "video"
+ },
+ "rubicon": {
+ "prefmtype": "native"
+ }
}
}
}
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/exemplary/dooh.json b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/dooh.json
index faa9a7f6646..8990fbc4d93 100644
--- a/endpoints/openrtb2/sample-requests/valid-whole/exemplary/dooh.json
+++ b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/dooh.json
@@ -3,7 +3,16 @@
"config": {
"mockBidders": [
{"bidderName": "appnexus", "currency": "USD", "price": 0.00}
- ]
+ ],
+ "bidderInfoOverrides":{
+ "appnexus": {
+ "capabilities": {
+ "dooh": {
+ "mediaTypes": ["banner"]
+ }
+ }
+ }
+ }
},
"mockBidRequest": {
"id": "some-request-id",
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/exemplary/preferred-media-type.json b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/preferred-media-type.json
new file mode 100644
index 00000000000..5dd9a0bd221
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/preferred-media-type.json
@@ -0,0 +1,206 @@
+{
+ "description": "multiformat request with preferred media type",
+ "config": {
+ "mockBidders": [
+ {
+ "bidderName": "appnexus",
+ "currency": "USD",
+ "price": 1.00
+ },
+ {
+ "bidderName": "pubmatic",
+ "currency": "USD",
+ "price": 2.00
+ }
+ ],
+ "bidderInfoOverrides": {
+ "appnexus": {
+ "openrtb": {
+ "multiformat-supported": false
+ }
+ },
+ "pubmatic": {
+ "openrtb": {
+ "multiformat-supported": false
+ }
+ }
+ },
+ "preferredmediatype":{
+ "pubmatic" : "video"
+ }
+ },
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "site": {
+ "page": "prebid.org"
+ },
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "video": {
+ "w": 640,
+ "h": 480,
+ "mimes": [
+ "video/mp4"
+ ],
+ "protocols": [
+ 2, 3, 5, 6
+ ]
+ },
+ "ext": {
+ "appnexus": {
+ "placementId": 12883451
+ },
+ "pubmatic": {
+ "publisherId": "123"
+ }
+ }
+ }
+ ],
+ "tmax": 500,
+ "ext": {
+ "prebid": {
+ "biddercontrols":{
+ "appnexus":{
+ "prefmtype":"banner"
+ }
+ }
+ }
+ }
+ },
+ "expectedMockBidderRequests": {
+ "appnexus": {
+ "id": "some-request-id",
+ "site": {
+ "page": "prebid.org",
+ "ext": {
+ "amp": 0
+ }
+ },
+ "at": 1,
+ "device": {
+ "ip": "192.0.2.1"
+ },
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "placementId": 12883451
+ }
+ },
+ "secure": 1
+ }
+ ],
+ "tmax": 500
+ },
+ "pubmatic": {
+ "id": "some-request-id",
+ "site": {
+ "page": "prebid.org",
+ "ext": {
+ "amp": 0
+ }
+ },
+ "at": 1,
+ "device": {
+ "ip": "192.0.2.1"
+ },
+ "imp": [
+ {
+ "id": "some-impression-id",
+ "video": {
+ "w": 640,
+ "h": 480,
+ "mimes": [
+ "video/mp4"
+ ],
+ "protocols": [
+ 2, 3, 5, 6
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "123"
+ }
+ },
+ "secure": 1
+ }
+ ],
+ "tmax": 500
+ }
+ },
+ "expectedBidResponse": {
+ "id": "some-request-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "appnexus-bid",
+ "impid": "some-impression-id",
+ "price": 1.0,
+ "ext": {
+ "origbidcpm": 1.0,
+ "origbidcur": "USD",
+ "prebid": {
+ "meta": {
+ "adaptercode": "appnexus"
+ },
+ "type": "banner"
+ }
+ }
+ }
+ ],
+ "seat": "appnexus"
+ },
+ {
+ "bid": [
+ {
+ "id": "pubmatic-bid",
+ "impid": "some-impression-id",
+ "price": 2.0,
+ "ext": {
+ "origbidcpm": 2.0,
+ "origbidcur": "USD",
+ "prebid": {
+ "meta": {
+ "adaptercode": "pubmatic"
+ },
+ "type": "banner"
+ }
+ }
+ }
+ ],
+ "seat": "pubmatic"
+ }
+ ],
+ "bidid": "test bid id",
+ "cur": "USD",
+ "nbr": 0
+ },
+ "expectedReturnCode": 200
+ }
\ No newline at end of file
diff --git a/endpoints/openrtb2/test_utils.go b/endpoints/openrtb2/test_utils.go
index 92e54ed3ed4..b19cb5badab 100644
--- a/endpoints/openrtb2/test_utils.go
+++ b/endpoints/openrtb2/test_utils.go
@@ -93,12 +93,27 @@ type testConfigValues struct {
MockBidders []mockBidderHandler `json:"mockBidders"`
RealParamsValidator bool `json:"realParamsValidator"`
BidderInfos map[string]bidderInfoOverrides `json:"bidderInfoOverrides"`
+ PreferredMediaType openrtb_ext.PreferredMediaType `json:"preferredmediatype"`
}
type bidderInfoOverrides struct {
- OpenRTB *OpenRTBInfo `json:"openrtb"`
+ OpenRTB *OpenRTBInfo `json:"openrtb"`
+ Capabilities *CapabilitiesInfo `json:"capabilities"`
}
type OpenRTBInfo struct {
- Version string `json:"version"`
+ Version string `json:"version"`
+ MultiformatSupported *bool `json:"multiformat-supported"`
+}
+
+// CapabilitiesInfo specifies the supported platforms for a bidder.
+type CapabilitiesInfo struct {
+ App *PlatformInfo `json:"app" mapstructure:"app"`
+ Site *PlatformInfo `json:"site" mapstructure:"site"`
+ DOOH *PlatformInfo `json:"dooh" mapstructure:"dooh"`
+}
+
+// PlatformInfo specifies the supported media types for a bidder.
+type PlatformInfo struct {
+ MediaTypes []openrtb_ext.BidType `yaml:"mediaTypes" mapstructure:"mediaTypes"`
}
type brokenExchange struct{}
@@ -1224,13 +1239,20 @@ func buildTestExchange(testCfg *testConfigValues, adapterMap map[openrtb_ext.Bid
if len(testCfg.MockBidders) == 0 {
testCfg.MockBidders = append(testCfg.MockBidders, mockBidderHandler{BidderName: "appnexus", Currency: "USD", Price: 0.00})
}
+ singleFormatBidders := make(map[openrtb_ext.BidderName]struct{})
for _, mockBidder := range testCfg.MockBidders {
bidServer := httptest.NewServer(http.HandlerFunc(mockBidder.bid))
- bidderAdapter := mockAdapter{mockServerURL: bidServer.URL, seat: mockBidder.Seat}
+ bidderAdapter := &mockAdapter{mockServerURL: bidServer.URL, seat: mockBidder.Seat}
bidderName := openrtb_ext.BidderName(mockBidder.BidderName)
- adapterMap[bidderName] = exchange.AdaptBidder(&bidderAdapter, bidServer.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, bidderName, nil, "")
+ infoAwareBidderAdapter := adapters.BuildInfoAwareBidder(bidderAdapter, bidderInfos[string(bidderName)])
+
+ adapterMap[bidderName] = exchange.AdaptBidder(infoAwareBidderAdapter, bidServer.Client(), &config.Configuration{}, &metricsConfig.NilMetricsEngine{}, bidderName, nil, "")
mockBidServersArray = append(mockBidServersArray, bidServer)
+
+ if bidderInfo := bidderInfos[string(bidderName)]; bidderInfo.OpenRTB != nil && bidderInfo.OpenRTB.MultiformatSupported != nil && !*bidderInfo.OpenRTB.MultiformatSupported {
+ singleFormatBidders[bidderName] = struct{}{}
+ }
}
mockCurrencyConverter := currency.NewRateConverter(mockCurrencyRatesServer.Client(), mockCurrencyRatesServer.URL, time.Second)
@@ -1241,7 +1263,6 @@ func buildTestExchange(testCfg *testConfigValues, adapterMap map[openrtb_ext.Bid
}.Builder
testExchange := exchange.NewExchange(adapterMap,
-
&wellBehavedCache{},
cfg,
requestValidator,
@@ -1254,6 +1275,7 @@ func buildTestExchange(testCfg *testConfigValues, adapterMap map[openrtb_ext.Bid
&adscert.NilSigner{},
macros.NewStringIndexBasedReplacer(),
nil,
+ singleFormatBidders,
)
testExchange = &exchangeTestWrapper{
@@ -1284,11 +1306,38 @@ func buildTestEndpoint(test testCase, cfg *config.Configuration) (httprouter.Han
bidderInfos, _ := config.LoadBidderInfoFromDisk("../../static/bidder-info")
for bidder, overrides := range test.Config.BidderInfos {
if bi, ok := bidderInfos[bidder]; ok {
- if overrides.OpenRTB != nil && len(overrides.OpenRTB.Version) > 0 {
+ if overrides.OpenRTB != nil || overrides.Capabilities != nil {
if bi.OpenRTB == nil {
bi.OpenRTB = &config.OpenRTBInfo{}
}
- bi.OpenRTB.Version = overrides.OpenRTB.Version
+ if overrides.OpenRTB != nil {
+ if len(overrides.OpenRTB.Version) > 0 {
+ bi.OpenRTB.Version = overrides.OpenRTB.Version
+ }
+ if overrides.OpenRTB.MultiformatSupported != nil {
+ bi.OpenRTB.MultiformatSupported = overrides.OpenRTB.MultiformatSupported
+ }
+ }
+ if overrides.Capabilities != nil {
+ if bi.Capabilities == nil {
+ bi.Capabilities = &config.CapabilitiesInfo{}
+ }
+
+ if overrides.Capabilities.Site != nil {
+ bi.Capabilities.Site = &config.PlatformInfo{}
+ bi.Capabilities.Site.MediaTypes = overrides.Capabilities.Site.MediaTypes
+ }
+
+ if overrides.Capabilities.App != nil {
+ bi.Capabilities.App = &config.PlatformInfo{}
+ bi.Capabilities.App.MediaTypes = overrides.Capabilities.App.MediaTypes
+ }
+
+ if overrides.Capabilities.DOOH != nil {
+ bi.Capabilities.DOOH = &config.PlatformInfo{}
+ bi.Capabilities.DOOH.MediaTypes = overrides.Capabilities.DOOH.MediaTypes
+ }
+ }
bidderInfos[bidder] = bi
}
}
diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go
index e70c32055a0..7eadeac0fce 100644
--- a/exchange/adapter_util.go
+++ b/exchange/adapter_util.go
@@ -10,12 +10,12 @@ import (
"github.com/prebid/prebid-server/v3/openrtb_ext"
)
-func BuildAdapters(client *http.Client, cfg *config.Configuration, infos config.BidderInfos, me metrics.MetricsEngine) (map[openrtb_ext.BidderName]AdaptedBidder, []error) {
+func BuildAdapters(client *http.Client, cfg *config.Configuration, infos config.BidderInfos, me metrics.MetricsEngine) (map[openrtb_ext.BidderName]AdaptedBidder, map[openrtb_ext.BidderName]struct{}, []error) {
server := config.Server{ExternalUrl: cfg.ExternalURL, GvlID: cfg.GDPR.HostVendorID, DataCenter: cfg.DataCenter}
- bidders, errs := buildBidders(infos, newAdapterBuilders(), server)
+ bidders, singleFormatBidders, errs := buildBidders(infos, newAdapterBuilders(), server)
if len(errs) > 0 {
- return nil, errs
+ return nil, nil, errs
}
exchangeBidders := make(map[openrtb_ext.BidderName]AdaptedBidder, len(bidders))
@@ -25,11 +25,12 @@ func BuildAdapters(client *http.Client, cfg *config.Configuration, infos config.
exchangeBidder = addValidatedBidderMiddleware(exchangeBidder)
exchangeBidders[bidderName] = exchangeBidder
}
- return exchangeBidders, nil
+ return exchangeBidders, singleFormatBidders, nil
}
-func buildBidders(infos config.BidderInfos, builders map[openrtb_ext.BidderName]adapters.Builder, server config.Server) (map[openrtb_ext.BidderName]adapters.Bidder, []error) {
+func buildBidders(infos config.BidderInfos, builders map[openrtb_ext.BidderName]adapters.Builder, server config.Server) (map[openrtb_ext.BidderName]adapters.Bidder, map[openrtb_ext.BidderName]struct{}, []error) {
bidders := make(map[openrtb_ext.BidderName]adapters.Bidder)
+ singleFormatBidders := make(map[openrtb_ext.BidderName]struct{})
var errs []error
for bidder, info := range infos {
@@ -61,9 +62,12 @@ func buildBidders(infos config.BidderInfos, builders map[openrtb_ext.BidderName]
continue
}
bidders[bidderName] = adapters.BuildInfoAwareBidder(bidderInstance, info)
+ if !adapters.IsMultiFormatSupported(info) {
+ singleFormatBidders[bidderName] = struct{}{}
+ }
}
}
- return bidders, errs
+ return bidders, singleFormatBidders, errs
}
func setAliasBuilder(info config.BidderInfo, builders map[openrtb_ext.BidderName]adapters.Builder, bidderName openrtb_ext.BidderName) error {
diff --git a/exchange/adapter_util_test.go b/exchange/adapter_util_test.go
index 3f558af5610..e6da2f8e7c6 100644
--- a/exchange/adapter_util_test.go
+++ b/exchange/adapter_util_test.go
@@ -17,8 +17,15 @@ import (
)
var (
- infoEnabled = config.BidderInfo{Disabled: false}
- infoDisabled = config.BidderInfo{Disabled: true}
+ falseValue = false
+ infoEnabled = config.BidderInfo{Disabled: false}
+ infoDisabled = config.BidderInfo{Disabled: true}
+ multiformatDisabled = config.BidderInfo{
+ Disabled: false,
+ OpenRTB: &config.OpenRTBInfo{
+ MultiformatSupported: &falseValue,
+ },
+ }
)
func TestBuildAdapters(t *testing.T) {
@@ -36,15 +43,17 @@ func TestBuildAdapters(t *testing.T) {
rubiconBidderValidated := addValidatedBidderMiddleware(rubiconBidderAdapted)
testCases := []struct {
- description string
- bidderInfos map[string]config.BidderInfo
- expectedBidders map[openrtb_ext.BidderName]AdaptedBidder
- expectedErrors []error
+ description string
+ bidderInfos map[string]config.BidderInfo
+ expectedBidders map[openrtb_ext.BidderName]AdaptedBidder
+ expectedSingleFormatBidders map[openrtb_ext.BidderName]struct{}
+ expectedErrors []error
}{
{
- description: "No Bidders",
- bidderInfos: map[string]config.BidderInfo{},
- expectedBidders: map[openrtb_ext.BidderName]AdaptedBidder{},
+ description: "No Bidders",
+ bidderInfos: map[string]config.BidderInfo{},
+ expectedBidders: map[openrtb_ext.BidderName]AdaptedBidder{},
+ expectedSingleFormatBidders: map[openrtb_ext.BidderName]struct{}{},
},
{
description: "One Bidder",
@@ -52,6 +61,7 @@ func TestBuildAdapters(t *testing.T) {
expectedBidders: map[openrtb_ext.BidderName]AdaptedBidder{
openrtb_ext.BidderAppnexus: appnexusValidated,
},
+ expectedSingleFormatBidders: map[openrtb_ext.BidderName]struct{}{},
},
{
description: "Many Bidders",
@@ -60,6 +70,7 @@ func TestBuildAdapters(t *testing.T) {
openrtb_ext.BidderAppnexus: appnexusValidated,
openrtb_ext.BidderRubicon: rubiconBidderValidated,
},
+ expectedSingleFormatBidders: map[openrtb_ext.BidderName]struct{}{},
},
{
description: "Invalid - Builder Errors",
@@ -67,13 +78,29 @@ func TestBuildAdapters(t *testing.T) {
expectedErrors: []error{
errors.New("unknown: unknown bidder"),
},
+ expectedSingleFormatBidders: nil,
+ },
+ {
+ description: "Bidders with multiformat Support Disabled",
+ bidderInfos: map[string]config.BidderInfo{"appnexus": multiformatDisabled, "rubicon": multiformatDisabled},
+ expectedBidders: map[openrtb_ext.BidderName]AdaptedBidder{
+ openrtb_ext.BidderAppnexus: appnexusValidated,
+ openrtb_ext.BidderRubicon: rubiconBidderValidated,
+ },
+ expectedSingleFormatBidders: map[openrtb_ext.BidderName]struct{}{
+ openrtb_ext.BidderAppnexus: {},
+ openrtb_ext.BidderRubicon: {},
+ },
},
}
cfg := &config.Configuration{}
for _, test := range testCases {
- bidders, errs := BuildAdapters(client, cfg, test.bidderInfos, metricEngine)
+ bidders, singleFormatBidders, errs := BuildAdapters(client, cfg, test.bidderInfos, metricEngine)
assert.Equal(t, test.expectedBidders, bidders, test.description+":bidders")
+
+ assert.Equal(t, test.expectedSingleFormatBidders, singleFormatBidders, test.description+":singleFormatBidders")
+
assert.ElementsMatch(t, test.expectedErrors, errs, test.description+":errors")
}
}
@@ -152,7 +179,7 @@ func TestBuildBidders(t *testing.T) {
}
for _, test := range testCases {
- bidders, errs := buildBidders(test.bidderInfos, test.builders, server)
+ bidders, _, errs := buildBidders(test.bidderInfos, test.builders, server)
// For Test Setup Convenience
if test.expectedBidders == nil {
diff --git a/exchange/exchange.go b/exchange/exchange.go
index daddf9debc2..4fd35279f23 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -85,6 +85,7 @@ type exchange struct {
macroReplacer macros.Replacer
priceFloorEnabled bool
priceFloorFetcher floors.FloorFetcher
+ singleFormatBidders map[openrtb_ext.BidderName]struct{}
}
// Container to pass out response ext data from the GetAllBids goroutines back into the main thread
@@ -136,7 +137,7 @@ func (randomDeduplicateBidBooleanGenerator) Generate() bool {
return rand.Intn(100) < 50
}
-func NewExchange(adapters map[openrtb_ext.BidderName]AdaptedBidder, cache prebid_cache_client.Client, cfg *config.Configuration, requestValidator ortb.RequestValidator, syncersByBidder map[string]usersync.Syncer, metricsEngine metrics.MetricsEngine, infos config.BidderInfos, gdprPermsBuilder gdpr.PermissionsBuilder, currencyConverter *currency.RateConverter, categoriesFetcher stored_requests.CategoryFetcher, adsCertSigner adscert.Signer, macroReplacer macros.Replacer, priceFloorFetcher floors.FloorFetcher) Exchange {
+func NewExchange(adapters map[openrtb_ext.BidderName]AdaptedBidder, cache prebid_cache_client.Client, cfg *config.Configuration, requestValidator ortb.RequestValidator, syncersByBidder map[string]usersync.Syncer, metricsEngine metrics.MetricsEngine, infos config.BidderInfos, gdprPermsBuilder gdpr.PermissionsBuilder, currencyConverter *currency.RateConverter, categoriesFetcher stored_requests.CategoryFetcher, adsCertSigner adscert.Signer, macroReplacer macros.Replacer, priceFloorFetcher floors.FloorFetcher, singleFormatBidders map[openrtb_ext.BidderName]struct{}) Exchange {
bidderToSyncerKey := map[string]string{}
for bidder, syncer := range syncersByBidder {
bidderToSyncerKey[bidder] = syncer.Key()
@@ -184,6 +185,7 @@ func NewExchange(adapters map[openrtb_ext.BidderName]AdaptedBidder, cache prebid
macroReplacer: macroReplacer,
priceFloorEnabled: cfg.PriceFloors.Enabled,
priceFloorFetcher: priceFloorFetcher,
+ singleFormatBidders: singleFormatBidders,
}
}
@@ -401,8 +403,11 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog
} else if r.Account.AlternateBidderCodes != nil {
alternateBidderCodes = *r.Account.AlternateBidderCodes
}
+
+ liveAdaptersPreferredMediaType := getBidderPreferredMediaTypeMap(requestExtPrebid, &r.Account, liveAdapters, e.singleFormatBidders)
+
var extraRespInfo extraAuctionResponseInfo
- adapterBids, adapterExtra, extraRespInfo = e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions, accountDebugAllow, r.GlobalPrivacyControlHeader, debugLog.DebugOverride, alternateBidderCodes, requestExtLegacy.Prebid.Experiment, r.HookExecutor, r.StartTime, bidAdjustmentRules, r.TmaxAdjustments, responseDebugAllow)
+ adapterBids, adapterExtra, extraRespInfo = e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions, accountDebugAllow, r.GlobalPrivacyControlHeader, debugLog.DebugOverride, alternateBidderCodes, requestExtLegacy.Prebid.Experiment, r.HookExecutor, r.StartTime, bidAdjustmentRules, r.TmaxAdjustments, responseDebugAllow, liveAdaptersPreferredMediaType)
fledge = extraRespInfo.fledge
anyBidsReturned = extraRespInfo.bidsFound
r.BidderResponseStartTime = extraRespInfo.bidderResponseStartTime
@@ -550,6 +555,41 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog
}, nil
}
+// getBidderPreferredMediaType reads the preferred media type from the request and account and returns a map of bidder to preferred media type. Preference given to the request over account.
+func getBidderPreferredMediaTypeMap(prebid *openrtb_ext.ExtRequestPrebid, account *config.Account, liveAdapters []openrtb_ext.BidderName, singleFormatBidders map[openrtb_ext.BidderName]struct{}) openrtb_ext.PreferredMediaType {
+ preferredMediaType := make(openrtb_ext.PreferredMediaType)
+
+ // Skip if no bidders are present in singleFormatBidders
+ if len(singleFormatBidders) == 0 {
+ return nil
+ }
+
+ for _, bidder := range liveAdapters {
+
+ // Skip if the bidder is not present in singleFormatBidders
+ if _, found := singleFormatBidders[bidder]; !found {
+ continue
+ }
+
+ //read preferred media type from request
+ if prebid != nil && prebid.BidderControls != nil {
+ if bidderControl, found := prebid.BidderControls[bidder]; found && bidderControl.PreferredMediaType != "" {
+ preferredMediaType[bidder] = bidderControl.PreferredMediaType
+ continue
+ }
+ }
+
+ // if preferred media type not present in the request, read from account config
+ if account != nil && account.PreferredMediaType != nil {
+ if preferredType, found := account.PreferredMediaType[bidder]; found {
+ preferredMediaType[bidder] = preferredType
+ }
+ }
+ }
+
+ return preferredMediaType
+}
+
func buildMultiBidMap(prebid *openrtb_ext.ExtRequestPrebid) map[string]openrtb_ext.ExtMultiBid {
if prebid == nil || prebid.MultiBid == nil {
return nil
@@ -713,7 +753,8 @@ func (e *exchange) getAllBids(
pbsRequestStartTime time.Time,
bidAdjustmentRules map[string][]openrtb_ext.Adjustment,
tmaxAdjustments *TmaxAdjustmentsPreprocessed,
- responseDebugAllowed bool) (
+ responseDebugAllowed bool,
+ liveAdaptersPreferredMediaType openrtb_ext.PreferredMediaType) (
map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid,
map[openrtb_ext.BidderName]*seatResponseExtra,
extraAuctionResponseInfo) {
@@ -746,6 +787,12 @@ func (e *exchange) getAllBids(
reqInfo.PbsEntryPoint = bidderRequest.BidderLabels.RType
reqInfo.GlobalPrivacyControlHeader = globalPrivacyControlHeader
+ if len(liveAdaptersPreferredMediaType) > 0 {
+ if mtype, found := liveAdaptersPreferredMediaType[bidder.BidderName]; found {
+ reqInfo.PreferredMediaType = mtype
+ }
+ }
+
bidReqOptions := bidRequestOptions{
accountDebugAllowed: accountDebugAllowed,
headerDebugAllowed: headerDebugAllowed,
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 1370065f1f8..dcd8dcdec7a 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -71,7 +71,7 @@ func TestNewExchange(t *testing.T) {
t.Fatal(err)
}
- adapters, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
+ adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
if adaptersErr != nil {
t.Fatalf("Error intializing adapters: %v", adaptersErr)
}
@@ -84,7 +84,7 @@ func TestNewExchange(t *testing.T) {
},
}.Builder
- e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil).(*exchange)
+ e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange)
for _, bidderName := range knownAdapters {
if _, ok := e.adapterMap[bidderName]; !ok {
if biddersInfo[string(bidderName)].IsEnabled() {
@@ -121,7 +121,7 @@ func TestCharacterEscape(t *testing.T) {
defer server.Close()
- adapters, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
+ adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
if adaptersErr != nil {
t.Fatalf("Error intializing adapters: %v", adaptersErr)
}
@@ -134,7 +134,7 @@ func TestCharacterEscape(t *testing.T) {
},
}.Builder
- e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil).(*exchange)
+ e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange)
// 3) Build all the parameters e.buildBidResponse(ctx.Background(), liveA... ) needs
//liveAdapters []openrtb_ext.BidderName,
@@ -1224,7 +1224,7 @@ func TestGetBidCacheInfoEndToEnd(t *testing.T) {
t.Fatal(err)
}
- adapters, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
+ adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
if adaptersErr != nil {
t.Fatalf("Error intializing adapters: %v", adaptersErr)
}
@@ -1237,7 +1237,7 @@ func TestGetBidCacheInfoEndToEnd(t *testing.T) {
},
}.Builder
- e := NewExchange(adapters, pbc, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil).(*exchange)
+ e := NewExchange(adapters, pbc, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange)
// 3) Build all the parameters e.buildBidResponse(ctx.Background(), liveA... ) needs
liveAdapters := []openrtb_ext.BidderName{bidderName}
@@ -1583,7 +1583,7 @@ func TestBidResponseCurrency(t *testing.T) {
t.Fatal(err)
}
- adapters, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
+ adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
if adaptersErr != nil {
t.Fatalf("Error intializing adapters: %v", adaptersErr)
}
@@ -1596,7 +1596,7 @@ func TestBidResponseCurrency(t *testing.T) {
},
}.Builder
- e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil).(*exchange)
+ e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange)
liveAdapters := make([]openrtb_ext.BidderName, 1)
liveAdapters[0] = "appnexus"
@@ -1739,12 +1739,12 @@ func TestBidResponseImpExtInfo(t *testing.T) {
biddersInfo := config.BidderInfos{"appnexus": config.BidderInfo{Endpoint: "http://ib.adnxs.com"}}
- adapters, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
+ adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
if adaptersErr != nil {
t.Fatalf("Error intializing adapters: %v", adaptersErr)
}
- e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, nil, gdprPermsBuilder, nil, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil).(*exchange)
+ e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, nil, gdprPermsBuilder, nil, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange)
liveAdapters := make([]openrtb_ext.BidderName, 1)
liveAdapters[0] = "appnexus"
@@ -1815,7 +1815,7 @@ func TestRaceIntegration(t *testing.T) {
t.Fatal(err)
}
- adapters, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
+ adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
if adaptersErr != nil {
t.Fatalf("Error intializing adapters: %v", adaptersErr)
}
@@ -1838,7 +1838,7 @@ func TestRaceIntegration(t *testing.T) {
},
}.Builder
- ex := NewExchange(adapters, &wellBehavedCache{}, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, &nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil).(*exchange)
+ ex := NewExchange(adapters, &wellBehavedCache{}, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, &nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange)
_, err = ex.HoldAuction(context.Background(), auctionRequest, &debugLog)
if err != nil {
t.Errorf("HoldAuction returned unexpected error: %v", err)
@@ -1923,7 +1923,7 @@ func TestPanicRecovery(t *testing.T) {
t.Fatal(err)
}
- adapters, adaptersErr := BuildAdapters(&http.Client{}, cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
+ adapters, _, adaptersErr := BuildAdapters(&http.Client{}, cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
if adaptersErr != nil {
t.Fatalf("Error intializing adapters: %v", adaptersErr)
}
@@ -1936,7 +1936,7 @@ func TestPanicRecovery(t *testing.T) {
},
}.Builder
- e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil).(*exchange)
+ e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange)
chBids := make(chan *bidResponseWrapper, 1)
panicker := func(bidderRequest BidderRequest, conversions currency.Conversions) {
@@ -1989,7 +1989,7 @@ func TestPanicRecoveryHighLevel(t *testing.T) {
t.Fatal(err)
}
- adapters, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
+ adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
if adaptersErr != nil {
t.Fatalf("Error intializing adapters: %v", adaptersErr)
}
@@ -2006,7 +2006,7 @@ func TestPanicRecoveryHighLevel(t *testing.T) {
allowAllBidders: true,
},
}.Builder
- e := NewExchange(adapters, &mockCache{}, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, categoriesFetcher, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil).(*exchange)
+ e := NewExchange(adapters, &mockCache{}, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, categoriesFetcher, &adscert.NilSigner{}, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange)
e.adapterMap[openrtb_ext.BidderBeachfront] = panicingAdapter{}
e.adapterMap[openrtb_ext.BidderAppnexus] = panicingAdapter{}
@@ -4571,7 +4571,7 @@ func TestPassExperimentConfigsToHoldAuction(t *testing.T) {
signer := MockSigner{}
- adapters, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
+ adapters, _, adaptersErr := BuildAdapters(server.Client(), cfg, biddersInfo, &metricsConf.NilMetricsEngine{})
if adaptersErr != nil {
t.Fatalf("Error intializing adapters: %v", adaptersErr)
}
@@ -4584,7 +4584,7 @@ func TestPassExperimentConfigsToHoldAuction(t *testing.T) {
},
}.Builder
- e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &signer, macros.NewStringIndexBasedReplacer(), nil).(*exchange)
+ e := NewExchange(adapters, nil, cfg, &mockRequestValidator{}, map[string]usersync.Syncer{}, &metricsConf.NilMetricsEngine{}, biddersInfo, gdprPermsBuilder, currencyConverter, nilCategoryFetcher{}, &signer, macros.NewStringIndexBasedReplacer(), nil, nil).(*exchange)
// Define mock incoming bid requeset
mockBidRequest := &openrtb2.BidRequest{
@@ -5170,19 +5170,20 @@ func TestGetAllBids(t *testing.T) {
defer server.Close()
type testIn struct {
- bidderRequests []BidderRequest
- bidAdjustments map[string]float64
- conversions currency.Conversions
- accountDebugAllowed bool
- globalPrivacyControlHeader string
- headerDebugAllowed bool
- alternateBidderCodes openrtb_ext.ExtAlternateBidderCodes
- experiment *openrtb_ext.Experiment
- hookExecutor hookexecution.StageExecutor
- pbsRequestStartTime time.Time
- bidAdjustmentRules map[string][]openrtb_ext.Adjustment
- tmaxAdjustments *TmaxAdjustmentsPreprocessed
- adapterMap map[openrtb_ext.BidderName]AdaptedBidder
+ bidderRequests []BidderRequest
+ bidAdjustments map[string]float64
+ conversions currency.Conversions
+ accountDebugAllowed bool
+ globalPrivacyControlHeader string
+ headerDebugAllowed bool
+ alternateBidderCodes openrtb_ext.ExtAlternateBidderCodes
+ experiment *openrtb_ext.Experiment
+ hookExecutor hookexecution.StageExecutor
+ pbsRequestStartTime time.Time
+ bidAdjustmentRules map[string][]openrtb_ext.Adjustment
+ tmaxAdjustments *TmaxAdjustmentsPreprocessed
+ adapterMap map[openrtb_ext.BidderName]AdaptedBidder
+ liveAdaptersPreferredMediaType map[openrtb_ext.BidderName]openrtb_ext.BidType
}
type testResults struct {
adapterBids map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid
@@ -5475,7 +5476,7 @@ func TestGetAllBids(t *testing.T) {
adapterBids, adapterExtra, extraRespInfo := e.getAllBids(context.Background(), test.in.bidderRequests, test.in.bidAdjustments,
test.in.conversions, test.in.accountDebugAllowed, test.in.globalPrivacyControlHeader, test.in.headerDebugAllowed, test.in.alternateBidderCodes, test.in.experiment,
- test.in.hookExecutor, test.in.pbsRequestStartTime, test.in.bidAdjustmentRules, test.in.tmaxAdjustments, false)
+ test.in.hookExecutor, test.in.pbsRequestStartTime, test.in.bidAdjustmentRules, test.in.tmaxAdjustments, false, test.in.liveAdaptersPreferredMediaType)
assert.Equalf(t, test.expected.extraRespInfo.bidsFound, extraRespInfo.bidsFound, "extraRespInfo.bidsFound mismatch")
assert.Equalf(t, test.expected.adapterBids, adapterBids, "adapterBids mismatch")
@@ -6355,6 +6356,163 @@ func TestBidsToUpdate(t *testing.T) {
}
}
+func TestGetBidderPreferredMediaType(t *testing.T) {
+ tests := []struct {
+ name string
+ prebid *openrtb_ext.ExtRequestPrebid
+ account *config.Account
+ liveAdapters []openrtb_ext.BidderName
+ singleFormatBidders map[openrtb_ext.BidderName]struct{}
+ expected openrtb_ext.PreferredMediaType
+ }{
+ {
+ name: "Nil account and request preferred media type",
+ prebid: nil,
+ account: &config.Account{},
+ liveAdapters: []openrtb_ext.BidderName{"bidderA"},
+ singleFormatBidders: map[openrtb_ext.BidderName]struct{}{
+ "bidderA": {},
+ },
+ expected: openrtb_ext.PreferredMediaType{},
+ },
+ {
+ name: "Account preferred media type only",
+ prebid: nil,
+ account: &config.Account{
+ PreferredMediaType: map[openrtb_ext.BidderName]openrtb_ext.BidType{
+ "bidderA": openrtb_ext.BidTypeBanner,
+ },
+ },
+ liveAdapters: []openrtb_ext.BidderName{"bidderA"},
+ singleFormatBidders: map[openrtb_ext.BidderName]struct{}{
+ "bidderA": {},
+ },
+ expected: openrtb_ext.PreferredMediaType{
+ "bidderA": openrtb_ext.BidTypeBanner,
+ },
+ },
+ {
+ name: "Request preferred media type only",
+ prebid: &openrtb_ext.ExtRequestPrebid{
+ BidderControls: map[openrtb_ext.BidderName]openrtb_ext.BidderControl{
+ "bidderB": {PreferredMediaType: openrtb_ext.BidTypeVideo},
+ },
+ },
+ account: &config.Account{},
+ liveAdapters: []openrtb_ext.BidderName{"bidderB"},
+ singleFormatBidders: map[openrtb_ext.BidderName]struct{}{
+ "bidderB": {},
+ },
+ expected: openrtb_ext.PreferredMediaType{
+ "bidderB": openrtb_ext.BidTypeVideo,
+ },
+ },
+ {
+ name: "Account and request preferred media type",
+ prebid: &openrtb_ext.ExtRequestPrebid{
+ BidderControls: map[openrtb_ext.BidderName]openrtb_ext.BidderControl{
+ "bidderB": {PreferredMediaType: openrtb_ext.BidTypeVideo},
+ },
+ },
+ account: &config.Account{
+ PreferredMediaType: map[openrtb_ext.BidderName]openrtb_ext.BidType{
+ "bidderA": openrtb_ext.BidTypeBanner,
+ },
+ },
+ liveAdapters: []openrtb_ext.BidderName{"bidderA", "bidderB", "bidderC"},
+ singleFormatBidders: map[openrtb_ext.BidderName]struct{}{
+ "bidderA": {},
+ "bidderB": {},
+ },
+ expected: openrtb_ext.PreferredMediaType{
+ "bidderA": openrtb_ext.BidTypeBanner,
+ "bidderB": openrtb_ext.BidTypeVideo,
+ },
+ },
+ {
+ name: "Request overrides account preferred media type",
+ prebid: &openrtb_ext.ExtRequestPrebid{
+ BidderControls: map[openrtb_ext.BidderName]openrtb_ext.BidderControl{
+ "bidderA": {PreferredMediaType: openrtb_ext.BidTypeVideo},
+ },
+ },
+ account: &config.Account{
+ PreferredMediaType: map[openrtb_ext.BidderName]openrtb_ext.BidType{
+ "bidderA": openrtb_ext.BidTypeBanner,
+ },
+ },
+ liveAdapters: []openrtb_ext.BidderName{"bidderA"},
+ singleFormatBidders: map[openrtb_ext.BidderName]struct{}{
+ "bidderA": {},
+ },
+ expected: openrtb_ext.PreferredMediaType{
+ "bidderA": openrtb_ext.BidTypeVideo,
+ },
+ },
+ {
+ name: "Bidder not in singleFormatBidders",
+ prebid: &openrtb_ext.ExtRequestPrebid{
+ BidderControls: map[openrtb_ext.BidderName]openrtb_ext.BidderControl{
+ "bidderA": {PreferredMediaType: openrtb_ext.BidTypeVideo},
+ },
+ },
+ account: &config.Account{
+ PreferredMediaType: map[openrtb_ext.BidderName]openrtb_ext.BidType{
+ "bidderA": openrtb_ext.BidTypeBanner,
+ },
+ },
+ liveAdapters: []openrtb_ext.BidderName{"bidderA"},
+ singleFormatBidders: map[openrtb_ext.BidderName]struct{}{
+ "bidderB": {},
+ },
+ expected: openrtb_ext.PreferredMediaType{},
+ },
+ {
+ name: "No bidders in singleFormatBidders",
+ prebid: &openrtb_ext.ExtRequestPrebid{
+ BidderControls: map[openrtb_ext.BidderName]openrtb_ext.BidderControl{
+ "bidderA": {PreferredMediaType: openrtb_ext.BidTypeVideo},
+ },
+ },
+ account: &config.Account{
+ PreferredMediaType: map[openrtb_ext.BidderName]openrtb_ext.BidType{
+ "bidderA": openrtb_ext.BidTypeBanner,
+ },
+ },
+ liveAdapters: []openrtb_ext.BidderName{"bidderA"},
+ singleFormatBidders: make(map[openrtb_ext.BidderName]struct{}),
+ expected: nil,
+ },
+ {
+ name: "Different bidders in singleFormatBidders than liveAdapters",
+ prebid: &openrtb_ext.ExtRequestPrebid{
+ BidderControls: map[openrtb_ext.BidderName]openrtb_ext.BidderControl{
+ "bidderA": {PreferredMediaType: openrtb_ext.BidTypeVideo},
+ },
+ },
+ account: &config.Account{
+ PreferredMediaType: map[openrtb_ext.BidderName]openrtb_ext.BidType{
+ "bidderC": openrtb_ext.BidTypeBanner,
+ "bidderD": openrtb_ext.BidTypeVideo,
+ },
+ },
+ liveAdapters: []openrtb_ext.BidderName{"bidderA", "bidderB"},
+ singleFormatBidders: map[openrtb_ext.BidderName]struct{}{
+ "bidderC": {},
+ "bidderD": {},
+ },
+ expected: openrtb_ext.PreferredMediaType{},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := getBidderPreferredMediaTypeMap(tt.prebid, tt.account, tt.liveAdapters, tt.singleFormatBidders)
+ assert.Equal(t, tt.expected, result)
+ })
+ }
+}
+
func TestIsEEACountry(t *testing.T) {
eeaCountries := []string{"FRA", "DEU", "ITA", "ESP", "NLD"}
diff --git a/openrtb_ext/preferredmediatype.go b/openrtb_ext/preferredmediatype.go
new file mode 100644
index 00000000000..5fdfb740a06
--- /dev/null
+++ b/openrtb_ext/preferredmediatype.go
@@ -0,0 +1,3 @@
+package openrtb_ext
+
+type PreferredMediaType map[BidderName]BidType
diff --git a/openrtb_ext/request.go b/openrtb_ext/request.go
index 46cdb1a674a..a05133fc377 100644
--- a/openrtb_ext/request.go
+++ b/openrtb_ext/request.go
@@ -91,6 +91,8 @@ type ExtRequestPrebid struct {
// - basic: excludes debugmessages and analytic_tags from output
// any other value or an empty string disables trace output at all.
Trace string `json:"trace,omitempty"`
+
+ BidderControls map[BidderName]BidderControl `json:"biddercontrols,omitempty"`
}
type AdServerTarget struct {
@@ -367,6 +369,10 @@ type ExtMultiBid struct {
TargetBidderCodePrefix string `json:"targetbiddercodeprefix,omitempty"`
}
+type BidderControl struct {
+ PreferredMediaType BidType `json:"prefmtype"`
+}
+
func (m ExtMultiBid) String() string {
maxBid := ""
if m.MaxBids != nil {
diff --git a/router/router.go b/router/router.go
index d412b5152e2..9e3d9fd4831 100644
--- a/router/router.go
+++ b/router/router.go
@@ -217,7 +217,7 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R
cacheClient := pbc.NewClient(cacheHttpClient, &cfg.CacheURL, &cfg.ExtCacheURL, r.MetricsEngine)
- adapters, adaptersErrs := exchange.BuildAdapters(generalHttpClient, cfg, cfg.BidderInfos, r.MetricsEngine)
+ adapters, singleFormatAdapters, adaptersErrs := exchange.BuildAdapters(generalHttpClient, cfg, cfg.BidderInfos, r.MetricsEngine)
if len(adaptersErrs) > 0 {
errs := errortypes.NewAggregateError("Failed to initialize adapters", adaptersErrs)
return nil, errs
@@ -233,7 +233,7 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R
tmaxAdjustments := exchange.ProcessTMaxAdjustments(cfg.TmaxAdjustments)
planBuilder := hooks.NewExecutionPlanBuilder(cfg.Hooks, repo)
macroReplacer := macros.NewStringIndexBasedReplacer()
- theExchange := exchange.NewExchange(adapters, cacheClient, cfg, requestValidator, syncersByBidder, r.MetricsEngine, cfg.BidderInfos, gdprPermsBuilder, rateConvertor, categoriesFetcher, adsCertSigner, macroReplacer, priceFloorFetcher)
+ theExchange := exchange.NewExchange(adapters, cacheClient, cfg, requestValidator, syncersByBidder, r.MetricsEngine, cfg.BidderInfos, gdprPermsBuilder, rateConvertor, categoriesFetcher, adsCertSigner, macroReplacer, priceFloorFetcher, singleFormatAdapters)
var uuidGenerator uuidutil.UUIDRandomGenerator
openrtbEndpoint, err := openrtb2.NewEndpoint(uuidGenerator, theExchange, requestValidator, fetcher, accounts, cfg, r.MetricsEngine, analyticsRunner, disabledBidders, defReqJSON, activeBidders, storedRespFetcher, planBuilder, tmaxAdjustments)
if err != nil {
From b8fb75da104ca78c198eeb8b4fced65406bea4d6 Mon Sep 17 00:00:00 2001
From: Abdullah Al Mamun Oronno
Date: Thu, 3 Apr 2025 10:36:27 -0400
Subject: [PATCH 25/40] IX: Pass ext.ixdiag fields through (#4262)
Co-authored-by: Oronno Mamun
---
adapters/ix/ix.go | 66 ++---
adapters/ix/ix_test.go | 29 ++-
.../ixtest/exemplary/additional-consent.json | 6 +
adapters/ix/ixtest/exemplary/app-site-id.json | 4 +-
.../ix/ixtest/exemplary/banner-no-format.json | 8 +-
adapters/ix/ixtest/exemplary/fledge.json | 6 +
adapters/ix/ixtest/exemplary/ixdiag.json | 239 ++++++++++++++++++
.../multi-format-with-ext-prebid-type.json | 8 +-
.../exemplary/multi-format-with-mtype.json | 8 +-
.../multi-imp-multi-size-requests.json | 6 +
.../ixtest/exemplary/multi-imp-requests.json | 8 +-
adapters/ix/ixtest/exemplary/multibid.json | 8 +-
.../ix/ixtest/exemplary/multiple-siteIds.json | 6 +-
.../native-eventtrackers-compat-12.json | 8 +-
adapters/ix/ixtest/exemplary/no-pub-id.json | 6 +
adapters/ix/ixtest/exemplary/no-pub.json | 6 +
.../ix/ixtest/exemplary/simple-audio.json | 8 +-
.../exemplary/simple-banner-multi-size.json | 6 +
.../ix/ixtest/exemplary/simple-native.json | 8 +-
.../ix/ixtest/exemplary/simple-video.json | 8 +-
.../ix/ixtest/exemplary/structured-pod.json | 8 +-
.../supplemental/app-site-id-publisher.json | 4 +-
.../ix/ixtest/supplemental/bad-fledge.json | 6 +
.../ix/ixtest/supplemental/bad-imp-id.json | 8 +-
.../ix/ixtest/supplemental/bad-request.json | 8 +-
.../supplemental/bad-response-body.json | 8 +-
.../ix/ixtest/supplemental/dsa-request.json | 8 +-
.../ix/ixtest/supplemental/fledge-no-bid.json | 6 +
.../multi-imp-requests-error.json | 8 +-
.../native-eventtrackers-empty.json | 8 +-
.../native-eventtrackers-missing.json | 8 +-
.../ixtest/supplemental/native-missing.json | 8 +-
.../ix/ixtest/supplemental/no-content.json | 8 +-
.../ix/ixtest/supplemental/not-found.json | 8 +-
adapters/ix/ixtest/supplemental/sid.json | 7 +-
35 files changed, 499 insertions(+), 64 deletions(-)
create mode 100644 adapters/ix/ixtest/exemplary/ixdiag.json
diff --git a/adapters/ix/ix.go b/adapters/ix/ix.go
index 48becbdcf4c..b24d99eff3b 100644
--- a/adapters/ix/ix.go
+++ b/adapters/ix/ix.go
@@ -25,15 +25,9 @@ type IxAdapter struct {
}
type ExtRequest struct {
- Prebid *openrtb_ext.ExtRequestPrebid `json:"prebid"`
+ Prebid *openrtb_ext.ExtRequestPrebid `json:"prebid,omitempty"`
SChain *openrtb2.SupplyChain `json:"schain,omitempty"`
- IxDiag *IxDiag `json:"ixdiag,omitempty"`
-}
-
-type IxDiag struct {
- PbsV string `json:"pbsv,omitempty"`
- PbjsV string `json:"pbjsv,omitempty"`
- MultipleSiteIds string `json:"multipleSiteIds,omitempty"`
+ IxDiag json.RawMessage `json:"ixdiag,omitempty"`
}
type auctionConfig struct {
@@ -57,7 +51,7 @@ func (a *IxAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters
filteredImps := make([]openrtb2.Imp, 0, len(request.Imp))
requestCopy := *request
- ixDiag := &IxDiag{}
+ ixDiagFields := make(map[string]interface{})
for _, imp := range requestCopy.Imp {
var err error
@@ -94,9 +88,9 @@ func (a *IxAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters
}
requestCopy.Imp = filteredImps
- setPublisherId(&requestCopy, uniqueSiteIDs, ixDiag)
+ setPublisherId(&requestCopy, uniqueSiteIDs, ixDiagFields)
- err := setIxDiagIntoExtRequest(&requestCopy, ixDiag, version.Ver)
+ err := setIxDiagIntoExtRequest(&requestCopy, ixDiagFields, version.Ver)
if err != nil {
errs = append(errs, err)
}
@@ -112,7 +106,7 @@ func (a *IxAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters
return requests, errs
}
-func setPublisherId(requestCopy *openrtb2.BidRequest, uniqueSiteIDs map[string]struct{}, ixDiag *IxDiag) {
+func setPublisherId(requestCopy *openrtb2.BidRequest, uniqueSiteIDs map[string]struct{}, ixDiagFields map[string]interface{}) {
siteIDs := make([]string, 0, len(uniqueSiteIDs))
for key := range uniqueSiteIDs {
siteIDs = append(siteIDs, key)
@@ -150,7 +144,7 @@ func setPublisherId(requestCopy *openrtb2.BidRequest, uniqueSiteIDs map[string]s
// Sorting siteIDs for predictable output as Go maps don't guarantee order
sort.Strings(siteIDs)
multipleSiteIDs := strings.Join(siteIDs, ", ")
- ixDiag.MultipleSiteIds = multipleSiteIDs
+ ixDiagFields["multipleSiteIds"] = multipleSiteIDs
}
}
@@ -403,8 +397,8 @@ func extractVersionWithoutCommitHash(ver string) string {
return ver // if no hyphen, return the original string
}
-func setIxDiagIntoExtRequest(request *openrtb2.BidRequest, ixDiag *IxDiag, ver string) error {
- extRequest := &ExtRequest{}
+func setIxDiagIntoExtRequest(request *openrtb2.BidRequest, ixDiagAdditionalFields map[string]interface{}, ver string) error {
+ var extRequest ExtRequest
if request.Ext != nil {
if err := jsonutil.Unmarshal(request.Ext, &extRequest); err != nil {
return err
@@ -412,28 +406,42 @@ func setIxDiagIntoExtRequest(request *openrtb2.BidRequest, ixDiag *IxDiag, ver s
}
if extRequest.Prebid != nil && extRequest.Prebid.Channel != nil {
- ixDiag.PbjsV = extRequest.Prebid.Channel.Version
+ ixDiagAdditionalFields["pbjsv"] = extRequest.Prebid.Channel.Version
}
// Slice commit hash out of version
+ prebidServerVersion := "unknown" // Default value when the version cannot be determined
if ver != "" {
- ixDiag.PbsV = extractVersionWithoutCommitHash(ver)
+ prebidServerVersion = extractVersionWithoutCommitHash(ver)
}
+ ixDiagAdditionalFields["pbsv"] = prebidServerVersion
+ ixDiagAdditionalFields["pbsp"] = "go" // indicate prebid server implementation use Go version
- // Only set request.ext if ixDiag is not empty
- if *ixDiag != (IxDiag{}) {
- extRequest := &ExtRequest{}
- if request.Ext != nil {
- if err := jsonutil.Unmarshal(request.Ext, &extRequest); err != nil {
- return err
- }
- }
- extRequest.IxDiag = ixDiag
- extRequestJson, err := json.Marshal(extRequest)
- if err != nil {
+ var ixDiagMap map[string]interface{}
+ if extRequest.IxDiag != nil && len(extRequest.IxDiag) > 0 {
+ if err := jsonutil.Unmarshal(extRequest.IxDiag, &ixDiagMap); err != nil {
return err
}
- request.Ext = extRequestJson
+ } else {
+ ixDiagMap = make(map[string]interface{})
+ }
+
+ for k, v := range ixDiagAdditionalFields {
+ ixDiagMap[k] = v
}
+
+ ixDiagJSON, err := json.Marshal(ixDiagMap)
+ if err != nil {
+ return err
+ }
+
+ extRequest.IxDiag = ixDiagJSON
+
+ extRequestJSON, err := json.Marshal(extRequest)
+ if err != nil {
+ return err
+ }
+
+ request.Ext = extRequestJSON
return nil
}
diff --git a/adapters/ix/ix_test.go b/adapters/ix/ix_test.go
index 48b9796bbb5..d46b69adffc 100644
--- a/adapters/ix/ix_test.go
+++ b/adapters/ix/ix_test.go
@@ -195,7 +195,7 @@ func TestBuildIxDiag(t *testing.T) {
},
expectedRequest: &openrtb2.BidRequest{
ID: "1",
- Ext: json.RawMessage(`{"prebid":{"channel":{"name":"web","version":"7.20"}},"ixdiag":{"pbsv":"1.880","pbjsv":"7.20"}}`),
+ Ext: json.RawMessage(`{"prebid":{"channel":{"name":"web","version":"7.20"}},"ixdiag":{"pbjsv":"7.20","pbsp":"go","pbsv":"1.880"}}`),
},
expectError: false,
pbsVersion: "1.880-abcdef",
@@ -208,7 +208,7 @@ func TestBuildIxDiag(t *testing.T) {
},
expectedRequest: &openrtb2.BidRequest{
ID: "1",
- Ext: json.RawMessage(`{"prebid":{"server":{"externalurl":"http://localhost:8000","gvlid":0,"datacenter":""}},"ixdiag":{"pbsv":"1.880"}}`),
+ Ext: json.RawMessage(`{"prebid":{"server":{"externalurl":"http://localhost:8000","gvlid":0,"datacenter":""}},"ixdiag":{"pbsp":"go","pbsv":"1.880"}}`),
},
expectError: false,
pbsVersion: "1.880-abcdef",
@@ -220,7 +220,7 @@ func TestBuildIxDiag(t *testing.T) {
},
expectedRequest: &openrtb2.BidRequest{
ID: "1",
- Ext: json.RawMessage(`{"prebid":null,"ixdiag":{"pbsv":"1.880"}}`),
+ Ext: json.RawMessage(`{"ixdiag":{"pbsp":"go","pbsv":"1.880"}}`),
},
expectError: false,
pbsVersion: "1.880-abcdef",
@@ -232,7 +232,7 @@ func TestBuildIxDiag(t *testing.T) {
},
expectedRequest: &openrtb2.BidRequest{
ID: "1",
- Ext: json.RawMessage(`{"prebid":null,"ixdiag":{"pbsv":"0.23.1"}}`),
+ Ext: json.RawMessage(`{"ixdiag":{"pbsp":"go","pbsv":"0.23.1"}}`),
},
expectError: false,
pbsVersion: "0.23.1-3-g4ee257d8",
@@ -245,7 +245,7 @@ func TestBuildIxDiag(t *testing.T) {
},
expectedRequest: &openrtb2.BidRequest{
ID: "1",
- Ext: json.RawMessage(`{"prebid":{"channel":{"name":"web","version":"7.20"}},"ixdiag":{"pbsv":"1.880","pbjsv":"7.20"}}`),
+ Ext: json.RawMessage(`{"prebid":{"channel":{"name":"web","version":"7.20"}},"ixdiag":{"pbjsv":"7.20","pbsp":"go","pbsv":"1.880"}}`),
},
expectError: false,
pbsVersion: "1.880",
@@ -258,7 +258,20 @@ func TestBuildIxDiag(t *testing.T) {
},
expectedRequest: &openrtb2.BidRequest{
ID: "1",
- Ext: json.RawMessage(`{"prebid":{"channel":{"name":"web","version":"7.20"}},"ixdiag":{"pbjsv":"7.20"}}`),
+ Ext: json.RawMessage(`{"prebid":{"channel":{"name":"web","version":"7.20"}},"ixdiag":{"pbjsv":"7.20","pbsp":"go","pbsv":"unknown"}}`),
+ },
+ expectError: false,
+ pbsVersion: "",
+ },
+ {
+ description: "request ixdiag contain other fields that should pass-through along with additional version fields",
+ request: &openrtb2.BidRequest{
+ ID: "1",
+ Ext: json.RawMessage(`{"prebid":{"channel":{"name":"web","version":"7.20"}},"ixdiag":{"msd":2,"msi":1,"nvin":"123"}}`),
+ },
+ expectedRequest: &openrtb2.BidRequest{
+ ID: "1",
+ Ext: json.RawMessage(`{"prebid":{"channel":{"name":"web","version":"7.20"}},"ixdiag":{"msd":2,"msi":1,"nvin":"123","pbjsv":"7.20","pbsp":"go","pbsv":"unknown"}}`),
},
expectError: false,
pbsVersion: "",
@@ -280,8 +293,8 @@ func TestBuildIxDiag(t *testing.T) {
for _, test := range testCases {
t.Run(test.description, func(t *testing.T) {
- ixDiag := &IxDiag{}
- err := setIxDiagIntoExtRequest(test.request, ixDiag, test.pbsVersion)
+ ixDiagFields := make(map[string]interface{})
+ err := setIxDiagIntoExtRequest(test.request, ixDiagFields, test.pbsVersion)
if test.expectError {
assert.NotNil(t, err)
} else {
diff --git a/adapters/ix/ixtest/exemplary/additional-consent.json b/adapters/ix/ixtest/exemplary/additional-consent.json
index dcd388dd505..b3fb8f4e842 100644
--- a/adapters/ix/ixtest/exemplary/additional-consent.json
+++ b/adapters/ix/ixtest/exemplary/additional-consent.json
@@ -57,6 +57,12 @@
"consented_providers": [1]
}
}
+ },
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
}
},
"impIDs":["test-imp-id"]
diff --git a/adapters/ix/ixtest/exemplary/app-site-id.json b/adapters/ix/ixtest/exemplary/app-site-id.json
index 4ba3ed52da9..c4ecc31d075 100644
--- a/adapters/ix/ixtest/exemplary/app-site-id.json
+++ b/adapters/ix/ixtest/exemplary/app-site-id.json
@@ -65,7 +65,9 @@
},
"ext": {
"ixdiag": {
- "pbjsv": "7.0.0"
+ "pbjsv": "7.0.0",
+ "pbsp": "go",
+ "pbsv": "unknown"
},
"prebid": {
"channel": {
diff --git a/adapters/ix/ixtest/exemplary/banner-no-format.json b/adapters/ix/ixtest/exemplary/banner-no-format.json
index 8024a98eb58..cd7db2b6007 100644
--- a/adapters/ix/ixtest/exemplary/banner-no-format.json
+++ b/adapters/ix/ixtest/exemplary/banner-no-format.json
@@ -41,7 +41,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/exemplary/fledge.json b/adapters/ix/ixtest/exemplary/fledge.json
index 876b9785684..34bdf8c5f0b 100644
--- a/adapters/ix/ixtest/exemplary/fledge.json
+++ b/adapters/ix/ixtest/exemplary/fledge.json
@@ -70,6 +70,12 @@
"publisher": {
"id": "569749"
}
+ },
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
}
},
"impIDs":["test-imp-id"]
diff --git a/adapters/ix/ixtest/exemplary/ixdiag.json b/adapters/ix/ixtest/exemplary/ixdiag.json
new file mode 100644
index 00000000000..482a7666624
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/ixdiag.json
@@ -0,0 +1,239 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id-1",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "siteId": "569749"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-2",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "minduration": 15,
+ "maxduration": 30,
+ "protocols": [
+ 2,
+ 3,
+ 5,
+ 6,
+ 7,
+ 8
+ ],
+ "w": 940,
+ "h": 560
+ },
+ "ext": {
+ "bidder": {
+ "siteId": "569750"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-3",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "siteId": "569751"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "https://www.example.com/"
+ },
+ "ext": {
+ "prebid": {
+ "channel": {
+ "name": "web",
+ "version": "7.0.0"
+ }
+ },
+ "ixdiag": {
+ "msd": 2,
+ "msi": 2,
+ "mfu": 0,
+ "ren": false,
+ "version": "6.29.1"
+ }
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://host/endpoint",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id-1",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "siteId": "569749"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-2",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "minduration": 15,
+ "maxduration": 30,
+ "protocols": [
+ 2,
+ 3,
+ 5,
+ 6,
+ 7,
+ 8
+ ],
+ "w": 940,
+ "h": 560
+ },
+ "ext": {
+ "bidder": {
+ "siteId": "569750"
+ }
+ }
+ },
+ {
+ "banner": {
+ "format": [
+ {
+ "h": 600,
+ "w": 300
+ }
+ ],
+ "h": 600,
+ "w": 300
+ },
+ "ext": {
+ "bidder": {
+ "siteId": "569751"
+ }
+ },
+ "id": "test-imp-id-3"
+ }
+ ],
+ "site": {
+ "page": "https://www.example.com/",
+ "publisher": {
+ }
+ },
+ "ext": {
+ "ixdiag": {
+ "mfu": 0,
+ "msd": 2,
+ "msi": 2,
+ "multipleSiteIds": "569749, 569750, 569751",
+ "pbjsv": "7.0.0",
+ "pbsp": "go",
+ "pbsv": "unknown",
+ "ren": false,
+ "version": "6.29.1"
+ },
+ "prebid": {
+ "channel": {
+ "name": "web",
+ "version": "7.0.0"
+ }
+ }
+ }
+ },
+ "impIDs":["test-imp-id-1","test-imp-id-2","test-imp-id-3"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "seat": "958",
+ "bid": [
+ {
+ "id": "7706636740145184841",
+ "impid": "test-imp-id-1",
+ "price": 0.5,
+ "adid": "29681110",
+ "adm": "some-test-ad",
+ "adomain": [
+ "https://advertiser.example.com"
+ ],
+ "cid": "958",
+ "crid": "29681110",
+ "h": 250,
+ "w": 300,
+ "ext": {
+ "ix": {}
+ }
+ }
+ ]
+ }
+ ],
+ "bidid": "5778926625248726496",
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "7706636740145184841",
+ "impid": "test-imp-id-1",
+ "price": 0.5,
+ "adm": "some-test-ad",
+ "adid": "29681110",
+ "adomain": [
+ "https://advertiser.example.com"
+ ],
+ "cid": "958",
+ "crid": "29681110",
+ "w": 300,
+ "h": 250,
+ "ext": {
+ "ix": {}
+ }
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/ix/ixtest/exemplary/multi-format-with-ext-prebid-type.json b/adapters/ix/ixtest/exemplary/multi-format-with-ext-prebid-type.json
index 25986a1b864..5f624ac735b 100644
--- a/adapters/ix/ixtest/exemplary/multi-format-with-ext-prebid-type.json
+++ b/adapters/ix/ixtest/exemplary/multi-format-with-ext-prebid-type.json
@@ -75,7 +75,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["multi-format-test-imp-id"]
},
diff --git a/adapters/ix/ixtest/exemplary/multi-format-with-mtype.json b/adapters/ix/ixtest/exemplary/multi-format-with-mtype.json
index ee571c96af0..9cd869261ef 100644
--- a/adapters/ix/ixtest/exemplary/multi-format-with-mtype.json
+++ b/adapters/ix/ixtest/exemplary/multi-format-with-mtype.json
@@ -75,7 +75,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["multi-format-test-imp-id"]
},
diff --git a/adapters/ix/ixtest/exemplary/multi-imp-multi-size-requests.json b/adapters/ix/ixtest/exemplary/multi-imp-multi-size-requests.json
index ca122dee6bd..adbdfee8fb6 100644
--- a/adapters/ix/ixtest/exemplary/multi-imp-multi-size-requests.json
+++ b/adapters/ix/ixtest/exemplary/multi-imp-multi-size-requests.json
@@ -144,6 +144,12 @@
"publisher": {
"id": "569749"
}
+ },
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
}
},
"impIDs":["test-imp-id-1","test-imp-id-2","test-imp-id-3"]
diff --git a/adapters/ix/ixtest/exemplary/multi-imp-requests.json b/adapters/ix/ixtest/exemplary/multi-imp-requests.json
index 1ab57a89c3f..44629a3c03b 100644
--- a/adapters/ix/ixtest/exemplary/multi-imp-requests.json
+++ b/adapters/ix/ixtest/exemplary/multi-imp-requests.json
@@ -197,7 +197,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id-1","test-imp-id-2","test-imp-id-3","test-imp-id-4","test-imp-id-5"]
},
diff --git a/adapters/ix/ixtest/exemplary/multibid.json b/adapters/ix/ixtest/exemplary/multibid.json
index 5ac68675d28..0232c69a7d5 100644
--- a/adapters/ix/ixtest/exemplary/multibid.json
+++ b/adapters/ix/ixtest/exemplary/multibid.json
@@ -41,7 +41,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/exemplary/multiple-siteIds.json b/adapters/ix/ixtest/exemplary/multiple-siteIds.json
index 93778438945..92b593dd6a3 100644
--- a/adapters/ix/ixtest/exemplary/multiple-siteIds.json
+++ b/adapters/ix/ixtest/exemplary/multiple-siteIds.json
@@ -148,8 +148,10 @@
},
"ext": {
"ixdiag": {
- "multipleSiteIds": "569749, 569750, 569751",
- "pbjsv": "7.0.0"
+ "multipleSiteIds": "569749, 569750, 569751",
+ "pbjsv": "7.0.0",
+ "pbsp": "go",
+ "pbsv": "unknown"
},
"prebid": {
"channel": {
diff --git a/adapters/ix/ixtest/exemplary/native-eventtrackers-compat-12.json b/adapters/ix/ixtest/exemplary/native-eventtrackers-compat-12.json
index 8d7dcc4c55a..bf8e2809d1a 100644
--- a/adapters/ix/ixtest/exemplary/native-eventtrackers-compat-12.json
+++ b/adapters/ix/ixtest/exemplary/native-eventtrackers-compat-12.json
@@ -35,7 +35,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/exemplary/no-pub-id.json b/adapters/ix/ixtest/exemplary/no-pub-id.json
index 0f280633ad6..579eb20046e 100644
--- a/adapters/ix/ixtest/exemplary/no-pub-id.json
+++ b/adapters/ix/ixtest/exemplary/no-pub-id.json
@@ -54,6 +54,12 @@
"id": "569749",
"name": "publisher-name"
}
+ },
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
}
},
"impIDs":["test-imp-id"]
diff --git a/adapters/ix/ixtest/exemplary/no-pub.json b/adapters/ix/ixtest/exemplary/no-pub.json
index 60db036bc8b..30330264497 100644
--- a/adapters/ix/ixtest/exemplary/no-pub.json
+++ b/adapters/ix/ixtest/exemplary/no-pub.json
@@ -50,6 +50,12 @@
"publisher": {
"id": "569749"
}
+ },
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
}
},
"impIDs":["test-imp-id"]
diff --git a/adapters/ix/ixtest/exemplary/simple-audio.json b/adapters/ix/ixtest/exemplary/simple-audio.json
index 38131a2bb0e..7920474f7f4 100644
--- a/adapters/ix/ixtest/exemplary/simple-audio.json
+++ b/adapters/ix/ixtest/exemplary/simple-audio.json
@@ -45,7 +45,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/exemplary/simple-banner-multi-size.json b/adapters/ix/ixtest/exemplary/simple-banner-multi-size.json
index 3fef8bf4dad..9544e56ca57 100644
--- a/adapters/ix/ixtest/exemplary/simple-banner-multi-size.json
+++ b/adapters/ix/ixtest/exemplary/simple-banner-multi-size.json
@@ -68,6 +68,12 @@
"publisher": {
"id": "569749"
}
+ },
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
}
},
"impIDs":["test-imp-id"]
diff --git a/adapters/ix/ixtest/exemplary/simple-native.json b/adapters/ix/ixtest/exemplary/simple-native.json
index 7d6e378a01d..e3ceb2c55e9 100644
--- a/adapters/ix/ixtest/exemplary/simple-native.json
+++ b/adapters/ix/ixtest/exemplary/simple-native.json
@@ -35,7 +35,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/exemplary/simple-video.json b/adapters/ix/ixtest/exemplary/simple-video.json
index 5a0a3de5950..214e89e7b92 100644
--- a/adapters/ix/ixtest/exemplary/simple-video.json
+++ b/adapters/ix/ixtest/exemplary/simple-video.json
@@ -61,7 +61,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/exemplary/structured-pod.json b/adapters/ix/ixtest/exemplary/structured-pod.json
index 0cc9eafc6f0..1f18efa2dc0 100644
--- a/adapters/ix/ixtest/exemplary/structured-pod.json
+++ b/adapters/ix/ixtest/exemplary/structured-pod.json
@@ -123,7 +123,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id-1","test-imp-id-2"]
},
diff --git a/adapters/ix/ixtest/supplemental/app-site-id-publisher.json b/adapters/ix/ixtest/supplemental/app-site-id-publisher.json
index a5837396f54..935813ab44a 100644
--- a/adapters/ix/ixtest/supplemental/app-site-id-publisher.json
+++ b/adapters/ix/ixtest/supplemental/app-site-id-publisher.json
@@ -69,7 +69,9 @@
},
"ext": {
"ixdiag": {
- "pbjsv": "7.0.0"
+ "pbjsv": "7.0.0",
+ "pbsp": "go",
+ "pbsv": "unknown"
},
"prebid": {
"channel": {
diff --git a/adapters/ix/ixtest/supplemental/bad-fledge.json b/adapters/ix/ixtest/supplemental/bad-fledge.json
index d835d40a33f..a2b52a49625 100644
--- a/adapters/ix/ixtest/supplemental/bad-fledge.json
+++ b/adapters/ix/ixtest/supplemental/bad-fledge.json
@@ -70,6 +70,12 @@
"publisher": {
"id": "569749"
}
+ },
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
}
},
"impIDs":["test-imp-id"]
diff --git a/adapters/ix/ixtest/supplemental/bad-imp-id.json b/adapters/ix/ixtest/supplemental/bad-imp-id.json
index 8812625a98b..f110f9d0ab9 100644
--- a/adapters/ix/ixtest/supplemental/bad-imp-id.json
+++ b/adapters/ix/ixtest/supplemental/bad-imp-id.json
@@ -45,7 +45,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/supplemental/bad-request.json b/adapters/ix/ixtest/supplemental/bad-request.json
index 83df3285e74..452e9a4ae3d 100644
--- a/adapters/ix/ixtest/supplemental/bad-request.json
+++ b/adapters/ix/ixtest/supplemental/bad-request.json
@@ -45,7 +45,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/supplemental/bad-response-body.json b/adapters/ix/ixtest/supplemental/bad-response-body.json
index e416123023f..9de15b39175 100644
--- a/adapters/ix/ixtest/supplemental/bad-response-body.json
+++ b/adapters/ix/ixtest/supplemental/bad-response-body.json
@@ -45,7 +45,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/supplemental/dsa-request.json b/adapters/ix/ixtest/supplemental/dsa-request.json
index 969cbbe46d3..755e618ed9d 100644
--- a/adapters/ix/ixtest/supplemental/dsa-request.json
+++ b/adapters/ix/ixtest/supplemental/dsa-request.json
@@ -102,6 +102,12 @@
]
}
}
+ },
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
}
},
"impIDs":["test-imp-id"]
@@ -191,4 +197,4 @@
]
}
]
- }
\ No newline at end of file
+ }
diff --git a/adapters/ix/ixtest/supplemental/fledge-no-bid.json b/adapters/ix/ixtest/supplemental/fledge-no-bid.json
index d28b7ee0537..46eaea7d6c5 100644
--- a/adapters/ix/ixtest/supplemental/fledge-no-bid.json
+++ b/adapters/ix/ixtest/supplemental/fledge-no-bid.json
@@ -70,6 +70,12 @@
"publisher": {
"id": "569749"
}
+ },
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
}
},
"impIDs":["test-imp-id"]
diff --git a/adapters/ix/ixtest/supplemental/multi-imp-requests-error.json b/adapters/ix/ixtest/supplemental/multi-imp-requests-error.json
index 6613dce7169..d5b0824b253 100644
--- a/adapters/ix/ixtest/supplemental/multi-imp-requests-error.json
+++ b/adapters/ix/ixtest/supplemental/multi-imp-requests-error.json
@@ -116,7 +116,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id-2","test-imp-id-3"]
},
diff --git a/adapters/ix/ixtest/supplemental/native-eventtrackers-empty.json b/adapters/ix/ixtest/supplemental/native-eventtrackers-empty.json
index 780184f475f..f0d5c09ec77 100644
--- a/adapters/ix/ixtest/supplemental/native-eventtrackers-empty.json
+++ b/adapters/ix/ixtest/supplemental/native-eventtrackers-empty.json
@@ -35,7 +35,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/supplemental/native-eventtrackers-missing.json b/adapters/ix/ixtest/supplemental/native-eventtrackers-missing.json
index 7b43bcc2caa..b26c02350dd 100644
--- a/adapters/ix/ixtest/supplemental/native-eventtrackers-missing.json
+++ b/adapters/ix/ixtest/supplemental/native-eventtrackers-missing.json
@@ -35,7 +35,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/supplemental/native-missing.json b/adapters/ix/ixtest/supplemental/native-missing.json
index cf4305602b9..ba6032c0635 100644
--- a/adapters/ix/ixtest/supplemental/native-missing.json
+++ b/adapters/ix/ixtest/supplemental/native-missing.json
@@ -35,7 +35,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/supplemental/no-content.json b/adapters/ix/ixtest/supplemental/no-content.json
index 76b4dc3545d..ed10286d7e1 100644
--- a/adapters/ix/ixtest/supplemental/no-content.json
+++ b/adapters/ix/ixtest/supplemental/no-content.json
@@ -45,7 +45,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/supplemental/not-found.json b/adapters/ix/ixtest/supplemental/not-found.json
index a3773dc6883..703b252b1cb 100644
--- a/adapters/ix/ixtest/supplemental/not-found.json
+++ b/adapters/ix/ixtest/supplemental/not-found.json
@@ -45,7 +45,13 @@
}
}
}
- ]
+ ],
+ "ext": {
+ "ixdiag": {
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
+ }
},
"impIDs":["test-imp-id"]
},
diff --git a/adapters/ix/ixtest/supplemental/sid.json b/adapters/ix/ixtest/supplemental/sid.json
index 9b5aaf605ba..f3f4e176d31 100644
--- a/adapters/ix/ixtest/supplemental/sid.json
+++ b/adapters/ix/ixtest/supplemental/sid.json
@@ -63,9 +63,10 @@
"body": {
"ext": {
"ixdiag": {
- "multipleSiteIds": "569749, 569750"
- },
- "prebid": null
+ "multipleSiteIds": "569749, 569750",
+ "pbsp": "go",
+ "pbsv": "unknown"
+ }
},
"id": "test-request-id",
"imp": [
From 9bc6eca13fdf2c714cadeb10b845dddff64742f1 Mon Sep 17 00:00:00 2001
From: Brian Sardo <1168933+bsardo@users.noreply.github.com>
Date: Mon, 7 Apr 2025 11:40:21 -0400
Subject: [PATCH 26/40] AppNexus: Support member param as int (#4284)
---
adapters/appnexus/appnexus.go | 4 +-
.../supplemental/member-as-int-test.json | 151 ++++++++++++++++++
adapters/appnexus/params_test.go | 3 +
openrtb_ext/imp_appnexus.go | 2 +-
static/bidder-params/appnexus.json | 2 +-
util/jsonutil/intstring.go | 19 +++
util/jsonutil/intstring_test.go | 58 +++++++
7 files changed, 235 insertions(+), 4 deletions(-)
create mode 100644 adapters/appnexus/appnexustest/supplemental/member-as-int-test.json
create mode 100644 util/jsonutil/intstring.go
create mode 100644 util/jsonutil/intstring_test.go
diff --git a/adapters/appnexus/appnexus.go b/adapters/appnexus/appnexus.go
index eb7b71272cf..a25f3f31640 100644
--- a/adapters/appnexus/appnexus.go
+++ b/adapters/appnexus/appnexus.go
@@ -90,7 +90,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
continue
}
- memberId := impExtIncoming.Bidder.Member
+ memberId := string(impExtIncoming.Bidder.Member)
if memberId != "" {
// The Appnexus API requires a Member ID in the URL. This means the request may fail if
// different impressions have different member IDs.
@@ -288,7 +288,7 @@ func handleLegacyParams(appnexusExt *openrtb_ext.ExtImpAppnexus) {
}
func validateAppnexusExt(appnexusExt *openrtb_ext.ExtImpAppnexus) error {
- if appnexusExt.PlacementId == 0 && (appnexusExt.InvCode == "" || appnexusExt.Member == "") {
+ if appnexusExt.PlacementId == 0 && (appnexusExt.InvCode == "" || string(appnexusExt.Member) == "") {
return &errortypes.BadInput{
Message: "No placement or member+invcode provided",
}
diff --git a/adapters/appnexus/appnexustest/supplemental/member-as-int-test.json b/adapters/appnexus/appnexustest/supplemental/member-as-int-test.json
new file mode 100644
index 00000000000..69f8469ef9b
--- /dev/null
+++ b/adapters/appnexus/appnexustest/supplemental/member-as-int-test.json
@@ -0,0 +1,151 @@
+{
+ "mockBidRequest": {
+ "id": "some-req-id",
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "native": {
+ "request": "{\"ver\":\"1.1\",\"context\":1,\"contextsubtype\":11,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1,\"hmin\":1}},{\"id\":3,\"required\":0,\"data\":{\"type\":1,\"len\":200}},{\"id\":4,\"required\":0,\"data\":{\"type\":2,\"len\":15000}},{\"id\":5,\"required\":0,\"data\":{\"type\":6,\"len\":40}},{\"id\":6,\"required\":0,\"data\":{\"type\":500}}]}",
+ "ver": "1.1"
+ },
+ "ext": {
+ "bidder": {
+ "member": 103,
+ "inv_code": "abc"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "prebid.org",
+ "page": "prebid.org"
+ },
+ "device": {
+ "ip": "152.193.6.74"
+ },
+ "user": {
+ "id": "db089de9-a62e-4861-a881-0ff15e052516",
+ "buyeruid": "8299345306627569435"
+ },
+ "tmax": 500
+ },
+ "httpcalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://ib.adnxs.com/openrtb2?member_id=103",
+ "body": {
+ "id": "some-req-id",
+ "imp": [
+ {
+ "id": "some-imp-id",
+ "native": {
+ "request": "{\"ver\":\"1.1\",\"context\":1,\"contextsubtype\":11,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1,\"hmin\":1}},{\"id\":3,\"required\":0,\"data\":{\"type\":1,\"len\":200}},{\"id\":4,\"required\":0,\"data\":{\"type\":2,\"len\":15000}},{\"id\":5,\"required\":0,\"data\":{\"type\":6,\"len\":40}},{\"id\":6,\"required\":0,\"data\":{\"type\":500}}]}",
+ "ver": "1.1"
+ },
+ "tagid": "abc",
+ "ext": {
+ "appnexus": {}
+ }
+ }
+ ],
+ "ext": {
+ "appnexus": {
+ "hb_source": 5
+ }
+ },
+ "site": {
+ "domain": "prebid.org",
+ "page": "prebid.org"
+ },
+ "device": {
+ "ip": "152.193.6.74"
+ },
+ "user": {
+ "id": "db089de9-a62e-4861-a881-0ff15e052516",
+ "buyeruid": "8299345306627569435"
+ },
+ "tmax": 500
+ },
+ "impIDs":["some-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "some-req-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "928185755156387460",
+ "impid": "some-imp-id",
+ "price": 1.000000,
+ "adid": "69595837",
+ "adm": "{}",
+ "adomain": [
+ "appnexus.com"
+ ],
+ "iurl": "http://nym1-ib.adnxs.com/cr?id=69595837",
+ "cid": "958",
+ "crid": "69595837",
+ "cat": [
+ "IAB3-1"
+ ],
+ "ext": {
+ "appnexus": {
+ "brand_id": 350,
+ "brand_category_id": 350,
+ "auction_id": 5607483846416358664,
+ "bidder_id": 2,
+ "bid_ad_type": 3,
+ "deal_priority": 5
+ }
+ }
+ }
+ ],
+ "seat": "958"
+ }
+ ],
+ "bidid": "8141327771600527856",
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "928185755156387460",
+ "impid": "some-imp-id",
+ "price": 1,
+ "adm": "{}",
+ "adid": "69595837",
+ "adomain": [
+ "appnexus.com"
+ ],
+ "iurl": "http://nym1-ib.adnxs.com/cr?id=69595837",
+ "cid": "958",
+ "crid": "69595837",
+ "cat": [
+ "IAB3-1"
+ ],
+ "ext": {
+ "appnexus": {
+ "brand_id": 350,
+ "brand_category_id": 350,
+ "auction_id": 5607483846416358664,
+ "bidder_id": 2,
+ "bid_ad_type": 3,
+ "deal_priority": 5
+ }
+ }
+ },
+ "type": "native"
+ }
+ ]
+ }
+ ]
+ }
+
\ No newline at end of file
diff --git a/adapters/appnexus/params_test.go b/adapters/appnexus/params_test.go
index e828bf57da7..225b1ac3231 100644
--- a/adapters/appnexus/params_test.go
+++ b/adapters/appnexus/params_test.go
@@ -47,6 +47,7 @@ var validParams = []string{
`{"placementId":123,"position":"above"}`,
`{"placement_id":123,"position":"below"}`,
`{"member":"123","inv_code":"456"}`,
+ `{"member":123,"inv_code":"456"}`,
`{"placementId":123, "keywords":[{"key":"foo","value":["bar"]}]}`,
`{"placement_id":123, "keywords":[{"key":"foo","value":["bar", "baz"]}]}`,
`{"placement_id":123, "keywords":[{"key":"foo"}]}`,
@@ -66,9 +67,11 @@ var invalidParams = []string{
`[]`,
`{}`,
`{"placement_id":123, "placementId":123}`,
+ `{"member":123}`,
`{"member":"123"}`,
`{"member":"123","invCode":45}`,
`{"placementId":"123","member":"123","invCode":45}`,
+ `{"placementId":"123","member":"123","invCode":"45"}`,
`{"placement_id":123, "position":"left"}`,
`{"placement_id":123, "position":"left"}`,
`{"placement_id":123, "reserve":"45"}`,
diff --git a/openrtb_ext/imp_appnexus.go b/openrtb_ext/imp_appnexus.go
index 9e7a43495c8..bde37bdc9de 100644
--- a/openrtb_ext/imp_appnexus.go
+++ b/openrtb_ext/imp_appnexus.go
@@ -15,7 +15,7 @@ type ExtImpAppnexus struct {
LegacyTrafficSourceCode string `json:"trafficSourceCode"`
PlacementId jsonutil.StringInt `json:"placement_id"`
InvCode string `json:"inv_code"`
- Member string `json:"member"`
+ Member jsonutil.IntString `json:"member"`
Keywords ExtImpAppnexusKeywords `json:"keywords"`
TrafficSourceCode string `json:"traffic_source_code"`
Reserve float64 `json:"reserve"`
diff --git a/static/bidder-params/appnexus.json b/static/bidder-params/appnexus.json
index 6a9a5d7d45d..37909b12066 100644
--- a/static/bidder-params/appnexus.json
+++ b/static/bidder-params/appnexus.json
@@ -22,7 +22,7 @@
"description": "Deprecated, use inv_code instead."
},
"member": {
- "type": "string",
+ "type": ["integer", "string"],
"description": "An ID which identifies the member selling the impression."
},
"keywords": {
diff --git a/util/jsonutil/intstring.go b/util/jsonutil/intstring.go
new file mode 100644
index 00000000000..09c91577cbe
--- /dev/null
+++ b/util/jsonutil/intstring.go
@@ -0,0 +1,19 @@
+package jsonutil
+
+import (
+ "errors"
+
+ "github.com/tidwall/gjson"
+)
+
+type IntString string
+
+func (st *IntString) UnmarshalJSON(b []byte) error {
+ res := gjson.ParseBytes(b)
+ if res.Type != gjson.Number && res.Type != gjson.String {
+ return errors.New("invalid type")
+ }
+
+ *st = IntString(res.String())
+ return nil
+}
diff --git a/util/jsonutil/intstring_test.go b/util/jsonutil/intstring_test.go
new file mode 100644
index 00000000000..f8131701e72
--- /dev/null
+++ b/util/jsonutil/intstring_test.go
@@ -0,0 +1,58 @@
+package jsonutil
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestIntStringUnmarshalJSON(t *testing.T) {
+ tests := []struct {
+ name string
+ jsonData json.RawMessage
+ expectError bool
+ want string
+ }{
+ {
+ name: "null",
+ jsonData: []byte(`{"item_id": null}`),
+ want: "",
+ expectError: true,
+ },
+ {
+ name: "string",
+ jsonData: []byte(`{"item_id": "30"}`),
+ want: "30",
+ },
+ {
+ name: "int",
+ jsonData: []byte(`{"item_id": 30}`),
+ want: "30",
+ },
+ {
+ name: "error",
+ jsonData: []byte(`{"item_id": []`),
+ want: "",
+ expectError: true,
+ },
+ }
+
+ type Item struct {
+ ItemId IntString `json:"item_id"`
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ var item Item
+ err := UnmarshalValid(test.jsonData, &item)
+ assert.Equal(t, string(test.want), string(item.ItemId))
+
+ if test.expectError {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ }
+ })
+ }
+}
From 242593bbeafb4a5a82acd2a9cceaf49b3733899e Mon Sep 17 00:00:00 2001
From: MadSense Ops
Date: Mon, 7 Apr 2025 21:00:42 +0200
Subject: [PATCH 27/40] New Adapter: MadSense (#4169)
---
adapters/madsense/madsense.go | 125 +++++++
adapters/madsense/madsense_test.go | 17 +
.../madsensetest/exemplary/banner-app.json | 116 +++++++
.../madsensetest/exemplary/banner-web.json | 126 +++++++
.../exemplary/mixed-imp-types.json | 312 ++++++++++++++++++
.../madsensetest/exemplary/video-app.json | 141 ++++++++
.../madsensetest/exemplary/video-web-pod.json | 212 ++++++++++++
.../madsensetest/exemplary/video-web.json | 146 ++++++++
.../bad-request-imp-ext-bidder.json | 34 ++
.../supplemental/bad-request-imp-ext.json | 33 ++
.../supplemental/bad-response-error.json | 93 ++++++
.../supplemental/bad-response-mtype.json | 122 +++++++
.../supplemental/bad-response-status-400.json | 98 ++++++
.../supplemental/bad-response-status-500.json | 92 ++++++
.../supplemental/no-content-response.json | 87 +++++
.../supplemental/test-response.json | 143 ++++++++
adapters/madsense/params_test.go | 51 +++
adapters/madsense/utils.go | 99 ++++++
exchange/adapter_builders.go | 2 +
openrtb_ext/bidders.go | 2 +
openrtb_ext/imp_madsense.go | 5 +
static/bidder-info/madsense.yaml | 12 +
static/bidder-params/madsense.json | 14 +
23 files changed, 2082 insertions(+)
create mode 100644 adapters/madsense/madsense.go
create mode 100644 adapters/madsense/madsense_test.go
create mode 100644 adapters/madsense/madsensetest/exemplary/banner-app.json
create mode 100644 adapters/madsense/madsensetest/exemplary/banner-web.json
create mode 100644 adapters/madsense/madsensetest/exemplary/mixed-imp-types.json
create mode 100644 adapters/madsense/madsensetest/exemplary/video-app.json
create mode 100644 adapters/madsense/madsensetest/exemplary/video-web-pod.json
create mode 100644 adapters/madsense/madsensetest/exemplary/video-web.json
create mode 100644 adapters/madsense/madsensetest/supplemental/bad-request-imp-ext-bidder.json
create mode 100644 adapters/madsense/madsensetest/supplemental/bad-request-imp-ext.json
create mode 100644 adapters/madsense/madsensetest/supplemental/bad-response-error.json
create mode 100644 adapters/madsense/madsensetest/supplemental/bad-response-mtype.json
create mode 100644 adapters/madsense/madsensetest/supplemental/bad-response-status-400.json
create mode 100644 adapters/madsense/madsensetest/supplemental/bad-response-status-500.json
create mode 100644 adapters/madsense/madsensetest/supplemental/no-content-response.json
create mode 100644 adapters/madsense/madsensetest/supplemental/test-response.json
create mode 100644 adapters/madsense/params_test.go
create mode 100644 adapters/madsense/utils.go
create mode 100644 openrtb_ext/imp_madsense.go
create mode 100644 static/bidder-info/madsense.yaml
create mode 100644 static/bidder-params/madsense.json
diff --git a/adapters/madsense/madsense.go b/adapters/madsense/madsense.go
new file mode 100644
index 00000000000..5cf32d64d5a
--- /dev/null
+++ b/adapters/madsense/madsense.go
@@ -0,0 +1,125 @@
+package madsense
+
+import (
+ "net/http"
+ "net/url"
+
+ "github.com/prebid/openrtb/v20/openrtb2"
+ "github.com/prebid/prebid-server/v3/adapters"
+ "github.com/prebid/prebid-server/v3/config"
+ "github.com/prebid/prebid-server/v3/errortypes"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+ "github.com/prebid/prebid-server/v3/util/jsonutil"
+)
+
+type adapter struct {
+ endpoint string
+}
+
+// Builder builds a new instance of the MadSense adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
+ bidder := &adapter{
+ endpoint: config.Endpoint,
+ }
+ return bidder, nil
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+ reqs := make([]*adapters.RequestData, 0, len(request.Imp))
+ var errs []error
+
+ appendReq := func(imps []openrtb2.Imp) {
+ req, err := a.makeRequest(request, imps)
+ if err != nil {
+ errs = append(errs, err)
+ return
+ }
+ if req != nil {
+ reqs = append(reqs, req)
+ }
+ }
+
+ var videoImps []openrtb2.Imp
+ for i := range request.Imp {
+ imp := &request.Imp[i]
+ if imp.Banner != nil {
+ appendReq(request.Imp[i : i+1])
+ } else if imp.Video != nil {
+ videoImps = append(videoImps, request.Imp[i])
+ }
+ }
+
+ // we support video podding, so we want to send all video impressions in a single request
+ appendReq(videoImps)
+
+ return reqs, errs
+}
+
+func (a *adapter) makeRequest(request *openrtb2.BidRequest, imps []openrtb2.Imp) (*adapters.RequestData, error) {
+ if len(imps) == 0 {
+ return nil, nil
+ }
+ ext, err := parseImpExt(&imps[0])
+ if err != nil {
+ return nil, err
+ }
+
+ request.Imp = imps
+ body, err := jsonutil.Marshal(request)
+ if err != nil {
+ return nil, err
+ }
+
+ companyId := ext.CompanyId
+ if request.Test == 1 {
+ companyId = "test"
+ }
+
+ return &adapters.RequestData{
+ Method: http.MethodPost,
+ Uri: a.getEndpointURL(companyId),
+ Body: body,
+ Headers: getHeaders(request),
+ ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
+ }, nil
+}
+
+func (a *adapter) getEndpointURL(companyId string) string {
+ params := url.Values{}
+ params.Add("company_id", companyId)
+ return a.endpoint + "?" + params.Encode()
+}
+
+func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+ if adapters.IsResponseStatusCodeNoContent(response) {
+ return nil, nil
+ }
+
+ if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil {
+ return nil, []error{err}
+ }
+
+ var resp openrtb2.BidResponse
+ if err := jsonutil.Unmarshal(response.Body, &resp); err != nil {
+ return nil, []error{&errortypes.BadServerResponse{
+ Message: "Bad Server Response",
+ }}
+ }
+
+ var bidErrors []error
+ bidderResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+ for i := range resp.SeatBid {
+ seatBid := &resp.SeatBid[i]
+ for j := range seatBid.Bid {
+ bid := &seatBid.Bid[j]
+ typedBid, err := getTypedBidFromBid(bid)
+ if err != nil {
+ bidErrors = append(bidErrors, err)
+ continue
+ }
+ bidderResponse.Bids = append(bidderResponse.Bids, typedBid)
+ }
+ }
+
+ return bidderResponse, bidErrors
+}
diff --git a/adapters/madsense/madsense_test.go b/adapters/madsense/madsense_test.go
new file mode 100644
index 00000000000..8093066ac5f
--- /dev/null
+++ b/adapters/madsense/madsense_test.go
@@ -0,0 +1,17 @@
+package madsense
+
+import (
+ "github.com/prebid/prebid-server/v3/adapters/adapterstest"
+ "github.com/prebid/prebid-server/v3/config"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+ "github.com/stretchr/testify/require"
+ "testing"
+)
+
+func TestJsonSamples(t *testing.T) {
+ bidder, buildErr := Builder(openrtb_ext.BidderMadSense, config.Adapter{
+ Endpoint: "https://test.localhost.com"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+
+ require.NoError(t, buildErr, "Builder returned unexpected error")
+ adapterstest.RunJSONBidderTest(t, "madsensetest", bidder)
+}
diff --git a/adapters/madsense/madsensetest/exemplary/banner-app.json b/adapters/madsense/madsensetest/exemplary/banner-app.json
new file mode 100644
index 00000000000..bc1b2668fce
--- /dev/null
+++ b/adapters/madsense/madsensetest/exemplary/banner-app.json
@@ -0,0 +1,116 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "app": {
+ "bundle": "54321"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "app": {
+ "bundle": "54321"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "884f46aa-25ab-488a-bd7e-90e3a31a03e0",
+ "crid": "b83e6e58-9342-4e8c-bf6a-4ad09b231547",
+ "price": 10,
+ "impid": "test-imp-id",
+ "adm": "
",
+ "mtype": 1
+ }
+ ]
+ }
+ ],
+ "seat": "madsense"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "884f46aa-25ab-488a-bd7e-90e3a31a03e0",
+ "crid": "b83e6e58-9342-4e8c-bf6a-4ad09b231547",
+ "price": 10,
+ "impid": "test-imp-id",
+ "adm": "
",
+ "mtype": 1
+ },
+ "type": "banner"
+ }
+ ],
+ "seat": "madsense"
+ }
+ ]
+}
diff --git a/adapters/madsense/madsensetest/exemplary/banner-web.json b/adapters/madsense/madsensetest/exemplary/banner-web.json
new file mode 100644
index 00000000000..0ad9c5c8960
--- /dev/null
+++ b/adapters/madsense/madsensetest/exemplary/banner-web.json
@@ -0,0 +1,126 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "user-agent",
+ "ipv6": "2001:db8:3333:4444:5555:6666:7777:8888"
+ },
+ "site": {
+ "domain": "domain.com",
+ "page": "http://domain.com/page",
+ "ref": "https://example.com/page"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Origin": [
+ "domain.com"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "2001:db8:3333:4444:5555:6666:7777:8888"
+ ],
+ "Referer": [
+ "https://example.com/page"
+ ]
+ },
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "user-agent",
+ "ipv6": "2001:db8:3333:4444:5555:6666:7777:8888"
+ },
+ "site": {
+ "domain": "domain.com",
+ "page": "http://domain.com/page",
+ "ref": "https://example.com/page"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "884f46aa-25ab-488a-bd7e-90e3a31a03e0",
+ "crid": "b83e6e58-9342-4e8c-bf6a-4ad09b231547",
+ "price": 10,
+ "impid": "test-imp-id",
+ "adm": "",
+ "mtype": 1
+ }
+ ]
+ }
+ ],
+ "seat": "madsense"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "884f46aa-25ab-488a-bd7e-90e3a31a03e0",
+ "crid": "b83e6e58-9342-4e8c-bf6a-4ad09b231547",
+ "price": 10,
+ "impid": "test-imp-id",
+ "adm": "",
+ "mtype": 1
+ },
+ "type": "banner"
+ }
+ ],
+ "seat": "madsense"
+ }
+ ]
+}
diff --git a/adapters/madsense/madsensetest/exemplary/mixed-imp-types.json b/adapters/madsense/madsensetest/exemplary/mixed-imp-types.json
new file mode 100644
index 00000000000..a453fd989ad
--- /dev/null
+++ b/adapters/madsense/madsensetest/exemplary/mixed-imp-types.json
@@ -0,0 +1,312 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-2",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-3",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "domain.com",
+ "page": "http://domain.com/page"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Origin": [
+ "domain.com"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-2",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "site": {
+ "domain": "domain.com",
+ "page": "http://domain.com/page"
+ }
+ },
+ "impIDs":["test-imp-id","test-imp-id-2"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ },
+ {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801",
+ "impid": "test-imp-id-2",
+ "price": 10,
+ "adm": "some-test-ad-2",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 30,
+ "cat": [
+ "IAB1-1"
+ ]
+ }
+ ],
+ "seat": "madsense"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Origin": [
+ "domain.com"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id-3",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "site": {
+ "domain": "domain.com",
+ "page": "http://domain.com/page"
+ }
+ },
+ "impIDs":["test-imp-id-3"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "884f46aa-25ab-488a-bd7e-90e3a31a03e2",
+ "crid": "b83e6e58-9342-4e8c-bf6a-4ad09b231547",
+ "price": 10,
+ "impid": "test-imp-id-3",
+ "adm": "",
+ "mtype": 1
+ }
+ ]
+ }
+ ],
+ "seat": "madsense"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ },
+ "type": "video",
+ "video": {
+ "duration": 15,
+ "primary_category": "IAB1-5"
+ }
+ },
+ {
+ "bid": {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801",
+ "impid": "test-imp-id-2",
+ "price": 10,
+ "adm": "some-test-ad-2",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 30,
+ "cat": [
+ "IAB1-1"
+ ]
+ },
+ "type": "video",
+ "video": {
+ "duration": 30,
+ "primary_category": "IAB1-1"
+ }
+ }
+ ]
+ },
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "884f46aa-25ab-488a-bd7e-90e3a31a03e2",
+ "crid": "b83e6e58-9342-4e8c-bf6a-4ad09b231547",
+ "price": 10,
+ "impid": "test-imp-id-3",
+ "adm": "",
+ "mtype": 1
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
+
diff --git a/adapters/madsense/madsensetest/exemplary/video-app.json b/adapters/madsense/madsensetest/exemplary/video-app.json
new file mode 100644
index 00000000000..d3007dc2b83
--- /dev/null
+++ b/adapters/madsense/madsensetest/exemplary/video-app.json
@@ -0,0 +1,141 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "app": {
+ "bundle": "54321"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "app": {
+ "bundle": "54321"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ }
+ ],
+ "seat": "madsense"
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ },
+ "type": "video",
+ "video": {
+ "duration": 15,
+ "primary_category": "IAB1-5"
+ }
+ }
+ ]
+ }
+ ]
+}
+
diff --git a/adapters/madsense/madsensetest/exemplary/video-web-pod.json b/adapters/madsense/madsensetest/exemplary/video-web-pod.json
new file mode 100644
index 00000000000..ce3e354cb60
--- /dev/null
+++ b/adapters/madsense/madsensetest/exemplary/video-web-pod.json
@@ -0,0 +1,212 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-2",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+
+ ],
+ "site": {
+ "domain": "domain.com",
+ "page": "http://domain.com/page"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Origin": [
+ "domain.com"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-2",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "site": {
+ "domain": "domain.com",
+ "page": "http://domain.com/page"
+ }
+ },
+ "impIDs":["test-imp-id","test-imp-id-2"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ },
+ {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801",
+ "impid": "test-imp-id-2",
+ "price": 10,
+ "adm": "some-test-ad-2",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 30,
+ "cat": [
+ "IAB1-1"
+ ]
+ }
+ ],
+ "seat": "madsense"
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ },
+ "type": "video",
+ "video": {
+ "duration": 15,
+ "primary_category": "IAB1-5"
+ }
+ },
+ {
+ "bid": {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e801",
+ "impid": "test-imp-id-2",
+ "price": 10,
+ "adm": "some-test-ad-2",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 30,
+ "cat": [
+ "IAB1-1"
+ ]
+ },
+ "type": "video",
+ "video": {
+ "duration": 30,
+ "primary_category": "IAB1-1"
+ }
+ }
+ ]
+ }
+ ]
+}
+
diff --git a/adapters/madsense/madsensetest/exemplary/video-web.json b/adapters/madsense/madsensetest/exemplary/video-web.json
new file mode 100644
index 00000000000..bf66a6470fd
--- /dev/null
+++ b/adapters/madsense/madsensetest/exemplary/video-web.json
@@ -0,0 +1,146 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "domain.com",
+ "page": "http://domain.com/page"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Origin": [
+ "domain.com"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "site": {
+ "domain": "domain.com",
+ "page": "http://domain.com/page"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ }
+ ],
+ "seat": "madsense"
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ },
+ "type": "video",
+ "video": {
+ "duration": 15,
+ "primary_category": "IAB1-5"
+ }
+ }
+ ]
+ }
+ ]
+}
+
diff --git a/adapters/madsense/madsensetest/supplemental/bad-request-imp-ext-bidder.json b/adapters/madsense/madsensetest/supplemental/bad-request-imp-ext-bidder.json
new file mode 100644
index 00000000000..b795e6df3c5
--- /dev/null
+++ b/adapters/madsense/madsensetest/supplemental/bad-request-imp-ext-bidder.json
@@ -0,0 +1,34 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {}
+ }
+ ],
+ "app": {
+ "bundle": "54321"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [],
+ "expectedBidResponses": [],
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "Error while decoding bidderExt.Bidder",
+ "comparison": "startswith"
+ }
+ ]
+}
+
diff --git a/adapters/madsense/madsensetest/supplemental/bad-request-imp-ext.json b/adapters/madsense/madsensetest/supplemental/bad-request-imp-ext.json
new file mode 100644
index 00000000000..32f09afb60a
--- /dev/null
+++ b/adapters/madsense/madsensetest/supplemental/bad-request-imp-ext.json
@@ -0,0 +1,33 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ }
+ }
+ ],
+ "app": {
+ "bundle": "54321"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [],
+ "expectedBidResponses": [],
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "Error while decoding imp.Ext",
+ "comparison": "startswith"
+ }
+ ]
+}
+
diff --git a/adapters/madsense/madsensetest/supplemental/bad-response-error.json b/adapters/madsense/madsensetest/supplemental/bad-response-error.json
new file mode 100644
index 00000000000..1ce30f8c3f3
--- /dev/null
+++ b/adapters/madsense/madsensetest/supplemental/bad-response-error.json
@@ -0,0 +1,93 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "app": {
+ "bundle": "54321"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "app": {
+ "bundle": "54321"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": "invalid response"
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Bad Server Response",
+ "comparison": "literal"
+ }
+ ]
+}
+
diff --git a/adapters/madsense/madsensetest/supplemental/bad-response-mtype.json b/adapters/madsense/madsensetest/supplemental/bad-response-mtype.json
new file mode 100644
index 00000000000..6c9c6c94a67
--- /dev/null
+++ b/adapters/madsense/madsensetest/supplemental/bad-response-mtype.json
@@ -0,0 +1,122 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "app": {
+ "bundle": "54321"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "app": {
+ "bundle": "54321"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 4,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ }
+ ],
+ "seat": "madsense"
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [{
+ "currency": "USD",
+ "bids": []
+ }],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "MType 4 not supported",
+ "comparison": "literal"
+ }
+ ]
+}
+
diff --git a/adapters/madsense/madsensetest/supplemental/bad-response-status-400.json b/adapters/madsense/madsensetest/supplemental/bad-response-status-400.json
new file mode 100644
index 00000000000..87424d2f86c
--- /dev/null
+++ b/adapters/madsense/madsensetest/supplemental/bad-response-status-400.json
@@ -0,0 +1,98 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "site": {
+ "domain": "domain.com",
+ "page": "page.com/test"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Origin": [
+ "domain.com"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "site": {
+ "domain": "domain.com",
+ "page": "page.com/test"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 400
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/madsense/madsensetest/supplemental/bad-response-status-500.json b/adapters/madsense/madsensetest/supplemental/bad-response-status-500.json
new file mode 100644
index 00000000000..143431c7144
--- /dev/null
+++ b/adapters/madsense/madsensetest/supplemental/bad-response-status-500.json
@@ -0,0 +1,92 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "app": {
+ "bundle": "54321"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "app": {
+ "bundle": "54321"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 500
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Unexpected status code: 500. Run with request.debug = 1 for more info",
+ "comparison": "literal"
+ }
+ ]
+}
+
diff --git a/adapters/madsense/madsensetest/supplemental/no-content-response.json b/adapters/madsense/madsensetest/supplemental/no-content-response.json
new file mode 100644
index 00000000000..27caa245cd3
--- /dev/null
+++ b/adapters/madsense/madsensetest/supplemental/no-content-response.json
@@ -0,0 +1,87 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "app": {
+ "bundle": "54321"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=9876543",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "app": {
+ "bundle": "54321"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 204
+ }
+ }
+ ],
+ "expectedBidResponses": []
+}
+
diff --git a/adapters/madsense/madsensetest/supplemental/test-response.json b/adapters/madsense/madsensetest/supplemental/test-response.json
new file mode 100644
index 00000000000..9ef7c7894f4
--- /dev/null
+++ b/adapters/madsense/madsensetest/supplemental/test-response.json
@@ -0,0 +1,143 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "test": 1,
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "app": {
+ "bundle": "54321"
+ },
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "uri": "https://test.localhost.com?company_id=test",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "test": 1,
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": [
+ "video/mp4"
+ ],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "company_id": "9876543"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ip": "1.2.3.4",
+ "ua": "user-agent"
+ },
+ "app": {
+ "bundle": "54321"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ }
+ ],
+ "seat": "madsense"
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 10,
+ "adm": "some-test-ad",
+ "crid": "54321",
+ "w": 1920,
+ "h": 1080,
+ "mtype": 2,
+ "dur": 15,
+ "cat": [
+ "IAB1-5",
+ "IAB1-6"
+ ]
+ },
+ "type": "video",
+ "video": {
+ "duration": 15,
+ "primary_category": "IAB1-5"
+ }
+ }
+ ]
+ }
+ ]
+}
+
diff --git a/adapters/madsense/params_test.go b/adapters/madsense/params_test.go
new file mode 100644
index 00000000000..de597067458
--- /dev/null
+++ b/adapters/madsense/params_test.go
@@ -0,0 +1,51 @@
+package madsense
+
+import (
+ "encoding/json"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+ "github.com/stretchr/testify/require"
+ "testing"
+)
+
+// This file actually intends to test static/bidder-params/madsense.json
+//
+// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.madsense
+
+// TestValidParams makes sure that the madsense schema accepts all imp.ext fields which we intend to support.
+func TestValidParams(t *testing.T) {
+ validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+ require.NoError(t, err, "Failed to fetch the json-schemas")
+
+ for _, validParam := range validParams {
+ err := validator.Validate(openrtb_ext.BidderMadSense, json.RawMessage(validParam))
+ require.NoError(t, err, "Schema rejected madsense params: %s", validParam)
+ }
+}
+
+// TestInvalidParams makes sure that the madsense schema rejects all the imp.ext fields we don't support.
+func TestInvalidParams(t *testing.T) {
+ validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+ require.NoError(t, err, "Failed to fetch the json-schemas")
+
+ for _, invalidParam := range invalidParams {
+ err := validator.Validate(openrtb_ext.BidderMadSense, json.RawMessage(invalidParam))
+ require.Error(t, err, "Schema allowed unexpected params: %s", invalidParam)
+ }
+}
+
+var validParams = []string{
+ `{"company_id": "9876543"}`,
+}
+
+var invalidParams = []string{
+ ``,
+ `null`,
+ `true`,
+ `5`,
+ `4.2`,
+ `[]`,
+ `{}`,
+ `{"companyId": "987654a"}`,
+ `{"companyId": "98765432"}`,
+ `{"company_id": ""}`,
+}
diff --git a/adapters/madsense/utils.go b/adapters/madsense/utils.go
new file mode 100644
index 00000000000..992d136330c
--- /dev/null
+++ b/adapters/madsense/utils.go
@@ -0,0 +1,99 @@
+package madsense
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/prebid/openrtb/v20/openrtb2"
+ "github.com/prebid/prebid-server/v3/adapters"
+ "github.com/prebid/prebid-server/v3/errortypes"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+ "github.com/prebid/prebid-server/v3/util/jsonutil"
+)
+
+func parseImpExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpMadSense, error) {
+ var bidderExt adapters.ExtImpBidder
+
+ if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil {
+ return nil, &errortypes.BadInput{
+ Message: fmt.Sprintf("Error while decoding imp.Ext, err: %v", err),
+ }
+ }
+
+ ext := openrtb_ext.ExtImpMadSense{}
+ err := jsonutil.Unmarshal(bidderExt.Bidder, &ext)
+ if err != nil {
+ return nil, &errortypes.BadInput{
+ Message: fmt.Sprintf("Error while decoding bidderExt.Bidder, err: %v", err),
+ }
+ }
+
+ return &ext, nil
+}
+
+func getHeaders(request *openrtb2.BidRequest) http.Header {
+ headers := http.Header{}
+ headers.Set("Content-Type", "application/json;charset=utf-8")
+ headers.Set("Accept", "application/json")
+ headers.Set("X-Openrtb-Version", "2.6")
+
+ if request.Device != nil {
+ if len(request.Device.UA) > 0 {
+ headers.Set("User-Agent", request.Device.UA)
+ }
+
+ if len(request.Device.IP) > 0 {
+ headers.Set("X-Forwarded-For", request.Device.IP)
+ }
+
+ if len(request.Device.IPv6) > 0 {
+ headers.Set("X-Forwarded-For", request.Device.IPv6)
+ }
+ }
+
+ if request.Site != nil {
+ if request.Site.Domain != "" {
+ headers.Set("Origin", request.Site.Domain)
+ }
+ if request.Site.Ref != "" {
+ headers.Set("Referer", request.Site.Ref)
+ }
+ }
+ return headers
+}
+
+func getTypedBidFromBid(bid *openrtb2.Bid) (*adapters.TypedBid, error) {
+ bidType, err := getMediaTypeForBid(bid)
+ if err != nil {
+ return nil, err
+ }
+
+ var bidVideo *openrtb_ext.ExtBidPrebidVideo
+ if bidType == openrtb_ext.BidTypeVideo {
+ bidVideo = &openrtb_ext.ExtBidPrebidVideo{}
+ if len(bid.Cat) > 0 {
+ bidVideo.PrimaryCategory = bid.Cat[0]
+ }
+ if bid.Dur > 0 {
+ bidVideo.Duration = int(bid.Dur)
+ }
+ }
+ return &adapters.TypedBid{
+ Bid: bid,
+ BidType: bidType,
+ BidVideo: bidVideo,
+ }, nil
+}
+
+func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) {
+ switch bid.MType {
+ case openrtb2.MarkupBanner:
+ return openrtb_ext.BidTypeBanner, nil
+ case openrtb2.MarkupVideo:
+ return openrtb_ext.BidTypeVideo, nil
+ default:
+ return "", &errortypes.BadServerResponse{
+ Message: fmt.Sprintf("MType %v not supported", bid.MType),
+ }
+ }
+}
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 7647de71786..07b607461f7 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -140,6 +140,7 @@ import (
"github.com/prebid/prebid-server/v3/adapters/loyal"
"github.com/prebid/prebid-server/v3/adapters/lunamedia"
"github.com/prebid/prebid-server/v3/adapters/mabidder"
+ "github.com/prebid/prebid-server/v3/adapters/madsense"
"github.com/prebid/prebid-server/v3/adapters/madvertise"
"github.com/prebid/prebid-server/v3/adapters/marsmedia"
"github.com/prebid/prebid-server/v3/adapters/mediago"
@@ -389,6 +390,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
openrtb_ext.BidderLoyal: loyal.Builder,
openrtb_ext.BidderLunaMedia: lunamedia.Builder,
openrtb_ext.BidderMabidder: mabidder.Builder,
+ openrtb_ext.BidderMadSense: madsense.Builder,
openrtb_ext.BidderMadvertise: madvertise.Builder,
openrtb_ext.BidderMarsmedia: marsmedia.Builder,
openrtb_ext.BidderMediafuse: appnexus.Builder,
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 10755dfd7fd..1057a873987 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -157,6 +157,7 @@ var coreBidderNames []BidderName = []BidderName{
BidderLoyal,
BidderLunaMedia,
BidderMabidder,
+ BidderMadSense,
BidderMadvertise,
BidderMarsmedia,
BidderMediafuse,
@@ -511,6 +512,7 @@ const (
BidderLoyal BidderName = "loyal"
BidderLunaMedia BidderName = "lunamedia"
BidderMabidder BidderName = "mabidder"
+ BidderMadSense BidderName = "madsense"
BidderMadvertise BidderName = "madvertise"
BidderMarsmedia BidderName = "marsmedia"
BidderMediafuse BidderName = "mediafuse"
diff --git a/openrtb_ext/imp_madsense.go b/openrtb_ext/imp_madsense.go
new file mode 100644
index 00000000000..a0d4c0a6df0
--- /dev/null
+++ b/openrtb_ext/imp_madsense.go
@@ -0,0 +1,5 @@
+package openrtb_ext
+
+type ExtImpMadSense struct {
+ CompanyId string `json:"company_id"`
+}
diff --git a/static/bidder-info/madsense.yaml b/static/bidder-info/madsense.yaml
new file mode 100644
index 00000000000..4105c65fe98
--- /dev/null
+++ b/static/bidder-info/madsense.yaml
@@ -0,0 +1,12 @@
+endpoint: "https://ads.madsense.io/pbs"
+maintainer:
+ email: "prebid@madsense.io"
+capabilities:
+ app:
+ mediaTypes:
+ - banner
+ - video
+ site:
+ mediaTypes:
+ - banner
+ - video
\ No newline at end of file
diff --git a/static/bidder-params/madsense.json b/static/bidder-params/madsense.json
new file mode 100644
index 00000000000..54410fd2aee
--- /dev/null
+++ b/static/bidder-params/madsense.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "madSense Adapter Params",
+ "description": "A schema which validates params accepted by the madSense adapter",
+ "type": "object",
+ "properties": {
+ "company_id": {
+ "type": "string",
+ "description": "An id used to identify madSense company",
+ "minLength": 1
+ }
+ },
+ "required": ["company_id"]
+}
From ed9ed1a8bba3e78dc04afe96161f71eb13773ad5 Mon Sep 17 00:00:00 2001
From: Alexander Pykhteyev
Date: Tue, 8 Apr 2025 02:21:25 +0700
Subject: [PATCH 28/40] New Adapter: AdTarget.org - Limelight Alias (#4211)
Co-authored-by: apykhteyev
---
static/bidder-info/adtg_org.yaml | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 static/bidder-info/adtg_org.yaml
diff --git a/static/bidder-info/adtg_org.yaml b/static/bidder-info/adtg_org.yaml
new file mode 100644
index 00000000000..60b13764b94
--- /dev/null
+++ b/static/bidder-info/adtg_org.yaml
@@ -0,0 +1,2 @@
+endpoint: "http://ads-pbs.rtb.adtarget.org/openrtb/{{.PublisherID}}?host={{.Host}}"
+aliasOf: "limelightDigital"
From a136cd017dade1bed91762756fef9a14d6cda245 Mon Sep 17 00:00:00 2001
From: Bernhard Bohne <1151341+el-chuck@users.noreply.github.com>
Date: Mon, 7 Apr 2025 23:01:08 +0200
Subject: [PATCH 29/40] Smaato: Add iframe user sync (#4280)
---
static/bidder-info/smaato.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/static/bidder-info/smaato.yaml b/static/bidder-info/smaato.yaml
index 2b1b5c3fe17..071190ce79d 100644
--- a/static/bidder-info/smaato.yaml
+++ b/static/bidder-info/smaato.yaml
@@ -20,4 +20,7 @@ userSync:
redirect:
url: "https://s.ad.smaato.net/c/?adExInit=p&redir={{.RedirectURL}}&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}"
userMacro: "$UID"
+ iframe:
+ url: "https://s.ad.smaato.net/i/?adExInit=p&redir={{.RedirectURL}}&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}"
+ userMacro: "$UID"
From a346f287ba082feb0b7ee01736d60790636e59cc Mon Sep 17 00:00:00 2001
From: Maximiliano Zurita <76264143+maximilianozurita@users.noreply.github.com>
Date: Mon, 7 Apr 2025 18:22:21 -0300
Subject: [PATCH 30/40] EPlanning: Add schain support (#4146)
---
adapters/eplanning/eplanning.go | 106 +++++++++++++++++-
adapters/eplanning/eplanning_test.go | 3 +-
.../supplemental/bid-with-0-nodes-schain.json | 87 ++++++++++++++
.../supplemental/bid-with-2-nodes-schain.json | 101 +++++++++++++++++
.../supplemental/bid-with-3-nodes-schain.json | 106 ++++++++++++++++++
.../supplemental/bid-with-schain-slim.json | 94 ++++++++++++++++
.../bid-with-schain-unmarshal-error.json | 38 +++++++
.../supplemental/bid-with-schain.json | 94 ++++++++++++++++
8 files changed, 625 insertions(+), 4 deletions(-)
create mode 100644 adapters/eplanning/eplanningtest/supplemental/bid-with-0-nodes-schain.json
create mode 100644 adapters/eplanning/eplanningtest/supplemental/bid-with-2-nodes-schain.json
create mode 100644 adapters/eplanning/eplanningtest/supplemental/bid-with-3-nodes-schain.json
create mode 100644 adapters/eplanning/eplanningtest/supplemental/bid-with-schain-slim.json
create mode 100644 adapters/eplanning/eplanningtest/supplemental/bid-with-schain-unmarshal-error.json
create mode 100644 adapters/eplanning/eplanningtest/supplemental/bid-with-schain.json
diff --git a/adapters/eplanning/eplanning.go b/adapters/eplanning/eplanning.go
index dc8ab900ea3..e3d3f0c1bbc 100644
--- a/adapters/eplanning/eplanning.go
+++ b/adapters/eplanning/eplanning.go
@@ -1,12 +1,12 @@
package eplanning
import (
+ "encoding/json"
"math/rand"
"net/http"
"net/url"
- "strings"
-
"regexp"
+ "strings"
"fmt"
@@ -195,6 +195,13 @@ func (adapter *EPlanningAdapter) MakeRequests(request *openrtb2.BidRequest, reqI
query.Set("vctx", strconv.Itoa(impType))
query.Set("vv", vastVersionDefault)
}
+ if request.Source != nil && request.Source.Ext != nil {
+ err := setSchain(request.Source.Ext, &query)
+ if err != nil {
+ errors = append(errors, err)
+ return nil, errors
+ }
+ }
uriObj.RawQuery = query.Encode()
uri := uriObj.String()
@@ -212,6 +219,101 @@ func (adapter *EPlanningAdapter) MakeRequests(request *openrtb2.BidRequest, reqI
return requests, errors
}
+func setSchain(ext json.RawMessage, query *url.Values) error {
+ openRtbSchain, err := unmarshalSupplyChain(ext)
+ if err != nil {
+ return err
+ }
+ if openRtbSchain == nil || len(openRtbSchain.Nodes) > 2 {
+ return nil
+ }
+
+ schainValue, err := makeSupplyChain(*openRtbSchain)
+ if err != nil {
+ return err
+ }
+
+ if schainValue != "" {
+ query.Set("sch", schainValue)
+ }
+
+ return nil
+}
+
+func unmarshalSupplyChain(ext json.RawMessage) (*openrtb2.SupplyChain, error) {
+ var extSChain openrtb_ext.ExtRequestPrebidSChain
+ err := jsonutil.Unmarshal(ext, &extSChain)
+ if err != nil {
+ return nil, err
+ }
+ return &extSChain.SChain, nil
+}
+
+func makeSupplyChain(openRtbSchain openrtb2.SupplyChain) (string, error) {
+ if len(openRtbSchain.Nodes) == 0 {
+ return "", nil
+ }
+
+ const schainPrefixFmt = "%s,%d"
+ const schainNodeFmt = "!%s,%s,%s,%s,%s,%s,%s"
+ schainPrefix := fmt.Sprintf(schainPrefixFmt, openRtbSchain.Ver, openRtbSchain.Complete)
+ var sb strings.Builder
+ sb.WriteString(schainPrefix)
+ for _, node := range openRtbSchain.Nodes {
+ nodeValues := []any{
+ node.ASI, node.SID, node.HP, node.RID, node.Name, node.Domain, node.Ext,
+ }
+ formattedValues, err := formatNodeValues(nodeValues)
+ if err != nil {
+ return "", err
+ }
+
+ schainNode := fmt.Sprintf(schainNodeFmt, formattedValues...)
+ sb.WriteString(schainNode)
+ }
+
+ return sb.String(), nil
+}
+
+func formatNodeValues(nodeValues []any) ([]any, error) {
+ var formattedValues []any
+ for _, value := range nodeValues {
+ formattedValue, err := makeNodeValue(value)
+ if err != nil {
+ return nil, err
+ }
+ formattedValues = append(formattedValues, formattedValue)
+ }
+ return formattedValues, nil
+}
+
+func makeNodeValue(nodeParam any) (string, error) {
+ switch nodeParam := nodeParam.(type) {
+ case string:
+ // url.QueryEscape() follows the application/x-www-form-urlencoded convention, which encodes spaces as + and RFC 3986 encodes as %20
+ return strings.ReplaceAll(url.QueryEscape(nodeParam), "+", "%20"), nil
+ case *int8:
+ pointer := nodeParam
+ if pointer == nil {
+ return "", nil
+ }
+ return makeNodeValue(int(*pointer))
+ case int:
+ return strconv.Itoa(nodeParam), nil
+ case json.RawMessage:
+ if nodeParam != nil {
+ freeFormJson, err := json.Marshal(nodeParam)
+ if err != nil {
+ return "", err
+ }
+ return makeNodeValue(string(freeFormJson))
+ }
+ return "", nil
+ default:
+ return "", nil
+ }
+}
+
func isMobileDevice(request *openrtb2.BidRequest) bool {
return request.Device != nil && (request.Device.DeviceType == adcom1.DeviceMobile || request.Device.DeviceType == adcom1.DevicePhone || request.Device.DeviceType == adcom1.DeviceTablet)
}
diff --git a/adapters/eplanning/eplanning_test.go b/adapters/eplanning/eplanning_test.go
index 1d220184c6b..08af3b36b1c 100644
--- a/adapters/eplanning/eplanning_test.go
+++ b/adapters/eplanning/eplanning_test.go
@@ -1,12 +1,11 @@
package eplanning
import (
- "testing"
-
"github.com/prebid/prebid-server/v3/adapters"
"github.com/prebid/prebid-server/v3/adapters/adapterstest"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/openrtb_ext"
+ "testing"
)
func TestJsonSamples(t *testing.T) {
diff --git a/adapters/eplanning/eplanningtest/supplemental/bid-with-0-nodes-schain.json b/adapters/eplanning/eplanningtest/supplemental/bid-with-0-nodes-schain.json
new file mode 100644
index 00000000000..26d3faa9f0b
--- /dev/null
+++ b/adapters/eplanning/eplanningtest/supplemental/bid-with-0-nodes-schain.json
@@ -0,0 +1,87 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "source": {
+ "ext": {
+ "schain": {
+ "ver": "1.0",
+ "complete": 1,
+ "nodes": []
+ }
+ }
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "ci": "12345"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://rtb.e-planning.net/pbs/1/12345/1/FILE/ROS?e=300x250%3A300x250&ncb=1&ur=FILE",
+ "body": {},
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "sI": { "k": "12345" },
+ "sec": "ROS",
+ "sp": [
+ {
+ "k": "300x250",
+ "a": [{
+ "i": "123456789abcdef",
+ "pr": "0.5",
+ "adm": "test
",
+ "crid": "abcdef123456789",
+ "id": "adid12345",
+ "w": 300,
+ "h": 250
+ }]
+ }
+ ]
+ }
+ }
+ }
+ ],
+
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "123456789abcdef",
+ "impid": "test-imp-id",
+ "price": 0.5,
+ "adm": "test
",
+ "adid": "adid12345",
+ "crid": "abcdef123456789",
+ "w": 300,
+ "h": 250
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/adapters/eplanning/eplanningtest/supplemental/bid-with-2-nodes-schain.json b/adapters/eplanning/eplanningtest/supplemental/bid-with-2-nodes-schain.json
new file mode 100644
index 00000000000..0a6276ce1a9
--- /dev/null
+++ b/adapters/eplanning/eplanningtest/supplemental/bid-with-2-nodes-schain.json
@@ -0,0 +1,101 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "source": {
+ "ext": {
+ "schain": {
+ "ver": "1.0",
+ "complete": 1,
+ "nodes": [
+ {
+ "asi": "exchange1.com",
+ "sid": "1234",
+ "hp": 1,
+ "ext": "text"
+ },
+ {
+ "asi":"exchange2.com",
+ "sid":"abcd",
+ "hp":3,
+ "rid":"bid-request-2",
+ "domain":"intermediary.com"
+ }
+ ]
+ }
+ }
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "ci": "12345"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://rtb.e-planning.net/pbs/1/12345/1/FILE/ROS?e=300x250%3A300x250&ncb=1&sch=1.0%2C1%21exchange1.com%2C1234%2C1%2C%2C%2C%2C%2522text%2522%21exchange2.com%2Cabcd%2C3%2Cbid-request-2%2C%2Cintermediary.com%2C&ur=FILE",
+ "body": {},
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "sI": { "k": "12345" },
+ "sec": "ROS",
+ "sp": [
+ {
+ "k": "300x250",
+ "a": [{
+ "i": "123456789abcdef",
+ "pr": "0.5",
+ "adm": "test
",
+ "crid": "abcdef123456789",
+ "id": "adid12345",
+ "w": 300,
+ "h": 250
+ }]
+ }
+ ]
+ }
+ }
+ }
+ ],
+
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "123456789abcdef",
+ "impid": "test-imp-id",
+ "price": 0.5,
+ "adm": "test
",
+ "adid": "adid12345",
+ "crid": "abcdef123456789",
+ "w": 300,
+ "h": 250
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/adapters/eplanning/eplanningtest/supplemental/bid-with-3-nodes-schain.json b/adapters/eplanning/eplanningtest/supplemental/bid-with-3-nodes-schain.json
new file mode 100644
index 00000000000..84fef06a92e
--- /dev/null
+++ b/adapters/eplanning/eplanningtest/supplemental/bid-with-3-nodes-schain.json
@@ -0,0 +1,106 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "source": {
+ "ext": {
+ "schain": {
+ "ver": "1.0",
+ "complete": 1,
+ "nodes": [
+ {
+ "asi": "exchange1.com",
+ "sid": "1234",
+ "hp": 1,
+ "ext": "text"
+ },
+ {
+ "asi": "exchange2.com",
+ "sid": "abcd",
+ "hp": 1,
+ "ext": 1
+ },
+ {
+ "asi": "exchange3.com",
+ "sid": "abcdf",
+ "hp": 1,
+ "ext": 1
+ }
+ ]
+ }
+ }
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "ci": "12345"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://rtb.e-planning.net/pbs/1/12345/1/FILE/ROS?e=300x250%3A300x250&ncb=1&ur=FILE",
+ "body": {},
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "sI": { "k": "12345" },
+ "sec": "ROS",
+ "sp": [
+ {
+ "k": "300x250",
+ "a": [{
+ "i": "123456789abcdef",
+ "pr": "0.5",
+ "adm": "test
",
+ "crid": "abcdef123456789",
+ "id": "adid12345",
+ "w": 300,
+ "h": 250
+ }]
+ }
+ ]
+ }
+ }
+ }
+ ],
+
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "123456789abcdef",
+ "impid": "test-imp-id",
+ "price": 0.5,
+ "adm": "test
",
+ "adid": "adid12345",
+ "crid": "abcdef123456789",
+ "w": 300,
+ "h": 250
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/adapters/eplanning/eplanningtest/supplemental/bid-with-schain-slim.json b/adapters/eplanning/eplanningtest/supplemental/bid-with-schain-slim.json
new file mode 100644
index 00000000000..83ad385b3ac
--- /dev/null
+++ b/adapters/eplanning/eplanningtest/supplemental/bid-with-schain-slim.json
@@ -0,0 +1,94 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "source": {
+ "ext": {
+ "schain": {
+ "ver": "1.0",
+ "complete": 1,
+ "nodes": [
+ {
+ "asi": "exchange1.com",
+ "sid": "1234",
+ "rid":"bid-request",
+ "name":"publisher1, Inc."
+ }
+ ]
+ }
+ }
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "ci": "12345"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://rtb.e-planning.net/pbs/1/12345/1/FILE/ROS?e=300x250%3A300x250&ncb=1&sch=1.0%2C1%21exchange1.com%2C1234%2C%2Cbid-request%2Cpublisher1%252C%2520Inc.%2C%2C&ur=FILE",
+ "body": {},
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "sI": { "k": "12345" },
+ "sec": "ROS",
+ "sp": [
+ {
+ "k": "300x250",
+ "a": [{
+ "i": "123456789abcdef",
+ "pr": "0.5",
+ "adm": "test
",
+ "crid": "abcdef123456789",
+ "id": "adid12345",
+ "w": 300,
+ "h": 250
+ }]
+ }
+ ]
+ }
+ }
+ }
+ ],
+
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "123456789abcdef",
+ "impid": "test-imp-id",
+ "price": 0.5,
+ "adm": "test
",
+ "adid": "adid12345",
+ "crid": "abcdef123456789",
+ "w": 300,
+ "h": 250
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/adapters/eplanning/eplanningtest/supplemental/bid-with-schain-unmarshal-error.json b/adapters/eplanning/eplanningtest/supplemental/bid-with-schain-unmarshal-error.json
new file mode 100644
index 00000000000..d371911ff7a
--- /dev/null
+++ b/adapters/eplanning/eplanningtest/supplemental/bid-with-schain-unmarshal-error.json
@@ -0,0 +1,38 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "source": {
+ "ext": {
+ "schain": ""
+ }
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "ci": "12345"
+ }
+ }
+ }
+ ]
+ },
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "cannot unmarshal openrtb_ext.ExtRequestPrebidSChain.SChain: expect { or n, but found ",
+ "comparison": "startswith"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/adapters/eplanning/eplanningtest/supplemental/bid-with-schain.json b/adapters/eplanning/eplanningtest/supplemental/bid-with-schain.json
new file mode 100644
index 00000000000..02b591625ba
--- /dev/null
+++ b/adapters/eplanning/eplanningtest/supplemental/bid-with-schain.json
@@ -0,0 +1,94 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "source": {
+ "ext": {
+ "schain": {
+ "ver": "1.0",
+ "complete": 1,
+ "nodes": [
+ {
+ "asi": "exchange1.com",
+ "sid": "1234",
+ "hp": 1,
+ "ext": "text"
+ }
+ ]
+ }
+ }
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "ci": "12345"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://rtb.e-planning.net/pbs/1/12345/1/FILE/ROS?e=300x250%3A300x250&ncb=1&sch=1.0%2C1%21exchange1.com%2C1234%2C1%2C%2C%2C%2C%2522text%2522&ur=FILE",
+ "body": {},
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "sI": { "k": "12345" },
+ "sec": "ROS",
+ "sp": [
+ {
+ "k": "300x250",
+ "a": [{
+ "i": "123456789abcdef",
+ "pr": "0.5",
+ "adm": "test
",
+ "crid": "abcdef123456789",
+ "id": "adid12345",
+ "w": 300,
+ "h": 250
+ }]
+ }
+ ]
+ }
+ }
+ }
+ ],
+
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "123456789abcdef",
+ "impid": "test-imp-id",
+ "price": 0.5,
+ "adm": "test
",
+ "adid": "adid12345",
+ "crid": "abcdef123456789",
+ "w": 300,
+ "h": 250
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
From 076912e5f4e0b8ef22d1b01bd7fd3272acdf249b Mon Sep 17 00:00:00 2001
From: Bugxyb
Date: Tue, 8 Apr 2025 22:20:30 +0800
Subject: [PATCH 31/40] Algorix: Add site support (#4265)
Co-authored-by: xunyunbo
---
.../exemplary/sample-banner-web.json | 98 ++++++++++++++++
.../exemplary/sample-native-web.json | 99 ++++++++++++++++
.../exemplary/sample-video-web.json | 106 ++++++++++++++++++
static/bidder-info/algorix.yaml | 5 +
4 files changed, 308 insertions(+)
create mode 100644 adapters/algorix/algorixtest/exemplary/sample-banner-web.json
create mode 100644 adapters/algorix/algorixtest/exemplary/sample-native-web.json
create mode 100644 adapters/algorix/algorixtest/exemplary/sample-video-web.json
diff --git a/adapters/algorix/algorixtest/exemplary/sample-banner-web.json b/adapters/algorix/algorixtest/exemplary/sample-banner-web.json
new file mode 100644
index 00000000000..5e4aef4196d
--- /dev/null
+++ b/adapters/algorix/algorixtest/exemplary/sample-banner-web.json
@@ -0,0 +1,98 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [{"w": 320, "h": 50}]
+ },
+ "ext": {
+ "bidder": {
+ "sid": "testSid",
+ "token": "testToken",
+ "region": "APAC"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ }
+ },
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://apac.xyz.test.com?sid=testSid&token=testToken",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id":"test-imp-id",
+ "banner": {
+ "format": [{"w": 320, "h": 50}],
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "sid": "testSid",
+ "token": "testToken",
+ "region": "APAC"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "seat": "ttx",
+ "bid": [{
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 0.5,
+ "adm": "some-ads",
+ "crid": "crid_testid"
+ }]
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 0.5,
+ "adm": "some-ads",
+ "crid": "crid_testid"
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/algorix/algorixtest/exemplary/sample-native-web.json b/adapters/algorix/algorixtest/exemplary/sample-native-web.json
new file mode 100644
index 00000000000..a6e35ed8660
--- /dev/null
+++ b/adapters/algorix/algorixtest/exemplary/sample-native-web.json
@@ -0,0 +1,99 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"context\":1,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":2,\"required\":1,\"title\":{\"len\":90}},{\"id\":6,\"required\":1,\"img\":{\"type\":3,\"wmin\":128,\"hmin\":128,\"mimes\":[\"image/jpg\",\"image/jpeg\",\"image/png\"]}},{\"id\":7,\"required\":1,\"data\":{\"type\":2,\"len\":120}}]}",
+ "ver": "1.2"
+ },
+ "ext": {
+ "bidder": {
+ "sid": "testSid",
+ "token": "testToken",
+ "placementId": "testPlacementId",
+ "appId": "testAppId"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ }
+ },
+ "httpcalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://xyz.test.com?sid=testSid&token=testToken",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "native": {
+ "request": "{\"ver\":\"1.2\",\"context\":1,\"plcmttype\":4,\"plcmtcnt\":1,\"assets\":[{\"id\":2,\"required\":1,\"title\":{\"len\":90}},{\"id\":6,\"required\":1,\"img\":{\"type\":3,\"wmin\":128,\"hmin\":128,\"mimes\":[\"image/jpg\",\"image/jpeg\",\"image/png\"]}},{\"id\":7,\"required\":1,\"data\":{\"type\":2,\"len\":120}}]}",
+ "ver": "1.2"
+ },
+ "ext": {
+ "bidder": {
+ "sid": "testSid",
+ "token": "testToken",
+ "placementId": "testPlacementId",
+ "appId": "testAppId"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "8400d766-58b3-47d4-80d7-6658b337d403",
+ "impid": "test-imp-id",
+ "price": 1.2,
+ "adm": "some ads",
+ "crid": "crid_testid"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "8400d766-58b3-47d4-80d7-6658b337d403",
+ "impid": "test-imp-id",
+ "price": 1.2,
+ "adm": "some ads",
+ "crid": "crid_testid"
+
+ },
+ "type": "native"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/algorix/algorixtest/exemplary/sample-video-web.json b/adapters/algorix/algorixtest/exemplary/sample-video-web.json
new file mode 100644
index 00000000000..c0ab947a5cd
--- /dev/null
+++ b/adapters/algorix/algorixtest/exemplary/sample-video-web.json
@@ -0,0 +1,106 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 320,
+ "h": 480,
+ "mimes": [
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "sid": "testSid",
+ "token": "testToken",
+ "placementId": "testPlacementId",
+ "appId": "testAppId"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ }
+ },
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://xyz.test.com?sid=testSid&token=testToken",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id":"test-imp-id",
+ "video": {
+ "w": 320,
+ "h": 480,
+ "mimes": [
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "sid": "testSid",
+ "token": "testToken",
+ "placementId": "testPlacementId",
+ "appId": "testAppId"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "seat": "ttx",
+ "bid": [{
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 1.2,
+ "adm": "some-ads",
+ "crid": "crid_testid"
+ }]
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+ "impid": "test-imp-id",
+ "price": 1.2,
+ "adm": "some-ads",
+ "crid": "crid_testid"
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
diff --git a/static/bidder-info/algorix.yaml b/static/bidder-info/algorix.yaml
index dc5f80a5ebd..f80fa26e981 100644
--- a/static/bidder-info/algorix.yaml
+++ b/static/bidder-info/algorix.yaml
@@ -8,3 +8,8 @@ capabilities:
- banner
- video
- native
+ site:
+ mediaTypes:
+ - banner
+ - video
+ - native
From e37a2e90999d46be1f42a1d01ae018243d45e990 Mon Sep 17 00:00:00 2001
From: Tommy Pettersen <42890605+TommyHPettersen@users.noreply.github.com>
Date: Tue, 8 Apr 2025 16:31:51 +0200
Subject: [PATCH 32/40] Kobler: Add app support (#4268)
Co-authored-by: acsbendi
---
.../exemplary/app-simple_banner.json | 134 ++++++++++++++++++
...le_banner.json => site-simple_banner.json} | 0
static/bidder-info/kobler.yaml | 3 +
3 files changed, 137 insertions(+)
create mode 100644 adapters/kobler/koblertest/exemplary/app-simple_banner.json
rename adapters/kobler/koblertest/exemplary/{simple_banner.json => site-simple_banner.json} (100%)
diff --git a/adapters/kobler/koblertest/exemplary/app-simple_banner.json b/adapters/kobler/koblertest/exemplary/app-simple_banner.json
new file mode 100644
index 00000000000..c81f33373e9
--- /dev/null
+++ b/adapters/kobler/koblertest/exemplary/app-simple_banner.json
@@ -0,0 +1,134 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "device": {
+ "devicetype": 2
+ },
+ "app": {
+ "publisher": {
+ "id": "123456789"
+ },
+ "cat": ["IAB22-1"],
+ "bundle": "com.app.some",
+ "name": "Some App",
+ "domain": "some-app.com",
+ "id": "123456789"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "tagid": "test",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 320,
+ "h": 100
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://fake.endpoint",
+ "body": {
+ "id": "test-request-id",
+ "device": {
+ "devicetype": 2
+ },
+ "app": {
+ "publisher": {
+ "id": "123456789"
+ },
+ "cat": ["IAB22-1"],
+ "bundle": "com.app.some",
+ "name": "Some App",
+ "domain": "some-app.com",
+ "id": "123456789"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "tagid": "test",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 320,
+ "h": 100
+ }
+ ]
+ }
+ }
+ ],
+ "cur": ["USD"]
+ },
+ "impIDs": ["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "test_bid_id",
+ "impid": "test-imp-id",
+ "price": 0.27543,
+ "adm": "",
+ "cid": "test_cid",
+ "crid": "test_crid",
+ "dealid": "test_dealid",
+ "w": 300,
+ "h": 250,
+ "ext": {
+ "prebid": {
+ "type": "banner"
+ }
+ }
+ }
+ ],
+ "seat": "kobler"
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "bids": [
+ {
+ "bid": {
+ "id": "test_bid_id",
+ "impid": "test-imp-id",
+ "price": 0.27543,
+ "adm": "",
+ "cid": "test_cid",
+ "crid": "test_crid",
+ "dealid": "test_dealid",
+ "w": 300,
+ "h": 250,
+ "ext": {
+ "prebid": {
+ "type": "banner"
+ }
+ }
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/kobler/koblertest/exemplary/simple_banner.json b/adapters/kobler/koblertest/exemplary/site-simple_banner.json
similarity index 100%
rename from adapters/kobler/koblertest/exemplary/simple_banner.json
rename to adapters/kobler/koblertest/exemplary/site-simple_banner.json
diff --git a/static/bidder-info/kobler.yaml b/static/bidder-info/kobler.yaml
index 8429aaa4bb2..8a090f8e342 100644
--- a/static/bidder-info/kobler.yaml
+++ b/static/bidder-info/kobler.yaml
@@ -10,3 +10,6 @@ capabilities:
site:
mediaTypes:
- banner
+ app:
+ mediaTypes:
+ - banner
From d9f894d0182ccb09c94e06793073b985f3145cbf Mon Sep 17 00:00:00 2001
From: Monis Qadri
Date: Tue, 8 Apr 2025 20:18:26 +0530
Subject: [PATCH 33/40] Medianet: Update codepath-notification email (#4276)
---
.github/workflows/scripts/codepath-notification | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/scripts/codepath-notification b/.github/workflows/scripts/codepath-notification
index 5a029531403..2c1bb0fb9be 100644
--- a/.github/workflows/scripts/codepath-notification
+++ b/.github/workflows/scripts/codepath-notification
@@ -16,4 +16,4 @@ rubicon: header-bidding@magnite.com
pubmatic: header-bidding@pubmatic.com
openx: prebid@openx.com
adapters/ix|imp_ix|ix.json|ix.yaml: pdu-supply-prebid@indexexchange.com
-medianet: prebid-support@media.net
+medianet: prebid@media.net
From a2a2bc67a829baf3c35159a5b9aa98e9dd07918c Mon Sep 17 00:00:00 2001
From: Jozef Bartek <31618107+jbartek25@users.noreply.github.com>
Date: Tue, 8 Apr 2025 17:01:28 +0200
Subject: [PATCH 34/40] Improve Digital: Add iframe user sync (#4274)
---
static/bidder-info/improvedigital.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/static/bidder-info/improvedigital.yaml b/static/bidder-info/improvedigital.yaml
index 4cd30d7c6b2..cb5ea798074 100644
--- a/static/bidder-info/improvedigital.yaml
+++ b/static/bidder-info/improvedigital.yaml
@@ -16,6 +16,9 @@ capabilities:
- audio
- native
userSync:
+ iframe:
+ url: "https://ad.360yield.com/user_sync?rt=html&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}"
+ userMacro: "{PUB_USER_ID}"
redirect:
url: "https://ad.360yield.com/server_match?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}"
userMacro: "{PUB_USER_ID}"
From fec52ab618c5d35bd122d563395fd3ae6d69aa56 Mon Sep 17 00:00:00 2001
From: Mikael Lundin
Date: Thu, 10 Apr 2025 19:14:11 +0200
Subject: [PATCH 35/40] Adnuntius: Add multi-format and native support (#4223)
---
adapters/adnuntius/adnuntius.go | 437 +++++-------------
adapters/adnuntius/adnuntius_types.go | 86 ++++
adapters/adnuntius/adnuntius_utils.go | 205 ++++++++
.../exemplary/simple-banner.json | 7 +-
.../exemplary/simple-native-banner.json | 139 ++++++
.../exemplary/simple-native.json | 97 ++++
.../supplemental/banner-nil-check.json | 29 --
.../supplemental/check-dealId.json | 7 +-
...heck-dsa-advertiser-legalName-omitted.json | 5 +-
.../check-dsa-advertiser-legalName.json | 5 +-
.../check-dsa-advertiser-omitted.json | 5 +-
.../supplemental/check-gdpr.json | 5 +-
.../supplemental/check-gross-bids.json | 5 +-
.../supplemental/check-native-error.json | 80 ++++
.../supplemental/check-net-bids.json | 5 +-
.../check-noCookies-parameter.json | 5 +-
.../supplemental/check-noCookies.json | 7 +-
.../supplemental/check-order-multi-imp.json | 14 +-
.../supplemental/check-userId.json | 5 +-
.../supplemental/empty-regs-ext.json | 5 +-
.../supplemental/empty-regs.json | 5 +-
.../supplemental/height-error.json | 4 +-
.../supplemental/invalid-regs-ext.json | 2 +-
.../supplemental/max-deals-test.json | 5 +-
.../supplemental/native-error.json | 24 -
.../supplemental/send-header-information.json | 5 +-
.../adnuntiustest/supplemental/site-ext.json | 5 +-
.../supplemental/size-check.json | 5 +-
.../supplemental/status-400.json | 3 +-
.../supplemental/test-networks.json | 9 +-
.../supplemental/user-ext-invalid.json | 37 ++
.../adnuntiustest/supplemental/user-ext.json | 7 +-
.../supplemental/video-error.json | 8 +-
.../supplemental/width-error.json | 3 +-
static/bidder-info/adnuntius.yaml | 2 +
35 files changed, 876 insertions(+), 401 deletions(-)
create mode 100644 adapters/adnuntius/adnuntius_types.go
create mode 100644 adapters/adnuntius/adnuntius_utils.go
create mode 100644 adapters/adnuntius/adnuntiustest/exemplary/simple-native-banner.json
create mode 100644 adapters/adnuntius/adnuntiustest/exemplary/simple-native.json
delete mode 100644 adapters/adnuntius/adnuntiustest/supplemental/banner-nil-check.json
create mode 100644 adapters/adnuntius/adnuntiustest/supplemental/check-native-error.json
delete mode 100644 adapters/adnuntius/adnuntiustest/supplemental/native-error.json
create mode 100644 adapters/adnuntius/adnuntiustest/supplemental/user-ext-invalid.json
diff --git a/adapters/adnuntius/adnuntius.go b/adapters/adnuntius/adnuntius.go
index 53736627d90..c1a929a7846 100644
--- a/adapters/adnuntius/adnuntius.go
+++ b/adapters/adnuntius/adnuntius.go
@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"net/http"
- "net/url"
+
"strconv"
"strings"
@@ -18,80 +18,6 @@ import (
"github.com/prebid/prebid-server/v3/util/timeutil"
)
-type QueryString map[string]string
-type adapter struct {
- time timeutil.Time
- endpoint string
- extraInfo string
-}
-type adnAdunit struct {
- AuId string `json:"auId"`
- TargetId string `json:"targetId"`
- Dimensions [][]int64 `json:"dimensions,omitempty"`
- MaxDeals int `json:"maxDeals,omitempty"`
-}
-
-type extDeviceAdnuntius struct {
- NoCookies bool `json:"noCookies,omitempty"`
-}
-type siteExt struct {
- Data interface{} `json:"data"`
-}
-
-type adnAdvertiser struct {
- LegalName string `json:"legalName,omitempty"`
- Name string `json:"name,omitempty"`
-}
-
-type Ad struct {
- Bid struct {
- Amount float64
- Currency string
- }
- NetBid struct {
- Amount float64
- }
- GrossBid struct {
- Amount float64
- }
- DealID string `json:"dealId,omitempty"`
- AdId string
- CreativeWidth string
- CreativeHeight string
- CreativeId string
- LineItemId string
- Html string
- DestinationUrls map[string]string
- AdvertiserDomains []string
- Advertiser adnAdvertiser `json:"advertiser,omitempty"`
-}
-
-type AdUnit struct {
- AuId string
- TargetId string
- Html string
- ResponseId string
- Ads []Ad
- Deals []Ad `json:"deals,omitempty"`
-}
-
-type AdnResponse struct {
- AdUnits []AdUnit
-}
-type adnMetaData struct {
- Usi string `json:"usi,omitempty"`
-}
-type adnRequest struct {
- AdUnits []adnAdunit `json:"adUnits"`
- MetaData adnMetaData `json:"metaData,omitempty"`
- Context string `json:"context,omitempty"`
- KeyValues interface{} `json:"kv,omitempty"`
-}
-
-type RequestExt struct {
- Bidder adnAdunit `json:"bidder"`
-}
-
const defaultNetwork = "default"
const defaultSite = "unknown"
const minutesInHour = 60
@@ -111,106 +37,13 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
return a.generateRequests(*request)
}
-func setHeaders(ortbRequest openrtb2.BidRequest) http.Header {
-
- headers := http.Header{}
- headers.Add("Content-Type", "application/json;charset=utf-8")
- headers.Add("Accept", "application/json")
- if ortbRequest.Device != nil {
- if ortbRequest.Device.IP != "" {
- headers.Add("X-Forwarded-For", ortbRequest.Device.IP)
- }
- if ortbRequest.Device.UA != "" {
- headers.Add("user-agent", ortbRequest.Device.UA)
- }
- }
- return headers
-}
-
-func makeEndpointUrl(ortbRequest openrtb2.BidRequest, a *adapter, noCookies bool) (string, []error) {
- uri, err := url.Parse(a.endpoint)
- endpointUrl := a.endpoint
- if err != nil {
- return "", []error{fmt.Errorf("failed to parse Adnuntius endpoint: %v", err)}
- }
-
- gdpr, consent, err := getGDPR(&ortbRequest)
- if err != nil {
- return "", []error{fmt.Errorf("failed to parse Adnuntius endpoint: %v", err)}
- }
-
- if !noCookies {
- var deviceExt extDeviceAdnuntius
- if ortbRequest.Device != nil && ortbRequest.Device.Ext != nil {
- if err := jsonutil.Unmarshal(ortbRequest.Device.Ext, &deviceExt); err != nil {
- return "", []error{fmt.Errorf("failed to parse Adnuntius endpoint: %v", err)}
- }
- }
-
- if deviceExt.NoCookies {
- noCookies = true
- }
- }
-
- _, offset := a.time.Now().Zone()
- tzo := -offset / minutesInHour
-
- q := uri.Query()
- if gdpr != "" {
- endpointUrl = a.extraInfo
- q.Set("gdpr", gdpr)
- }
-
- if consent != "" {
- q.Set("consentString", consent)
- }
-
- if noCookies {
- q.Set("noCookies", "true")
- }
-
- q.Set("tzo", fmt.Sprint(tzo))
- q.Set("format", "prebidServer")
-
- url := endpointUrl + "?" + q.Encode()
- return url, nil
-}
-
-func getImpSizes(imp openrtb2.Imp) [][]int64 {
-
- if len(imp.Banner.Format) > 0 {
- sizes := make([][]int64, len(imp.Banner.Format))
- for i, format := range imp.Banner.Format {
- sizes[i] = []int64{format.W, format.H}
- }
-
- return sizes
- }
-
- if imp.Banner.W != nil && imp.Banner.H != nil {
- size := make([][]int64, 1)
- size[0] = []int64{*imp.Banner.W, *imp.Banner.H}
- return size
- }
-
- return nil
-}
-
-/*
-Generate the requests to Adnuntius to reduce the amount of requests going out.
-*/
func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters.RequestData, []error) {
var requestData []*adapters.RequestData
- networkAdunitMap := make(map[string][]adnAdunit)
+ networkAdunitMap := make(map[string][]adnRequestAdunit)
headers := setHeaders(ortbRequest)
var noCookies bool = false
for _, imp := range ortbRequest.Imp {
- if imp.Banner == nil {
- return nil, []error{&errortypes.BadInput{
- Message: fmt.Sprintf("ignoring imp id=%s, Adnuntius supports only Banner", imp.ID),
- }}
- }
var bidderExt adapters.ExtImpBidder
if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil {
@@ -218,7 +51,6 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters
Message: fmt.Sprintf("Error unmarshalling ExtImpBidder: %s", err.Error()),
}}
}
-
var adnuntiusExt openrtb_ext.ImpExtAdnunitus
if err := jsonutil.Unmarshal(bidderExt.Bidder, &adnuntiusExt); err != nil {
return nil, []error{&errortypes.BadInput{
@@ -235,17 +67,39 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters
network = adnuntiusExt.Network
}
- adUnit := adnAdunit{
- AuId: adnuntiusExt.Auid,
- TargetId: fmt.Sprintf("%s-%s", adnuntiusExt.Auid, imp.ID),
- Dimensions: getImpSizes(imp),
+ // Remove when we support video.
+ if imp.Video != nil {
+ return nil, []error{&errortypes.BadInput{
+ Message: fmt.Sprintf("ignoring imp id=%s, Adnuntius supports only native and banner", imp.ID),
+ }}
+ }
+
+ if imp.Banner != nil {
+ adUnit := generateAdUnit(imp, adnuntiusExt, "banner")
+ adUnit.AdType = ""
+
+ networkAdunitMap[network] = append(
+ networkAdunitMap[network],
+ adUnit)
}
- if adnuntiusExt.MaxDeals > 0 {
- adUnit.MaxDeals = adnuntiusExt.MaxDeals
+
+ if imp.Native != nil {
+ adUnit := generateAdUnit(imp, adnuntiusExt, "native")
+ adUnit.AdType = "NATIVE"
+ nativeRequest := json.RawMessage{}
+
+ if err := jsonutil.Unmarshal([]byte(imp.Native.Request), &nativeRequest); err != nil {
+ return nil, []error{&errortypes.BadInput{
+ Message: fmt.Sprintf("Error unmarshalling Native: %s", err.Error()),
+ }}
+ }
+
+ adUnit.NativeRequest.Ortb = nativeRequest
+ networkAdunitMap[network] = append(
+ networkAdunitMap[network],
+ adUnit)
}
- networkAdunitMap[network] = append(
- networkAdunitMap[network],
- adUnit)
+
}
endpoint, err := makeEndpointUrl(ortbRequest, a, noCookies)
@@ -260,11 +114,18 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters
site = ortbRequest.Site.Page
}
- extSite, erro := getSiteExtAsKv(&ortbRequest)
- if erro != nil {
+ extSite, err := getSiteExtAsKv(&ortbRequest)
+ if err != nil {
return nil, []error{fmt.Errorf("failed to parse site Ext: %v", err)}
}
+ var extUser openrtb_ext.ExtUser
+ if ortbRequest.User != nil && ortbRequest.User.Ext != nil {
+ if err := jsonutil.Unmarshal(ortbRequest.User.Ext, &extUser); err != nil {
+ return nil, []error{fmt.Errorf("failed to parse Ext User: %v", err)}
+ }
+ }
+
for _, networkAdunits := range networkAdunitMap {
adnuntiusRequest := adnRequest{
@@ -273,13 +134,6 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters
KeyValues: extSite.Data,
}
- var extUser openrtb_ext.ExtUser
- if ortbRequest.User != nil && ortbRequest.User.Ext != nil {
- if err := jsonutil.Unmarshal(ortbRequest.User.Ext, &extUser); err != nil {
- return nil, []error{fmt.Errorf("failed to parse Ext User: %v", err)}
- }
- }
-
// Will change when our adserver can accept multiple user IDS
if extUser.Eids != nil && len(extUser.Eids) > 0 {
if len(extUser.Eids[0].UIDs) > 0 {
@@ -316,7 +170,6 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters
}
func (a *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
-
if response.StatusCode == http.StatusBadRequest {
return nil, []error{&errortypes.BadInput{
Message: fmt.Sprintf("Status code: %d, Request malformed", response.StatusCode),
@@ -342,107 +195,127 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapte
return bidResponse, nil
}
-func getSiteExtAsKv(request *openrtb2.BidRequest) (siteExt, error) {
- var extSite siteExt
- if request.Site != nil && request.Site.Ext != nil {
- if err := jsonutil.Unmarshal(request.Site.Ext, &extSite); err != nil {
- return extSite, fmt.Errorf("failed to parse ExtSite in Adnuntius: %v", err)
+func generateBidResponse(adnResponse *AdnResponse, request *openrtb2.BidRequest) (*adapters.BidderResponse, []error) {
+ bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(adnResponse.AdUnits))
+ var currency string
+ adunitMap := map[string]AdUnit{}
+ adunitMediaTypeMap := map[string][]AdUnit{}
+
+ /* Check the ad unit response to see if there are any multi ad */
+ for _, adnRespAdunit := range adnResponse.AdUnits {
+ result := strings.Split(adnRespAdunit.TargetId, ":")
+ if adnRespAdunit.MatchedAdCount > 0 {
+ adunitMediaTypeMap[result[0]] = append(adunitMediaTypeMap[result[0]], adnRespAdunit)
}
}
- return extSite, nil
-}
-func getGDPR(request *openrtb2.BidRequest) (string, string, error) {
-
- gdpr := ""
- var extRegs openrtb_ext.ExtRegs
- if request.Regs != nil && request.Regs.Ext != nil {
- if err := jsonutil.Unmarshal(request.Regs.Ext, &extRegs); err != nil {
- return "", "", fmt.Errorf("failed to parse ExtRegs in Adnuntius GDPR check: %v", err)
- }
- if extRegs.GDPR != nil && (*extRegs.GDPR == 0 || *extRegs.GDPR == 1) {
- gdpr = strconv.Itoa(int(*extRegs.GDPR))
+ /* Compare price if there are multiple media types */
+ for targetId, mappedAdunit := range adunitMediaTypeMap {
+ highestBidAtIndex := 0
+ if len(mappedAdunit) > 1 {
+ for index := range mappedAdunit {
+ if mappedAdunit[index].Ads[0].Bid.Amount > mappedAdunit[highestBidAtIndex].Ads[0].Bid.Amount {
+ highestBidAtIndex = index
+ }
+ }
}
+ adunitMap[targetId] = mappedAdunit[highestBidAtIndex]
}
- consent := ""
- if request.User != nil && request.User.Ext != nil {
- var extUser openrtb_ext.ExtUser
- if err := jsonutil.Unmarshal(request.User.Ext, &extUser); err != nil {
- return "", "", fmt.Errorf("failed to parse ExtUser in Adnuntius GDPR check: %v", err)
+ for _, imp := range request.Imp {
+
+ auId, _, _, err := jsonparser.Get(imp.Ext, "bidder", "auId")
+ if err != nil {
+ return nil, []error{&errortypes.BadInput{
+ Message: fmt.Sprintf("Error at Bidder auId: %s", err.Error()),
+ }}
}
- consent = extUser.Consent
- }
- return gdpr, consent, nil
-}
+ targetID := fmt.Sprintf("%s-%s", string(auId), imp.ID)
-func generateReturnExt(ad Ad, request *openrtb2.BidRequest) (json.RawMessage, error) {
- // We always force the publisher to render
- var adRender int8 = 0
+ adunit := adunitMap[targetID]
- var requestRegsExt *openrtb_ext.ExtRegs
- if request.Regs != nil && request.Regs.Ext != nil {
- if err := jsonutil.Unmarshal(request.Regs.Ext, &requestRegsExt); err != nil {
+ if len(adunit.Ads) > 0 {
- return nil, fmt.Errorf("Failed to parse Ext information in Adnuntius: %v", err)
- }
- }
+ ad := adunit.Ads[0]
+ html := adunit.Html
+ var mType openrtb2.MarkupType = openrtb2.MarkupBanner
+ var native []byte
- if ad.Advertiser.Name != "" && requestRegsExt != nil && requestRegsExt.DSA != nil {
- legalName := ad.Advertiser.Name
- if ad.Advertiser.LegalName != "" {
- legalName = ad.Advertiser.LegalName
- }
- ext := &openrtb_ext.ExtBid{
- DSA: &openrtb_ext.ExtBidDSA{
- AdRender: &adRender,
- Paid: legalName,
- Behalf: legalName,
- },
- }
- returnExt, err := json.Marshal(ext)
- if err != nil {
- return nil, fmt.Errorf("Failed to parse Ext information in Adnuntius: %v", err)
- }
+ currency = ad.Bid.Currency
+ if adunit.NativeJson != nil {
+ nativeJson, _, _, nativeErr := jsonparser.Get(adunit.NativeJson, "ortb")
+ if nativeErr != nil {
+ return nil, []error{&errortypes.BadServerResponse{
+ Message: fmt.Sprintf("Failed to parse native json where imp id=%s", imp.ID),
+ }}
+ }
+ native = nativeJson
+ }
+
+ if native != nil {
+ html = string(native)
+ mType = openrtb2.MarkupNative
+ }
+
+ adBid, err := generateAdResponse(ad, imp, html, mType, request)
+ if err != nil {
+ return nil, err
+ }
- return returnExt, nil
+ bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+ Bid: adBid,
+ BidType: convertMarkupTypeToBidType(mType),
+ })
+
+ for _, deal := range adunit.Deals {
+ mType = 1
+ dealBid, err := generateAdResponse(deal, imp, deal.Html, mType, request)
+ if err != nil {
+ return nil, err
+ }
+
+ bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+ Bid: dealBid,
+ BidType: convertMarkupTypeToBidType(mType),
+ })
+ }
+ }
}
- return nil, nil
+ bidResponse.Currency = currency
+ return bidResponse, nil
}
-func generateAdResponse(ad Ad, imp openrtb2.Imp, html string, request *openrtb2.BidRequest) (*openrtb2.Bid, []error) {
-
+func generateAdResponse(ad Ad, imp openrtb2.Imp, html string, mType openrtb2.MarkupType, request *openrtb2.BidRequest) (*openrtb2.Bid, []error) {
creativeWidth, widthErr := strconv.ParseInt(ad.CreativeWidth, 10, 64)
if widthErr != nil {
- return nil, []error{&errortypes.BadInput{
+ return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("Value of width: %s is not a string", ad.CreativeWidth),
}}
}
creativeHeight, heightErr := strconv.ParseInt(ad.CreativeHeight, 10, 64)
if heightErr != nil {
- return nil, []error{&errortypes.BadInput{
+ return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("Value of height: %s is not a string", ad.CreativeHeight),
}}
}
- price := ad.Bid.Amount
-
var bidderExt adapters.ExtImpBidder
if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil {
- return nil, []error{&errortypes.BadInput{
+ return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("Error unmarshalling ExtImpBidder: %s", err.Error()),
}}
}
var adnuntiusExt openrtb_ext.ImpExtAdnunitus
if err := jsonutil.Unmarshal(bidderExt.Bidder, &adnuntiusExt); err != nil {
- return nil, []error{&errortypes.BadInput{
+ return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("Error unmarshalling ExtImpValues: %s", err.Error()),
}}
}
+ price := ad.Bid.Amount
if adnuntiusExt.BidType != "" {
if strings.EqualFold(string(adnuntiusExt.BidType), "net") {
price = ad.NetBid.Amount
@@ -454,7 +327,7 @@ func generateAdResponse(ad Ad, imp openrtb2.Imp, html string, request *openrtb2.
extJson, err := generateReturnExt(ad, request)
if err != nil {
- return nil, []error{&errortypes.BadInput{
+ return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("Error extracting Ext: %s", err.Error()),
}}
}
@@ -470,68 +343,10 @@ func generateAdResponse(ad Ad, imp openrtb2.Imp, html string, request *openrtb2.
CrID: ad.CreativeId,
Price: price * 1000,
AdM: html,
+ MType: mType,
ADomain: ad.AdvertiserDomains,
Ext: extJson,
}
- return &bid, nil
-
-}
-
-func generateBidResponse(adnResponse *AdnResponse, request *openrtb2.BidRequest) (*adapters.BidderResponse, []error) {
- bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(adnResponse.AdUnits))
- var currency string
- adunitMap := map[string]AdUnit{}
-
- for _, adnRespAdunit := range adnResponse.AdUnits {
- adunitMap[adnRespAdunit.TargetId] = adnRespAdunit
- }
-
- for _, imp := range request.Imp {
-
- auId, _, _, err := jsonparser.Get(imp.Ext, "bidder", "auId")
- if err != nil {
- return nil, []error{&errortypes.BadInput{
- Message: fmt.Sprintf("Error at Bidder auId: %s", err.Error()),
- }}
- }
-
- targetID := fmt.Sprintf("%s-%s", string(auId), imp.ID)
- adunit := adunitMap[targetID]
-
- if len(adunit.Ads) > 0 {
-
- ad := adunit.Ads[0]
- currency = ad.Bid.Currency
- adBid, err := generateAdResponse(ad, imp, adunit.Html, request)
- if err != nil {
- return nil, []error{&errortypes.BadInput{
- Message: "Error at ad generation",
- }}
- }
-
- bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
- Bid: adBid,
- BidType: "banner",
- })
-
- for _, deal := range adunit.Deals {
- dealBid, err := generateAdResponse(deal, imp, deal.Html, request)
- if err != nil {
- return nil, []error{&errortypes.BadInput{
- Message: "Error at ad generation",
- }}
- }
-
- bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
- Bid: dealBid,
- BidType: "banner",
- })
- }
-
- }
-
- }
- bidResponse.Currency = currency
- return bidResponse, nil
+ return &bid, nil
}
diff --git a/adapters/adnuntius/adnuntius_types.go b/adapters/adnuntius/adnuntius_types.go
new file mode 100644
index 00000000000..17d81cd6a03
--- /dev/null
+++ b/adapters/adnuntius/adnuntius_types.go
@@ -0,0 +1,86 @@
+package adnuntius
+
+import (
+ "encoding/json"
+
+ "github.com/prebid/prebid-server/v3/util/timeutil"
+)
+
+type QueryString map[string]string
+type adapter struct {
+ time timeutil.Time
+ endpoint string
+ extraInfo string
+}
+
+type NativeRequest struct {
+ Ortb json.RawMessage `json:"ortb,omitempty"`
+}
+
+type adnRequestAdunit struct {
+ AuId string `json:"auId"`
+ TargetId string `json:"targetId"`
+ AdType string `json:"adType,omitempty"`
+ NativeRequest NativeRequest `json:"nativeRequest,omitempty"`
+ Dimensions [][]int64 `json:"dimensions,omitempty"`
+ MaxDeals int `json:"maxDeals,omitempty"`
+}
+
+type extDeviceAdnuntius struct {
+ NoCookies bool `json:"noCookies,omitempty"`
+}
+type siteExt struct {
+ Data interface{} `json:"data"`
+}
+
+type adnAdvertiser struct {
+ LegalName string `json:"legalName,omitempty"`
+ Name string `json:"name,omitempty"`
+}
+
+type Ad struct {
+ Bid struct {
+ Amount float64
+ Currency string
+ }
+ NetBid struct {
+ Amount float64
+ }
+ GrossBid struct {
+ Amount float64
+ }
+ DealID string `json:"dealId,omitempty"`
+ AdId string
+ CreativeWidth string
+ CreativeHeight string
+ CreativeId string
+ LineItemId string
+ Html string
+ DestinationUrls map[string]string
+ AdvertiserDomains []string
+ Advertiser adnAdvertiser `json:"advertiser,omitempty"`
+}
+
+type AdUnit struct {
+ AuId string
+ TargetId string
+ Html string
+ MatchedAdCount int
+ ResponseId string
+ NativeJson json.RawMessage `json:"nativeJson,omitempty"`
+ Ads []Ad
+ Deals []Ad `json:"deals,omitempty"`
+}
+
+type AdnResponse struct {
+ AdUnits []AdUnit
+}
+type adnMetaData struct {
+ Usi string `json:"usi,omitempty"`
+}
+type adnRequest struct {
+ AdUnits []adnRequestAdunit `json:"adUnits"`
+ MetaData adnMetaData `json:"metaData,omitempty"`
+ Context string `json:"context,omitempty"`
+ KeyValues interface{} `json:"kv,omitempty"`
+}
diff --git a/adapters/adnuntius/adnuntius_utils.go b/adapters/adnuntius/adnuntius_utils.go
new file mode 100644
index 00000000000..ebbd7a80055
--- /dev/null
+++ b/adapters/adnuntius/adnuntius_utils.go
@@ -0,0 +1,205 @@
+package adnuntius
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strconv"
+
+ "github.com/prebid/openrtb/v20/openrtb2"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+ "github.com/prebid/prebid-server/v3/util/jsonutil"
+)
+
+type RequestExt struct {
+ Bidder adnRequestAdunit `json:"bidder"`
+}
+
+func setHeaders(ortbRequest openrtb2.BidRequest) http.Header {
+
+ headers := http.Header{}
+ headers.Add("Content-Type", "application/json;charset=utf-8")
+ headers.Add("Accept", "application/json")
+ if ortbRequest.Device != nil {
+ if ortbRequest.Device.IP != "" {
+ headers.Add("X-Forwarded-For", ortbRequest.Device.IP)
+ }
+ if ortbRequest.Device.UA != "" {
+ headers.Add("user-agent", ortbRequest.Device.UA)
+ }
+ }
+ return headers
+}
+
+func makeEndpointUrl(ortbRequest openrtb2.BidRequest, a *adapter, noCookies bool) (string, []error) {
+ uri, err := url.Parse(a.endpoint)
+ if err != nil {
+ return "", []error{fmt.Errorf("failed to parse Adnuntius endpoint: %v", err)}
+ }
+
+ gdpr, consent, err := getGDPR(&ortbRequest)
+ if err != nil {
+ return "", []error{fmt.Errorf("failed to parse GDPR information: %v", err)}
+ }
+
+ if gdpr != "" {
+ extraInfoURI, err := url.Parse(a.extraInfo)
+ if err != nil {
+ return "", []error{fmt.Errorf("invalid extraInfo URL: %v", err)}
+ }
+ uri = extraInfoURI
+ }
+
+ if !noCookies {
+ var deviceExt extDeviceAdnuntius
+ if ortbRequest.Device != nil && ortbRequest.Device.Ext != nil {
+ if err := jsonutil.Unmarshal(ortbRequest.Device.Ext, &deviceExt); err != nil {
+ return "", []error{fmt.Errorf("failed to parse device ext: %v", err)}
+ }
+ }
+
+ if deviceExt.NoCookies {
+ noCookies = true
+ }
+ }
+
+ _, offset := a.time.Now().Zone()
+ tzo := -offset / minutesInHour
+
+ q := uri.Query()
+ if gdpr != "" {
+ q.Set("gdpr", gdpr)
+ }
+
+ if consent != "" {
+ q.Set("consentString", consent)
+ }
+
+ if noCookies {
+ q.Set("noCookies", "true")
+ }
+
+ q.Set("tzo", strconv.Itoa(tzo))
+ q.Set("format", "prebidServer")
+
+ // Set the query params to the URI
+ uri.RawQuery = q.Encode()
+
+ // Return the correctly formatted URL
+ return uri.String(), nil
+}
+
+func getImpSizes(imp openrtb2.Imp, bidType string) [][]int64 {
+ if bidType == "banner" {
+ if imp.Banner != nil {
+ if len(imp.Banner.Format) > 0 {
+ sizes := make([][]int64, len(imp.Banner.Format))
+ for i, format := range imp.Banner.Format {
+ sizes[i] = []int64{format.W, format.H}
+ }
+
+ return sizes
+ } else if imp.Banner.W != nil && imp.Banner.H != nil {
+ size := make([][]int64, 1)
+ size[0] = []int64{*imp.Banner.W, *imp.Banner.H}
+ return size
+ }
+ }
+ }
+
+ return nil
+}
+
+func getSiteExtAsKv(request *openrtb2.BidRequest) (siteExt, []error) {
+ var extSite siteExt
+ if request.Site != nil && request.Site.Ext != nil {
+ if err := jsonutil.Unmarshal(request.Site.Ext, &extSite); err != nil {
+ return extSite, []error{fmt.Errorf("failed to parse site ext in Adnuntius: %v", err)}
+ }
+ }
+ return extSite, nil
+}
+
+func getGDPR(request *openrtb2.BidRequest) (string, string, error) {
+
+ gdpr := ""
+ var extRegs openrtb_ext.ExtRegs
+ if request.Regs != nil && request.Regs.Ext != nil {
+ if err := jsonutil.Unmarshal(request.Regs.Ext, &extRegs); err != nil {
+ return "", "", fmt.Errorf("failed to parse ExtRegs in Adnuntius GDPR check: %v", err)
+ }
+ if extRegs.GDPR != nil && (*extRegs.GDPR == 0 || *extRegs.GDPR == 1) {
+ gdpr = strconv.Itoa(int(*extRegs.GDPR))
+ }
+ }
+
+ consent := ""
+ if request.User != nil && request.User.Ext != nil {
+ var extUser openrtb_ext.ExtUser
+ if err := jsonutil.Unmarshal(request.User.Ext, &extUser); err != nil {
+ return "", "", fmt.Errorf("failed to parse ExtUser in Adnuntius GDPR check: %v", err)
+ }
+ consent = extUser.Consent
+ }
+
+ return gdpr, consent, nil
+}
+
+func generateReturnExt(ad Ad, request *openrtb2.BidRequest) (json.RawMessage, error) {
+ // We always force the publisher to render
+ var adRender int8 = 0
+
+ var requestRegsExt *openrtb_ext.ExtRegs
+ if request.Regs != nil && request.Regs.Ext != nil {
+ if err := jsonutil.Unmarshal(request.Regs.Ext, &requestRegsExt); err != nil {
+
+ return nil, fmt.Errorf("Failed to parse Ext information in Adnuntius: %v", err)
+ }
+ }
+
+ if ad.Advertiser.Name != "" && requestRegsExt != nil && requestRegsExt.DSA != nil {
+ legalName := ad.Advertiser.Name
+ if ad.Advertiser.LegalName != "" {
+ legalName = ad.Advertiser.LegalName
+ }
+ ext := &openrtb_ext.ExtBid{
+ DSA: &openrtb_ext.ExtBidDSA{
+ AdRender: &adRender,
+ Paid: legalName,
+ Behalf: legalName,
+ },
+ }
+
+ returnExt, err := jsonutil.Marshal(ext)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to parse Ext information in Adnuntius: %v", err)
+ }
+
+ return returnExt, nil
+ }
+ return nil, nil
+}
+
+func generateAdUnit(imp openrtb2.Imp, adnuntiusExt openrtb_ext.ImpExtAdnunitus, bidType string) adnRequestAdunit {
+ adUnit := adnRequestAdunit{
+ AuId: adnuntiusExt.Auid,
+ TargetId: fmt.Sprintf("%s-%s:%s", adnuntiusExt.Auid, imp.ID, bidType),
+ Dimensions: getImpSizes(imp, bidType),
+ }
+
+ if adnuntiusExt.MaxDeals > 0 {
+ adUnit.MaxDeals = adnuntiusExt.MaxDeals
+ }
+ return adUnit
+}
+
+func convertMarkupTypeToBidType(markupType openrtb2.MarkupType) openrtb_ext.BidType {
+ switch markupType {
+ case openrtb2.MarkupBanner:
+ return openrtb_ext.BidTypeBanner
+ case openrtb2.MarkupNative:
+ return openrtb_ext.BidTypeNative
+ }
+ return openrtb_ext.BidTypeBanner
+}
diff --git a/adapters/adnuntius/adnuntiustest/exemplary/simple-banner.json b/adapters/adnuntius/adnuntiustest/exemplary/simple-banner.json
index 1358d08a518..ae5389176fc 100644
--- a/adapters/adnuntius/adnuntiustest/exemplary/simple-banner.json
+++ b/adapters/adnuntius/adnuntiustest/exemplary/simple-banner.json
@@ -36,7 +36,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -51,7 +52,8 @@
"adUnits": [
{
"auId": "0000000000000123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -90,6 +92,7 @@
"adomain": ["google.com"],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/exemplary/simple-native-banner.json b/adapters/adnuntius/adnuntiustest/exemplary/simple-native-banner.json
new file mode 100644
index 00000000000..fb20797e1ba
--- /dev/null
+++ b/adapters/adnuntius/adnuntiustest/exemplary/simple-native-banner.json
@@ -0,0 +1,139 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "site": {
+ "page": "prebid.org"
+ },
+ "imp": [
+ {
+ "id": "test-native-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "native": {
+ "request": "{\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]},{\"event\":2,\"methods\":[1]}],\"assets\":[{\"id\":789,\"required\":1,\"title\":{\"len\":140}},{\"id\":1,\"required\":1,\"img\":{\"type\":3,\"w\":250,\"h\":250}},{\"id\":122,\"required\":1,\"img\":{\"type\":1,\"w\":15,\"h\":15}},{\"id\":2,\"required\":1,\"data\":{\"type\":1}},{\"id\":3,\"required\":1,\"data\":{\"type\":2}},{\"id\":4,\"required\":0,\"data\":{\"type\":3}},{\"id\":5,\"required\":0,\"data\":{\"type\":4}},{\"id\":6,\"required\":0,\"data\":{\"type\":5}},{\"id\":7,\"required\":0,\"data\":{\"type\":6}},{\"id\":8,\"required\":0,\"data\":{\"type\":7}},{\"id\":9,\"required\":0,\"data\":{\"type\":8}},{\"id\":10,\"required\":0,\"data\":{\"type\":9}},{\"id\":11,\"required\":0,\"data\":{\"type\":10}},{\"id\":12,\"required\":0,\"data\":{\"type\":11}}]}"
+ },
+ "ext": {
+ "bidder": {
+ "auId": "123"
+ }
+ }
+ }
+ ]
+ },
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://whatever.url?format=prebidServer&tzo=0",
+ "body": {
+ "adUnits": [
+ {
+ "auId": "123",
+ "targetId": "123-test-native-id:banner",
+ "nativeRequest": {},
+ "dimensions": [[300,250],[300,600]]
+ },
+ {
+ "auId": "123",
+ "targetId": "123-test-native-id:native",
+ "adType": "NATIVE",
+ "nativeRequest":{"ortb":{"eventtrackers":[{"event":1,"methods":[1,2]},{"event":2,"methods":[1]}],"assets":[{"id":789,"required":1,"title":{"len":140}},{"id":1,"required":1,"img":{"type":3,"w":250,"h":250}},{"id":122,"required":1,"img":{"type":1,"w":15,"h":15}},{"id":2,"required":1,"data":{"type":1}},{"id":3,"required":1,"data":{"type":2}},{"id":4,"required":0,"data":{"type":3}},{"id":5,"required":0,"data":{"type":4}},{"id":6,"required":0,"data":{"type":5}},{"id":7,"required":0,"data":{"type":6}},{"id":8,"required":0,"data":{"type":7}},{"id":9,"required":0,"data":{"type":8}},{"id":10,"required":0,"data":{"type":9}},{"id":11,"required":0,"data":{"type":10}},{"id":12,"required":0,"data":{"type":11}}]}}
+ }
+ ],
+ "context": "prebid.org",
+ "metaData": {}
+ },
+ "impIDs":["test-native-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "adUnits": [
+ {
+ "auId": "0000000000000123",
+ "targetId": "123-test-native-id:banner",
+ "matchedAdCount": 1,
+ "html": "",
+ "responseId": "adn-rsp-900646517",
+ "ads": [
+ {
+ "destinationUrls": {
+ "url": "http://www.google.com"
+ },
+ "advertiserDomains": ["google.com"],
+ "bid": {
+ "amount": 19.0,
+ "currency": "NOK"
+ },
+ "adId": "adn-id-1559784094",
+ "creativeWidth": "980",
+ "creativeHeight": "240",
+ "creativeId": "jn9hpzvlsf8cpdmm",
+ "lineItemId": "q7y9qm5b0xt9htrv"
+ }
+ ]
+ },
+ {
+ "auId": "0000000000000123",
+ "targetId": "123-test-native-id:native",
+ "matchedAdCount": 1,
+ "html": "",
+ "nativeJson": {"ortb":{"ver":"1.2","assets":[{"id":789,"required":true,"title":{"text":"Adnuntius Forever"}},{"id":1,"required":true,"img":{"type":3,"url":"https://assets.adnuntius.com/cfacah/qz2pmlqb8k2y8wqhzvn8zy8v3m2p209ms0pjk1wjy8x037mx0g.jpg?id=4013198","w":250,"h":250}},{"id":122,"required":true,"img":{"type":1,"url":"https://assets.adnuntius.com/cfacah/f9tcm571y850k8bt8mp7fsfyrnj6lhr1sz99fzxyfkwglq2znp.jpg?id=4013199","w":15,"h":15}},{"id":2,"required":true,"data":{"type":1,"value":"CNN"}},{"id":3,"required":true,"data":{"type":2,"value":"Adnuntius is a glorious company"}},{"id":4,"required":false,"data":{"type":3,"value":"5"}},{"id":5,"required":false,"data":{"type":4,"value":"1001"}},{"id":6,"required":false,"data":{"type":5,"value":"8923"}},{"id":9,"required":false,"data":{"type":8,"value":"555-1234"}},{"id":11,"required":false,"data":{"type":10,"value":"Click on the link to learn more"}},{"id":12,"required":false,"data":{"type":11,"value":"Adnuntius"}}],"link":{"url":"https://delivery.adnuntius.com/c/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw?ct=1640189&r=https%3A%2F%2Fadnuntius.com"},"eventtrackers":[{"event":1,"method":1,"url":"https://delivery.adnuntius.com/b/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw.gif"},{"event":2,"method":1,"url":"https://delivery.adnuntius.com/v/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw.gif"}]}},
+ "responseId": "adn-rsp-900646517",
+ "ads": [
+ {
+ "destinationUrls": {
+ "url": "http://www.google.com"
+ },
+ "advertiserDomains": ["google.com"],
+ "bid": {
+ "amount": 20.0,
+ "currency": "NOK"
+ },
+ "adId": "adn-id-1559784094",
+ "creativeWidth": "980",
+ "creativeHeight": "240",
+ "creativeId": "jn9hpzvlsf8cpdmm",
+ "lineItemId": "q7y9qm5b0xt9htrv"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "bids": [
+ {
+ "bid": {
+ "id": "adn-id-1559784094",
+ "impid": "test-native-id",
+ "price": 20000,
+ "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":789,\"required\":true,\"title\":{\"text\":\"Adnuntius Forever\"}},{\"id\":1,\"required\":true,\"img\":{\"type\":3,\"url\":\"https://assets.adnuntius.com/cfacah/qz2pmlqb8k2y8wqhzvn8zy8v3m2p209ms0pjk1wjy8x037mx0g.jpg?id=4013198\",\"w\":250,\"h\":250}},{\"id\":122,\"required\":true,\"img\":{\"type\":1,\"url\":\"https://assets.adnuntius.com/cfacah/f9tcm571y850k8bt8mp7fsfyrnj6lhr1sz99fzxyfkwglq2znp.jpg?id=4013199\",\"w\":15,\"h\":15}},{\"id\":2,\"required\":true,\"data\":{\"type\":1,\"value\":\"CNN\"}},{\"id\":3,\"required\":true,\"data\":{\"type\":2,\"value\":\"Adnuntius is a glorious company\"}},{\"id\":4,\"required\":false,\"data\":{\"type\":3,\"value\":\"5\"}},{\"id\":5,\"required\":false,\"data\":{\"type\":4,\"value\":\"1001\"}},{\"id\":6,\"required\":false,\"data\":{\"type\":5,\"value\":\"8923\"}},{\"id\":9,\"required\":false,\"data\":{\"type\":8,\"value\":\"555-1234\"}},{\"id\":11,\"required\":false,\"data\":{\"type\":10,\"value\":\"Click on the link to learn more\"}},{\"id\":12,\"required\":false,\"data\":{\"type\":11,\"value\":\"Adnuntius\"}}],\"link\":{\"url\":\"https://delivery.adnuntius.com/c/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw?ct=1640189&r=https%3A%2F%2Fadnuntius.com\"},\"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"https://delivery.adnuntius.com/b/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw.gif\"},{\"event\":2,\"method\":1,\"url\":\"https://delivery.adnuntius.com/v/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw.gif\"}]}",
+ "adid": "adn-id-1559784094",
+ "adomain": ["google.com"],
+ "cid": "q7y9qm5b0xt9htrv",
+ "crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 4,
+ "w": 980,
+ "h": 240
+ },
+ "type": "native"
+ }
+ ],
+ "currency": "NOK"
+ }
+ ]
+}
diff --git a/adapters/adnuntius/adnuntiustest/exemplary/simple-native.json b/adapters/adnuntius/adnuntiustest/exemplary/simple-native.json
new file mode 100644
index 00000000000..8b435acfe76
--- /dev/null
+++ b/adapters/adnuntius/adnuntiustest/exemplary/simple-native.json
@@ -0,0 +1,97 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "site": {
+ "page": "prebid.org"
+ },
+ "imp": [
+ {
+ "id": "test-native-id",
+ "native": {
+ "request": "{\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]},{\"event\":2,\"methods\":[1]}],\"assets\":[{\"id\":789,\"required\":1,\"title\":{\"len\":140}},{\"id\":1,\"required\":1,\"img\":{\"type\":3,\"w\":250,\"h\":250}},{\"id\":122,\"required\":1,\"img\":{\"type\":1,\"w\":15,\"h\":15}},{\"id\":2,\"required\":1,\"data\":{\"type\":1}},{\"id\":3,\"required\":1,\"data\":{\"type\":2}},{\"id\":4,\"required\":0,\"data\":{\"type\":3}},{\"id\":5,\"required\":0,\"data\":{\"type\":4}},{\"id\":6,\"required\":0,\"data\":{\"type\":5}},{\"id\":7,\"required\":0,\"data\":{\"type\":6}},{\"id\":8,\"required\":0,\"data\":{\"type\":7}},{\"id\":9,\"required\":0,\"data\":{\"type\":8}},{\"id\":10,\"required\":0,\"data\":{\"type\":9}},{\"id\":11,\"required\":0,\"data\":{\"type\":10}},{\"id\":12,\"required\":0,\"data\":{\"type\":11}}]}"
+ },
+ "ext": {
+ "bidder": {
+ "auId": "123"
+ }
+ }
+ }
+ ]
+ },
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://whatever.url?format=prebidServer&tzo=0",
+ "body": {
+ "adUnits": [
+ {
+ "auId": "123",
+ "targetId": "123-test-native-id:native",
+ "adType": "NATIVE",
+ "nativeRequest":{"ortb":{"eventtrackers":[{"event":1,"methods":[1,2]},{"event":2,"methods":[1]}],"assets":[{"id":789,"required":1,"title":{"len":140}},{"id":1,"required":1,"img":{"type":3,"w":250,"h":250}},{"id":122,"required":1,"img":{"type":1,"w":15,"h":15}},{"id":2,"required":1,"data":{"type":1}},{"id":3,"required":1,"data":{"type":2}},{"id":4,"required":0,"data":{"type":3}},{"id":5,"required":0,"data":{"type":4}},{"id":6,"required":0,"data":{"type":5}},{"id":7,"required":0,"data":{"type":6}},{"id":8,"required":0,"data":{"type":7}},{"id":9,"required":0,"data":{"type":8}},{"id":10,"required":0,"data":{"type":9}},{"id":11,"required":0,"data":{"type":10}},{"id":12,"required":0,"data":{"type":11}}]}}
+ }
+ ],
+ "context": "prebid.org",
+ "metaData": {}
+ },
+ "impIDs":["test-native-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "adUnits": [
+ {
+ "auId": "0000000000000123",
+ "targetId": "123-test-native-id:native",
+ "matchedAdCount": 1,
+ "html": "",
+ "nativeJson": {"ortb":{"ver":"1.2","assets":[{"id":789,"required":true,"title":{"text":"Adnuntius Forever"}},{"id":1,"required":true,"img":{"type":3,"url":"https://assets.adnuntius.com/cfacah/qz2pmlqb8k2y8wqhzvn8zy8v3m2p209ms0pjk1wjy8x037mx0g.jpg?id=4013198","w":250,"h":250}},{"id":122,"required":true,"img":{"type":1,"url":"https://assets.adnuntius.com/cfacah/f9tcm571y850k8bt8mp7fsfyrnj6lhr1sz99fzxyfkwglq2znp.jpg?id=4013199","w":15,"h":15}},{"id":2,"required":true,"data":{"type":1,"value":"CNN"}},{"id":3,"required":true,"data":{"type":2,"value":"Adnuntius is a glorious company"}},{"id":4,"required":false,"data":{"type":3,"value":"5"}},{"id":5,"required":false,"data":{"type":4,"value":"1001"}},{"id":6,"required":false,"data":{"type":5,"value":"8923"}},{"id":9,"required":false,"data":{"type":8,"value":"555-1234"}},{"id":11,"required":false,"data":{"type":10,"value":"Click on the link to learn more"}},{"id":12,"required":false,"data":{"type":11,"value":"Adnuntius"}}],"link":{"url":"https://delivery.adnuntius.com/c/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw?ct=1640189&r=https%3A%2F%2Fadnuntius.com"},"eventtrackers":[{"event":1,"method":1,"url":"https://delivery.adnuntius.com/b/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw.gif"},{"event":2,"method":1,"url":"https://delivery.adnuntius.com/v/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw.gif"}]}},
+ "responseId": "adn-rsp-900646517",
+ "ads": [
+ {
+ "destinationUrls": {
+ "url": "http://www.google.com"
+ },
+ "advertiserDomains": ["google.com"],
+ "bid": {
+ "amount": 20.0,
+ "currency": "NOK"
+ },
+ "adId": "adn-id-1559784094",
+ "creativeWidth": "980",
+ "creativeHeight": "240",
+ "creativeId": "jn9hpzvlsf8cpdmm",
+ "lineItemId": "q7y9qm5b0xt9htrv"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "bids": [
+ {
+ "bid": {
+ "id": "adn-id-1559784094",
+ "impid": "test-native-id",
+ "price": 20000,
+ "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":789,\"required\":true,\"title\":{\"text\":\"Adnuntius Forever\"}},{\"id\":1,\"required\":true,\"img\":{\"type\":3,\"url\":\"https://assets.adnuntius.com/cfacah/qz2pmlqb8k2y8wqhzvn8zy8v3m2p209ms0pjk1wjy8x037mx0g.jpg?id=4013198\",\"w\":250,\"h\":250}},{\"id\":122,\"required\":true,\"img\":{\"type\":1,\"url\":\"https://assets.adnuntius.com/cfacah/f9tcm571y850k8bt8mp7fsfyrnj6lhr1sz99fzxyfkwglq2znp.jpg?id=4013199\",\"w\":15,\"h\":15}},{\"id\":2,\"required\":true,\"data\":{\"type\":1,\"value\":\"CNN\"}},{\"id\":3,\"required\":true,\"data\":{\"type\":2,\"value\":\"Adnuntius is a glorious company\"}},{\"id\":4,\"required\":false,\"data\":{\"type\":3,\"value\":\"5\"}},{\"id\":5,\"required\":false,\"data\":{\"type\":4,\"value\":\"1001\"}},{\"id\":6,\"required\":false,\"data\":{\"type\":5,\"value\":\"8923\"}},{\"id\":9,\"required\":false,\"data\":{\"type\":8,\"value\":\"555-1234\"}},{\"id\":11,\"required\":false,\"data\":{\"type\":10,\"value\":\"Click on the link to learn more\"}},{\"id\":12,\"required\":false,\"data\":{\"type\":11,\"value\":\"Adnuntius\"}}],\"link\":{\"url\":\"https://delivery.adnuntius.com/c/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw?ct=1640189&r=https%3A%2F%2Fadnuntius.com\"},\"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"https://delivery.adnuntius.com/b/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw.gif\"},{\"event\":2,\"method\":1,\"url\":\"https://delivery.adnuntius.com/v/F1i91dCdKGIaWlotJHElIzQfj0T8qblUtK9cVXT1Qk8AAAAQCtjQz9kbGWD4nuZy3q6HaHGLAo_4rvebVEWFar2PLtv390pVPgSqDpWMkf24FSxJzl2pN3R3uB61gWbrxyxDx47w2QxHYYa9qYwhaJJf7EZU6ko47RlaZS6pMq83EjVwS5YbUYtMoEBgt7zNBL_EvrwPbYt3Tw3fZxXGWB4plvHLpE0DWObeaOFyAfI9fJ7MHSx68m7OTe-h35x60bk8NwpCuNBG7r1iW9gsWWzt4LDOuU3OQl0Jcgskc90wCbVsYIXv5PvSBqu4kSuC644UEpdMz1cbsw.gif\"}]}",
+ "adid": "adn-id-1559784094",
+ "adomain": ["google.com"],
+ "cid": "q7y9qm5b0xt9htrv",
+ "crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 4,
+ "w": 980,
+ "h": 240
+ },
+ "type": "native"
+ }
+ ],
+ "currency": "NOK"
+ }
+ ]
+}
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/banner-nil-check.json b/adapters/adnuntius/adnuntiustest/supplemental/banner-nil-check.json
deleted file mode 100644
index ae6b7cd823b..00000000000
--- a/adapters/adnuntius/adnuntiustest/supplemental/banner-nil-check.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "mockBidRequest": {
- "id": "test-request-id",
- "user": {
- "id": "1kjh3429kjh295jkl"
- },
- "device":{
- "ext":{
- "noCookies" : true
- }
- },
- "imp": [
- {
- "id": "test-imp-id",
- "ext": {
- "bidder": {
- "auId": "123"
- }
- }
- }
- ]
- },
- "expectedMakeRequestsErrors": [
- {
- "value": "ignoring imp id=test-imp-id, Adnuntius supports only Banner",
- "comparison": "literal"
- }
- ]
-}
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-dealId.json b/adapters/adnuntius/adnuntiustest/supplemental/check-dealId.json
index bf263dad3c6..1bc9ef86047 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-dealId.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-dealId.json
@@ -36,8 +36,9 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
- "dimensions": [[300,250],[300,600]]
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
+ "dimensions": [[300,250],[300,600]]
}
],
"context": "prebid.org",
@@ -52,6 +53,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -92,6 +94,7 @@
"dealid" : "deal_123",
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-legalName-omitted.json b/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-legalName-omitted.json
index 75675ae4b50..7dbc98654fe 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-legalName-omitted.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-legalName-omitted.json
@@ -50,7 +50,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -71,6 +72,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -114,6 +116,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240,
"ext": {
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-legalName.json b/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-legalName.json
index f9eebec3612..7ca8c5cf77e 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-legalName.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-legalName.json
@@ -50,7 +50,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -71,6 +72,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -115,6 +117,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240,
"ext": {
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-omitted.json b/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-omitted.json
index 9456c1fd9f4..42bb1c8abcd 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-omitted.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-dsa-advertiser-omitted.json
@@ -50,7 +50,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -71,6 +72,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -111,6 +113,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-gdpr.json b/adapters/adnuntius/adnuntiustest/supplemental/check-gdpr.json
index 5b5aaf14bb2..97c08b8e1c6 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-gdpr.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-gdpr.json
@@ -43,7 +43,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -61,6 +62,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -101,6 +103,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-gross-bids.json b/adapters/adnuntius/adnuntiustest/supplemental/check-gross-bids.json
index d2cdf1515da..72eb3dc58f6 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-gross-bids.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-gross-bids.json
@@ -36,7 +36,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -54,6 +55,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -93,6 +95,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-native-error.json b/adapters/adnuntius/adnuntiustest/supplemental/check-native-error.json
new file mode 100644
index 00000000000..47021c480c6
--- /dev/null
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-native-error.json
@@ -0,0 +1,80 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "site": {
+ "page": "prebid.org"
+ },
+ "imp": [
+ {
+ "id": "test-native-id",
+ "native": {
+ "request": "{\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]},{\"event\":2,\"methods\":[1]}],\"assets\":[{\"id\":789,\"required\":1,\"title\":{\"len\":140}},{\"id\":1,\"required\":1,\"img\":{\"type\":3,\"w\":250,\"h\":250}},{\"id\":122,\"required\":1,\"img\":{\"type\":1,\"w\":15,\"h\":15}},{\"id\":2,\"required\":1,\"data\":{\"type\":1}},{\"id\":3,\"required\":1,\"data\":{\"type\":2}},{\"id\":4,\"required\":0,\"data\":{\"type\":3}},{\"id\":5,\"required\":0,\"data\":{\"type\":4}},{\"id\":6,\"required\":0,\"data\":{\"type\":5}},{\"id\":7,\"required\":0,\"data\":{\"type\":6}},{\"id\":8,\"required\":0,\"data\":{\"type\":7}},{\"id\":9,\"required\":0,\"data\":{\"type\":8}},{\"id\":10,\"required\":0,\"data\":{\"type\":9}},{\"id\":11,\"required\":0,\"data\":{\"type\":10}},{\"id\":12,\"required\":0,\"data\":{\"type\":11}}]}"
+ },
+ "ext": {
+ "bidder": {
+ "auId": "123"
+ }
+ }
+ }
+ ]
+ },
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://whatever.url?format=prebidServer&tzo=0",
+ "body": {
+ "adUnits": [
+ {
+ "auId": "123",
+ "targetId": "123-test-native-id:native",
+ "adType": "NATIVE",
+ "nativeRequest":{"ortb":{"eventtrackers":[{"event":1,"methods":[1,2]},{"event":2,"methods":[1]}],"assets":[{"id":789,"required":1,"title":{"len":140}},{"id":1,"required":1,"img":{"type":3,"w":250,"h":250}},{"id":122,"required":1,"img":{"type":1,"w":15,"h":15}},{"id":2,"required":1,"data":{"type":1}},{"id":3,"required":1,"data":{"type":2}},{"id":4,"required":0,"data":{"type":3}},{"id":5,"required":0,"data":{"type":4}},{"id":6,"required":0,"data":{"type":5}},{"id":7,"required":0,"data":{"type":6}},{"id":8,"required":0,"data":{"type":7}},{"id":9,"required":0,"data":{"type":8}},{"id":10,"required":0,"data":{"type":9}},{"id":11,"required":0,"data":{"type":10}},{"id":12,"required":0,"data":{"type":11}}]}}
+ }
+ ],
+ "context": "prebid.org",
+ "metaData": {}
+ },
+ "impIDs":["test-native-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "adUnits": [
+ {
+ "auId": "0000000000000123",
+ "targetId": "123-test-native-id:native",
+ "matchedAdCount": 1,
+ "html": "",
+ "nativeJson": {},
+ "responseId": "adn-rsp-900646517",
+ "ads": [
+ {
+ "destinationUrls": {
+ "url": "http://www.google.com"
+ },
+ "advertiserDomains": ["google.com"],
+ "bid": {
+ "amount": 20.0,
+ "currency": "NOK"
+ },
+ "adId": "adn-id-1559784094",
+ "creativeWidth": "980",
+ "creativeHeight": "240",
+ "creativeId": "jn9hpzvlsf8cpdmm",
+ "lineItemId": "q7y9qm5b0xt9htrv"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Failed to parse native json where imp id=test-native-id",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-net-bids.json b/adapters/adnuntius/adnuntiustest/supplemental/check-net-bids.json
index 27f08b72294..7ff67451a61 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-net-bids.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-net-bids.json
@@ -36,7 +36,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -54,6 +55,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -93,6 +95,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-noCookies-parameter.json b/adapters/adnuntius/adnuntiustest/supplemental/check-noCookies-parameter.json
index a4c1637bfe0..c13fd7ae533 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-noCookies-parameter.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-noCookies-parameter.json
@@ -36,7 +36,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -54,6 +55,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -94,6 +96,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-noCookies.json b/adapters/adnuntius/adnuntiustest/supplemental/check-noCookies.json
index 5e8f2f5f8ec..e5f2469cffb 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-noCookies.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-noCookies.json
@@ -40,7 +40,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -57,7 +58,8 @@
"adUnits": [
{
"auId": "0000000000000123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -98,6 +100,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-order-multi-imp.json b/adapters/adnuntius/adnuntiustest/supplemental/check-order-multi-imp.json
index edf902ea6ad..1035bb35c15 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-order-multi-imp.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-order-multi-imp.json
@@ -56,12 +56,14 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
},
{
"auId": "456",
- "targetId": "456-test-imp-id-2",
+ "targetId": "456-test-imp-id-2:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -76,7 +78,8 @@
"adUnits": [
{
"auId": "0000000000000456",
- "targetId": "456-test-imp-id-2",
+ "targetId": "456-test-imp-id-2:banner",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -99,7 +102,8 @@
},
{
"auId": "0000000000000123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -138,6 +142,7 @@
"adomain": ["google.com"],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
@@ -153,6 +158,7 @@
"adomain": ["google.com"],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/check-userId.json b/adapters/adnuntius/adnuntiustest/supplemental/check-userId.json
index 15cb06084da..7b1a063f1af 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/check-userId.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-userId.json
@@ -35,7 +35,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -53,6 +54,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -93,6 +95,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/empty-regs-ext.json b/adapters/adnuntius/adnuntiustest/supplemental/empty-regs-ext.json
index b4eb94e2cb3..1c1de916804 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/empty-regs-ext.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/empty-regs-ext.json
@@ -38,7 +38,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -56,6 +57,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -96,6 +98,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/empty-regs.json b/adapters/adnuntius/adnuntiustest/supplemental/empty-regs.json
index aa871612cdd..50e3230eff2 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/empty-regs.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/empty-regs.json
@@ -37,7 +37,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -55,6 +56,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -95,6 +97,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/height-error.json b/adapters/adnuntius/adnuntiustest/supplemental/height-error.json
index 75df3107aa3..5dbd360067b 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/height-error.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/height-error.json
@@ -35,7 +35,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -53,6 +54,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/invalid-regs-ext.json b/adapters/adnuntius/adnuntiustest/supplemental/invalid-regs-ext.json
index 27e043de1cb..4cf575d348f 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/invalid-regs-ext.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/invalid-regs-ext.json
@@ -39,7 +39,7 @@
},
"expectedMakeRequestsErrors": [
{
- "value": "failed to parse URL: [failed to parse Adnuntius endpoint: failed to parse ExtRegs in Adnuntius GDPR check: expect { or n, but found \"]",
+ "value": "failed to parse URL: [failed to parse GDPR information: failed to parse ExtRegs in Adnuntius GDPR check: expect { or n, but found \"]",
"comparison": "literal"
}
]
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/max-deals-test.json b/adapters/adnuntius/adnuntiustest/supplemental/max-deals-test.json
index cca9d50ff7c..cb59ef59dd9 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/max-deals-test.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/max-deals-test.json
@@ -37,7 +37,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]],
"maxDeals": 2
}
@@ -143,6 +144,7 @@
"adomain": ["google.com"],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 300,
"h": 250
},
@@ -159,6 +161,7 @@
"cid": "6l5w2d29kz3vkprq",
"crid": "dl0knc1lnks9jgvx",
"dealid": "deal_123",
+ "mtype": 1,
"w": 300,
"h": 250
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/native-error.json b/adapters/adnuntius/adnuntiustest/supplemental/native-error.json
deleted file mode 100644
index cf21ba0ef99..00000000000
--- a/adapters/adnuntius/adnuntiustest/supplemental/native-error.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "mockBidRequest": {
- "id": "unsupported-native-request",
- "imp": [
- {
- "id": "unsupported-native-imp",
- "native": {
- "ver": "1.1"
- },
- "ext": {
- "bidder": {
- "auId": "1"
- }
- }
- }
- ]
- },
- "expectedMakeRequestsErrors": [
- {
- "value": "ignoring imp id=unsupported-native-imp, Adnuntius supports only Banner",
- "comparison": "literal"
- }
- ]
-}
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/send-header-information.json b/adapters/adnuntius/adnuntiustest/supplemental/send-header-information.json
index 42cd7d6372f..6d464e2cad3 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/send-header-information.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/send-header-information.json
@@ -55,7 +55,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -73,6 +74,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -113,6 +115,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/site-ext.json b/adapters/adnuntius/adnuntiustest/supplemental/site-ext.json
index 4cd4077703c..4c059192602 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/site-ext.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/site-ext.json
@@ -42,7 +42,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -63,6 +64,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -103,6 +105,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/size-check.json b/adapters/adnuntius/adnuntiustest/supplemental/size-check.json
index be44843751d..0a616ca9c60 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/size-check.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/size-check.json
@@ -33,7 +33,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,600]]
}
],
@@ -51,6 +52,7 @@
{
"auId": "0000000000000123",
"targetId": "123-test-imp-id",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -91,6 +93,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/status-400.json b/adapters/adnuntius/adnuntiustest/supplemental/status-400.json
index 5a0b4606735..0e3f1afe938 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/status-400.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/status-400.json
@@ -32,7 +32,8 @@
"adUnits": [
{
"auId": "",
- "targetId": "-test-imp-id",
+ "targetId": "-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/test-networks.json b/adapters/adnuntius/adnuntiustest/supplemental/test-networks.json
index a8a60393ffb..5a5724e6633 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/test-networks.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/test-networks.json
@@ -37,8 +37,9 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
- "dimensions": [[300,250],[300,600]]
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
+ "dimensions": [[300,250],[300,600]]
}
],
"context": "prebid.org",
@@ -52,7 +53,8 @@
"adUnits": [
{
"auId": "0000000000000123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -91,6 +93,7 @@
"adomain": ["google.com"],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/user-ext-invalid.json b/adapters/adnuntius/adnuntiustest/supplemental/user-ext-invalid.json
new file mode 100644
index 00000000000..3e71a4f1aca
--- /dev/null
+++ b/adapters/adnuntius/adnuntiustest/supplemental/user-ext-invalid.json
@@ -0,0 +1,37 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "ext":""
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "auId": "123"
+ }
+ }
+ }
+ ]
+ },
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "failed to parse URL: [failed to parse GDPR information: failed to parse ExtUser in Adnuntius GDPR check: expect { or n, but found \"]",
+ "comparison": "literal"
+ }
+ ]
+
+}
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/user-ext.json b/adapters/adnuntius/adnuntiustest/supplemental/user-ext.json
index 83486dd066e..4d3ccb13738 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/user-ext.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/user-ext.json
@@ -44,7 +44,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
@@ -61,7 +62,8 @@
"adUnits": [
{
"auId": "0000000000000123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "matchedAdCount": 1,
"html": "",
"responseId": "adn-rsp-900646517",
"ads": [
@@ -102,6 +104,7 @@
],
"cid": "q7y9qm5b0xt9htrv",
"crid": "jn9hpzvlsf8cpdmm",
+ "mtype": 1,
"w": 980,
"h": 240
},
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/video-error.json b/adapters/adnuntius/adnuntiustest/supplemental/video-error.json
index ed22dc540bf..0beac0a29ae 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/video-error.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/video-error.json
@@ -1,9 +1,9 @@
{
"mockBidRequest": {
- "id": "unsupported-native-request",
+ "id": "unsupported-video-request",
"imp": [
{
- "id": "unsupported-native-imp",
+ "id": "unsupported-video-imp",
"video": {
"w": 728,
"h": 90
@@ -18,8 +18,8 @@
},
"expectedMakeRequestsErrors": [
{
- "value": "ignoring imp id=unsupported-native-imp, Adnuntius supports only Banner",
+ "value": "ignoring imp id=unsupported-video-imp, Adnuntius supports only native and banner",
"comparison": "literal"
}
]
-}
+}
\ No newline at end of file
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/width-error.json b/adapters/adnuntius/adnuntiustest/supplemental/width-error.json
index dabc6e62a96..3125eb7c10e 100644
--- a/adapters/adnuntius/adnuntiustest/supplemental/width-error.json
+++ b/adapters/adnuntius/adnuntiustest/supplemental/width-error.json
@@ -35,7 +35,8 @@
"adUnits": [
{
"auId": "123",
- "targetId": "123-test-imp-id",
+ "targetId": "123-test-imp-id:banner",
+ "nativeRequest": {},
"dimensions": [[300,250],[300,600]]
}
],
diff --git a/static/bidder-info/adnuntius.yaml b/static/bidder-info/adnuntius.yaml
index 0e1d86dd286..beb7c5d6ef6 100644
--- a/static/bidder-info/adnuntius.yaml
+++ b/static/bidder-info/adnuntius.yaml
@@ -7,6 +7,8 @@ capabilities:
app:
mediaTypes:
- banner
+ - native
site:
mediaTypes:
- banner
+ - native
From 222febeb146ead2d85b0c270053e44213967ab72 Mon Sep 17 00:00:00 2001
From: Vu Hoang PHAN
Date: Tue, 22 Apr 2025 18:45:34 +0200
Subject: [PATCH 36/40] New Adapter: Mobkoi (#4240)
---
adapters/mobkoi/mobkoi.go | 121 ++++++++++++++
adapters/mobkoi/mobkoi_test.go | 21 +++
.../mobkoitest/exemplary/banner-web.json | 148 ++++++++++++++++++
.../mobkoitest/exemplary/fallback-uri.json | 148 ++++++++++++++++++
.../mobkoitest/exemplary/use-tag-id.json | 146 +++++++++++++++++
.../mobkoitest/supplemental/bad-imp-ext.json | 41 +++++
.../mobkoitest/supplemental/bad-input.json | 108 +++++++++++++
.../mobkoitest/supplemental/bad-response.json | 116 ++++++++++++++
.../mobkoitest/supplemental/no-content.json | 99 ++++++++++++
.../supplemental/no-tag-nor-placement-id.json | 45 ++++++
.../mobkoitest/supplemental/server-error.json | 108 +++++++++++++
adapters/mobkoi/params_test.go | 63 ++++++++
exchange/adapter_builders.go | 2 +
openrtb_ext/bidders.go | 2 +
openrtb_ext/imp_mobkoi.go | 6 +
static/bidder-info/mobkoi.yaml | 10 ++
static/bidder-params/mobkoi.json | 17 ++
17 files changed, 1201 insertions(+)
create mode 100644 adapters/mobkoi/mobkoi.go
create mode 100644 adapters/mobkoi/mobkoi_test.go
create mode 100644 adapters/mobkoi/mobkoitest/exemplary/banner-web.json
create mode 100644 adapters/mobkoi/mobkoitest/exemplary/fallback-uri.json
create mode 100644 adapters/mobkoi/mobkoitest/exemplary/use-tag-id.json
create mode 100644 adapters/mobkoi/mobkoitest/supplemental/bad-imp-ext.json
create mode 100644 adapters/mobkoi/mobkoitest/supplemental/bad-input.json
create mode 100644 adapters/mobkoi/mobkoitest/supplemental/bad-response.json
create mode 100644 adapters/mobkoi/mobkoitest/supplemental/no-content.json
create mode 100644 adapters/mobkoi/mobkoitest/supplemental/no-tag-nor-placement-id.json
create mode 100644 adapters/mobkoi/mobkoitest/supplemental/server-error.json
create mode 100644 adapters/mobkoi/params_test.go
create mode 100644 openrtb_ext/imp_mobkoi.go
create mode 100644 static/bidder-info/mobkoi.yaml
create mode 100644 static/bidder-params/mobkoi.json
diff --git a/adapters/mobkoi/mobkoi.go b/adapters/mobkoi/mobkoi.go
new file mode 100644
index 00000000000..19a6d34d52c
--- /dev/null
+++ b/adapters/mobkoi/mobkoi.go
@@ -0,0 +1,121 @@
+package mobkoi
+
+import (
+ "errors"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/prebid/openrtb/v20/openrtb2"
+ "github.com/prebid/prebid-server/v3/adapters"
+ "github.com/prebid/prebid-server/v3/config"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+ "github.com/prebid/prebid-server/v3/util/jsonutil"
+)
+
+type adapter struct {
+ endpoint string
+}
+
+type BidderExt struct {
+ Bidder openrtb_ext.ImpExtMobkoi `json:"bidder"`
+}
+
+type UserExt struct {
+ Consent string `json:"consent"`
+}
+
+// Builder builds a new instance of the {bidder} adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
+ bidder := &adapter{
+ endpoint: config.Endpoint,
+ }
+ return bidder, nil
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+ ext := BidderExt{}
+ if err := jsonutil.Unmarshal(request.Imp[0].Ext, &ext); err != nil {
+ return nil, []error{err}
+ }
+
+ if request.Imp[0].TagID == "" {
+ if ext.Bidder.PlacementID != "" {
+ request.Imp[0].TagID = ext.Bidder.PlacementID
+ } else {
+ return nil, []error{
+ errors.New("invalid because it comes with neither request.imp[0].tagId nor req.imp[0].ext.Bidder.placementId"),
+ }
+ }
+ }
+
+ uri := a.endpoint
+ if ext.Bidder.AdServerBaseUrl != "" {
+ baseURL, err := url.ParseRequestURI(ext.Bidder.AdServerBaseUrl)
+ if err == nil { // Ensure parsing doesn't fail
+ baseURL.Path = strings.TrimRight(baseURL.Path, "/") + "/bid"
+ uri = baseURL.String()
+ }
+ }
+
+ if request.User != nil && request.User.Consent != "" {
+ user := *request.User
+ userExt, err := jsonutil.Marshal(UserExt{
+ Consent: user.Consent,
+ })
+ if err != nil {
+ return nil, []error{err}
+ }
+ user.Ext = userExt
+ request.User = &user
+ }
+
+ requestJSON, err := jsonutil.Marshal(request)
+ if err != nil {
+ return nil, []error{err}
+ }
+
+ headers := http.Header{}
+ headers.Add("Content-Type", "application/json")
+ headers.Add("Accept", "application/json")
+
+ requestData := &adapters.RequestData{
+ Method: http.MethodPost,
+ Uri: uri,
+ Body: requestJSON,
+ Headers: headers,
+ ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
+ }
+
+ return []*adapters.RequestData{requestData}, nil
+}
+
+func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+ if adapters.IsResponseStatusCodeNoContent(responseData) {
+ return nil, nil
+ }
+
+ if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil {
+ return nil, []error{err}
+ }
+
+ var response openrtb2.BidResponse
+ if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil {
+ return nil, []error{err}
+ }
+
+ bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+ bidResponse.Currency = response.Cur
+
+ for _, seatBid := range response.SeatBid {
+ for i := range seatBid.Bid {
+ bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+ Bid: &seatBid.Bid[i],
+ BidType: openrtb_ext.BidTypeBanner,
+ Seat: "mobkoi",
+ })
+
+ }
+ }
+ return bidResponse, nil
+}
diff --git a/adapters/mobkoi/mobkoi_test.go b/adapters/mobkoi/mobkoi_test.go
new file mode 100644
index 00000000000..36ee6a329c0
--- /dev/null
+++ b/adapters/mobkoi/mobkoi_test.go
@@ -0,0 +1,21 @@
+package mobkoi
+
+import (
+ "testing"
+
+ "github.com/prebid/prebid-server/v3/adapters/adapterstest"
+ "github.com/prebid/prebid-server/v3/config"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+ bidder, buildErr := Builder(openrtb_ext.BidderMobkoi, config.Adapter{
+ Endpoint: "http://any.url"},
+ config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+
+ if buildErr != nil {
+ t.Fatalf("Builder returned unexpected error %v", buildErr)
+ }
+
+ adapterstest.RunJSONBidderTest(t, "mobkoitest", bidder)
+}
diff --git a/adapters/mobkoi/mobkoitest/exemplary/banner-web.json b/adapters/mobkoi/mobkoitest/exemplary/banner-web.json
new file mode 100644
index 00000000000..45c33e215b8
--- /dev/null
+++ b/adapters/mobkoi/mobkoitest/exemplary/banner-web.json
@@ -0,0 +1,148 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 1000,
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string"
+ },
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "headers": {
+ "Content-Type": [
+ "application/json"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "uri": "http://dev.mobkoi.com/bid",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "placementId",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string",
+ "ext": {
+ "consent": "consent-string"
+ }
+ },
+ "tmax": 1000
+ },
+ "impIDs": [
+ "some-impression-id1"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "awesome-resp-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+ "impid": "some-impression-id1",
+ "price": 3.5,
+ "adm": "awesome-markup",
+ "adomain": [
+ "awesome.com"
+ ],
+ "crid": "20",
+ "w": 320,
+ "h": 50,
+ "lurl": "mobkoi/loss",
+ "nurl": "mobkoi/win"
+ }
+ ],
+ "type": "banner",
+ "seat": "mobkoi"
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "bids": [
+ {
+ "bid": {
+ "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+ "impid": "some-impression-id1",
+ "price": 3.5,
+ "adm": "awesome-markup",
+ "crid": "20",
+ "adomain": [
+ "awesome.com"
+ ],
+ "w": 320,
+ "h": 50,
+ "lurl": "mobkoi/loss",
+ "nurl": "mobkoi/win"
+ },
+ "type": "banner",
+ "seat": "mobkoi"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/mobkoi/mobkoitest/exemplary/fallback-uri.json b/adapters/mobkoi/mobkoitest/exemplary/fallback-uri.json
new file mode 100644
index 00000000000..6f40bcd2e38
--- /dev/null
+++ b/adapters/mobkoi/mobkoitest/exemplary/fallback-uri.json
@@ -0,0 +1,148 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 1000,
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string"
+ },
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "invalid"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "headers": {
+ "Content-Type": [
+ "application/json"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "uri": "http://any.url",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "placementId",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "invalid"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string",
+ "ext": {
+ "consent": "consent-string"
+ }
+ },
+ "tmax": 1000
+ },
+ "impIDs": [
+ "some-impression-id1"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "awesome-resp-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+ "impid": "some-impression-id1",
+ "price": 3.5,
+ "adm": "awesome-markup",
+ "adomain": [
+ "awesome.com"
+ ],
+ "crid": "20",
+ "w": 320,
+ "h": 50,
+ "lurl": "mobkoi/loss",
+ "nurl": "mobkoi/win"
+ }
+ ],
+ "type": "banner",
+ "seat": "mobkoi"
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "bids": [
+ {
+ "bid": {
+ "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+ "impid": "some-impression-id1",
+ "price": 3.5,
+ "adm": "awesome-markup",
+ "crid": "20",
+ "adomain": [
+ "awesome.com"
+ ],
+ "w": 320,
+ "h": 50,
+ "lurl": "mobkoi/loss",
+ "nurl": "mobkoi/win"
+ },
+ "type": "banner",
+ "seat": "mobkoi"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/mobkoi/mobkoitest/exemplary/use-tag-id.json b/adapters/mobkoi/mobkoitest/exemplary/use-tag-id.json
new file mode 100644
index 00000000000..cc26ab0cd10
--- /dev/null
+++ b/adapters/mobkoi/mobkoitest/exemplary/use-tag-id.json
@@ -0,0 +1,146 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 1000,
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string"
+ },
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "tagId",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "headers": {
+ "Content-Type": [
+ "application/json"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "uri": "http://dev.mobkoi.com/bid",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "tagId",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string",
+ "ext": {
+ "consent": "consent-string"
+ }
+ },
+ "tmax": 1000
+ },
+ "impIDs": [
+ "some-impression-id1"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "awesome-resp-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+ "impid": "some-impression-id1",
+ "price": 3.5,
+ "adm": "awesome-markup",
+ "adomain": [
+ "awesome.com"
+ ],
+ "crid": "20",
+ "w": 320,
+ "h": 50,
+ "lurl": "mobkoi/loss",
+ "nurl": "mobkoi/win"
+ }
+ ],
+ "type": "banner",
+ "seat": "mobkoi"
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "bids": [
+ {
+ "bid": {
+ "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+ "impid": "some-impression-id1",
+ "price": 3.5,
+ "adm": "awesome-markup",
+ "crid": "20",
+ "adomain": [
+ "awesome.com"
+ ],
+ "w": 320,
+ "h": 50,
+ "lurl": "mobkoi/loss",
+ "nurl": "mobkoi/win"
+ },
+ "type": "banner",
+ "seat": "mobkoi"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/mobkoi/mobkoitest/supplemental/bad-imp-ext.json b/adapters/mobkoi/mobkoitest/supplemental/bad-imp-ext.json
new file mode 100644
index 00000000000..f9ceba76491
--- /dev/null
+++ b/adapters/mobkoi/mobkoitest/supplemental/bad-imp-ext.json
@@ -0,0 +1,41 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 1000,
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string"
+ },
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": []
+ }
+ ]
+ },
+ "httpCalls": [],
+ "expectedBidResponses": [],
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "expect { or n, but found [",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/mobkoi/mobkoitest/supplemental/bad-input.json b/adapters/mobkoi/mobkoitest/supplemental/bad-input.json
new file mode 100644
index 00000000000..cac08d4bbfd
--- /dev/null
+++ b/adapters/mobkoi/mobkoitest/supplemental/bad-input.json
@@ -0,0 +1,108 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 1000,
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string"
+ },
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "headers": {
+ "Content-Type": [
+ "application/json"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "uri": "http://dev.mobkoi.com/bid",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "placementId",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string",
+ "ext": {
+ "consent": "consent-string"
+ }
+ },
+ "tmax": 1000
+ },
+ "impIDs": [
+ "some-impression-id1"
+ ]
+ },
+ "mockResponse": {
+ "status": 400,
+ "body": {
+ "message": "irrelevant"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/mobkoi/mobkoitest/supplemental/bad-response.json b/adapters/mobkoi/mobkoitest/supplemental/bad-response.json
new file mode 100644
index 00000000000..4d872c212d6
--- /dev/null
+++ b/adapters/mobkoi/mobkoitest/supplemental/bad-response.json
@@ -0,0 +1,116 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 1000,
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string"
+ },
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "headers": {
+ "Content-Type": [
+ "application/json"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "uri": "http://dev.mobkoi.com/bid",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "placementId",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string",
+ "ext": {
+ "consent": "consent-string"
+ }
+ },
+ "tmax": 1000
+ },
+ "impIDs": [
+ "some-impression-id1"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "awesome-resp-id",
+ "seatbid": [
+ {
+ "bid": {},
+ "type": "banner",
+ "seat": "mobkoi"
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "cannot unmarshal .*",
+ "comparison": "regex"
+ }
+ ]
+}
diff --git a/adapters/mobkoi/mobkoitest/supplemental/no-content.json b/adapters/mobkoi/mobkoitest/supplemental/no-content.json
new file mode 100644
index 00000000000..e645bb079b4
--- /dev/null
+++ b/adapters/mobkoi/mobkoitest/supplemental/no-content.json
@@ -0,0 +1,99 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 1000,
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string"
+ },
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "headers": {
+ "Content-Type": [
+ "application/json"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "uri": "http://dev.mobkoi.com/bid",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "placementId",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string",
+ "ext": {
+ "consent": "consent-string"
+ }
+ },
+ "tmax": 1000
+ },
+ "impIDs": [
+ "some-impression-id1"
+ ]
+ },
+ "mockResponse": {
+ "status": 204
+ }
+ }
+ ],
+ "expectedBidResponses": []
+}
diff --git a/adapters/mobkoi/mobkoitest/supplemental/no-tag-nor-placement-id.json b/adapters/mobkoi/mobkoitest/supplemental/no-tag-nor-placement-id.json
new file mode 100644
index 00000000000..a3c943f3a07
--- /dev/null
+++ b/adapters/mobkoi/mobkoitest/supplemental/no-tag-nor-placement-id.json
@@ -0,0 +1,45 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 1000,
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string"
+ },
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [],
+ "expectedBidResponses": [],
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "invalid because it comes with neither request.imp[0].tagId nor req.imp[0].ext.Bidder.placementId",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/mobkoi/mobkoitest/supplemental/server-error.json b/adapters/mobkoi/mobkoitest/supplemental/server-error.json
new file mode 100644
index 00000000000..c21b37863c8
--- /dev/null
+++ b/adapters/mobkoi/mobkoitest/supplemental/server-error.json
@@ -0,0 +1,108 @@
+{
+ "mockBidRequest": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "tmax": 1000,
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string"
+ },
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "headers": {
+ "Content-Type": [
+ "application/json"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "uri": "http://dev.mobkoi.com/bid",
+ "body": {
+ "id": "some-request-id",
+ "device": {
+ "ua": "test-user-agent",
+ "ip": "123.123.123.123",
+ "language": "en",
+ "dnt": 0
+ },
+ "imp": [
+ {
+ "id": "some-impression-id1",
+ "tagid": "placementId",
+ "banner": {
+ "w": 320,
+ "h": 50
+ },
+ "ext": {
+ "bidder": {
+ "placementId": "placementId",
+ "adServerBaseUrl": "http://dev.mobkoi.com"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "test.com",
+ "publisher": {
+ "id": "123456789"
+ }
+ },
+ "user": {
+ "buyeruid": "awesome-user",
+ "consent": "consent-string",
+ "ext": {
+ "consent": "consent-string"
+ }
+ },
+ "tmax": 1000
+ },
+ "impIDs": [
+ "some-impression-id1"
+ ]
+ },
+ "mockResponse": {
+ "status": 500,
+ "body": {
+ "message": "irrelevant"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Unexpected status code: 500. Run with request.debug = 1 for more info",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/mobkoi/params_test.go b/adapters/mobkoi/params_test.go
new file mode 100644
index 00000000000..1ee1fd97798
--- /dev/null
+++ b/adapters/mobkoi/params_test.go
@@ -0,0 +1,63 @@
+package mobkoi
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+)
+
+func TestValidParams(test *testing.T) {
+ validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+
+ if err != nil {
+ test.Fatalf("Failed to fetch the json-schemas. %v", err)
+ }
+
+ for _, validParam := range validParams {
+ err := validator.Validate(openrtb_ext.BidderMobkoi, json.RawMessage(validParam))
+
+ if err != nil {
+ test.Errorf("Schema rejected Mobkoi params: %s\nError: %v", validParam, err)
+ }
+ }
+}
+
+func TestInvalidParams(test *testing.T) {
+ validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+
+ if err != nil {
+ test.Fatalf("Failed to fetch the json-schemas. %v", err)
+ }
+
+ for _, invalidParam := range invalidParams {
+ err := validator.Validate(openrtb_ext.BidderMobkoi, json.RawMessage(invalidParam))
+
+ if err == nil {
+ test.Errorf("Schema allowed unexpected params: %s", invalidParam)
+ }
+ }
+}
+
+var validParams = []string{
+ `{}`,
+ `{"foo":"bar"}`,
+ `{"placementId":"abc"}`,
+ `{"placementId":"abc", "adServerBaseUrl":"https://adserver.mobkoi.com"}`,
+ `{"adServerBaseUrl":"http://dev.mobkoi.com"}`,
+ `{"placementId":"abc", "adServerBaseUrl":"https://adserver.mobkoi.com"}`,
+}
+
+var invalidParams = []string{
+ ``,
+ `null`,
+ `true`,
+ `1`,
+ `1.0`,
+ `[]`,
+ `{"placementId":123, "adServerBaseUrl":"mobkoi.com"}`,
+ `{"placementId":"abc", "adServerBaseUrl":"https://ikea.ad.com"}`,
+ `{"placementId":"abc", "adServerBaseUrl":"http://ikea.ad.com"}`,
+ `{"placementId":"abc", "adServerBaseUrl":"https://adserver.mobkoi.net"}`,
+ `{"placementId":"abc", "adServerBaseUrl":"https://mobkoi.com"}`,
+}
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 07b607461f7..87821fd0c75 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -154,6 +154,7 @@ import (
"github.com/prebid/prebid-server/v3/adapters/missena"
"github.com/prebid/prebid-server/v3/adapters/mobfoxpb"
"github.com/prebid/prebid-server/v3/adapters/mobilefuse"
+ "github.com/prebid/prebid-server/v3/adapters/mobkoi"
"github.com/prebid/prebid-server/v3/adapters/motorik"
"github.com/prebid/prebid-server/v3/adapters/nativo"
"github.com/prebid/prebid-server/v3/adapters/nextmillennium"
@@ -405,6 +406,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
openrtb_ext.BidderMissena: missena.Builder,
openrtb_ext.BidderMobfoxpb: mobfoxpb.Builder,
openrtb_ext.BidderMobileFuse: mobilefuse.Builder,
+ openrtb_ext.BidderMobkoi: mobkoi.Builder,
openrtb_ext.BidderMotorik: motorik.Builder,
openrtb_ext.BidderNativo: nativo.Builder,
openrtb_ext.BidderNextMillennium: nextmillennium.Builder,
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 1057a873987..67cf8e7c15e 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -172,6 +172,7 @@ var coreBidderNames []BidderName = []BidderName{
BidderMissena,
BidderMobfoxpb,
BidderMobileFuse,
+ BidderMobkoi,
BidderMotorik,
BidderNativo,
BidderNextMillennium,
@@ -527,6 +528,7 @@ const (
BidderMissena BidderName = "missena"
BidderMobfoxpb BidderName = "mobfoxpb"
BidderMobileFuse BidderName = "mobilefuse"
+ BidderMobkoi BidderName = "mobkoi"
BidderMotorik BidderName = "motorik"
BidderNativo BidderName = "nativo"
BidderNextMillennium BidderName = "nextmillennium"
diff --git a/openrtb_ext/imp_mobkoi.go b/openrtb_ext/imp_mobkoi.go
new file mode 100644
index 00000000000..ffb110e9eab
--- /dev/null
+++ b/openrtb_ext/imp_mobkoi.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ImpExtMobkoi struct {
+ PlacementID string `json:"placementId"`
+ AdServerBaseUrl string `json:"adServerBaseUrl"`
+}
diff --git a/static/bidder-info/mobkoi.yaml b/static/bidder-info/mobkoi.yaml
new file mode 100644
index 00000000000..fcb17c3ba6f
--- /dev/null
+++ b/static/bidder-info/mobkoi.yaml
@@ -0,0 +1,10 @@
+endpoint: "https://pbs.maximus.mobkoi.com/bid"
+maintainer:
+ email: platformteam@mobkoi.com
+gvlVendorID: 898
+openrtb:
+ version: 2.6
+capabilities:
+ site:
+ mediaTypes:
+ - banner
diff --git a/static/bidder-params/mobkoi.json b/static/bidder-params/mobkoi.json
new file mode 100644
index 00000000000..8286229b035
--- /dev/null
+++ b/static/bidder-params/mobkoi.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Mobkoi Adapter Params",
+ "description": "A schema which validates params accepted by the Mobkoi adapter",
+ "type": "object",
+ "properties": {
+ "placementId": {
+ "type": "string",
+ "description": "Placement ID"
+ },
+ "adServerBaseUrl": {
+ "type": "string",
+ "description": "Mobkoi's ad server url",
+ "pattern": "^https?://[^.]+\\.mobkoi\\.com$"
+ }
+ }
+}
From 62d637718476cd436d1e62ef6cdc1adc62eec22e Mon Sep 17 00:00:00 2001
From: andre-gielow-ttd <124626380+andre-gielow-ttd@users.noreply.github.com>
Date: Wed, 23 Apr 2025 11:59:42 -0400
Subject: [PATCH 37/40] TheTradeDesk: Dynamically construct endpoint using
supplySourceId (#4294)
---
adapters/thetradedesk/params_test.go | 10 +-
adapters/thetradedesk/thetradedesk.go | 89 +++--
adapters/thetradedesk/thetradedesk_test.go | 120 +++++--
.../ortb_response_video_parsing.json | 285 ++++++++++++++++
.../prebidjs_response_video_parsing.json | 308 ++++++++++++++++++
.../exemplary/simple-banner-inapp.json | 3 +-
...mple-banner-multiple-bids-and-formats.json | 3 +-
.../simple-banner-multiple-bids.json | 3 +-
.../exemplary/simple-banner.json | 3 +-
.../exemplary/simple-empty-publisherId.json | 3 +-
.../exemplary/simple-multi-type-banner.json | 3 +-
.../exemplary/simple-multi-type-video.json | 3 +-
.../exemplary/simple-native.json | 3 +-
.../exemplary/simple-video.json | 3 +-
.../exemplary/use-supply-source-id-param.json | 208 ++++++++++++
.../200-response-from-target.json | 3 +-
.../204-response-from-target.json | 3 +-
.../400-response-from-target.json | 3 +-
.../500-response-from-target.json | 3 +-
.../supplemental/invalid-mtype.json | 3 +-
.../supplemental/invalid-supplySourceId.json | 45 +++
openrtb_ext/imp_thetradedesk.go | 7 +-
static/bidder-params/thetradedesk.json | 6 +
23 files changed, 1029 insertions(+), 91 deletions(-)
create mode 100644 adapters/thetradedesk/thetradedesktest/exemplary/ortb_response_video_parsing.json
create mode 100644 adapters/thetradedesk/thetradedesktest/exemplary/prebidjs_response_video_parsing.json
create mode 100644 adapters/thetradedesk/thetradedesktest/exemplary/use-supply-source-id-param.json
create mode 100644 adapters/thetradedesk/thetradedesktest/supplemental/invalid-supplySourceId.json
diff --git a/adapters/thetradedesk/params_test.go b/adapters/thetradedesk/params_test.go
index 05febe45fab..b0829fb290c 100644
--- a/adapters/thetradedesk/params_test.go
+++ b/adapters/thetradedesk/params_test.go
@@ -35,9 +35,9 @@ func TestInvalidParams(t *testing.T) {
}
var validParams = []string{
- `{"publisherId": "123456"}`,
- `{"publisherId": "pub-123456"}`,
- `{"publisherId": "publisherIDAllString"}`,
+ `{"publisherId": "123456", "supplySourceId": "xyz_123"}`,
+ `{"publisherId": "pub-123456", "supplySourceId": "direct_123"}`,
+ `{"publisherId": "publisherIDAllString", "supplySourceId": "direct123"}`,
}
var invalidParams = []string{
@@ -48,6 +48,6 @@ var invalidParams = []string{
`4.2`,
`[]`,
`{}`,
- `{"publisherId": 123456}`,
- `{"publisherId": 0}`,
+ `{"publisherId": 123456, "supplySourceId": 123}`,
+ `{"publisherId": 0, "supplySourceId": 0}`,
}
diff --git a/adapters/thetradedesk/thetradedesk.go b/adapters/thetradedesk/thetradedesk.go
index 0288b4bb097..47fb9ee0fde 100644
--- a/adapters/thetradedesk/thetradedesk.go
+++ b/adapters/thetradedesk/thetradedesk.go
@@ -17,18 +17,16 @@ import (
"github.com/prebid/openrtb/v20/openrtb2"
)
-const PREBID_INTEGRATION_TYPE = "1"
+//const PREBID_INTEGRATION_TYPE = "1"
type adapter struct {
- bidderEndpoint string
-}
-
-type ExtImpBidderTheTradeDesk struct {
- adapters.ExtImpBidder
+ bidderEndpointTemplate string
+ defaultEndpoint string
+ templateEndpoint *template.Template
}
func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
- pubID, err := getPublisherId(request.Imp)
+ pubID, supplySourceId, err := getExtensionInfo(request.Imp)
if err != nil {
return nil, []error{err}
@@ -87,37 +85,74 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
return nil, errs
}
+ bidderEndpoint, err := a.buildEndpointURL(supplySourceId)
+ if err != nil {
+ return nil, []error{errors.New("Failed to build endpoint URL")}
+ }
+
headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("Accept", "application/json")
- headers.Add("x-integration-type", PREBID_INTEGRATION_TYPE)
+ //headers.Add("x-integration-type", PREBID_INTEGRATION_TYPE) this will be parsed and added conditionally later
return []*adapters.RequestData{{
Method: "POST",
- Uri: a.bidderEndpoint,
+ Uri: bidderEndpoint,
Body: reqJSON,
Headers: headers,
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
}}, errs
}
-func getPublisherId(impressions []openrtb2.Imp) (string, error) {
+func (a *adapter) buildEndpointURL(supplySourceId string) (string, error) {
+ if supplySourceId == "" {
+ return a.defaultEndpoint, nil
+ }
+
+ urlParams := macros.EndpointTemplateParams{SupplyId: supplySourceId}
+ bidderEndpoint, err := macros.ResolveMacros(a.templateEndpoint, urlParams)
+
+ if err != nil {
+ return "", fmt.Errorf("unable to resolve endpoint macros: %v", err)
+ }
+
+ return bidderEndpoint, nil
+}
+
+func getExtensionInfo(impressions []openrtb2.Imp) (string, string, error) {
+ publisherId := ""
+ supplySourceId := ""
for _, imp := range impressions {
+ var ttdExt, err = getImpressionExt(&imp)
+ if err != nil {
+ return "", "", err
+ }
- var bidderExt ExtImpBidderTheTradeDesk
- if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil {
- return "", err
+ if ttdExt.PublisherId != "" && publisherId == "" {
+ publisherId = ttdExt.PublisherId
}
- var ttdExt openrtb_ext.ExtImpTheTradeDesk
- if err := jsonutil.Unmarshal(bidderExt.Bidder, &ttdExt); err != nil {
- return "", err
+ if ttdExt.SupplySourceId != "" && supplySourceId == "" {
+ supplySourceId = ttdExt.SupplySourceId
}
- if ttdExt.PublisherId != "" {
- return ttdExt.PublisherId, nil
+ if publisherId != "" && supplySourceId != "" {
+ break
}
}
- return "", nil
+ return publisherId, supplySourceId, nil
+}
+
+func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpTheTradeDesk, error) {
+ var bidderExt adapters.ExtImpBidder
+ if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil {
+ return nil, err
+ }
+
+ var ttdExt openrtb_ext.ExtImpTheTradeDesk
+ if err := jsonutil.Unmarshal(bidderExt.Bidder, &ttdExt); err != nil {
+ return nil, err
+ }
+ return &ttdExt, nil
}
func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
@@ -172,11 +207,6 @@ func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
}
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
- template, err := template.New("endpointTemplate").Parse(config.Endpoint)
- if err != nil {
- return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
- }
-
if len(config.ExtraAdapterInfo) > 0 {
isValidEndpoint, err := regexp.Match("([a-z]+)$", []byte(config.ExtraAdapterInfo))
if !isValidEndpoint || err != nil {
@@ -184,14 +214,21 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co
}
}
+ template, err := template.New("endpointTemplate").Parse(config.Endpoint)
+ if err != nil {
+ return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
+ }
+
urlParams := macros.EndpointTemplateParams{SupplyId: config.ExtraAdapterInfo}
- bidderEndpoint, err := macros.ResolveMacros(template, urlParams)
+ defaultEndpoint, err := macros.ResolveMacros(template, urlParams)
if err != nil {
return nil, fmt.Errorf("unable to resolve endpoint macros: %v", err)
}
return &adapter{
- bidderEndpoint: bidderEndpoint,
+ bidderEndpointTemplate: config.Endpoint,
+ defaultEndpoint: defaultEndpoint,
+ templateEndpoint: template,
}, nil
}
diff --git a/adapters/thetradedesk/thetradedesk_test.go b/adapters/thetradedesk/thetradedesk_test.go
index 658d812bcac..42166c4b76c 100644
--- a/adapters/thetradedesk/thetradedesk_test.go
+++ b/adapters/thetradedesk/thetradedesk_test.go
@@ -2,12 +2,13 @@ package thetradedesk
import (
"encoding/json"
+ "github.com/prebid/prebid-server/v3/adapters/adapterstest"
"net/http"
"testing"
+ "text/template"
"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v3/adapters"
- "github.com/prebid/prebid-server/v3/adapters/adapterstest"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/openrtb_ext"
"github.com/stretchr/testify/assert"
@@ -116,15 +117,16 @@ func TestGetBidType(t *testing.T) {
}
}
-func TestGetPublisherId(t *testing.T) {
+func TestGetExtensionInfo(t *testing.T) {
type args struct {
impressions []openrtb2.Imp
}
tests := []struct {
- name string
- args args
- expectedPublisherId string
- wantErr bool
+ name string
+ args args
+ expectedPublisherId string
+ expectedSupplySourceId string
+ wantErr bool
}{
{
name: "valid_publisher_Id",
@@ -132,12 +134,13 @@ func TestGetPublisherId(t *testing.T) {
impressions: []openrtb2.Imp{
{
Video: &openrtb2.Video{},
- Ext: json.RawMessage(`{"bidder":{"publisherId":"1"}}`),
+ Ext: json.RawMessage(`{"bidder":{"publisherId":"1", "supplySourceId": "abc"}}`),
},
},
},
- expectedPublisherId: "1",
- wantErr: false,
+ expectedPublisherId: "1",
+ expectedSupplySourceId: "abc",
+ wantErr: false,
},
{
name: "multiple_valid_publisher_Id",
@@ -145,16 +148,17 @@ func TestGetPublisherId(t *testing.T) {
impressions: []openrtb2.Imp{
{
Video: &openrtb2.Video{},
- Ext: json.RawMessage(`{"bidder":{"publisherId":"1"}}`),
+ Ext: json.RawMessage(`{"bidder":{"publisherId":"1", "supplySourceId": "abc"}}`),
},
{
Video: &openrtb2.Video{},
- Ext: json.RawMessage(`{"bidder":{"publisherId":"2"}}`),
+ Ext: json.RawMessage(`{"bidder":{"publisherId":"2", "supplySourceId": "def"}}`),
},
},
},
- expectedPublisherId: "1",
- wantErr: false,
+ expectedPublisherId: "1",
+ expectedSupplySourceId: "abc",
+ wantErr: false,
},
{
name: "not_publisherId_present",
@@ -166,8 +170,9 @@ func TestGetPublisherId(t *testing.T) {
},
},
},
- expectedPublisherId: "",
- wantErr: false,
+ expectedPublisherId: "",
+ expectedSupplySourceId: "",
+ wantErr: false,
},
{
name: "nil_publisherId_present",
@@ -179,16 +184,18 @@ func TestGetPublisherId(t *testing.T) {
},
},
},
- expectedPublisherId: "",
- wantErr: false,
+ expectedPublisherId: "",
+ expectedSupplySourceId: "",
+ wantErr: false,
},
{
name: "no_impressions",
args: args{
impressions: []openrtb2.Imp{},
},
- expectedPublisherId: "",
- wantErr: false,
+ expectedPublisherId: "",
+ expectedSupplySourceId: "",
+ wantErr: false,
},
{
name: "invalid_bidder_object",
@@ -200,15 +207,17 @@ func TestGetPublisherId(t *testing.T) {
},
},
},
- expectedPublisherId: "",
- wantErr: false,
+ expectedPublisherId: "",
+ expectedSupplySourceId: "",
+ wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- publisherId, err := getPublisherId(tt.args.impressions)
+ publisherId, supplySourceId, err := getExtensionInfo(tt.args.impressions)
assert.Equal(t, tt.wantErr, err != nil)
assert.Equal(t, tt.expectedPublisherId, publisherId)
+ assert.Equal(t, tt.expectedSupplySourceId, supplySourceId)
})
}
}
@@ -268,9 +277,12 @@ func TestTheTradeDeskAdapter_MakeRequests(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- a := &adapter{
- bidderEndpoint: tt.fields.URI,
- }
+ a, buildErr := Builder(openrtb_ext.BidderTheTradeDesk, config.Adapter{
+ Endpoint: `https://adsrvr.org/bid/bidder/{{.SupplyId}}`,
+ ExtraAdapterInfo: "test",
+ }, config.Server{})
+ assert.Nil(t, buildErr)
+
gotReqData, gotErr := a.MakeRequests(tt.args.request, tt.args.reqInfo)
assert.Equal(t, tt.wantErr, len(gotErr) != 0)
if tt.wantErr == false {
@@ -374,12 +386,64 @@ func TestTheTradeDeskAdapter_MakeBids(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- a := &adapter{
- bidderEndpoint: tt.fields.URI,
- }
+ a, buildErr := Builder(openrtb_ext.BidderTheTradeDesk, config.Adapter{
+ Endpoint: `https://adsrvr.org/bid/bidder/{{.SupplyId}}`,
+ ExtraAdapterInfo: "test",
+ }, config.Server{})
+ assert.Nil(t, buildErr)
gotResp, gotErr := a.MakeBids(tt.args.internalRequest, tt.args.externalRequest, tt.args.response)
assert.Equal(t, tt.wantErr, gotErr, gotErr)
assert.Equal(t, tt.wantResp, gotResp)
})
}
}
+
+func TestTheTradeDeskAdapter_BuildEndpoint(t *testing.T) {
+ tests := []struct {
+ name string
+ supplySourceId string
+ defaultEndpoint string
+ expectedEndpoint string
+ wantErr []error
+ }{
+ {
+ name: "valid_supply_source_id",
+ supplySourceId: "pub_abc",
+ defaultEndpoint: "https://direct.adsrvr.org/bid/bidder/default_publisher",
+ expectedEndpoint: "https://direct.adsrvr.org/bid/bidder/pub_abc",
+ wantErr: nil,
+ },
+ {
+ name: "empty_supply_source_id",
+ supplySourceId: "",
+ defaultEndpoint: "https://direct.adsrvr.org/bid/bidder/default_publisher",
+ expectedEndpoint: "https://direct.adsrvr.org/bid/bidder/default_publisher",
+ wantErr: nil,
+ },
+ {
+ name: "empty_ssi_and_no_default_expect_err",
+ supplySourceId: "",
+ defaultEndpoint: "",
+ expectedEndpoint: "",
+ wantErr: nil,
+ },
+ }
+
+ endpointTemplate, err := template.New("endpointTemplate").Parse("https://direct.adsrvr.org/bid/bidder/{{.SupplyId}}")
+ assert.Nil(t, err)
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ a := &adapter{
+ bidderEndpointTemplate: "https://direct.adsrvr.org/bid/bidder/{{.SupplyId}}",
+ defaultEndpoint: tt.defaultEndpoint,
+ templateEndpoint: endpointTemplate,
+ }
+ finalEndpoint, err := a.buildEndpointURL(tt.supplySourceId)
+ if tt.wantErr != nil {
+ assert.NotNil(t, err)
+ }
+ assert.Equal(t, tt.expectedEndpoint, finalEndpoint)
+ })
+ }
+}
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/ortb_response_video_parsing.json b/adapters/thetradedesk/thetradedesktest/exemplary/ortb_response_video_parsing.json
new file mode 100644
index 00000000000..d0683a2d051
--- /dev/null
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/ortb_response_video_parsing.json
@@ -0,0 +1,285 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "instl": 0,
+ "ext": {
+ "gpid": "/1030006,22910642311/bakewithzoha/recipe",
+ "bidder": {
+ "publisherId": "123456"
+ }
+ },
+ "id": "test-imp-id",
+ "bidfloorcur": "USD",
+ "bidfloor": 1.72,
+ "tagid": "pbs-local/preroll",
+ "video": {
+ "minduration": 5,
+ "startdelay": 0,
+ "api": [1, 2],
+ "w": 300,
+ "h": 169,
+ "mimes": [
+ "application/javascript",
+ "video/mp4",
+ "video/webm"
+ ],
+ "protocols": [2, 3, 5, 6, 7, 8],
+ "maxduration": 30,
+ "placement": 3,
+ "plcmt": 4,
+ "skip": 1,
+ "content": {
+ "channel": {
+ "name": "Bake",
+ "domain": "https://ttd-bake.com/chicken-lasagna/"
+ },
+ "context": 5,
+ "genre": "Food & Drink",
+ "cattax": 1,
+ "cat": ["IAB8", "IAB8", "IAB8-8"]
+ },
+ "playbackmethod": [2]
+ }
+ }
+ ],
+ "cur": ["USD"],
+ "site": {
+ "publisher": {
+ "id": "123456"
+ },
+ "mobile": 1,
+ "privacypolicy": 1,
+ "page": "https://example.com/chicken-lasagna/",
+ "domain": "ttd-bake.com",
+ "ref": "https://example.com/?s=easy+lasagna",
+ "id": "20619",
+ "name": "Bake With Zoha"
+ },
+ "device": {
+ "js": 1,
+ "w": 1680,
+ "h": 1050,
+ "osv": "NT 10.0",
+ "os": "Windows",
+ "dnt": 0,
+ "language": "en",
+ "ip": "66.129.221.46",
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
+ "sua": {
+ "source": 1,
+ "platform": {
+ "brand": "Windows"
+ },
+ "browsers": [
+ {
+ "brand": "Google Chrome",
+ "version": ["135"]
+ }
+ ],
+ "mobile": 0
+ },
+ "devicetype": 2
+ },
+ "test": 0,
+ "source": {
+ "fd": 1,
+ "pchain": "1363c924529b3998:20619",
+ "ext": {
+ "schain": {
+ "ver": "1.0",
+ "complete": 1,
+ "nodes": [
+ {
+ "asi": "example.com",
+ "sid": "050fd4e480110f1b92d451b879e6c780",
+ "hp": 1,
+ "rid": "4555b7da05efd4d4"
+ }
+ ]
+ }
+ }
+ },
+ "bcat": ["211", "211", "181", "524", "271", "514"],
+ "cattax": 6,
+ "tmax": 750
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://direct.adsrvr.org/bid/bidder/ttd",
+ "headers": {
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "tagid": "pbs-local/preroll",
+ "bidfloorcur": "USD",
+ "bidfloor": 1.72,
+ "video": {
+ "minduration": 5,
+ "maxduration": 30,
+ "api": [1,2],
+ "mimes": [
+ "application/javascript",
+ "video/mp4",
+ "video/webm"
+ ],
+ "placement": 3,
+ "protocols": [2, 3, 5, 6, 7, 8 ],
+ "w": 300,
+ "h": 169,
+ "playbackmethod": [2],
+ "plcmt": 4,
+ "skip": 1,
+ "startdelay": 0
+ },
+ "ext": {
+ "gpid": "/1030006,22910642311/bakewithzoha/recipe",
+ "bidder": {
+ "publisherId": "123456"
+ }
+ }
+ }
+ ],
+ "cur": ["USD"],
+ "site": {
+ "publisher": {
+ "id": "123456"
+ },
+ "mobile": 1,
+ "privacypolicy": 1,
+ "page": "https://example.com/chicken-lasagna/",
+ "domain": "ttd-bake.com",
+ "ref": "https://example.com/?s=easy+lasagna",
+ "id": "20619",
+ "name": "Bake With Zoha"
+ },
+ "device": {
+ "js": 1,
+ "w": 1680,
+ "h": 1050,
+ "osv": "NT 10.0",
+ "os": "Windows",
+ "dnt": 0,
+ "language": "en",
+ "ip": "66.129.221.46",
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
+ "sua": {
+ "source": 1,
+ "platform": {
+ "brand": "Windows"
+ },
+ "browsers": [
+ {
+ "brand": "Google Chrome",
+ "version": ["135"]
+ }
+ ],
+ "mobile": 0
+ },
+ "devicetype": 2
+ },
+ "source": {
+ "fd": 1,
+ "pchain": "1363c924529b3998:20619",
+ "ext": {
+ "schain": {
+ "ver": "1.0",
+ "complete": 1,
+ "nodes": [
+ {
+ "asi": "example.com",
+ "sid": "050fd4e480110f1b92d451b879e6c780",
+ "hp": 1,
+ "rid": "4555b7da05efd4d4"
+ }
+ ]
+ }
+ }
+ },
+ "bcat": ["211", "211", "181", "524", "271", "514"],
+ "cattax": 6,
+ "tmax": 750
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-imp-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "test-slot-id",
+ "impid": "test-imp-id",
+ "price": 0.1,
+ "adm": "some-test-valid-adm",
+ "cid": "test-imp-id-ortb-cid",
+ "crid": "creative-123",
+ "adomain": [
+ "ttd-ortb.com"
+ ],
+ "w": 640,
+ "h": 360,
+ "cat": [
+ "286",
+ "287",
+ "313"
+ ],
+ "cattax": 6,
+ "mtype": 2,
+ "dur": 30
+ }
+ ],
+ "seat": "5038"
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "test-slot-id",
+ "impid": "test-imp-id",
+ "price": 0.1,
+ "crid": "creative-123",
+ "cid": "test-imp-id-ortb-cid",
+ "adm": "some-test-valid-adm",
+ "w": 640,
+ "h": 360,
+ "dur": 30,
+ "mtype": 2,
+ "adomain": [
+ "ttd-ortb.com"
+ ],
+ "cattax": 6,
+ "cat": [
+ "286",
+ "287",
+ "313"
+ ]
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
+
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/prebidjs_response_video_parsing.json b/adapters/thetradedesk/thetradedesktest/exemplary/prebidjs_response_video_parsing.json
new file mode 100644
index 00000000000..24a532d4368
--- /dev/null
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/prebidjs_response_video_parsing.json
@@ -0,0 +1,308 @@
+{
+ "mockBidRequest": {
+ "id": "3621b7f6603b81ea08",
+ "imp": [
+ {
+ "id": "362240e73c1361aba",
+ "tagid": "/18190176,23070927648/AdThrive_Video_Coll_SOff_Smartphone/599de1450b08e2314df63095",
+ "video": {
+ "minduration": 1,
+ "maxduration": 15,
+ "api": [2, 7],
+ "mimes": ["video/mp4", "application/javascript"],
+ "placement": 1,
+ "protocols": [1, 2, 3, 4, 5, 6, 7, 8],
+ "w": 400,
+ "h": 225,
+ "playbackmethod": [6],
+ "plcmt": 2,
+ "pos": 1,
+ "startdelay": 0,
+ "linearity": 1,
+ "skip": 0,
+ "playbackend": 3
+ },
+ "bidfloor": 3.3507,
+ "bidfloorcur": "USD",
+ "secure": 1,
+ "ext": {
+ "bidder": {
+ "publisherId": "123456",
+ "supplySourceId": "pub_abc"
+ },
+ "data": {
+ "adserver": {
+ "name": "gam",
+ "adslot": "/18190176,23070927648/AdThrive_Video_Coll_SOff_Smartphone/599de1450b08e2314df63095"
+ },
+ "jwTargeting": {
+ "playerID": "s2WHEhYP",
+ "mediaID": "jJjdbKQW"
+ },
+ "pbadslot": "/18190176,23070927648/AdThrive_Video_Coll_SOff_Smartphone/599de1450b08e2314df63095"
+ },
+ "siteId": "1170765",
+ "gpid": "/18190176,23070927648/AdThrive_Video_Coll_SOff_Smartphone/599de1450b08e2314df63095"
+ }
+ }
+ ],
+ "site": {
+ "page": "ttd.com",
+ "id": "site-id"
+ },
+ "device": {
+ "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_3_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3.1 Mobile/15E148 Safari/604.1",
+ "dnt": 0,
+ "language": "en",
+ "connectiontype": 0,
+ "w": 375,
+ "h": 812,
+ "ext": {
+ "vpw": 375,
+ "vph": 740
+ },
+ "js": 1
+ },
+ "user": {
+ "ext": {
+ "eids": [
+ {
+ "source": "criteo.com",
+ "uids": [
+ {
+ "id": "198lR19LYzIxODFxc1d5WGxCelQ5ZDh1NWhqNUI2NGU2UDdOYnpJdHpNSk0lMkZ3aDhJeEdmWEVhSSUyQkRUYzlJcSUyQjElMkJzWTkyeGNaRHBzd0xxNVN0WGR1UXd3blRFYzBLRG9mMlclMkJhbDY0VWhNNDdORlIyUnVPVGN5a2NqdlZwZlR4NzdYcGo",
+ "atype": 1
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "at": 1,
+ "cur": ["USD"],
+ "source": {
+ "ext": {
+ "schain": {
+ "ver": "1.0",
+ "complete": 1,
+ "nodes": [
+ {
+ "asi": "example.com",
+ "sid": "599de1450b08e2314df63095",
+ "hp": 1
+ }
+ ]
+ }
+ }
+ },
+ "ext": {
+ "ttdprebid": {
+ "ver": "TTD-PREBID-2024.07.27",
+ "pbjs": "9.32.0",
+ "keywords": []
+ }
+ },
+ "bcat": [
+ "IAB8-5",
+ "IAB8-18"
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://direct.adsrvr.org/bid/bidder/pub_abc",
+ "headers": {
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "body": {
+ "id": "3621b7f6603b81ea08",
+ "at": 1,
+ "cur": ["USD"],
+ "bcat": [
+ "IAB8-5",
+ "IAB8-18"
+ ],
+ "site": {
+ "id": "site-id",
+ "page": "ttd.com",
+ "publisher": {
+ "id": "123456"
+ }
+ },
+ "source": {
+ "ext": {
+ "schain": {
+ "ver": "1.0",
+ "complete": 1,
+ "nodes": [
+ {
+ "asi": "example.com",
+ "sid": "599de1450b08e2314df63095",
+ "hp": 1
+ }
+ ]
+ }
+ }
+ },
+ "user": {
+ "ext": {
+ "eids": [
+ {
+ "source": "criteo.com",
+ "uids": [
+ {
+ "id": "198lR19LYzIxODFxc1d5WGxCelQ5ZDh1NWhqNUI2NGU2UDdOYnpJdHpNSk0lMkZ3aDhJeEdmWEVhSSUyQkRUYzlJcSUyQjElMkJzWTkyeGNaRHBzd0xxNVN0WGR1UXd3blRFYzBLRG9mMlclMkJhbDY0VWhNNDdORlIyUnVPVGN5a2NqdlZwZlR4NzdYcGo",
+ "atype": 1
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "ext": {
+ "ttdprebid": {
+ "ver": "TTD-PREBID-2024.07.27",
+ "pbjs": "9.32.0",
+ "keywords": []
+ }
+ },
+ "device": {
+ "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_3_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3.1 Mobile/15E148 Safari/604.1",
+ "dnt": 0,
+ "language": "en",
+ "connectiontype": 0,
+ "w": 375,
+ "h": 812,
+ "ext": {
+ "vpw": 375,
+ "vph": 740
+ },
+ "js": 1
+ },
+ "imp": [
+ {
+ "id": "362240e73c1361aba",
+ "tagid": "/18190176,23070927648/AdThrive_Video_Coll_SOff_Smartphone/599de1450b08e2314df63095",
+ "video": {
+ "minduration": 1,
+ "maxduration": 15,
+ "api": [2, 7],
+ "mimes": ["video/mp4", "application/javascript"],
+ "placement": 1,
+ "protocols": [1, 2, 3, 4, 5, 6, 7, 8],
+ "w": 400,
+ "h": 225,
+ "playbackmethod": [6],
+ "plcmt": 2,
+ "pos": 1,
+ "startdelay": 0,
+ "linearity": 1,
+ "skip": 0,
+ "playbackend": 3
+ },
+ "bidfloor": 3.3507,
+ "bidfloorcur": "USD",
+ "secure": 1,
+ "ext": {
+ "bidder": {
+ "publisherId": "123456",
+ "supplySourceId": "pub_abc"
+ },
+ "data": {
+ "adserver": {
+ "name": "gam",
+ "adslot": "/18190176,23070927648/AdThrive_Video_Coll_SOff_Smartphone/599de1450b08e2314df63095"
+ },
+ "jwTargeting": {
+ "playerID": "s2WHEhYP",
+ "mediaID": "jJjdbKQW"
+ },
+ "pbadslot": "/18190176,23070927648/AdThrive_Video_Coll_SOff_Smartphone/599de1450b08e2314df63095"
+ },
+ "siteId": "1170765",
+ "gpid": "/18190176,23070927648/AdThrive_Video_Coll_SOff_Smartphone/599de1450b08e2314df63095"
+ }
+ }
+ ]
+ },
+ "impIDs":["362240e73c1361aba"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "4555b7da05efd4d4",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "ttd-bid-1",
+ "impid": "ttd-bid-1-impid",
+ "price": 0.1,
+ "adm": "some-test-ad-vast",
+ "cid": "ttd_cid",
+ "crid": "creative-123",
+ "adomain": [
+ "ttd-bid.com"
+ ],
+ "w": 480,
+ "h": 360,
+ "cat": [
+ "IAB22"
+ ],
+ "mtype": 2,
+ "ext": {
+ "advid": "u143h4c",
+ "duration": 15,
+ "viewabilityvendors": [],
+ "mediatype": 2
+ }
+ }
+ ],
+ "seat": "1550"
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "ttd-bid-1",
+ "impid": "ttd-bid-1-impid",
+ "price": 0.1,
+ "crid": "creative-123",
+ "adm": "some-test-ad-vast",
+ "w": 480,
+ "h": 360,
+ "adomain": [
+ "ttd-bid.com"
+ ],
+ "cat": [
+ "IAB22"
+ ],
+ "cid": "ttd_cid",
+ "mtype": 2,
+ "ext": {
+ "advid": "u143h4c",
+ "duration": 15,
+ "viewabilityvendors": [],
+ "mediatype": 2
+ }
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
+
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-inapp.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-inapp.json
index e10445382c8..0b1ffe87001 100644
--- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-inapp.json
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-inapp.json
@@ -44,8 +44,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids-and-formats.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids-and-formats.json
index 0180d48dde2..6219c7d5ed4 100644
--- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids-and-formats.json
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids-and-formats.json
@@ -70,8 +70,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id-multiple-bids",
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids.json
index 4d46fa6907b..d9ab70a1d65 100644
--- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids.json
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner-multiple-bids.json
@@ -62,8 +62,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id-multiple-bids",
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner.json
index 4ac6acb0556..c7f904e524c 100644
--- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner.json
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-banner.json
@@ -44,8 +44,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-empty-publisherId.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-empty-publisherId.json
index ef6f6695553..f4ff473838d 100644
--- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-empty-publisherId.json
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-empty-publisherId.json
@@ -44,8 +44,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-banner.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-banner.json
index 10286c96081..a09ed5c2f4e 100644
--- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-banner.json
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-banner.json
@@ -47,8 +47,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-video.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-video.json
index e8f4bbca57c..01b39a4b7aa 100644
--- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-video.json
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-multi-type-video.json
@@ -47,8 +47,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-native.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-native.json
index 4d1b77ab0fb..8304adb1614 100644
--- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-native.json
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-native.json
@@ -29,8 +29,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/simple-video.json b/adapters/thetradedesk/thetradedesktest/exemplary/simple-video.json
index 5dc945bab1f..e238b34faf5 100644
--- a/adapters/thetradedesk/thetradedesktest/exemplary/simple-video.json
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/simple-video.json
@@ -49,8 +49,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/exemplary/use-supply-source-id-param.json b/adapters/thetradedesk/thetradedesktest/exemplary/use-supply-source-id-param.json
new file mode 100644
index 00000000000..d7d330de57a
--- /dev/null
+++ b/adapters/thetradedesk/thetradedesktest/exemplary/use-supply-source-id-param.json
@@ -0,0 +1,208 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "site": {
+ "id": "site-id",
+ "page": "ttd.com"
+ },
+ "device": {
+ "os": "android",
+ "ip": "91.199.242.236",
+ "ua": "random user agent"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "tagid": "pbs-local/preroll",
+ "video": {
+ "minduration": 0,
+ "maxduration": 60,
+ "api": [1,2],
+ "mimes": [
+ "video/mp4",
+ "video/webm",
+ "application/javascript"
+ ],
+ "placement": 1,
+ "protocols": [2,3,4,5,6],
+ "w": 300,
+ "h": 250,
+ "playbackmethod": [1,2,3,4,5,6],
+ "plcmt": 1,
+ "skip": 1
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "123456",
+ "supplySourceId": "publisher_xyz"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-2",
+ "tagid": "pbs-local/preroll",
+ "video": {
+ "minduration": 0,
+ "maxduration": 60,
+ "api": [1,2],
+ "mimes": [
+ "video/mp4",
+ "video/webm",
+ "application/javascript"
+ ],
+ "placement": 1,
+ "protocols": [2,3,4,5,6],
+ "w": 300,
+ "h": 250,
+ "playbackmethod": [1,2,3,4,5,6],
+ "plcmt": 1,
+ "skip": 1
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "987654",
+ "supplySourceId": "publisher_abc"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://direct.adsrvr.org/bid/bidder/publisher_xyz",
+ "headers": {
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "Accept": [
+ "application/json"
+ ]
+ },
+ "body": {
+ "id": "test-request-id",
+ "site": {
+ "id": "site-id",
+ "page": "ttd.com",
+ "publisher": {
+ "id": "123456"
+ }
+ },
+ "device": {
+ "os": "android",
+ "ip": "91.199.242.236",
+ "ua": "random user agent"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "tagid": "pbs-local/preroll",
+ "video": {
+ "maxduration": 60,
+ "api": [1,2],
+ "mimes": [
+ "video/mp4",
+ "video/webm",
+ "application/javascript"
+ ],
+ "placement": 1,
+ "protocols": [2,3,4,5,6],
+ "w": 300,
+ "h": 250,
+ "playbackmethod": [1,2,3,4,5,6],
+ "plcmt": 1,
+ "skip": 1
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "123456",
+ "supplySourceId": "publisher_xyz"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-2",
+ "tagid": "pbs-local/preroll",
+ "video": {
+ "maxduration": 60,
+ "api": [1,2],
+ "mimes": [
+ "video/mp4",
+ "video/webm",
+ "application/javascript"
+ ],
+ "placement": 1,
+ "protocols": [2,3,4,5,6],
+ "w": 300,
+ "h": 250,
+ "playbackmethod": [1,2,3,4,5,6],
+ "plcmt": 1,
+ "skip": 1
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "987654",
+ "supplySourceId": "publisher_abc"
+ }
+ }
+ }
+ ]
+ },
+ "impIDs":["test-imp-id", "test-imp-id-2"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "currency": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "test-slot-id",
+ "impid": "test-imp-id",
+ "price": 0.1,
+ "crid": "creative-123",
+ "adm": "some-test-ad-vast",
+ "h": 250,
+ "w": 300,
+ "ext": {
+ "prebid": {
+ "type": "video"
+ }
+ },
+ "mtype": 2
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "test-slot-id",
+ "impid": "test-imp-id",
+ "price": 0.1,
+ "crid": "creative-123",
+ "adm": "some-test-ad-vast",
+ "h": 250,
+ "w": 300,
+ "ext": {
+ "prebid": {
+ "type": "video"
+ }
+ },
+ "mtype": 2
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
+
diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/200-response-from-target.json b/adapters/thetradedesk/thetradedesktest/supplemental/200-response-from-target.json
index fdbe15ac48e..fa92fd45e49 100644
--- a/adapters/thetradedesk/thetradedesktest/supplemental/200-response-from-target.json
+++ b/adapters/thetradedesk/thetradedesktest/supplemental/200-response-from-target.json
@@ -46,8 +46,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/204-response-from-target.json b/adapters/thetradedesk/thetradedesktest/supplemental/204-response-from-target.json
index a329982ea50..06407e7cb83 100644
--- a/adapters/thetradedesk/thetradedesktest/supplemental/204-response-from-target.json
+++ b/adapters/thetradedesk/thetradedesktest/supplemental/204-response-from-target.json
@@ -46,8 +46,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/400-response-from-target.json b/adapters/thetradedesk/thetradedesktest/supplemental/400-response-from-target.json
index ad5ffc62b51..a177c5835fe 100644
--- a/adapters/thetradedesk/thetradedesktest/supplemental/400-response-from-target.json
+++ b/adapters/thetradedesk/thetradedesktest/supplemental/400-response-from-target.json
@@ -46,8 +46,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/500-response-from-target.json b/adapters/thetradedesk/thetradedesktest/supplemental/500-response-from-target.json
index f2ccb342113..b6526b6fd20 100644
--- a/adapters/thetradedesk/thetradedesktest/supplemental/500-response-from-target.json
+++ b/adapters/thetradedesk/thetradedesktest/supplemental/500-response-from-target.json
@@ -46,8 +46,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/invalid-mtype.json b/adapters/thetradedesk/thetradedesktest/supplemental/invalid-mtype.json
index 52b392eb835..077587438b2 100644
--- a/adapters/thetradedesk/thetradedesktest/supplemental/invalid-mtype.json
+++ b/adapters/thetradedesk/thetradedesktest/supplemental/invalid-mtype.json
@@ -25,8 +25,7 @@
],
"Accept": [
"application/json"
- ],
- "X-Integration-Type": ["1"]
+ ]
},
"body": {
"id": "test-request-id",
diff --git a/adapters/thetradedesk/thetradedesktest/supplemental/invalid-supplySourceId.json b/adapters/thetradedesk/thetradedesktest/supplemental/invalid-supplySourceId.json
new file mode 100644
index 00000000000..69f7898ccff
--- /dev/null
+++ b/adapters/thetradedesk/thetradedesktest/supplemental/invalid-supplySourceId.json
@@ -0,0 +1,45 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "app": {
+ "bundle": "test.app.bundle",
+ "publisher": {
+ "id": "this_id_will_be_replaced"
+ }
+ },
+ "device": {
+ "ifa": "test-ifa-123456",
+ "os": "android",
+ "ip": "91.199.242.236",
+ "ua": "random user agent"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "supplySourceId": 55555
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [],
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "cannot unmarshal openrtb_ext.ExtImpTheTradeDesk.SupplySourceId: expects \" or n, but found 5",
+ "comparison": "literal"
+ }
+ ]
+}
+
diff --git a/openrtb_ext/imp_thetradedesk.go b/openrtb_ext/imp_thetradedesk.go
index 89cca83f65e..bb2b628d773 100644
--- a/openrtb_ext/imp_thetradedesk.go
+++ b/openrtb_ext/imp_thetradedesk.go
@@ -1,8 +1,7 @@
package openrtb_ext
-// ExtImpTheTradeDesk defines the contract for bidrequest.imp[i].ext
-// PublisherId is mandatory parameters, others are optional parameters
-
+// ExtImpTheTradeDesk defines the contract for bidrequest.imp[i].ext.prebid.bidder.thetradedesk
type ExtImpTheTradeDesk struct {
- PublisherId string `json:"publisherId"`
+ PublisherId string `json:"publisherId"`
+ SupplySourceId string `json:"supplySourceId"`
}
diff --git a/static/bidder-params/thetradedesk.json b/static/bidder-params/thetradedesk.json
index 5a85cf2f516..63dae6d9785 100644
--- a/static/bidder-params/thetradedesk.json
+++ b/static/bidder-params/thetradedesk.json
@@ -6,7 +6,13 @@
"properties": {
"publisherId": {
"type": "string",
+ "minLength": 1,
"description": "An ID which identifies the publisher"
+ },
+ "supplySourceId": {
+ "type":"string",
+ "minLength": 1,
+ "description": "An ID provided by TheTradeDesk used to determine which endpoint to use"
}
},
"required": ["publisherId"]
From eabbf0c43baf641767a49cad21d0c67b399cd8e3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 24 Apr 2025 09:24:07 -0400
Subject: [PATCH 38/40] Bump golang.org/x/net from 0.36.0 to 0.38.0 (#4305)
---
go.mod | 8 ++++----
go.sum | 16 ++++++++--------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/go.mod b/go.mod
index e04389784fe..da0f47998e3 100644
--- a/go.mod
+++ b/go.mod
@@ -40,8 +40,8 @@ require (
github.com/vrischmann/go-metrics-influxdb v0.1.1
github.com/xeipuuv/gojsonschema v1.2.0
github.com/yudai/gojsondiff v1.0.0
- golang.org/x/net v0.36.0
- golang.org/x/text v0.22.0
+ golang.org/x/net v0.38.0
+ golang.org/x/text v0.23.0
google.golang.org/grpc v1.56.3
gopkg.in/evanphx/json-patch.v5 v5.9.0
gopkg.in/yaml.v3 v3.0.1
@@ -78,8 +78,8 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/yudai/pp v2.0.1+incompatible // indirect
- golang.org/x/crypto v0.35.0 // indirect
- golang.org/x/sys v0.30.0 // indirect
+ golang.org/x/crypto v0.36.0 // indirect
+ golang.org/x/sys v0.31.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
diff --git a/go.sum b/go.sum
index 1c03a4d375b..5398b2d6b1d 100644
--- a/go.sum
+++ b/go.sum
@@ -546,8 +546,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
-golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
+golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
+golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -632,8 +632,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
-golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
+golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
+golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -744,8 +744,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
-golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
+golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -758,8 +758,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
-golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
+golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
+golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
From 788397f49076b173fee43cd93cb50ffd85be3d7f Mon Sep 17 00:00:00 2001
From: TheodorCiuciucCriteo
Date: Thu, 24 Apr 2025 21:09:49 +0300
Subject: [PATCH 39/40] Criteo: Declare ORTB 2.6 support (#4311)
---
static/bidder-info/criteo.yaml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/static/bidder-info/criteo.yaml b/static/bidder-info/criteo.yaml
index 0695f0cc134..908bfd4aeb9 100644
--- a/static/bidder-info/criteo.yaml
+++ b/static/bidder-info/criteo.yaml
@@ -2,6 +2,10 @@ endpoint: "https://ssp-bidder.criteo.com/openrtb/pbs/auction/request?profile=230
maintainer:
email: "prebid@criteo.com"
gvlVendorID: 91
+openrtb:
+ version: 2.6
+ gpp-supported: true
+ multiformat-supported: true
capabilities:
app:
mediaTypes:
From 19d2cda55bdb4a7cfc29de0bfbf2d47cf2d0e707 Mon Sep 17 00:00:00 2001
From: SiddhantAgrawal
Date: Thu, 24 Apr 2025 23:53:59 +0530
Subject: [PATCH 40/40] InMobi: Add redirect usersync (#4310)
---
static/bidder-info/inmobi.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/static/bidder-info/inmobi.yaml b/static/bidder-info/inmobi.yaml
index 3f0c9b9b480..2ae242cec60 100644
--- a/static/bidder-info/inmobi.yaml
+++ b/static/bidder-info/inmobi.yaml
@@ -17,4 +17,6 @@ userSync:
iframe:
url: "https://sync.inmobi.com/prebid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}"
userMacro: "{ID5UID}"
-
+ redirect:
+ url: "https://sync.inmobi.com/prebid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}"
+ userMacro: "{ID5UID}"