diff --git a/deploy/databases-development.json b/deploy/databases-development.json index 900f06115..efe5a426b 100644 --- a/deploy/databases-development.json +++ b/deploy/databases-development.json @@ -46,6 +46,27 @@ "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]" ] }, + { + "properties": { + "resource": { + "id": "Billing", + "partitionKey": { + "paths": [ + "/id" + ], + "kind": "Hash" + } + }, + "options": {} + }, + "name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Billing')]", + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "location": "[resourceGroup().location]", + "apiVersion": "2019-08-01", + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]" + ] + }, { "properties": { "resource": { diff --git a/deploy/rp-production.json b/deploy/rp-production.json index 5519c0d99..56b8934c1 100644 --- a/deploy/rp-production.json +++ b/deploy/rp-production.json @@ -491,6 +491,28 @@ "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))]" ] }, + { + "properties": { + "resource": { + "id": "Billing", + "partitionKey": { + "paths": [ + "/id" + ], + "kind": "Hash" + } + }, + "options": {} + }, + "name": "[concat(parameters('databaseAccountName'), '/', 'ARO', '/Billing')]", + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "location": "[resourceGroup().location]", + "apiVersion": "2019-08-01", + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), 'ARO')]", + "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))]" + ] + }, { "properties": { "resource": { diff --git a/hack/e2e/run-rp-and-e2e.sh b/hack/e2e/run-rp-and-e2e.sh index 3a27f9ec5..28498d643 100755 --- a/hack/e2e/run-rp-and-e2e.sh +++ b/hack/e2e/run-rp-and-e2e.sh @@ -134,6 +134,7 @@ echo "######################################" echo "######## Current settings : ##########" echo echo "LOCATION=$LOCATION" +echo "AZURE_SUBSCRIPTION_ID=$AZURE_SUBSCRIPTION_ID" echo echo "COSMOSDB_ACCOUNT=$COSMOSDB_ACCOUNT" echo "DATABASE_NAME=$DATABASE_NAME" @@ -151,3 +152,6 @@ echo "######################################" [ "$PROXY_HOSTNAME" ] || ( echo ">> PROXY_HOSTNAME is not set please validate your ./secrets/env"; exit 128 ) [ "$COSMOSDB_ACCOUNT" ] || ( echo ">> COSMOSDB_ACCOUNT is not set please validate your ./secrets/env"; exit 128 ) [ "$DATABASE_NAME" ] || ( echo ">> DATABASE_NAME is not set please validate your ./secrets/env"; exit 128 ) +[ "$AZURE_SUBSCRIPTION_ID" ] || ( echo ">> AZURE_SUBSCRIPTION_ID is not set please validate your ./secrets/env"; exit 128 ) + +az account set -s $AZURE_SUBSCRIPTION_ID >/dev/null diff --git a/pkg/api/billing.go b/pkg/api/billing.go new file mode 100644 index 000000000..f5f178ad6 --- /dev/null +++ b/pkg/api/billing.go @@ -0,0 +1,16 @@ +package api + +// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0. + +// Billing represents a Billing entry +type Billing struct { + MissingFields + + CreationTime int `json:"creationTime,omitempty"` + DeletionTime int `json:"deletionTime,omitempty"` + LastBillingTime int `json:"lastBillingTime,omitempty"` + + Location string `json:"location,omitempty"` + TenantID string `json:"tenantID,omitempty"` +} diff --git a/pkg/api/billingdocument.go b/pkg/api/billingdocument.go new file mode 100644 index 000000000..2ae418dac --- /dev/null +++ b/pkg/api/billingdocument.go @@ -0,0 +1,32 @@ +package api + +// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0. + +// BillingDocuments represents billing documents. +// pkg/database/cosmosdb requires its definition. +type BillingDocuments struct { + Count int `json:"_count,omitempty"` + ResourceID string `json:"_rid,omitempty"` + BillingDocuments []*BillingDocument `json:"Documents,omitempty"` +} + +// BillingDocument represents a billing document. +// pkg/database/cosmosdb requires its definition. +type BillingDocument struct { + MissingFields + + ID string `json:"id,omitempty"` + ResourceID string `json:"_rid,omitempty"` + Timestamp int `json:"_ts,omitempty"` + Self string `json:"_self,omitempty"` + ETag string `json:"_etag,omitempty"` + Attachments string `json:"_attachments,omitempty"` + LSN int `json:"_lsn,omitempty"` + Metadata map[string]interface{} `json:"_metadata,omitempty"` + + Billing *Billing `json:"billing,omitempty"` + + Key string `json:"key,omitempty"` + ClusterResourceGroupIDKey string `json:"clusterResourceGroupIDKey,omitempty"` +} diff --git a/pkg/backend/openshiftcluster.go b/pkg/backend/openshiftcluster.go index b2589dd2c..4927c480a 100644 --- a/pkg/backend/openshiftcluster.go +++ b/pkg/backend/openshiftcluster.go @@ -92,7 +92,7 @@ func (ocb *openShiftClusterBackend) handle(ctx context.Context, log *logrus.Entr stop := ocb.heartbeat(ctx, cancel, log, doc) defer stop() - m, err := openshiftcluster.NewManager(log, ocb.env, ocb.db.OpenShiftClusters, doc) + m, err := openshiftcluster.NewManager(log, ocb.env, ocb.db.OpenShiftClusters, ocb.db.Billing, doc) if err != nil { log.Error(err) return ocb.endLease(ctx, stop, doc, api.ProvisioningStateFailed, err) diff --git a/pkg/backend/openshiftcluster/create.go b/pkg/backend/openshiftcluster/create.go index 2ec9e53bf..d347212c7 100644 --- a/pkg/backend/openshiftcluster/create.go +++ b/pkg/backend/openshiftcluster/create.go @@ -231,7 +231,7 @@ func (m *Manager) Create(ctx context.Context) error { return err } - i, err := install.NewInstaller(ctx, m.log, m.env, m.db, m.doc) + i, err := install.NewInstaller(ctx, m.log, m.env, m.db, m.billing, m.doc) if err != nil { return err } diff --git a/pkg/backend/openshiftcluster/delete.go b/pkg/backend/openshiftcluster/delete.go index 0e59a0bc1..9db31920b 100644 --- a/pkg/backend/openshiftcluster/delete.go +++ b/pkg/backend/openshiftcluster/delete.go @@ -91,5 +91,13 @@ func (m *Manager) Delete(ctx context.Context) error { detailedErr.StatusCode == http.StatusForbidden { err = nil } + + if err != nil { + return err + } + + m.log.Printf("updating billing record with deletion time") + _, err = m.billing.MarkForDeletion(ctx, m.doc.ID) + return err } diff --git a/pkg/backend/openshiftcluster/openshiftcluster.go b/pkg/backend/openshiftcluster/openshiftcluster.go index 6a79b8461..8204420ae 100644 --- a/pkg/backend/openshiftcluster/openshiftcluster.go +++ b/pkg/backend/openshiftcluster/openshiftcluster.go @@ -22,6 +22,7 @@ type Manager struct { log *logrus.Entry env env.Interface db database.OpenShiftClusters + billing database.Billing fpAuthorizer autorest.Authorizer groups resources.GroupsClient @@ -34,7 +35,7 @@ type Manager struct { doc *api.OpenShiftClusterDocument } -func NewManager(log *logrus.Entry, env env.Interface, db database.OpenShiftClusters, doc *api.OpenShiftClusterDocument) (*Manager, error) { +func NewManager(log *logrus.Entry, env env.Interface, db database.OpenShiftClusters, billing database.Billing, doc *api.OpenShiftClusterDocument) (*Manager, error) { r, err := azure.ParseResourceID(doc.OpenShiftCluster.ID) if err != nil { return nil, err @@ -59,6 +60,7 @@ func NewManager(log *logrus.Entry, env env.Interface, db database.OpenShiftClust log: log, env: env, db: db, + billing: billing, fpAuthorizer: fpAuthorizer, groups: resources.NewGroupsClient(r.SubscriptionID, fpAuthorizer), diff --git a/pkg/database/billing.go b/pkg/database/billing.go new file mode 100644 index 000000000..5a097cf69 --- /dev/null +++ b/pkg/database/billing.go @@ -0,0 +1,124 @@ +package database + +// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0. + +import ( + "context" + "fmt" + "net/http" + "strings" + + "github.com/Azure/ARO-RP/pkg/api" + "github.com/Azure/ARO-RP/pkg/database/cosmosdb" +) + +type billing struct { + c cosmosdb.BillingDocumentClient + uuid string +} + +// Billing is the database interface for BillingDocuments +type Billing interface { + Create(context.Context, *api.BillingDocument) (*api.BillingDocument, error) + Get(context.Context, string) (*api.BillingDocument, error) + MarkForDeletion(context.Context, string) (*api.BillingDocument, error) +} + +// NewBilling returns a new Billing +func NewBilling(ctx context.Context, uuid string, dbc cosmosdb.DatabaseClient, dbid, collid string) (Billing, error) { + collc := cosmosdb.NewCollectionClient(dbc, dbid) + + triggers := []*cosmosdb.Trigger{ + { + ID: "setCreationBillingTimeStamp", + TriggerOperation: cosmosdb.TriggerOperationCreate, + TriggerType: cosmosdb.TriggerTypePre, + Body: `function trigger() { + var request = getContext().getRequest(); + var body = request.getBody(); + var date = new Date(); + var now = Math.floor(date.getTime() / 1000); + var billingBody = body["billing"]; + if (!billingBody["creationTime"]) { + billingBody["creationTime"] = now; + } + request.setBody(body); +}`, + }, + { + ID: "setDeletionBillingTimeStamp", + TriggerOperation: cosmosdb.TriggerOperationReplace, + TriggerType: cosmosdb.TriggerTypePre, + Body: `function trigger() { + var request = getContext().getRequest(); + var body = request.getBody(); + var date = new Date(); + var now = Math.floor(date.getTime() / 1000); + var billingBody = body["billing"]; + if (!billingBody["deletionTime"]) { + billingBody["deletionTime"] = now; + } + request.setBody(body); +}`, + }, + } + + triggerc := cosmosdb.NewTriggerClient(collc, collid) + for _, trigger := range triggers { + _, err := triggerc.Create(ctx, trigger) + if err != nil && !cosmosdb.IsErrorStatusCode(err, http.StatusConflict) { + return nil, err + } + } + + return &billing{ + c: cosmosdb.NewBillingDocumentClient(collc, collid), + uuid: uuid, + }, nil +} + +// Creating Billing Document +func (c *billing) Create(ctx context.Context, doc *api.BillingDocument) (*api.BillingDocument, error) { + if doc.ID != strings.ToLower(doc.ID) { + return nil, fmt.Errorf("id %q is not lower case", doc.ID) + } + + return c.c.Create(ctx, doc.ID, doc, &cosmosdb.Options{PreTriggers: []string{"setCreationBillingTimeStamp"}}) +} + +func (c *billing) Get(ctx context.Context, id string) (*api.BillingDocument, error) { + if id != strings.ToLower(id) { + return nil, fmt.Errorf("id %q is not lower case", id) + } + + return c.c.Get(ctx, id, id, nil) +} + +func (c *billing) patch(ctx context.Context, id string, f func(*api.BillingDocument) error, options *cosmosdb.Options) (*api.BillingDocument, error) { + var doc *api.BillingDocument + + err := cosmosdb.RetryOnPreconditionFailed(func() (err error) { + doc, err = c.Get(ctx, id) + if err != nil { + return + } + + err = f(doc) + if err != nil { + return + } + + doc, err = c.c.Replace(ctx, doc.ID, doc, options) + return + }) + + return doc, err +} + +// MarkForDeletion update the deletion timestamp field in the document +func (c *billing) MarkForDeletion(ctx context.Context, id string) (*api.BillingDocument, error) { + return c.patch(ctx, id, func(billingdoc *api.BillingDocument) error { + return nil + }, &cosmosdb.Options{PreTriggers: []string{"setDeletionBillingTimeStamp"}}) +} diff --git a/pkg/database/cosmosdb/generate.go b/pkg/database/cosmosdb/generate.go index 4f5071009..ce51f46a2 100644 --- a/pkg/database/cosmosdb/generate.go +++ b/pkg/database/cosmosdb/generate.go @@ -1,4 +1,4 @@ -//go:generate go run ../../../vendor/github.com/jim-minter/go-cosmosdb/cmd/gencosmosdb github.com/Azure/ARO-RP/pkg/api,AsyncOperationDocument github.com/Azure/ARO-RP/pkg/api,MonitorDocument github.com/Azure/ARO-RP/pkg/api,OpenShiftClusterDocument github.com/Azure/ARO-RP/pkg/api,SubscriptionDocument +//go:generate go run ../../../vendor/github.com/jim-minter/go-cosmosdb/cmd/gencosmosdb github.com/Azure/ARO-RP/pkg/api,AsyncOperationDocument github.com/Azure/ARO-RP/pkg/api,BillingDocument github.com/Azure/ARO-RP/pkg/api,MonitorDocument github.com/Azure/ARO-RP/pkg/api,OpenShiftClusterDocument github.com/Azure/ARO-RP/pkg/api,SubscriptionDocument //go:generate go run ../../../vendor/github.com/golang/mock/mockgen -destination=../../util/mocks/database/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/database/$GOPACKAGE OpenShiftClusterDocumentIterator //go:generate go run ../../../vendor/golang.org/x/tools/cmd/goimports -local=github.com/Azure/ARO-RP -e -w ../../util/mocks/database/$GOPACKAGE/$GOPACKAGE.go diff --git a/pkg/database/cosmosdb/zz_generated_billingdocument.go b/pkg/database/cosmosdb/zz_generated_billingdocument.go new file mode 100644 index 000000000..46eb88bc7 --- /dev/null +++ b/pkg/database/cosmosdb/zz_generated_billingdocument.go @@ -0,0 +1,289 @@ +// Code generated by github.com/jim-minter/go-cosmosdb, DO NOT EDIT. + +package cosmosdb + +import ( + "context" + "net/http" + "strings" + + pkg "github.com/Azure/ARO-RP/pkg/api" +) + +type billingDocumentClient struct { + *databaseClient + path string +} + +// BillingDocumentClient is a billingDocument client +type BillingDocumentClient interface { + Create(context.Context, string, *pkg.BillingDocument, *Options) (*pkg.BillingDocument, error) + List(*Options) BillingDocumentRawIterator + ListAll(context.Context, *Options) (*pkg.BillingDocuments, error) + Get(context.Context, string, string, *Options) (*pkg.BillingDocument, error) + Replace(context.Context, string, *pkg.BillingDocument, *Options) (*pkg.BillingDocument, error) + Delete(context.Context, string, *pkg.BillingDocument, *Options) error + Query(string, *Query, *Options) BillingDocumentRawIterator + QueryAll(context.Context, string, *Query, *Options) (*pkg.BillingDocuments, error) + ChangeFeed(*Options) BillingDocumentIterator +} + +type billingDocumentChangeFeedIterator struct { + *billingDocumentClient + continuation string + options *Options +} + +type billingDocumentListIterator struct { + *billingDocumentClient + continuation string + done bool + options *Options +} + +type billingDocumentQueryIterator struct { + *billingDocumentClient + partitionkey string + query *Query + continuation string + done bool + options *Options +} + +// BillingDocumentIterator is a billingDocument iterator +type BillingDocumentIterator interface { + Next(context.Context) (*pkg.BillingDocuments, error) +} + +// BillingDocumentRawIterator is a billingDocument raw iterator +type BillingDocumentRawIterator interface { + BillingDocumentIterator + NextRaw(context.Context, interface{}) error +} + +// NewBillingDocumentClient returns a new billingDocument client +func NewBillingDocumentClient(collc CollectionClient, collid string) BillingDocumentClient { + return &billingDocumentClient{ + databaseClient: collc.(*collectionClient).databaseClient, + path: collc.(*collectionClient).path + "/colls/" + collid, + } +} + +func (c *billingDocumentClient) all(ctx context.Context, i BillingDocumentIterator) (*pkg.BillingDocuments, error) { + allbillingDocuments := &pkg.BillingDocuments{} + + for { + billingDocuments, err := i.Next(ctx) + if err != nil { + return nil, err + } + if billingDocuments == nil { + break + } + + allbillingDocuments.Count += billingDocuments.Count + allbillingDocuments.ResourceID = billingDocuments.ResourceID + allbillingDocuments.BillingDocuments = append(allbillingDocuments.BillingDocuments, billingDocuments.BillingDocuments...) + } + + return allbillingDocuments, nil +} + +func (c *billingDocumentClient) Create(ctx context.Context, partitionkey string, newbillingDocument *pkg.BillingDocument, options *Options) (billingDocument *pkg.BillingDocument, err error) { + headers := http.Header{} + headers.Set("X-Ms-Documentdb-Partitionkey", `["`+partitionkey+`"]`) + + if options == nil { + options = &Options{} + } + options.NoETag = true + + err = c.setOptions(options, newbillingDocument, headers) + if err != nil { + return + } + + err = c.do(ctx, http.MethodPost, c.path+"/docs", "docs", c.path, http.StatusCreated, &newbillingDocument, &billingDocument, headers) + return +} + +func (c *billingDocumentClient) List(options *Options) BillingDocumentRawIterator { + return &billingDocumentListIterator{billingDocumentClient: c, options: options} +} + +func (c *billingDocumentClient) ListAll(ctx context.Context, options *Options) (*pkg.BillingDocuments, error) { + return c.all(ctx, c.List(options)) +} + +func (c *billingDocumentClient) Get(ctx context.Context, partitionkey, billingDocumentid string, options *Options) (billingDocument *pkg.BillingDocument, err error) { + headers := http.Header{} + headers.Set("X-Ms-Documentdb-Partitionkey", `["`+partitionkey+`"]`) + + err = c.setOptions(options, nil, headers) + if err != nil { + return + } + + err = c.do(ctx, http.MethodGet, c.path+"/docs/"+billingDocumentid, "docs", c.path+"/docs/"+billingDocumentid, http.StatusOK, nil, &billingDocument, headers) + return +} + +func (c *billingDocumentClient) Replace(ctx context.Context, partitionkey string, newbillingDocument *pkg.BillingDocument, options *Options) (billingDocument *pkg.BillingDocument, err error) { + headers := http.Header{} + headers.Set("X-Ms-Documentdb-Partitionkey", `["`+partitionkey+`"]`) + + err = c.setOptions(options, newbillingDocument, headers) + if err != nil { + return + } + + err = c.do(ctx, http.MethodPut, c.path+"/docs/"+newbillingDocument.ID, "docs", c.path+"/docs/"+newbillingDocument.ID, http.StatusOK, &newbillingDocument, &billingDocument, headers) + return +} + +func (c *billingDocumentClient) Delete(ctx context.Context, partitionkey string, billingDocument *pkg.BillingDocument, options *Options) (err error) { + headers := http.Header{} + headers.Set("X-Ms-Documentdb-Partitionkey", `["`+partitionkey+`"]`) + + err = c.setOptions(options, billingDocument, headers) + if err != nil { + return + } + + err = c.do(ctx, http.MethodDelete, c.path+"/docs/"+billingDocument.ID, "docs", c.path+"/docs/"+billingDocument.ID, http.StatusNoContent, nil, nil, headers) + return +} + +func (c *billingDocumentClient) Query(partitionkey string, query *Query, options *Options) BillingDocumentRawIterator { + return &billingDocumentQueryIterator{billingDocumentClient: c, partitionkey: partitionkey, query: query, options: options} +} + +func (c *billingDocumentClient) QueryAll(ctx context.Context, partitionkey string, query *Query, options *Options) (*pkg.BillingDocuments, error) { + return c.all(ctx, c.Query(partitionkey, query, options)) +} + +func (c *billingDocumentClient) ChangeFeed(options *Options) BillingDocumentIterator { + return &billingDocumentChangeFeedIterator{billingDocumentClient: c} +} + +func (c *billingDocumentClient) setOptions(options *Options, billingDocument *pkg.BillingDocument, headers http.Header) error { + if options == nil { + return nil + } + + if billingDocument != nil && !options.NoETag { + if billingDocument.ETag == "" { + return ErrETagRequired + } + headers.Set("If-Match", billingDocument.ETag) + } + if len(options.PreTriggers) > 0 { + headers.Set("X-Ms-Documentdb-Pre-Trigger-Include", strings.Join(options.PreTriggers, ",")) + } + if len(options.PostTriggers) > 0 { + headers.Set("X-Ms-Documentdb-Post-Trigger-Include", strings.Join(options.PostTriggers, ",")) + } + if len(options.PartitionKeyRangeID) > 0 { + headers.Set("X-Ms-Documentdb-PartitionKeyRangeID", options.PartitionKeyRangeID) + } + + return nil +} + +func (i *billingDocumentChangeFeedIterator) Next(ctx context.Context) (billingDocuments *pkg.BillingDocuments, err error) { + headers := http.Header{} + headers.Set("A-IM", "Incremental feed") + + headers.Set("X-Ms-Max-Item-Count", "-1") + if i.continuation != "" { + headers.Set("If-None-Match", i.continuation) + } + + err = i.setOptions(i.options, nil, headers) + if err != nil { + return + } + + err = i.do(ctx, http.MethodGet, i.path+"/docs", "docs", i.path, http.StatusOK, nil, &billingDocuments, headers) + if IsErrorStatusCode(err, http.StatusNotModified) { + err = nil + } + if err != nil { + return + } + + i.continuation = headers.Get("Etag") + + return +} + +func (i *billingDocumentListIterator) Next(ctx context.Context) (billingDocuments *pkg.BillingDocuments, err error) { + err = i.NextRaw(ctx, &billingDocuments) + return +} + +func (i *billingDocumentListIterator) NextRaw(ctx context.Context, raw interface{}) (err error) { + if i.done { + return + } + + headers := http.Header{} + headers.Set("X-Ms-Max-Item-Count", "-1") + if i.continuation != "" { + headers.Set("X-Ms-Continuation", i.continuation) + } + + err = i.setOptions(i.options, nil, headers) + if err != nil { + return + } + + err = i.do(ctx, http.MethodGet, i.path+"/docs", "docs", i.path, http.StatusOK, nil, &raw, headers) + if err != nil { + return + } + + i.continuation = headers.Get("X-Ms-Continuation") + i.done = i.continuation == "" + + return +} + +func (i *billingDocumentQueryIterator) Next(ctx context.Context) (billingDocuments *pkg.BillingDocuments, err error) { + err = i.NextRaw(ctx, &billingDocuments) + return +} + +func (i *billingDocumentQueryIterator) NextRaw(ctx context.Context, raw interface{}) (err error) { + if i.done { + return + } + + headers := http.Header{} + headers.Set("X-Ms-Max-Item-Count", "-1") + headers.Set("X-Ms-Documentdb-Isquery", "True") + headers.Set("Content-Type", "application/query+json") + if i.partitionkey != "" { + headers.Set("X-Ms-Documentdb-Partitionkey", `["`+i.partitionkey+`"]`) + } else { + headers.Set("X-Ms-Documentdb-Query-Enablecrosspartition", "True") + } + if i.continuation != "" { + headers.Set("X-Ms-Continuation", i.continuation) + } + + err = i.setOptions(i.options, nil, headers) + if err != nil { + return + } + + err = i.do(ctx, http.MethodPost, i.path+"/docs", "docs", i.path, http.StatusOK, &i.query, &raw, headers) + if err != nil { + return + } + + i.continuation = headers.Get("X-Ms-Continuation") + i.done = i.continuation == "" + + return +} diff --git a/pkg/database/database.go b/pkg/database/database.go index f942d600c..b254cdff5 100644 --- a/pkg/database/database.go +++ b/pkg/database/database.go @@ -27,6 +27,7 @@ type Database struct { m metrics.Interface AsyncOperations AsyncOperations + Billing Billing Monitors Monitors OpenShiftClusters OpenShiftClusters Subscriptions Subscriptions @@ -62,6 +63,11 @@ func NewDatabase(ctx context.Context, log *logrus.Entry, env env.Interface, m me return nil, err } + db.Billing, err = NewBilling(ctx, uuid, dbc, env.DatabaseName(), "Billing") + if err != nil { + return nil, err + } + db.Monitors, err = NewMonitors(ctx, uuid, dbc, env.DatabaseName(), "Monitors") if err != nil { return nil, err diff --git a/pkg/database/generate.go b/pkg/database/generate.go index 304f38250..658bc790a 100644 --- a/pkg/database/generate.go +++ b/pkg/database/generate.go @@ -3,5 +3,5 @@ package database // Copyright (c) Microsoft Corporation. // Licensed under the Apache License 2.0. -//go:generate go run ../../vendor/github.com/golang/mock/mockgen -destination=../util/mocks/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/$GOPACKAGE AsyncOperations,OpenShiftClusters,Subscriptions +//go:generate go run ../../vendor/github.com/golang/mock/mockgen -destination=../util/mocks/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/$GOPACKAGE AsyncOperations,Billing,OpenShiftClusters,Subscriptions //go:generate go run ../../vendor/golang.org/x/tools/cmd/goimports -local=github.com/Azure/ARO-RP -e -w ../util/mocks/$GOPACKAGE/$GOPACKAGE.go diff --git a/pkg/deploy/bindata.go b/pkg/deploy/bindata.go index 405b9a52d..1017616c8 100644 --- a/pkg/deploy/bindata.go +++ b/pkg/deploy/bindata.go @@ -84,7 +84,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _databasesDevelopmentJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x57\x5d\x4f\xdb\x3c\x18\xbd\xef\xaf\x88\xfc\xbe\x52\x5a\xa9\xf9\x42\x6c\x62\xbd\x63\x43\xda\x10\x62\x4c\x03\xed\xa6\xea\x85\x71\x9e\x12\x8f\xc4\x36\xf6\x13\x69\xdd\xc4\x7f\x9f\x9c\x34\xfd\x8a\x53\x86\x04\x6c\x54\x35\x57\xd8\x27\xe7\xf9\x3a\xc7\x56\x7f\xf5\x3c\xcf\xf3\xc8\xff\x86\x65\x50\x50\x32\xf2\x48\x86\xa8\xcc\x28\x8a\xea\x9d\xb0\xa0\x82\xde\x40\x01\x02\x43\xfa\xb3\xd4\x10\x32\x59\xcc\xcf\x4c\x74\x10\x27\x6f\x82\x38\x09\xe2\x24\x4a\x41\xe5\x72\x66\x71\x57\x50\xa8\x9c\x22\x84\xdf\x8d\x14\xff\x91\x61\x1d\x81\x49\x81\x20\xf0\x1b\x68\xc3\xa5\xb0\x81\x92\x30\xb6\x7f\x0d\x40\x51\x4d\x0b\x40\xd0\x86\x8c\xbc\x3a\xad\x6a\x3f\xa5\x48\xaf\xa9\x81\x63\xc6\x64\x29\xf0\x33\x2d\x60\x0d\x50\x81\x70\xa6\xec\x2e\x31\xa8\xb9\xb8\x21\x8b\xc3\xfb\x61\x9b\xe8\x91\x0c\xbd\x15\x1e\xa2\xc1\xc8\x52\x33\xb0\x39\x8e\x17\x98\x0d\x2a\xa5\xa5\x02\x8d\x1c\x4c\x2b\xcc\x1a\x89\xf3\xb4\x42\xf0\xd4\xa6\x32\x5e\xb6\xa4\xef\xaf\x66\xef\x0f\x26\xa4\xf5\xe1\x4a\xa9\x0b\x1e\xa9\x90\x4b\xe1\x4e\xa3\x02\xfc\x08\x0a\x13\xc8\xe9\x14\x74\x80\x99\x96\xe5\x4d\xa6\x4a\xb4\xb1\x0f\xe3\xd8\x11\xa2\xb7\x25\x20\x11\x75\x5f\xc9\x98\x49\xc1\x28\xf6\x5d\xd9\xaf\x0c\xd1\x1f\x0c\x3d\x3f\xf2\x87\x5e\x77\x95\x83\x09\x19\xba\xa7\x74\xce\x99\x96\x46\x4e\x31\x3c\x91\xac\xb4\xaa\x3b\x79\x1f\x6d\x04\x31\x91\xb9\xcb\x4f\xe6\x7b\x66\x93\x29\x97\x8c\xe2\x5c\x89\xe3\x66\x22\x1f\xb5\x2c\x55\x7f\x10\x36\x87\xad\xf8\x54\xf1\x15\x05\x1f\xc4\xc9\xbb\x20\x3e\x0a\xe2\xc4\xa9\xb8\x67\x92\xc5\xb1\x99\x09\x76\xa1\x40\xd3\x7a\xb8\xed\xb9\x7b\x73\x3f\x21\xb7\x88\x33\x98\x75\x52\xce\x91\x98\xad\x0b\xda\x09\x8b\x78\xda\x96\x44\xb3\x26\xee\x2c\xaa\x0f\x6f\xb9\xa8\x12\xff\x44\x4d\xe6\x66\x70\x68\xb7\xfa\x32\x85\x29\x2d\x73\xbc\xc2\x9c\x8c\xbc\xb7\xf1\xe1\x51\x1c\x3f\x56\xf7\x2f\xad\x59\x0b\xd8\x98\x90\xff\x94\x3a\x8e\xec\x45\x4a\xb9\xb0\xf7\xe4\xf3\x4a\x7a\x03\x97\x82\x02\x91\x9a\x0b\xe1\x54\xca\x32\xe0\x69\xda\xf7\x1f\x5f\x56\x47\x4f\x37\x7a\xbf\xf5\xaa\x58\xcb\x69\xf2\x82\x86\x3c\x97\x82\xa3\x6c\xcd\x63\x19\x67\xd7\x9c\x18\x24\xaf\xc1\x85\xcd\x58\xf6\xf6\xdb\x6d\xfb\x5d\x28\x10\x97\x19\x9f\xe2\x87\xbc\x34\xd8\x1e\xcc\x32\xe0\x93\xfb\x70\x8d\xf1\x85\x1d\x59\x0a\x7e\x57\xc2\x19\xcc\xbe\xc8\x9c\xb3\x07\x0a\x5a\x80\x1f\xae\xaa\x9b\x65\xc1\xf6\x67\xed\x59\xc0\xa3\xdb\x6d\xdd\x69\xd6\x64\x2b\xa2\xa3\x0b\xcd\x7a\x86\xa4\x59\xad\xa6\xaf\xab\x46\x3e\x4d\xb7\x0e\xba\x59\xff\x5e\x29\x1c\x04\x3e\x4d\xf2\xdd\x2a\x77\xab\xf7\x35\xbc\x14\xad\x1b\x64\xff\x64\xec\xf6\x93\x71\x59\x5e\x1b\xa6\xb9\xda\x9d\x1f\x50\xaf\xc1\x66\x6b\x5d\xdf\x5b\xec\xaf\x5a\xac\x57\xff\x7f\xdf\xfb\x1d\x00\x00\xff\xff\x47\x7b\x47\xa9\x01\x14\x00\x00") +var _databasesDevelopmentJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x58\x5f\x4f\xdb\x3e\x14\x7d\xef\xa7\x88\xfc\xfb\x49\x69\xa5\xe6\x1f\x62\x13\xeb\x1b\x0c\x69\x43\x88\x31\x0d\xb4\x97\xaa\x0f\xc6\xb9\x25\x1e\x89\x6d\xec\x6b\x69\xdd\xc4\x77\x9f\x9c\x34\xfd\x97\xb4\x80\x04\x6c\xad\xea\x3e\xd5\x3e\x3e\xf7\xfa\xde\x73\xec\xaa\xbf\x3b\x9e\xe7\x79\xe4\x7f\xc3\x32\x28\x28\x19\x78\x24\x43\x54\x66\x10\x45\xd5\x4c\x58\x50\x41\x6f\xa1\x00\x81\x21\xfd\x65\x35\x84\x4c\x16\xd3\x35\x13\x1d\xc4\xc9\xbb\x20\x4e\x82\x38\x89\x52\x50\xb9\x9c\x38\xdc\x35\x14\x2a\xa7\x08\xe1\x0f\x23\xc5\x7f\xa4\x5f\x45\x60\x52\x20\x08\xfc\x0e\xda\x70\x29\x5c\xa0\x24\x8c\xdd\xa7\x06\x28\xaa\x69\x01\x08\xda\x90\x81\x57\xa5\x55\xce\xa7\x14\xe9\x0d\x35\x70\xcc\x98\xb4\x02\xbf\xd0\x02\x96\x00\x25\x08\x27\xca\xcd\x12\x83\x9a\x8b\x5b\x32\x5b\x7c\xe8\x37\x89\x9e\xc9\xd0\x59\xe0\x21\x1a\x8c\xb4\x9a\x81\xcb\x71\x38\xc3\xac\x50\x29\x2d\x15\x68\xe4\x60\x1a\x61\x96\x48\x5a\x57\x4b\x04\x4f\x5d\x2a\xc3\x79\x49\xba\xfe\x62\xf6\x7e\x6f\x44\x1a\x1b\x17\x8e\x3a\xe3\x91\x0a\xb9\x14\xed\x69\x94\x80\x9f\x41\x61\x02\x39\x1e\x83\x0e\x30\xd3\xd2\xde\x66\xca\xa2\x8b\x7d\x18\xc7\x2d\x21\x3a\x1b\x02\x12\x51\xd5\x95\x0c\x99\x14\x8c\x62\xb7\x2d\xfb\x85\x26\xfa\xbd\xbe\xe7\x47\x7e\xdf\x5b\x7f\xca\xde\x88\xf4\xdb\xbb\x74\xc1\x99\x96\x46\x8e\x31\x3c\x95\xcc\x3a\xd5\x9d\x9e\x44\x2b\x41\x4c\x64\xee\xf3\xd3\xe9\x9c\x59\x65\xca\x25\xa3\x38\x55\xe2\xb0\xee\xc8\x27\x2d\xad\xea\xf6\xc2\x7a\xb1\x11\x9f\x2a\xbe\xa0\xe0\x83\x38\xf9\x10\xc4\x47\x41\x9c\xb4\x2a\xee\x95\x64\x71\x6c\x26\x82\x5d\x2a\xd0\xb4\x6a\x6e\xb3\xef\xde\xd4\x4f\xc8\x1d\xe2\x1c\x26\x6b\x29\xa7\x48\xcc\x96\x05\xdd\x0a\x8b\x78\xda\x94\x44\x3d\x46\xed\x59\x94\x1b\xef\xb8\x28\x13\xff\x4c\x4d\xd6\xce\xd0\xa2\xdd\x72\x67\x0a\x63\x6a\x73\xbc\xc6\x9c\x0c\xbc\xf7\xf1\xe1\x51\x1c\x3f\x57\xf7\x6f\xad\x59\x07\x58\xe9\x90\xff\x92\x3a\x8e\xdc\x45\x4a\xb9\x70\xf7\xe4\xeb\x4a\x7a\x05\x97\x82\x02\x91\x9a\x4b\xd1\xaa\x94\x79\xc0\xb3\xb4\xeb\x3f\xff\x58\x6b\x6a\xba\x52\xfb\x8d\x57\xc5\x52\x4e\xa3\x37\x34\xe4\x09\xcf\x73\xf7\x66\xec\x82\x11\xb7\xc1\x5e\xd3\x7a\xef\x6d\xb5\xdb\xb6\xba\x90\x82\xa3\x6c\xf4\x63\x1e\x67\x9b\x7c\xf5\x94\x07\x2e\x48\xb6\xc1\x7d\x75\x5b\xf6\xf6\xdb\x6d\xfb\x5d\x2a\x10\x57\x19\x1f\xe3\xc7\xdc\x1a\x6c\x36\x66\x1e\xf0\xc5\x7d\xb8\xc4\xf8\xc6\x8e\xb4\x82\xdf\x5b\x38\x87\xc9\x57\x99\x73\xf6\xc8\x81\x66\xe0\xc7\x4f\xb5\x9e\x65\xc6\xf6\xb4\xf2\xcc\xe0\xd1\xdd\xa6\xea\xd4\x63\xb4\x11\xb1\xa6\x0a\xf5\x78\x85\xa4\x59\xa5\xa6\x6f\x8b\x46\x3e\x4b\x37\x36\xba\x1e\xff\xde\x51\x38\x08\x7c\x99\xe4\xd7\xab\x7c\x7b\x7f\xa7\x35\x6e\x90\xfd\x93\xb1\xdb\x4f\xc6\x95\xbd\x31\x4c\x73\xb5\x3b\xff\x4b\x6c\x83\xcd\x96\xaa\xbe\xb7\xd8\x5f\xb5\x58\xa7\xfa\xfe\xd0\xf9\x13\x00\x00\xff\xff\x5a\x48\x34\xec\x58\x17\x00\x00") func databasesDevelopmentJsonBytes() ([]byte, error) { return bindataRead( @@ -224,7 +224,7 @@ func rpProductionParametersJson() (*asset, error) { return a, nil } -var _rpProductionJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x7b\x73\xa2\xca\xd6\xf7\xff\xfb\x53\xa4\xf2\x3e\x55\x99\x79\xdf\x49\x02\xa8\x99\x70\xaa\xce\x1f\x8a\x82\x12\x45\xb9\x35\xc8\x79\x76\x9d\x82\x06\x91\xd0\x5c\x36\x17\x8d\x3e\xb5\xbf\xfb\x5b\x0d\x62\xbc\x6b\x32\x99\xcb\x3e\xcf\x66\xaa\x32\x2a\xdd\xab\x57\xaf\xfe\xad\x4b\x2f\xba\x9b\xff\xf9\xed\xea\xea\xea\xea\xfa\xbf\x52\x38\x75\x02\xf3\xfa\x1f\x57\xd7\xd3\x2c\x8b\xd3\x7f\xdc\xdf\x97\xbf\xdc\x05\x66\x68\xba\x4e\xe0\x84\xd9\x9d\xb9\xcc\x13\xe7\x0e\x46\xc1\xea\x5e\x7a\x4f\x11\x64\xe3\x96\x20\x6f\x09\xf2\xde\x76\x62\x14\x2d\x70\x39\xc5\x09\x62\x64\x66\xce\xdd\x73\x1a\x85\xff\xe7\xfa\x4b\xd9\x02\x8c\xc2\xcc\x09\x33\xe0\x24\xa9\x17\x85\xb8\x21\xf2\x8e\xc0\xff\xaa\x02\x33\x33\xf1\x4c\x0b\x39\xe9\xf5\x3f\xae\x4a\xae\xca\x7a\x28\x4f\x33\x27\x49\x9f\x9c\xc5\xcc\xcc\x51\xd6\x84\xd0\x49\xd3\x51\x84\x3c\xe8\x15\x65\xff\xb5\x2e\x8b\xaf\xff\xd9\xfa\x56\x50\xc8\x9c\xd0\x0c\xb3\x9e\x8d\xdb\xfc\x57\x9a\x5b\x29\x4c\xbc\x38\xf3\xa2\xf0\xd3\xe7\xbb\xea\xde\xef\x2b\x2e\xb6\x2a\x46\xd6\xb3\x03\xab\x8a\xb1\x99\x98\x81\x83\x39\xf9\x74\x33\x89\x65\x27\x99\x79\xd0\x19\x25\x5e\x08\xbd\xd8\x44\x3d\xfb\xe6\xf3\x41\x1a\xb1\x93\x04\x5e\x8a\xbb\xbc\xdd\xaf\xad\x42\xa9\x03\x13\x27\xdb\xef\xcc\x56\x21\xd7\xc9\xae\x0f\xde\xfd\x7d\xbf\xd9\x52\x72\x4e\x92\x79\x13\x0f\x9a\xd9\x01\x39\x6d\x97\x4c\x1c\x33\x73\x0e\xb0\xbf\x2e\x61\x3b\xc8\xc9\x9c\x23\xed\xef\xfd\xfa\xe7\x6f\x87\xbf\x6d\x70\x7a\x9d\x96\x12\xfc\x95\x86\x35\xf9\xb5\x86\xf5\x72\xb1\x16\x9f\xfe\x5c\xe9\xd1\x6b\x8f\xb6\x15\xc9\xb4\x03\x2f\x6c\xc6\x1e\x63\xb6\xf2\xd0\x46\xce\x1e\xdf\xd7\xd9\x22\xc6\xbf\x5e\xa7\x59\xe2\x85\xee\x2b\x57\x7f\x7e\x39\x40\x05\x79\x4e\x98\x31\x4e\x92\x31\x51\x10\x44\xa1\x60\x06\xef\xa4\x68\x9b\x99\x69\x99\xa9\xd3\x84\x30\xca\xc3\xec\x1b\x08\x45\x81\xe9\x7d\x03\x23\xce\x4b\x96\x98\x4c\x94\x06\x51\xda\x6e\xf5\x46\xfb\x03\xbb\x4b\x65\x1b\x17\xd7\xb6\x33\xc1\x48\x06\x26\xca\x8b\x52\x27\x5a\x39\x8a\xfa\x23\x0d\x9a\x49\x62\x2e\xce\xb4\xf7\xaf\xdf\x0f\xb6\x77\xc8\x56\xbd\x4f\x3e\xfe\x8a\xe9\x51\xe2\x4c\xbc\x97\xb7\x4a\x27\x30\x5f\xfa\x4e\xe8\x66\xd3\xeb\x7f\x5c\x51\xc4\xc1\x06\x02\x3b\x60\x93\xc2\x4d\xd8\x6a\x82\xde\xc7\x64\x60\xa7\x36\x13\x85\x13\xcf\x7d\xf5\x34\xef\x24\xd3\x09\x67\x5e\x12\x85\xd8\xa5\xbd\x8f\x48\x9c\x23\x24\x17\x36\xe0\x44\x7d\x07\xe6\x89\x73\x8a\x4a\x12\xf7\x02\xd3\x7d\x27\xa6\x57\x95\x9b\x79\x21\xf7\x6f\xe0\x61\x10\xd9\xe7\x59\x78\x97\x42\x1c\xb2\xba\xef\xeb\x6c\x9a\x4e\x47\xb9\x85\x3c\xf8\xe4\x2c\xde\x47\x61\x16\xa4\xe9\x1b\x0d\xc8\x96\xed\x4d\x9c\x34\xca\x13\xb8\xe3\xc0\x76\x48\xa5\x7e\x7e\xd0\x67\x5c\x87\x65\xcb\xd7\x72\x66\x86\xb6\x99\xd8\xdb\x7e\xe1\xcf\x1d\xe9\xc6\x49\x14\x63\x0f\x7f\xc0\x6e\x94\xf7\x0b\x51\xf4\x46\x4d\x84\x22\x68\x62\xc7\x38\x70\xb2\x69\x64\xaf\x5a\xc8\x3c\x78\x9a\x7e\xc5\x4d\x12\xdf\xc6\x5e\xbc\x3b\xb6\x95\x3c\x06\x1e\x4c\xa2\x34\x9a\x64\x77\x82\x93\xcd\xa3\xc4\xbf\x5f\xb7\x6b\xdb\x89\x93\xa6\x4e\xba\x5b\xb5\x62\xa7\xf0\xbf\x95\xc4\xb8\x24\xca\xe3\x4f\x9f\xef\xaa\x9b\xbb\x5e\xf7\xda\x8c\xbd\x8d\xd8\x91\x22\x48\xfa\x96\xf8\x7a\x4b\x90\x07\x07\xf2\xe7\x48\x7c\xb2\x32\x5e\xbd\x51\x69\x81\xf2\xa4\xe8\xca\xf1\x00\xe0\x70\xdc\x70\x49\x5b\xdb\x65\xb7\x25\x7e\xb6\x42\x51\xc9\xb3\xb7\xe4\xdf\xb3\x3f\xdd\x5c\x30\x96\x37\x5f\xae\x6e\x4a\x40\x1c\x0e\x8c\xf6\x9a\xc9\x4c\x17\x33\x14\xe6\x08\x9d\x2c\xfc\xe7\xd1\xbb\x7f\x9e\x08\x4b\x37\x30\x5a\x09\xff\x70\x30\xb5\x4f\xfe\x40\xd4\x7c\x6d\x99\xd0\x77\x42\x7b\xd5\xdb\x51\x14\xa1\x77\x8d\xdd\x06\x57\x2b\x8a\xdf\xc2\x14\x8a\x4c\xbb\x65\x22\x33\x84\x5e\xe8\x4a\x39\x3a\x11\xcc\x7f\x10\x9e\x8e\xe0\xf8\x03\x71\xf5\xda\x27\x27\x49\xef\x8f\xe9\xcd\x0a\x6c\xc8\x5a\x7d\xa8\xca\x61\xe8\x9d\x06\xd3\x69\x60\x1e\x18\xe7\xef\xd6\xb7\x03\x90\xda\xed\xd6\xaa\xc8\x37\xf7\x2a\x4e\x22\x6b\xdf\x73\x7d\x54\x47\x0a\xea\x7b\xbc\x17\xbf\x7e\x04\xe7\x59\x04\x8b\x51\xb8\x56\xe0\xae\xaf\xd9\x2b\x8e\x19\x6b\x7b\xd8\x13\x5b\x79\xe5\x48\xda\x65\xac\x71\xae\x6a\x05\xa1\x51\x94\xe0\xa0\xac\x5e\xaf\x5d\x06\x95\xd7\xf2\xdf\x6a\xa7\x90\x95\xe4\xe8\xc8\x4c\xfa\x32\x83\x50\x8e\xc4\x77\x77\x2a\x1b\x63\xd2\xcd\xb2\x78\xd7\x8d\xef\x57\xb8\x54\xa4\x61\x1e\x58\x4e\x32\x9c\x8c\xaa\x7e\x50\x67\x2a\x24\xce\x1f\xb9\x93\x66\x23\xb3\x08\x62\xaf\xef\xa7\x8e\x89\xb2\xe9\xf2\x3e\x71\x4c\x7b\x71\x1c\x79\x17\x0e\x48\xa9\x36\x97\x8e\xc7\xa5\x21\x13\xb2\x2e\x8f\x98\xb6\x14\xed\x3b\x47\x4b\x7b\x21\x7a\xec\x84\x76\x3a\x0c\x0f\xc2\xe9\x1b\xc3\x83\xdf\x0e\x4b\xee\x03\xe2\xb4\x7f\xb7\xa9\xf4\xdf\xb3\xda\xa1\xcc\x4c\xe6\x39\xc9\x56\x48\x77\xa0\x0c\x34\x63\x13\x7a\x19\x9e\x24\xd4\xbe\x29\xe2\xcb\x63\x37\x31\x6d\xa7\x98\xc0\xef\x4f\x39\xd6\xc5\x82\x72\xf2\x74\x3d\x30\xc3\xdc\x44\xfb\x58\x3b\x80\xd4\xeb\x99\x97\x64\xb9\x89\x06\x26\x9c\x7a\xa1\x33\x4a\xa2\x89\x77\x20\x67\xb3\x2e\x1e\xa5\xe7\x8a\x94\x3d\x8f\x82\x38\xcf\x9c\x04\x4f\x72\xd6\xf3\xf8\xeb\x7f\xc1\x28\x84\x66\xf6\x09\x8f\xdd\xcd\x97\xab\xcd\x9c\x58\x35\x23\xba\xf9\xfc\xe5\xea\xe6\xf6\x74\xd0\x57\x26\x87\xd4\xd4\x49\xaa\xf1\x82\x28\xca\xed\xdb\x3c\x75\x92\x53\xd5\x90\x17\xe6\x2f\x6f\x0b\x35\xae\x6d\x2f\x35\x2d\xe4\x8c\xcc\x34\x9d\x47\x89\x8d\x27\xb8\x4e\x98\x79\x6b\x5d\xc9\x92\xdc\x39\x63\x56\xd2\x74\x7f\x4e\x7c\xb0\x60\x5c\x4d\x2a\x4f\xa7\xf2\x36\xaf\xf3\x54\x5f\xa9\xaf\xcd\x5a\x14\x38\xf7\xaf\x12\xbb\xbf\x4b\xd3\xe9\xbd\x99\x67\xd3\x28\xf1\x96\x8e\xfd\x6f\x1f\x33\x70\x3e\xe4\x5e\x13\xf6\x9d\x45\xdb\xcc\xcc\xbd\x34\xe7\xe6\x34\xf9\xac\xeb\xae\xae\xe3\xf1\x79\x75\xed\xe7\x2b\x2f\xab\x7f\xf8\xce\x11\xe3\x7d\x9d\x66\x51\x62\xba\x67\xf5\xa1\x28\xeb\x05\xa6\xeb\x48\xce\xc4\x49\x9c\x10\x9e\x8f\x8c\xca\x71\x4e\xa7\xa5\xfd\x90\x1c\xbb\x6b\x9e\x8d\x27\xa2\xc9\x64\x55\xbc\xdb\xe9\x9f\x2b\x5c\x9a\xb7\xeb\xc7\xbb\x5d\x33\xbc\x57\x72\xf6\x6a\xbb\x91\x99\x39\xe9\x91\x14\xf1\xd5\x19\x2f\x17\xa5\x6d\x2f\xf5\xcf\x77\xbc\xcc\xff\x0f\xe3\xca\xcf\xb0\x49\x14\x94\x49\xa7\x33\x7c\x96\x0f\x87\xec\x8b\x5a\xb9\xda\x18\xbe\x55\xae\x57\x59\xb9\xc4\x51\xe2\x04\x5e\x1e\xfc\xbb\x2f\xc9\x67\x02\xc9\x0f\x42\x51\x58\x3a\xb0\x8b\x50\x54\x46\x1b\xa3\x8b\x82\xeb\x1f\x19\x58\x9f\x0c\x6f\xca\x96\x7a\x61\xe6\x24\x13\x13\x3a\x17\xe6\x23\xaa\xeb\x82\x81\xdc\x08\x75\xb0\x8b\xb8\x0d\x3d\x78\x49\x3a\xe0\x0d\x11\xe8\x46\x1d\x2f\x30\x93\xc5\x45\x46\x7d\x5d\xc9\x8b\xdf\xd8\xe7\xcd\xeb\x72\xeb\x7d\x75\x48\x16\x5e\x0c\x8b\xb6\xdf\x60\xac\xaf\xde\x29\x9c\xad\xfa\x69\x6e\x85\x07\x72\xcd\x17\xd7\xbf\x08\xbc\xab\xb8\x64\xf5\x35\xbd\x2f\x1b\xad\xf0\x3b\x0b\x9d\x6c\xf5\xb1\xbc\x71\xb1\x83\xd9\xbc\xce\xcc\x17\x0f\x32\xff\x1e\x94\x6c\x13\xd8\x0e\x66\xdf\x9e\xfa\x38\x48\x75\x17\x1b\xfb\xa9\xd4\xcb\x19\xfc\x36\x78\xac\xe9\xd8\x61\x2a\x3b\x59\xe6\x85\xee\xb7\x11\xba\xda\x7e\xe8\xd6\x37\x2d\x07\xed\x46\x93\x45\x9f\x8f\x86\x94\xef\xc1\x46\x75\x9d\x0f\x48\x3e\xa6\xd6\x7b\xb0\xb8\x69\xe0\x5b\x6f\xc8\x29\x9e\xbb\xbe\x61\xd0\x7f\x6e\xea\xea\xd8\xf5\xf6\xe1\x38\x1d\x65\xbe\x9f\xfe\x65\x25\xcf\xb7\x7e\x9a\xce\xf1\xbb\x87\x29\x1f\x8b\x5f\x9c\x97\xcc\x09\x71\x84\x78\x51\x04\xb3\x2e\xfd\x5d\x3c\x3f\x4c\xcf\x85\x89\x57\xef\xf6\xfc\x9b\x01\xf9\x2b\x5c\x9b\xc5\x3a\xa4\xce\x6b\xaf\x2e\x8c\x09\xaa\x0c\x0c\x93\xa7\x59\x14\xc8\xc5\x7a\x91\xb7\xd4\xed\x9a\xa1\x8d\x9c\x64\x33\xb1\xb2\x5e\xbe\x74\x96\x80\x99\x67\x91\x5a\xa6\x0b\x06\x5e\x18\x6d\x50\x79\x43\x54\x93\x6e\xd8\xed\x0b\x0d\x53\x91\xc8\x73\x60\xe6\xd8\xef\x32\xfa\xd7\xe5\xb2\x9a\xc2\x78\x58\x66\xea\x3c\xd4\x3f\xad\xcc\x7b\xf9\x4d\x89\xe4\xe2\x89\xe8\xa7\x1b\x48\x01\xa2\xc7\x90\xc8\x69\x46\x4f\x37\x9f\xbf\xdc\x0c\xda\x03\x56\x1a\x0a\x4a\x47\x68\xab\x52\xff\x9f\xff\xb5\xaa\x70\x75\x6b\x5f\xfd\x77\x4e\x10\x35\xb8\xf9\xf7\xe6\xe6\xe6\xcb\x8a\xfc\xa6\xab\xd8\x5e\x11\x70\xf3\xf9\xf3\x97\x9b\x9b\x9b\xcf\xff\x1d\xde\x60\xf2\x72\x9b\x19\x0a\x6c\x8f\x03\x1d\x49\xee\x0d\x85\xf7\xb6\xb0\xb3\x5e\x60\xaf\x91\x8e\x00\x7a\xd2\x50\x18\x74\x04\xe5\xfd\x4d\x6c\xac\x25\xd8\x6a\x60\xa4\xf6\xfb\x72\x87\x91\x3a\xef\xa4\xfd\xba\xc4\x60\x8b\xac\x34\xea\x0d\x9a\x5c\xe7\x7d\x34\x57\x6b\x06\x0e\x11\x6c\xaa\x4a\xf7\x9b\x88\x36\xf3\x6c\xba\x43\x78\x30\x6c\xbf\x9b\xd1\x41\x64\x6f\xf3\xd9\x6c\x0f\x7a\x42\x73\xd4\x63\xfa\xbd\x8e\xa0\x30\x1d\x49\x61\x86\x83\xc1\x50\x10\x9a\x83\x77\x36\x72\x6a\xc1\xd3\xe1\xa6\x9b\x2d\x55\x68\xf7\x3b\xff\xc4\x04\x0f\x52\x5a\x2d\xc0\xba\x29\x2a\x17\x75\xfb\x43\xa6\xa9\xbc\x09\xc3\xc7\x32\xc1\x9b\xa2\xed\xc8\x43\x55\x62\x3a\x9c\x34\x54\x47\x6f\x13\xc0\x2e\x75\x6c\xf3\x37\x28\xe3\x3f\xbb\xea\xef\xe8\x20\xeb\x31\x64\xa3\xd7\x05\x73\x83\x63\x09\x43\x6e\x66\x0e\xd3\xd2\x45\xf5\x25\xb6\x42\x50\x17\x35\x1b\x59\xa1\xf8\xc4\x78\x03\x77\xac\x1b\x33\x53\x13\xdd\x5e\x00\x16\x30\xa0\x17\x43\xaf\xe5\x8f\x9f\x55\xd7\xd0\xf9\x85\x55\xeb\x45\x7d\x65\x30\x1f\x2a\xe3\xc6\x93\xdc\x0a\x60\x40\x67\x3d\x4e\xf2\x0c\xad\x41\xf5\x95\xc6\x0c\x72\x20\x1f\x7a\x2d\x46\xea\xf4\xe6\x83\xb6\xff\xd2\xeb\x48\x8c\x4e\x1a\xac\x8a\x04\x5e\x21\x1a\x13\x45\x45\x8a\xa2\xb2\xaa\x48\xb8\x0f\xbd\x8e\x34\xb5\x39\xd6\x1b\xeb\x02\xea\x71\x20\xb7\x03\xb4\xb0\xa8\x46\x66\x68\x0d\xa2\xd7\x35\x10\x0c\x85\xd8\xa2\xea\xae\xa5\xa1\xa5\xa5\xb1\xc4\x98\x72\x3d\x26\xe4\x71\x3f\x82\x1e\x43\x53\x63\xbd\x37\xb3\x38\xe4\xf5\x6b\xfc\xdc\x92\xe9\x89\x4e\x49\xde\x93\x1b\x3d\xc1\xb0\x95\xf5\x18\x22\x33\x35\x72\x6e\xd5\x78\xa2\xc7\x4d\x09\xbb\xdb\x5a\x0e\xbd\xc7\x99\xc1\xcd\x73\x23\x00\xbe\x55\xe3\xa7\xb0\xcb\xcf\xcc\x00\x3c\xdb\x4c\x63\x06\x03\x38\x83\x5d\xe0\xf5\x29\x30\x37\xb4\xf9\x4c\x45\x2d\xa1\xaf\xda\xa2\xb4\x20\xfb\x12\xf0\x33\x09\xb4\x58\x85\x21\xea\x4c\x88\xdb\x6a\x66\x7d\x0d\x65\x90\xa3\x17\x36\xd3\x8a\xec\xae\x34\x87\xcb\x68\xd6\xaf\xb5\xa6\x63\x2a\x9b\x1a\x14\x58\xf6\x03\x32\x1e\xd7\xf8\x19\xa4\xe8\xc0\x66\x1a\xcf\x16\x45\xcc\x4c\x0a\x34\xe0\x82\xce\x4c\x4d\x58\x58\x35\x61\x66\x84\x62\x3e\xd6\x85\xe7\xcb\x69\x1a\xa9\xad\x81\xdc\xe6\xf8\xd8\x66\x1a\xb1\xb5\xa0\x03\xab\x0b\x90\x15\x4a\x9e\xa9\x8b\x39\xa6\xcf\xb8\x71\xc3\xd6\x08\xb7\xaf\xfb\xae\xa9\x35\x96\x36\xc7\xa6\xd6\x26\x3d\x4a\x4a\xfb\x81\x81\x0c\x8e\x5e\x8c\xf5\xd6\xc2\xa2\x62\x34\xae\x89\xb9\x55\xe3\xc3\x7e\xad\x45\x8e\x3d\x1a\x41\x0e\xa4\x2b\x39\x64\x30\x00\xa9\xa1\xb1\x4b\x43\x26\xd3\xb1\x2e\x21\x58\x13\xb3\x21\xd3\xc8\x2d\x8a\x5d\x8c\x29\x37\xc7\xb2\x66\xdc\xf8\x79\xac\x8b\xee\xc8\xa3\x91\xcd\x0d\x66\x18\x6b\xfd\x90\x47\x90\xa3\x97\xfd\x40\x9c\x8d\xf5\x98\x84\x81\x9a\xc3\x00\xcc\xad\x45\xf3\x71\xc4\xd8\xac\x42\x8c\x43\x06\x65\x53\x27\x04\x0b\x43\x26\x9f\x2d\x0e\xd9\x4c\xd0\x98\x5a\x9a\x4a\xaf\xca\x67\x63\xea\x25\x66\x02\x7e\x0a\x29\x40\xc2\x60\x4e\x9b\x5d\x89\x80\xdd\xc1\x43\x7f\x41\xcf\xc7\x9a\x90\x8c\x35\x1b\xc1\x45\x63\x5b\x9e\x14\x9d\xf5\x6b\x88\xb4\xf4\x55\xfb\x14\xfb\x60\xeb\x3c\xea\x6b\x42\x6a\x8a\x31\xb2\x02\xd6\xb3\x38\xe0\x8f\x74\x84\xe0\x3c\x0e\x21\x67\x3f\x9b\x1c\x78\x36\x97\x64\xc3\xd0\x07\x4f\x6b\x9e\x34\x61\x06\x03\xb0\xc3\x13\x78\xb6\x6a\x3c\xfa\x28\x9e\xc6\x14\xbd\x30\x4e\xf3\x94\x5b\xf3\x18\xcb\xea\x89\x09\x84\xa9\xcd\x34\xff\x5f\x9f\x02\xc4\x78\x41\xe3\x31\x2e\xe5\x59\x1b\xe4\x06\x43\x13\x06\x43\x62\x8c\xe4\x36\x43\x16\x58\x38\x20\xeb\x9d\x32\xd2\xba\x6f\x36\x27\x66\xe3\x52\xff\xb3\x71\x80\x88\x0b\xfa\xb7\x8d\x3b\xed\x71\x36\xc6\x74\x71\xdf\x96\xf0\xc9\xd0\x1a\xd3\x71\xf0\x82\x8c\x76\x29\x53\xa3\xd6\x0a\xc7\xd4\x14\x8d\xa9\x94\x76\x34\xb0\x64\x7c\x30\x92\xdc\xe8\x69\x6d\x93\x38\x94\xc3\x9a\x34\xb5\xb8\xb9\x3b\xd6\xe3\xa5\xa1\x0d\xf0\xd8\x4f\x2d\x8d\xa5\x7a\x1c\xfb\x00\x29\xf0\xdc\xd7\xc8\x99\x15\x20\xc2\xaa\xf5\xdc\x4d\x7c\xe0\xfb\xe5\xf8\x92\x3e\xa4\xc4\xf5\x3d\x5c\xc7\xd6\xf9\xd8\xee\xfa\x2e\xe4\x68\xdf\xd2\xd8\xbc\xaf\x49\xb3\x31\x95\x21\xe8\xb5\x76\xe5\xf5\xc4\x04\x46\x0c\x03\x50\x1b\x6b\x2f\x69\x5f\x13\x32\x83\xc1\xfa\xc8\xfa\x06\x53\xda\x90\x91\x22\x12\x83\x05\x4d\x8c\x6b\x4d\xb7\x2f\x93\x73\x43\xe7\xb3\xb1\xd6\x58\xdb\xcc\x0d\x39\x79\xb6\x66\x3f\x98\xda\x4b\x3a\x96\x1b\x0b\x43\x93\xa2\xb1\x5e\x61\x40\x88\xac\x9a\x3d\x19\x87\x20\xec\x07\x42\x68\x2a\x74\x6c\xb4\x89\x97\x61\xbb\x49\x0e\x9e\x3b\x0b\x26\x14\x10\x6e\xd7\x94\x9b\x99\x21\x37\x43\xb8\xa0\x63\xd8\x95\x0a\x59\xc2\x05\x1d\x98\x3a\x8f\x6c\x8a\x4d\x2d\x4e\x9c\xf1\x8b\xe6\xcc\xd0\xa5\xe7\x3e\x25\xe4\xa6\x4c\xe7\x86\x2e\xe6\x06\xf3\x58\x17\x16\xe4\xdc\xa2\xa4\x6c\xac\xd5\xb3\x71\xc8\xc7\x06\x67\xa3\x7e\x20\xcc\xac\xc0\x48\x4d\x5d\x20\x18\x37\xce\x4c\x4a\x8a\xa1\xd7\x9c\xc1\x80\x9e\xd9\xcc\x63\x6e\x70\xf4\xb3\x49\x81\xc5\x1a\x63\x35\x7e\x66\xd5\xc4\x59\x3f\xa8\xe4\x45\x3f\x5b\x54\x23\x30\x35\x98\x9b\xa1\x30\xb3\xbc\xe6\xe3\xa8\x83\xc7\x30\xfe\xca\xb8\xbe\x37\xd6\x01\x61\x76\x07\xde\xd0\x6b\xe1\xef\x7c\xcf\x93\xbe\xaa\xa8\xc5\x2b\x2a\xdb\x95\x64\x15\xf5\x17\x31\xdd\x7b\x8e\x5c\x67\x1e\xf1\x8c\xb8\x2a\xcf\xf4\x1e\x7a\x4c\xcf\x5f\x97\x53\x59\x00\x3a\xae\x87\xeb\x4f\xc4\x88\x9f\x88\x31\x5d\xe1\x64\x4c\xb1\x44\xaf\x5d\x2f\xfb\x5b\x93\xfc\xbe\xc6\x86\xd8\x47\xf4\x35\x6c\x07\xf7\xb1\x3f\xa6\xe8\xdc\xf0\xb6\xb0\xcf\x2b\xa8\x05\x00\x4b\x3c\x31\x6a\x81\x79\x17\xd6\xd0\xd2\xe6\x40\x66\x34\x23\x1e\x70\x6c\xd8\xe3\xe2\x99\xad\xf3\xf9\x58\x7b\xf1\x19\x17\x29\x8e\x2e\x10\x86\x46\xfa\x3a\x61\xc4\x56\x57\xc2\x98\x99\x88\x04\x2d\x28\x0a\x39\x85\xc1\x23\xb6\x13\x9c\xac\xbe\xa8\x12\xe0\x6d\xc6\x45\xc3\xb1\x46\xa2\x1e\x47\xce\x0c\x0e\x05\x8e\x18\xf1\x4a\xe9\xaf\x5c\x33\xa0\x49\x88\xf5\x8c\x13\x9f\x18\xc0\x23\x4b\xa3\x29\x03\xd0\x35\x53\x7b\xf1\xc7\x14\xbb\x30\x98\xd6\x84\x71\x91\x6c\x68\xe4\xcc\x0e\x54\x17\x74\x90\x20\x01\x41\x15\x55\x52\x64\xdc\xd8\x52\x48\xa0\xaa\x2c\x50\x75\x4c\x33\x60\x33\x43\x6e\x05\x56\x8d\xaf\x8d\x75\x1e\xf3\x29\x16\xfe\xad\xdd\x6b\x0c\x9e\x07\xf3\xb5\xbc\xf4\xc8\xb5\x38\x3a\x34\xb5\xba\xdb\xd7\x7c\x8c\xd7\xa9\xc5\xbd\xcc\xec\x05\x99\x5b\x0b\x72\x69\x6b\xfc\x72\x5c\xe3\x31\xb6\x62\x8b\x6a\x2c\x19\x37\x56\x80\x2f\x68\x22\x00\x03\xc0\x02\x59\x56\x08\x8f\x67\xa6\x53\xc7\x6b\x25\x86\x8e\xa8\xb1\x0e\x52\x9b\x69\x15\xf8\xe9\x31\x64\x58\x8c\x9b\x0f\x14\x85\x04\xb2\x48\x80\xae\xea\xd3\x40\xed\x34\x5a\x8a\xaa\x7a\xd8\xef\x42\x1d\x20\x18\xfa\x6e\x0f\xa5\xf7\x36\xc7\x86\x70\xd1\x28\x69\xb4\x09\x9a\xaf\x09\x08\x86\x46\x3c\xa6\xd4\x50\x97\x1b\x73\x18\xd0\x58\x97\x08\x53\x03\xcb\x7e\x68\x4c\x6d\xed\x85\x00\x3a\x1f\xf7\xbc\x66\x66\x2d\x5a\x04\xac\x8d\xe3\x9e\x1b\xef\xf2\xb2\x34\x34\x61\x61\xe8\xa2\x6b\x70\x74\xcd\x0a\x5e\x66\x63\x4d\xc4\xfd\x0c\x4c\xed\x05\xf5\x98\xd2\x0f\x59\x9a\x94\xf5\xc3\x16\x5a\xf9\x56\x1f\xf3\xed\x90\x82\x26\x92\x46\x0b\xa8\x2f\x2a\x00\x3c\x3f\xd1\x05\x34\xae\xf1\xc8\xee\x0e\x66\x30\x6c\x66\xb8\x4e\xcf\x8d\x9f\x4d\x3c\x96\x4c\x73\x2e\x3c\x37\xe7\x7b\xf4\x44\x6c\xa3\xc4\x52\xb6\x5a\x03\xf5\x18\xf8\xd2\x67\x68\x56\xf1\x45\x57\x24\x80\x0c\x3a\x88\x93\x55\xa1\x05\x3a\xea\xac\xd7\x6d\x86\xfb\xf5\xcb\x31\xc2\xfe\xda\x0e\x58\xd2\xea\x8a\x2e\xb6\x57\x30\x00\x44\x8f\x93\x66\x36\xd5\x48\x2d\x8a\xf5\xb1\x2c\x8d\x00\xa5\x86\x5c\xe9\x7a\x61\xe3\x72\xc8\x81\x55\x7c\x23\xba\x85\xae\x91\x46\x1b\xf8\x2c\x50\x58\x09\xa8\x3e\xa2\x2b\x5a\x70\x41\x2f\x20\x43\x66\x46\x57\xf0\xcb\x3e\xd1\x35\xcb\x6b\x2d\x1d\x5d\x48\x2d\x0a\x3e\x60\x1d\xc0\x38\xd9\xe0\x6f\x69\x30\x8d\xb9\xa1\x11\x4f\x63\x6a\x9a\x59\x94\xe8\x0e\xda\xe3\xf9\x80\xd9\x6f\x9f\x29\xc7\x24\xb5\x28\x7b\x66\x17\xf6\x93\x4c\x0c\x0e\x2d\x2a\x5a\x63\x9d\x9f\xf5\x75\x7e\x5e\xfa\x12\x95\x12\x98\x26\xb6\xa9\x8f\xa3\xf6\xdc\xe3\x3b\x6c\x47\x51\xd1\x50\x04\x2d\x5e\x24\x58\x06\xa8\x8d\x8e\xd2\x51\xbd\xb5\x8e\x53\xec\xc2\x5a\x90\x0b\xc8\xd0\x53\x83\x23\x63\xcb\x23\x9f\xc7\x32\xe9\xd9\x5a\xc3\xb7\x38\xb5\x6c\x3f\x28\x6c\x69\xde\x63\x48\xb9\xd7\xee\xcc\x07\xed\xe6\xc3\x40\x69\x6e\xf0\xba\xa2\xd1\x8c\x9e\x2c\x2d\xf3\x4d\xbd\xe7\xae\x7c\xe7\xb2\xd2\xed\x7e\x4d\x68\xc0\x9a\x84\x2c\x99\x2e\x64\xd4\x0f\xd7\xd8\xcc\x8d\xe6\x76\x4c\xb3\xb6\x17\x4c\x55\x9f\xa8\xe4\xb5\x34\x74\x9e\x32\x35\x01\xe1\x58\xc7\xaa\xe1\xb8\x15\xdb\x5d\xf5\x90\x1d\x02\xd8\x87\xe9\x62\xdc\x32\x42\x09\xc1\x67\x32\x37\x74\xa9\x66\xd5\xf8\xa4\xaf\xd1\xb9\xc5\xa1\xdc\x90\x1b\xc4\x58\xe7\x43\x43\x17\x9f\x24\x95\xe6\x76\x63\x2b\x83\x03\x41\xa9\x03\x25\xcf\xbd\xf6\xfc\xb1\x28\xe7\x93\x1d\x95\x90\x26\xaa\x4f\x0f\x24\x40\x8b\xaa\x0f\x38\x19\xb8\x74\xbf\x66\x4c\xa1\x47\x2f\x6c\xad\xbe\xe2\x97\xf6\x0d\xad\xd4\xb3\xaa\x8e\x42\xb6\x54\x59\xa5\x87\xea\x92\xf0\xfa\x6a\xc7\xed\x63\x6c\xeb\x3d\x57\x67\x24\x41\x62\x85\x8e\x4e\xf2\x23\xa5\x03\x26\x2a\xcb\xb3\x92\x8f\xc6\x3d\x37\x7a\x32\xf4\x69\x19\x5b\xb3\x82\xa2\xb0\x74\x5b\x02\xbc\xaa\x13\x06\xaf\x74\x54\x7a\x25\xe7\xb9\x49\xf9\x33\x9b\x7b\x59\xf6\x29\x2c\x57\x09\xff\x3f\xed\x6b\x3c\x69\x05\x52\x6a\xc8\x8d\x67\x88\x7d\x67\x00\xea\xab\x98\x57\x50\x88\x06\x0f\x3a\xb4\x2c\xab\x8d\xae\x4e\xd8\x6d\x95\xa4\x59\x05\x19\xbc\xea\xd3\x43\x45\x05\x43\xd0\x26\x42\xbe\x53\xf0\xbc\xfd\x3b\x03\x5f\xf9\xe9\x90\x23\xc5\x47\xaa\x42\xf2\xbc\xe2\xdb\x13\x89\x10\x14\x9d\x60\xdb\x22\x41\x03\x05\x89\xb4\x08\xf8\x91\x8a\x5a\x03\x8b\xb2\x97\x67\xda\x96\x25\xd5\xe6\x15\xa2\x4e\xf3\x0b\x69\xa0\x10\x58\x9f\xd1\x48\xf1\xce\xb5\x25\xb0\x2a\x92\x26\xa5\x1d\xd8\x92\xc7\x0a\x63\x85\xfd\x40\x4e\xb7\x35\x83\xa1\xe8\x2a\x2a\x3d\x94\x81\x34\x52\x7d\x34\x94\x48\xba\x2b\x92\x42\x59\x97\xa5\xfb\x12\xc0\x76\xe4\x85\x1d\xc9\xfb\xfa\x79\x9a\x07\x6c\x8b\x81\xa2\x76\xd8\xb6\x84\x07\xd7\xa7\x65\xb5\xf3\x32\x33\x6a\x83\xa3\xf5\x44\x82\x1e\x4a\x3e\xea\xbe\xce\xd5\x8a\x7e\x17\xe3\x5f\xdd\x03\x3e\x90\x55\xe2\xb4\x0c\x00\x10\x58\x9d\xb0\x59\xc5\x07\x9a\x08\xe8\xb6\x42\x34\x38\x59\xb5\x27\x2a\xee\x93\x8f\x30\x3f\x04\x0c\x01\x62\xdc\xa3\x32\x50\x25\xb5\xd1\xc2\x63\x75\xa9\xdc\x0b\xcc\x2b\x58\xd7\x8f\xd2\x94\x15\xe2\x85\xd5\x09\x34\x54\x49\xa9\xa5\xf8\x02\x3b\x92\xa1\xff\xc4\x4d\x67\xb0\x26\xe5\xd8\x77\x3f\xc9\xf0\xa0\xbe\x61\xbd\x2f\xf4\x38\x40\x21\xb6\x7f\x96\xbc\x8e\x7d\x04\xa9\x43\x72\x18\x83\xa0\x03\x86\x12\x0b\x64\x65\x85\x4f\x45\x35\x64\x85\x68\xe0\x7e\x74\x00\xe0\x07\xfc\xbc\x28\x5b\xc6\x39\x45\xfc\x40\x2f\xed\x60\x90\x57\x73\x0a\xe8\x15\x73\x39\x1c\xd3\x20\x1b\xfb\x78\x8e\x78\xb0\x34\x16\xdb\x9b\x85\xbe\x1c\xbc\x60\x3d\x55\x80\x30\x02\x80\x6f\x4b\x18\xef\x3e\xc2\xf4\x05\x49\x6d\xa8\xb8\x1f\x4a\x87\x6e\x8b\x40\xc2\x63\x16\x6e\x95\x05\x58\x6f\x55\x1a\x86\xcd\x27\x45\x95\x04\x95\xa0\x81\xea\x0b\x6c\x21\x2f\xf5\x22\x59\xac\x63\x45\x3b\x60\x17\x18\xc7\xf6\xfc\x22\xbb\x98\x6d\xd8\x52\x77\xd4\x9e\x87\x98\x1e\x3f\x8f\x2d\xa0\x35\x62\x9b\x25\x9e\x44\xcd\x20\x0c\xbd\x47\x5b\x01\x20\x6c\x8a\x5e\x98\x0b\x1c\xdf\xbf\xc4\x56\xa0\xe6\x36\xc7\x2e\x0c\x0a\xe0\x58\xd5\x52\x29\xb0\xb0\x03\xf4\x6c\x00\xe2\x49\xd2\x1a\x94\xa9\xf3\x33\x2b\x20\xf1\xdc\x83\xc3\xbe\xbe\xd2\x8d\xbd\x71\x12\x63\xd6\xe1\xc0\xb3\x5a\x93\xa6\x30\x94\x44\x18\xa8\x74\x5f\xa6\x49\x58\xeb\xcd\xc6\x01\xca\xfb\xd4\x7a\x2e\xb0\xc0\xf1\x81\xe1\x35\x91\xe2\x1e\xa8\x53\x03\x4b\xe8\xd1\x9e\xa9\xd5\x67\x55\x9c\xdc\xeb\xb6\x48\x3c\x57\x29\xc7\x1a\x09\xa2\x6a\xb3\x8c\x0f\xea\x86\x26\x28\x98\x77\xbb\x4d\xcc\x6c\x5d\x58\xf4\x29\x3e\xb6\x3c\xda\xb7\x28\x21\x31\xf4\x9e\x0b\x43\x90\xf7\xd8\xf9\x53\xaf\x98\x5b\x80\xdc\xee\xf2\x0d\xc8\xd1\xb1\x15\x8a\xee\xaa\x9d\x65\xc1\x1b\x41\x22\xbb\xcb\xc7\xe3\x9a\xc0\x3a\x5d\x09\x59\xab\x3c\x88\xde\x8c\xdc\xc2\xef\x73\xf4\xd2\xe6\xca\x38\x96\x57\xdd\xf5\xef\x56\x11\x1f\x36\x91\xe2\xb5\x20\xe3\x15\xf3\x94\x85\x25\xaf\x3e\xeb\x63\x77\x6d\x87\x38\xa2\xf0\xa1\x43\x6f\x37\x4e\xda\x28\x5b\xfa\x0d\x64\x77\xe1\xc3\xe6\x67\x67\x45\x7b\xb3\xef\x55\x9f\x44\x3c\x56\x1d\x23\xb6\x38\x75\xaf\xad\xaa\x8c\x14\xf2\x33\x2b\x94\x58\x2b\x90\x00\x0c\x2a\x19\x6e\xeb\x4b\x55\x56\xe1\xe8\xd0\xc0\xf2\xee\x08\x33\x0b\xcf\x3b\x38\x75\xd5\x57\x12\xdb\xef\x81\xa1\x1b\xc8\x62\x5a\xfa\x58\xe7\x73\x53\x6b\x84\x55\x3d\xb5\xcb\xc7\x76\xc0\x12\x86\x9a\x21\x47\x3d\xcd\x8f\x4a\xe1\xf8\x5c\x40\xdb\xd8\x12\x4b\xbe\x8e\xe8\xdc\x6e\x5d\x35\xa0\x71\x8c\xe6\xef\xe9\x58\x25\x4f\x20\xe0\xb9\xc5\xb3\x01\xf8\x99\xc5\x01\xde\x0a\x05\x62\xac\x35\x9e\x0f\xd6\xd9\xd0\xcb\x57\x4c\xd1\xf3\xd1\x61\xec\x2e\xf1\xbd\x1e\x03\x86\x0c\xe2\x11\x2c\x70\x2b\xd2\x63\xed\xa5\x36\xd6\x11\x8e\xeb\x2d\xb9\xca\x01\xb1\xc4\x13\xa0\xd8\xdc\xe6\x80\x2f\x86\x3e\x6d\xe1\x18\x82\xf3\x33\x5b\x17\x10\xf4\x4e\xc7\x1c\xdb\xba\x55\xc5\x66\x5b\x76\x70\x22\xaa\x42\x5b\x21\xb1\x8f\x26\x5b\x45\xfe\x04\xf0\xc8\xe8\x4c\xa7\x76\x87\x9e\x1b\x5a\x43\x31\x39\x14\xd8\x2c\x2f\x96\xf6\x89\x1e\x8a\x2a\xc9\xaa\x64\xab\x25\x12\x2a\xad\xa2\xe6\x93\xca\x82\x81\xc2\xd2\x8a\xa4\x0a\xb2\x04\x0a\xdb\x2f\x02\xf5\x65\xa0\x12\xa0\xad\xfa\x40\xe5\xe7\x71\xab\xb0\xa1\x88\x6e\xa9\x1d\x34\x11\x89\x17\x1e\x8f\xc5\xab\xbf\xa5\x05\x6c\xf3\x4b\xdf\xa7\xe2\xfa\x65\x79\x9f\x15\x65\x55\x18\xc8\x78\x0c\x3b\x45\xd9\xb6\x42\x90\xd8\xdf\x17\x3c\xf0\xf3\x58\x56\x3b\x25\x8e\xb1\x1d\x7c\x9d\xb7\xc2\x27\x15\xb5\x26\x8a\x4a\x77\x24\x85\x08\x79\x96\x17\x8b\xcf\x27\xfc\xc4\xae\x1d\xac\x62\xe0\x9f\x6b\x0b\xab\x38\xf8\x07\xd8\x43\x96\x17\x65\x95\x6c\x49\x84\xfa\x24\xe9\x53\x34\x26\x05\x8c\x2b\xe2\x08\x76\x71\x4c\xfa\x6d\x36\x4d\x53\x5d\xac\x3f\x1b\xf1\x5d\x65\x1f\x50\xaf\xb3\x87\xb3\xd7\x7b\x6c\x0b\x28\x9d\x97\x49\x85\xad\x4a\x9f\x0d\xb9\xf5\x16\x8c\x6d\xd0\xe3\x45\x9d\x20\x47\x52\x67\xfd\xdb\xbc\xd7\x16\x89\xc1\x32\xaa\x0b\x6d\x71\x59\xd1\xb7\xbd\x9d\xb9\x49\x3b\xda\x99\xef\x6c\xda\x5f\x9e\xb4\xbc\x8d\xb9\x0a\x55\xe5\x27\xe6\x0f\x27\xee\x55\xed\x53\x55\x7e\x1c\xcf\x2f\x86\xde\xc6\xe7\x30\x5a\x95\x91\xd6\xb8\x2f\xf9\x6b\x6d\x62\x64\x06\x8f\xf9\x30\x7c\x0f\xf7\x85\x69\x2e\xcb\xb9\x31\xb6\x3d\x52\x6c\x69\x60\x66\xeb\x52\x61\xab\x54\x0a\x3c\x8f\x94\x01\x35\x68\x37\x9f\xd4\x00\x2c\x4b\x9f\x48\x4e\xad\xae\x3d\x75\xca\x1c\xeb\xca\x06\xbe\xa4\xba\x18\xeb\x63\xad\x41\x18\x9a\xc4\x38\x0a\x99\xe1\x79\x89\x29\x93\x24\xa4\xc0\xa2\x1f\x4a\x53\x18\xd8\xc8\x6e\x1e\xcc\x81\xe2\xfe\x57\x79\xa9\x52\xd7\x36\x72\x84\xa3\xf6\x4b\x51\x67\x07\x1f\xb4\x58\xc6\x5c\xb2\xa1\x49\xbd\xb1\x2e\x8d\x20\x07\x72\x95\x9a\xc6\x46\x28\xc9\x6a\xb3\xb4\x65\x8a\xcf\x0a\x12\x10\x44\x51\x15\xd8\x91\xca\x33\x8a\x18\xb7\x15\x16\x28\xa0\x03\x64\x9d\x28\x70\xd5\x12\x09\x61\x04\x70\xfc\xa5\x96\xf9\x47\x35\x00\xbe\xcc\xb1\x84\x52\x6b\x21\x0b\x09\x91\xa9\x19\x84\x48\xbd\x90\x78\x7e\x09\xdd\xbd\xfa\x5b\xf6\x4f\xf4\x79\x81\x41\x6b\xdd\xc1\xb6\x6b\x3d\x36\x85\x7d\x62\x69\x41\x21\xa4\xca\x3e\x15\x9f\xf9\xc3\x79\xe1\x43\x73\xdb\x29\x0c\x1e\x33\x4b\xa3\x73\x53\x97\x66\xd0\x7b\x9d\xaf\xe2\xb9\x23\x4f\x80\x91\xe4\xc1\x27\x8d\x04\x79\x91\x13\xf6\xd9\x00\xc7\x9d\x23\x1c\x8b\x76\xed\x19\x0c\xd2\xcc\xa2\x1a\xa9\xa9\x35\xd0\xeb\x78\x44\x4f\x1a\x59\xd9\x34\x60\x33\xfe\xf6\xb3\x1b\x29\x40\xa9\xa1\x10\xab\x7c\x9d\xd0\x80\x54\x91\x7f\x8c\x8d\xc5\x0e\x2f\x87\xec\xcb\x7f\x80\x4d\x12\x89\x17\xa0\x92\x12\xab\x22\x7a\xdb\x37\x32\xc7\xcb\x6c\x62\x6e\xc3\x1e\x1d\xad\x5f\xe2\x7a\x63\x9e\xb7\xd1\xfe\xda\x6f\xc9\x3f\xd5\x9e\x60\xdc\xc4\x36\x47\x2f\x3e\x3a\x36\x31\xb9\x22\x07\x9d\xa9\x65\x2e\x0b\xf3\x3c\xb1\x95\x78\x36\x0e\x62\x34\xae\x49\x13\xf8\x1c\x53\x63\x9d\x9f\x58\x1c\x1d\xea\x35\xf1\x01\x2e\x9b\x55\x3c\x3b\x83\x5d\x71\x66\x69\xe8\x19\xcf\xc1\x2c\xca\x20\xfa\x54\xf9\xfc\x13\x63\x72\x5c\x3d\x03\x0d\x8c\x19\x8e\xad\xd6\x7a\xc2\xa1\xbc\xc7\x15\x36\x7a\xdd\xa7\xd5\x77\x6c\xb3\xa7\xb6\x46\x67\x70\xd1\x9a\x3a\xa1\x80\xc6\xe5\x33\x88\xa5\xa1\x09\xb8\xac\xdf\xe3\xca\xe7\x12\x45\x5e\x91\x13\x22\x18\xd0\xb9\xa3\x89\xee\xee\x33\x97\xe1\xa2\xe5\x5b\xf3\xc8\xed\x75\x57\x7a\xab\x09\x84\xc5\xb4\x56\xcf\x86\x54\x97\xef\xbe\xe6\xa6\x60\x15\x07\x88\xb1\x6f\x51\x0d\x3c\x97\xc6\xfa\x51\xe5\xe8\x66\x36\x57\x3c\x0b\xf8\x83\x79\xae\xf2\x69\x38\x7e\x96\xa6\x58\x87\x61\x38\x98\x59\xc1\xda\x9e\x3f\x31\xde\x74\x69\x71\x00\x41\xa6\xb9\x1c\xb4\x53\x17\x06\xc0\xb3\x28\x9a\x78\x92\x9b\x01\xe3\xfe\xf3\x9f\x37\x9f\x2f\x5e\x06\x78\x7e\x8d\xd6\x07\xaf\xbe\xba\x68\xa3\x4e\x34\x73\x92\x38\x89\x66\xde\x6a\x39\xcf\xc4\x44\xa9\x73\x72\x57\x91\x67\x3b\x61\x56\x6e\x3f\x3a\x74\xae\xcd\x6a\x95\x92\x9a\x3a\x49\x33\x4d\x3d\x37\x74\x0e\x6e\x62\xca\x37\xee\xf7\x4a\x8a\xa7\x16\x57\x1d\x5b\xfb\x37\x28\x97\xf0\xaf\x28\x2c\xee\x0f\x93\x5d\xad\xf7\xab\x38\xbf\xf9\xfc\x7b\xb1\x04\x69\x5f\x40\x17\xed\x8f\x7b\xd3\x0a\xd1\xb3\xdb\xe8\x98\x72\x4f\xd3\xfd\xf6\x8e\x29\x19\x9a\xc8\x91\x9d\xec\x3b\x6e\xa8\xab\x7d\xf8\x86\xba\x9d\xc5\xd5\x9b\x8b\xaa\x0f\x9f\x43\xf4\x96\x05\x9d\xaf\x8b\x37\xdf\xb3\x37\x6f\x7b\xfd\xde\xd1\x91\xdd\x1c\xc6\xd7\xb5\xc1\xfb\xdc\x9f\xd8\x0e\x69\x87\xa9\x11\x85\xa7\xcf\x8d\x70\x51\x64\x99\xe8\xec\x20\x3d\xde\x12\x8d\x0b\xcf\x88\x38\xb7\xd5\xef\xdd\xc7\x4d\x1d\xdb\xd4\x58\xdc\x9c\x98\x81\x87\xb0\x21\xb8\x6e\x1e\x59\x48\xb8\x16\x6d\x7a\xf0\x8c\x8a\xab\x23\x56\xc9\xdc\x3d\x59\x68\xad\x74\xeb\x73\xd6\x3e\xdd\x9c\x3e\x5b\xed\xe6\xf3\xb6\x56\x9e\x38\xb9\x68\x7f\x29\xf7\x39\xd5\xdf\x24\xbc\x7d\xb0\x50\xb9\xd3\x10\xa2\xf4\x22\xd0\x3c\x39\x0b\x80\xeb\xde\x17\x14\x3e\x48\xd9\x57\x87\x56\x1c\x40\x41\xd1\x4a\xb9\xb3\xb1\x14\xdd\xe9\x5e\xef\x01\xf2\xe1\x96\x24\xfe\x06\xe4\x51\x40\x9e\x3c\x14\xee\xa7\xe2\x31\x9d\xc1\x5f\x1a\x8f\x2b\xc9\xfd\x3c\x38\x9a\xe5\x36\x01\x39\x36\x4f\x6c\xb5\xac\x4a\x95\x92\x3d\x77\x2c\x21\x49\x94\x27\x44\xde\x53\xf5\x8b\x8f\xc8\x3b\x84\xf7\x72\x87\xd2\xf7\x3e\x30\x61\xab\x6b\xc5\xf9\x96\x1b\xec\x9f\x3b\x12\xa1\x74\x7d\xb2\x03\xf3\xc4\xcb\x16\x05\x20\x3e\xf0\x24\x8f\x43\xe4\xab\x70\x20\x4c\xdd\x8f\x3e\xca\xe7\xdc\x36\xd8\x12\xaa\x9d\xd0\x8e\x23\x2f\x3c\x73\x3e\x62\x75\x5d\xb8\x63\xa0\x52\x83\x83\x3a\x79\xe9\x52\xfd\x4a\x0f\xdf\xb6\x51\xe7\xfa\xff\x5e\x36\x8b\xb9\x60\x0f\xc9\x79\x3e\xbf\x45\x1c\xc5\xf6\x89\xea\x9c\xc3\xbf\x8c\x4c\x4e\x96\x38\x5e\xff\xc2\x43\x40\x56\x5b\x27\x2f\x9c\x06\x5e\x7c\x0a\x08\x8e\xdc\x2f\x0f\x7c\x77\xa2\xff\x9f\x7f\x6e\xda\xcf\xb2\xf9\x75\x6c\x34\xa9\xbf\xac\xcd\x5f\xb1\xff\xeb\xda\xfc\xd8\xf9\x09\x66\x3f\x4e\xbc\x99\x99\xad\xcd\xfe\x8a\xcf\xcd\x80\xb0\x5d\x9e\xe9\x71\xe4\xb4\xb4\x33\x6d\x6c\x1d\xe9\xe3\x7c\x2f\x85\x8e\x9d\x42\xa7\x6f\x89\xfd\x99\xff\x7f\x92\x5e\x23\x14\xcd\xc1\x16\xd7\x65\x7c\x7d\x74\xb7\x5a\x59\x85\x8d\x92\xb9\x99\xd8\x8e\xad\x24\xe6\x64\xe2\xc1\x33\xc5\x39\x33\x73\xe6\xe6\x42\x49\xcc\x30\xf5\xb2\x2a\x75\x76\x38\xd5\x25\x39\x41\x94\x39\xab\x1a\xe9\x89\xb2\x49\x51\x70\x9b\xf9\xe3\xb6\xe9\x3d\x5b\xde\x5f\x95\xa8\x82\xc2\xc1\xfd\xaf\x97\xa5\xc2\x56\x4e\xe2\x3e\x76\x9c\xc4\x0b\xdd\xdb\x0f\xc2\xd8\xce\xf7\x51\x49\x7d\x0f\x7a\x3f\xe6\x98\xa8\x8f\xce\x6a\xbd\x7d\x3c\x7e\x7f\x9f\xca\xfd\xad\x4a\x3f\x46\x95\x66\xc7\x0e\x8a\xb8\x58\x87\x36\x06\x7f\x53\x95\xbe\x29\xfe\xfa\x0b\xe8\xd0\x0e\xe6\x3f\x4a\x95\x0e\x8e\xc7\xf7\xd3\x21\xdf\x0b\x0b\xec\x70\x45\x52\xb7\x1d\xc1\x3c\x70\xc2\x6c\x6f\x6e\x72\x56\xd7\x60\x14\xa6\x5e\x9a\x39\x21\x5c\x9c\x3b\x91\x6d\x75\x34\x35\xf3\x5a\xa3\xef\xcc\xca\xe3\x2b\xe4\x2c\x89\x36\x4f\x78\x3e\xc0\xff\x9e\x0c\xde\x15\x68\x56\x95\x85\x2a\x15\x75\x81\x10\xb7\x18\xda\x0f\x63\x0e\xb0\xb8\x73\xbc\xfe\x70\x32\x71\x92\xea\xdc\xa5\x53\x67\xe4\x79\xb1\x64\x86\xae\xc3\x7a\x28\x2b\xf7\xdf\xaf\x1f\xda\x90\x44\xfd\xae\x4e\xdd\x91\x74\xe3\x8e\xa6\xbe\xd4\x89\xbb\xaf\x0f\x77\x8d\xfa\x1d\x59\x23\xbf\x34\xa8\x3b\xf2\xeb\xc3\xdd\xc3\x5d\x8d\x28\x3e\x3f\xd0\x77\x0d\xe2\xae\xde\x28\xbe\x3c\x7e\xbd\x23\x1f\xeb\x77\xd4\xc3\xcd\x97\x2b\x6f\xf2\xc9\xf9\x23\x37\x51\xfa\x69\x2f\xa3\xb7\x71\x02\x7f\x91\x7a\x2b\xff\x7c\xb9\xba\xf9\x72\x30\x01\xb8\x55\xfc\xb0\x0e\x78\xe9\xb6\x0d\x2b\xfb\xd4\x09\xcb\x60\xf3\xa8\x61\xdd\xd6\x8d\x77\x9f\xbc\xfb\x43\x4f\xd5\xb9\x10\x13\x65\xa0\xfd\xe4\x2c\x5a\x66\xea\xd8\x03\x27\x33\x31\x4c\xb4\xc4\xcb\x9c\x2d\xef\x74\x91\xf9\xdd\x7e\xe6\xb3\xff\x36\x87\x8b\xf2\xa6\xaf\x5a\x7f\xbf\x43\xe2\xbb\xe7\x50\x57\xb6\xa0\xf3\x12\x3b\x89\xb7\x3a\x29\xee\x9a\x89\x12\xe7\xea\x93\x2c\xf6\x3f\xbf\x31\xa5\x4a\xdf\x12\x8f\x3f\x38\x82\xda\x36\xd3\x1f\x10\xb4\x54\xcc\x9c\x75\xf6\x37\x4d\x69\x78\x73\xc8\x6f\x1f\x7a\x4e\x1e\x67\xa7\x5f\x97\xf2\x72\x1b\xa4\xb7\xc5\x81\x7a\xb7\xd9\x34\x89\x72\x77\x1a\xe7\x45\x6e\xbb\x4e\x10\xef\x0d\x0d\x0e\xa5\xf7\x0f\x42\xf4\xcb\xd5\xcd\x3d\x16\x2b\xee\xd0\x37\xe2\xf5\x3e\xfd\x03\xb5\x57\xbf\x7d\xc7\xc9\xde\xc7\xa1\xec\x44\x5f\x76\x1e\xcc\x1f\x14\xdd\xcf\x44\x60\x33\x5d\x84\x70\x18\x3b\xd5\x29\x6f\x47\x1e\x59\xc5\x66\x92\x79\xb8\xc4\xa1\x37\x43\xec\x94\xcc\xa6\xe7\x73\x9c\xd7\xf7\xde\x89\x2c\xc5\x91\x17\x32\x5d\x6d\xc6\x3a\x5d\x33\x9d\x1e\x31\xe1\x47\xfa\xb0\x32\x53\x4a\x86\xa3\x94\x07\xa2\xfe\x48\x10\x6f\xd5\xbb\xef\xa8\x33\xf8\xf3\xce\x60\x7c\xa8\x1e\xdd\xc3\x28\xcc\x4c\x2f\xfc\xae\x27\x24\xff\x10\x95\xda\xea\xd6\x25\xfa\x75\xcc\x2a\xbd\xb3\xfd\x5f\x5d\xa5\x07\x51\xe8\x65\xd1\xde\x30\xbf\xb6\xf3\x9f\xa6\xcb\xb7\xe4\x2f\xa6\xc7\xd5\x08\xfc\xad\xc0\x7f\x2b\xf0\xc6\xfd\x4b\x15\x78\x18\x3b\xa1\x3c\xf5\x26\x19\x53\xad\x91\xf9\x61\x9a\xbc\x45\xf1\x07\xeb\x74\x1e\x7a\x7f\xe4\x78\x4e\x75\x26\xf7\xb0\x5d\xf8\x43\x8e\xe4\xbb\x4c\x3c\xeb\xe2\xf7\xfe\x29\xe9\x54\xd7\x99\xf3\xbc\x4f\x3f\xed\xf9\x0e\x4c\xaf\x56\x5c\x49\x9b\xf6\xa1\x67\x9f\x1c\xe8\xea\xfa\xf5\xba\xe2\x39\x61\xf6\x31\xcc\x1f\x47\xf9\x85\x09\x82\x9f\xeb\x6b\xf6\x8c\xc5\xdf\x4e\xe7\x6f\xa7\xb3\x71\xff\x52\xa7\x23\x6f\x2c\x80\xfc\xcf\x08\x1d\x7f\x31\x45\xdd\x12\xf0\xdf\x4a\xfa\xbf\x4a\x49\xd7\xe0\x71\x73\xcf\xde\x3b\x1c\xd2\xb3\xbf\x5c\xdd\x48\xa3\xab\xfb\x2b\xc9\x31\x6d\x27\xb9\x08\x1c\xcd\xd5\x7b\x4d\x8a\x11\xbc\x4f\x22\xe4\x94\x9b\x4e\x70\xcf\xf6\x60\x70\xce\x48\xa4\x30\x8a\x0f\x3f\x42\xf1\x0e\x2f\x81\xc6\xed\xb5\x9d\x89\x17\x16\xd6\xe0\xc0\x1a\x6a\xe9\xa0\xe8\xf7\x99\x7e\x25\x52\x24\x65\x4d\x68\xdb\x5f\x29\xf3\xeb\x6d\xad\xf6\xd8\xb8\xad\x3f\x3a\x93\x5b\xcb\xae\x53\xb7\x93\x07\xe2\x61\x62\x99\x8f\xa4\xe9\x7c\x3d\xf6\x46\xe9\xad\xb7\x9f\xbe\xff\xc5\xd4\x55\x89\xf5\x33\x9e\x9d\x9a\x6f\x4c\x67\x3f\xde\x12\xf4\x2d\x41\xde\xc6\x89\x33\xf3\x9c\xf9\x25\x8f\xf3\x2e\x40\x0b\x8b\xd1\xb2\xca\x66\x5f\x31\x51\x58\xbe\xca\x2d\xfa\xdf\x0c\x9d\xba\x4d\x7f\xb5\xe8\x47\xeb\x96\xb4\xeb\x93\xdb\xfa\xd7\xc7\xaf\xb7\x26\x45\x93\xb7\xf0\xe1\xeb\x63\xad\x6e\x53\x24\xf5\x2e\xe8\xbc\xe5\x55\xf5\xbf\x10\x74\xde\xe2\xa5\x8e\x09\xf9\xe6\xcb\xd5\x16\x02\x3f\xd6\x8c\x56\x36\xef\x95\xce\xd5\xaa\xc0\x36\xa0\xbf\xd5\x53\x16\x5b\x0b\x6d\x27\x49\x3f\x1e\xe9\x1f\xed\x57\x7e\xa0\xb6\x34\x2c\x9b\x86\xf6\xe3\xe3\xed\xc4\xa9\x37\x6e\xeb\x14\xf9\x70\x4b\xd7\x1e\xad\xdb\x09\xfd\xb5\x5e\xfb\xea\x90\x8d\x7a\x83\xf8\x6b\x1b\xda\xbf\xea\x93\x9d\x93\x2a\xbc\xb1\x21\xf0\xfd\x9a\xbb\xbb\x4f\x70\xb7\x27\x1b\x8d\x7c\xae\x7c\x4d\x5b\x90\xaf\x70\xe1\xb7\xeb\xe6\x6e\x6b\x3f\x4e\x21\xdf\xd2\xcf\x1f\xaa\x7c\x96\x33\x71\x26\x26\x41\xde\x52\x26\x45\xdf\xd6\x49\xfa\xeb\xed\x63\xcd\x7c\xbc\xa5\xbe\x52\x93\x49\xad\x06\x9d\x1a\x59\xff\x6b\xbb\xaa\x0f\x7d\x78\x7f\xd9\xf8\x1d\x53\xb4\xdf\xca\xef\x7f\xfe\xf6\xff\x03\x00\x00\xff\xff\x20\x6f\x04\x85\xaa\x87\x00\x00") +var _rpProductionJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x7b\x73\xe2\xb8\xb6\xef\xff\xf3\x29\x52\xb9\xa7\x2a\xdd\xf7\x76\x12\xdb\x84\x74\xbc\xab\xf6\x1f\x60\xb0\xc1\x01\x07\xbf\x64\xe3\x7d\xa6\x76\xd9\xb2\x30\x0e\xf2\x63\xfc\x80\xc0\xa9\xf9\xee\xb7\x64\x63\xc2\x1b\x92\x4e\x77\x4f\xef\x33\x9e\xaa\x1e\x88\xa5\xa5\xa5\xa5\xdf\x7a\x68\xe9\xc1\xff\xfc\x76\x71\x71\x71\x71\xf9\x5f\x29\x1c\xa3\xc0\xbe\xfc\xc7\xc5\xe5\x38\xcb\xe2\xf4\x1f\xb7\xb7\xe5\x5f\x6e\x02\x3b\xb4\x3d\x14\xa0\x30\xbb\xb1\x17\x79\x82\x6e\x60\x14\x2c\xdf\xa5\xb7\x0c\x45\xd7\xaf\x29\xfa\x9a\xa2\x6f\x5d\x14\xe3\x68\x4e\xca\x69\x28\x88\xb1\x9d\xa1\x9b\xe7\x34\x0a\xff\xcf\xe5\x97\xb2\x05\x18\x85\x19\x0a\x33\x80\x92\xd4\x8f\x42\xd2\x10\x7d\x43\x91\xff\xaa\x02\x53\x3b\xf1\x6d\x07\xa3\xf4\xf2\x1f\x17\x25\x57\x65\x3d\x9c\xa7\x19\x4a\xd2\x47\x34\x9f\xda\x39\xce\x1a\x10\xa2\x34\x1d\x44\xd8\x87\x7e\x51\xf6\x5f\xab\xb2\xe4\xf9\x9f\x8d\x6f\x05\x85\x0c\x85\x76\x98\x75\x5d\xd2\xe6\xbf\xd2\xdc\x49\x61\xe2\xc7\x99\x1f\x85\x9f\x3e\xdf\x54\xef\x7e\x5f\x72\xb1\x51\x31\x72\x9e\x11\xac\x2a\xc6\x76\x62\x07\x88\x70\xf2\xe9\x6a\x14\xab\x28\x99\xfa\x10\x0d\x12\x3f\x84\x7e\x6c\xe3\xae\x7b\xf5\x79\x2f\x8d\x18\x25\x81\x9f\x92\x2e\x6f\xf6\x6b\xa3\x50\x8a\x60\x82\xb2\xdd\xce\x6c\x14\xf2\x50\x76\xb9\xf7\xed\xef\xbb\xcd\x96\x92\x43\x49\xe6\x8f\x7c\x68\x67\x7b\xe4\xb4\x59\x32\x41\x76\x86\xf6\xb0\xbf\x2a\xe1\x22\x8c\x32\x74\xa0\xfd\x9d\xbf\xfe\xf9\xdb\xfe\x6f\x6b\x9c\x5e\xa6\xa5\x04\xff\x4a\xc3\x9a\xfc\xb5\x86\xf5\x7c\xb1\x16\x9f\xfe\x5c\xea\xd1\x6b\x8f\x36\x15\xc9\x76\x03\x3f\x6c\xc4\x3e\x67\x37\xf3\xd0\xc5\x68\x87\xef\xcb\x6c\x1e\x93\xbf\x5e\xa6\x59\xe2\x87\xde\x2b\x57\x7f\x7e\xd9\x43\x05\xfb\x28\xcc\x38\x94\x64\x5c\x14\x04\x51\x28\xd9\xc1\x3b\x29\xba\x76\x66\x3b\x76\x8a\x1a\x10\x46\x79\x98\x7d\x03\xa1\x28\xb0\xfd\x6f\x60\x04\xbd\x64\x89\xcd\x45\x69\x10\xa5\xad\x66\x77\xb0\x3b\xb0\xdb\x54\x36\x71\x71\xe9\xa2\x11\x41\x32\xb0\x71\x5e\x94\x3a\xd2\xca\x41\xd4\x1f\x68\xd0\x4e\x12\x7b\x7e\xa2\xbd\x7f\xfd\xbe\xb7\xbd\x7d\xb6\xea\x7d\xf2\x99\x2c\x99\x1e\x24\x68\xe4\xbf\xbc\x55\x3a\x81\xfd\xd2\x43\xa1\x97\x8d\x2f\xff\x71\xc1\x50\x7b\x1b\x08\xdc\x80\x4f\x0a\x37\xe1\xea\x09\x7e\x1f\x93\x81\x9b\xba\x5c\x14\x8e\x7c\xef\xd5\xd3\xbc\x93\x4c\x3b\x9c\xfa\x49\x14\x12\x97\xf6\x3e\x22\x71\x8e\xb1\x5a\xd8\x80\x23\xf5\x11\xcc\x13\x74\x8c\x4a\x12\x77\x03\xdb\x7b\x27\xa6\x97\x95\x1b\x79\x21\xf7\x6f\xe0\xa1\x1f\xb9\xa7\x59\x78\x97\x42\xec\xb3\xba\xef\xeb\x6c\x9a\x8e\x07\xb9\x83\x7d\xf8\x88\xe6\xef\xa3\x30\x0d\xd2\xf4\x8d\x06\x64\xc3\xf6\x26\x28\x8d\xf2\x04\x6e\x39\xb0\x2d\x52\xe9\x24\xdf\xeb\x33\x2e\xc3\xb2\xe5\x4b\x35\xb3\x43\xd7\x4e\xdc\x4d\xbf\xf0\xe7\x96\x74\xe3\x24\x8a\x89\x87\xdf\x63\x37\xca\xf7\x85\x28\xba\x83\x06\xc6\x11\xb4\x89\x63\xec\xa3\x6c\x1c\xb9\xcb\x16\x32\x1f\x1e\xa7\x5f\x71\x93\xc4\xd7\xb1\x1f\x6f\x8f\x6d\x25\x8f\xbe\x0f\x93\x28\x8d\x46\xd9\x8d\x84\xb2\x59\x94\x4c\x6e\x57\xed\xba\x6e\x82\xd2\x14\xa5\xdb\x55\x2b\x76\x0a\xff\x5b\x49\x4c\x48\xa2\x3c\xfe\xf4\xf9\xa6\x7a\xb9\xed\x75\x2f\xed\xd8\x5f\x8b\x1d\x19\x8a\x66\xaf\xa9\xaf\xd7\x14\xbd\x77\x20\x7f\x8e\xc4\x47\x4b\xe3\xd5\x1d\x94\x16\x28\x4f\x8a\xae\x1c\x0e\x00\xf6\xc7\x0d\xe7\xb4\xb5\x59\x76\x53\xe2\x27\x2b\x14\x95\x7c\x77\x43\xfe\x5d\xf7\xd3\xd5\x19\x63\x79\xf5\xe5\xe2\xaa\x04\xc4\xfe\xc0\x68\xa7\x99\xcc\xf6\x08\x43\x61\x8e\xf1\xd1\xc2\x7f\x1e\x7c\xfb\xe7\x91\xb0\x74\x0d\xa3\x95\xf0\xf7\x07\x53\xbb\xe4\xf7\x44\xcd\x97\x8e\x0d\x27\x28\x74\x97\xbd\x1d\x44\x11\x7e\xd7\xd8\xad\x71\xb5\xa4\xf8\x2d\x4c\xe1\xc8\x76\x9b\x36\xb6\x43\xe8\x87\x9e\x92\xe3\x23\xc1\xfc\x07\xe1\xe9\x00\x8e\x3f\x10\x57\xaf\x7d\x42\x49\x7a\x7b\x48\x6f\x96\x60\xc3\xce\xf2\x43\x55\x8e\x40\xef\x38\x98\x8e\x03\x73\xcf\x38\x7f\xb7\xbe\xed\x81\xd4\x76\xb7\x96\x45\xbe\xb9\x57\x71\x12\x39\xbb\x9e\xeb\xa3\x3a\x52\x50\xdf\xe1\xbd\xf8\xeb\x47\x70\x9e\x45\xb0\x18\x85\x4b\x0d\x6e\xfb\x9a\x9d\xe2\x84\xb1\x96\x4f\x3c\xb1\x93\x57\x8e\xa4\x55\xc6\x1a\xa7\xaa\x56\x10\x1a\x44\x09\x09\xca\xee\xee\x6a\xe7\x41\xe5\xb5\xfc\xb7\xda\x29\xec\x24\x39\x3e\x30\x93\x3e\xcf\x20\x94\x23\xf1\xdd\x9d\xca\xda\x98\x74\xb2\x2c\xde\x76\xe3\xbb\x15\xce\x15\x69\x98\x07\x0e\x4a\x9e\x46\x83\xaa\x1f\xcc\x89\x0a\x09\xfa\x23\x47\x69\x36\xb0\x8b\x20\xf6\xf2\x76\x8c\x6c\x9c\x8d\x17\xb7\x09\xb2\xdd\xf9\x61\xe4\x9d\x39\x20\xa5\xda\x9c\x3b\x1e\xe7\x86\x4c\xd8\x39\x3f\x62\xda\x50\xb4\xef\x1c\x2d\xed\x84\xe8\x31\x0a\xdd\xf4\x29\xdc\x0b\xa7\x6f\x0c\x0f\x7e\xdb\x2f\xb9\x0f\x88\xd3\xfe\xdd\x62\xd2\x7f\x4f\x6b\xfb\x32\x33\x99\x8f\x92\x8d\x90\x6e\x4f\x19\x68\xc7\x36\xf4\x33\x32\x49\xa8\x7d\x53\xc4\x97\xc7\x5e\x62\xbb\xa8\x98\xc0\xef\x4e\x39\x56\xc5\x82\x72\xf2\x74\xd9\xb7\xc3\xdc\xc6\xbb\x58\xdb\x83\xd4\xcb\xa9\x9f\x64\xb9\x8d\xfb\x36\x1c\xfb\x21\x1a\x24\xd1\xc8\xdf\x93\xb3\x59\x15\x8f\xd2\x53\x45\xca\x9e\x47\x41\x9c\x67\x28\x21\x93\x9c\xd5\x3c\xfe\xf2\x5f\x30\x0a\xa1\x9d\x7d\x22\x63\x77\xf5\xe5\x62\x3d\x27\x56\xcd\x88\xae\x3e\x7f\xb9\xb8\xba\x3e\x1e\xf4\x95\xc9\x21\x3d\x45\x49\x35\x5e\x10\x47\xb9\x7b\x9d\xa7\x28\x39\x56\x0d\xfb\x61\xfe\xf2\xb6\x50\xe3\xd2\xf5\x53\xdb\xc1\x68\x60\xa7\xe9\x2c\x4a\x5c\x32\xc1\x45\x61\xe6\xaf\x74\x25\x4b\x72\x74\xc2\xac\xa4\xe9\xee\x9c\x78\x6f\xc1\xb8\x9a\x54\x1e\x4f\xe5\xad\x3f\xa7\xa9\xbe\x52\x5f\x99\xb5\x28\x40\xb7\xaf\x12\xbb\xbd\x49\xd3\xf1\xad\x9d\x67\xe3\x28\xf1\x17\xc8\xfd\xf7\x84\x30\x70\x3a\xe4\x5e\x11\x9e\xa0\x79\xcb\xce\xec\x9d\x34\xe7\xfa\x34\xf9\xa4\xeb\xae\x9e\xc3\xf1\x79\xf5\xec\xe6\x2b\xcf\xab\xbf\xff\xcd\x01\xe3\x7d\x99\x66\x51\x62\x7b\x27\xf5\xa1\x28\xeb\x07\xb6\x87\x14\x34\x42\x09\x0a\xe1\xe9\xc8\xa8\x1c\xe7\x74\x5c\xda\x0f\x05\xb9\x1d\xfb\x64\x3c\x11\x8d\x46\xcb\xe2\x9d\x76\xef\x54\xe1\xd2\xbc\x5d\x3e\xdc\x6c\x9b\xe1\x9d\x92\xd3\x57\xdb\x8d\xed\x0c\xa5\x07\x52\xc4\x17\x27\xbc\x5c\x94\xb6\xfc\x74\x72\xba\xe3\x65\xfe\xff\x29\xae\xfc\x0c\x9f\x44\x41\x99\x74\x3a\xc1\x67\xb9\x38\xe4\x9e\xd5\xca\xc5\xda\xf0\x2d\x73\xbd\xda\xd2\x25\x0e\x12\x14\xf8\x79\xf0\xef\x9e\xa2\x9e\x08\x24\x3f\x08\x45\x61\xe9\xc0\xce\x42\x51\x19\x6d\x0c\xce\x0a\xae\x7f\x64\x60\x7d\x34\xbc\x29\x5b\xea\x86\x19\x4a\x46\x36\x44\x67\xe6\x23\xaa\xe7\x8c\x81\x5c\x0b\x75\x88\x8b\xb8\x0e\x7d\x78\x4e\x3a\xe0\x0d\x11\xe8\x5a\x1d\x3f\xb0\x93\xf9\x59\x46\x7d\x55\xc9\x8f\xdf\xd8\xe7\xf5\xe7\x7c\xeb\x7d\xb1\x4f\x16\x7e\x0c\x8b\xb6\xdf\x60\xac\x2f\xde\x29\x9c\x8d\xfa\x69\xee\x84\x7b\x72\xcd\x67\xd7\x3f\x0b\xbc\xcb\xb8\x64\xf9\x35\xbd\x2d\x1b\xad\xf0\x3b\x0d\x51\xb6\xfc\x58\xbe\x38\xdb\xc1\xac\x3f\x27\xe6\x8b\x7b\x99\x7f\x0f\x4a\x36\x09\x6c\x06\xb3\x6f\x4f\x7d\xec\xa5\xba\x8d\x8d\xdd\x54\xea\xf9\x0c\x7e\x1b\x3c\x56\x74\xdc\x30\x55\x51\x96\xf9\xa1\xf7\x6d\x84\x2e\x36\x17\xdd\x7a\xb6\x83\xf0\x76\x34\x59\xf4\xf9\x60\x48\xf9\x1e\x6c\x54\xcf\xe9\x80\xe4\x63\x6a\xbd\x07\x8b\xeb\x06\xbe\xf9\x86\x9c\xe2\xa9\xe7\x1b\x06\xfd\xe7\xa6\xae\x0e\x3d\x6f\x1f\x8e\xe3\x51\xe6\xfb\xe9\x9f\x57\xf2\x74\xeb\xc7\xe9\x1c\x7e\xbb\x9f\xf2\xa1\xf8\x05\xbd\x64\x28\x24\x11\xe2\x59\x11\xcc\xaa\xf4\x77\xf1\xfc\x30\x3d\x15\x26\x5e\xbc\xdb\xf3\xaf\x07\xe4\xaf\x70\x6d\x14\xfb\x90\xda\xaf\xbd\x3a\x33\x26\xa8\x32\x30\x5c\x9e\x66\x51\xa0\x16\xfb\x45\xde\x52\xb7\x63\x87\x2e\x46\xc9\x7a\x62\x65\xb5\x7d\xe9\x24\x01\x3b\xcf\x22\xbd\x4c\x17\xf4\xfd\x30\x5a\xa3\xf2\x86\xa8\x26\x5d\xb3\xdb\x67\x1a\xa6\x22\x91\x87\x60\x86\xdc\x77\x19\xfd\xcb\x72\x5b\x4d\x61\x3c\x1c\x3b\x45\xf7\x77\x9f\x96\xe6\xbd\xfc\xa6\x45\x6a\xb1\x22\xfa\xe9\x0a\x32\x80\xea\x72\x34\x46\x8d\xe8\xf1\xea\xf3\x97\xab\x7e\xab\xcf\x2b\x4f\x92\xd6\x96\x5a\xba\xd2\xfb\xe7\x7f\x2d\x2b\x5c\x5c\xbb\x17\xff\x9d\x53\x54\x0d\xae\xff\x7b\x75\x75\xf5\x65\x49\x7e\xdd\x55\x6c\xee\x08\xb8\xfa\xfc\xf9\xcb\xd5\xd5\xd5\xe7\xff\x0e\xaf\x08\x79\xb5\xc5\x3d\x49\x7c\x57\x00\x6d\x45\xed\x3e\x49\xef\x6d\x61\x6b\xbf\xc0\x4e\x23\x6d\x09\x74\x95\x27\xa9\xdf\x96\xb4\xf7\x37\xb1\xb6\x97\x60\xa3\x81\x81\xde\xeb\xa9\x6d\x4e\x69\xbf\x93\xf6\xeb\x16\x83\x0d\xb2\xca\xa0\xdb\x6f\x08\xed\xf7\xd1\x5c\xee\x19\xd8\x47\xb0\xa1\x6b\x9d\x6f\x22\xda\xc8\xb3\xf1\x16\xe1\xfe\x53\xeb\xdd\x8c\xf6\x23\x77\x93\xcf\x46\xab\xdf\x95\x1a\x83\x2e\xd7\xeb\xb6\x25\x8d\x6b\x2b\x1a\xf7\xd4\xef\x3f\x49\x52\xa3\xff\xce\x46\x8e\x6d\x78\xda\xdf\x74\xa3\xa9\x4b\xad\x5e\xfb\x9f\x84\xe0\x5e\x4a\xcb\x0d\x58\x57\x45\xe5\xa2\x6e\xef\x89\x6b\x68\x6f\xc2\xf0\xa1\x4c\xf0\xba\x68\xdb\xea\x93\xae\x70\x6d\x41\x79\xd2\x07\x6f\x13\xc0\x36\x75\x62\xf3\xd7\x28\x93\x7f\xb6\xd5\x1f\x99\x20\xeb\x72\x74\xbd\xdb\x01\x33\x4b\xe0\x29\x4b\x6d\x64\x88\x6b\x9a\xb2\xfe\x12\x3b\x21\xb8\x93\x0d\x17\x3b\xa1\xfc\xc8\xf9\x7d\x6f\x68\x5a\x53\xdb\x90\xbd\x6e\x00\xe6\x30\x60\xe7\x4f\x7e\x73\x32\x7c\xd6\x3d\xcb\x14\xe7\x4e\xad\x1b\xf5\xb4\xfe\xec\x49\x1b\xd6\x1f\xd5\x66\x00\x03\x36\xeb\x0a\x8a\x6f\x19\x75\xa6\xa7\xd5\xa7\x50\x00\xf9\x93\xdf\xe4\x94\x76\x77\xd6\x6f\x4d\x5e\xba\x6d\x85\x33\x69\x8b\xd7\xb1\x24\x6a\x54\x7d\xa4\xe9\x58\xd3\x74\x5e\x97\x29\xef\xbe\xdb\x56\xc6\xae\xc0\xfb\x43\x53\xc2\x5d\x01\xe4\x6e\x80\xe7\x0e\x53\xcf\x2c\xa3\x4e\x75\x3b\x16\x86\xa1\x14\x3b\xcc\x9d\xe7\x18\x78\xe1\x18\x3c\x35\x64\x3c\x9f\x0b\x45\xd2\x8f\xa0\xcb\xb1\xcc\xd0\xec\x4e\x1d\x01\xfb\xbd\x9a\x38\x73\x54\x76\x64\x32\x8a\xff\xe8\x45\x8f\x30\x6c\x66\x5d\x8e\xca\x6c\x83\x9e\x39\x35\x91\xea\x0a\x63\xca\xed\x34\x17\x4f\xfe\xc3\xd4\x12\x66\xb9\x15\x80\x89\x53\x13\xc7\xb0\x23\x4e\xed\x00\x3c\xbb\x5c\x7d\x0a\x03\x38\x85\x1d\xe0\xf7\x18\x30\xb3\x8c\xd9\x54\xc7\x4d\xa9\xa7\xbb\xb2\x32\xa7\x7b\x0a\x98\x64\x0a\x68\xf2\x1a\x47\xdd\x71\x21\x69\xab\x91\xf5\x0c\x9c\x41\x81\x9d\xbb\x5c\x33\x72\x3b\xca\x0c\x2e\xa2\x69\xaf\xd6\x1c\x0f\x99\x6c\x6c\x31\x60\xd1\x0b\xe8\x78\x58\x13\xa7\x90\x61\x03\x97\xab\x3f\x3b\x0c\x35\xb5\x19\x50\x87\x73\x36\xb3\x0d\x69\xee\xd4\xa4\xa9\x15\xca\xf9\xd0\x94\x9e\xcf\xa7\x69\xa5\xae\x01\x72\x57\x10\x63\x97\xab\xc7\xce\x9c\x0d\x9c\x0e\xc0\x4e\xa8\xf8\xb6\x29\xe7\x84\x3e\xe7\xc5\x75\xd7\xa0\xbc\x9e\x39\xf1\x6c\xa3\xbe\x70\x05\x3e\x75\xd6\xe9\x31\x4a\xda\x0b\x2c\x6c\x09\xec\x7c\x68\x36\xe7\x0e\x13\xe3\x61\x4d\xce\x9d\x9a\x18\xf6\x6a\x4d\x7a\xe8\xb3\x18\x0a\x20\x5d\xca\x21\x83\x01\x48\x2d\x83\x5f\x58\x2a\x9d\x0e\x4d\x05\xc3\x9a\x9c\x3d\x71\xf5\xdc\x61\xf8\xf9\x90\xf1\x72\x22\x6b\xce\x8b\x9f\x87\xa6\xec\x0d\x7c\x16\xbb\x42\x7f\x4a\xb0\xd6\x0b\x45\x0c\x05\x76\xd1\x0b\xe4\xe9\xd0\x8c\x69\x18\xe8\x39\x0c\xc0\xcc\x99\x37\x1e\x06\x9c\xcb\x6b\xd4\x30\xe4\x70\x36\x46\x21\x98\x5b\x2a\xfd\xec\x08\xd8\xe5\x82\xfa\xd8\x31\x74\x76\x59\x3e\x1b\x32\x2f\x31\x17\x88\x63\xc8\x00\x1a\x06\x33\xd6\xee\x28\x14\xec\xf4\xef\x7b\x73\x76\x36\x34\xa4\x64\x68\xb8\x18\xce\xeb\x9b\xf2\x64\xd8\xac\x57\xc3\xb4\x63\x2e\xdb\x67\xf8\x7b\xd7\x14\x71\xcf\x90\x52\x5b\x8e\xb1\x13\xf0\xbe\x23\x80\xc9\xc0\xc4\x18\xce\xe2\x10\x0a\xee\xb3\x2d\x80\x67\x7b\x41\xd7\x2d\xb3\xff\xb8\xe2\xc9\x90\xa6\x30\x00\x5b\x3c\x81\x67\xa7\x26\xe2\x8f\xe2\x69\xc8\xb0\x73\xeb\x38\x4f\xb9\x33\x8b\x89\xac\x1e\xb9\x40\x1a\xbb\x5c\xe3\xff\xf5\x18\x40\x0d\xe7\x2c\x19\xe3\x52\x9e\xb5\x7e\x6e\x71\x2c\x65\x71\x34\xc1\x48\xee\x72\x74\x81\x85\x3d\xb2\xde\x2a\xa3\xac\xfa\xe6\x0a\x72\x36\x2c\xf5\x3f\x1b\x06\x98\x3a\xa3\x7f\x9b\xb8\x33\x1e\xa6\x43\x42\x97\xf4\x6d\x01\x1f\x2d\xa3\x3e\x1e\x06\x2f\xd8\x6a\x95\x32\xb5\x6a\xcd\x70\xc8\x8c\xf1\x90\x49\x59\x64\x80\x05\x37\x01\x03\xc5\x8b\x1e\x57\x36\x49\xc0\x39\xac\x29\x63\x47\x98\x79\x43\x33\x5e\x58\x46\x9f\x8c\xfd\xd8\x31\x78\xa6\x2b\xf0\xf7\x90\x01\xcf\x3d\x83\x9e\x3a\x01\xa6\x9c\x5a\xd7\x5b\xc7\x07\x79\x5f\x8e\x2f\x3d\x81\x8c\xbc\x7a\x47\xea\xb8\xa6\x18\xbb\x9d\x89\x07\x05\x76\xe2\x18\x7c\xde\x33\x94\xe9\x90\xc9\x30\xf4\x9b\xdb\xf2\x7a\xe4\x02\x2b\x86\x01\xa8\x0d\x8d\x97\xb4\x67\x48\x99\xc5\x11\x7d\xe4\x27\x16\x57\xda\x90\x81\x26\x53\xfd\x39\x4b\x0d\x6b\x0d\xaf\xa7\xd2\x33\xcb\x14\xb3\xa1\x51\x5f\xd9\xcc\x35\x39\xf9\xae\xe1\xde\xdb\xc6\x4b\x3a\x54\xeb\x73\xcb\x50\xa2\xa1\x59\x61\x40\x8a\x9c\x9a\x3b\x1a\x86\x20\xec\x05\x52\x68\x6b\x6c\x6c\xb5\xa8\x97\xa7\x56\x83\xee\x3f\xb7\xe7\x5c\x28\x61\xd2\xae\xad\x36\x32\x4b\x6d\x84\x70\xce\xc6\xb0\xa3\x14\xb2\x84\x73\x36\xb0\x4d\x11\xbb\x0c\x9f\x3a\x82\x3c\x15\xe7\x8d\xa9\x65\x2a\xcf\x3d\x46\xca\x6d\x95\xcd\x2d\x53\xce\x2d\xee\xe1\x4e\x9a\xd3\x33\x87\x51\xb2\xa1\x71\x97\x0d\x43\x31\xb6\x04\x17\xf7\x02\x69\xea\x04\x56\x6a\x9b\x12\xc5\x79\x71\x66\x33\x4a\x0c\xfd\xc6\x14\x06\xec\xd4\xe5\x1e\x72\x4b\x60\x9f\x6d\x06\xcc\x57\x18\xab\x89\x53\xa7\x26\x4f\x7b\x41\x25\x2f\xf6\xd9\x61\xea\x81\x6d\xc0\xdc\x0e\xa5\xa9\xe3\x37\x1e\x06\x6d\x32\x86\xf1\x57\xce\x9b\xf8\x43\x13\x50\x76\xa7\xef\x3f\xf9\x4d\xf2\x5d\xec\xfa\xca\x57\x1d\x37\x45\x4d\xe7\x3b\x8a\xaa\xe3\xde\x3c\x66\xbb\xcf\x91\x87\x66\x91\xc8\xc9\xcb\xf2\x5c\xf7\xbe\xcb\x75\x27\xab\x72\x3a\x0f\x40\xdb\xf3\x49\xfd\x91\x1c\x89\x23\x39\x66\x2b\x9c\x0c\x19\x9e\xea\xb6\xee\xca\xfe\xd6\x94\x49\xcf\xe0\x43\xe2\x23\x7a\x06\xb1\x83\xbb\xd8\x1f\x32\x6c\x6e\xf9\x1b\xd8\x17\x35\xdc\x04\x80\xa7\x1e\x39\xbd\xc0\xbc\x07\x6b\x78\xe1\x0a\x20\xb3\x1a\x91\x08\x04\x3e\xec\x0a\xf1\xd4\x35\xc5\x7c\x68\xbc\x4c\x38\x0f\x6b\xc8\x94\x28\xcb\xa0\x27\x26\x65\xc5\x4e\x47\x21\x98\x19\xc9\x14\x2b\x69\x1a\x3d\x86\xc1\x03\xb1\x13\x82\xaa\xbf\xe8\x0a\x10\x5d\xce\xc3\x4f\x43\x83\xc6\x5d\x81\x9e\x5a\x02\x0e\x90\x1c\x89\x5a\xe9\xaf\x3c\x3b\x60\x69\x48\xf4\x4c\x90\x1f\x39\x20\x62\xc7\x60\x19\x0b\xb0\x35\xdb\x78\x99\x0c\x19\x7e\x6e\x71\xcd\x11\xe7\x61\xd5\x32\xe8\xa9\x1b\xe8\x1e\x68\x63\x49\x01\x92\x2e\xeb\xb4\xcc\x79\xb1\xa3\xd1\x40\xd7\x79\xa0\x9b\x84\x66\xc0\x67\x96\xda\x0c\x9c\x9a\x58\x1b\x9a\x22\xe1\x53\x2e\xfc\x5b\xab\x5b\xef\x3f\xf7\x67\x2b\x79\x99\x91\xe7\x08\x6c\x68\x1b\x77\x5e\xcf\x98\x10\xbc\x8e\x1d\xe1\x65\xea\xce\xe9\xdc\x99\xd3\x0b\xd7\x10\x17\xc3\x9a\x48\xb0\x15\x3b\x4c\x7d\xc1\x79\xb1\x06\x26\x92\x21\x03\xd0\x07\x3c\x50\x55\x8d\xf2\x45\x6e\x3c\x46\x7e\x33\xb1\x4c\xcc\x0c\x4d\x90\xba\x5c\xb3\xc0\x4f\x97\xa3\xc3\x62\xdc\x26\x40\xd3\x68\xa0\xca\x14\xe8\xe8\x13\x16\xe8\xed\x7a\x53\xd3\x75\x9f\xf8\x5d\x68\x02\x0c\xc3\x89\xd7\xc5\xe9\xad\x2b\xf0\x21\x9c\xd7\x4b\x1a\x2d\x8a\x15\x6b\x12\x86\xa1\x15\x0f\x19\x3d\x34\xd5\xfa\x0c\x06\x2c\xd1\x25\xca\x36\xc0\xa2\x17\x5a\x63\xd7\x78\xa1\x80\x29\xc6\x5d\xbf\x91\x39\xf3\x26\x05\x6b\xc3\xb8\xeb\xc5\xdb\xbc\x2c\x2c\x43\x9a\x5b\xa6\xec\x59\x02\x5b\x73\x82\x97\xe9\xd0\x90\x49\x3f\x03\xdb\x78\xc1\x5d\xae\xf4\x43\x8e\xa1\x64\xbd\xb0\x89\x97\xbe\x75\x42\xf8\x46\xb4\x64\xc8\xb4\xd5\x04\xfa\x8b\x0e\x80\x28\x8e\x4c\x09\x0f\x6b\x22\x76\x3b\xfd\x29\x0c\x1b\x19\xa9\xd3\xf5\xe2\x67\x9b\x8c\x25\xd7\x98\x49\xcf\x8d\xd9\x0e\x3d\x99\xd8\x28\xb9\x94\xad\x51\xc7\x5d\x0e\xbe\xf4\x38\x96\xd7\x26\xb2\x27\x53\x40\x05\x6d\x2c\xa8\xba\xd4\x04\x6d\x7d\xda\xed\x34\xc2\xdd\xfa\xe5\x18\x11\x7f\xed\x06\x3c\xed\x74\x64\x8f\xd8\x2b\x18\x00\xaa\x2b\x28\x53\x97\xa9\xa7\x0e\xc3\x4f\x88\x2c\xad\x00\xa7\x96\x5a\xe9\x7a\x61\xe3\x72\x28\x80\x65\x7c\x23\x7b\x85\xae\xd1\x56\x0b\x4c\x78\xa0\xf1\x0a\xd0\x27\x98\xad\x68\xc1\x39\x3b\x87\x1c\x9d\x59\x1d\x69\x52\xf6\x89\xad\x39\x7e\x73\x81\x4c\x29\x75\x18\x78\x4f\x74\x80\xe0\x64\x8d\xbf\x85\xc5\xd5\x67\x96\x41\x3d\x0e\x99\x71\xe6\x30\xb2\xd7\x6f\x0d\x67\x7d\x6e\xb7\x7d\xae\x1c\x93\xd4\x61\xdc\xa9\x5b\xd8\x4f\x3a\xb1\x04\x3c\xaf\x68\x0d\x4d\x71\xda\x33\xc5\x59\xe9\x4b\x74\x46\xe2\x1a\xc4\xa6\x3e\x0c\x5a\x33\x5f\x6c\xf3\x6d\x4d\xc7\x4f\x32\x68\x8a\x32\xc5\x73\x40\xaf\xb7\xb5\xb6\xee\xaf\x74\x9c\xe1\xe7\xce\x9c\x9e\x43\x8e\x1d\x5b\x02\x1d\x3b\x3e\xfd\x3c\x54\x69\xdf\x35\xea\x13\x47\xd0\xcb\xf6\x83\xc2\x96\xe6\x5d\x8e\x56\xbb\xad\xf6\xac\xdf\x6a\xdc\xf7\xb5\xc6\x1a\xaf\x4b\x1a\x8d\xe8\xd1\x31\xb2\x89\x6d\x76\xbd\xa5\xef\x5c\x54\xba\xdd\xab\x49\x75\x58\x53\xb0\xa3\xb2\x85\x8c\x7a\xe1\x0a\x9b\xb9\xd5\xd8\x8c\x69\x56\xf6\x82\xab\xea\x53\x95\xbc\x16\x96\x29\x32\xb6\x21\x61\x12\xeb\x38\x35\x12\xb7\x12\xbb\xab\xef\xb3\x43\x80\xf8\x30\x53\x8e\x9b\x56\xa8\x60\xf8\x4c\xe7\x96\xa9\xd4\x9c\x9a\x98\xf4\x0c\x36\x77\x04\x9c\x5b\x6a\x9d\x1a\x9a\x62\x68\x99\xf2\xa3\xa2\xb3\xc2\x76\x6c\x65\x09\x20\x28\x75\xa0\xe4\xb9\xdb\x9a\x3d\x14\xe5\x26\x74\x5b\xa7\x94\x91\x3e\x61\xfb\x0a\x60\x65\x7d\x02\x04\x15\x78\x6c\xaf\x66\x8d\xa1\xcf\xce\x5d\xe3\x6e\xc9\x2f\x3b\xb1\x8c\x52\xcf\xaa\x3a\x1a\xdd\xd4\x55\x9d\x7d\xd2\x17\x94\xdf\xd3\xdb\x5e\x8f\x60\xdb\xec\x7a\x26\xa7\x48\x0a\x2f\xb5\x4d\x5a\x1c\x68\x6d\x30\xd2\x79\x91\x57\x26\x78\xd8\xf5\xa2\x47\xcb\x1c\x97\xb1\x35\x2f\x69\x1a\xcf\xb6\x14\x20\xea\x26\x65\x89\x5a\x5b\x67\x97\x72\x9e\xd9\xcc\x64\xea\x0a\x2f\x8b\x1e\x43\xe4\xaa\x90\xff\x8f\x7b\x86\x48\x3b\x81\x92\x5a\x6a\xfd\x19\x12\xdf\x19\x80\xbb\x65\xcc\x2b\x69\x54\x5d\x04\x6d\x56\x55\xf5\x7a\xc7\xa4\xdc\x96\x4e\xb3\xbc\x86\x2d\x51\x9f\xb0\x4f\x9a\x0e\x9e\x40\x8b\x0a\xc5\x76\xc1\xf3\xe6\xdf\x39\xf8\xca\x4f\x9b\x1e\x68\x13\xac\x6b\xb4\x28\x6a\x13\x77\xa4\x50\x92\x66\x52\x7c\x4b\xa6\x58\xa0\x61\x99\x95\x81\x38\xd0\x71\xb3\xef\x30\xee\xe2\x44\xdb\xaa\xa2\xbb\xa2\x46\xdd\xb1\xe2\x5c\xe9\x6b\x14\xd1\x67\x3c\xd0\xfc\x53\x6d\x49\xbc\x8e\x95\x51\x69\x07\x36\xe4\xb1\xc4\x58\x61\x3f\x30\xea\x34\xa7\x30\x94\x3d\x4d\x67\x9f\x54\xa0\x0c\xf4\x09\x7e\x52\x68\xb6\x23\xd3\x52\x59\x97\x67\x7b\x0a\x20\x76\xe4\x85\x1f\xa8\xbb\xfa\x79\x9c\x07\x62\x8b\x81\xa6\xb7\xf9\x96\x42\x06\x77\xc2\xaa\x7a\xfb\x65\x6a\xd5\xfa\x07\xeb\xc9\x14\xfb\xa4\x4c\x70\xe7\x75\xae\x56\xf4\xbb\x18\xff\xea\x1d\x98\x00\x55\xa7\x8e\xcb\x00\x00\x89\x37\x29\x97\xd7\x26\xc0\x90\x01\xdb\xd2\xa8\xba\xa0\xea\xee\x48\x27\x7d\x9a\x60\xc2\x0f\x05\x43\x80\x39\xef\xa0\x0c\x74\x45\xaf\x37\xc9\x58\x9d\x2b\xf7\x02\xf3\x1a\xd1\xf5\x83\x34\x55\x8d\x7a\xe1\x4d\x0a\x3f\xe9\xb4\xd2\xd4\x26\x12\x3f\x50\xe1\xe4\x51\x18\x4f\x61\x4d\xc9\x89\xef\x7e\x54\xe1\x5e\x7d\x23\x7a\x5f\xe8\x71\x80\x43\x62\xff\x1c\x75\x15\xfb\x48\x4a\x9b\x16\x08\x06\x41\x1b\x3c\x29\x3c\x50\xb5\x25\x3e\x35\xdd\x52\x35\xaa\x4e\xfa\xd1\x06\x40\xec\x8b\xb3\xa2\x6c\x19\xe7\x14\xf1\x03\xbb\x70\x83\x7e\x5e\xcd\x29\xa0\x5f\xcc\xe5\x48\x4c\x83\x5d\xe2\xe3\x05\xea\xde\x31\x78\x62\x6f\xe6\xe6\xa2\xff\x42\xf4\x54\x03\xd2\x00\x00\xb1\xa5\x10\xbc\x4f\x30\xa1\x2f\x29\x7a\x5d\x27\xfd\xd0\xda\x6c\x4b\x06\x0a\x19\xb3\x70\xa3\x2c\x20\x7a\xab\xb3\x30\x6c\x3c\x6a\xba\x22\xe9\x14\x0b\xf4\x89\xc4\x17\xf2\xd2\xcf\x92\xc5\x2a\x56\x74\x03\x7e\x4e\x70\xec\xce\xce\xb2\x8b\xd9\x9a\x2d\xf5\x06\xad\x59\x48\xe8\x89\xb3\xd8\x01\x46\x3d\x76\x79\xea\x51\x36\x2c\xca\x32\xbb\xac\x13\x00\xca\x65\xd8\xb9\x3d\x27\xf1\xfd\x4b\xec\x04\x7a\xee\x0a\xfc\xdc\x62\x00\x89\x55\x1d\x9d\x01\x73\x37\xc0\xcf\x16\xa0\x1e\x15\xa3\xce\xd8\xa6\x38\x75\x02\x9a\xcc\x3d\x04\xe2\xeb\x2b\xdd\xd8\x19\x27\x39\xe6\x91\x00\x9e\xf5\x9a\x32\x86\xa1\x22\xc3\x40\x67\x7b\x2a\x4b\xc3\x5a\x77\x3a\x0c\x70\xde\x63\x56\x73\x81\x39\x89\x0f\x2c\xbf\x81\x35\x6f\x4f\x9d\x1a\x58\x40\x9f\xf5\x6d\xe3\x6e\x5a\xc5\xc9\xdd\x4e\x93\x26\x73\x95\x72\xac\xb1\x24\xeb\x2e\xcf\x4d\xc0\x9d\x65\x48\x1a\xe1\xdd\x6d\x51\x53\xd7\x94\xe6\x3d\x46\x8c\x1d\x9f\x9d\x38\x8c\x94\x58\x66\xd7\x83\x21\xc8\xbb\xfc\xec\xb1\x5b\xcc\x2d\x40\xee\x76\xc4\x3a\x14\xd8\xd8\x09\x65\x6f\xd9\xce\xa2\xe0\x8d\xa2\xb1\xdb\x11\xe3\x61\x4d\xe2\x51\x47\xc1\xce\x32\x0f\x62\x36\x22\xaf\xf0\xfb\x02\xbb\x70\x85\x32\x8e\x15\x75\x6f\xf5\x77\xa7\x88\x0f\x1b\x58\xf3\x9b\x90\xf3\x8b\x79\xca\xdc\x51\x97\x9f\xcd\xa1\xb7\xb2\x43\x02\x55\xf8\xd0\x27\x7f\x3b\x4e\x5a\x2b\x5b\xfa\x0d\xec\x76\xe0\xfd\xfa\x67\xb4\xa4\xbd\xde\xf7\xaa\x4f\x32\x19\xab\xb6\x15\x3b\x82\xbe\xd3\x56\x55\x46\x09\xc5\xa9\x13\x2a\xbc\x13\x28\x00\x06\x95\x0c\x37\xf5\xa5\x2a\xab\x09\x6c\x68\x11\x79\xb7\xa5\xa9\x43\xe6\x1d\x82\xbe\xec\x2b\x4d\xec\x77\xdf\x32\x2d\xec\x70\x4d\x73\x68\x8a\xb9\x6d\xd4\xc3\xaa\x9e\xde\x11\x63\x37\xe0\x29\x4b\xcf\x30\xd2\x8f\xf3\xa3\x33\x24\x3e\x97\xf0\x26\xb6\xe4\x92\xaf\x03\x3a\xb7\x5d\x57\x0f\x58\x12\xa3\x4d\x76\x74\xac\x92\x27\x90\xc8\xdc\xe2\xd9\x02\xe2\xd4\x11\x80\xe8\x84\x12\x35\x34\xea\xcf\x7b\xeb\xac\xe9\xe5\x2b\xa6\xd8\xd9\x60\x3f\x76\x17\xe4\x5d\x97\x03\x4f\x1c\x16\x31\x2c\x70\x2b\xb3\x43\xe3\xa5\x36\x34\x31\x89\xeb\x1d\xb5\xca\x01\xf1\xd4\x23\x60\xf8\xdc\x15\xc0\x44\x0e\x27\xac\x43\x62\x08\x61\x92\xb9\xa6\x84\xa1\x7f\x3c\xe6\xd8\xd4\xad\x2a\x36\xdb\xb0\x83\x23\x59\x97\x5a\x1a\x4d\x7c\x34\xdd\x2c\xf2\x27\x40\xc4\x56\x7b\x3c\x76\xdb\xec\xcc\x32\xea\x9a\x2d\xe0\xc0\xe5\x45\xb9\xb4\x4f\xec\x93\xac\xd3\xbc\x4e\x37\x9b\x32\xa5\xb3\x3a\x6e\x3c\xea\x3c\xe8\x6b\x3c\xab\x29\xba\xa4\x2a\xa0\xb0\xfd\x32\xd0\x5f\xfa\x3a\x05\x5a\xfa\x04\xe8\xe2\x2c\x6e\x16\x36\x14\xb3\x4d\xbd\x8d\x47\x32\xf5\x22\x92\xb1\x78\xf5\xb7\xac\x44\x6c\x7e\xe9\xfb\x74\x52\xbf\x2c\x3f\xe1\x65\x55\x97\xfa\x2a\x19\xc3\x76\x51\xb6\xa5\x51\x34\xf1\xf7\x05\x0f\xe2\x2c\x56\xf5\x76\x89\x63\x62\x07\x5f\xe7\xad\xf0\x51\xc7\xcd\x91\xa6\xb3\x6d\x45\xa3\x42\x91\x17\xe5\xe2\xf3\x11\x3f\xb1\x6d\x07\xab\x18\xf8\xe7\xda\xc2\x2a\x0e\xfe\x01\xf6\x90\x17\x65\x55\xa7\x9b\x0a\xa5\x3f\x2a\xe6\x18\x0f\x69\x89\xe0\x8a\x3a\x80\x5d\x12\x93\x7e\x9b\x4d\x33\x74\x8f\xe8\xcf\x5a\x7c\x57\xd9\x07\xdc\x6d\xef\xe0\xec\xf5\x1d\xdf\x04\x5a\xfb\x65\x54\x61\xab\xd2\x67\x4b\x6d\xbe\x05\x63\x6b\xf4\x44\xd9\xa4\xe8\x81\xd2\x5e\xfd\x6d\xd6\x6d\xc9\x54\x7f\x11\xdd\x49\x2d\x79\x51\xd1\x77\xfd\xad\xb9\x49\x2b\xda\x9a\xef\xac\xdb\x5f\x91\x76\xfc\xb5\xb9\x0a\x53\xe5\x27\x66\xf7\x47\xde\x55\xed\x33\x55\x7e\x9c\xcc\x2f\x9e\xfc\xb5\xcf\x61\xb4\x2c\xa3\xac\x70\x5f\xf2\xd7\x5c\xc7\xc8\x14\x1e\xf2\x61\xe4\x1d\xe9\x0b\xd7\x58\x94\x73\x63\x62\x7b\x94\xd8\x31\xc0\xd4\x35\x95\xc2\x56\xe9\x0c\x78\x1e\x68\x7d\xa6\xdf\x6a\x3c\xea\x01\x58\x94\x3e\x91\x1e\x3b\x1d\x77\x8c\xca\x1c\xeb\xd2\x06\xbe\xa4\xa6\x1c\x9b\x43\xa3\x4e\x59\x86\xc2\x21\x8d\xce\xc8\xbc\xc4\x56\x69\x1a\x32\x60\xde\x0b\x95\x31\x0c\x5c\xec\x36\xf6\xe6\x40\x49\xff\xab\xbc\x54\xa9\x6b\x6b\x39\xc2\x41\xeb\xa5\xa8\xb3\x85\x0f\x56\x2e\x63\x2e\xd5\x32\x94\xee\xd0\x54\x06\x50\x00\xb9\xce\x8c\x63\x2b\x54\x54\xbd\x51\xda\x32\x6d\xc2\x4b\x0a\x90\x64\x59\x97\xf8\x81\x2e\x72\x9a\x1c\xb7\x34\x1e\x68\xa0\x0d\x54\x93\x2a\x70\xd5\x94\x29\x69\x00\x48\xfc\xa5\x97\xf9\x47\x3d\x00\x13\x55\xe0\x29\xad\xd6\xc4\x0e\x96\x22\xdb\xb0\x28\x99\x79\xa1\xc9\xfc\x12\x7a\x3b\xf5\x37\xec\x9f\x3c\x11\x25\x0e\xaf\x74\x87\xd8\xae\xd5\xd8\x14\xf6\x89\x67\x25\x8d\x52\x2a\xfb\x54\x7c\x16\xf7\xe7\x85\xf7\xcd\x6d\xc7\x30\x78\xc8\x1c\x83\xcd\x6d\x53\x99\x42\xff\x75\xbe\x4a\xe6\x8e\x22\x05\x06\x8a\x0f\x1f\x0d\x1a\xe4\x45\x4e\x78\xc2\x07\x24\xee\x1c\x90\x58\xb4\xe3\x4e\x61\x90\x66\x0e\x53\x4f\x6d\xa3\x8e\x5f\xc7\x23\x7a\x34\xe8\xca\xa6\x01\x97\x9b\x6c\xae\xdd\x28\x01\x4e\x2d\x8d\x5a\xe6\xeb\xa4\x3a\x64\x8a\xfc\x63\x6c\xcd\xb7\x78\xd9\x67\x5f\xfe\x03\x6c\x92\x4c\xbd\x00\x9d\x56\x78\x1d\xb3\x9b\xbe\x91\x3b\x5c\x66\x1d\x73\x6b\xf6\xe8\x60\xfd\x12\xd7\x6b\xf3\xbc\xb5\xf6\x57\x7e\x4b\xfd\xa9\xf6\x84\xe0\x26\x76\x05\x76\xfe\xd1\xb1\x89\x2d\x14\x39\xe8\x4c\x2f\x73\x59\x84\xe7\x91\xab\xc5\xd3\x61\x10\xe3\x61\x4d\x19\xc1\xe7\x98\x19\x9a\xe2\xc8\x11\xd8\xd0\xac\xc9\xf7\x70\xd1\xa8\xe2\xd9\x29\xec\xc8\x53\xc7\xc0\xcf\x64\x0e\xe6\x30\x16\xd5\x63\xca\xf5\x4f\x82\xc9\x61\xb5\x06\x1a\x58\x53\x12\x5b\xad\xf4\x44\xc0\x79\x57\x28\x6c\xf4\xaa\x4f\xcb\xef\xc4\x66\x8f\x5d\x83\xcd\xe0\xbc\x39\x46\xa1\x84\x87\xe5\x1a\xc4\xc2\x32\x24\x52\x76\xd2\x15\xca\x75\x89\x22\xaf\x28\x48\x11\x0c\xd8\x1c\x19\xb2\xb7\xbd\xe6\xf2\x34\x6f\x4e\x9c\x59\xe4\x75\x3b\x4b\xbd\x35\x24\xca\xe1\x9a\xcb\xb5\x21\xdd\x13\x3b\xaf\xb9\x29\x58\xc5\x01\x72\x3c\x71\x98\x3a\x99\x4b\x13\xfd\xa8\x72\x74\x53\x57\x28\xd6\x02\xfe\xe0\x9e\xab\x7c\x1a\x89\x9f\x95\x31\xd1\x61\x18\xf6\xa7\x4e\xb0\xb2\xe7\x8f\x9c\x3f\x5e\x38\x02\xc0\x90\x6b\x2c\xfa\xad\xd4\x83\x01\xf0\x1d\x86\xa5\x1e\xd5\x46\xc0\x79\xff\xfc\xe7\xd5\xe7\xb3\xb7\x01\x9e\xde\xa3\xf5\xc1\xbb\xaf\xce\x3a\xa8\x13\x4d\x51\x12\x27\xd1\xd4\x5f\x6e\xe7\x19\xd9\x38\x45\x47\x4f\x15\xf9\x2e\x0a\xb3\xf2\xf8\xd1\xbe\x7b\x6d\x96\xbb\x94\xf4\x14\x25\x8d\x34\xf5\xbd\x10\xed\x3d\xc4\x94\xaf\xbd\xef\x96\x14\x8f\x6d\xae\x3a\xb4\xf7\xaf\x5f\x6e\xe1\x5f\x52\x98\xdf\xee\x27\xbb\xdc\xef\x57\x71\x7e\xf5\xf9\xf7\x62\x0b\xd2\xae\x80\xce\x3a\x1f\xf7\xa6\x1d\xa2\x27\x8f\xd1\x71\xe5\x99\xa6\xdb\xcd\x13\x53\x2a\xb4\x31\x52\x51\xf6\x1d\x0f\xd4\xd5\x3e\xfc\x40\xdd\xd6\xe6\xea\xf5\x4d\xd5\xfb\xef\x21\x7a\xcb\x86\xce\xd7\xcd\x9b\xef\x39\x9b\xb7\xb9\x7f\xef\xe0\xc8\xae\x0f\xe3\xeb\xde\xe0\x5d\xee\x8f\x1c\x87\x74\xc3\xd4\x8a\xc2\xe3\xf7\x46\x78\x38\x72\x6c\x7c\x72\x90\x1e\xae\xa9\xfa\x99\x77\x44\x9c\x3a\xea\xf7\xee\xeb\xa6\x0e\x1d\x6a\x2c\x5e\x8e\xec\xc0\xc7\xc4\x10\x5c\x36\x0e\x6c\x24\x5c\x89\x36\xdd\x7b\x47\xc5\xc5\x01\xab\x64\x6f\xdf\x2c\xb4\x52\xba\xd5\x3d\x6b\x9f\xae\x8e\xdf\xad\x76\xf5\x79\x53\x2b\x8f\xdc\x5c\xb4\xbb\x95\xfb\x94\xea\xaf\x13\xde\xbc\x58\xa8\x3c\x69\x08\x71\x7a\x16\x68\x1e\xd1\x1c\x90\xba\xb7\x05\x85\x0f\x52\xf6\xe5\xa5\x15\x7b\x50\x50\xb4\x52\x9e\x6c\x2c\x45\x77\xbc\xd7\x3b\x80\xbc\xbf\xa6\xa9\xbf\x01\x79\x10\x90\x47\x2f\x85\xfb\xa9\x78\x4c\xa7\xf0\x2f\x8d\xc7\xa5\xe4\x7e\x1e\x1c\xed\xf2\x98\x80\x1a\xdb\x47\x8e\x5a\x56\xa5\x4a\xc9\x9e\xba\x96\x90\xa6\xca\x1b\x22\x6f\x99\xbb\xb3\xaf\xc8\xdb\x87\xf7\xf2\x84\xd2\xf7\xbe\x30\x61\xa3\x6b\xc5\xfd\x96\x6b\xec\x9f\xba\x12\xa1\x74\x7d\x2a\x82\x79\xe2\x67\xf3\x02\x10\x1f\x78\x93\xc7\x3e\xf2\x55\x38\x10\xa6\xde\x47\x5f\xe5\x73\xea\x18\x6c\x09\xd5\x76\xe8\xc6\x91\x1f\x9e\xb8\x1f\xb1\x7a\xce\x3c\x31\x50\xa9\xc1\x5e\x9d\x3c\x77\xab\x7e\xa5\x87\x6f\x3b\xa8\x73\xf9\x7f\xcf\x9b\xc5\x9c\x71\x86\xe4\x34\x9f\xdf\x22\x8e\xe2\xf8\x44\x75\xcf\xe1\x2f\x23\x93\xa3\x25\x0e\xd7\x3f\xf3\x12\x90\xe5\xd1\xc9\x33\xa7\x81\x67\xdf\x02\x42\x22\xf7\xf3\x03\xdf\xad\xe8\xff\xe7\xdf\x9b\xf6\xb3\x6c\xfe\x1d\x31\x9a\xcc\x2f\x6b\xf3\x97\xec\xff\x75\x6d\x7e\x8c\x7e\x82\xd9\x8f\x13\x7f\x6a\x67\x2b\xb3\xbf\xe4\x73\x3d\x20\x6c\x95\x77\x7a\x1c\xb8\x2d\xed\x44\x1b\x1b\x57\xfa\xa0\xef\xa5\xd0\x31\x2a\x74\xfa\x9a\xda\x9d\xf9\xff\x27\xe9\x35\xc6\xd1\x0c\x6c\x70\x5d\xc6\xd7\x07\x4f\xab\x95\x55\xf8\x28\x99\xd9\x89\x8b\x5c\x2d\xb1\x47\x23\x1f\x9e\x28\x2e\xd8\x19\x9a\xd9\x73\x2d\xb1\xc3\xd4\xcf\xaa\xd4\xd9\xfe\x54\x97\x82\x82\x28\x43\xcb\x1a\xe9\x91\xb2\x49\x51\x70\x93\xf9\xc3\xb6\xe9\x3d\x47\xde\x5f\x95\xa8\x82\xc2\xde\xf3\xaf\xe7\xa5\xc2\x96\x4e\xe2\x36\x46\x28\xf1\x43\xef\xfa\x83\x30\xb6\xf5\x7d\x50\x52\xdf\x81\xde\x8f\xb9\x26\xea\xa3\xb3\x5a\x6f\x1f\x8f\xdf\xdf\xa7\x72\x7f\xab\xd2\x8f\x51\xa5\xe9\xa1\x8b\x22\xce\xd6\xa1\xb5\xc1\x5f\x57\xa5\x6f\x8a\xbf\x7e\x01\x1d\xda\xc2\xfc\x47\xa9\xd2\xde\xf1\xf8\x7e\x3a\x34\xf1\xc3\x02\x3b\x42\x91\xd4\x6d\x45\x30\x0f\x50\x98\xed\xcc\x4d\x4e\xea\x1a\x8c\xc2\xd4\x4f\x33\x14\xc2\xf9\xa9\x1b\xd9\x96\x57\x53\x73\xaf\x35\x7a\x68\x5a\x5e\x5f\xa1\x66\x49\xb4\x7e\xc3\xf3\x1e\xfe\x77\x64\xf0\xae\x40\xb3\xaa\x2c\x55\xa9\xa8\x33\x84\xb8\xc1\xd0\x6e\x18\xb3\x87\xc5\xad\xeb\xf5\x9f\x46\x23\x94\x54\xf7\x2e\x1d\xbb\x23\xcf\x8f\x15\x3b\xf4\x10\xef\xe3\xac\x3c\x7f\xbf\x5a\xb4\xa1\xa9\xbb\x9b\x3b\xe6\x86\x66\xeb\x37\x2c\xf3\xe5\x8e\xba\xf9\x7a\x7f\x53\xbf\xbb\xa1\x6b\xf4\x97\x3a\x73\x43\x7f\xbd\xbf\xb9\xbf\xa9\x51\xc5\xe7\x7b\xf6\xa6\x4e\xdd\xdc\xd5\x8b\x2f\x0f\x5f\x6f\xe8\x87\xbb\x1b\xe6\xfe\xea\xcb\x85\x3f\xfa\x84\xfe\xc8\x6d\x9c\x7e\xda\xc9\xe8\xad\xdd\xc0\x5f\xa4\xde\xca\x7f\xbe\x5c\x5c\x7d\xd9\x9b\x00\xdc\x28\xbe\x5f\x07\xfc\x74\xd3\x86\x95\x7d\x6a\x87\x65\xb0\x79\xd0\xb0\x6e\xea\xc6\xbb\x6f\xde\xfd\xa1\xb7\xea\x9c\x89\x89\x32\xd0\x7e\x44\xf3\xa6\x9d\x22\xb7\x8f\x32\x9b\xc0\xc4\x48\xfc\x0c\x6d\x78\xa7\xb3\xcc\xef\xe6\x9a\xcf\xee\xaf\x39\x9c\x95\x37\x7d\xd5\xfa\xdb\x2d\x12\xdf\x3d\x87\xba\xb4\x05\xed\x97\x18\x25\xfe\xf2\xa6\xb8\x4b\x2e\x4a\xd0\xc5\x27\x55\xee\x7d\x7e\x63\x4a\x95\xbd\xa6\x1e\x7e\x70\x04\xb5\x69\xa6\x3f\x20\x68\xa9\x98\x39\xe9\xec\xaf\x1a\xca\xd3\xd5\x3e\xbf\xbd\x6f\x9d\x3c\xce\x8e\xff\x5c\xca\xcb\x75\x90\x5e\x17\x17\xea\x5d\x67\xe3\x24\xca\xbd\x71\x9c\x17\xb9\xed\x3b\x8a\x7a\x6f\x68\xb0\x2f\xbd\xbf\x17\xa2\x5f\x2e\xae\x6e\x89\x58\x49\x87\xbe\x11\xaf\xb7\xe9\x1f\xb8\xb5\xfc\xdb\x77\x9c\xec\x7d\x1c\xca\x8e\xf4\x65\x6b\x61\x7e\xaf\xe8\x7e\x26\x02\x1b\xe9\x3c\x84\x4f\x31\xaa\x6e\x79\x3b\xb0\x64\x15\xdb\x49\xe6\x93\x12\xfb\x7e\x19\x62\xab\x64\x36\x3e\x9d\xe3\xbc\xbc\xf5\x8f\x64\x29\x0e\xfc\x20\xd3\xc5\x7a\xac\xd3\xb1\xd3\xf1\x01\x13\x7e\xa0\x0f\x4b\x33\xa5\x65\x24\x4a\xb9\xa7\xee\x1e\x28\xea\xad\x7a\xf7\x1d\x75\x86\x7c\xde\x1a\x8c\x0f\xd5\xa3\x5b\x18\x85\x99\xed\x87\xdf\xf5\x86\xe4\x1f\xa2\x52\x1b\xdd\x3a\x47\xbf\x0e\x59\xa5\x77\xb6\xff\x57\x57\xe9\xa6\x8f\xf1\xee\x8f\xc9\xbc\x36\xf3\x2b\xa9\xf2\x5f\x4c\x41\x97\xa2\xfd\x5b\x31\xff\x56\xcc\xb5\xf7\xe7\x2a\x66\x3f\x0a\xfd\x2c\xda\x19\xe6\xd7\x76\x7e\x25\xcd\x3c\xc7\xc9\x5e\xd3\x7f\x31\xfd\xad\x46\xe0\x6f\x05\xfe\x5b\x81\xd7\xde\x9f\xab\xc0\x4f\x31\x0a\xd5\xb1\x3f\xca\xb8\x6a\xf3\xda\x0f\xd3\xe4\x0d\x8a\x3f\x58\xa7\xf3\xd0\xff\x23\x47\x8f\xe8\x54\x52\x70\xb3\xf0\x87\xdc\x95\x79\x9e\x78\x56\xc5\x6f\x27\xc7\xa4\x53\x3d\x27\x2e\xda\x3f\xbe\x0c\xfb\x1d\x98\x5e\x6e\x85\x54\xd6\xed\x43\xd7\x3d\x3a\xd0\xd5\xf3\xd7\xeb\x8a\x8f\xc2\xec\x63\x98\x3f\x8c\xf2\x5f\x22\x56\xdc\x31\x16\x7f\x3b\x9d\xbf\x9d\xce\xda\xfb\x73\x9d\x8e\xba\xb6\x33\xf9\x3f\x23\x74\xfc\x8b\x29\xea\x86\x80\xff\x56\xd2\xff\x55\x4a\xba\x02\x8f\x97\xfb\xee\xce\xad\xad\xbe\xfb\xe5\xe2\x4a\x19\x5c\xdc\x5e\x28\xc8\x76\x51\x72\x16\x38\x1a\xcb\x1f\x1c\x2a\x46\xf0\x36\x89\x30\x2a\x4f\x83\x91\x9e\xed\xc0\xe0\x94\x91\x48\x61\x14\xef\x5f\xdb\xf4\xf7\x9f\x4d\x20\xed\xb5\xd0\xc8\x0f\x0b\x6b\xb0\xe7\x70\x83\xb2\x57\xf4\xbb\x4c\xbf\x12\x29\x56\x4b\x6c\xe8\xba\x5f\x19\xfb\xeb\x75\xad\xf6\x50\xbf\xbe\x7b\x40\xa3\x6b\xc7\xbd\x63\xae\x47\xf7\xd4\xfd\xc8\xb1\x1f\x68\x1b\x7d\x3d\xf4\x53\xef\x1b\x3f\x4b\xfc\xfe\x5f\x8c\xaf\x4a\xac\x16\x5f\xb7\x6a\xbe\x71\x9d\xe9\xe1\x9a\x62\xaf\x29\xfa\x3a\x4e\xd0\xd4\x47\xb3\x73\xd6\xd9\xcf\x40\x0b\x4f\xd0\xb2\x5c\x66\xba\xe0\xa2\xb0\xfc\x8d\xc5\xe8\x7f\x33\x74\xee\x5c\xf6\xab\xc3\x3e\x38\xd7\xb4\x7b\x37\xba\xbe\xfb\xfa\xf0\xf5\xda\x66\x58\xfa\x1a\xde\x7f\x7d\xa8\xdd\xb9\x0c\xcd\xbc\x0b\x3a\xfb\x7e\x97\xfd\x17\x80\xce\x5b\xbc\xd4\x21\x21\x5f\x7d\xb9\xd8\x40\xe0\xc7\x9a\xd1\xca\xe6\xbd\xd2\xb9\x58\x16\xd8\x04\xf4\xb7\x7a\xca\xe2\xcc\xaf\x8b\x92\xf4\xe3\x91\xfe\xd1\x7e\xe5\x07\x6a\x4b\xdd\x71\x59\xe8\x3e\x3c\x5c\x8f\xd0\x5d\xfd\xfa\x8e\xa1\xef\xaf\xd9\xda\x83\x73\x3d\x62\xbf\xde\xd5\xbe\x22\xba\x7e\x57\xa7\x7e\x6d\x43\xfb\xab\x2e\xb9\x1e\x55\xe1\xb5\x93\xba\xef\xd7\xdc\xed\x03\xbc\xdb\x3d\x59\x6b\xe4\x73\xe5\x6b\x5a\x92\x7a\x41\x0a\xbf\x5d\x37\xb7\x5b\xfb\x71\x0a\xf9\x96\x7e\xfe\x50\xe5\x73\xd0\x08\x8d\x6c\x8a\xbe\x66\x6c\x86\xbd\xbe\xa3\xd9\xaf\xd7\x0f\x35\xfb\xe1\x9a\xf9\xca\x8c\x46\xb5\x1a\x44\x35\xfa\xee\xd7\x76\x55\x1f\xba\xab\xe6\xbc\xf1\x3b\xa4\x68\xbf\x95\xdf\xff\xfc\xed\xff\x07\x00\x00\xff\xff\x56\x3c\x3b\x1d\x43\x8b\x00\x00") func rpProductionJsonBytes() ([]byte, error) { return bindataRead( diff --git a/pkg/deploy/generator/resources.go b/pkg/deploy/generator/resources.go index ef3b50c38..cabc7b7d5 100644 --- a/pkg/deploy/generator/resources.go +++ b/pkg/deploy/generator/resources.go @@ -1162,6 +1162,29 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]", }, }, + { + Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{ + SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{ + Resource: &mgmtdocumentdb.SQLContainerResource{ + ID: to.StringPtr("Billing"), + PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{ + Paths: &[]string{ + "/id", + }, + Kind: mgmtdocumentdb.PartitionKindHash, + }, + }, + Options: map[string]*string{}, + }, + Name: to.StringPtr("[concat(parameters('databaseAccountName'), '/', " + databaseName + ", '/Billing')]"), + Type: to.StringPtr("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"), + Location: to.StringPtr("[resourceGroup().location]"), + }, + APIVersion: apiVersions["documentdb"], + DependsOn: []string{ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]", + }, + }, { Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{ SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{ diff --git a/pkg/install/billing.go b/pkg/install/billing.go new file mode 100644 index 000000000..270280017 --- /dev/null +++ b/pkg/install/billing.go @@ -0,0 +1,30 @@ +package install + +// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0. + +import ( + "context" + "net/http" + + "github.com/Azure/ARO-RP/pkg/api" + "github.com/Azure/ARO-RP/pkg/database/cosmosdb" +) + +func (i *Installer) createBillingRecord(ctx context.Context) error { + _, err := i.billing.Create(ctx, &api.BillingDocument{ + ID: i.doc.ID, + Key: i.doc.Key, + ClusterResourceGroupIDKey: i.doc.ClusterResourceGroupIDKey, + Billing: &api.Billing{ + TenantID: i.doc.OpenShiftCluster.Properties.ServicePrincipalProfile.TenantID, + Location: i.doc.OpenShiftCluster.Location, + }, + }) + // If create return a conflict, this means row is already present in database + if err, ok := err.(*cosmosdb.Error); ok && err.StatusCode == http.StatusConflict { + return nil + } + + return err +} diff --git a/pkg/install/billing_test.go b/pkg/install/billing_test.go new file mode 100644 index 000000000..831f9eb1c --- /dev/null +++ b/pkg/install/billing_test.go @@ -0,0 +1,155 @@ +package install + +// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0. + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" + + "github.com/Azure/ARO-RP/pkg/api" + "github.com/Azure/ARO-RP/pkg/database/cosmosdb" + mock_database "github.com/Azure/ARO-RP/pkg/util/mocks/database" +) + +func TestCreateBillingEntry(t *testing.T) { + ctx := context.Background() + mockSubID := "11111111-1111-1111-1111-111111111111" + mockTenantID := mockSubID + location := "eastus" + // controller := gomock.NewController(t) + // defer controller.Finish() + // billing := mock_database.NewMockBilling(controller) + + type test struct { + name string + openshiftdoc *api.OpenShiftClusterDocument + mocks func(*test, *mock_database.MockBilling) + wantError error + } + + for _, tt := range []*test{ + { + name: "create a new billing entry", + openshiftdoc: &api.OpenShiftClusterDocument{ + Key: "11111111-1111-1111-1111-111111111111", + ClusterResourceGroupIDKey: fmt.Sprintf("/subscriptions/%s/resourcegroups/rgName", mockSubID), + ID: mockSubID, + OpenShiftCluster: &api.OpenShiftCluster{ + Properties: api.OpenShiftClusterProperties{ + ServicePrincipalProfile: api.ServicePrincipalProfile{ + TenantID: mockTenantID, + }, + }, + Location: location, + }, + }, + mocks: func(tt *test, billing *mock_database.MockBilling) { + billingDoc := &api.BillingDocument{ + Key: tt.openshiftdoc.Key, + ClusterResourceGroupIDKey: tt.openshiftdoc.ClusterResourceGroupIDKey, + ID: mockSubID, + Billing: &api.Billing{ + TenantID: tt.openshiftdoc.OpenShiftCluster.Properties.ServicePrincipalProfile.TenantID, + Location: tt.openshiftdoc.OpenShiftCluster.Location, + }, + } + + billing.EXPECT(). + Create(gomock.Any(), billingDoc). + Return(billingDoc, nil) + }, + }, + { + name: "error on create a new billing entry", + openshiftdoc: &api.OpenShiftClusterDocument{ + Key: "11111111-1111-1111-1111-111111111111", + ClusterResourceGroupIDKey: fmt.Sprintf("/subscriptions/%s/resourcegroups/rgName", mockSubID), + ID: mockSubID, + OpenShiftCluster: &api.OpenShiftCluster{ + Properties: api.OpenShiftClusterProperties{ + ServicePrincipalProfile: api.ServicePrincipalProfile{ + TenantID: mockTenantID, + }, + }, + Location: location, + }, + }, + mocks: func(tt *test, billing *mock_database.MockBilling) { + billingDoc := &api.BillingDocument{ + Key: tt.openshiftdoc.Key, + ClusterResourceGroupIDKey: tt.openshiftdoc.ClusterResourceGroupIDKey, + ID: mockSubID, + Billing: &api.Billing{ + TenantID: tt.openshiftdoc.OpenShiftCluster.Properties.ServicePrincipalProfile.TenantID, + Location: tt.openshiftdoc.OpenShiftCluster.Location, + }, + } + + billing.EXPECT(). + Create(gomock.Any(), billingDoc). + Return(nil, tt.wantError) + }, + wantError: fmt.Errorf("Error creating document"), + }, + { + name: "billing document already existing on DB on create", + openshiftdoc: &api.OpenShiftClusterDocument{ + Key: "11111111-1111-1111-1111-111111111111", + ClusterResourceGroupIDKey: fmt.Sprintf("/subscriptions/%s/resourcegroups/rgName", mockSubID), + ID: mockSubID, + OpenShiftCluster: &api.OpenShiftCluster{ + Properties: api.OpenShiftClusterProperties{ + ServicePrincipalProfile: api.ServicePrincipalProfile{ + TenantID: mockTenantID, + }, + }, + Location: location, + }, + }, + mocks: func(tt *test, billing *mock_database.MockBilling) { + billingDoc := &api.BillingDocument{ + Key: tt.openshiftdoc.Key, + ClusterResourceGroupIDKey: tt.openshiftdoc.ClusterResourceGroupIDKey, + ID: mockSubID, + Billing: &api.Billing{ + TenantID: tt.openshiftdoc.OpenShiftCluster.Properties.ServicePrincipalProfile.TenantID, + Location: tt.openshiftdoc.OpenShiftCluster.Location, + }, + } + + billing.EXPECT(). + Create(gomock.Any(), billingDoc). + Return(nil, &cosmosdb.Error{ + StatusCode: http.StatusConflict, + }) + }, + wantError: nil, + }, + } { + t.Run(tt.name, func(t *testing.T) { + controller := gomock.NewController(t) + defer controller.Finish() + billing := mock_database.NewMockBilling(controller) + + tt.mocks(tt, billing) + i := &Installer{ + log: logrus.NewEntry(logrus.StandardLogger()), + doc: tt.openshiftdoc, + billing: billing, + } + + err := i.createBillingRecord(ctx) + if err != nil { + if tt.wantError != err { + t.Errorf("Error want (%s), having (%s)", tt.wantError.Error(), err.Error()) + } + } + }) + } +} diff --git a/pkg/install/install.go b/pkg/install/install.go index c4bdc4d69..e7b1690c9 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -51,6 +51,7 @@ type Installer struct { log *logrus.Entry env env.Interface db database.OpenShiftClusters + billing database.Billing doc *api.OpenShiftClusterDocument cipher encryption.Cipher fpAuthorizer autorest.Authorizer @@ -84,7 +85,7 @@ type condition struct { } // NewInstaller creates a new Installer -func NewInstaller(ctx context.Context, log *logrus.Entry, env env.Interface, db database.OpenShiftClusters, doc *api.OpenShiftClusterDocument) (*Installer, error) { +func NewInstaller(ctx context.Context, log *logrus.Entry, env env.Interface, db database.OpenShiftClusters, billing database.Billing, doc *api.OpenShiftClusterDocument) (*Installer, error) { r, err := azure.ParseResourceID(doc.OpenShiftCluster.ID) if err != nil { return nil, err @@ -114,6 +115,7 @@ func NewInstaller(ctx context.Context, log *logrus.Entry, env env.Interface, db log: log, env: env, db: db, + billing: billing, cipher: cipher, doc: doc, fpAuthorizer: fpAuthorizer, @@ -142,6 +144,7 @@ func (i *Installer) Install(ctx context.Context, installConfig *installconfig.In action(func(ctx context.Context) error { return i.installStorage(ctx, installConfig, platformCreds, image) }), + action(i.createBillingRecord), action(i.installResources), action(i.createPrivateEndpoint), action(i.updateAPIIP), diff --git a/pkg/util/mocks/database/database.go b/pkg/util/mocks/database/database.go index 472bdf7e4..aa4e22e18 100644 --- a/pkg/util/mocks/database/database.go +++ b/pkg/util/mocks/database/database.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/Azure/ARO-RP/pkg/database (interfaces: AsyncOperations,OpenShiftClusters,Subscriptions) +// Source: github.com/Azure/ARO-RP/pkg/database (interfaces: AsyncOperations,Billing,OpenShiftClusters,Subscriptions) // Package mock_database is a generated GoMock package. package mock_database @@ -82,6 +82,74 @@ func (mr *MockAsyncOperationsMockRecorder) Patch(arg0, arg1, arg2 interface{}) * return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Patch", reflect.TypeOf((*MockAsyncOperations)(nil).Patch), arg0, arg1, arg2) } +// MockBilling is a mock of Billing interface +type MockBilling struct { + ctrl *gomock.Controller + recorder *MockBillingMockRecorder +} + +// MockBillingMockRecorder is the mock recorder for MockBilling +type MockBillingMockRecorder struct { + mock *MockBilling +} + +// NewMockBilling creates a new mock instance +func NewMockBilling(ctrl *gomock.Controller) *MockBilling { + mock := &MockBilling{ctrl: ctrl} + mock.recorder = &MockBillingMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockBilling) EXPECT() *MockBillingMockRecorder { + return m.recorder +} + +// Create mocks base method +func (m *MockBilling) Create(arg0 context.Context, arg1 *api.BillingDocument) (*api.BillingDocument, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", arg0, arg1) + ret0, _ := ret[0].(*api.BillingDocument) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create +func (mr *MockBillingMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockBilling)(nil).Create), arg0, arg1) +} + +// Get mocks base method +func (m *MockBilling) Get(arg0 context.Context, arg1 string) (*api.BillingDocument, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0, arg1) + ret0, _ := ret[0].(*api.BillingDocument) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get +func (mr *MockBillingMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockBilling)(nil).Get), arg0, arg1) +} + +// MarkForDeletion mocks base method +func (m *MockBilling) MarkForDeletion(arg0 context.Context, arg1 string) (*api.BillingDocument, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MarkForDeletion", arg0, arg1) + ret0, _ := ret[0].(*api.BillingDocument) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// MarkForDeletion indicates an expected call of MarkForDeletion +func (mr *MockBillingMockRecorder) MarkForDeletion(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarkForDeletion", reflect.TypeOf((*MockBilling)(nil).MarkForDeletion), arg0, arg1) +} + // MockOpenShiftClusters is a mock of OpenShiftClusters interface type MockOpenShiftClusters struct { ctrl *gomock.Controller