From 48434dfd466d5919bf127f0723498fd13b012975 Mon Sep 17 00:00:00 2001 From: Scott Date: Thu, 5 Aug 2021 10:27:27 +1000 Subject: [PATCH] Feature: Candle conversion & Candle validation (#716) * Remove old concept. Introduce new job types and candle scaling * Adds extra processing, commands * new concept for queued jobs. Jobs can pause. New commands to manage status * =End of day commit designing tables and implementing prerequisites further. * Adds postgres data history relations * Fixes table design for sqlite. Fixes all issues from merge * Fixes craziness of database design. Adds some functions to get related jobs * Fixes errors * Updates some documentation, manages prerequisite jobs a little better, adds rpc funcs * Fixes database design and adjust repo functions * Tests database relationship * Test coverage of new job functions * Finishes coverage of new functions * Commands and RPC coverage * New database modifications for new job types * Adds db support of new columns. Adds conversion validation. lint * command blurb changes * Allows websocket test to pass consistently * Fixes merge issue preventing datahistorymanager from starting via config * Minor fixes for different job type processing * Fixes rangeholder issue, fixes validation, does not address jobs not starting or wrong status * Fixes database tests, but at what cost. Fixes dhm tests * Fixes dhj completion issue. Adds prerequisite by nickname * Fixes validation processing. Adds db tests and validation * Fixes validation job processing range * Fixes trade sql. Reduces defaults. Validation processing and errors * Updates cli job commands. adds validation decimal. fix job validation * Expands run job handling and tests * Validation work * Fixes validation processing * candle relations. new job type. updating database design * Adds secondary exchange support. Sets stage for candle override * Re adds accidentally deleted relationship * Updates loading and saving candles to have relationship data when relevant * Now validates and replaces candle data appropriately * Fixes getting and setting datahistory data. Neatens DHM * Test coverage * Updates proto for new db types. New test coverage. Secondary exchange work * Investigation into never-ending validation jobs. Now that intervals are ruled out, now need to complete the job.... * Fixes issues with validation job completion. Fixes validation volume issue for secondary exchange * Adds candle warning support to the backtester * Fixes warnings * lint and begin docs * Documentation updates. Final testing changes * Minor fixes * docs, prerequisite checks, more testing * Fixes binance trade test. Rename err * Documentation fixes. Figure fixes * documentation update * Fixes remote PSQL tests * Fix binance mock test * Remove unnecessary JSON * regen proto * Some minor nit fixes * Var usage, query sorting, log improving, sql mirroring * Extra coverage * Experimental removal of m.jobs and mutex. Fix messaging * Fixes error * Lint fixes, command description improvements. More isRunning gates * description improvements * Lint * BUFF regenerate * Rough concept to fix insertions taking up long periods of time * New calculation for trade data. Adds batch saving This also adds an experimental request feature to shut down lingering requests. However, its uncertain whether or not this is having any impact. Initially thought it was the trades that was taking time and not SQL. Will investigate further * Removes experimental requester. Adds documentation. Fixes typo * rm unused error * re-adds more forgotten contributors * Now with proper commit count --- CONTRIBUTORS | 4 +- README.md | 8 +- backtester/data/kline/database/database.go | 6 + .../data/kline/database/database_test.go | 13 +- backtester/data/kline/kline.go | 22 +- .../eventhandlers/portfolio/portfolio.go | 60 +- backtester/eventtypes/kline/kline_types.go | 11 +- backtester/report/report.go | 13 + backtester/report/report_test.go | 10 +- backtester/report/report_types.go | 9 + backtester/report/tpl.gohtml | 11 +- cmd/documentation/documentation.go | 10 + .../engine_templates/datahistory_manager.tmpl | 121 +- cmd/gctcli/data_history.go | 484 +- config/config_types.go | 9 +- .../postgres.sql | 9 + .../sqlite3.sql | 11 + .../postgres.sql | 19 + .../sqlite3.sql | 27 + .../postgres.sql | 12 + .../20210709133512_candle_details/sqlite3.sql | 15 + database/models/postgres/boil_table_names.go | 46 +- database/models/postgres/candle.go | 569 +- database/models/postgres/candle_test.go | 321 +- database/models/postgres/datahistoryjob.go | 1620 +- .../models/postgres/datahistoryjob_test.go | 1507 +- .../models/postgres/datahistoryjobresult.go | 23 - database/models/postgres/exchange.go | 266 +- database/models/postgres/exchange_test.go | 328 + database/models/sqlite3/boil_suites_test.go | 38 +- database/models/sqlite3/boil_table_names.go | 48 +- database/models/sqlite3/candle.go | 569 +- database/models/sqlite3/candle_test.go | 322 +- database/models/sqlite3/datahistoryjob.go | 1593 +- .../models/sqlite3/datahistoryjob_test.go | 1507 +- .../models/sqlite3/datahistoryjobresult.go | 23 - database/models/sqlite3/exchange.go | 266 +- database/models/sqlite3/exchange_test.go | 328 + database/repository/candle/candle.go | 38 +- database/repository/candle/candle_test.go | 13 +- database/repository/candle/candle_types.go | 15 +- .../datahistoryjob/datahistoryjob.go | 900 +- .../datahistoryjob/datahistoryjob_test.go | 109 +- .../datahistoryjob/datahistoryjob_types.go | 58 +- .../datahistoryjobresult.go | 2 +- database/repository/trade/trade.go | 17 +- engine/datahistory_manager.go | 1214 +- engine/datahistory_manager.md | 121 +- engine/datahistory_manager_test.go | 1019 +- engine/datahistory_manager_types.go | 114 +- engine/rpcserver.go | 179 +- engine/rpcserver_test.go | 73 +- exchanges/binance/binance.go | 7 +- exchanges/binance/binance_test.go | 20 +- exchanges/kline/kline.go | 62 + exchanges/kline/kline_datastorage.go | 46 +- exchanges/kline/kline_test.go | 87 + exchanges/kline/kline_types.go | 33 +- exchanges/okgroup/okgroup_wrapper.go | 2 +- exchanges/request/request.go | 2 - exchanges/trade/trade.go | 3 + gctrpc/rpc.pb.go | 2346 +-- gctrpc/rpc.pb.gw.go | 199 +- gctrpc/rpc.proto | 64 +- gctrpc/rpc.swagger.json | 180 +- gctrpc/rpc_grpc.pb.go | 100 +- testdata/http_mock/binance/binance.json | 13600 ++++++++-------- 67 files changed, 21319 insertions(+), 9562 deletions(-) create mode 100644 database/migrations/20210617165159_datahistoryjob_relations/postgres.sql create mode 100644 database/migrations/20210617165159_datahistoryjob_relations/sqlite3.sql create mode 100644 database/migrations/20210630125121_datahistoryjob_conversions/postgres.sql create mode 100644 database/migrations/20210630125121_datahistoryjob_conversions/sqlite3.sql create mode 100644 database/migrations/20210709133512_candle_details/postgres.sql create mode 100644 database/migrations/20210709133512_candle_details/sqlite3.sql diff --git a/CONTRIBUTORS b/CONTRIBUTORS index fb32de0cda3..00c57953029 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -14,6 +14,7 @@ vadimzhukck | https://github.com/vadimzhukck 140am | https://github.com/140am marcofranssen | https://github.com/marcofranssen dackroyd | https://github.com/dackroyd +ydm | https://github.com/ydm cranktakular | https://github.com/cranktakular woshidama323 | https://github.com/woshidama323 crackcomm | https://github.com/crackcomm @@ -21,6 +22,7 @@ azhang | https://github.com/azhang andreygrehov | https://github.com/andreygrehov bretep | https://github.com/bretep Christian-Achilli | https://github.com/Christian-Achilli +lrascao | https://github.com/lrascao MarkDzulko | https://github.com/MarkDzulko yangrq1018 | https://github.com/yangrq1018 gam-phon | https://github.com/gam-phon @@ -28,9 +30,9 @@ cornelk | https://github.com/cornelk if1live | https://github.com/if1live lozdog245 | https://github.com/lozdog245 soxipy | https://github.com/soxipy +tk42 | https://github.com/tk42 mshogin | https://github.com/mshogin herenow | https://github.com/herenow -tk42 | https://github.com/tk42 daniel-cohen | https://github.com/daniel-cohen DirectX | https://github.com/DirectX frankzougc | https://github.com/frankzougc diff --git a/README.md b/README.md index f65bb785d74..c19280769fe 100644 --- a/README.md +++ b/README.md @@ -143,8 +143,8 @@ Binaries will be published once the codebase reaches a stable condition. |User|Contribution Amount| |--|--| | [thrasher-](https://github.com/thrasher-) | 656 | -| [shazbert](https://github.com/shazbert) | 209 | -| [gloriousCode](https://github.com/gloriousCode) | 184 | +| [shazbert](https://github.com/shazbert) | 212 | +| [gloriousCode](https://github.com/gloriousCode) | 186 | | [dependabot-preview[bot]](https://github.com/apps/dependabot-preview) | 88 | | [xtda](https://github.com/xtda) | 47 | | [dependabot[bot]](https://github.com/apps/dependabot) | 18 | @@ -156,6 +156,7 @@ Binaries will be published once the codebase reaches a stable condition. | [140am](https://github.com/140am) | 8 | | [marcofranssen](https://github.com/marcofranssen) | 8 | | [dackroyd](https://github.com/dackroyd) | 5 | +| [ydm](https://github.com/ydm) | 5 | | [cranktakular](https://github.com/cranktakular) | 5 | | [woshidama323](https://github.com/woshidama323) | 3 | | [crackcomm](https://github.com/crackcomm) | 3 | @@ -163,6 +164,7 @@ Binaries will be published once the codebase reaches a stable condition. | [andreygrehov](https://github.com/andreygrehov) | 2 | | [bretep](https://github.com/bretep) | 2 | | [Christian-Achilli](https://github.com/Christian-Achilli) | 2 | +| [lrascao](https://github.com/lrascao) | 2 | | [MarkDzulko](https://github.com/MarkDzulko) | 2 | | [yangrq1018](https://github.com/yangrq1018) | 2 | | [gam-phon](https://github.com/gam-phon) | 2 | @@ -170,9 +172,9 @@ Binaries will be published once the codebase reaches a stable condition. | [if1live](https://github.com/if1live) | 2 | | [lozdog245](https://github.com/lozdog245) | 2 | | [soxipy](https://github.com/soxipy) | 2 | +| [tk42](https://github.com/tk42) | 2 | | [mshogin](https://github.com/mshogin) | 2 | | [herenow](https://github.com/herenow) | 2 | -| [tk42](https://github.com/tk42) | 2 | | [daniel-cohen](https://github.com/daniel-cohen) | 1 | | [DirectX](https://github.com/DirectX) | 1 | | [frankzougc](https://github.com/frankzougc) | 1 | diff --git a/backtester/data/kline/database/database.go b/backtester/data/kline/database/database.go index 98cf0b2d6a1..98c8440d4e3 100644 --- a/backtester/data/kline/database/database.go +++ b/backtester/data/kline/database/database.go @@ -11,6 +11,7 @@ import ( "github.com/thrasher-corp/gocryptotrader/exchanges/asset" gctkline "github.com/thrasher-corp/gocryptotrader/exchanges/kline" "github.com/thrasher-corp/gocryptotrader/exchanges/trade" + "github.com/thrasher-corp/gocryptotrader/log" ) // LoadData retrieves data from an existing database using GoCryptoTrader's database handling implementation @@ -29,6 +30,11 @@ func LoadData(startDate, endDate time.Time, interval time.Duration, exchangeName return nil, fmt.Errorf("could not retrieve database candle data for %v %v %v, %v", exchangeName, a, fPair, err) } resp.Item = klineItem + for i := range klineItem.Candles { + if klineItem.Candles[i].ValidationIssues != "" { + log.Warnf(log.BackTester, "candle validation issue for %v %v %v: %v", klineItem.Exchange, klineItem.Asset, klineItem.Pair, klineItem.Candles[i].ValidationIssues) + } + } case common.DataTrade: trades, err := trade.GetTradesInRange( exchangeName, diff --git a/backtester/data/kline/database/database_test.go b/backtester/data/kline/database/database_test.go index 85f2732e632..a7311ce343d 100644 --- a/backtester/data/kline/database/database_test.go +++ b/backtester/data/kline/database/database_test.go @@ -110,12 +110,13 @@ func TestLoadDataCandles(t *testing.T) { Interval: gctkline.FifteenMin, Candles: []gctkline.Candle{ { - Time: dInsert, - Open: 1337, - High: 1337, - Low: 1337, - Close: 1337, - Volume: 1337, + Time: dInsert, + Open: 1337, + High: 1337, + Low: 1337, + Close: 1337, + Volume: 1337, + ValidationIssues: "hello world", }, }, } diff --git a/backtester/data/kline/kline.go b/backtester/data/kline/kline.go index 097a66e967e..fc9b025eb5a 100644 --- a/backtester/data/kline/kline.go +++ b/backtester/data/kline/kline.go @@ -37,11 +37,12 @@ func (d *DataFromKline) Load() error { CurrencyPair: d.Item.Pair, AssetType: d.Item.Asset, }, - Open: d.Item.Candles[i].Open, - High: d.Item.Candles[i].High, - Low: d.Item.Candles[i].Low, - Close: d.Item.Candles[i].Close, - Volume: d.Item.Candles[i].Volume, + Open: d.Item.Candles[i].Open, + High: d.Item.Candles[i].High, + Low: d.Item.Candles[i].Low, + Close: d.Item.Candles[i].Close, + Volume: d.Item.Candles[i].Volume, + ValidationIssues: d.Item.Candles[i].ValidationIssues, } d.addedTimes[d.Item.Candles[i].Time] = true } @@ -75,11 +76,12 @@ func (d *DataFromKline) Append(ki *gctkline.Item) { CurrencyPair: ki.Pair, AssetType: ki.Asset, }, - Open: gctCandles[i].Open, - High: gctCandles[i].High, - Low: gctCandles[i].Low, - Close: gctCandles[i].Close, - Volume: gctCandles[i].Volume, + Open: gctCandles[i].Open, + High: gctCandles[i].High, + Low: gctCandles[i].Low, + Close: gctCandles[i].Close, + Volume: gctCandles[i].Volume, + ValidationIssues: gctCandles[i].ValidationIssues, }) candleTimes = append(candleTimes, gctCandles[i].Time) } diff --git a/backtester/eventhandlers/portfolio/portfolio.go b/backtester/eventhandlers/portfolio/portfolio.go index 635009bbad9..0a2cada0167 100644 --- a/backtester/eventhandlers/portfolio/portfolio.go +++ b/backtester/eventhandlers/portfolio/portfolio.go @@ -50,8 +50,8 @@ func (p *Portfolio) Reset() { // on buy/sell, the portfolio manager will size the order and assess the risk of the order // if successful, it will pass on an order.Order to be used by the exchange event handler to place an order based on // the portfolio manager's recommendations -func (p *Portfolio) OnSignal(signal signal.Event, cs *exchange.Settings) (*order.Order, error) { - if signal == nil || cs == nil { +func (p *Portfolio) OnSignal(s signal.Event, cs *exchange.Settings) (*order.Order, error) { + if s == nil || cs == nil { return nil, common.ErrNilArguments } if p.sizeManager == nil { @@ -63,69 +63,69 @@ func (p *Portfolio) OnSignal(signal signal.Event, cs *exchange.Settings) (*order o := &order.Order{ Base: event.Base{ - Offset: signal.GetOffset(), - Exchange: signal.GetExchange(), - Time: signal.GetTime(), - CurrencyPair: signal.Pair(), - AssetType: signal.GetAssetType(), - Interval: signal.GetInterval(), - Reason: signal.GetReason(), + Offset: s.GetOffset(), + Exchange: s.GetExchange(), + Time: s.GetTime(), + CurrencyPair: s.Pair(), + AssetType: s.GetAssetType(), + Interval: s.GetInterval(), + Reason: s.GetReason(), }, - Direction: signal.GetDirection(), + Direction: s.GetDirection(), } - if signal.GetDirection() == "" { + if s.GetDirection() == "" { return o, errInvalidDirection } - lookup := p.exchangeAssetPairSettings[signal.GetExchange()][signal.GetAssetType()][signal.Pair()] + lookup := p.exchangeAssetPairSettings[s.GetExchange()][s.GetAssetType()][s.Pair()] if lookup == nil { return nil, fmt.Errorf("%w for %v %v %v", errNoPortfolioSettings, - signal.GetExchange(), - signal.GetAssetType(), - signal.Pair()) + s.GetExchange(), + s.GetAssetType(), + s.Pair()) } prevHolding := lookup.GetLatestHoldings() if p.iteration == 0 { prevHolding.InitialFunds = lookup.InitialFunds prevHolding.RemainingFunds = lookup.InitialFunds - prevHolding.Exchange = signal.GetExchange() - prevHolding.Pair = signal.Pair() - prevHolding.Asset = signal.GetAssetType() - prevHolding.Timestamp = signal.GetTime() + prevHolding.Exchange = s.GetExchange() + prevHolding.Pair = s.Pair() + prevHolding.Asset = s.GetAssetType() + prevHolding.Timestamp = s.GetTime() } p.iteration++ - if signal.GetDirection() == common.DoNothing || signal.GetDirection() == common.MissingData || signal.GetDirection() == "" { + if s.GetDirection() == common.DoNothing || s.GetDirection() == common.MissingData || s.GetDirection() == "" { return o, nil } - if signal.GetDirection() == gctorder.Sell && prevHolding.PositionsSize == 0 { + if s.GetDirection() == gctorder.Sell && prevHolding.PositionsSize == 0 { o.AppendReason("no holdings to sell") o.SetDirection(common.CouldNotSell) - signal.SetDirection(o.Direction) + s.SetDirection(o.Direction) return o, nil } // for simplicity, the backtester will round to 8 decimal places remainingFundsRounded := math.Floor(prevHolding.RemainingFunds*100000000) / 100000000 - if signal.GetDirection() == gctorder.Buy && remainingFundsRounded <= 0 { + if s.GetDirection() == gctorder.Buy && remainingFundsRounded <= 0 { o.AppendReason("not enough funds to buy") o.SetDirection(common.CouldNotBuy) - signal.SetDirection(o.Direction) + s.SetDirection(o.Direction) return o, nil } - o.Price = signal.GetPrice() + o.Price = s.GetPrice() o.OrderType = gctorder.Market - o.BuyLimit = signal.GetBuyLimit() - o.SellLimit = signal.GetSellLimit() + o.BuyLimit = s.GetBuyLimit() + o.SellLimit = s.GetSellLimit() sizingFunds := prevHolding.RemainingFunds - if signal.GetDirection() == gctorder.Sell { + if s.GetDirection() == gctorder.Sell { sizingFunds = prevHolding.PositionsSize } - sizedOrder := p.sizeOrder(signal, cs, o, sizingFunds) + sizedOrder := p.sizeOrder(s, cs, o, sizingFunds) o.Funds = sizingFunds sizedAmountRounded := math.Floor(sizedOrder.Amount*100000000) / 100000000 if sizedAmountRounded <= 0 { @@ -138,7 +138,7 @@ func (p *Portfolio) OnSignal(signal signal.Event, cs *exchange.Settings) (*order return o, nil } - return p.evaluateOrder(signal, o, sizedOrder) + return p.evaluateOrder(s, o, sizedOrder) } func (p *Portfolio) evaluateOrder(d common.Directioner, originalOrderSignal, sizedOrder *order.Order) (*order.Order, error) { diff --git a/backtester/eventtypes/kline/kline_types.go b/backtester/eventtypes/kline/kline_types.go index 5734b579ca7..97f9e7ce1ea 100644 --- a/backtester/eventtypes/kline/kline_types.go +++ b/backtester/eventtypes/kline/kline_types.go @@ -8,9 +8,10 @@ import ( // a common.DataEventHandler type type Kline struct { event.Base - Open float64 - Close float64 - Low float64 - High float64 - Volume float64 + Open float64 + Close float64 + Low float64 + High float64 + Volume float64 + ValidationIssues string } diff --git a/backtester/report/report.go b/backtester/report/report.go index 006996d90cc..23f910d8da1 100644 --- a/backtester/report/report.go +++ b/backtester/report/report.go @@ -23,6 +23,19 @@ func (d *Data) GenerateReport() error { return err } + for i := range d.OriginalCandles { + for j := range d.OriginalCandles[i].Candles { + if d.OriginalCandles[i].Candles[j].ValidationIssues == "" { + continue + } + d.Warnings = append(d.Warnings, Warning{ + Exchange: d.OriginalCandles[i].Exchange, + Asset: d.OriginalCandles[i].Asset, + Pair: d.OriginalCandles[i].Pair, + Message: fmt.Sprintf("candle data %v", d.OriginalCandles[i].Candles[j].ValidationIssues), + }) + } + } for i := range d.EnhancedCandles { if len(d.EnhancedCandles[i].Candles) >= maxChartLimit { d.EnhancedCandles[i].IsOverLimit = true diff --git a/backtester/report/report_test.go b/backtester/report/report_test.go index 7287acd0be2..dae21fc5726 100644 --- a/backtester/report/report_test.go +++ b/backtester/report/report_test.go @@ -37,7 +37,15 @@ func TestGenerateReport(t *testing.T) { OriginalCandles: []*gctkline.Item{ { Candles: []gctkline.Candle{ - {}, + { + Time: time.Now(), + Open: 1337, + High: 1337, + Low: 1337, + Close: 1337, + Volume: 1337, + ValidationIssues: "hello world!", + }, }, }, }, diff --git a/backtester/report/report_types.go b/backtester/report/report_types.go index 72bc7881f60..07d5810057c 100644 --- a/backtester/report/report_types.go +++ b/backtester/report/report_types.go @@ -33,6 +33,15 @@ type Data struct { Config *config.Config TemplatePath string OutputPath string + Warnings []Warning +} + +// Warning holds any candle warnings +type Warning struct { + Exchange string + Asset asset.Item + Pair currency.Pair + Message string } // DetailedKline enhances kline details for the purpose of rich reporting results diff --git a/backtester/report/tpl.gohtml b/backtester/report/tpl.gohtml index 24bb093f598..36e8462a57b 100644 --- a/backtester/report/tpl.gohtml +++ b/backtester/report/tpl.gohtml @@ -278,6 +278,15 @@ {{end}} {{end}} + {{ range .Warnings}} + + {{.Exchange}} + {{.Asset}} + {{.Pair.Base}} + {{.Pair.Quote}} + {{.Message}} + + {{end}} @@ -742,7 +751,7 @@ ${{ printf "%f" $ev.SignalEvent.Price}} {{$pair.Quote}} {{$ev.SignalEvent.GetDirection}} {{$ev.SignalEvent.GetReason}} - {{ end }} + {{ end }} ${{printf "%.8f" $ev.Holdings.CommittedFunds}} {{$pair.Quote}} {{end}} diff --git a/cmd/documentation/documentation.go b/cmd/documentation/documentation.go index 202358342c9..c0ff5cd0aa9 100644 --- a/cmd/documentation/documentation.go +++ b/cmd/documentation/documentation.go @@ -175,6 +175,16 @@ func main() { URL: "https://github.com/tk42", Contributions: 2, }, + { + Login: "mshogin", + URL: "https://github.com/mshogin", + Contributions: 2, + }, + { + Login: "herenow", + URL: "https://github.com/herenow", + Contributions: 2, + }, { Login: "daniel-cohen", URL: "https://github.com/daniel-cohen", diff --git a/cmd/documentation/engine_templates/datahistory_manager.tmpl b/cmd/documentation/engine_templates/datahistory_manager.tmpl index 3942f45b4a3..e2016288252 100644 --- a/cmd/documentation/engine_templates/datahistory_manager.tmpl +++ b/cmd/documentation/engine_templates/datahistory_manager.tmpl @@ -1,6 +1,6 @@ {{define "engine datahistory_manager" -}} {{template "header" .}} -## Current Features for {{.CapitalName}} +## What is the data history manager? + The data history manager is an engine subsystem responsible for ensuring that the candle/trade history in the range you define is synchronised to your database + It is a long running synchronisation task designed to not overwhelm resources and ensure that all data requested is accounted for and saved to the database + The data history manager is disabled by default and requires a database connection to function @@ -11,7 +11,19 @@ + Jobs will fetch data at sizes you request (which can cater to hardware limitations such as low RAM) + Jobs are completed once all data has been fetched/attempted to be fetched in the time range -## What are the prerequisites? +## Current Features for the data history manager ++ Retrieval and storage of exchange API candle data ++ Retrieval and storage of exchange API trade data ++ Conversion of stored trade data into custom candle data ++ Conversion of stored candle data into custom candle data ++ Validation of stored candle data against exchange API data + + Optionally can replace data when an issue is found on a customisable threshold ++ Validation of stored candle data against a secondary exchange's API data ++ Pausing and unpause jobs ++ Queue jobs via prerequisite jobs ++ GRPC command support for creating/modifying/checking jobs + +## What are the requirements for the data history manager? + Ensure you have a database setup, you can read about that [here](/database) + Ensure you have run dbmigrate under `/cmd/dbmigrate` via `dbmigrate -command=up`, you can read about that [here](/database#create-and-run-migrations) + Ensure you have seeded exchanges to the database via the application dbseed under `/cmd/dbseed`, you can read about it [here](/cmd/dbseed) @@ -20,9 +32,28 @@ + Read below on how to enable the data history manager and add data history jobs ## What is a data history job? -A job is a set of parameters which will allow GoCryptoTrader to periodically retrieve historical data. Its purpose is to break up the process of retrieving large sets of data for multiple currencies and exchanges into more manageable chunks in a "set and forget" style. +A job is a set of parameters which will allow GoCryptoTrader to periodically retrieve, convert or validate historical data. Its purpose is to break up the process of retrieving large sets of data for multiple currencies and exchanges into more manageable chunks in a "set and forget" style. For a breakdown of what a job consists of and what each parameter does, please review the database tables and the cycle details below. +### What kind of data jobs are there? +A breakdown of each type is under the Add Jobs command list below + +### What are the different job status types? + +| Job Status | Description | Representative value | +| ---------- | ----------- | -------------------- | +| active | A job that is ready to processed | 0 | +| failed | The job has failed to retrieve/covert/validate the data you have specified. See the associated data history job results to understand why | 1 | +| complete | The job has successfully retrieved/converted/validated all data you have specified | 2 | +| removed | The job has been deleted. No data is removed, but the job can no longer be processed | 3 | +| missing data | The job is complete, however there is some missing data. See the associated data history job results to understand why | 4 | +| paused | The job has been paused and will not be processed. Either it has a prerequisite job that needs to be completed, or a user must unpause the job | 5 | + +### How do I add a job? ++ First ensure that the data history monitor is enabled, you can do this via the config (see table `dataHistoryManager` under Config parameters below), via run time parameter (see table Application run time parameters below) or via the RPC command `enablesubsystem --subsystemname="data_history_manager"` ++ The simplest way of adding a new data history job is via the GCTCLI under `/cmd/gctcli`. + + Modify the following example command to your needs: `.\gctcli.exe datahistory addjob savecandles --nickname=binance-spot-bnb-btc-1h-candles --exchange=binance --asset=spot --pair=BNB-BTC --interval=3600 --start_date="2020-06-02 12:00:00" --end_date="2020-12-02 12:00:00" --request_size_limit=10 --max_retry_attempts=3 --batch_size=3` + ## What happens during a data history cycle? + Once the checkInterval ticker timer has finished, the data history manager will process all jobs considered `active`. + A job's start and end time is broken down into intervals defined by the `interval` variable of a job. For a job beginning `2020-01-01` to `2020-01-02` with an interval of one hour will create 24 chunks to retrieve @@ -35,45 +66,75 @@ For a breakdown of what a job consists of and what each parameter does, please r + The errors for retrieval failures are stored in the database, allowing you to understand why a certain chunk of time is unavailable (eg exchange downtime and missing data) + All results are saved to the database, the data history manager will analyse all results and ready jobs for the next round of processing -## How do I add one? -+ First ensure that the data history monitor is enabled, you can do this via the config (see table `dataHistoryManager` under Config parameters below), via run time parameter (see table Application run time parameters below) or via the RPC command `enablesubsystem --subsystemname="data_history_manager"` -+ The simplest way of adding a new data history job is via the GCTCLI under `/cmd/gctcli`. - + Modify the following example command to your needs: `.\gctcli.exe datahistory upsertjob --nickname=binance-spot-bnb-btc-1h-candles --exchange=binance --asset=spot --pair=BNB-BTC --interval=3600 --start_date="2020-06-02 12:00:00" --end_date="2020-12-02 12:00:00" --request_size_limit=10 --data_type=0 --max_retry_attempts=3 --batch_size=3` - ### Candle intervals and trade fetching + A candle interval is required for a job, even when fetching trade data. This is to appropriately break down requests into time interval chunks. However, it is restricted to only a small range of times. This is to prevent fetching issues as fetching trades over a period of days or weeks will take a significant amount of time. When setting a job to fetch trades, the allowable range is less than 4 hours and greater than 10 minutes. -### Application run time parameters +## Job queuing and prerequisite jobs +You can add jobs which will be paused by default by using the `prerequisite` subcommand containing the associated job nickname. The prerequisite job will be checked to ensure it exists and has not yet completed and add the relationship. ++ Once you have set a prerequisite job, when the prerequisite job status is set to `complete`, the data history manager will search for any jobs which are pending its completion and update their status to `active`. ++ If the prerequisite job is deleted or fails, the upcoming job will _not_ be run. ++ Multiple jobs can use the same prerequisite job, but a job cannot have multiple prerequisites + + Attempting to add a new prerequisite will overwrite the existing prerequisite ++ You can chain many queued jobs together allowing for automated and large scale data retrieval projects. For example: + +| Job Type | Job Name | Description | Prerequisite Job | +| -------- | -------- | ----------- | ---------------- | +| savetrades | save-trades | Save jobs between 01-01-2021 and 01-02-2021 | | +| converttrades | convert-trades | Convert trades to 5m candles | save-trades | +| validatecandles | validate-candles | Ensure the converted trades match the exchange's API data | convert-trades | +| convertcandles | convert-candles-10m | Now that we have confidence in conversion, convert candle to 10m | validate-candles | +| convertcandles | convert-candles-25m | Now that we have confidence in conversion, convert candle to 25m | validate-candles | +| convertcandles | convert-candles-1d | Now that we have confidence in conversion, convert candle to 1d | validate-candles | + +## Application run time parameters | Parameter | Description | Example | | ------ | ----------- | ------- | | datahistorymanager | A boolean value which determines if the data history manager is enabled. Defaults to `false` | `-datahistorymanager=true` | -### Config parameters -#### dataHistoryManager +## Config parameters +### dataHistoryManager | Config | Description | Example | | ------ | ----------- | ------- | | enabled | If enabled will run the data history manager on startup | `true` | | checkInterval | A golang `time.Duration` interval of when to attempt to fetch all active jobs' data | `15000000000` | | maxJobsPerCycle | Allows you to control how many jobs are processed after the `checkInterval` timer finishes. Useful if you have many jobs, but don't wish to constantly be retrieving data | `5` | +| maxResultInsertions | When saving candle/trade results, loop it in batches of this number. | `10000` | | verbose | Displays some extra logs to your logging output to help debug | `false` | -### RPC commands +## RPC commands The below table is a summary of commands. For more details, view the commands in `/cmd/gctcli` or `/gctrpc/rpc.swagger.json` | Command | Description | | ------ | ----------- | -| UpsertDataHistoryJob | Updates or Inserts a job to the manager and database | +| AddJob | Shows a list of subcommands to add a new job type, detailed in the next table | | GetDataHistoryJobDetails | Returns a job's details via its nickname or ID. Can optionally return an array of all run results | | GetActiveDataHistoryJobs | Will return all jobs that have an `active` status | | DeleteJob | Will remove a job for processing. Data is preserved in the database for later reference | | GetDataHistoryJobsBetween | Returns all jobs, of all status types between the dates provided | | GetDataHistoryJobSummary | Will return an executive summary of the progress of your job by nickname | +| PauseDataHistoryJob | Will set a job's status to paused | +| UnpauseDataHistoryJob | Will se a job's status to `active` | + +### AddJob commands + +| Command | Description | DataHistoryJobDataType | +| ------- | ----------- | ---------------------- | +| savecandles | Will fetch candle data from an exchange and save it to the database | 0 | +| savetrades | Will fetch trade data from an exchange and save it to the database | 1 | +| converttrades | Convert trades saved to the database to any candle resolution eg 30min | 2 | +| convertcandles | Convert candles saved to the database to a new resolution eg 1min -> 5min | 3 | +| validatecandles | Will compare database candle data with API candle data - useful for validating converted trades and candles | 4 | +| secondaryvalidatecandles | Will compare database candle data with a different exchange's API candle data | 5 | + -### Database tables -#### datahistoryjob +## Database tables +The following is a screenshot of the relationship between relevant data history job tables +![image](https://user-images.githubusercontent.com/9261323/125889821-954b730a-01fd-4eb0-839d-3cc623178f20.png) + +### datahistoryjob | Field | Description | Example | | ------ | ----------- | ------- | @@ -86,14 +147,20 @@ The below table is a summary of commands. For more details, view the commands in | start_time | When to begin fetching data | `01-01-2017T13:33:37Z` | | end_time | When to finish fetching data | `01-01-2018T13:33:37Z` | | interval | A golang `time.Duration` representation of the candle interval to use. | `30000000000` | -| data_type | The data type to fetch. `0` is candles and `1` is trades | `0` | +| data_type | The data type to fetch. See job types in table `AddJob commands` above | `0` | | request_size | The number of candles to fetch. eg if `500`, the data history manager will break up the request into the appropriate timeframe to ensure the data history run interval will fetch 500 candles to save to the database | `500` | | max_retries | For an interval period, the amount of attempts the data history manager is allowed to attempt to fetch data before moving onto the next period. This can be useful for determining whether the exchange is missing the data in that time period or, if just one failure of three, just means that the data history manager couldn't finish one request | `3` | | batch_count | The number of requests to make when processing a job | `3` | -| status | A numerical representation for the status. `0` is active, `1` is failed `2` is complete, `3` is removed and `4` is missing data | `0` | +| status | A numerical representation for the status. See data history job status subsection | `0` | | created | The date the job was created. | `2020-01-01T13:33:37Z` | +| conversion_interval | When converting data as a job, this determines the resulting interval | `86400000000000` | +| overwrite_data | If data already exists, the setting allows you to overwrite it | `true` | +| secondary_exchange_id | For a `secondaryvalidatecandles` job, the exchange id of the exchange to compare data to. | `ftx` | +| decimal_place_comparison | When validating API candles, this will round the data to the supplied decimal point to check for equality | `3` | +| replace_on_issue | When there is an issue validating candles for a `validatecandles` job, the API data will overwrite the existing candle data | `false` | + +### datahistoryjobresult -#### datahistoryjobresult | Field | Description | Example | | ------ | ----------- | ------- | | id | Unique ID of the job status | `deadbeef-dead-beef-dead-beef13371337` | @@ -104,6 +171,24 @@ The below table is a summary of commands. For more details, view the commands in | interval_end_time | The end date of the period fetched | `2020-01-02T13:33:37Z` | | run_time | The time the job was ran | `2020-01-03T13:33:37Z` | +### datahistoryjobrelations + +| Field | Description | Example | +| ------ | ----------- | ------- | +| prerequisite_job_id | The job that must be completed before `job_id` can be run | `deadbeef-dead-beef-dead-beef13371337` | +| job_id | The job that will be run after `prerequisite_job_id` completes | `deadbeef-dead-beef-dead-beef13371337` | + +### candle +The candle table also has relationships to data history jobs. Only the relevant columns are listed below: + +| Field | Description | Example | +| ------ | ----------- | ------- | +| source_job_id | The source job id for where the candle data came from. | `deadbeef-dead-beef-dead-beef13371337` | +| validation_job_id | When job id for what job validated the candle data | `deadbeef-dead-beef-dead-beef13371337` | +| validation_issues | If any discrepancies are found, the data will be written to the column | `issues found at 2020-07-08 00:00:00, Open api: 9262.62 db: 9262.69 diff: 3%, replacing database candle data with API data` | + + + ### Please click GoDocs chevron above to view current GoDoc information for this package {{template "contributions"}} {{template "donations" .}} diff --git a/cmd/gctcli/data_history.go b/cmd/gctcli/data_history.go index 85f57cefc13..a3e35e7f7cd 100644 --- a/cmd/gctcli/data_history.go +++ b/cmd/gctcli/data_history.go @@ -8,84 +8,11 @@ import ( "time" "github.com/thrasher-corp/gocryptotrader/common" - "github.com/thrasher-corp/gocryptotrader/common/convert" "github.com/thrasher-corp/gocryptotrader/currency" "github.com/thrasher-corp/gocryptotrader/gctrpc" "github.com/urfave/cli/v2" ) -var ( - maxRetryAttempts, requestSizeLimit, batchSize uint64 - guidExample = "deadbeef-dead-beef-dead-beef13371337" - specificJobSubCommands = []cli.Flag{ - &cli.StringFlag{ - Name: "id", - Usage: guidExample, - }, - &cli.StringFlag{ - Name: "nickname", - Usage: "binance-spot-btc-usdt-2019-trades", - }, - } - fullJobSubCommands = []cli.Flag{ - &cli.StringFlag{ - Name: "nickname", - Usage: "binance-spot-btc-usdt-2019-trades", - Required: true, - }, - &cli.StringFlag{ - Name: "exchange", - Usage: "binance", - }, - &cli.StringFlag{ - Name: "asset", - Usage: "spot", - }, - &cli.StringFlag{ - Name: "pair", - Usage: "btc-usdt", - }, - &cli.StringFlag{ - Name: "start_date", - Usage: "formatted as: 2006-01-02 15:04:05", - Value: time.Now().AddDate(-1, 0, 0).Format(common.SimpleTimeFormat), - Destination: &startTime, - }, - &cli.StringFlag{ - Name: "end_date", - Usage: "formatted as: 2006-01-02 15:04:05", - Value: time.Now().AddDate(0, -1, 0).Format(common.SimpleTimeFormat), - Destination: &endTime, - }, - &cli.Uint64Flag{ - Name: "interval", - Usage: klineMessage, - }, - &cli.Uint64Flag{ - Name: "request_size_limit", - Usage: "the number of candles to retrieve per API request", - Destination: &requestSizeLimit, - Value: 500, - }, - &cli.Uint64Flag{ - Name: "data_type", - Usage: "0 for candles, 1 for trades", - }, - &cli.Uint64Flag{ - Name: "max_retry_attempts", - Usage: "the maximum retry attempts for an interval period before giving up", - Value: 3, - Destination: &maxRetryAttempts, - }, - &cli.Uint64Flag{ - Name: "batch_size", - Usage: "the amount of API calls to make per run", - Destination: &batchSize, - Value: 3, - }, - } -) - var dataHistoryCommands = &cli.Command{ Name: "datahistory", Usage: "manage data history jobs to retrieve historic trade or candle data over time", @@ -127,10 +54,7 @@ var dataHistoryCommands = &cli.Command{ ArgsUsage: "", Action: getDataHistoryJob, Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "nickname", - Usage: "binance-spot-btc-usdt-2019-trades", - }, + nicknameFlag, }, }, { @@ -139,34 +63,238 @@ var dataHistoryCommands = &cli.Command{ ArgsUsage: "", Action: getDataHistoryJobSummary, Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "nickname", - Usage: "binance-spot-btc-usdt-2019-trades", - }, + nicknameFlag, }, }, + dataHistoryJobCommands, { - Name: "addnewjob", - Usage: "creates a new data history job", - Flags: fullJobSubCommands, - Action: upsertDataHistoryJob, + Name: "deletejob", + Usage: "sets a jobs status to deleted so it no longer is processed", + ArgsUsage: " or ", + Flags: specificJobSubCommands, + Action: setDataHistoryJobStatus, }, { - Name: "upsertjob", - Usage: "adds a new job, or updates an existing one if it matches jobid OR nickname", - Flags: fullJobSubCommands, - Action: upsertDataHistoryJob, + Name: "pausejob", + Usage: "sets a jobs status to paused so it no longer is processed", + ArgsUsage: " or ", + Flags: specificJobSubCommands, + Action: setDataHistoryJobStatus, }, { - Name: "deletejob", - Usage: "sets a jobs status to deleted so it no longer is processed", + Name: "unpausejob", + Usage: "sets a jobs status to active so it can be processed", ArgsUsage: " or ", Flags: specificJobSubCommands, - Action: deleteDataHistoryJob, + Action: setDataHistoryJobStatus, + }, + { + Name: "updateprerequisite", + Usage: "adds or updates a prerequisite job to the job referenced - if the job is active, it will be set as 'paused'", + ArgsUsage: " ", + Flags: prerequisiteJobSubCommands, + Action: setPrerequisiteJob, + }, + { + Name: "removeprerequisite", + Usage: "removes a prerequisite job from the job referenced - if the job is 'paused', it will be set as 'active'", + ArgsUsage: "", + Flags: []cli.Flag{ + nicknameFlag, + }, + Action: setPrerequisiteJob, + }, + }, +} + +var dataHistoryJobCommands = &cli.Command{ + Name: "addjob", + Usage: "add or update data history jobs", + ArgsUsage: " ", + Subcommands: []*cli.Command{ + { + Name: "savecandles", + Usage: "will fetch candle data from an exchange and save it to the database", + Flags: append(baseJobSubCommands, dataHandlingJobSubCommands...), + Action: upsertDataHistoryJob, + }, + { + Name: "convertcandles", + Usage: "convert candles saved to the database to a new resolution eg 1min -> 5min", + Flags: append(baseJobSubCommands, candleConvertJobJobSubCommands...), + Action: upsertDataHistoryJob, + }, + { + Name: "savetrades", + Usage: "will fetch trade data from an exchange and save it to the database", + Flags: append(baseJobSubCommands, tradeHandlingJobSubCommands...), + Action: upsertDataHistoryJob, + }, + { + Name: "converttrades", + Usage: "convert trades saved to the database to any candle resolution eg 30min", + Flags: append(baseJobSubCommands, dataHandlingJobSubCommands...), + Action: upsertDataHistoryJob, + }, + { + Name: "validatecandles", + Usage: "will compare database candle data with API candle data - useful for validating converted trades and candles", + Flags: append(baseJobSubCommands, validationJobSubCommands...), + Action: upsertDataHistoryJob, + }, + { + Name: "secondaryvalidatecandles", + Usage: "will compare database candle data with a different exchange's API candle data - ", + Flags: append(baseJobSubCommands, secondaryValidationJobSubCommands...), + Action: upsertDataHistoryJob, }, }, } +var ( + maxRetryAttempts, requestSizeLimit, batchSize, comparisonDecimalPlaces uint64 + guidExample = "deadbeef-dead-beef-dead-beef13371337" + overwriteDataFlag = &cli.BoolFlag{ + Name: "overwrite_existing_data", + Usage: "will process and overwrite data if matching data exists at an interval period. if false, will not process or save data", + } + comparisonDecimalPlacesFlag = &cli.Uint64Flag{ + Name: "comparison_decimal_places", + Usage: "the number of decimal places used to compare against API data for accuracy", + Destination: &comparisonDecimalPlaces, + Value: 3, + } + intolerancePercentageFlag = &cli.Float64Flag{ + Name: "intolerance_percentage", + Usage: "the number of decimal places used to compare against API data for accuracy", + } + requestSize500Flag = &cli.Uint64Flag{ + Name: "request_size_limit", + Usage: "the number of candle intervals to retrieve per request. eg if interval is 1d and request_size_limit is 500, then retrieve 500 intervals per batch", + Destination: &requestSizeLimit, + Value: 500, + } + requestSize50Flag = &cli.Uint64Flag{ + Name: "request_size_limit", + Usage: "the number of intervals to retrieve per request. eg if interval is 1d and request_size_limit is 50, then retrieve 50 intervals per batch", + Destination: &requestSizeLimit, + Value: 50, + } + requestSize10Flag = &cli.Uint64Flag{ + Name: "request_size_limit", + Usage: "the number of intervals worth of trades to retrieve per API request. eg if interval is 1m and request_size_limit is 10, then retrieve 10 minutes of trades per batch", + Destination: &requestSizeLimit, + Value: 10, + } + nicknameFlag = &cli.StringFlag{ + Name: "nickname", + Usage: "binance-spot-btc-usdt-2019-trades", + } + prerequisiteJobSubCommands = []cli.Flag{ + nicknameFlag, + &cli.StringFlag{ + Name: "prerequisite_job_nickname", + Usage: "binance-spot-btc-usdt-2018-trades", + }, + } + specificJobSubCommands = []cli.Flag{ + &cli.StringFlag{ + Name: "id", + Usage: guidExample, + }, + } + baseJobSubCommands = []cli.Flag{ + nicknameFlag, + &cli.StringFlag{ + Name: "exchange", + Usage: "eg binance", + Required: true, + }, + &cli.StringFlag{ + Name: "asset", + Usage: "eg spot", + Required: true, + }, + &cli.StringFlag{ + Name: "pair", + Usage: "eg btc-usdt", + Required: true, + }, + &cli.StringFlag{ + Name: "start_date", + Usage: "formatted as: 2006-01-02 15:04:05", + Value: time.Now().AddDate(-1, 0, 0).Format(common.SimpleTimeFormat), + Destination: &startTime, + }, + &cli.StringFlag{ + Name: "end_date", + Usage: "formatted as: 2006-01-02 15:04:05", + Value: time.Now().AddDate(0, -1, 0).Format(common.SimpleTimeFormat), + Destination: &endTime, + }, + &cli.Uint64Flag{ + Name: "interval", + Usage: klineMessage, + Required: true, + }, + &cli.Uint64Flag{ + Name: "max_retry_attempts", + Usage: "the maximum retry attempts for an interval period before giving up", + Value: 3, + Destination: &maxRetryAttempts, + }, + &cli.Uint64Flag{ + Name: "batch_size", + Usage: "when a job is processed, the number of processing cycles to run. eg a batch size of 3, an interval of 1m and a request_size_limit of 3 will retrieve 3 batches of 3m per cycle", + Destination: &batchSize, + Value: 3, + }, + &cli.StringFlag{ + Name: "prerequisite_job_nickname", + Usage: "if present, adds or updates the job to have a prerequisite, will only run when prerequisite job is complete - use command 'removeprerequisite' to remove a prerequisite", + }, + &cli.BoolFlag{ + Name: "upsert", + Usage: "if true, will update an existing job if the nickname is shared. if false, will reject a job if the nickname already exists", + }, + } + dataHandlingJobSubCommands = []cli.Flag{ + requestSize500Flag, + overwriteDataFlag, + } + tradeHandlingJobSubCommands = []cli.Flag{ + requestSize10Flag, + overwriteDataFlag, + } + candleConvertJobJobSubCommands = []cli.Flag{ + &cli.Uint64Flag{ + Name: "conversion_interval", + Usage: "the resulting converted candle interval. Can be converted to any interval, however the following " + klineMessage, + Required: true, + }, + requestSize500Flag, + overwriteDataFlag, + } + validationJobSubCommands = []cli.Flag{ + requestSize50Flag, + comparisonDecimalPlacesFlag, + intolerancePercentageFlag, + &cli.Uint64Flag{ + Name: "replace_on_issue", + Usage: "if true, when the intolerance percentage is exceeded, then the comparison API candle will replace the database candle", + }, + } + secondaryValidationJobSubCommands = []cli.Flag{ + &cli.StringFlag{ + Name: "secondary_exchange", + Usage: "the exchange to compare candles data to", + }, + requestSize50Flag, + comparisonDecimalPlacesFlag, + intolerancePercentageFlag, + } +) + func getDataHistoryJob(c *cli.Context) error { if c.NArg() == 0 && c.NumFlags() == 0 { return cli.ShowCommandHelp(c, c.Command.Name) @@ -249,14 +377,10 @@ func upsertDataHistoryJob(c *cli.Context) error { ) if c.IsSet("nickname") { nickname = c.String("nickname") - } else { - nickname = c.Args().First() } if c.IsSet("exchange") { exchange = c.String("exchange") - } else { - exchange = c.Args().Get(1) } if !validExchange(exchange) { return errInvalidExchange @@ -264,8 +388,6 @@ func upsertDataHistoryJob(c *cli.Context) error { if c.IsSet("asset") { assetType = c.String("asset") - } else { - assetType = c.Args().Get(2) } if !validAsset(assetType) { return errInvalidAsset @@ -273,8 +395,6 @@ func upsertDataHistoryJob(c *cli.Context) error { if c.IsSet("pair") { pair = c.String("pair") - } else { - pair = c.Args().Get(3) } if !validPair(pair) { return errInvalidPair @@ -303,21 +423,12 @@ func upsertDataHistoryJob(c *cli.Context) error { if c.IsSet("interval") { interval = c.Int64("interval") - } else { - interval, err = convert.Int64FromString(c.Args().Get(6)) - if err != nil { - return fmt.Errorf("cannot process interval: %w", err) - } } candleInterval := time.Duration(interval) * time.Second if c.IsSet("request_size_limit") { requestSizeLimit = c.Uint64("request_size_limit") } - if c.IsSet("data_type") { - dataType = c.Int64("data_type") - } - if c.IsSet("max_retry_attempts") { maxRetryAttempts = c.Uint64("max_retry_attempts") } @@ -325,6 +436,70 @@ func upsertDataHistoryJob(c *cli.Context) error { if c.IsSet("batch_size") { batchSize = c.Uint64("batch_size") } + var upsert bool + if c.IsSet("upsert") { + upsert = c.Bool("upsert") + } + + var secondaryExchange string + if c.IsSet("secondary_exchange") { + secondaryExchange = c.String("secondary_exchange") + } + + var prerequisiteJobNickname string + if c.IsSet("prerequisite_job_nickname") { + prerequisiteJobNickname = c.String("prerequisite_job_nickname") + } + + var intolerancePercentage float64 + if c.IsSet("intolerance_percentage") { + intolerancePercentage = c.Float64("intolerance_percentage") + } + + var replaceOnIssue bool + if c.IsSet("replace_on_issue") { + replaceOnIssue = c.Bool("replace_on_issue") + } + + switch c.Command.Name { + case "savecandles": + dataType = 0 + case "savetrades": + dataType = 1 + case "convertcandles": + dataType = 3 + case "converttrades": + dataType = 2 + case "validatecandles": + dataType = 4 + case "secondaryvalidatecandles": + dataType = 5 + default: + return errors.New("unrecognised command, cannot set data type") + } + + var conversionInterval time.Duration + var overwriteExistingData bool + + switch dataType { + case 0, 1: + if c.IsSet("overwrite_existing_data") { + overwriteExistingData = c.Bool("overwrite_existing_data") + } + case 2, 3: + var cInterval int64 + if c.IsSet("conversion_interval") { + cInterval = c.Int64("conversion_interval") + } + conversionInterval = time.Duration(cInterval) * time.Second + if c.IsSet("overwrite_existing_data") { + overwriteExistingData = c.Bool("overwrite_existing_data") + } + case 4: + if c.IsSet("comparison_decimal_places") { + comparisonDecimalPlaces = c.Uint64("comparison_decimal_places") + } + } conn, err := setupClient() if err != nil { @@ -346,16 +521,21 @@ func upsertDataHistoryJob(c *cli.Context) error { Base: p.Base.String(), Quote: p.Quote.String(), }, - StartDate: negateLocalOffset(s), - EndDate: negateLocalOffset(e), - Interval: int64(candleInterval), - RequestSizeLimit: int64(requestSizeLimit), - DataType: dataType, - MaxRetryAttempts: int64(maxRetryAttempts), - BatchSize: int64(batchSize), - } - if strings.EqualFold(c.Command.Name, "addnewjob") { - request.InsertOnly = true + StartDate: negateLocalOffset(s), + EndDate: negateLocalOffset(e), + Interval: int64(candleInterval), + RequestSizeLimit: int64(requestSizeLimit), + DataType: dataType, + MaxRetryAttempts: int64(maxRetryAttempts), + BatchSize: int64(batchSize), + ConversionInterval: int64(conversionInterval), + OverwriteExistingData: overwriteExistingData, + PrerequisiteJobNickname: prerequisiteJobNickname, + InsertOnly: !upsert, + DecimalPlaceComparison: int64(comparisonDecimalPlaces), + SecondaryExchangeName: secondaryExchange, + IssueTolerancePercentage: intolerancePercentage, + ReplaceOnIssue: replaceOnIssue, } result, err := client.UpsertDataHistoryJob(context.Background(), request) @@ -418,7 +598,7 @@ func getDataHistoryJobsBetween(c *cli.Context) error { return nil } -func deleteDataHistoryJob(c *cli.Context) error { +func setDataHistoryJobStatus(c *cli.Context) error { if c.NArg() == 0 && c.NumFlags() == 0 { return cli.ShowCommandHelp(c, c.Command.Name) } @@ -439,6 +619,18 @@ func deleteDataHistoryJob(c *cli.Context) error { return errors.New("can only set 'id' OR 'nickname'") } + var status int64 + switch c.Command.Name { + case "deletejob": + status = 3 + case "pausejob": + status = 5 + case "unpausejob": + status = 0 + default: + return fmt.Errorf("unable to modify data history job status, unrecognised command '%v'", c.Command.Name) + } + conn, err := setupClient() if err != nil { return err @@ -450,12 +642,13 @@ func deleteDataHistoryJob(c *cli.Context) error { } }() client := gctrpc.NewGoCryptoTraderClient(conn) - request := &gctrpc.GetDataHistoryJobDetailsRequest{ + request := &gctrpc.SetDataHistoryJobStatusRequest{ Id: id, Nickname: nickname, + Status: status, } - result, err := client.DeleteDataHistoryJob(context.Background(), request) + result, err := client.SetDataHistoryJobStatus(context.Background(), request) if err != nil { return err } @@ -497,3 +690,50 @@ func getDataHistoryJobSummary(c *cli.Context) error { jsonOutput(result) return nil } + +func setPrerequisiteJob(c *cli.Context) error { + if c.NArg() == 0 && c.NumFlags() == 0 { + return cli.ShowCommandHelp(c, c.Command.Name) + } + + var nickname string + if c.IsSet("nickname") { + nickname = c.String("nickname") + } else { + nickname = c.Args().First() + } + + var prerequisite string + if c.IsSet("prerequisite_job_nickname") { + prerequisite = c.String("prerequisite_job_nickname") + } else { + prerequisite = c.Args().Get(1) + } + + if c.Command.Name == "updateprerequisite" && prerequisite == "" { + return errors.New("prerequisite required") + } + + conn, err := setupClient() + if err != nil { + return err + } + defer func() { + err = conn.Close() + if err != nil { + fmt.Print(err) + } + }() + client := gctrpc.NewGoCryptoTraderClient(conn) + request := &gctrpc.UpdateDataHistoryJobPrerequisiteRequest{ + PrerequisiteJobNickname: prerequisite, + Nickname: nickname, + } + + result, err := client.UpdateDataHistoryJobPrerequisite(context.Background(), request) + if err != nil { + return err + } + jsonOutput(result) + return nil +} diff --git a/config/config_types.go b/config/config_types.go index eb79b010c20..39c650b4bfd 100644 --- a/config/config_types.go +++ b/config/config_types.go @@ -103,10 +103,11 @@ type Config struct { // DataHistoryManager holds all information required for the data history manager type DataHistoryManager struct { - Enabled bool `json:"enabled"` - CheckInterval time.Duration `json:"checkInterval"` - MaxJobsPerCycle int64 `json:"maxJobsPerCycle"` - Verbose bool `json:"verbose"` + Enabled bool `json:"enabled"` + CheckInterval time.Duration `json:"checkInterval"` + MaxJobsPerCycle int64 `json:"maxJobsPerCycle"` + MaxResultInsertions int64 `json:"maxResultInsertions"` + Verbose bool `json:"verbose"` } // ConnectionMonitorConfig defines the connection monitor variables to ensure diff --git a/database/migrations/20210617165159_datahistoryjob_relations/postgres.sql b/database/migrations/20210617165159_datahistoryjob_relations/postgres.sql new file mode 100644 index 00000000000..cd16afc02d5 --- /dev/null +++ b/database/migrations/20210617165159_datahistoryjob_relations/postgres.sql @@ -0,0 +1,9 @@ +-- +goose Up +CREATE TABLE datahistoryjobrelations +( + prerequisite_job_id uuid not null REFERENCES datahistoryjob(id), + job_id uuid not null REFERENCES datahistoryjob(id), + PRIMARY KEY (prerequisite_job_id, job_id) +); +-- +goose Down +DROP TABLE datahistoryjobrelations; diff --git a/database/migrations/20210617165159_datahistoryjob_relations/sqlite3.sql b/database/migrations/20210617165159_datahistoryjob_relations/sqlite3.sql new file mode 100644 index 00000000000..a7fbf363be5 --- /dev/null +++ b/database/migrations/20210617165159_datahistoryjob_relations/sqlite3.sql @@ -0,0 +1,11 @@ +-- +goose Up +CREATE TABLE datahistoryjobrelations +( + prerequisite_job_id text not null, + job_id text not null, + PRIMARY KEY (prerequisite_job_id, job_id), + FOREIGN KEY (prerequisite_job_id) REFERENCES datahistoryjob(id) ON DELETE RESTRICT, + FOREIGN KEY (job_id) REFERENCES datahistoryjob(id) ON DELETE RESTRICT +); +-- +goose Down +DROP TABLE datahistoryjobrelations; diff --git a/database/migrations/20210630125121_datahistoryjob_conversions/postgres.sql b/database/migrations/20210630125121_datahistoryjob_conversions/postgres.sql new file mode 100644 index 00000000000..978e61d48af --- /dev/null +++ b/database/migrations/20210630125121_datahistoryjob_conversions/postgres.sql @@ -0,0 +1,19 @@ +-- +goose Up +ALTER TABLE datahistoryjob + ADD conversion_interval DOUBLE PRECISION, + ADD overwrite_data boolean, + ADD decimal_place_comparison INTEGER, + ADD secondary_exchange_id uuid REFERENCES exchange(id), + ADD issue_tolerance_percentage DOUBLE PRECISION, + ADD replace_on_issue boolean; + +-- +goose Down +ALTER TABLE datahistoryjob + DROP replace_on_issue, + DROP issue_tolerance_percentage, + DROP CONSTRAINT datahistoryjob_secondary_exchange_id_fkey, + DROP secondary_exchange_id, + DROP decimal_place_comparison, + DROP overwrite_data, + DROP conversion_interval; + diff --git a/database/migrations/20210630125121_datahistoryjob_conversions/sqlite3.sql b/database/migrations/20210630125121_datahistoryjob_conversions/sqlite3.sql new file mode 100644 index 00000000000..2d58994db12 --- /dev/null +++ b/database/migrations/20210630125121_datahistoryjob_conversions/sqlite3.sql @@ -0,0 +1,27 @@ +-- +goose Up +ALTER TABLE datahistoryjob + ADD conversion_interval real; +ALTER TABLE datahistoryjob + ADD overwrite_data integer; +ALTER TABLE datahistoryjob + ADD decimal_place_comparison integer; +ALTER TABLE datahistoryjob + ADD secondary_exchange_id text REFERENCES exchange(id) ON DELETE RESTRICT; +ALTER TABLE datahistoryjob + ADD issue_tolerance_percentage real; +ALTER TABLE datahistoryjob + ADD replace_on_issue integer; + +-- +goose Down +ALTER TABLE datahistoryjob + DROP replace_on_issue; +ALTER TABLE datahistoryjob + DROP issue_tolerance_percentage; +ALTER TABLE datahistoryjob + DROP secondary_exchange_id; +ALTER TABLE datahistoryjob + DROP decimal_place_comparison; +ALTER TABLE datahistoryjob + DROP overwrite_data; +ALTER TABLE datahistoryjob + DROP conversion_interval; diff --git a/database/migrations/20210709133512_candle_details/postgres.sql b/database/migrations/20210709133512_candle_details/postgres.sql new file mode 100644 index 00000000000..3a2116fcf4e --- /dev/null +++ b/database/migrations/20210709133512_candle_details/postgres.sql @@ -0,0 +1,12 @@ +-- +goose Up +ALTER TABLE candle + ADD source_job_id uuid references datahistoryjob(id), + ADD validation_job_id uuid REFERENCES datahistoryjob(id), + ADD validation_issues TEXT; +-- +goose Down +ALTER TABLE candle + DROP validation_issues, + DROP CONSTRAINT candle_validation_job_id_fkey, + DROP validation_job_id, + DROP CONSTRAINT candle_source_job_id_fkey, + DROP source_job_id; diff --git a/database/migrations/20210709133512_candle_details/sqlite3.sql b/database/migrations/20210709133512_candle_details/sqlite3.sql new file mode 100644 index 00000000000..c7e980aff0e --- /dev/null +++ b/database/migrations/20210709133512_candle_details/sqlite3.sql @@ -0,0 +1,15 @@ +-- +goose Up +ALTER TABLE candle + ADD source_job_id TEXT REFERENCES datahistoryjob(id); +ALTER TABLE candle + ADD validation_job_id TEXT REFERENCES datahistoryjob(id); +ALTER TABLE candle + ADD validation_issues TEXT; +-- +goose Down +ALTER TABLE candle + DROP validation_issues; +ALTER TABLE candle + DROP validation_job_id; +ALTER TABLE candle + DROP source_job_id; + diff --git a/database/models/postgres/boil_table_names.go b/database/models/postgres/boil_table_names.go index d55b12d868f..cc9c7ea4821 100644 --- a/database/models/postgres/boil_table_names.go +++ b/database/models/postgres/boil_table_names.go @@ -4,27 +4,29 @@ package postgres var TableNames = struct { - AuditEvent string - Candle string - Datahistoryjob string - Datahistoryjobresult string - Exchange string - Script string - ScriptExecution string - Trade string - WithdrawalCrypto string - WithdrawalFiat string - WithdrawalHistory string + AuditEvent string + Candle string + Datahistoryjob string + Datahistoryjobrelations string + Datahistoryjobresult string + Exchange string + Script string + ScriptExecution string + Trade string + WithdrawalCrypto string + WithdrawalFiat string + WithdrawalHistory string }{ - AuditEvent: "audit_event", - Candle: "candle", - Datahistoryjob: "datahistoryjob", - Datahistoryjobresult: "datahistoryjobresult", - Exchange: "exchange", - Script: "script", - ScriptExecution: "script_execution", - Trade: "trade", - WithdrawalCrypto: "withdrawal_crypto", - WithdrawalFiat: "withdrawal_fiat", - WithdrawalHistory: "withdrawal_history", + AuditEvent: "audit_event", + Candle: "candle", + Datahistoryjob: "datahistoryjob", + Datahistoryjobrelations: "datahistoryjobrelations", + Datahistoryjobresult: "datahistoryjobresult", + Exchange: "exchange", + Script: "script", + ScriptExecution: "script_execution", + Trade: "trade", + WithdrawalCrypto: "withdrawal_crypto", + WithdrawalFiat: "withdrawal_fiat", + WithdrawalHistory: "withdrawal_history", } diff --git a/database/models/postgres/candle.go b/database/models/postgres/candle.go index 8690c1eacd3..3826fbff7e4 100644 --- a/database/models/postgres/candle.go +++ b/database/models/postgres/candle.go @@ -19,53 +19,63 @@ import ( "github.com/thrasher-corp/sqlboiler/queries/qm" "github.com/thrasher-corp/sqlboiler/queries/qmhelper" "github.com/thrasher-corp/sqlboiler/strmangle" + "github.com/volatiletech/null" ) // Candle is an object representing the database table. type Candle struct { - ID string `boil:"id" json:"id" toml:"id" yaml:"id"` - ExchangeNameID string `boil:"exchange_name_id" json:"exchange_name_id" toml:"exchange_name_id" yaml:"exchange_name_id"` - Base string `boil:"base" json:"base" toml:"base" yaml:"base"` - Quote string `boil:"quote" json:"quote" toml:"quote" yaml:"quote"` - Interval int64 `boil:"interval" json:"interval" toml:"interval" yaml:"interval"` - Timestamp time.Time `boil:"timestamp" json:"timestamp" toml:"timestamp" yaml:"timestamp"` - Open float64 `boil:"open" json:"open" toml:"open" yaml:"open"` - High float64 `boil:"high" json:"high" toml:"high" yaml:"high"` - Low float64 `boil:"low" json:"low" toml:"low" yaml:"low"` - Close float64 `boil:"close" json:"close" toml:"close" yaml:"close"` - Volume float64 `boil:"volume" json:"volume" toml:"volume" yaml:"volume"` - Asset string `boil:"asset" json:"asset" toml:"asset" yaml:"asset"` + ID string `boil:"id" json:"id" toml:"id" yaml:"id"` + ExchangeNameID string `boil:"exchange_name_id" json:"exchange_name_id" toml:"exchange_name_id" yaml:"exchange_name_id"` + Base string `boil:"base" json:"base" toml:"base" yaml:"base"` + Quote string `boil:"quote" json:"quote" toml:"quote" yaml:"quote"` + Interval int64 `boil:"interval" json:"interval" toml:"interval" yaml:"interval"` + Timestamp time.Time `boil:"timestamp" json:"timestamp" toml:"timestamp" yaml:"timestamp"` + Open float64 `boil:"open" json:"open" toml:"open" yaml:"open"` + High float64 `boil:"high" json:"high" toml:"high" yaml:"high"` + Low float64 `boil:"low" json:"low" toml:"low" yaml:"low"` + Close float64 `boil:"close" json:"close" toml:"close" yaml:"close"` + Volume float64 `boil:"volume" json:"volume" toml:"volume" yaml:"volume"` + Asset string `boil:"asset" json:"asset" toml:"asset" yaml:"asset"` + SourceJobID null.String `boil:"source_job_id" json:"source_job_id,omitempty" toml:"source_job_id" yaml:"source_job_id,omitempty"` + ValidationJobID null.String `boil:"validation_job_id" json:"validation_job_id,omitempty" toml:"validation_job_id" yaml:"validation_job_id,omitempty"` + ValidationIssues null.String `boil:"validation_issues" json:"validation_issues,omitempty" toml:"validation_issues" yaml:"validation_issues,omitempty"` R *candleR `boil:"-" json:"-" toml:"-" yaml:"-"` L candleL `boil:"-" json:"-" toml:"-" yaml:"-"` } var CandleColumns = struct { - ID string - ExchangeNameID string - Base string - Quote string - Interval string - Timestamp string - Open string - High string - Low string - Close string - Volume string - Asset string + ID string + ExchangeNameID string + Base string + Quote string + Interval string + Timestamp string + Open string + High string + Low string + Close string + Volume string + Asset string + SourceJobID string + ValidationJobID string + ValidationIssues string }{ - ID: "id", - ExchangeNameID: "exchange_name_id", - Base: "base", - Quote: "quote", - Interval: "interval", - Timestamp: "timestamp", - Open: "open", - High: "high", - Low: "low", - Close: "close", - Volume: "volume", - Asset: "asset", + ID: "id", + ExchangeNameID: "exchange_name_id", + Base: "base", + Quote: "quote", + Interval: "interval", + Timestamp: "timestamp", + Open: "open", + High: "high", + Low: "low", + Close: "close", + Volume: "volume", + Asset: "asset", + SourceJobID: "source_job_id", + ValidationJobID: "validation_job_id", + ValidationIssues: "validation_issues", } // Generated where @@ -85,44 +95,79 @@ func (w whereHelperfloat64) GTE(x float64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) } +type whereHelpernull_String struct{ field string } + +func (w whereHelpernull_String) EQ(x null.String) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, false, x) +} +func (w whereHelpernull_String) NEQ(x null.String) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, true, x) +} +func (w whereHelpernull_String) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } +func (w whereHelpernull_String) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } +func (w whereHelpernull_String) LT(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpernull_String) LTE(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpernull_String) GT(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpernull_String) GTE(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} + var CandleWhere = struct { - ID whereHelperstring - ExchangeNameID whereHelperstring - Base whereHelperstring - Quote whereHelperstring - Interval whereHelperint64 - Timestamp whereHelpertime_Time - Open whereHelperfloat64 - High whereHelperfloat64 - Low whereHelperfloat64 - Close whereHelperfloat64 - Volume whereHelperfloat64 - Asset whereHelperstring + ID whereHelperstring + ExchangeNameID whereHelperstring + Base whereHelperstring + Quote whereHelperstring + Interval whereHelperint64 + Timestamp whereHelpertime_Time + Open whereHelperfloat64 + High whereHelperfloat64 + Low whereHelperfloat64 + Close whereHelperfloat64 + Volume whereHelperfloat64 + Asset whereHelperstring + SourceJobID whereHelpernull_String + ValidationJobID whereHelpernull_String + ValidationIssues whereHelpernull_String }{ - ID: whereHelperstring{field: "\"candle\".\"id\""}, - ExchangeNameID: whereHelperstring{field: "\"candle\".\"exchange_name_id\""}, - Base: whereHelperstring{field: "\"candle\".\"base\""}, - Quote: whereHelperstring{field: "\"candle\".\"quote\""}, - Interval: whereHelperint64{field: "\"candle\".\"interval\""}, - Timestamp: whereHelpertime_Time{field: "\"candle\".\"timestamp\""}, - Open: whereHelperfloat64{field: "\"candle\".\"open\""}, - High: whereHelperfloat64{field: "\"candle\".\"high\""}, - Low: whereHelperfloat64{field: "\"candle\".\"low\""}, - Close: whereHelperfloat64{field: "\"candle\".\"close\""}, - Volume: whereHelperfloat64{field: "\"candle\".\"volume\""}, - Asset: whereHelperstring{field: "\"candle\".\"asset\""}, + ID: whereHelperstring{field: "\"candle\".\"id\""}, + ExchangeNameID: whereHelperstring{field: "\"candle\".\"exchange_name_id\""}, + Base: whereHelperstring{field: "\"candle\".\"base\""}, + Quote: whereHelperstring{field: "\"candle\".\"quote\""}, + Interval: whereHelperint64{field: "\"candle\".\"interval\""}, + Timestamp: whereHelpertime_Time{field: "\"candle\".\"timestamp\""}, + Open: whereHelperfloat64{field: "\"candle\".\"open\""}, + High: whereHelperfloat64{field: "\"candle\".\"high\""}, + Low: whereHelperfloat64{field: "\"candle\".\"low\""}, + Close: whereHelperfloat64{field: "\"candle\".\"close\""}, + Volume: whereHelperfloat64{field: "\"candle\".\"volume\""}, + Asset: whereHelperstring{field: "\"candle\".\"asset\""}, + SourceJobID: whereHelpernull_String{field: "\"candle\".\"source_job_id\""}, + ValidationJobID: whereHelpernull_String{field: "\"candle\".\"validation_job_id\""}, + ValidationIssues: whereHelpernull_String{field: "\"candle\".\"validation_issues\""}, } // CandleRels is where relationship names are stored. var CandleRels = struct { - ExchangeName string + ExchangeName string + SourceJob string + ValidationJob string }{ - ExchangeName: "ExchangeName", + ExchangeName: "ExchangeName", + SourceJob: "SourceJob", + ValidationJob: "ValidationJob", } // candleR is where relationships are stored. type candleR struct { - ExchangeName *Exchange + ExchangeName *Exchange + SourceJob *Datahistoryjob + ValidationJob *Datahistoryjob } // NewStruct creates a new relationship struct @@ -134,8 +179,8 @@ func (*candleR) NewStruct() *candleR { type candleL struct{} var ( - candleAllColumns = []string{"id", "exchange_name_id", "base", "quote", "interval", "timestamp", "open", "high", "low", "close", "volume", "asset"} - candleColumnsWithoutDefault = []string{"exchange_name_id", "base", "quote", "interval", "timestamp", "open", "high", "low", "close", "volume", "asset"} + candleAllColumns = []string{"id", "exchange_name_id", "base", "quote", "interval", "timestamp", "open", "high", "low", "close", "volume", "asset", "source_job_id", "validation_job_id", "validation_issues"} + candleColumnsWithoutDefault = []string{"exchange_name_id", "base", "quote", "interval", "timestamp", "open", "high", "low", "close", "volume", "asset", "source_job_id", "validation_job_id", "validation_issues"} candleColumnsWithDefault = []string{"id"} candlePrimaryKeyColumns = []string{"id"} ) @@ -429,6 +474,34 @@ func (o *Candle) ExchangeName(mods ...qm.QueryMod) exchangeQuery { return query } +// SourceJob pointed to by the foreign key. +func (o *Candle) SourceJob(mods ...qm.QueryMod) datahistoryjobQuery { + queryMods := []qm.QueryMod{ + qm.Where("\"id\" = ?", o.SourceJobID), + } + + queryMods = append(queryMods, mods...) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + return query +} + +// ValidationJob pointed to by the foreign key. +func (o *Candle) ValidationJob(mods ...qm.QueryMod) datahistoryjobQuery { + queryMods := []qm.QueryMod{ + qm.Where("\"id\" = ?", o.ValidationJobID), + } + + queryMods = append(queryMods, mods...) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + return query +} + // LoadExchangeName allows an eager lookup of values, cached into the // loaded structs of the objects. This is for an N-1 relationship. func (candleL) LoadExchangeName(ctx context.Context, e boil.ContextExecutor, singular bool, maybeCandle interface{}, mods queries.Applicator) error { @@ -530,6 +603,216 @@ func (candleL) LoadExchangeName(ctx context.Context, e boil.ContextExecutor, sin return nil } +// LoadSourceJob allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for an N-1 relationship. +func (candleL) LoadSourceJob(ctx context.Context, e boil.ContextExecutor, singular bool, maybeCandle interface{}, mods queries.Applicator) error { + var slice []*Candle + var object *Candle + + if singular { + object = maybeCandle.(*Candle) + } else { + slice = *maybeCandle.(*[]*Candle) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &candleR{} + } + if !queries.IsNil(object.SourceJobID) { + args = append(args, object.SourceJobID) + } + + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &candleR{} + } + + for _, a := range args { + if queries.Equal(a, obj.SourceJobID) { + continue Outer + } + } + + if !queries.IsNil(obj.SourceJobID) { + args = append(args, obj.SourceJobID) + } + + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`datahistoryjob`), qm.WhereIn(`datahistoryjob.id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load Datahistoryjob") + } + + var resultSlice []*Datahistoryjob + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice Datahistoryjob") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results of eager load for datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(candleAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + + if len(resultSlice) == 0 { + return nil + } + + if singular { + foreign := resultSlice[0] + object.R.SourceJob = foreign + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.SourceJobCandles = append(foreign.R.SourceJobCandles, object) + return nil + } + + for _, local := range slice { + for _, foreign := range resultSlice { + if queries.Equal(local.SourceJobID, foreign.ID) { + local.R.SourceJob = foreign + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.SourceJobCandles = append(foreign.R.SourceJobCandles, local) + break + } + } + } + + return nil +} + +// LoadValidationJob allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for an N-1 relationship. +func (candleL) LoadValidationJob(ctx context.Context, e boil.ContextExecutor, singular bool, maybeCandle interface{}, mods queries.Applicator) error { + var slice []*Candle + var object *Candle + + if singular { + object = maybeCandle.(*Candle) + } else { + slice = *maybeCandle.(*[]*Candle) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &candleR{} + } + if !queries.IsNil(object.ValidationJobID) { + args = append(args, object.ValidationJobID) + } + + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &candleR{} + } + + for _, a := range args { + if queries.Equal(a, obj.ValidationJobID) { + continue Outer + } + } + + if !queries.IsNil(obj.ValidationJobID) { + args = append(args, obj.ValidationJobID) + } + + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`datahistoryjob`), qm.WhereIn(`datahistoryjob.id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load Datahistoryjob") + } + + var resultSlice []*Datahistoryjob + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice Datahistoryjob") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results of eager load for datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(candleAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + + if len(resultSlice) == 0 { + return nil + } + + if singular { + foreign := resultSlice[0] + object.R.ValidationJob = foreign + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.ValidationJobCandles = append(foreign.R.ValidationJobCandles, object) + return nil + } + + for _, local := range slice { + for _, foreign := range resultSlice { + if queries.Equal(local.ValidationJobID, foreign.ID) { + local.R.ValidationJob = foreign + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.ValidationJobCandles = append(foreign.R.ValidationJobCandles, local) + break + } + } + } + + return nil +} + // SetExchangeName of the candle to the related item. // Sets o.R.ExchangeName to related. // Adds o to related.R.ExchangeNameCandles. @@ -577,6 +860,162 @@ func (o *Candle) SetExchangeName(ctx context.Context, exec boil.ContextExecutor, return nil } +// SetSourceJob of the candle to the related item. +// Sets o.R.SourceJob to related. +// Adds o to related.R.SourceJobCandles. +func (o *Candle) SetSourceJob(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Datahistoryjob) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"candle\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"source_job_id"}), + strmangle.WhereClause("\"", "\"", 2, candlePrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + queries.Assign(&o.SourceJobID, related.ID) + if o.R == nil { + o.R = &candleR{ + SourceJob: related, + } + } else { + o.R.SourceJob = related + } + + if related.R == nil { + related.R = &datahistoryjobR{ + SourceJobCandles: CandleSlice{o}, + } + } else { + related.R.SourceJobCandles = append(related.R.SourceJobCandles, o) + } + + return nil +} + +// RemoveSourceJob relationship. +// Sets o.R.SourceJob to nil. +// Removes o from all passed in related items' relationships struct (Optional). +func (o *Candle) RemoveSourceJob(ctx context.Context, exec boil.ContextExecutor, related *Datahistoryjob) error { + var err error + + queries.SetScanner(&o.SourceJobID, nil) + if _, err = o.Update(ctx, exec, boil.Whitelist("source_job_id")); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + o.R.SourceJob = nil + if related == nil || related.R == nil { + return nil + } + + for i, ri := range related.R.SourceJobCandles { + if queries.Equal(o.SourceJobID, ri.SourceJobID) { + continue + } + + ln := len(related.R.SourceJobCandles) + if ln > 1 && i < ln-1 { + related.R.SourceJobCandles[i] = related.R.SourceJobCandles[ln-1] + } + related.R.SourceJobCandles = related.R.SourceJobCandles[:ln-1] + break + } + return nil +} + +// SetValidationJob of the candle to the related item. +// Sets o.R.ValidationJob to related. +// Adds o to related.R.ValidationJobCandles. +func (o *Candle) SetValidationJob(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Datahistoryjob) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"candle\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"validation_job_id"}), + strmangle.WhereClause("\"", "\"", 2, candlePrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + queries.Assign(&o.ValidationJobID, related.ID) + if o.R == nil { + o.R = &candleR{ + ValidationJob: related, + } + } else { + o.R.ValidationJob = related + } + + if related.R == nil { + related.R = &datahistoryjobR{ + ValidationJobCandles: CandleSlice{o}, + } + } else { + related.R.ValidationJobCandles = append(related.R.ValidationJobCandles, o) + } + + return nil +} + +// RemoveValidationJob relationship. +// Sets o.R.ValidationJob to nil. +// Removes o from all passed in related items' relationships struct (Optional). +func (o *Candle) RemoveValidationJob(ctx context.Context, exec boil.ContextExecutor, related *Datahistoryjob) error { + var err error + + queries.SetScanner(&o.ValidationJobID, nil) + if _, err = o.Update(ctx, exec, boil.Whitelist("validation_job_id")); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + o.R.ValidationJob = nil + if related == nil || related.R == nil { + return nil + } + + for i, ri := range related.R.ValidationJobCandles { + if queries.Equal(o.ValidationJobID, ri.ValidationJobID) { + continue + } + + ln := len(related.R.ValidationJobCandles) + if ln > 1 && i < ln-1 { + related.R.ValidationJobCandles[i] = related.R.ValidationJobCandles[ln-1] + } + related.R.ValidationJobCandles = related.R.ValidationJobCandles[:ln-1] + break + } + return nil +} + // Candles retrieves all the records using an executor. func Candles(mods ...qm.QueryMod) candleQuery { mods = append(mods, qm.From("\"candle\"")) diff --git a/database/models/postgres/candle_test.go b/database/models/postgres/candle_test.go index 03f44535147..ae2df943be9 100644 --- a/database/models/postgres/candle_test.go +++ b/database/models/postgres/candle_test.go @@ -545,6 +545,108 @@ func testCandleToOneExchangeUsingExchangeName(t *testing.T) { } } +func testCandleToOneDatahistoryjobUsingSourceJob(t *testing.T) { + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var local Candle + var foreign Datahistoryjob + + seed := randomize.NewSeed() + if err := randomize.Struct(seed, &local, candleDBTypes, true, candleColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Candle struct: %s", err) + } + if err := randomize.Struct(seed, &foreign, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := foreign.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + queries.Assign(&local.SourceJobID, foreign.ID) + if err := local.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := local.SourceJob().One(ctx, tx) + if err != nil { + t.Fatal(err) + } + + if !queries.Equal(check.ID, foreign.ID) { + t.Errorf("want: %v, got %v", foreign.ID, check.ID) + } + + slice := CandleSlice{&local} + if err = local.L.LoadSourceJob(ctx, tx, false, (*[]*Candle)(&slice), nil); err != nil { + t.Fatal(err) + } + if local.R.SourceJob == nil { + t.Error("struct should have been eager loaded") + } + + local.R.SourceJob = nil + if err = local.L.LoadSourceJob(ctx, tx, true, &local, nil); err != nil { + t.Fatal(err) + } + if local.R.SourceJob == nil { + t.Error("struct should have been eager loaded") + } +} + +func testCandleToOneDatahistoryjobUsingValidationJob(t *testing.T) { + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var local Candle + var foreign Datahistoryjob + + seed := randomize.NewSeed() + if err := randomize.Struct(seed, &local, candleDBTypes, true, candleColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Candle struct: %s", err) + } + if err := randomize.Struct(seed, &foreign, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := foreign.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + queries.Assign(&local.ValidationJobID, foreign.ID) + if err := local.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := local.ValidationJob().One(ctx, tx) + if err != nil { + t.Fatal(err) + } + + if !queries.Equal(check.ID, foreign.ID) { + t.Errorf("want: %v, got %v", foreign.ID, check.ID) + } + + slice := CandleSlice{&local} + if err = local.L.LoadValidationJob(ctx, tx, false, (*[]*Candle)(&slice), nil); err != nil { + t.Fatal(err) + } + if local.R.ValidationJob == nil { + t.Error("struct should have been eager loaded") + } + + local.R.ValidationJob = nil + if err = local.L.LoadValidationJob(ctx, tx, true, &local, nil); err != nil { + t.Fatal(err) + } + if local.R.ValidationJob == nil { + t.Error("struct should have been eager loaded") + } +} + func testCandleToOneSetOpExchangeUsingExchangeName(t *testing.T) { var err error @@ -602,6 +704,223 @@ func testCandleToOneSetOpExchangeUsingExchangeName(t *testing.T) { } } } +func testCandleToOneSetOpDatahistoryjobUsingSourceJob(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Candle + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + for i, x := range []*Datahistoryjob{&b, &c} { + err = a.SetSourceJob(ctx, tx, i != 0, x) + if err != nil { + t.Fatal(err) + } + + if a.R.SourceJob != x { + t.Error("relationship struct not set to correct value") + } + + if x.R.SourceJobCandles[0] != &a { + t.Error("failed to append to foreign relationship struct") + } + if !queries.Equal(a.SourceJobID, x.ID) { + t.Error("foreign key was wrong value", a.SourceJobID) + } + + zero := reflect.Zero(reflect.TypeOf(a.SourceJobID)) + reflect.Indirect(reflect.ValueOf(&a.SourceJobID)).Set(zero) + + if err = a.Reload(ctx, tx); err != nil { + t.Fatal("failed to reload", err) + } + + if !queries.Equal(a.SourceJobID, x.ID) { + t.Error("foreign key was wrong value", a.SourceJobID, x.ID) + } + } +} + +func testCandleToOneRemoveOpDatahistoryjobUsingSourceJob(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Candle + var b Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = a.SetSourceJob(ctx, tx, true, &b); err != nil { + t.Fatal(err) + } + + if err = a.RemoveSourceJob(ctx, tx, &b); err != nil { + t.Error("failed to remove relationship") + } + + count, err := a.SourceJob().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 0 { + t.Error("want no relationships remaining") + } + + if a.R.SourceJob != nil { + t.Error("R struct entry should be nil") + } + + if !queries.IsValuerNil(a.SourceJobID) { + t.Error("foreign key value should be nil") + } + + if len(b.R.SourceJobCandles) != 0 { + t.Error("failed to remove a from b's relationships") + } +} + +func testCandleToOneSetOpDatahistoryjobUsingValidationJob(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Candle + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + for i, x := range []*Datahistoryjob{&b, &c} { + err = a.SetValidationJob(ctx, tx, i != 0, x) + if err != nil { + t.Fatal(err) + } + + if a.R.ValidationJob != x { + t.Error("relationship struct not set to correct value") + } + + if x.R.ValidationJobCandles[0] != &a { + t.Error("failed to append to foreign relationship struct") + } + if !queries.Equal(a.ValidationJobID, x.ID) { + t.Error("foreign key was wrong value", a.ValidationJobID) + } + + zero := reflect.Zero(reflect.TypeOf(a.ValidationJobID)) + reflect.Indirect(reflect.ValueOf(&a.ValidationJobID)).Set(zero) + + if err = a.Reload(ctx, tx); err != nil { + t.Fatal("failed to reload", err) + } + + if !queries.Equal(a.ValidationJobID, x.ID) { + t.Error("foreign key was wrong value", a.ValidationJobID, x.ID) + } + } +} + +func testCandleToOneRemoveOpDatahistoryjobUsingValidationJob(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Candle + var b Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = a.SetValidationJob(ctx, tx, true, &b); err != nil { + t.Fatal(err) + } + + if err = a.RemoveValidationJob(ctx, tx, &b); err != nil { + t.Error("failed to remove relationship") + } + + count, err := a.ValidationJob().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 0 { + t.Error("want no relationships remaining") + } + + if a.R.ValidationJob != nil { + t.Error("R struct entry should be nil") + } + + if !queries.IsValuerNil(a.ValidationJobID) { + t.Error("foreign key value should be nil") + } + + if len(b.R.ValidationJobCandles) != 0 { + t.Error("failed to remove a from b's relationships") + } +} func testCandlesReload(t *testing.T) { t.Parallel() @@ -677,7 +996,7 @@ func testCandlesSelect(t *testing.T) { } var ( - candleDBTypes = map[string]string{`ID`: `uuid`, `ExchangeNameID`: `uuid`, `Base`: `character varying`, `Quote`: `character varying`, `Interval`: `bigint`, `Timestamp`: `timestamp with time zone`, `Open`: `double precision`, `High`: `double precision`, `Low`: `double precision`, `Close`: `double precision`, `Volume`: `double precision`, `Asset`: `character varying`} + candleDBTypes = map[string]string{`ID`: `uuid`, `ExchangeNameID`: `uuid`, `Base`: `character varying`, `Quote`: `character varying`, `Interval`: `bigint`, `Timestamp`: `timestamp with time zone`, `Open`: `double precision`, `High`: `double precision`, `Low`: `double precision`, `Close`: `double precision`, `Volume`: `double precision`, `Asset`: `character varying`, `SourceJobID`: `uuid`, `ValidationJobID`: `uuid`, `ValidationIssues`: `text`} _ = bytes.MinRead ) diff --git a/database/models/postgres/datahistoryjob.go b/database/models/postgres/datahistoryjob.go index b875f80a544..79dd3162660 100644 --- a/database/models/postgres/datahistoryjob.go +++ b/database/models/postgres/datahistoryjob.go @@ -19,113 +19,228 @@ import ( "github.com/thrasher-corp/sqlboiler/queries/qm" "github.com/thrasher-corp/sqlboiler/queries/qmhelper" "github.com/thrasher-corp/sqlboiler/strmangle" + "github.com/volatiletech/null" ) // Datahistoryjob is an object representing the database table. type Datahistoryjob struct { - ID string `boil:"id" json:"id" toml:"id" yaml:"id"` - Nickname string `boil:"nickname" json:"nickname" toml:"nickname" yaml:"nickname"` - ExchangeNameID string `boil:"exchange_name_id" json:"exchange_name_id" toml:"exchange_name_id" yaml:"exchange_name_id"` - Asset string `boil:"asset" json:"asset" toml:"asset" yaml:"asset"` - Base string `boil:"base" json:"base" toml:"base" yaml:"base"` - Quote string `boil:"quote" json:"quote" toml:"quote" yaml:"quote"` - StartTime time.Time `boil:"start_time" json:"start_time" toml:"start_time" yaml:"start_time"` - EndTime time.Time `boil:"end_time" json:"end_time" toml:"end_time" yaml:"end_time"` - DataType float64 `boil:"data_type" json:"data_type" toml:"data_type" yaml:"data_type"` - Interval float64 `boil:"interval" json:"interval" toml:"interval" yaml:"interval"` - RequestSize float64 `boil:"request_size" json:"request_size" toml:"request_size" yaml:"request_size"` - MaxRetries float64 `boil:"max_retries" json:"max_retries" toml:"max_retries" yaml:"max_retries"` - BatchCount float64 `boil:"batch_count" json:"batch_count" toml:"batch_count" yaml:"batch_count"` - Status float64 `boil:"status" json:"status" toml:"status" yaml:"status"` - Created time.Time `boil:"created" json:"created" toml:"created" yaml:"created"` + ID string `boil:"id" json:"id" toml:"id" yaml:"id"` + Nickname string `boil:"nickname" json:"nickname" toml:"nickname" yaml:"nickname"` + ExchangeNameID string `boil:"exchange_name_id" json:"exchange_name_id" toml:"exchange_name_id" yaml:"exchange_name_id"` + Asset string `boil:"asset" json:"asset" toml:"asset" yaml:"asset"` + Base string `boil:"base" json:"base" toml:"base" yaml:"base"` + Quote string `boil:"quote" json:"quote" toml:"quote" yaml:"quote"` + StartTime time.Time `boil:"start_time" json:"start_time" toml:"start_time" yaml:"start_time"` + EndTime time.Time `boil:"end_time" json:"end_time" toml:"end_time" yaml:"end_time"` + DataType float64 `boil:"data_type" json:"data_type" toml:"data_type" yaml:"data_type"` + Interval float64 `boil:"interval" json:"interval" toml:"interval" yaml:"interval"` + RequestSize float64 `boil:"request_size" json:"request_size" toml:"request_size" yaml:"request_size"` + MaxRetries float64 `boil:"max_retries" json:"max_retries" toml:"max_retries" yaml:"max_retries"` + BatchCount float64 `boil:"batch_count" json:"batch_count" toml:"batch_count" yaml:"batch_count"` + Status float64 `boil:"status" json:"status" toml:"status" yaml:"status"` + Created time.Time `boil:"created" json:"created" toml:"created" yaml:"created"` + ConversionInterval null.Float64 `boil:"conversion_interval" json:"conversion_interval,omitempty" toml:"conversion_interval" yaml:"conversion_interval,omitempty"` + OverwriteData null.Bool `boil:"overwrite_data" json:"overwrite_data,omitempty" toml:"overwrite_data" yaml:"overwrite_data,omitempty"` + DecimalPlaceComparison null.Int `boil:"decimal_place_comparison" json:"decimal_place_comparison,omitempty" toml:"decimal_place_comparison" yaml:"decimal_place_comparison,omitempty"` + SecondaryExchangeID null.String `boil:"secondary_exchange_id" json:"secondary_exchange_id,omitempty" toml:"secondary_exchange_id" yaml:"secondary_exchange_id,omitempty"` + IssueTolerancePercentage null.Float64 `boil:"issue_tolerance_percentage" json:"issue_tolerance_percentage,omitempty" toml:"issue_tolerance_percentage" yaml:"issue_tolerance_percentage,omitempty"` + ReplaceOnIssue null.Bool `boil:"replace_on_issue" json:"replace_on_issue,omitempty" toml:"replace_on_issue" yaml:"replace_on_issue,omitempty"` R *datahistoryjobR `boil:"-" json:"-" toml:"-" yaml:"-"` L datahistoryjobL `boil:"-" json:"-" toml:"-" yaml:"-"` } var DatahistoryjobColumns = struct { - ID string - Nickname string - ExchangeNameID string - Asset string - Base string - Quote string - StartTime string - EndTime string - DataType string - Interval string - RequestSize string - MaxRetries string - BatchCount string - Status string - Created string + ID string + Nickname string + ExchangeNameID string + Asset string + Base string + Quote string + StartTime string + EndTime string + DataType string + Interval string + RequestSize string + MaxRetries string + BatchCount string + Status string + Created string + ConversionInterval string + OverwriteData string + DecimalPlaceComparison string + SecondaryExchangeID string + IssueTolerancePercentage string + ReplaceOnIssue string }{ - ID: "id", - Nickname: "nickname", - ExchangeNameID: "exchange_name_id", - Asset: "asset", - Base: "base", - Quote: "quote", - StartTime: "start_time", - EndTime: "end_time", - DataType: "data_type", - Interval: "interval", - RequestSize: "request_size", - MaxRetries: "max_retries", - BatchCount: "batch_count", - Status: "status", - Created: "created", + ID: "id", + Nickname: "nickname", + ExchangeNameID: "exchange_name_id", + Asset: "asset", + Base: "base", + Quote: "quote", + StartTime: "start_time", + EndTime: "end_time", + DataType: "data_type", + Interval: "interval", + RequestSize: "request_size", + MaxRetries: "max_retries", + BatchCount: "batch_count", + Status: "status", + Created: "created", + ConversionInterval: "conversion_interval", + OverwriteData: "overwrite_data", + DecimalPlaceComparison: "decimal_place_comparison", + SecondaryExchangeID: "secondary_exchange_id", + IssueTolerancePercentage: "issue_tolerance_percentage", + ReplaceOnIssue: "replace_on_issue", } // Generated where +type whereHelpernull_Float64 struct{ field string } + +func (w whereHelpernull_Float64) EQ(x null.Float64) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, false, x) +} +func (w whereHelpernull_Float64) NEQ(x null.Float64) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, true, x) +} +func (w whereHelpernull_Float64) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } +func (w whereHelpernull_Float64) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } +func (w whereHelpernull_Float64) LT(x null.Float64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpernull_Float64) LTE(x null.Float64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpernull_Float64) GT(x null.Float64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpernull_Float64) GTE(x null.Float64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} + +type whereHelpernull_Bool struct{ field string } + +func (w whereHelpernull_Bool) EQ(x null.Bool) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, false, x) +} +func (w whereHelpernull_Bool) NEQ(x null.Bool) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, true, x) +} +func (w whereHelpernull_Bool) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } +func (w whereHelpernull_Bool) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } +func (w whereHelpernull_Bool) LT(x null.Bool) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpernull_Bool) LTE(x null.Bool) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpernull_Bool) GT(x null.Bool) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpernull_Bool) GTE(x null.Bool) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} + +type whereHelpernull_Int struct{ field string } + +func (w whereHelpernull_Int) EQ(x null.Int) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, false, x) +} +func (w whereHelpernull_Int) NEQ(x null.Int) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, true, x) +} +func (w whereHelpernull_Int) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } +func (w whereHelpernull_Int) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } +func (w whereHelpernull_Int) LT(x null.Int) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpernull_Int) LTE(x null.Int) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpernull_Int) GT(x null.Int) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpernull_Int) GTE(x null.Int) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} + var DatahistoryjobWhere = struct { - ID whereHelperstring - Nickname whereHelperstring - ExchangeNameID whereHelperstring - Asset whereHelperstring - Base whereHelperstring - Quote whereHelperstring - StartTime whereHelpertime_Time - EndTime whereHelpertime_Time - DataType whereHelperfloat64 - Interval whereHelperfloat64 - RequestSize whereHelperfloat64 - MaxRetries whereHelperfloat64 - BatchCount whereHelperfloat64 - Status whereHelperfloat64 - Created whereHelpertime_Time + ID whereHelperstring + Nickname whereHelperstring + ExchangeNameID whereHelperstring + Asset whereHelperstring + Base whereHelperstring + Quote whereHelperstring + StartTime whereHelpertime_Time + EndTime whereHelpertime_Time + DataType whereHelperfloat64 + Interval whereHelperfloat64 + RequestSize whereHelperfloat64 + MaxRetries whereHelperfloat64 + BatchCount whereHelperfloat64 + Status whereHelperfloat64 + Created whereHelpertime_Time + ConversionInterval whereHelpernull_Float64 + OverwriteData whereHelpernull_Bool + DecimalPlaceComparison whereHelpernull_Int + SecondaryExchangeID whereHelpernull_String + IssueTolerancePercentage whereHelpernull_Float64 + ReplaceOnIssue whereHelpernull_Bool }{ - ID: whereHelperstring{field: "\"datahistoryjob\".\"id\""}, - Nickname: whereHelperstring{field: "\"datahistoryjob\".\"nickname\""}, - ExchangeNameID: whereHelperstring{field: "\"datahistoryjob\".\"exchange_name_id\""}, - Asset: whereHelperstring{field: "\"datahistoryjob\".\"asset\""}, - Base: whereHelperstring{field: "\"datahistoryjob\".\"base\""}, - Quote: whereHelperstring{field: "\"datahistoryjob\".\"quote\""}, - StartTime: whereHelpertime_Time{field: "\"datahistoryjob\".\"start_time\""}, - EndTime: whereHelpertime_Time{field: "\"datahistoryjob\".\"end_time\""}, - DataType: whereHelperfloat64{field: "\"datahistoryjob\".\"data_type\""}, - Interval: whereHelperfloat64{field: "\"datahistoryjob\".\"interval\""}, - RequestSize: whereHelperfloat64{field: "\"datahistoryjob\".\"request_size\""}, - MaxRetries: whereHelperfloat64{field: "\"datahistoryjob\".\"max_retries\""}, - BatchCount: whereHelperfloat64{field: "\"datahistoryjob\".\"batch_count\""}, - Status: whereHelperfloat64{field: "\"datahistoryjob\".\"status\""}, - Created: whereHelpertime_Time{field: "\"datahistoryjob\".\"created\""}, + ID: whereHelperstring{field: "\"datahistoryjob\".\"id\""}, + Nickname: whereHelperstring{field: "\"datahistoryjob\".\"nickname\""}, + ExchangeNameID: whereHelperstring{field: "\"datahistoryjob\".\"exchange_name_id\""}, + Asset: whereHelperstring{field: "\"datahistoryjob\".\"asset\""}, + Base: whereHelperstring{field: "\"datahistoryjob\".\"base\""}, + Quote: whereHelperstring{field: "\"datahistoryjob\".\"quote\""}, + StartTime: whereHelpertime_Time{field: "\"datahistoryjob\".\"start_time\""}, + EndTime: whereHelpertime_Time{field: "\"datahistoryjob\".\"end_time\""}, + DataType: whereHelperfloat64{field: "\"datahistoryjob\".\"data_type\""}, + Interval: whereHelperfloat64{field: "\"datahistoryjob\".\"interval\""}, + RequestSize: whereHelperfloat64{field: "\"datahistoryjob\".\"request_size\""}, + MaxRetries: whereHelperfloat64{field: "\"datahistoryjob\".\"max_retries\""}, + BatchCount: whereHelperfloat64{field: "\"datahistoryjob\".\"batch_count\""}, + Status: whereHelperfloat64{field: "\"datahistoryjob\".\"status\""}, + Created: whereHelpertime_Time{field: "\"datahistoryjob\".\"created\""}, + ConversionInterval: whereHelpernull_Float64{field: "\"datahistoryjob\".\"conversion_interval\""}, + OverwriteData: whereHelpernull_Bool{field: "\"datahistoryjob\".\"overwrite_data\""}, + DecimalPlaceComparison: whereHelpernull_Int{field: "\"datahistoryjob\".\"decimal_place_comparison\""}, + SecondaryExchangeID: whereHelpernull_String{field: "\"datahistoryjob\".\"secondary_exchange_id\""}, + IssueTolerancePercentage: whereHelpernull_Float64{field: "\"datahistoryjob\".\"issue_tolerance_percentage\""}, + ReplaceOnIssue: whereHelpernull_Bool{field: "\"datahistoryjob\".\"replace_on_issue\""}, } // DatahistoryjobRels is where relationship names are stored. var DatahistoryjobRels = struct { - ExchangeName string - JobDatahistoryjobresults string + ExchangeName string + SecondaryExchange string + SourceJobCandles string + ValidationJobCandles string + PrerequisiteJobDatahistoryjobs string + JobDatahistoryjobs string + JobDatahistoryjobresults string }{ - ExchangeName: "ExchangeName", - JobDatahistoryjobresults: "JobDatahistoryjobresults", + ExchangeName: "ExchangeName", + SecondaryExchange: "SecondaryExchange", + SourceJobCandles: "SourceJobCandles", + ValidationJobCandles: "ValidationJobCandles", + PrerequisiteJobDatahistoryjobs: "PrerequisiteJobDatahistoryjobs", + JobDatahistoryjobs: "JobDatahistoryjobs", + JobDatahistoryjobresults: "JobDatahistoryjobresults", } // datahistoryjobR is where relationships are stored. type datahistoryjobR struct { - ExchangeName *Exchange - JobDatahistoryjobresults DatahistoryjobresultSlice + ExchangeName *Exchange + SecondaryExchange *Exchange + SourceJobCandles CandleSlice + ValidationJobCandles CandleSlice + PrerequisiteJobDatahistoryjobs DatahistoryjobSlice + JobDatahistoryjobs DatahistoryjobSlice + JobDatahistoryjobresults DatahistoryjobresultSlice } // NewStruct creates a new relationship struct @@ -137,8 +252,8 @@ func (*datahistoryjobR) NewStruct() *datahistoryjobR { type datahistoryjobL struct{} var ( - datahistoryjobAllColumns = []string{"id", "nickname", "exchange_name_id", "asset", "base", "quote", "start_time", "end_time", "data_type", "interval", "request_size", "max_retries", "batch_count", "status", "created"} - datahistoryjobColumnsWithoutDefault = []string{"nickname", "exchange_name_id", "asset", "base", "quote", "start_time", "end_time", "data_type", "interval", "request_size", "max_retries", "batch_count", "status", "created"} + datahistoryjobAllColumns = []string{"id", "nickname", "exchange_name_id", "asset", "base", "quote", "start_time", "end_time", "data_type", "interval", "request_size", "max_retries", "batch_count", "status", "created", "conversion_interval", "overwrite_data", "decimal_place_comparison", "secondary_exchange_id", "issue_tolerance_percentage", "replace_on_issue"} + datahistoryjobColumnsWithoutDefault = []string{"nickname", "exchange_name_id", "asset", "base", "quote", "start_time", "end_time", "data_type", "interval", "request_size", "max_retries", "batch_count", "status", "created", "conversion_interval", "overwrite_data", "decimal_place_comparison", "secondary_exchange_id", "issue_tolerance_percentage", "replace_on_issue"} datahistoryjobColumnsWithDefault = []string{"id"} datahistoryjobPrimaryKeyColumns = []string{"id"} ) @@ -432,6 +547,106 @@ func (o *Datahistoryjob) ExchangeName(mods ...qm.QueryMod) exchangeQuery { return query } +// SecondaryExchange pointed to by the foreign key. +func (o *Datahistoryjob) SecondaryExchange(mods ...qm.QueryMod) exchangeQuery { + queryMods := []qm.QueryMod{ + qm.Where("\"id\" = ?", o.SecondaryExchangeID), + } + + queryMods = append(queryMods, mods...) + + query := Exchanges(queryMods...) + queries.SetFrom(query.Query, "\"exchange\"") + + return query +} + +// SourceJobCandles retrieves all the candle's Candles with an executor via source_job_id column. +func (o *Datahistoryjob) SourceJobCandles(mods ...qm.QueryMod) candleQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.Where("\"candle\".\"source_job_id\"=?", o.ID), + ) + + query := Candles(queryMods...) + queries.SetFrom(query.Query, "\"candle\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"candle\".*"}) + } + + return query +} + +// ValidationJobCandles retrieves all the candle's Candles with an executor via validation_job_id column. +func (o *Datahistoryjob) ValidationJobCandles(mods ...qm.QueryMod) candleQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.Where("\"candle\".\"validation_job_id\"=?", o.ID), + ) + + query := Candles(queryMods...) + queries.SetFrom(query.Query, "\"candle\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"candle\".*"}) + } + + return query +} + +// PrerequisiteJobDatahistoryjobs retrieves all the datahistoryjob's Datahistoryjobs with an executor via id column. +func (o *Datahistoryjob) PrerequisiteJobDatahistoryjobs(mods ...qm.QueryMod) datahistoryjobQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.InnerJoin("\"datahistoryjobrelations\" on \"datahistoryjob\".\"id\" = \"datahistoryjobrelations\".\"prerequisite_job_id\""), + qm.Where("\"datahistoryjobrelations\".\"job_id\"=?", o.ID), + ) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"datahistoryjob\".*"}) + } + + return query +} + +// JobDatahistoryjobs retrieves all the datahistoryjob's Datahistoryjobs with an executor via id column. +func (o *Datahistoryjob) JobDatahistoryjobs(mods ...qm.QueryMod) datahistoryjobQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.InnerJoin("\"datahistoryjobrelations\" on \"datahistoryjob\".\"id\" = \"datahistoryjobrelations\".\"job_id\""), + qm.Where("\"datahistoryjobrelations\".\"prerequisite_job_id\"=?", o.ID), + ) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"datahistoryjob\".*"}) + } + + return query +} + // JobDatahistoryjobresults retrieves all the datahistoryjobresult's Datahistoryjobresults with an executor via job_id column. func (o *Datahistoryjob) JobDatahistoryjobresults(mods ...qm.QueryMod) datahistoryjobresultQuery { var queryMods []qm.QueryMod @@ -554,9 +769,9 @@ func (datahistoryjobL) LoadExchangeName(ctx context.Context, e boil.ContextExecu return nil } -// LoadJobDatahistoryjobresults allows an eager lookup of values, cached into the -// loaded structs of the objects. This is for a 1-M or N-M relationship. -func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { +// LoadSecondaryExchange allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for an N-1 relationship. +func (datahistoryjobL) LoadSecondaryExchange(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { var slice []*Datahistoryjob var object *Datahistoryjob @@ -571,7 +786,10 @@ func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil. if object.R == nil { object.R = &datahistoryjobR{} } - args = append(args, object.ID) + if !queries.IsNil(object.SecondaryExchangeID) { + args = append(args, object.SecondaryExchangeID) + } + } else { Outer: for _, obj := range slice { @@ -580,12 +798,15 @@ func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil. } for _, a := range args { - if a == obj.ID { + if queries.Equal(a, obj.SecondaryExchangeID) { continue Outer } } - args = append(args, obj.ID) + if !queries.IsNil(obj.SecondaryExchangeID) { + args = append(args, obj.SecondaryExchangeID) + } + } } @@ -593,54 +814,58 @@ func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil. return nil } - query := NewQuery(qm.From(`datahistoryjobresult`), qm.WhereIn(`datahistoryjobresult.job_id in ?`, args...)) + query := NewQuery(qm.From(`exchange`), qm.WhereIn(`exchange.id in ?`, args...)) if mods != nil { mods.Apply(query) } results, err := query.QueryContext(ctx, e) if err != nil { - return errors.Wrap(err, "failed to eager load datahistoryjobresult") + return errors.Wrap(err, "failed to eager load Exchange") } - var resultSlice []*Datahistoryjobresult + var resultSlice []*Exchange if err = queries.Bind(results, &resultSlice); err != nil { - return errors.Wrap(err, "failed to bind eager loaded slice datahistoryjobresult") + return errors.Wrap(err, "failed to bind eager loaded slice Exchange") } if err = results.Close(); err != nil { - return errors.Wrap(err, "failed to close results in eager load on datahistoryjobresult") + return errors.Wrap(err, "failed to close results of eager load for exchange") } if err = results.Err(); err != nil { - return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjobresult") + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for exchange") } - if len(datahistoryjobresultAfterSelectHooks) != 0 { + if len(datahistoryjobAfterSelectHooks) != 0 { for _, obj := range resultSlice { if err := obj.doAfterSelectHooks(ctx, e); err != nil { return err } } } + + if len(resultSlice) == 0 { + return nil + } + if singular { - object.R.JobDatahistoryjobresults = resultSlice - for _, foreign := range resultSlice { - if foreign.R == nil { - foreign.R = &datahistoryjobresultR{} - } - foreign.R.Job = object + foreign := resultSlice[0] + object.R.SecondaryExchange = foreign + if foreign.R == nil { + foreign.R = &exchangeR{} } + foreign.R.SecondaryExchangeDatahistoryjobs = append(foreign.R.SecondaryExchangeDatahistoryjobs, object) return nil } - for _, foreign := range resultSlice { - for _, local := range slice { - if local.ID == foreign.JobID { - local.R.JobDatahistoryjobresults = append(local.R.JobDatahistoryjobresults, foreign) + for _, local := range slice { + for _, foreign := range resultSlice { + if queries.Equal(local.SecondaryExchangeID, foreign.ID) { + local.R.SecondaryExchange = foreign if foreign.R == nil { - foreign.R = &datahistoryjobresultR{} + foreign.R = &exchangeR{} } - foreign.R.Job = local + foreign.R.SecondaryExchangeDatahistoryjobs = append(foreign.R.SecondaryExchangeDatahistoryjobs, local) break } } @@ -649,53 +874,1172 @@ func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil. return nil } -// SetExchangeName of the datahistoryjob to the related item. -// Sets o.R.ExchangeName to related. -// Adds o to related.R.ExchangeNameDatahistoryjobs. -func (o *Datahistoryjob) SetExchangeName(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Exchange) error { - var err error - if insert { - if err = related.Insert(ctx, exec, boil.Infer()); err != nil { - return errors.Wrap(err, "failed to insert into foreign table") +// LoadSourceJobCandles allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (datahistoryjobL) LoadSourceJobCandles(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob + + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } + + for _, a := range args { + if queries.Equal(a, obj.ID) { + continue Outer + } + } + + args = append(args, obj.ID) } } - updateQuery := fmt.Sprintf( - "UPDATE \"datahistoryjob\" SET %s WHERE %s", - strmangle.SetParamNames("\"", "\"", 1, []string{"exchange_name_id"}), - strmangle.WhereClause("\"", "\"", 2, datahistoryjobPrimaryKeyColumns), - ) - values := []interface{}{related.ID, o.ID} + if len(args) == 0 { + return nil + } - if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, updateQuery) - fmt.Fprintln(boil.DebugWriter, values) + query := NewQuery(qm.From(`candle`), qm.WhereIn(`candle.source_job_id in ?`, args...)) + if mods != nil { + mods.Apply(query) } - if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { - return errors.Wrap(err, "failed to update local table") + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load candle") } - o.ExchangeNameID = related.ID - if o.R == nil { - o.R = &datahistoryjobR{ - ExchangeName: related, + var resultSlice []*Candle + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice candle") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on candle") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for candle") + } + + if len(candleAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } } - } else { - o.R.ExchangeName = related + } + if singular { + object.R.SourceJobCandles = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &candleR{} + } + foreign.R.SourceJob = object + } + return nil } - if related.R == nil { - related.R = &exchangeR{ - ExchangeNameDatahistoryjobs: DatahistoryjobSlice{o}, + for _, foreign := range resultSlice { + for _, local := range slice { + if queries.Equal(local.ID, foreign.SourceJobID) { + local.R.SourceJobCandles = append(local.R.SourceJobCandles, foreign) + if foreign.R == nil { + foreign.R = &candleR{} + } + foreign.R.SourceJob = local + break + } } - } else { - related.R.ExchangeNameDatahistoryjobs = append(related.R.ExchangeNameDatahistoryjobs, o) } return nil } +// LoadValidationJobCandles allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (datahistoryjobL) LoadValidationJobCandles(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob + + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } + + for _, a := range args { + if queries.Equal(a, obj.ID) { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`candle`), qm.WhereIn(`candle.validation_job_id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load candle") + } + + var resultSlice []*Candle + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice candle") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on candle") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for candle") + } + + if len(candleAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.ValidationJobCandles = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &candleR{} + } + foreign.R.ValidationJob = object + } + return nil + } + + for _, foreign := range resultSlice { + for _, local := range slice { + if queries.Equal(local.ID, foreign.ValidationJobID) { + local.R.ValidationJobCandles = append(local.R.ValidationJobCandles, foreign) + if foreign.R == nil { + foreign.R = &candleR{} + } + foreign.R.ValidationJob = local + break + } + } + } + + return nil +} + +// LoadPrerequisiteJobDatahistoryjobs allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (datahistoryjobL) LoadPrerequisiteJobDatahistoryjobs(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob + + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } + + for _, a := range args { + if a == obj.ID { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery( + qm.Select("\"datahistoryjob\".*, \"a\".\"job_id\""), + qm.From("\"datahistoryjob\""), + qm.InnerJoin("\"datahistoryjobrelations\" as \"a\" on \"datahistoryjob\".\"id\" = \"a\".\"prerequisite_job_id\""), + qm.WhereIn("\"a\".\"job_id\" in ?", args...), + ) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load datahistoryjob") + } + + var resultSlice []*Datahistoryjob + + var localJoinCols []string + for results.Next() { + one := new(Datahistoryjob) + var localJoinCol string + + err = results.Scan(&one.ID, &one.Nickname, &one.ExchangeNameID, &one.Asset, &one.Base, &one.Quote, &one.StartTime, &one.EndTime, &one.DataType, &one.Interval, &one.RequestSize, &one.MaxRetries, &one.BatchCount, &one.Status, &one.Created, &one.ConversionInterval, &one.OverwriteData, &one.DecimalPlaceComparison, &one.SecondaryExchangeID, &one.IssueTolerancePercentage, &one.ReplaceOnIssue, &localJoinCol) + if err != nil { + return errors.Wrap(err, "failed to scan eager loaded results for datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "failed to plebian-bind eager loaded slice datahistoryjob") + } + + resultSlice = append(resultSlice, one) + localJoinCols = append(localJoinCols, localJoinCol) + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(datahistoryjobAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.PrerequisiteJobDatahistoryjobs = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.JobDatahistoryjobs = append(foreign.R.JobDatahistoryjobs, object) + } + return nil + } + + for i, foreign := range resultSlice { + localJoinCol := localJoinCols[i] + for _, local := range slice { + if local.ID == localJoinCol { + local.R.PrerequisiteJobDatahistoryjobs = append(local.R.PrerequisiteJobDatahistoryjobs, foreign) + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.JobDatahistoryjobs = append(foreign.R.JobDatahistoryjobs, local) + break + } + } + } + + return nil +} + +// LoadJobDatahistoryjobs allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (datahistoryjobL) LoadJobDatahistoryjobs(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob + + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } + + for _, a := range args { + if a == obj.ID { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery( + qm.Select("\"datahistoryjob\".*, \"a\".\"prerequisite_job_id\""), + qm.From("\"datahistoryjob\""), + qm.InnerJoin("\"datahistoryjobrelations\" as \"a\" on \"datahistoryjob\".\"id\" = \"a\".\"job_id\""), + qm.WhereIn("\"a\".\"prerequisite_job_id\" in ?", args...), + ) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load datahistoryjob") + } + + var resultSlice []*Datahistoryjob + + var localJoinCols []string + for results.Next() { + one := new(Datahistoryjob) + var localJoinCol string + + err = results.Scan(&one.ID, &one.Nickname, &one.ExchangeNameID, &one.Asset, &one.Base, &one.Quote, &one.StartTime, &one.EndTime, &one.DataType, &one.Interval, &one.RequestSize, &one.MaxRetries, &one.BatchCount, &one.Status, &one.Created, &one.ConversionInterval, &one.OverwriteData, &one.DecimalPlaceComparison, &one.SecondaryExchangeID, &one.IssueTolerancePercentage, &one.ReplaceOnIssue, &localJoinCol) + if err != nil { + return errors.Wrap(err, "failed to scan eager loaded results for datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "failed to plebian-bind eager loaded slice datahistoryjob") + } + + resultSlice = append(resultSlice, one) + localJoinCols = append(localJoinCols, localJoinCol) + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(datahistoryjobAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.JobDatahistoryjobs = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.PrerequisiteJobDatahistoryjobs = append(foreign.R.PrerequisiteJobDatahistoryjobs, object) + } + return nil + } + + for i, foreign := range resultSlice { + localJoinCol := localJoinCols[i] + for _, local := range slice { + if local.ID == localJoinCol { + local.R.JobDatahistoryjobs = append(local.R.JobDatahistoryjobs, foreign) + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.PrerequisiteJobDatahistoryjobs = append(foreign.R.PrerequisiteJobDatahistoryjobs, local) + break + } + } + } + + return nil +} + +// LoadJobDatahistoryjobresults allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob + + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } + + for _, a := range args { + if a == obj.ID { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`datahistoryjobresult`), qm.WhereIn(`datahistoryjobresult.job_id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load datahistoryjobresult") + } + + var resultSlice []*Datahistoryjobresult + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice datahistoryjobresult") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on datahistoryjobresult") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjobresult") + } + + if len(datahistoryjobresultAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.JobDatahistoryjobresults = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &datahistoryjobresultR{} + } + foreign.R.Job = object + } + return nil + } + + for _, foreign := range resultSlice { + for _, local := range slice { + if local.ID == foreign.JobID { + local.R.JobDatahistoryjobresults = append(local.R.JobDatahistoryjobresults, foreign) + if foreign.R == nil { + foreign.R = &datahistoryjobresultR{} + } + foreign.R.Job = local + break + } + } + } + + return nil +} + +// SetExchangeName of the datahistoryjob to the related item. +// Sets o.R.ExchangeName to related. +// Adds o to related.R.ExchangeNameDatahistoryjobs. +func (o *Datahistoryjob) SetExchangeName(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Exchange) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"datahistoryjob\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"exchange_name_id"}), + strmangle.WhereClause("\"", "\"", 2, datahistoryjobPrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + o.ExchangeNameID = related.ID + if o.R == nil { + o.R = &datahistoryjobR{ + ExchangeName: related, + } + } else { + o.R.ExchangeName = related + } + + if related.R == nil { + related.R = &exchangeR{ + ExchangeNameDatahistoryjobs: DatahistoryjobSlice{o}, + } + } else { + related.R.ExchangeNameDatahistoryjobs = append(related.R.ExchangeNameDatahistoryjobs, o) + } + + return nil +} + +// SetSecondaryExchange of the datahistoryjob to the related item. +// Sets o.R.SecondaryExchange to related. +// Adds o to related.R.SecondaryExchangeDatahistoryjobs. +func (o *Datahistoryjob) SetSecondaryExchange(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Exchange) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"datahistoryjob\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"secondary_exchange_id"}), + strmangle.WhereClause("\"", "\"", 2, datahistoryjobPrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + queries.Assign(&o.SecondaryExchangeID, related.ID) + if o.R == nil { + o.R = &datahistoryjobR{ + SecondaryExchange: related, + } + } else { + o.R.SecondaryExchange = related + } + + if related.R == nil { + related.R = &exchangeR{ + SecondaryExchangeDatahistoryjobs: DatahistoryjobSlice{o}, + } + } else { + related.R.SecondaryExchangeDatahistoryjobs = append(related.R.SecondaryExchangeDatahistoryjobs, o) + } + + return nil +} + +// RemoveSecondaryExchange relationship. +// Sets o.R.SecondaryExchange to nil. +// Removes o from all passed in related items' relationships struct (Optional). +func (o *Datahistoryjob) RemoveSecondaryExchange(ctx context.Context, exec boil.ContextExecutor, related *Exchange) error { + var err error + + queries.SetScanner(&o.SecondaryExchangeID, nil) + if _, err = o.Update(ctx, exec, boil.Whitelist("secondary_exchange_id")); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + o.R.SecondaryExchange = nil + if related == nil || related.R == nil { + return nil + } + + for i, ri := range related.R.SecondaryExchangeDatahistoryjobs { + if queries.Equal(o.SecondaryExchangeID, ri.SecondaryExchangeID) { + continue + } + + ln := len(related.R.SecondaryExchangeDatahistoryjobs) + if ln > 1 && i < ln-1 { + related.R.SecondaryExchangeDatahistoryjobs[i] = related.R.SecondaryExchangeDatahistoryjobs[ln-1] + } + related.R.SecondaryExchangeDatahistoryjobs = related.R.SecondaryExchangeDatahistoryjobs[:ln-1] + break + } + return nil +} + +// AddSourceJobCandles adds the given related objects to the existing relationships +// of the datahistoryjob, optionally inserting them as new records. +// Appends related to o.R.SourceJobCandles. +// Sets related.R.SourceJob appropriately. +func (o *Datahistoryjob) AddSourceJobCandles(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Candle) error { + var err error + for _, rel := range related { + if insert { + queries.Assign(&rel.SourceJobID, o.ID) + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } else { + updateQuery := fmt.Sprintf( + "UPDATE \"candle\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"source_job_id"}), + strmangle.WhereClause("\"", "\"", 2, candlePrimaryKeyColumns), + ) + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update foreign table") + } + + queries.Assign(&rel.SourceJobID, o.ID) + } + } + + if o.R == nil { + o.R = &datahistoryjobR{ + SourceJobCandles: related, + } + } else { + o.R.SourceJobCandles = append(o.R.SourceJobCandles, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &candleR{ + SourceJob: o, + } + } else { + rel.R.SourceJob = o + } + } + return nil +} + +// SetSourceJobCandles removes all previously related items of the +// datahistoryjob replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.SourceJob's SourceJobCandles accordingly. +// Replaces o.R.SourceJobCandles with related. +// Sets related.R.SourceJob's SourceJobCandles accordingly. +func (o *Datahistoryjob) SetSourceJobCandles(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Candle) error { + query := "update \"candle\" set \"source_job_id\" = null where \"source_job_id\" = $1" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + if o.R != nil { + for _, rel := range o.R.SourceJobCandles { + queries.SetScanner(&rel.SourceJobID, nil) + if rel.R == nil { + continue + } + + rel.R.SourceJob = nil + } + + o.R.SourceJobCandles = nil + } + return o.AddSourceJobCandles(ctx, exec, insert, related...) +} + +// RemoveSourceJobCandles relationships from objects passed in. +// Removes related items from R.SourceJobCandles (uses pointer comparison, removal does not keep order) +// Sets related.R.SourceJob. +func (o *Datahistoryjob) RemoveSourceJobCandles(ctx context.Context, exec boil.ContextExecutor, related ...*Candle) error { + var err error + for _, rel := range related { + queries.SetScanner(&rel.SourceJobID, nil) + if rel.R != nil { + rel.R.SourceJob = nil + } + if _, err = rel.Update(ctx, exec, boil.Whitelist("source_job_id")); err != nil { + return err + } + } + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.SourceJobCandles { + if rel != ri { + continue + } + + ln := len(o.R.SourceJobCandles) + if ln > 1 && i < ln-1 { + o.R.SourceJobCandles[i] = o.R.SourceJobCandles[ln-1] + } + o.R.SourceJobCandles = o.R.SourceJobCandles[:ln-1] + break + } + } + + return nil +} + +// AddValidationJobCandles adds the given related objects to the existing relationships +// of the datahistoryjob, optionally inserting them as new records. +// Appends related to o.R.ValidationJobCandles. +// Sets related.R.ValidationJob appropriately. +func (o *Datahistoryjob) AddValidationJobCandles(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Candle) error { + var err error + for _, rel := range related { + if insert { + queries.Assign(&rel.ValidationJobID, o.ID) + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } else { + updateQuery := fmt.Sprintf( + "UPDATE \"candle\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"validation_job_id"}), + strmangle.WhereClause("\"", "\"", 2, candlePrimaryKeyColumns), + ) + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update foreign table") + } + + queries.Assign(&rel.ValidationJobID, o.ID) + } + } + + if o.R == nil { + o.R = &datahistoryjobR{ + ValidationJobCandles: related, + } + } else { + o.R.ValidationJobCandles = append(o.R.ValidationJobCandles, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &candleR{ + ValidationJob: o, + } + } else { + rel.R.ValidationJob = o + } + } + return nil +} + +// SetValidationJobCandles removes all previously related items of the +// datahistoryjob replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.ValidationJob's ValidationJobCandles accordingly. +// Replaces o.R.ValidationJobCandles with related. +// Sets related.R.ValidationJob's ValidationJobCandles accordingly. +func (o *Datahistoryjob) SetValidationJobCandles(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Candle) error { + query := "update \"candle\" set \"validation_job_id\" = null where \"validation_job_id\" = $1" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + if o.R != nil { + for _, rel := range o.R.ValidationJobCandles { + queries.SetScanner(&rel.ValidationJobID, nil) + if rel.R == nil { + continue + } + + rel.R.ValidationJob = nil + } + + o.R.ValidationJobCandles = nil + } + return o.AddValidationJobCandles(ctx, exec, insert, related...) +} + +// RemoveValidationJobCandles relationships from objects passed in. +// Removes related items from R.ValidationJobCandles (uses pointer comparison, removal does not keep order) +// Sets related.R.ValidationJob. +func (o *Datahistoryjob) RemoveValidationJobCandles(ctx context.Context, exec boil.ContextExecutor, related ...*Candle) error { + var err error + for _, rel := range related { + queries.SetScanner(&rel.ValidationJobID, nil) + if rel.R != nil { + rel.R.ValidationJob = nil + } + if _, err = rel.Update(ctx, exec, boil.Whitelist("validation_job_id")); err != nil { + return err + } + } + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.ValidationJobCandles { + if rel != ri { + continue + } + + ln := len(o.R.ValidationJobCandles) + if ln > 1 && i < ln-1 { + o.R.ValidationJobCandles[i] = o.R.ValidationJobCandles[ln-1] + } + o.R.ValidationJobCandles = o.R.ValidationJobCandles[:ln-1] + break + } + } + + return nil +} + +// AddPrerequisiteJobDatahistoryjobs adds the given related objects to the existing relationships +// of the datahistoryjob, optionally inserting them as new records. +// Appends related to o.R.PrerequisiteJobDatahistoryjobs. +// Sets related.R.JobDatahistoryjobs appropriately. +func (o *Datahistoryjob) AddPrerequisiteJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + var err error + for _, rel := range related { + if insert { + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + } + + for _, rel := range related { + query := "insert into \"datahistoryjobrelations\" (\"job_id\", \"prerequisite_job_id\") values ($1, $2)" + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err = exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to insert into join table") + } + } + if o.R == nil { + o.R = &datahistoryjobR{ + PrerequisiteJobDatahistoryjobs: related, + } + } else { + o.R.PrerequisiteJobDatahistoryjobs = append(o.R.PrerequisiteJobDatahistoryjobs, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &datahistoryjobR{ + JobDatahistoryjobs: DatahistoryjobSlice{o}, + } + } else { + rel.R.JobDatahistoryjobs = append(rel.R.JobDatahistoryjobs, o) + } + } + return nil +} + +// SetPrerequisiteJobDatahistoryjobs removes all previously related items of the +// datahistoryjob replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.JobDatahistoryjobs's PrerequisiteJobDatahistoryjobs accordingly. +// Replaces o.R.PrerequisiteJobDatahistoryjobs with related. +// Sets related.R.JobDatahistoryjobs's PrerequisiteJobDatahistoryjobs accordingly. +func (o *Datahistoryjob) SetPrerequisiteJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + query := "delete from \"datahistoryjobrelations\" where \"job_id\" = $1" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + removePrerequisiteJobDatahistoryjobsFromJobDatahistoryjobsSlice(o, related) + if o.R != nil { + o.R.PrerequisiteJobDatahistoryjobs = nil + } + return o.AddPrerequisiteJobDatahistoryjobs(ctx, exec, insert, related...) +} + +// RemovePrerequisiteJobDatahistoryjobs relationships from objects passed in. +// Removes related items from R.PrerequisiteJobDatahistoryjobs (uses pointer comparison, removal does not keep order) +// Sets related.R.JobDatahistoryjobs. +func (o *Datahistoryjob) RemovePrerequisiteJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, related ...*Datahistoryjob) error { + var err error + query := fmt.Sprintf( + "delete from \"datahistoryjobrelations\" where \"job_id\" = $1 and \"prerequisite_job_id\" in (%s)", + strmangle.Placeholders(dialect.UseIndexPlaceholders, len(related), 2, 1), + ) + values := []interface{}{o.ID} + for _, rel := range related { + values = append(values, rel.ID) + } + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err = exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + removePrerequisiteJobDatahistoryjobsFromJobDatahistoryjobsSlice(o, related) + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.PrerequisiteJobDatahistoryjobs { + if rel != ri { + continue + } + + ln := len(o.R.PrerequisiteJobDatahistoryjobs) + if ln > 1 && i < ln-1 { + o.R.PrerequisiteJobDatahistoryjobs[i] = o.R.PrerequisiteJobDatahistoryjobs[ln-1] + } + o.R.PrerequisiteJobDatahistoryjobs = o.R.PrerequisiteJobDatahistoryjobs[:ln-1] + break + } + } + + return nil +} + +func removePrerequisiteJobDatahistoryjobsFromJobDatahistoryjobsSlice(o *Datahistoryjob, related []*Datahistoryjob) { + for _, rel := range related { + if rel.R == nil { + continue + } + for i, ri := range rel.R.JobDatahistoryjobs { + if o.ID != ri.ID { + continue + } + + ln := len(rel.R.JobDatahistoryjobs) + if ln > 1 && i < ln-1 { + rel.R.JobDatahistoryjobs[i] = rel.R.JobDatahistoryjobs[ln-1] + } + rel.R.JobDatahistoryjobs = rel.R.JobDatahistoryjobs[:ln-1] + break + } + } +} + +// AddJobDatahistoryjobs adds the given related objects to the existing relationships +// of the datahistoryjob, optionally inserting them as new records. +// Appends related to o.R.JobDatahistoryjobs. +// Sets related.R.PrerequisiteJobDatahistoryjobs appropriately. +func (o *Datahistoryjob) AddJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + var err error + for _, rel := range related { + if insert { + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + } + + for _, rel := range related { + query := "insert into \"datahistoryjobrelations\" (\"prerequisite_job_id\", \"job_id\") values ($1, $2)" + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err = exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to insert into join table") + } + } + if o.R == nil { + o.R = &datahistoryjobR{ + JobDatahistoryjobs: related, + } + } else { + o.R.JobDatahistoryjobs = append(o.R.JobDatahistoryjobs, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &datahistoryjobR{ + PrerequisiteJobDatahistoryjobs: DatahistoryjobSlice{o}, + } + } else { + rel.R.PrerequisiteJobDatahistoryjobs = append(rel.R.PrerequisiteJobDatahistoryjobs, o) + } + } + return nil +} + +// SetJobDatahistoryjobs removes all previously related items of the +// datahistoryjob replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.PrerequisiteJobDatahistoryjobs's JobDatahistoryjobs accordingly. +// Replaces o.R.JobDatahistoryjobs with related. +// Sets related.R.PrerequisiteJobDatahistoryjobs's JobDatahistoryjobs accordingly. +func (o *Datahistoryjob) SetJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + query := "delete from \"datahistoryjobrelations\" where \"prerequisite_job_id\" = $1" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + removeJobDatahistoryjobsFromPrerequisiteJobDatahistoryjobsSlice(o, related) + if o.R != nil { + o.R.JobDatahistoryjobs = nil + } + return o.AddJobDatahistoryjobs(ctx, exec, insert, related...) +} + +// RemoveJobDatahistoryjobs relationships from objects passed in. +// Removes related items from R.JobDatahistoryjobs (uses pointer comparison, removal does not keep order) +// Sets related.R.PrerequisiteJobDatahistoryjobs. +func (o *Datahistoryjob) RemoveJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, related ...*Datahistoryjob) error { + var err error + query := fmt.Sprintf( + "delete from \"datahistoryjobrelations\" where \"prerequisite_job_id\" = $1 and \"job_id\" in (%s)", + strmangle.Placeholders(dialect.UseIndexPlaceholders, len(related), 2, 1), + ) + values := []interface{}{o.ID} + for _, rel := range related { + values = append(values, rel.ID) + } + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err = exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + removeJobDatahistoryjobsFromPrerequisiteJobDatahistoryjobsSlice(o, related) + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.JobDatahistoryjobs { + if rel != ri { + continue + } + + ln := len(o.R.JobDatahistoryjobs) + if ln > 1 && i < ln-1 { + o.R.JobDatahistoryjobs[i] = o.R.JobDatahistoryjobs[ln-1] + } + o.R.JobDatahistoryjobs = o.R.JobDatahistoryjobs[:ln-1] + break + } + } + + return nil +} + +func removeJobDatahistoryjobsFromPrerequisiteJobDatahistoryjobsSlice(o *Datahistoryjob, related []*Datahistoryjob) { + for _, rel := range related { + if rel.R == nil { + continue + } + for i, ri := range rel.R.PrerequisiteJobDatahistoryjobs { + if o.ID != ri.ID { + continue + } + + ln := len(rel.R.PrerequisiteJobDatahistoryjobs) + if ln > 1 && i < ln-1 { + rel.R.PrerequisiteJobDatahistoryjobs[i] = rel.R.PrerequisiteJobDatahistoryjobs[ln-1] + } + rel.R.PrerequisiteJobDatahistoryjobs = rel.R.PrerequisiteJobDatahistoryjobs[:ln-1] + break + } + } +} + // AddJobDatahistoryjobresults adds the given related objects to the existing relationships // of the datahistoryjob, optionally inserting them as new records. // Appends related to o.R.JobDatahistoryjobresults. diff --git a/database/models/postgres/datahistoryjob_test.go b/database/models/postgres/datahistoryjob_test.go index 1b8d954ad87..131df78aab3 100644 --- a/database/models/postgres/datahistoryjob_test.go +++ b/database/models/postgres/datahistoryjob_test.go @@ -494,6 +494,328 @@ func testDatahistoryjobsInsertWhitelist(t *testing.T) { } } +func testDatahistoryjobToManySourceJobCandles(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, candleDBTypes, false, candleColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, candleDBTypes, false, candleColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + queries.Assign(&b.SourceJobID, a.ID) + queries.Assign(&c.SourceJobID, a.ID) + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := a.SourceJobCandles().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if queries.Equal(v.SourceJobID, b.SourceJobID) { + bFound = true + } + if queries.Equal(v.SourceJobID, c.SourceJobID) { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadSourceJobCandles(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.SourceJobCandles); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.SourceJobCandles = nil + if err = a.L.LoadSourceJobCandles(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.SourceJobCandles); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + +func testDatahistoryjobToManyValidationJobCandles(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, candleDBTypes, false, candleColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, candleDBTypes, false, candleColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + queries.Assign(&b.ValidationJobID, a.ID) + queries.Assign(&c.ValidationJobID, a.ID) + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := a.ValidationJobCandles().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if queries.Equal(v.ValidationJobID, b.ValidationJobID) { + bFound = true + } + if queries.Equal(v.ValidationJobID, c.ValidationJobID) { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadValidationJobCandles(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.ValidationJobCandles); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.ValidationJobCandles = nil + if err = a.L.LoadValidationJobCandles(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.ValidationJobCandles); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + +func testDatahistoryjobToManyPrerequisiteJobDatahistoryjobs(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + _, err = tx.Exec("insert into \"datahistoryjobrelations\" (\"job_id\", \"prerequisite_job_id\") values ($1, $2)", a.ID, b.ID) + if err != nil { + t.Fatal(err) + } + _, err = tx.Exec("insert into \"datahistoryjobrelations\" (\"job_id\", \"prerequisite_job_id\") values ($1, $2)", a.ID, c.ID) + if err != nil { + t.Fatal(err) + } + + check, err := a.PrerequisiteJobDatahistoryjobs().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if v.ID == b.ID { + bFound = true + } + if v.ID == c.ID { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadPrerequisiteJobDatahistoryjobs(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.PrerequisiteJobDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.PrerequisiteJobDatahistoryjobs = nil + if err = a.L.LoadPrerequisiteJobDatahistoryjobs(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.PrerequisiteJobDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + +func testDatahistoryjobToManyJobDatahistoryjobs(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + _, err = tx.Exec("insert into \"datahistoryjobrelations\" (\"prerequisite_job_id\", \"job_id\") values ($1, $2)", a.ID, b.ID) + if err != nil { + t.Fatal(err) + } + _, err = tx.Exec("insert into \"datahistoryjobrelations\" (\"prerequisite_job_id\", \"job_id\") values ($1, $2)", a.ID, c.ID) + if err != nil { + t.Fatal(err) + } + + check, err := a.JobDatahistoryjobs().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if v.ID == b.ID { + bFound = true + } + if v.ID == c.ID { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadJobDatahistoryjobs(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.JobDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.JobDatahistoryjobs = nil + if err = a.L.LoadJobDatahistoryjobs(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.JobDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + func testDatahistoryjobToManyJobDatahistoryjobresults(t *testing.T) { var err error ctx := context.Background() @@ -501,74 +823,1032 @@ func testDatahistoryjobToManyJobDatahistoryjobresults(t *testing.T) { defer func() { _ = tx.Rollback() }() var a Datahistoryjob - var b, c Datahistoryjobresult + var b, c Datahistoryjobresult + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, datahistoryjobresultDBTypes, false, datahistoryjobresultColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobresultDBTypes, false, datahistoryjobresultColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + b.JobID = a.ID + c.JobID = a.ID + + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := a.JobDatahistoryjobresults().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if v.JobID == b.JobID { + bFound = true + } + if v.JobID == c.JobID { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadJobDatahistoryjobresults(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.JobDatahistoryjobresults); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.JobDatahistoryjobresults = nil + if err = a.L.LoadJobDatahistoryjobresults(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.JobDatahistoryjobresults); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + +func testDatahistoryjobToManyAddOpSourceJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Candle{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddSourceJobCandles(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if !queries.Equal(a.ID, first.SourceJobID) { + t.Error("foreign key was wrong value", a.ID, first.SourceJobID) + } + if !queries.Equal(a.ID, second.SourceJobID) { + t.Error("foreign key was wrong value", a.ID, second.SourceJobID) + } + + if first.R.SourceJob != &a { + t.Error("relationship was not added properly to the foreign slice") + } + if second.R.SourceJob != &a { + t.Error("relationship was not added properly to the foreign slice") + } + + if a.R.SourceJobCandles[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.SourceJobCandles[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testDatahistoryjobToManySetOpSourceJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.SetSourceJobCandles(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } + + count, err := a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetSourceJobCandles(ctx, tx, true, &d, &e) + if err != nil { + t.Fatal(err) + } + + count, err = a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.SourceJobID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.SourceJobID) { + t.Error("want c's foreign key value to be nil") + } + if !queries.Equal(a.ID, d.SourceJobID) { + t.Error("foreign key was wrong value", a.ID, d.SourceJobID) + } + if !queries.Equal(a.ID, e.SourceJobID) { + t.Error("foreign key was wrong value", a.ID, e.SourceJobID) + } + + if b.R.SourceJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.SourceJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.SourceJob != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.SourceJob != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if a.R.SourceJobCandles[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.SourceJobCandles[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testDatahistoryjobToManyRemoveOpSourceJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.AddSourceJobCandles(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) + } + + count, err := a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 4 { + t.Error("count was wrong:", count) + } + + err = a.RemoveSourceJobCandles(ctx, tx, foreigners[:2]...) + if err != nil { + t.Fatal(err) + } + + count, err = a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.SourceJobID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.SourceJobID) { + t.Error("want c's foreign key value to be nil") + } + + if b.R.SourceJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.SourceJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.SourceJob != &a { + t.Error("relationship to a should have been preserved") + } + if e.R.SourceJob != &a { + t.Error("relationship to a should have been preserved") + } + + if len(a.R.SourceJobCandles) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.SourceJobCandles[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.SourceJobCandles[0] != &e { + t.Error("relationship to e should have been preserved") + } +} + +func testDatahistoryjobToManyAddOpValidationJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Candle{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddValidationJobCandles(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if !queries.Equal(a.ID, first.ValidationJobID) { + t.Error("foreign key was wrong value", a.ID, first.ValidationJobID) + } + if !queries.Equal(a.ID, second.ValidationJobID) { + t.Error("foreign key was wrong value", a.ID, second.ValidationJobID) + } + + if first.R.ValidationJob != &a { + t.Error("relationship was not added properly to the foreign slice") + } + if second.R.ValidationJob != &a { + t.Error("relationship was not added properly to the foreign slice") + } + + if a.R.ValidationJobCandles[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.ValidationJobCandles[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testDatahistoryjobToManySetOpValidationJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.SetValidationJobCandles(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } + + count, err := a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetValidationJobCandles(ctx, tx, true, &d, &e) + if err != nil { + t.Fatal(err) + } + + count, err = a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.ValidationJobID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.ValidationJobID) { + t.Error("want c's foreign key value to be nil") + } + if !queries.Equal(a.ID, d.ValidationJobID) { + t.Error("foreign key was wrong value", a.ID, d.ValidationJobID) + } + if !queries.Equal(a.ID, e.ValidationJobID) { + t.Error("foreign key was wrong value", a.ID, e.ValidationJobID) + } + + if b.R.ValidationJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.ValidationJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.ValidationJob != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.ValidationJob != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if a.R.ValidationJobCandles[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.ValidationJobCandles[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testDatahistoryjobToManyRemoveOpValidationJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.AddValidationJobCandles(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) + } + + count, err := a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 4 { + t.Error("count was wrong:", count) + } + + err = a.RemoveValidationJobCandles(ctx, tx, foreigners[:2]...) + if err != nil { + t.Fatal(err) + } + + count, err = a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.ValidationJobID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.ValidationJobID) { + t.Error("want c's foreign key value to be nil") + } + + if b.R.ValidationJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.ValidationJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.ValidationJob != &a { + t.Error("relationship to a should have been preserved") + } + if e.R.ValidationJob != &a { + t.Error("relationship to a should have been preserved") + } + + if len(a.R.ValidationJobCandles) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.ValidationJobCandles[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.ValidationJobCandles[0] != &e { + t.Error("relationship to e should have been preserved") + } +} + +func testDatahistoryjobToManyAddOpPrerequisiteJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Datahistoryjob{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddPrerequisiteJobDatahistoryjobs(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if first.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + if second.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + + if a.R.PrerequisiteJobDatahistoryjobs[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.PrerequisiteJobDatahistoryjobs[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testDatahistoryjobToManySetOpPrerequisiteJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.SetPrerequisiteJobDatahistoryjobs(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } + + count, err := a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetPrerequisiteJobDatahistoryjobs(ctx, tx, true, &d, &e) + if err != nil { + t.Fatal(err) + } + + count, err = a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + // The following checks cannot be implemented since we have no handle + // to these when we call Set(). Leaving them here as wishful thinking + // and to let people know there's dragons. + // + // if len(b.R.JobDatahistoryjobs) != 0 { + // t.Error("relationship was not removed properly from the slice") + // } + // if len(c.R.JobDatahistoryjobs) != 0 { + // t.Error("relationship was not removed properly from the slice") + // } + if d.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + if e.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + + if a.R.PrerequisiteJobDatahistoryjobs[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.PrerequisiteJobDatahistoryjobs[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testDatahistoryjobToManyRemoveOpPrerequisiteJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.AddPrerequisiteJobDatahistoryjobs(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) + } + + count, err := a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 4 { + t.Error("count was wrong:", count) + } + + err = a.RemovePrerequisiteJobDatahistoryjobs(ctx, tx, foreigners[:2]...) + if err != nil { + t.Fatal(err) + } + + count, err = a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if len(b.R.JobDatahistoryjobs) != 0 { + t.Error("relationship was not removed properly from the slice") + } + if len(c.R.JobDatahistoryjobs) != 0 { + t.Error("relationship was not removed properly from the slice") + } + if d.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if len(a.R.PrerequisiteJobDatahistoryjobs) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.PrerequisiteJobDatahistoryjobs[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.PrerequisiteJobDatahistoryjobs[0] != &e { + t.Error("relationship to e should have been preserved") + } +} + +func testDatahistoryjobToManyAddOpJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Datahistoryjob{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddJobDatahistoryjobs(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if first.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + if second.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + + if a.R.JobDatahistoryjobs[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.JobDatahistoryjobs[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.JobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testDatahistoryjobToManySetOpJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob seed := randomize.NewSeed() - if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } } - if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { t.Fatal(err) } - - if err = randomize.Struct(seed, &b, datahistoryjobresultDBTypes, false, datahistoryjobresultColumnsWithDefault...); err != nil { + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { t.Fatal(err) } - if err = randomize.Struct(seed, &c, datahistoryjobresultDBTypes, false, datahistoryjobresultColumnsWithDefault...); err != nil { + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { t.Fatal(err) } - b.JobID = a.ID - c.JobID = a.ID + err = a.SetJobDatahistoryjobs(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } - if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + count, err := a.JobDatahistoryjobs().Count(ctx, tx) + if err != nil { t.Fatal(err) } - if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetJobDatahistoryjobs(ctx, tx, true, &d, &e) + if err != nil { t.Fatal(err) } - check, err := a.JobDatahistoryjobresults().All(ctx, tx) + count, err = a.JobDatahistoryjobs().Count(ctx, tx) if err != nil { t.Fatal(err) } + if count != 2 { + t.Error("count was wrong:", count) + } - bFound, cFound := false, false - for _, v := range check { - if v.JobID == b.JobID { - bFound = true - } - if v.JobID == c.JobID { - cFound = true + // The following checks cannot be implemented since we have no handle + // to these when we call Set(). Leaving them here as wishful thinking + // and to let people know there's dragons. + // + // if len(b.R.PrerequisiteJobDatahistoryjobs) != 0 { + // t.Error("relationship was not removed properly from the slice") + // } + // if len(c.R.PrerequisiteJobDatahistoryjobs) != 0 { + // t.Error("relationship was not removed properly from the slice") + // } + if d.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + if e.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + + if a.R.JobDatahistoryjobs[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.JobDatahistoryjobs[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testDatahistoryjobToManyRemoveOpJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) } } - if !bFound { - t.Error("expected to find b") + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) } - if !cFound { - t.Error("expected to find c") + + err = a.AddJobDatahistoryjobs(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) } - slice := DatahistoryjobSlice{&a} - if err = a.L.LoadJobDatahistoryjobresults(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + count, err := a.JobDatahistoryjobs().Count(ctx, tx) + if err != nil { t.Fatal(err) } - if got := len(a.R.JobDatahistoryjobresults); got != 2 { - t.Error("number of eager loaded records wrong, got:", got) + if count != 4 { + t.Error("count was wrong:", count) } - a.R.JobDatahistoryjobresults = nil - if err = a.L.LoadJobDatahistoryjobresults(ctx, tx, true, &a, nil); err != nil { + err = a.RemoveJobDatahistoryjobs(ctx, tx, foreigners[:2]...) + if err != nil { t.Fatal(err) } - if got := len(a.R.JobDatahistoryjobresults); got != 2 { - t.Error("number of eager loaded records wrong, got:", got) + + count, err = a.JobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) } - if t.Failed() { - t.Logf("%#v", check) + if len(b.R.PrerequisiteJobDatahistoryjobs) != 0 { + t.Error("relationship was not removed properly from the slice") + } + if len(c.R.PrerequisiteJobDatahistoryjobs) != 0 { + t.Error("relationship was not removed properly from the slice") + } + if d.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if len(a.R.JobDatahistoryjobs) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.JobDatahistoryjobs[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.JobDatahistoryjobs[0] != &e { + t.Error("relationship to e should have been preserved") } } @@ -698,6 +1978,57 @@ func testDatahistoryjobToOneExchangeUsingExchangeName(t *testing.T) { } } +func testDatahistoryjobToOneExchangeUsingSecondaryExchange(t *testing.T) { + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var local Datahistoryjob + var foreign Exchange + + seed := randomize.NewSeed() + if err := randomize.Struct(seed, &local, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + if err := randomize.Struct(seed, &foreign, exchangeDBTypes, false, exchangeColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Exchange struct: %s", err) + } + + if err := foreign.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + queries.Assign(&local.SecondaryExchangeID, foreign.ID) + if err := local.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := local.SecondaryExchange().One(ctx, tx) + if err != nil { + t.Fatal(err) + } + + if !queries.Equal(check.ID, foreign.ID) { + t.Errorf("want: %v, got %v", foreign.ID, check.ID) + } + + slice := DatahistoryjobSlice{&local} + if err = local.L.LoadSecondaryExchange(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if local.R.SecondaryExchange == nil { + t.Error("struct should have been eager loaded") + } + + local.R.SecondaryExchange = nil + if err = local.L.LoadSecondaryExchange(ctx, tx, true, &local, nil); err != nil { + t.Fatal(err) + } + if local.R.SecondaryExchange == nil { + t.Error("struct should have been eager loaded") + } +} + func testDatahistoryjobToOneSetOpExchangeUsingExchangeName(t *testing.T) { var err error @@ -755,6 +2086,114 @@ func testDatahistoryjobToOneSetOpExchangeUsingExchangeName(t *testing.T) { } } } +func testDatahistoryjobToOneSetOpExchangeUsingSecondaryExchange(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Exchange + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + for i, x := range []*Exchange{&b, &c} { + err = a.SetSecondaryExchange(ctx, tx, i != 0, x) + if err != nil { + t.Fatal(err) + } + + if a.R.SecondaryExchange != x { + t.Error("relationship struct not set to correct value") + } + + if x.R.SecondaryExchangeDatahistoryjobs[0] != &a { + t.Error("failed to append to foreign relationship struct") + } + if !queries.Equal(a.SecondaryExchangeID, x.ID) { + t.Error("foreign key was wrong value", a.SecondaryExchangeID) + } + + zero := reflect.Zero(reflect.TypeOf(a.SecondaryExchangeID)) + reflect.Indirect(reflect.ValueOf(&a.SecondaryExchangeID)).Set(zero) + + if err = a.Reload(ctx, tx); err != nil { + t.Fatal("failed to reload", err) + } + + if !queries.Equal(a.SecondaryExchangeID, x.ID) { + t.Error("foreign key was wrong value", a.SecondaryExchangeID, x.ID) + } + } +} + +func testDatahistoryjobToOneRemoveOpExchangeUsingSecondaryExchange(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b Exchange + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = a.SetSecondaryExchange(ctx, tx, true, &b); err != nil { + t.Fatal(err) + } + + if err = a.RemoveSecondaryExchange(ctx, tx, &b); err != nil { + t.Error("failed to remove relationship") + } + + count, err := a.SecondaryExchange().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 0 { + t.Error("want no relationships remaining") + } + + if a.R.SecondaryExchange != nil { + t.Error("R struct entry should be nil") + } + + if !queries.IsValuerNil(a.SecondaryExchangeID) { + t.Error("foreign key value should be nil") + } + + if len(b.R.SecondaryExchangeDatahistoryjobs) != 0 { + t.Error("failed to remove a from b's relationships") + } +} func testDatahistoryjobsReload(t *testing.T) { t.Parallel() @@ -830,7 +2269,7 @@ func testDatahistoryjobsSelect(t *testing.T) { } var ( - datahistoryjobDBTypes = map[string]string{`ID`: `uuid`, `Nickname`: `character varying`, `ExchangeNameID`: `uuid`, `Asset`: `character varying`, `Base`: `character varying`, `Quote`: `character varying`, `StartTime`: `timestamp with time zone`, `EndTime`: `timestamp with time zone`, `DataType`: `double precision`, `Interval`: `double precision`, `RequestSize`: `double precision`, `MaxRetries`: `double precision`, `BatchCount`: `double precision`, `Status`: `double precision`, `Created`: `timestamp with time zone`} + datahistoryjobDBTypes = map[string]string{`ID`: `uuid`, `Nickname`: `character varying`, `ExchangeNameID`: `uuid`, `Asset`: `character varying`, `Base`: `character varying`, `Quote`: `character varying`, `StartTime`: `timestamp with time zone`, `EndTime`: `timestamp with time zone`, `DataType`: `double precision`, `Interval`: `double precision`, `RequestSize`: `double precision`, `MaxRetries`: `double precision`, `BatchCount`: `double precision`, `Status`: `double precision`, `Created`: `timestamp with time zone`, `ConversionInterval`: `double precision`, `OverwriteData`: `boolean`, `DecimalPlaceComparison`: `integer`, `SecondaryExchangeID`: `uuid`, `IssueTolerancePercentage`: `double precision`, `ReplaceOnIssue`: `boolean`} _ = bytes.MinRead ) diff --git a/database/models/postgres/datahistoryjobresult.go b/database/models/postgres/datahistoryjobresult.go index 8130b42b997..7e742ad0541 100644 --- a/database/models/postgres/datahistoryjobresult.go +++ b/database/models/postgres/datahistoryjobresult.go @@ -56,29 +56,6 @@ var DatahistoryjobresultColumns = struct { // Generated where -type whereHelpernull_String struct{ field string } - -func (w whereHelpernull_String) EQ(x null.String) qm.QueryMod { - return qmhelper.WhereNullEQ(w.field, false, x) -} -func (w whereHelpernull_String) NEQ(x null.String) qm.QueryMod { - return qmhelper.WhereNullEQ(w.field, true, x) -} -func (w whereHelpernull_String) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } -func (w whereHelpernull_String) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } -func (w whereHelpernull_String) LT(x null.String) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.LT, x) -} -func (w whereHelpernull_String) LTE(x null.String) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.LTE, x) -} -func (w whereHelpernull_String) GT(x null.String) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.GT, x) -} -func (w whereHelpernull_String) GTE(x null.String) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.GTE, x) -} - var DatahistoryjobresultWhere = struct { ID whereHelperstring JobID whereHelperstring diff --git a/database/models/postgres/exchange.go b/database/models/postgres/exchange.go index 69bab0db788..02c96db3bda 100644 --- a/database/models/postgres/exchange.go +++ b/database/models/postgres/exchange.go @@ -50,23 +50,26 @@ var ExchangeWhere = struct { // ExchangeRels is where relationship names are stored. var ExchangeRels = struct { - ExchangeNameCandles string - ExchangeNameDatahistoryjobs string - ExchangeNameTrades string - ExchangeNameWithdrawalHistories string + ExchangeNameCandles string + ExchangeNameDatahistoryjobs string + SecondaryExchangeDatahistoryjobs string + ExchangeNameTrades string + ExchangeNameWithdrawalHistories string }{ - ExchangeNameCandles: "ExchangeNameCandles", - ExchangeNameDatahistoryjobs: "ExchangeNameDatahistoryjobs", - ExchangeNameTrades: "ExchangeNameTrades", - ExchangeNameWithdrawalHistories: "ExchangeNameWithdrawalHistories", + ExchangeNameCandles: "ExchangeNameCandles", + ExchangeNameDatahistoryjobs: "ExchangeNameDatahistoryjobs", + SecondaryExchangeDatahistoryjobs: "SecondaryExchangeDatahistoryjobs", + ExchangeNameTrades: "ExchangeNameTrades", + ExchangeNameWithdrawalHistories: "ExchangeNameWithdrawalHistories", } // exchangeR is where relationships are stored. type exchangeR struct { - ExchangeNameCandles CandleSlice - ExchangeNameDatahistoryjobs DatahistoryjobSlice - ExchangeNameTrades TradeSlice - ExchangeNameWithdrawalHistories WithdrawalHistorySlice + ExchangeNameCandles CandleSlice + ExchangeNameDatahistoryjobs DatahistoryjobSlice + SecondaryExchangeDatahistoryjobs DatahistoryjobSlice + ExchangeNameTrades TradeSlice + ExchangeNameWithdrawalHistories WithdrawalHistorySlice } // NewStruct creates a new relationship struct @@ -401,6 +404,27 @@ func (o *Exchange) ExchangeNameDatahistoryjobs(mods ...qm.QueryMod) datahistoryj return query } +// SecondaryExchangeDatahistoryjobs retrieves all the datahistoryjob's Datahistoryjobs with an executor via secondary_exchange_id column. +func (o *Exchange) SecondaryExchangeDatahistoryjobs(mods ...qm.QueryMod) datahistoryjobQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.Where("\"datahistoryjob\".\"secondary_exchange_id\"=?", o.ID), + ) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"datahistoryjob\".*"}) + } + + return query +} + // ExchangeNameTrades retrieves all the trade's Trades with an executor via exchange_name_id column. func (o *Exchange) ExchangeNameTrades(mods ...qm.QueryMod) tradeQuery { var queryMods []qm.QueryMod @@ -633,6 +657,101 @@ func (exchangeL) LoadExchangeNameDatahistoryjobs(ctx context.Context, e boil.Con return nil } +// LoadSecondaryExchangeDatahistoryjobs allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (exchangeL) LoadSecondaryExchangeDatahistoryjobs(ctx context.Context, e boil.ContextExecutor, singular bool, maybeExchange interface{}, mods queries.Applicator) error { + var slice []*Exchange + var object *Exchange + + if singular { + object = maybeExchange.(*Exchange) + } else { + slice = *maybeExchange.(*[]*Exchange) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &exchangeR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &exchangeR{} + } + + for _, a := range args { + if queries.Equal(a, obj.ID) { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`datahistoryjob`), qm.WhereIn(`datahistoryjob.secondary_exchange_id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load datahistoryjob") + } + + var resultSlice []*Datahistoryjob + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice datahistoryjob") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(datahistoryjobAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.SecondaryExchangeDatahistoryjobs = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.SecondaryExchange = object + } + return nil + } + + for _, foreign := range resultSlice { + for _, local := range slice { + if queries.Equal(local.ID, foreign.SecondaryExchangeID) { + local.R.SecondaryExchangeDatahistoryjobs = append(local.R.SecondaryExchangeDatahistoryjobs, foreign) + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.SecondaryExchange = local + break + } + } + } + + return nil +} + // LoadExchangeNameTrades allows an eager lookup of values, cached into the // loaded structs of the objects. This is for a 1-M or N-M relationship. func (exchangeL) LoadExchangeNameTrades(ctx context.Context, e boil.ContextExecutor, singular bool, maybeExchange interface{}, mods queries.Applicator) error { @@ -929,6 +1048,129 @@ func (o *Exchange) AddExchangeNameDatahistoryjobs(ctx context.Context, exec boil return nil } +// AddSecondaryExchangeDatahistoryjobs adds the given related objects to the existing relationships +// of the exchange, optionally inserting them as new records. +// Appends related to o.R.SecondaryExchangeDatahistoryjobs. +// Sets related.R.SecondaryExchange appropriately. +func (o *Exchange) AddSecondaryExchangeDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + var err error + for _, rel := range related { + if insert { + queries.Assign(&rel.SecondaryExchangeID, o.ID) + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } else { + updateQuery := fmt.Sprintf( + "UPDATE \"datahistoryjob\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"secondary_exchange_id"}), + strmangle.WhereClause("\"", "\"", 2, datahistoryjobPrimaryKeyColumns), + ) + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update foreign table") + } + + queries.Assign(&rel.SecondaryExchangeID, o.ID) + } + } + + if o.R == nil { + o.R = &exchangeR{ + SecondaryExchangeDatahistoryjobs: related, + } + } else { + o.R.SecondaryExchangeDatahistoryjobs = append(o.R.SecondaryExchangeDatahistoryjobs, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &datahistoryjobR{ + SecondaryExchange: o, + } + } else { + rel.R.SecondaryExchange = o + } + } + return nil +} + +// SetSecondaryExchangeDatahistoryjobs removes all previously related items of the +// exchange replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.SecondaryExchange's SecondaryExchangeDatahistoryjobs accordingly. +// Replaces o.R.SecondaryExchangeDatahistoryjobs with related. +// Sets related.R.SecondaryExchange's SecondaryExchangeDatahistoryjobs accordingly. +func (o *Exchange) SetSecondaryExchangeDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + query := "update \"datahistoryjob\" set \"secondary_exchange_id\" = null where \"secondary_exchange_id\" = $1" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + if o.R != nil { + for _, rel := range o.R.SecondaryExchangeDatahistoryjobs { + queries.SetScanner(&rel.SecondaryExchangeID, nil) + if rel.R == nil { + continue + } + + rel.R.SecondaryExchange = nil + } + + o.R.SecondaryExchangeDatahistoryjobs = nil + } + return o.AddSecondaryExchangeDatahistoryjobs(ctx, exec, insert, related...) +} + +// RemoveSecondaryExchangeDatahistoryjobs relationships from objects passed in. +// Removes related items from R.SecondaryExchangeDatahistoryjobs (uses pointer comparison, removal does not keep order) +// Sets related.R.SecondaryExchange. +func (o *Exchange) RemoveSecondaryExchangeDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, related ...*Datahistoryjob) error { + var err error + for _, rel := range related { + queries.SetScanner(&rel.SecondaryExchangeID, nil) + if rel.R != nil { + rel.R.SecondaryExchange = nil + } + if _, err = rel.Update(ctx, exec, boil.Whitelist("secondary_exchange_id")); err != nil { + return err + } + } + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.SecondaryExchangeDatahistoryjobs { + if rel != ri { + continue + } + + ln := len(o.R.SecondaryExchangeDatahistoryjobs) + if ln > 1 && i < ln-1 { + o.R.SecondaryExchangeDatahistoryjobs[i] = o.R.SecondaryExchangeDatahistoryjobs[ln-1] + } + o.R.SecondaryExchangeDatahistoryjobs = o.R.SecondaryExchangeDatahistoryjobs[:ln-1] + break + } + } + + return nil +} + // AddExchangeNameTrades adds the given related objects to the existing relationships // of the exchange, optionally inserting them as new records. // Appends related to o.R.ExchangeNameTrades. diff --git a/database/models/postgres/exchange_test.go b/database/models/postgres/exchange_test.go index 282fcdb55f4..cc6079e7f16 100644 --- a/database/models/postgres/exchange_test.go +++ b/database/models/postgres/exchange_test.go @@ -650,6 +650,83 @@ func testExchangeToManyExchangeNameDatahistoryjobs(t *testing.T) { } } +func testExchangeToManySecondaryExchangeDatahistoryjobs(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Exchange + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, exchangeDBTypes, true, exchangeColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Exchange struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + queries.Assign(&b.SecondaryExchangeID, a.ID) + queries.Assign(&c.SecondaryExchangeID, a.ID) + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := a.SecondaryExchangeDatahistoryjobs().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if queries.Equal(v.SecondaryExchangeID, b.SecondaryExchangeID) { + bFound = true + } + if queries.Equal(v.SecondaryExchangeID, c.SecondaryExchangeID) { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := ExchangeSlice{&a} + if err = a.L.LoadSecondaryExchangeDatahistoryjobs(ctx, tx, false, (*[]*Exchange)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.SecondaryExchangeDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.SecondaryExchangeDatahistoryjobs = nil + if err = a.L.LoadSecondaryExchangeDatahistoryjobs(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.SecondaryExchangeDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + func testExchangeToManyExchangeNameTrades(t *testing.T) { var err error ctx := context.Background() @@ -956,6 +1033,257 @@ func testExchangeToManyAddOpExchangeNameDatahistoryjobs(t *testing.T) { } } } +func testExchangeToManyAddOpSecondaryExchangeDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Exchange + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Datahistoryjob{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddSecondaryExchangeDatahistoryjobs(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if !queries.Equal(a.ID, first.SecondaryExchangeID) { + t.Error("foreign key was wrong value", a.ID, first.SecondaryExchangeID) + } + if !queries.Equal(a.ID, second.SecondaryExchangeID) { + t.Error("foreign key was wrong value", a.ID, second.SecondaryExchangeID) + } + + if first.R.SecondaryExchange != &a { + t.Error("relationship was not added properly to the foreign slice") + } + if second.R.SecondaryExchange != &a { + t.Error("relationship was not added properly to the foreign slice") + } + + if a.R.SecondaryExchangeDatahistoryjobs[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.SecondaryExchangeDatahistoryjobs[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testExchangeToManySetOpSecondaryExchangeDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Exchange + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.SetSecondaryExchangeDatahistoryjobs(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } + + count, err := a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetSecondaryExchangeDatahistoryjobs(ctx, tx, true, &d, &e) + if err != nil { + t.Fatal(err) + } + + count, err = a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.SecondaryExchangeID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.SecondaryExchangeID) { + t.Error("want c's foreign key value to be nil") + } + if !queries.Equal(a.ID, d.SecondaryExchangeID) { + t.Error("foreign key was wrong value", a.ID, d.SecondaryExchangeID) + } + if !queries.Equal(a.ID, e.SecondaryExchangeID) { + t.Error("foreign key was wrong value", a.ID, e.SecondaryExchangeID) + } + + if b.R.SecondaryExchange != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.SecondaryExchange != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.SecondaryExchange != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.SecondaryExchange != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if a.R.SecondaryExchangeDatahistoryjobs[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.SecondaryExchangeDatahistoryjobs[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testExchangeToManyRemoveOpSecondaryExchangeDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Exchange + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.AddSecondaryExchangeDatahistoryjobs(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) + } + + count, err := a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 4 { + t.Error("count was wrong:", count) + } + + err = a.RemoveSecondaryExchangeDatahistoryjobs(ctx, tx, foreigners[:2]...) + if err != nil { + t.Fatal(err) + } + + count, err = a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.SecondaryExchangeID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.SecondaryExchangeID) { + t.Error("want c's foreign key value to be nil") + } + + if b.R.SecondaryExchange != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.SecondaryExchange != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.SecondaryExchange != &a { + t.Error("relationship to a should have been preserved") + } + if e.R.SecondaryExchange != &a { + t.Error("relationship to a should have been preserved") + } + + if len(a.R.SecondaryExchangeDatahistoryjobs) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.SecondaryExchangeDatahistoryjobs[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.SecondaryExchangeDatahistoryjobs[0] != &e { + t.Error("relationship to e should have been preserved") + } +} + func testExchangeToManyAddOpExchangeNameTrades(t *testing.T) { var err error diff --git a/database/models/sqlite3/boil_suites_test.go b/database/models/sqlite3/boil_suites_test.go index 535528e92a4..659ef7b61b3 100644 --- a/database/models/sqlite3/boil_suites_test.go +++ b/database/models/sqlite3/boil_suites_test.go @@ -193,8 +193,11 @@ func TestInsert(t *testing.T) { // TestToOne tests cannot be run in parallel // or deadlocks can occur. func TestToOne(t *testing.T) { + t.Run("CandleToDatahistoryjobUsingValidationJob", testCandleToOneDatahistoryjobUsingValidationJob) + t.Run("CandleToDatahistoryjobUsingSourceJob", testCandleToOneDatahistoryjobUsingSourceJob) t.Run("CandleToExchangeUsingExchangeName", testCandleToOneExchangeUsingExchangeName) t.Run("DatahistoryjobToExchangeUsingExchangeName", testDatahistoryjobToOneExchangeUsingExchangeName) + t.Run("DatahistoryjobToExchangeUsingSecondaryExchange", testDatahistoryjobToOneExchangeUsingSecondaryExchange) t.Run("DatahistoryjobresultToDatahistoryjobUsingJob", testDatahistoryjobresultToOneDatahistoryjobUsingJob) t.Run("ScriptExecutionToScriptUsingScript", testScriptExecutionToOneScriptUsingScript) t.Run("TradeToExchangeUsingExchangeName", testTradeToOneExchangeUsingExchangeName) @@ -213,8 +216,13 @@ func TestOneToOne(t *testing.T) { // TestToMany tests cannot be run in parallel // or deadlocks can occur. func TestToMany(t *testing.T) { + t.Run("DatahistoryjobToValidationJobCandles", testDatahistoryjobToManyValidationJobCandles) + t.Run("DatahistoryjobToSourceJobCandles", testDatahistoryjobToManySourceJobCandles) + t.Run("DatahistoryjobToPrerequisiteJobDatahistoryjobs", testDatahistoryjobToManyPrerequisiteJobDatahistoryjobs) + t.Run("DatahistoryjobToJobDatahistoryjobs", testDatahistoryjobToManyJobDatahistoryjobs) t.Run("DatahistoryjobToJobDatahistoryjobresults", testDatahistoryjobToManyJobDatahistoryjobresults) t.Run("ExchangeToExchangeNameDatahistoryjobs", testExchangeToManyExchangeNameDatahistoryjobs) + t.Run("ExchangeToSecondaryExchangeDatahistoryjobs", testExchangeToManySecondaryExchangeDatahistoryjobs) t.Run("ExchangeToExchangeNameWithdrawalHistories", testExchangeToManyExchangeNameWithdrawalHistories) t.Run("ScriptToScriptExecutions", testScriptToManyScriptExecutions) t.Run("WithdrawalHistoryToWithdrawalCryptos", testWithdrawalHistoryToManyWithdrawalCryptos) @@ -224,8 +232,11 @@ func TestToMany(t *testing.T) { // TestToOneSet tests cannot be run in parallel // or deadlocks can occur. func TestToOneSet(t *testing.T) { + t.Run("CandleToDatahistoryjobUsingValidationJobCandles", testCandleToOneSetOpDatahistoryjobUsingValidationJob) + t.Run("CandleToDatahistoryjobUsingSourceJobCandles", testCandleToOneSetOpDatahistoryjobUsingSourceJob) t.Run("CandleToExchangeUsingExchangeNameCandle", testCandleToOneSetOpExchangeUsingExchangeName) t.Run("DatahistoryjobToExchangeUsingExchangeNameDatahistoryjobs", testDatahistoryjobToOneSetOpExchangeUsingExchangeName) + t.Run("DatahistoryjobToExchangeUsingSecondaryExchangeDatahistoryjobs", testDatahistoryjobToOneSetOpExchangeUsingSecondaryExchange) t.Run("DatahistoryjobresultToDatahistoryjobUsingJobDatahistoryjobresults", testDatahistoryjobresultToOneSetOpDatahistoryjobUsingJob) t.Run("ScriptExecutionToScriptUsingScriptExecutions", testScriptExecutionToOneSetOpScriptUsingScript) t.Run("TradeToExchangeUsingExchangeNameTrade", testTradeToOneSetOpExchangeUsingExchangeName) @@ -236,7 +247,11 @@ func TestToOneSet(t *testing.T) { // TestToOneRemove tests cannot be run in parallel // or deadlocks can occur. -func TestToOneRemove(t *testing.T) {} +func TestToOneRemove(t *testing.T) { + t.Run("CandleToDatahistoryjobUsingValidationJobCandles", testCandleToOneRemoveOpDatahistoryjobUsingValidationJob) + t.Run("CandleToDatahistoryjobUsingSourceJobCandles", testCandleToOneRemoveOpDatahistoryjobUsingSourceJob) + t.Run("DatahistoryjobToExchangeUsingSecondaryExchangeDatahistoryjobs", testDatahistoryjobToOneRemoveOpExchangeUsingSecondaryExchange) +} // TestOneToOneSet tests cannot be run in parallel // or deadlocks can occur. @@ -252,8 +267,13 @@ func TestOneToOneRemove(t *testing.T) {} // TestToManyAdd tests cannot be run in parallel // or deadlocks can occur. func TestToManyAdd(t *testing.T) { + t.Run("DatahistoryjobToValidationJobCandles", testDatahistoryjobToManyAddOpValidationJobCandles) + t.Run("DatahistoryjobToSourceJobCandles", testDatahistoryjobToManyAddOpSourceJobCandles) + t.Run("DatahistoryjobToPrerequisiteJobDatahistoryjobs", testDatahistoryjobToManyAddOpPrerequisiteJobDatahistoryjobs) + t.Run("DatahistoryjobToJobDatahistoryjobs", testDatahistoryjobToManyAddOpJobDatahistoryjobs) t.Run("DatahistoryjobToJobDatahistoryjobresults", testDatahistoryjobToManyAddOpJobDatahistoryjobresults) t.Run("ExchangeToExchangeNameDatahistoryjobs", testExchangeToManyAddOpExchangeNameDatahistoryjobs) + t.Run("ExchangeToSecondaryExchangeDatahistoryjobs", testExchangeToManyAddOpSecondaryExchangeDatahistoryjobs) t.Run("ExchangeToExchangeNameWithdrawalHistories", testExchangeToManyAddOpExchangeNameWithdrawalHistories) t.Run("ScriptToScriptExecutions", testScriptToManyAddOpScriptExecutions) t.Run("WithdrawalHistoryToWithdrawalCryptos", testWithdrawalHistoryToManyAddOpWithdrawalCryptos) @@ -262,11 +282,23 @@ func TestToManyAdd(t *testing.T) { // TestToManySet tests cannot be run in parallel // or deadlocks can occur. -func TestToManySet(t *testing.T) {} +func TestToManySet(t *testing.T) { + t.Run("DatahistoryjobToValidationJobCandles", testDatahistoryjobToManySetOpValidationJobCandles) + t.Run("DatahistoryjobToSourceJobCandles", testDatahistoryjobToManySetOpSourceJobCandles) + t.Run("DatahistoryjobToPrerequisiteJobDatahistoryjobs", testDatahistoryjobToManySetOpPrerequisiteJobDatahistoryjobs) + t.Run("DatahistoryjobToJobDatahistoryjobs", testDatahistoryjobToManySetOpJobDatahistoryjobs) + t.Run("ExchangeToSecondaryExchangeDatahistoryjobs", testExchangeToManySetOpSecondaryExchangeDatahistoryjobs) +} // TestToManyRemove tests cannot be run in parallel // or deadlocks can occur. -func TestToManyRemove(t *testing.T) {} +func TestToManyRemove(t *testing.T) { + t.Run("DatahistoryjobToValidationJobCandles", testDatahistoryjobToManyRemoveOpValidationJobCandles) + t.Run("DatahistoryjobToSourceJobCandles", testDatahistoryjobToManyRemoveOpSourceJobCandles) + t.Run("DatahistoryjobToPrerequisiteJobDatahistoryjobs", testDatahistoryjobToManyRemoveOpPrerequisiteJobDatahistoryjobs) + t.Run("DatahistoryjobToJobDatahistoryjobs", testDatahistoryjobToManyRemoveOpJobDatahistoryjobs) + t.Run("ExchangeToSecondaryExchangeDatahistoryjobs", testExchangeToManyRemoveOpSecondaryExchangeDatahistoryjobs) +} func TestReload(t *testing.T) { t.Run("AuditEvents", testAuditEventsReload) diff --git a/database/models/sqlite3/boil_table_names.go b/database/models/sqlite3/boil_table_names.go index f2d2af92246..ff831ada671 100644 --- a/database/models/sqlite3/boil_table_names.go +++ b/database/models/sqlite3/boil_table_names.go @@ -4,29 +4,29 @@ package sqlite3 var TableNames = struct { - AuditEvent string - Candle string - Datahistoryjob string - Datahistoryjobresult string - Exchange string - GooseDBVersion string - Script string - ScriptExecution string - Trade string - WithdrawalCrypto string - WithdrawalFiat string - WithdrawalHistory string + AuditEvent string + Candle string + Datahistoryjob string + Datahistoryjobrelations string + Datahistoryjobresult string + Exchange string + Script string + ScriptExecution string + Trade string + WithdrawalCrypto string + WithdrawalFiat string + WithdrawalHistory string }{ - AuditEvent: "audit_event", - Candle: "candle", - Datahistoryjob: "datahistoryjob", - Datahistoryjobresult: "datahistoryjobresult", - Exchange: "exchange", - GooseDBVersion: "goose_db_version", - Script: "script", - ScriptExecution: "script_execution", - Trade: "trade", - WithdrawalCrypto: "withdrawal_crypto", - WithdrawalFiat: "withdrawal_fiat", - WithdrawalHistory: "withdrawal_history", + AuditEvent: "audit_event", + Candle: "candle", + Datahistoryjob: "datahistoryjob", + Datahistoryjobrelations: "datahistoryjobrelations", + Datahistoryjobresult: "datahistoryjobresult", + Exchange: "exchange", + Script: "script", + ScriptExecution: "script_execution", + Trade: "trade", + WithdrawalCrypto: "withdrawal_crypto", + WithdrawalFiat: "withdrawal_fiat", + WithdrawalHistory: "withdrawal_history", } diff --git a/database/models/sqlite3/candle.go b/database/models/sqlite3/candle.go index 2fb45de7a43..45ccab9b573 100644 --- a/database/models/sqlite3/candle.go +++ b/database/models/sqlite3/candle.go @@ -18,53 +18,63 @@ import ( "github.com/thrasher-corp/sqlboiler/queries/qm" "github.com/thrasher-corp/sqlboiler/queries/qmhelper" "github.com/thrasher-corp/sqlboiler/strmangle" + "github.com/volatiletech/null" ) // Candle is an object representing the database table. type Candle struct { - ID string `boil:"id" json:"id" toml:"id" yaml:"id"` - ExchangeNameID string `boil:"exchange_name_id" json:"exchange_name_id" toml:"exchange_name_id" yaml:"exchange_name_id"` - Base string `boil:"Base" json:"Base" toml:"Base" yaml:"Base"` - Quote string `boil:"Quote" json:"Quote" toml:"Quote" yaml:"Quote"` - Interval string `boil:"Interval" json:"Interval" toml:"Interval" yaml:"Interval"` - Timestamp string `boil:"Timestamp" json:"Timestamp" toml:"Timestamp" yaml:"Timestamp"` - Open float64 `boil:"Open" json:"Open" toml:"Open" yaml:"Open"` - High float64 `boil:"High" json:"High" toml:"High" yaml:"High"` - Low float64 `boil:"Low" json:"Low" toml:"Low" yaml:"Low"` - Close float64 `boil:"Close" json:"Close" toml:"Close" yaml:"Close"` - Volume float64 `boil:"Volume" json:"Volume" toml:"Volume" yaml:"Volume"` - Asset string `boil:"Asset" json:"Asset" toml:"Asset" yaml:"Asset"` + ID string `boil:"id" json:"id" toml:"id" yaml:"id"` + ExchangeNameID string `boil:"exchange_name_id" json:"exchange_name_id" toml:"exchange_name_id" yaml:"exchange_name_id"` + Base string `boil:"Base" json:"Base" toml:"Base" yaml:"Base"` + Quote string `boil:"Quote" json:"Quote" toml:"Quote" yaml:"Quote"` + Interval string `boil:"Interval" json:"Interval" toml:"Interval" yaml:"Interval"` + Timestamp string `boil:"Timestamp" json:"Timestamp" toml:"Timestamp" yaml:"Timestamp"` + Open float64 `boil:"Open" json:"Open" toml:"Open" yaml:"Open"` + High float64 `boil:"High" json:"High" toml:"High" yaml:"High"` + Low float64 `boil:"Low" json:"Low" toml:"Low" yaml:"Low"` + Close float64 `boil:"Close" json:"Close" toml:"Close" yaml:"Close"` + Volume float64 `boil:"Volume" json:"Volume" toml:"Volume" yaml:"Volume"` + Asset string `boil:"Asset" json:"Asset" toml:"Asset" yaml:"Asset"` + SourceJobID null.String `boil:"source_job_id" json:"source_job_id,omitempty" toml:"source_job_id" yaml:"source_job_id,omitempty"` + ValidationJobID null.String `boil:"validation_job_id" json:"validation_job_id,omitempty" toml:"validation_job_id" yaml:"validation_job_id,omitempty"` + ValidationIssues null.String `boil:"validation_issues" json:"validation_issues,omitempty" toml:"validation_issues" yaml:"validation_issues,omitempty"` R *candleR `boil:"-" json:"-" toml:"-" yaml:"-"` L candleL `boil:"-" json:"-" toml:"-" yaml:"-"` } var CandleColumns = struct { - ID string - ExchangeNameID string - Base string - Quote string - Interval string - Timestamp string - Open string - High string - Low string - Close string - Volume string - Asset string + ID string + ExchangeNameID string + Base string + Quote string + Interval string + Timestamp string + Open string + High string + Low string + Close string + Volume string + Asset string + SourceJobID string + ValidationJobID string + ValidationIssues string }{ - ID: "id", - ExchangeNameID: "exchange_name_id", - Base: "Base", - Quote: "Quote", - Interval: "Interval", - Timestamp: "Timestamp", - Open: "Open", - High: "High", - Low: "Low", - Close: "Close", - Volume: "Volume", - Asset: "Asset", + ID: "id", + ExchangeNameID: "exchange_name_id", + Base: "Base", + Quote: "Quote", + Interval: "Interval", + Timestamp: "Timestamp", + Open: "Open", + High: "High", + Low: "Low", + Close: "Close", + Volume: "Volume", + Asset: "Asset", + SourceJobID: "source_job_id", + ValidationJobID: "validation_job_id", + ValidationIssues: "validation_issues", } // Generated where @@ -84,44 +94,79 @@ func (w whereHelperfloat64) GTE(x float64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) } +type whereHelpernull_String struct{ field string } + +func (w whereHelpernull_String) EQ(x null.String) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, false, x) +} +func (w whereHelpernull_String) NEQ(x null.String) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, true, x) +} +func (w whereHelpernull_String) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } +func (w whereHelpernull_String) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } +func (w whereHelpernull_String) LT(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpernull_String) LTE(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpernull_String) GT(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpernull_String) GTE(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} + var CandleWhere = struct { - ID whereHelperstring - ExchangeNameID whereHelperstring - Base whereHelperstring - Quote whereHelperstring - Interval whereHelperstring - Timestamp whereHelperstring - Open whereHelperfloat64 - High whereHelperfloat64 - Low whereHelperfloat64 - Close whereHelperfloat64 - Volume whereHelperfloat64 - Asset whereHelperstring + ID whereHelperstring + ExchangeNameID whereHelperstring + Base whereHelperstring + Quote whereHelperstring + Interval whereHelperstring + Timestamp whereHelperstring + Open whereHelperfloat64 + High whereHelperfloat64 + Low whereHelperfloat64 + Close whereHelperfloat64 + Volume whereHelperfloat64 + Asset whereHelperstring + SourceJobID whereHelpernull_String + ValidationJobID whereHelpernull_String + ValidationIssues whereHelpernull_String }{ - ID: whereHelperstring{field: "\"candle\".\"id\""}, - ExchangeNameID: whereHelperstring{field: "\"candle\".\"exchange_name_id\""}, - Base: whereHelperstring{field: "\"candle\".\"Base\""}, - Quote: whereHelperstring{field: "\"candle\".\"Quote\""}, - Interval: whereHelperstring{field: "\"candle\".\"Interval\""}, - Timestamp: whereHelperstring{field: "\"candle\".\"Timestamp\""}, - Open: whereHelperfloat64{field: "\"candle\".\"Open\""}, - High: whereHelperfloat64{field: "\"candle\".\"High\""}, - Low: whereHelperfloat64{field: "\"candle\".\"Low\""}, - Close: whereHelperfloat64{field: "\"candle\".\"Close\""}, - Volume: whereHelperfloat64{field: "\"candle\".\"Volume\""}, - Asset: whereHelperstring{field: "\"candle\".\"Asset\""}, + ID: whereHelperstring{field: "\"candle\".\"id\""}, + ExchangeNameID: whereHelperstring{field: "\"candle\".\"exchange_name_id\""}, + Base: whereHelperstring{field: "\"candle\".\"Base\""}, + Quote: whereHelperstring{field: "\"candle\".\"Quote\""}, + Interval: whereHelperstring{field: "\"candle\".\"Interval\""}, + Timestamp: whereHelperstring{field: "\"candle\".\"Timestamp\""}, + Open: whereHelperfloat64{field: "\"candle\".\"Open\""}, + High: whereHelperfloat64{field: "\"candle\".\"High\""}, + Low: whereHelperfloat64{field: "\"candle\".\"Low\""}, + Close: whereHelperfloat64{field: "\"candle\".\"Close\""}, + Volume: whereHelperfloat64{field: "\"candle\".\"Volume\""}, + Asset: whereHelperstring{field: "\"candle\".\"Asset\""}, + SourceJobID: whereHelpernull_String{field: "\"candle\".\"source_job_id\""}, + ValidationJobID: whereHelpernull_String{field: "\"candle\".\"validation_job_id\""}, + ValidationIssues: whereHelpernull_String{field: "\"candle\".\"validation_issues\""}, } // CandleRels is where relationship names are stored. var CandleRels = struct { - ExchangeName string + ValidationJob string + SourceJob string + ExchangeName string }{ - ExchangeName: "ExchangeName", + ValidationJob: "ValidationJob", + SourceJob: "SourceJob", + ExchangeName: "ExchangeName", } // candleR is where relationships are stored. type candleR struct { - ExchangeName *Exchange + ValidationJob *Datahistoryjob + SourceJob *Datahistoryjob + ExchangeName *Exchange } // NewStruct creates a new relationship struct @@ -133,8 +178,8 @@ func (*candleR) NewStruct() *candleR { type candleL struct{} var ( - candleAllColumns = []string{"id", "exchange_name_id", "Base", "Quote", "Interval", "Timestamp", "Open", "High", "Low", "Close", "Volume", "Asset"} - candleColumnsWithoutDefault = []string{"id", "exchange_name_id", "Base", "Quote", "Interval", "Timestamp", "Open", "High", "Low", "Close", "Volume", "Asset"} + candleAllColumns = []string{"id", "exchange_name_id", "Base", "Quote", "Interval", "Timestamp", "Open", "High", "Low", "Close", "Volume", "Asset", "source_job_id", "validation_job_id", "validation_issues"} + candleColumnsWithoutDefault = []string{"id", "exchange_name_id", "Base", "Quote", "Interval", "Timestamp", "Open", "High", "Low", "Close", "Volume", "Asset", "source_job_id", "validation_job_id", "validation_issues"} candleColumnsWithDefault = []string{} candlePrimaryKeyColumns = []string{"id"} ) @@ -414,6 +459,34 @@ func (q candleQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (boo return count > 0, nil } +// ValidationJob pointed to by the foreign key. +func (o *Candle) ValidationJob(mods ...qm.QueryMod) datahistoryjobQuery { + queryMods := []qm.QueryMod{ + qm.Where("\"id\" = ?", o.ValidationJobID), + } + + queryMods = append(queryMods, mods...) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + return query +} + +// SourceJob pointed to by the foreign key. +func (o *Candle) SourceJob(mods ...qm.QueryMod) datahistoryjobQuery { + queryMods := []qm.QueryMod{ + qm.Where("\"id\" = ?", o.SourceJobID), + } + + queryMods = append(queryMods, mods...) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + return query +} + // ExchangeName pointed to by the foreign key. func (o *Candle) ExchangeName(mods ...qm.QueryMod) exchangeQuery { queryMods := []qm.QueryMod{ @@ -428,6 +501,216 @@ func (o *Candle) ExchangeName(mods ...qm.QueryMod) exchangeQuery { return query } +// LoadValidationJob allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for an N-1 relationship. +func (candleL) LoadValidationJob(ctx context.Context, e boil.ContextExecutor, singular bool, maybeCandle interface{}, mods queries.Applicator) error { + var slice []*Candle + var object *Candle + + if singular { + object = maybeCandle.(*Candle) + } else { + slice = *maybeCandle.(*[]*Candle) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &candleR{} + } + if !queries.IsNil(object.ValidationJobID) { + args = append(args, object.ValidationJobID) + } + + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &candleR{} + } + + for _, a := range args { + if queries.Equal(a, obj.ValidationJobID) { + continue Outer + } + } + + if !queries.IsNil(obj.ValidationJobID) { + args = append(args, obj.ValidationJobID) + } + + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`datahistoryjob`), qm.WhereIn(`datahistoryjob.id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load Datahistoryjob") + } + + var resultSlice []*Datahistoryjob + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice Datahistoryjob") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results of eager load for datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(candleAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + + if len(resultSlice) == 0 { + return nil + } + + if singular { + foreign := resultSlice[0] + object.R.ValidationJob = foreign + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.ValidationJobCandles = append(foreign.R.ValidationJobCandles, object) + return nil + } + + for _, local := range slice { + for _, foreign := range resultSlice { + if queries.Equal(local.ValidationJobID, foreign.ID) { + local.R.ValidationJob = foreign + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.ValidationJobCandles = append(foreign.R.ValidationJobCandles, local) + break + } + } + } + + return nil +} + +// LoadSourceJob allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for an N-1 relationship. +func (candleL) LoadSourceJob(ctx context.Context, e boil.ContextExecutor, singular bool, maybeCandle interface{}, mods queries.Applicator) error { + var slice []*Candle + var object *Candle + + if singular { + object = maybeCandle.(*Candle) + } else { + slice = *maybeCandle.(*[]*Candle) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &candleR{} + } + if !queries.IsNil(object.SourceJobID) { + args = append(args, object.SourceJobID) + } + + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &candleR{} + } + + for _, a := range args { + if queries.Equal(a, obj.SourceJobID) { + continue Outer + } + } + + if !queries.IsNil(obj.SourceJobID) { + args = append(args, obj.SourceJobID) + } + + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`datahistoryjob`), qm.WhereIn(`datahistoryjob.id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load Datahistoryjob") + } + + var resultSlice []*Datahistoryjob + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice Datahistoryjob") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results of eager load for datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(candleAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + + if len(resultSlice) == 0 { + return nil + } + + if singular { + foreign := resultSlice[0] + object.R.SourceJob = foreign + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.SourceJobCandles = append(foreign.R.SourceJobCandles, object) + return nil + } + + for _, local := range slice { + for _, foreign := range resultSlice { + if queries.Equal(local.SourceJobID, foreign.ID) { + local.R.SourceJob = foreign + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.SourceJobCandles = append(foreign.R.SourceJobCandles, local) + break + } + } + } + + return nil +} + // LoadExchangeName allows an eager lookup of values, cached into the // loaded structs of the objects. This is for an N-1 relationship. func (candleL) LoadExchangeName(ctx context.Context, e boil.ContextExecutor, singular bool, maybeCandle interface{}, mods queries.Applicator) error { @@ -529,6 +812,162 @@ func (candleL) LoadExchangeName(ctx context.Context, e boil.ContextExecutor, sin return nil } +// SetValidationJob of the candle to the related item. +// Sets o.R.ValidationJob to related. +// Adds o to related.R.ValidationJobCandles. +func (o *Candle) SetValidationJob(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Datahistoryjob) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"candle\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, []string{"validation_job_id"}), + strmangle.WhereClause("\"", "\"", 0, candlePrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + queries.Assign(&o.ValidationJobID, related.ID) + if o.R == nil { + o.R = &candleR{ + ValidationJob: related, + } + } else { + o.R.ValidationJob = related + } + + if related.R == nil { + related.R = &datahistoryjobR{ + ValidationJobCandles: CandleSlice{o}, + } + } else { + related.R.ValidationJobCandles = append(related.R.ValidationJobCandles, o) + } + + return nil +} + +// RemoveValidationJob relationship. +// Sets o.R.ValidationJob to nil. +// Removes o from all passed in related items' relationships struct (Optional). +func (o *Candle) RemoveValidationJob(ctx context.Context, exec boil.ContextExecutor, related *Datahistoryjob) error { + var err error + + queries.SetScanner(&o.ValidationJobID, nil) + if _, err = o.Update(ctx, exec, boil.Whitelist("validation_job_id")); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + o.R.ValidationJob = nil + if related == nil || related.R == nil { + return nil + } + + for i, ri := range related.R.ValidationJobCandles { + if queries.Equal(o.ValidationJobID, ri.ValidationJobID) { + continue + } + + ln := len(related.R.ValidationJobCandles) + if ln > 1 && i < ln-1 { + related.R.ValidationJobCandles[i] = related.R.ValidationJobCandles[ln-1] + } + related.R.ValidationJobCandles = related.R.ValidationJobCandles[:ln-1] + break + } + return nil +} + +// SetSourceJob of the candle to the related item. +// Sets o.R.SourceJob to related. +// Adds o to related.R.SourceJobCandles. +func (o *Candle) SetSourceJob(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Datahistoryjob) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"candle\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, []string{"source_job_id"}), + strmangle.WhereClause("\"", "\"", 0, candlePrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + queries.Assign(&o.SourceJobID, related.ID) + if o.R == nil { + o.R = &candleR{ + SourceJob: related, + } + } else { + o.R.SourceJob = related + } + + if related.R == nil { + related.R = &datahistoryjobR{ + SourceJobCandles: CandleSlice{o}, + } + } else { + related.R.SourceJobCandles = append(related.R.SourceJobCandles, o) + } + + return nil +} + +// RemoveSourceJob relationship. +// Sets o.R.SourceJob to nil. +// Removes o from all passed in related items' relationships struct (Optional). +func (o *Candle) RemoveSourceJob(ctx context.Context, exec boil.ContextExecutor, related *Datahistoryjob) error { + var err error + + queries.SetScanner(&o.SourceJobID, nil) + if _, err = o.Update(ctx, exec, boil.Whitelist("source_job_id")); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + o.R.SourceJob = nil + if related == nil || related.R == nil { + return nil + } + + for i, ri := range related.R.SourceJobCandles { + if queries.Equal(o.SourceJobID, ri.SourceJobID) { + continue + } + + ln := len(related.R.SourceJobCandles) + if ln > 1 && i < ln-1 { + related.R.SourceJobCandles[i] = related.R.SourceJobCandles[ln-1] + } + related.R.SourceJobCandles = related.R.SourceJobCandles[:ln-1] + break + } + return nil +} + // SetExchangeName of the candle to the related item. // Sets o.R.ExchangeName to related. // Adds o to related.R.ExchangeNameCandle. diff --git a/database/models/sqlite3/candle_test.go b/database/models/sqlite3/candle_test.go index e8d9f6408f7..c3b6038cfcf 100644 --- a/database/models/sqlite3/candle_test.go +++ b/database/models/sqlite3/candle_test.go @@ -494,6 +494,108 @@ func testCandlesInsertWhitelist(t *testing.T) { } } +func testCandleToOneDatahistoryjobUsingValidationJob(t *testing.T) { + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var local Candle + var foreign Datahistoryjob + + seed := randomize.NewSeed() + if err := randomize.Struct(seed, &local, candleDBTypes, true, candleColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Candle struct: %s", err) + } + if err := randomize.Struct(seed, &foreign, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := foreign.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + queries.Assign(&local.ValidationJobID, foreign.ID) + if err := local.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := local.ValidationJob().One(ctx, tx) + if err != nil { + t.Fatal(err) + } + + if !queries.Equal(check.ID, foreign.ID) { + t.Errorf("want: %v, got %v", foreign.ID, check.ID) + } + + slice := CandleSlice{&local} + if err = local.L.LoadValidationJob(ctx, tx, false, (*[]*Candle)(&slice), nil); err != nil { + t.Fatal(err) + } + if local.R.ValidationJob == nil { + t.Error("struct should have been eager loaded") + } + + local.R.ValidationJob = nil + if err = local.L.LoadValidationJob(ctx, tx, true, &local, nil); err != nil { + t.Fatal(err) + } + if local.R.ValidationJob == nil { + t.Error("struct should have been eager loaded") + } +} + +func testCandleToOneDatahistoryjobUsingSourceJob(t *testing.T) { + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var local Candle + var foreign Datahistoryjob + + seed := randomize.NewSeed() + if err := randomize.Struct(seed, &local, candleDBTypes, true, candleColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Candle struct: %s", err) + } + if err := randomize.Struct(seed, &foreign, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := foreign.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + queries.Assign(&local.SourceJobID, foreign.ID) + if err := local.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := local.SourceJob().One(ctx, tx) + if err != nil { + t.Fatal(err) + } + + if !queries.Equal(check.ID, foreign.ID) { + t.Errorf("want: %v, got %v", foreign.ID, check.ID) + } + + slice := CandleSlice{&local} + if err = local.L.LoadSourceJob(ctx, tx, false, (*[]*Candle)(&slice), nil); err != nil { + t.Fatal(err) + } + if local.R.SourceJob == nil { + t.Error("struct should have been eager loaded") + } + + local.R.SourceJob = nil + if err = local.L.LoadSourceJob(ctx, tx, true, &local, nil); err != nil { + t.Fatal(err) + } + if local.R.SourceJob == nil { + t.Error("struct should have been eager loaded") + } +} + func testCandleToOneExchangeUsingExchangeName(t *testing.T) { ctx := context.Background() tx := MustTx(boil.BeginTx(ctx, nil)) @@ -545,6 +647,224 @@ func testCandleToOneExchangeUsingExchangeName(t *testing.T) { } } +func testCandleToOneSetOpDatahistoryjobUsingValidationJob(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Candle + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + for i, x := range []*Datahistoryjob{&b, &c} { + err = a.SetValidationJob(ctx, tx, i != 0, x) + if err != nil { + t.Fatal(err) + } + + if a.R.ValidationJob != x { + t.Error("relationship struct not set to correct value") + } + + if x.R.ValidationJobCandles[0] != &a { + t.Error("failed to append to foreign relationship struct") + } + if !queries.Equal(a.ValidationJobID, x.ID) { + t.Error("foreign key was wrong value", a.ValidationJobID) + } + + zero := reflect.Zero(reflect.TypeOf(a.ValidationJobID)) + reflect.Indirect(reflect.ValueOf(&a.ValidationJobID)).Set(zero) + + if err = a.Reload(ctx, tx); err != nil { + t.Fatal("failed to reload", err) + } + + if !queries.Equal(a.ValidationJobID, x.ID) { + t.Error("foreign key was wrong value", a.ValidationJobID, x.ID) + } + } +} + +func testCandleToOneRemoveOpDatahistoryjobUsingValidationJob(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Candle + var b Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = a.SetValidationJob(ctx, tx, true, &b); err != nil { + t.Fatal(err) + } + + if err = a.RemoveValidationJob(ctx, tx, &b); err != nil { + t.Error("failed to remove relationship") + } + + count, err := a.ValidationJob().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 0 { + t.Error("want no relationships remaining") + } + + if a.R.ValidationJob != nil { + t.Error("R struct entry should be nil") + } + + if !queries.IsValuerNil(a.ValidationJobID) { + t.Error("foreign key value should be nil") + } + + if len(b.R.ValidationJobCandles) != 0 { + t.Error("failed to remove a from b's relationships") + } +} + +func testCandleToOneSetOpDatahistoryjobUsingSourceJob(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Candle + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + for i, x := range []*Datahistoryjob{&b, &c} { + err = a.SetSourceJob(ctx, tx, i != 0, x) + if err != nil { + t.Fatal(err) + } + + if a.R.SourceJob != x { + t.Error("relationship struct not set to correct value") + } + + if x.R.SourceJobCandles[0] != &a { + t.Error("failed to append to foreign relationship struct") + } + if !queries.Equal(a.SourceJobID, x.ID) { + t.Error("foreign key was wrong value", a.SourceJobID) + } + + zero := reflect.Zero(reflect.TypeOf(a.SourceJobID)) + reflect.Indirect(reflect.ValueOf(&a.SourceJobID)).Set(zero) + + if err = a.Reload(ctx, tx); err != nil { + t.Fatal("failed to reload", err) + } + + if !queries.Equal(a.SourceJobID, x.ID) { + t.Error("foreign key was wrong value", a.SourceJobID, x.ID) + } + } +} + +func testCandleToOneRemoveOpDatahistoryjobUsingSourceJob(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Candle + var b Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = a.SetSourceJob(ctx, tx, true, &b); err != nil { + t.Fatal(err) + } + + if err = a.RemoveSourceJob(ctx, tx, &b); err != nil { + t.Error("failed to remove relationship") + } + + count, err := a.SourceJob().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 0 { + t.Error("want no relationships remaining") + } + + if a.R.SourceJob != nil { + t.Error("R struct entry should be nil") + } + + if !queries.IsValuerNil(a.SourceJobID) { + t.Error("foreign key value should be nil") + } + + if len(b.R.SourceJobCandles) != 0 { + t.Error("failed to remove a from b's relationships") + } +} + func testCandleToOneSetOpExchangeUsingExchangeName(t *testing.T) { var err error @@ -677,7 +997,7 @@ func testCandlesSelect(t *testing.T) { } var ( - candleDBTypes = map[string]string{`ID`: `TEXT`, `ExchangeNameID`: `UUID`, `Base`: `TEXT`, `Quote`: `TEXT`, `Interval`: `TEXT`, `Timestamp`: `TIMESTAMP`, `Open`: `REAL`, `High`: `REAL`, `Low`: `REAL`, `Close`: `REAL`, `Volume`: `REAL`, `Asset`: `TEXT`} + candleDBTypes = map[string]string{`ID`: `TEXT`, `ExchangeNameID`: `UUID`, `Base`: `TEXT`, `Quote`: `TEXT`, `Interval`: `TEXT`, `Timestamp`: `TIMESTAMP`, `Open`: `REAL`, `High`: `REAL`, `Low`: `REAL`, `Close`: `REAL`, `Volume`: `REAL`, `Asset`: `TEXT`, `SourceJobID`: `TEXT`, `ValidationJobID`: `TEXT`, `ValidationIssues`: `TEXT`} _ = bytes.MinRead ) diff --git a/database/models/sqlite3/datahistoryjob.go b/database/models/sqlite3/datahistoryjob.go index cda9889ce21..7e70d594663 100644 --- a/database/models/sqlite3/datahistoryjob.go +++ b/database/models/sqlite3/datahistoryjob.go @@ -18,113 +18,205 @@ import ( "github.com/thrasher-corp/sqlboiler/queries/qm" "github.com/thrasher-corp/sqlboiler/queries/qmhelper" "github.com/thrasher-corp/sqlboiler/strmangle" + "github.com/volatiletech/null" ) // Datahistoryjob is an object representing the database table. type Datahistoryjob struct { - ID string `boil:"id" json:"id" toml:"id" yaml:"id"` - Nickname string `boil:"nickname" json:"nickname" toml:"nickname" yaml:"nickname"` - ExchangeNameID string `boil:"exchange_name_id" json:"exchange_name_id" toml:"exchange_name_id" yaml:"exchange_name_id"` - Asset string `boil:"asset" json:"asset" toml:"asset" yaml:"asset"` - Base string `boil:"base" json:"base" toml:"base" yaml:"base"` - Quote string `boil:"quote" json:"quote" toml:"quote" yaml:"quote"` - StartTime string `boil:"start_time" json:"start_time" toml:"start_time" yaml:"start_time"` - EndTime string `boil:"end_time" json:"end_time" toml:"end_time" yaml:"end_time"` - Interval float64 `boil:"interval" json:"interval" toml:"interval" yaml:"interval"` - DataType float64 `boil:"data_type" json:"data_type" toml:"data_type" yaml:"data_type"` - RequestSize float64 `boil:"request_size" json:"request_size" toml:"request_size" yaml:"request_size"` - MaxRetries float64 `boil:"max_retries" json:"max_retries" toml:"max_retries" yaml:"max_retries"` - BatchCount float64 `boil:"batch_count" json:"batch_count" toml:"batch_count" yaml:"batch_count"` - Status float64 `boil:"status" json:"status" toml:"status" yaml:"status"` - Created string `boil:"created" json:"created" toml:"created" yaml:"created"` + ID string `boil:"id" json:"id" toml:"id" yaml:"id"` + Nickname string `boil:"nickname" json:"nickname" toml:"nickname" yaml:"nickname"` + ExchangeNameID string `boil:"exchange_name_id" json:"exchange_name_id" toml:"exchange_name_id" yaml:"exchange_name_id"` + Asset string `boil:"asset" json:"asset" toml:"asset" yaml:"asset"` + Base string `boil:"base" json:"base" toml:"base" yaml:"base"` + Quote string `boil:"quote" json:"quote" toml:"quote" yaml:"quote"` + StartTime string `boil:"start_time" json:"start_time" toml:"start_time" yaml:"start_time"` + EndTime string `boil:"end_time" json:"end_time" toml:"end_time" yaml:"end_time"` + Interval float64 `boil:"interval" json:"interval" toml:"interval" yaml:"interval"` + DataType float64 `boil:"data_type" json:"data_type" toml:"data_type" yaml:"data_type"` + RequestSize float64 `boil:"request_size" json:"request_size" toml:"request_size" yaml:"request_size"` + MaxRetries float64 `boil:"max_retries" json:"max_retries" toml:"max_retries" yaml:"max_retries"` + BatchCount float64 `boil:"batch_count" json:"batch_count" toml:"batch_count" yaml:"batch_count"` + Status float64 `boil:"status" json:"status" toml:"status" yaml:"status"` + Created string `boil:"created" json:"created" toml:"created" yaml:"created"` + ConversionInterval null.Float64 `boil:"conversion_interval" json:"conversion_interval,omitempty" toml:"conversion_interval" yaml:"conversion_interval,omitempty"` + OverwriteData null.Int64 `boil:"overwrite_data" json:"overwrite_data,omitempty" toml:"overwrite_data" yaml:"overwrite_data,omitempty"` + DecimalPlaceComparison null.Int64 `boil:"decimal_place_comparison" json:"decimal_place_comparison,omitempty" toml:"decimal_place_comparison" yaml:"decimal_place_comparison,omitempty"` + SecondaryExchangeID null.String `boil:"secondary_exchange_id" json:"secondary_exchange_id,omitempty" toml:"secondary_exchange_id" yaml:"secondary_exchange_id,omitempty"` + IssueTolerancePercentage null.Float64 `boil:"issue_tolerance_percentage" json:"issue_tolerance_percentage,omitempty" toml:"issue_tolerance_percentage" yaml:"issue_tolerance_percentage,omitempty"` + ReplaceOnIssue null.Int64 `boil:"replace_on_issue" json:"replace_on_issue,omitempty" toml:"replace_on_issue" yaml:"replace_on_issue,omitempty"` R *datahistoryjobR `boil:"-" json:"-" toml:"-" yaml:"-"` L datahistoryjobL `boil:"-" json:"-" toml:"-" yaml:"-"` } var DatahistoryjobColumns = struct { - ID string - Nickname string - ExchangeNameID string - Asset string - Base string - Quote string - StartTime string - EndTime string - Interval string - DataType string - RequestSize string - MaxRetries string - BatchCount string - Status string - Created string + ID string + Nickname string + ExchangeNameID string + Asset string + Base string + Quote string + StartTime string + EndTime string + Interval string + DataType string + RequestSize string + MaxRetries string + BatchCount string + Status string + Created string + ConversionInterval string + OverwriteData string + DecimalPlaceComparison string + SecondaryExchangeID string + IssueTolerancePercentage string + ReplaceOnIssue string }{ - ID: "id", - Nickname: "nickname", - ExchangeNameID: "exchange_name_id", - Asset: "asset", - Base: "base", - Quote: "quote", - StartTime: "start_time", - EndTime: "end_time", - Interval: "interval", - DataType: "data_type", - RequestSize: "request_size", - MaxRetries: "max_retries", - BatchCount: "batch_count", - Status: "status", - Created: "created", + ID: "id", + Nickname: "nickname", + ExchangeNameID: "exchange_name_id", + Asset: "asset", + Base: "base", + Quote: "quote", + StartTime: "start_time", + EndTime: "end_time", + Interval: "interval", + DataType: "data_type", + RequestSize: "request_size", + MaxRetries: "max_retries", + BatchCount: "batch_count", + Status: "status", + Created: "created", + ConversionInterval: "conversion_interval", + OverwriteData: "overwrite_data", + DecimalPlaceComparison: "decimal_place_comparison", + SecondaryExchangeID: "secondary_exchange_id", + IssueTolerancePercentage: "issue_tolerance_percentage", + ReplaceOnIssue: "replace_on_issue", } // Generated where +type whereHelpernull_Float64 struct{ field string } + +func (w whereHelpernull_Float64) EQ(x null.Float64) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, false, x) +} +func (w whereHelpernull_Float64) NEQ(x null.Float64) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, true, x) +} +func (w whereHelpernull_Float64) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } +func (w whereHelpernull_Float64) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } +func (w whereHelpernull_Float64) LT(x null.Float64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpernull_Float64) LTE(x null.Float64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpernull_Float64) GT(x null.Float64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpernull_Float64) GTE(x null.Float64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} + +type whereHelpernull_Int64 struct{ field string } + +func (w whereHelpernull_Int64) EQ(x null.Int64) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, false, x) +} +func (w whereHelpernull_Int64) NEQ(x null.Int64) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, true, x) +} +func (w whereHelpernull_Int64) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } +func (w whereHelpernull_Int64) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } +func (w whereHelpernull_Int64) LT(x null.Int64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpernull_Int64) LTE(x null.Int64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpernull_Int64) GT(x null.Int64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpernull_Int64) GTE(x null.Int64) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} + var DatahistoryjobWhere = struct { - ID whereHelperstring - Nickname whereHelperstring - ExchangeNameID whereHelperstring - Asset whereHelperstring - Base whereHelperstring - Quote whereHelperstring - StartTime whereHelperstring - EndTime whereHelperstring - Interval whereHelperfloat64 - DataType whereHelperfloat64 - RequestSize whereHelperfloat64 - MaxRetries whereHelperfloat64 - BatchCount whereHelperfloat64 - Status whereHelperfloat64 - Created whereHelperstring + ID whereHelperstring + Nickname whereHelperstring + ExchangeNameID whereHelperstring + Asset whereHelperstring + Base whereHelperstring + Quote whereHelperstring + StartTime whereHelperstring + EndTime whereHelperstring + Interval whereHelperfloat64 + DataType whereHelperfloat64 + RequestSize whereHelperfloat64 + MaxRetries whereHelperfloat64 + BatchCount whereHelperfloat64 + Status whereHelperfloat64 + Created whereHelperstring + ConversionInterval whereHelpernull_Float64 + OverwriteData whereHelpernull_Int64 + DecimalPlaceComparison whereHelpernull_Int64 + SecondaryExchangeID whereHelpernull_String + IssueTolerancePercentage whereHelpernull_Float64 + ReplaceOnIssue whereHelpernull_Int64 }{ - ID: whereHelperstring{field: "\"datahistoryjob\".\"id\""}, - Nickname: whereHelperstring{field: "\"datahistoryjob\".\"nickname\""}, - ExchangeNameID: whereHelperstring{field: "\"datahistoryjob\".\"exchange_name_id\""}, - Asset: whereHelperstring{field: "\"datahistoryjob\".\"asset\""}, - Base: whereHelperstring{field: "\"datahistoryjob\".\"base\""}, - Quote: whereHelperstring{field: "\"datahistoryjob\".\"quote\""}, - StartTime: whereHelperstring{field: "\"datahistoryjob\".\"start_time\""}, - EndTime: whereHelperstring{field: "\"datahistoryjob\".\"end_time\""}, - Interval: whereHelperfloat64{field: "\"datahistoryjob\".\"interval\""}, - DataType: whereHelperfloat64{field: "\"datahistoryjob\".\"data_type\""}, - RequestSize: whereHelperfloat64{field: "\"datahistoryjob\".\"request_size\""}, - MaxRetries: whereHelperfloat64{field: "\"datahistoryjob\".\"max_retries\""}, - BatchCount: whereHelperfloat64{field: "\"datahistoryjob\".\"batch_count\""}, - Status: whereHelperfloat64{field: "\"datahistoryjob\".\"status\""}, - Created: whereHelperstring{field: "\"datahistoryjob\".\"created\""}, + ID: whereHelperstring{field: "\"datahistoryjob\".\"id\""}, + Nickname: whereHelperstring{field: "\"datahistoryjob\".\"nickname\""}, + ExchangeNameID: whereHelperstring{field: "\"datahistoryjob\".\"exchange_name_id\""}, + Asset: whereHelperstring{field: "\"datahistoryjob\".\"asset\""}, + Base: whereHelperstring{field: "\"datahistoryjob\".\"base\""}, + Quote: whereHelperstring{field: "\"datahistoryjob\".\"quote\""}, + StartTime: whereHelperstring{field: "\"datahistoryjob\".\"start_time\""}, + EndTime: whereHelperstring{field: "\"datahistoryjob\".\"end_time\""}, + Interval: whereHelperfloat64{field: "\"datahistoryjob\".\"interval\""}, + DataType: whereHelperfloat64{field: "\"datahistoryjob\".\"data_type\""}, + RequestSize: whereHelperfloat64{field: "\"datahistoryjob\".\"request_size\""}, + MaxRetries: whereHelperfloat64{field: "\"datahistoryjob\".\"max_retries\""}, + BatchCount: whereHelperfloat64{field: "\"datahistoryjob\".\"batch_count\""}, + Status: whereHelperfloat64{field: "\"datahistoryjob\".\"status\""}, + Created: whereHelperstring{field: "\"datahistoryjob\".\"created\""}, + ConversionInterval: whereHelpernull_Float64{field: "\"datahistoryjob\".\"conversion_interval\""}, + OverwriteData: whereHelpernull_Int64{field: "\"datahistoryjob\".\"overwrite_data\""}, + DecimalPlaceComparison: whereHelpernull_Int64{field: "\"datahistoryjob\".\"decimal_place_comparison\""}, + SecondaryExchangeID: whereHelpernull_String{field: "\"datahistoryjob\".\"secondary_exchange_id\""}, + IssueTolerancePercentage: whereHelpernull_Float64{field: "\"datahistoryjob\".\"issue_tolerance_percentage\""}, + ReplaceOnIssue: whereHelpernull_Int64{field: "\"datahistoryjob\".\"replace_on_issue\""}, } // DatahistoryjobRels is where relationship names are stored. var DatahistoryjobRels = struct { - ExchangeName string - JobDatahistoryjobresults string + ExchangeName string + SecondaryExchange string + ValidationJobCandles string + SourceJobCandles string + PrerequisiteJobDatahistoryjobs string + JobDatahistoryjobs string + JobDatahistoryjobresults string }{ - ExchangeName: "ExchangeName", - JobDatahistoryjobresults: "JobDatahistoryjobresults", + ExchangeName: "ExchangeName", + SecondaryExchange: "SecondaryExchange", + ValidationJobCandles: "ValidationJobCandles", + SourceJobCandles: "SourceJobCandles", + PrerequisiteJobDatahistoryjobs: "PrerequisiteJobDatahistoryjobs", + JobDatahistoryjobs: "JobDatahistoryjobs", + JobDatahistoryjobresults: "JobDatahistoryjobresults", } // datahistoryjobR is where relationships are stored. type datahistoryjobR struct { - ExchangeName *Exchange - JobDatahistoryjobresults DatahistoryjobresultSlice + ExchangeName *Exchange + SecondaryExchange *Exchange + ValidationJobCandles CandleSlice + SourceJobCandles CandleSlice + PrerequisiteJobDatahistoryjobs DatahistoryjobSlice + JobDatahistoryjobs DatahistoryjobSlice + JobDatahistoryjobresults DatahistoryjobresultSlice } // NewStruct creates a new relationship struct @@ -136,8 +228,8 @@ func (*datahistoryjobR) NewStruct() *datahistoryjobR { type datahistoryjobL struct{} var ( - datahistoryjobAllColumns = []string{"id", "nickname", "exchange_name_id", "asset", "base", "quote", "start_time", "end_time", "interval", "data_type", "request_size", "max_retries", "batch_count", "status", "created"} - datahistoryjobColumnsWithoutDefault = []string{"id", "nickname", "exchange_name_id", "asset", "base", "quote", "start_time", "end_time", "interval", "data_type", "request_size", "max_retries", "batch_count", "status"} + datahistoryjobAllColumns = []string{"id", "nickname", "exchange_name_id", "asset", "base", "quote", "start_time", "end_time", "interval", "data_type", "request_size", "max_retries", "batch_count", "status", "created", "conversion_interval", "overwrite_data", "decimal_place_comparison", "secondary_exchange_id", "issue_tolerance_percentage", "replace_on_issue"} + datahistoryjobColumnsWithoutDefault = []string{"id", "nickname", "exchange_name_id", "asset", "base", "quote", "start_time", "end_time", "interval", "data_type", "request_size", "max_retries", "batch_count", "status", "conversion_interval", "overwrite_data", "decimal_place_comparison", "secondary_exchange_id", "issue_tolerance_percentage", "replace_on_issue"} datahistoryjobColumnsWithDefault = []string{"created"} datahistoryjobPrimaryKeyColumns = []string{"id"} ) @@ -431,6 +523,106 @@ func (o *Datahistoryjob) ExchangeName(mods ...qm.QueryMod) exchangeQuery { return query } +// SecondaryExchange pointed to by the foreign key. +func (o *Datahistoryjob) SecondaryExchange(mods ...qm.QueryMod) exchangeQuery { + queryMods := []qm.QueryMod{ + qm.Where("\"id\" = ?", o.SecondaryExchangeID), + } + + queryMods = append(queryMods, mods...) + + query := Exchanges(queryMods...) + queries.SetFrom(query.Query, "\"exchange\"") + + return query +} + +// ValidationJobCandles retrieves all the candle's Candles with an executor via validation_job_id column. +func (o *Datahistoryjob) ValidationJobCandles(mods ...qm.QueryMod) candleQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.Where("\"candle\".\"validation_job_id\"=?", o.ID), + ) + + query := Candles(queryMods...) + queries.SetFrom(query.Query, "\"candle\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"candle\".*"}) + } + + return query +} + +// SourceJobCandles retrieves all the candle's Candles with an executor via source_job_id column. +func (o *Datahistoryjob) SourceJobCandles(mods ...qm.QueryMod) candleQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.Where("\"candle\".\"source_job_id\"=?", o.ID), + ) + + query := Candles(queryMods...) + queries.SetFrom(query.Query, "\"candle\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"candle\".*"}) + } + + return query +} + +// PrerequisiteJobDatahistoryjobs retrieves all the datahistoryjob's Datahistoryjobs with an executor via id column. +func (o *Datahistoryjob) PrerequisiteJobDatahistoryjobs(mods ...qm.QueryMod) datahistoryjobQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.InnerJoin("\"datahistoryjobrelations\" on \"datahistoryjob\".\"id\" = \"datahistoryjobrelations\".\"prerequisite_job_id\""), + qm.Where("\"datahistoryjobrelations\".\"job_id\"=?", o.ID), + ) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"datahistoryjob\".*"}) + } + + return query +} + +// JobDatahistoryjobs retrieves all the datahistoryjob's Datahistoryjobs with an executor via id column. +func (o *Datahistoryjob) JobDatahistoryjobs(mods ...qm.QueryMod) datahistoryjobQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.InnerJoin("\"datahistoryjobrelations\" on \"datahistoryjob\".\"id\" = \"datahistoryjobrelations\".\"job_id\""), + qm.Where("\"datahistoryjobrelations\".\"prerequisite_job_id\"=?", o.ID), + ) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"datahistoryjob\".*"}) + } + + return query +} + // JobDatahistoryjobresults retrieves all the datahistoryjobresult's Datahistoryjobresults with an executor via job_id column. func (o *Datahistoryjob) JobDatahistoryjobresults(mods ...qm.QueryMod) datahistoryjobresultQuery { var queryMods []qm.QueryMod @@ -553,9 +745,114 @@ func (datahistoryjobL) LoadExchangeName(ctx context.Context, e boil.ContextExecu return nil } -// LoadJobDatahistoryjobresults allows an eager lookup of values, cached into the +// LoadSecondaryExchange allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for an N-1 relationship. +func (datahistoryjobL) LoadSecondaryExchange(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob + + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} + } + if !queries.IsNil(object.SecondaryExchangeID) { + args = append(args, object.SecondaryExchangeID) + } + + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } + + for _, a := range args { + if queries.Equal(a, obj.SecondaryExchangeID) { + continue Outer + } + } + + if !queries.IsNil(obj.SecondaryExchangeID) { + args = append(args, obj.SecondaryExchangeID) + } + + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`exchange`), qm.WhereIn(`exchange.id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load Exchange") + } + + var resultSlice []*Exchange + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice Exchange") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results of eager load for exchange") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for exchange") + } + + if len(datahistoryjobAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + + if len(resultSlice) == 0 { + return nil + } + + if singular { + foreign := resultSlice[0] + object.R.SecondaryExchange = foreign + if foreign.R == nil { + foreign.R = &exchangeR{} + } + foreign.R.SecondaryExchangeDatahistoryjobs = append(foreign.R.SecondaryExchangeDatahistoryjobs, object) + return nil + } + + for _, local := range slice { + for _, foreign := range resultSlice { + if queries.Equal(local.SecondaryExchangeID, foreign.ID) { + local.R.SecondaryExchange = foreign + if foreign.R == nil { + foreign.R = &exchangeR{} + } + foreign.R.SecondaryExchangeDatahistoryjobs = append(foreign.R.SecondaryExchangeDatahistoryjobs, local) + break + } + } + } + + return nil +} + +// LoadValidationJobCandles allows an eager lookup of values, cached into the // loaded structs of the objects. This is for a 1-M or N-M relationship. -func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { +func (datahistoryjobL) LoadValidationJobCandles(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { var slice []*Datahistoryjob var object *Datahistoryjob @@ -579,7 +876,7 @@ func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil. } for _, a := range args { - if a == obj.ID { + if queries.Equal(a, obj.ID) { continue Outer } } @@ -592,29 +889,29 @@ func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil. return nil } - query := NewQuery(qm.From(`datahistoryjobresult`), qm.WhereIn(`datahistoryjobresult.job_id in ?`, args...)) + query := NewQuery(qm.From(`candle`), qm.WhereIn(`candle.validation_job_id in ?`, args...)) if mods != nil { mods.Apply(query) } results, err := query.QueryContext(ctx, e) if err != nil { - return errors.Wrap(err, "failed to eager load datahistoryjobresult") + return errors.Wrap(err, "failed to eager load candle") } - var resultSlice []*Datahistoryjobresult + var resultSlice []*Candle if err = queries.Bind(results, &resultSlice); err != nil { - return errors.Wrap(err, "failed to bind eager loaded slice datahistoryjobresult") + return errors.Wrap(err, "failed to bind eager loaded slice candle") } if err = results.Close(); err != nil { - return errors.Wrap(err, "failed to close results in eager load on datahistoryjobresult") + return errors.Wrap(err, "failed to close results in eager load on candle") } if err = results.Err(); err != nil { - return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjobresult") + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for candle") } - if len(datahistoryjobresultAfterSelectHooks) != 0 { + if len(candleAfterSelectHooks) != 0 { for _, obj := range resultSlice { if err := obj.doAfterSelectHooks(ctx, e); err != nil { return err @@ -622,24 +919,24 @@ func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil. } } if singular { - object.R.JobDatahistoryjobresults = resultSlice + object.R.ValidationJobCandles = resultSlice for _, foreign := range resultSlice { if foreign.R == nil { - foreign.R = &datahistoryjobresultR{} + foreign.R = &candleR{} } - foreign.R.Job = object + foreign.R.ValidationJob = object } return nil } for _, foreign := range resultSlice { for _, local := range slice { - if local.ID == foreign.JobID { - local.R.JobDatahistoryjobresults = append(local.R.JobDatahistoryjobresults, foreign) + if queries.Equal(local.ID, foreign.ValidationJobID) { + local.R.ValidationJobCandles = append(local.R.ValidationJobCandles, foreign) if foreign.R == nil { - foreign.R = &datahistoryjobresultR{} + foreign.R = &candleR{} } - foreign.R.Job = local + foreign.R.ValidationJob = local break } } @@ -648,51 +945,1075 @@ func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil. return nil } -// SetExchangeName of the datahistoryjob to the related item. -// Sets o.R.ExchangeName to related. -// Adds o to related.R.ExchangeNameDatahistoryjobs. -func (o *Datahistoryjob) SetExchangeName(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Exchange) error { - var err error - if insert { - if err = related.Insert(ctx, exec, boil.Infer()); err != nil { - return errors.Wrap(err, "failed to insert into foreign table") - } - } - - updateQuery := fmt.Sprintf( - "UPDATE \"datahistoryjob\" SET %s WHERE %s", - strmangle.SetParamNames("\"", "\"", 0, []string{"exchange_name_id"}), - strmangle.WhereClause("\"", "\"", 0, datahistoryjobPrimaryKeyColumns), - ) - values := []interface{}{related.ID, o.ID} - - if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, updateQuery) - fmt.Fprintln(boil.DebugWriter, values) - } +// LoadSourceJobCandles allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (datahistoryjobL) LoadSourceJobCandles(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob - if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { - return errors.Wrap(err, "failed to update local table") + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) } - o.ExchangeNameID = related.ID - if o.R == nil { - o.R = &datahistoryjobR{ - ExchangeName: related, + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} } + args = append(args, object.ID) } else { - o.R.ExchangeName = related - } + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } - if related.R == nil { - related.R = &exchangeR{ - ExchangeNameDatahistoryjobs: DatahistoryjobSlice{o}, + for _, a := range args { + if queries.Equal(a, obj.ID) { + continue Outer + } + } + + args = append(args, obj.ID) } - } else { - related.R.ExchangeNameDatahistoryjobs = append(related.R.ExchangeNameDatahistoryjobs, o) } - return nil + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`candle`), qm.WhereIn(`candle.source_job_id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load candle") + } + + var resultSlice []*Candle + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice candle") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on candle") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for candle") + } + + if len(candleAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.SourceJobCandles = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &candleR{} + } + foreign.R.SourceJob = object + } + return nil + } + + for _, foreign := range resultSlice { + for _, local := range slice { + if queries.Equal(local.ID, foreign.SourceJobID) { + local.R.SourceJobCandles = append(local.R.SourceJobCandles, foreign) + if foreign.R == nil { + foreign.R = &candleR{} + } + foreign.R.SourceJob = local + break + } + } + } + + return nil +} + +// LoadPrerequisiteJobDatahistoryjobs allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (datahistoryjobL) LoadPrerequisiteJobDatahistoryjobs(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob + + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } + + for _, a := range args { + if a == obj.ID { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery( + qm.Select("\"datahistoryjob\".*, \"a\".\"job_id\""), + qm.From("\"datahistoryjob\""), + qm.InnerJoin("\"datahistoryjobrelations\" as \"a\" on \"datahistoryjob\".\"id\" = \"a\".\"prerequisite_job_id\""), + qm.WhereIn("\"a\".\"job_id\" in ?", args...), + ) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load datahistoryjob") + } + + var resultSlice []*Datahistoryjob + + var localJoinCols []string + for results.Next() { + one := new(Datahistoryjob) + var localJoinCol string + + err = results.Scan(&one.ID, &one.Nickname, &one.ExchangeNameID, &one.Asset, &one.Base, &one.Quote, &one.StartTime, &one.EndTime, &one.Interval, &one.DataType, &one.RequestSize, &one.MaxRetries, &one.BatchCount, &one.Status, &one.Created, &one.ConversionInterval, &one.OverwriteData, &one.DecimalPlaceComparison, &one.SecondaryExchangeID, &one.IssueTolerancePercentage, &one.ReplaceOnIssue, &localJoinCol) + if err != nil { + return errors.Wrap(err, "failed to scan eager loaded results for datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "failed to plebian-bind eager loaded slice datahistoryjob") + } + + resultSlice = append(resultSlice, one) + localJoinCols = append(localJoinCols, localJoinCol) + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(datahistoryjobAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.PrerequisiteJobDatahistoryjobs = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.JobDatahistoryjobs = append(foreign.R.JobDatahistoryjobs, object) + } + return nil + } + + for i, foreign := range resultSlice { + localJoinCol := localJoinCols[i] + for _, local := range slice { + if local.ID == localJoinCol { + local.R.PrerequisiteJobDatahistoryjobs = append(local.R.PrerequisiteJobDatahistoryjobs, foreign) + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.JobDatahistoryjobs = append(foreign.R.JobDatahistoryjobs, local) + break + } + } + } + + return nil +} + +// LoadJobDatahistoryjobs allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (datahistoryjobL) LoadJobDatahistoryjobs(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob + + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } + + for _, a := range args { + if a == obj.ID { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery( + qm.Select("\"datahistoryjob\".*, \"a\".\"prerequisite_job_id\""), + qm.From("\"datahistoryjob\""), + qm.InnerJoin("\"datahistoryjobrelations\" as \"a\" on \"datahistoryjob\".\"id\" = \"a\".\"job_id\""), + qm.WhereIn("\"a\".\"prerequisite_job_id\" in ?", args...), + ) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load datahistoryjob") + } + + var resultSlice []*Datahistoryjob + + var localJoinCols []string + for results.Next() { + one := new(Datahistoryjob) + var localJoinCol string + + err = results.Scan(&one.ID, &one.Nickname, &one.ExchangeNameID, &one.Asset, &one.Base, &one.Quote, &one.StartTime, &one.EndTime, &one.Interval, &one.DataType, &one.RequestSize, &one.MaxRetries, &one.BatchCount, &one.Status, &one.Created, &one.ConversionInterval, &one.OverwriteData, &one.DecimalPlaceComparison, &one.SecondaryExchangeID, &one.IssueTolerancePercentage, &one.ReplaceOnIssue, &localJoinCol) + if err != nil { + return errors.Wrap(err, "failed to scan eager loaded results for datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "failed to plebian-bind eager loaded slice datahistoryjob") + } + + resultSlice = append(resultSlice, one) + localJoinCols = append(localJoinCols, localJoinCol) + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(datahistoryjobAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.JobDatahistoryjobs = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.PrerequisiteJobDatahistoryjobs = append(foreign.R.PrerequisiteJobDatahistoryjobs, object) + } + return nil + } + + for i, foreign := range resultSlice { + localJoinCol := localJoinCols[i] + for _, local := range slice { + if local.ID == localJoinCol { + local.R.JobDatahistoryjobs = append(local.R.JobDatahistoryjobs, foreign) + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.PrerequisiteJobDatahistoryjobs = append(foreign.R.PrerequisiteJobDatahistoryjobs, local) + break + } + } + } + + return nil +} + +// LoadJobDatahistoryjobresults allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (datahistoryjobL) LoadJobDatahistoryjobresults(ctx context.Context, e boil.ContextExecutor, singular bool, maybeDatahistoryjob interface{}, mods queries.Applicator) error { + var slice []*Datahistoryjob + var object *Datahistoryjob + + if singular { + object = maybeDatahistoryjob.(*Datahistoryjob) + } else { + slice = *maybeDatahistoryjob.(*[]*Datahistoryjob) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &datahistoryjobR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &datahistoryjobR{} + } + + for _, a := range args { + if a == obj.ID { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`datahistoryjobresult`), qm.WhereIn(`datahistoryjobresult.job_id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load datahistoryjobresult") + } + + var resultSlice []*Datahistoryjobresult + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice datahistoryjobresult") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on datahistoryjobresult") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjobresult") + } + + if len(datahistoryjobresultAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.JobDatahistoryjobresults = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &datahistoryjobresultR{} + } + foreign.R.Job = object + } + return nil + } + + for _, foreign := range resultSlice { + for _, local := range slice { + if local.ID == foreign.JobID { + local.R.JobDatahistoryjobresults = append(local.R.JobDatahistoryjobresults, foreign) + if foreign.R == nil { + foreign.R = &datahistoryjobresultR{} + } + foreign.R.Job = local + break + } + } + } + + return nil +} + +// SetExchangeName of the datahistoryjob to the related item. +// Sets o.R.ExchangeName to related. +// Adds o to related.R.ExchangeNameDatahistoryjobs. +func (o *Datahistoryjob) SetExchangeName(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Exchange) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"datahistoryjob\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, []string{"exchange_name_id"}), + strmangle.WhereClause("\"", "\"", 0, datahistoryjobPrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + o.ExchangeNameID = related.ID + if o.R == nil { + o.R = &datahistoryjobR{ + ExchangeName: related, + } + } else { + o.R.ExchangeName = related + } + + if related.R == nil { + related.R = &exchangeR{ + ExchangeNameDatahistoryjobs: DatahistoryjobSlice{o}, + } + } else { + related.R.ExchangeNameDatahistoryjobs = append(related.R.ExchangeNameDatahistoryjobs, o) + } + + return nil +} + +// SetSecondaryExchange of the datahistoryjob to the related item. +// Sets o.R.SecondaryExchange to related. +// Adds o to related.R.SecondaryExchangeDatahistoryjobs. +func (o *Datahistoryjob) SetSecondaryExchange(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Exchange) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"datahistoryjob\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, []string{"secondary_exchange_id"}), + strmangle.WhereClause("\"", "\"", 0, datahistoryjobPrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + queries.Assign(&o.SecondaryExchangeID, related.ID) + if o.R == nil { + o.R = &datahistoryjobR{ + SecondaryExchange: related, + } + } else { + o.R.SecondaryExchange = related + } + + if related.R == nil { + related.R = &exchangeR{ + SecondaryExchangeDatahistoryjobs: DatahistoryjobSlice{o}, + } + } else { + related.R.SecondaryExchangeDatahistoryjobs = append(related.R.SecondaryExchangeDatahistoryjobs, o) + } + + return nil +} + +// RemoveSecondaryExchange relationship. +// Sets o.R.SecondaryExchange to nil. +// Removes o from all passed in related items' relationships struct (Optional). +func (o *Datahistoryjob) RemoveSecondaryExchange(ctx context.Context, exec boil.ContextExecutor, related *Exchange) error { + var err error + + queries.SetScanner(&o.SecondaryExchangeID, nil) + if _, err = o.Update(ctx, exec, boil.Whitelist("secondary_exchange_id")); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + o.R.SecondaryExchange = nil + if related == nil || related.R == nil { + return nil + } + + for i, ri := range related.R.SecondaryExchangeDatahistoryjobs { + if queries.Equal(o.SecondaryExchangeID, ri.SecondaryExchangeID) { + continue + } + + ln := len(related.R.SecondaryExchangeDatahistoryjobs) + if ln > 1 && i < ln-1 { + related.R.SecondaryExchangeDatahistoryjobs[i] = related.R.SecondaryExchangeDatahistoryjobs[ln-1] + } + related.R.SecondaryExchangeDatahistoryjobs = related.R.SecondaryExchangeDatahistoryjobs[:ln-1] + break + } + return nil +} + +// AddValidationJobCandles adds the given related objects to the existing relationships +// of the datahistoryjob, optionally inserting them as new records. +// Appends related to o.R.ValidationJobCandles. +// Sets related.R.ValidationJob appropriately. +func (o *Datahistoryjob) AddValidationJobCandles(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Candle) error { + var err error + for _, rel := range related { + if insert { + queries.Assign(&rel.ValidationJobID, o.ID) + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } else { + updateQuery := fmt.Sprintf( + "UPDATE \"candle\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, []string{"validation_job_id"}), + strmangle.WhereClause("\"", "\"", 0, candlePrimaryKeyColumns), + ) + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update foreign table") + } + + queries.Assign(&rel.ValidationJobID, o.ID) + } + } + + if o.R == nil { + o.R = &datahistoryjobR{ + ValidationJobCandles: related, + } + } else { + o.R.ValidationJobCandles = append(o.R.ValidationJobCandles, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &candleR{ + ValidationJob: o, + } + } else { + rel.R.ValidationJob = o + } + } + return nil +} + +// SetValidationJobCandles removes all previously related items of the +// datahistoryjob replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.ValidationJob's ValidationJobCandles accordingly. +// Replaces o.R.ValidationJobCandles with related. +// Sets related.R.ValidationJob's ValidationJobCandles accordingly. +func (o *Datahistoryjob) SetValidationJobCandles(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Candle) error { + query := "update \"candle\" set \"validation_job_id\" = null where \"validation_job_id\" = ?" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + if o.R != nil { + for _, rel := range o.R.ValidationJobCandles { + queries.SetScanner(&rel.ValidationJobID, nil) + if rel.R == nil { + continue + } + + rel.R.ValidationJob = nil + } + + o.R.ValidationJobCandles = nil + } + return o.AddValidationJobCandles(ctx, exec, insert, related...) +} + +// RemoveValidationJobCandles relationships from objects passed in. +// Removes related items from R.ValidationJobCandles (uses pointer comparison, removal does not keep order) +// Sets related.R.ValidationJob. +func (o *Datahistoryjob) RemoveValidationJobCandles(ctx context.Context, exec boil.ContextExecutor, related ...*Candle) error { + var err error + for _, rel := range related { + queries.SetScanner(&rel.ValidationJobID, nil) + if rel.R != nil { + rel.R.ValidationJob = nil + } + if _, err = rel.Update(ctx, exec, boil.Whitelist("validation_job_id")); err != nil { + return err + } + } + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.ValidationJobCandles { + if rel != ri { + continue + } + + ln := len(o.R.ValidationJobCandles) + if ln > 1 && i < ln-1 { + o.R.ValidationJobCandles[i] = o.R.ValidationJobCandles[ln-1] + } + o.R.ValidationJobCandles = o.R.ValidationJobCandles[:ln-1] + break + } + } + + return nil +} + +// AddSourceJobCandles adds the given related objects to the existing relationships +// of the datahistoryjob, optionally inserting them as new records. +// Appends related to o.R.SourceJobCandles. +// Sets related.R.SourceJob appropriately. +func (o *Datahistoryjob) AddSourceJobCandles(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Candle) error { + var err error + for _, rel := range related { + if insert { + queries.Assign(&rel.SourceJobID, o.ID) + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } else { + updateQuery := fmt.Sprintf( + "UPDATE \"candle\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, []string{"source_job_id"}), + strmangle.WhereClause("\"", "\"", 0, candlePrimaryKeyColumns), + ) + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update foreign table") + } + + queries.Assign(&rel.SourceJobID, o.ID) + } + } + + if o.R == nil { + o.R = &datahistoryjobR{ + SourceJobCandles: related, + } + } else { + o.R.SourceJobCandles = append(o.R.SourceJobCandles, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &candleR{ + SourceJob: o, + } + } else { + rel.R.SourceJob = o + } + } + return nil +} + +// SetSourceJobCandles removes all previously related items of the +// datahistoryjob replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.SourceJob's SourceJobCandles accordingly. +// Replaces o.R.SourceJobCandles with related. +// Sets related.R.SourceJob's SourceJobCandles accordingly. +func (o *Datahistoryjob) SetSourceJobCandles(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Candle) error { + query := "update \"candle\" set \"source_job_id\" = null where \"source_job_id\" = ?" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + if o.R != nil { + for _, rel := range o.R.SourceJobCandles { + queries.SetScanner(&rel.SourceJobID, nil) + if rel.R == nil { + continue + } + + rel.R.SourceJob = nil + } + + o.R.SourceJobCandles = nil + } + return o.AddSourceJobCandles(ctx, exec, insert, related...) +} + +// RemoveSourceJobCandles relationships from objects passed in. +// Removes related items from R.SourceJobCandles (uses pointer comparison, removal does not keep order) +// Sets related.R.SourceJob. +func (o *Datahistoryjob) RemoveSourceJobCandles(ctx context.Context, exec boil.ContextExecutor, related ...*Candle) error { + var err error + for _, rel := range related { + queries.SetScanner(&rel.SourceJobID, nil) + if rel.R != nil { + rel.R.SourceJob = nil + } + if _, err = rel.Update(ctx, exec, boil.Whitelist("source_job_id")); err != nil { + return err + } + } + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.SourceJobCandles { + if rel != ri { + continue + } + + ln := len(o.R.SourceJobCandles) + if ln > 1 && i < ln-1 { + o.R.SourceJobCandles[i] = o.R.SourceJobCandles[ln-1] + } + o.R.SourceJobCandles = o.R.SourceJobCandles[:ln-1] + break + } + } + + return nil +} + +// AddPrerequisiteJobDatahistoryjobs adds the given related objects to the existing relationships +// of the datahistoryjob, optionally inserting them as new records. +// Appends related to o.R.PrerequisiteJobDatahistoryjobs. +// Sets related.R.JobDatahistoryjobs appropriately. +func (o *Datahistoryjob) AddPrerequisiteJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + var err error + for _, rel := range related { + if insert { + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + } + + for _, rel := range related { + query := "insert into \"datahistoryjobrelations\" (\"job_id\", \"prerequisite_job_id\") values (?, ?)" + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err = exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to insert into join table") + } + } + if o.R == nil { + o.R = &datahistoryjobR{ + PrerequisiteJobDatahistoryjobs: related, + } + } else { + o.R.PrerequisiteJobDatahistoryjobs = append(o.R.PrerequisiteJobDatahistoryjobs, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &datahistoryjobR{ + JobDatahistoryjobs: DatahistoryjobSlice{o}, + } + } else { + rel.R.JobDatahistoryjobs = append(rel.R.JobDatahistoryjobs, o) + } + } + return nil +} + +// SetPrerequisiteJobDatahistoryjobs removes all previously related items of the +// datahistoryjob replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.JobDatahistoryjobs's PrerequisiteJobDatahistoryjobs accordingly. +// Replaces o.R.PrerequisiteJobDatahistoryjobs with related. +// Sets related.R.JobDatahistoryjobs's PrerequisiteJobDatahistoryjobs accordingly. +func (o *Datahistoryjob) SetPrerequisiteJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + query := "delete from \"datahistoryjobrelations\" where \"job_id\" = ?" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + removePrerequisiteJobDatahistoryjobsFromJobDatahistoryjobsSlice(o, related) + if o.R != nil { + o.R.PrerequisiteJobDatahistoryjobs = nil + } + return o.AddPrerequisiteJobDatahistoryjobs(ctx, exec, insert, related...) +} + +// RemovePrerequisiteJobDatahistoryjobs relationships from objects passed in. +// Removes related items from R.PrerequisiteJobDatahistoryjobs (uses pointer comparison, removal does not keep order) +// Sets related.R.JobDatahistoryjobs. +func (o *Datahistoryjob) RemovePrerequisiteJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, related ...*Datahistoryjob) error { + var err error + query := fmt.Sprintf( + "delete from \"datahistoryjobrelations\" where \"job_id\" = ? and \"prerequisite_job_id\" in (%s)", + strmangle.Placeholders(dialect.UseIndexPlaceholders, len(related), 2, 1), + ) + values := []interface{}{o.ID} + for _, rel := range related { + values = append(values, rel.ID) + } + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err = exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + removePrerequisiteJobDatahistoryjobsFromJobDatahistoryjobsSlice(o, related) + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.PrerequisiteJobDatahistoryjobs { + if rel != ri { + continue + } + + ln := len(o.R.PrerequisiteJobDatahistoryjobs) + if ln > 1 && i < ln-1 { + o.R.PrerequisiteJobDatahistoryjobs[i] = o.R.PrerequisiteJobDatahistoryjobs[ln-1] + } + o.R.PrerequisiteJobDatahistoryjobs = o.R.PrerequisiteJobDatahistoryjobs[:ln-1] + break + } + } + + return nil +} + +func removePrerequisiteJobDatahistoryjobsFromJobDatahistoryjobsSlice(o *Datahistoryjob, related []*Datahistoryjob) { + for _, rel := range related { + if rel.R == nil { + continue + } + for i, ri := range rel.R.JobDatahistoryjobs { + if o.ID != ri.ID { + continue + } + + ln := len(rel.R.JobDatahistoryjobs) + if ln > 1 && i < ln-1 { + rel.R.JobDatahistoryjobs[i] = rel.R.JobDatahistoryjobs[ln-1] + } + rel.R.JobDatahistoryjobs = rel.R.JobDatahistoryjobs[:ln-1] + break + } + } +} + +// AddJobDatahistoryjobs adds the given related objects to the existing relationships +// of the datahistoryjob, optionally inserting them as new records. +// Appends related to o.R.JobDatahistoryjobs. +// Sets related.R.PrerequisiteJobDatahistoryjobs appropriately. +func (o *Datahistoryjob) AddJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + var err error + for _, rel := range related { + if insert { + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + } + + for _, rel := range related { + query := "insert into \"datahistoryjobrelations\" (\"prerequisite_job_id\", \"job_id\") values (?, ?)" + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err = exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to insert into join table") + } + } + if o.R == nil { + o.R = &datahistoryjobR{ + JobDatahistoryjobs: related, + } + } else { + o.R.JobDatahistoryjobs = append(o.R.JobDatahistoryjobs, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &datahistoryjobR{ + PrerequisiteJobDatahistoryjobs: DatahistoryjobSlice{o}, + } + } else { + rel.R.PrerequisiteJobDatahistoryjobs = append(rel.R.PrerequisiteJobDatahistoryjobs, o) + } + } + return nil +} + +// SetJobDatahistoryjobs removes all previously related items of the +// datahistoryjob replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.PrerequisiteJobDatahistoryjobs's JobDatahistoryjobs accordingly. +// Replaces o.R.JobDatahistoryjobs with related. +// Sets related.R.PrerequisiteJobDatahistoryjobs's JobDatahistoryjobs accordingly. +func (o *Datahistoryjob) SetJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + query := "delete from \"datahistoryjobrelations\" where \"prerequisite_job_id\" = ?" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + removeJobDatahistoryjobsFromPrerequisiteJobDatahistoryjobsSlice(o, related) + if o.R != nil { + o.R.JobDatahistoryjobs = nil + } + return o.AddJobDatahistoryjobs(ctx, exec, insert, related...) +} + +// RemoveJobDatahistoryjobs relationships from objects passed in. +// Removes related items from R.JobDatahistoryjobs (uses pointer comparison, removal does not keep order) +// Sets related.R.PrerequisiteJobDatahistoryjobs. +func (o *Datahistoryjob) RemoveJobDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, related ...*Datahistoryjob) error { + var err error + query := fmt.Sprintf( + "delete from \"datahistoryjobrelations\" where \"prerequisite_job_id\" = ? and \"job_id\" in (%s)", + strmangle.Placeholders(dialect.UseIndexPlaceholders, len(related), 2, 1), + ) + values := []interface{}{o.ID} + for _, rel := range related { + values = append(values, rel.ID) + } + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err = exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + removeJobDatahistoryjobsFromPrerequisiteJobDatahistoryjobsSlice(o, related) + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.JobDatahistoryjobs { + if rel != ri { + continue + } + + ln := len(o.R.JobDatahistoryjobs) + if ln > 1 && i < ln-1 { + o.R.JobDatahistoryjobs[i] = o.R.JobDatahistoryjobs[ln-1] + } + o.R.JobDatahistoryjobs = o.R.JobDatahistoryjobs[:ln-1] + break + } + } + + return nil +} + +func removeJobDatahistoryjobsFromPrerequisiteJobDatahistoryjobsSlice(o *Datahistoryjob, related []*Datahistoryjob) { + for _, rel := range related { + if rel.R == nil { + continue + } + for i, ri := range rel.R.PrerequisiteJobDatahistoryjobs { + if o.ID != ri.ID { + continue + } + + ln := len(rel.R.PrerequisiteJobDatahistoryjobs) + if ln > 1 && i < ln-1 { + rel.R.PrerequisiteJobDatahistoryjobs[i] = rel.R.PrerequisiteJobDatahistoryjobs[ln-1] + } + rel.R.PrerequisiteJobDatahistoryjobs = rel.R.PrerequisiteJobDatahistoryjobs[:ln-1] + break + } + } } // AddJobDatahistoryjobresults adds the given related objects to the existing relationships diff --git a/database/models/sqlite3/datahistoryjob_test.go b/database/models/sqlite3/datahistoryjob_test.go index 8a5f4aad418..313114ef3e8 100644 --- a/database/models/sqlite3/datahistoryjob_test.go +++ b/database/models/sqlite3/datahistoryjob_test.go @@ -494,6 +494,328 @@ func testDatahistoryjobsInsertWhitelist(t *testing.T) { } } +func testDatahistoryjobToManyValidationJobCandles(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, candleDBTypes, false, candleColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, candleDBTypes, false, candleColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + queries.Assign(&b.ValidationJobID, a.ID) + queries.Assign(&c.ValidationJobID, a.ID) + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := a.ValidationJobCandles().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if queries.Equal(v.ValidationJobID, b.ValidationJobID) { + bFound = true + } + if queries.Equal(v.ValidationJobID, c.ValidationJobID) { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadValidationJobCandles(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.ValidationJobCandles); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.ValidationJobCandles = nil + if err = a.L.LoadValidationJobCandles(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.ValidationJobCandles); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + +func testDatahistoryjobToManySourceJobCandles(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, candleDBTypes, false, candleColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, candleDBTypes, false, candleColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + queries.Assign(&b.SourceJobID, a.ID) + queries.Assign(&c.SourceJobID, a.ID) + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := a.SourceJobCandles().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if queries.Equal(v.SourceJobID, b.SourceJobID) { + bFound = true + } + if queries.Equal(v.SourceJobID, c.SourceJobID) { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadSourceJobCandles(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.SourceJobCandles); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.SourceJobCandles = nil + if err = a.L.LoadSourceJobCandles(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.SourceJobCandles); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + +func testDatahistoryjobToManyPrerequisiteJobDatahistoryjobs(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + _, err = tx.Exec("insert into \"datahistoryjobrelations\" (\"job_id\", \"prerequisite_job_id\") values (?, ?)", a.ID, b.ID) + if err != nil { + t.Fatal(err) + } + _, err = tx.Exec("insert into \"datahistoryjobrelations\" (\"job_id\", \"prerequisite_job_id\") values (?, ?)", a.ID, c.ID) + if err != nil { + t.Fatal(err) + } + + check, err := a.PrerequisiteJobDatahistoryjobs().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if v.ID == b.ID { + bFound = true + } + if v.ID == c.ID { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadPrerequisiteJobDatahistoryjobs(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.PrerequisiteJobDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.PrerequisiteJobDatahistoryjobs = nil + if err = a.L.LoadPrerequisiteJobDatahistoryjobs(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.PrerequisiteJobDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + +func testDatahistoryjobToManyJobDatahistoryjobs(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + _, err = tx.Exec("insert into \"datahistoryjobrelations\" (\"prerequisite_job_id\", \"job_id\") values (?, ?)", a.ID, b.ID) + if err != nil { + t.Fatal(err) + } + _, err = tx.Exec("insert into \"datahistoryjobrelations\" (\"prerequisite_job_id\", \"job_id\") values (?, ?)", a.ID, c.ID) + if err != nil { + t.Fatal(err) + } + + check, err := a.JobDatahistoryjobs().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if v.ID == b.ID { + bFound = true + } + if v.ID == c.ID { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadJobDatahistoryjobs(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.JobDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.JobDatahistoryjobs = nil + if err = a.L.LoadJobDatahistoryjobs(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.JobDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + func testDatahistoryjobToManyJobDatahistoryjobresults(t *testing.T) { var err error ctx := context.Background() @@ -501,74 +823,1032 @@ func testDatahistoryjobToManyJobDatahistoryjobresults(t *testing.T) { defer func() { _ = tx.Rollback() }() var a Datahistoryjob - var b, c Datahistoryjobresult + var b, c Datahistoryjobresult + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, datahistoryjobresultDBTypes, false, datahistoryjobresultColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobresultDBTypes, false, datahistoryjobresultColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + b.JobID = a.ID + c.JobID = a.ID + + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := a.JobDatahistoryjobresults().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if v.JobID == b.JobID { + bFound = true + } + if v.JobID == c.JobID { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := DatahistoryjobSlice{&a} + if err = a.L.LoadJobDatahistoryjobresults(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.JobDatahistoryjobresults); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.JobDatahistoryjobresults = nil + if err = a.L.LoadJobDatahistoryjobresults(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.JobDatahistoryjobresults); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + +func testDatahistoryjobToManyAddOpValidationJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Candle{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddValidationJobCandles(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if !queries.Equal(a.ID, first.ValidationJobID) { + t.Error("foreign key was wrong value", a.ID, first.ValidationJobID) + } + if !queries.Equal(a.ID, second.ValidationJobID) { + t.Error("foreign key was wrong value", a.ID, second.ValidationJobID) + } + + if first.R.ValidationJob != &a { + t.Error("relationship was not added properly to the foreign slice") + } + if second.R.ValidationJob != &a { + t.Error("relationship was not added properly to the foreign slice") + } + + if a.R.ValidationJobCandles[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.ValidationJobCandles[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testDatahistoryjobToManySetOpValidationJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.SetValidationJobCandles(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } + + count, err := a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetValidationJobCandles(ctx, tx, true, &d, &e) + if err != nil { + t.Fatal(err) + } + + count, err = a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.ValidationJobID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.ValidationJobID) { + t.Error("want c's foreign key value to be nil") + } + if !queries.Equal(a.ID, d.ValidationJobID) { + t.Error("foreign key was wrong value", a.ID, d.ValidationJobID) + } + if !queries.Equal(a.ID, e.ValidationJobID) { + t.Error("foreign key was wrong value", a.ID, e.ValidationJobID) + } + + if b.R.ValidationJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.ValidationJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.ValidationJob != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.ValidationJob != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if a.R.ValidationJobCandles[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.ValidationJobCandles[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testDatahistoryjobToManyRemoveOpValidationJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.AddValidationJobCandles(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) + } + + count, err := a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 4 { + t.Error("count was wrong:", count) + } + + err = a.RemoveValidationJobCandles(ctx, tx, foreigners[:2]...) + if err != nil { + t.Fatal(err) + } + + count, err = a.ValidationJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.ValidationJobID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.ValidationJobID) { + t.Error("want c's foreign key value to be nil") + } + + if b.R.ValidationJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.ValidationJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.ValidationJob != &a { + t.Error("relationship to a should have been preserved") + } + if e.R.ValidationJob != &a { + t.Error("relationship to a should have been preserved") + } + + if len(a.R.ValidationJobCandles) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.ValidationJobCandles[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.ValidationJobCandles[0] != &e { + t.Error("relationship to e should have been preserved") + } +} + +func testDatahistoryjobToManyAddOpSourceJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Candle{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddSourceJobCandles(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if !queries.Equal(a.ID, first.SourceJobID) { + t.Error("foreign key was wrong value", a.ID, first.SourceJobID) + } + if !queries.Equal(a.ID, second.SourceJobID) { + t.Error("foreign key was wrong value", a.ID, second.SourceJobID) + } + + if first.R.SourceJob != &a { + t.Error("relationship was not added properly to the foreign slice") + } + if second.R.SourceJob != &a { + t.Error("relationship was not added properly to the foreign slice") + } + + if a.R.SourceJobCandles[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.SourceJobCandles[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testDatahistoryjobToManySetOpSourceJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.SetSourceJobCandles(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } + + count, err := a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetSourceJobCandles(ctx, tx, true, &d, &e) + if err != nil { + t.Fatal(err) + } + + count, err = a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.SourceJobID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.SourceJobID) { + t.Error("want c's foreign key value to be nil") + } + if !queries.Equal(a.ID, d.SourceJobID) { + t.Error("foreign key was wrong value", a.ID, d.SourceJobID) + } + if !queries.Equal(a.ID, e.SourceJobID) { + t.Error("foreign key was wrong value", a.ID, e.SourceJobID) + } + + if b.R.SourceJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.SourceJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.SourceJob != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.SourceJob != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if a.R.SourceJobCandles[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.SourceJobCandles[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testDatahistoryjobToManyRemoveOpSourceJobCandles(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Candle + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Candle{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, candleDBTypes, false, strmangle.SetComplement(candlePrimaryKeyColumns, candleColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.AddSourceJobCandles(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) + } + + count, err := a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 4 { + t.Error("count was wrong:", count) + } + + err = a.RemoveSourceJobCandles(ctx, tx, foreigners[:2]...) + if err != nil { + t.Fatal(err) + } + + count, err = a.SourceJobCandles().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.SourceJobID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.SourceJobID) { + t.Error("want c's foreign key value to be nil") + } + + if b.R.SourceJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.SourceJob != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.SourceJob != &a { + t.Error("relationship to a should have been preserved") + } + if e.R.SourceJob != &a { + t.Error("relationship to a should have been preserved") + } + + if len(a.R.SourceJobCandles) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.SourceJobCandles[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.SourceJobCandles[0] != &e { + t.Error("relationship to e should have been preserved") + } +} + +func testDatahistoryjobToManyAddOpPrerequisiteJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Datahistoryjob{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddPrerequisiteJobDatahistoryjobs(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if first.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + if second.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + + if a.R.PrerequisiteJobDatahistoryjobs[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.PrerequisiteJobDatahistoryjobs[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testDatahistoryjobToManySetOpPrerequisiteJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.SetPrerequisiteJobDatahistoryjobs(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } + + count, err := a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetPrerequisiteJobDatahistoryjobs(ctx, tx, true, &d, &e) + if err != nil { + t.Fatal(err) + } + + count, err = a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + // The following checks cannot be implemented since we have no handle + // to these when we call Set(). Leaving them here as wishful thinking + // and to let people know there's dragons. + // + // if len(b.R.JobDatahistoryjobs) != 0 { + // t.Error("relationship was not removed properly from the slice") + // } + // if len(c.R.JobDatahistoryjobs) != 0 { + // t.Error("relationship was not removed properly from the slice") + // } + if d.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + if e.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + + if a.R.PrerequisiteJobDatahistoryjobs[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.PrerequisiteJobDatahistoryjobs[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testDatahistoryjobToManyRemoveOpPrerequisiteJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.AddPrerequisiteJobDatahistoryjobs(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) + } + + count, err := a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 4 { + t.Error("count was wrong:", count) + } + + err = a.RemovePrerequisiteJobDatahistoryjobs(ctx, tx, foreigners[:2]...) + if err != nil { + t.Fatal(err) + } + + count, err = a.PrerequisiteJobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if len(b.R.JobDatahistoryjobs) != 0 { + t.Error("relationship was not removed properly from the slice") + } + if len(c.R.JobDatahistoryjobs) != 0 { + t.Error("relationship was not removed properly from the slice") + } + if d.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.JobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if len(a.R.PrerequisiteJobDatahistoryjobs) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.PrerequisiteJobDatahistoryjobs[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.PrerequisiteJobDatahistoryjobs[0] != &e { + t.Error("relationship to e should have been preserved") + } +} + +func testDatahistoryjobToManyAddOpJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Datahistoryjob{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddJobDatahistoryjobs(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if first.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + if second.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + + if a.R.JobDatahistoryjobs[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.JobDatahistoryjobs[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.JobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testDatahistoryjobToManySetOpJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob seed := randomize.NewSeed() - if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } } - if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { t.Fatal(err) } - - if err = randomize.Struct(seed, &b, datahistoryjobresultDBTypes, false, datahistoryjobresultColumnsWithDefault...); err != nil { + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { t.Fatal(err) } - if err = randomize.Struct(seed, &c, datahistoryjobresultDBTypes, false, datahistoryjobresultColumnsWithDefault...); err != nil { + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { t.Fatal(err) } - b.JobID = a.ID - c.JobID = a.ID + err = a.SetJobDatahistoryjobs(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } - if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + count, err := a.JobDatahistoryjobs().Count(ctx, tx) + if err != nil { t.Fatal(err) } - if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetJobDatahistoryjobs(ctx, tx, true, &d, &e) + if err != nil { t.Fatal(err) } - check, err := a.JobDatahistoryjobresults().All(ctx, tx) + count, err = a.JobDatahistoryjobs().Count(ctx, tx) if err != nil { t.Fatal(err) } + if count != 2 { + t.Error("count was wrong:", count) + } - bFound, cFound := false, false - for _, v := range check { - if v.JobID == b.JobID { - bFound = true - } - if v.JobID == c.JobID { - cFound = true + // The following checks cannot be implemented since we have no handle + // to these when we call Set(). Leaving them here as wishful thinking + // and to let people know there's dragons. + // + // if len(b.R.PrerequisiteJobDatahistoryjobs) != 0 { + // t.Error("relationship was not removed properly from the slice") + // } + // if len(c.R.PrerequisiteJobDatahistoryjobs) != 0 { + // t.Error("relationship was not removed properly from the slice") + // } + if d.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + if e.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the slice") + } + + if a.R.JobDatahistoryjobs[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.JobDatahistoryjobs[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testDatahistoryjobToManyRemoveOpJobDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) } } - if !bFound { - t.Error("expected to find b") + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) } - if !cFound { - t.Error("expected to find c") + + err = a.AddJobDatahistoryjobs(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) } - slice := DatahistoryjobSlice{&a} - if err = a.L.LoadJobDatahistoryjobresults(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + count, err := a.JobDatahistoryjobs().Count(ctx, tx) + if err != nil { t.Fatal(err) } - if got := len(a.R.JobDatahistoryjobresults); got != 2 { - t.Error("number of eager loaded records wrong, got:", got) + if count != 4 { + t.Error("count was wrong:", count) } - a.R.JobDatahistoryjobresults = nil - if err = a.L.LoadJobDatahistoryjobresults(ctx, tx, true, &a, nil); err != nil { + err = a.RemoveJobDatahistoryjobs(ctx, tx, foreigners[:2]...) + if err != nil { t.Fatal(err) } - if got := len(a.R.JobDatahistoryjobresults); got != 2 { - t.Error("number of eager loaded records wrong, got:", got) + + count, err = a.JobDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) } - if t.Failed() { - t.Logf("%#v", check) + if len(b.R.PrerequisiteJobDatahistoryjobs) != 0 { + t.Error("relationship was not removed properly from the slice") + } + if len(c.R.PrerequisiteJobDatahistoryjobs) != 0 { + t.Error("relationship was not removed properly from the slice") + } + if d.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.PrerequisiteJobDatahistoryjobs[0] != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if len(a.R.JobDatahistoryjobs) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.JobDatahistoryjobs[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.JobDatahistoryjobs[0] != &e { + t.Error("relationship to e should have been preserved") } } @@ -698,6 +1978,57 @@ func testDatahistoryjobToOneExchangeUsingExchangeName(t *testing.T) { } } +func testDatahistoryjobToOneExchangeUsingSecondaryExchange(t *testing.T) { + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var local Datahistoryjob + var foreign Exchange + + seed := randomize.NewSeed() + if err := randomize.Struct(seed, &local, datahistoryjobDBTypes, true, datahistoryjobColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Datahistoryjob struct: %s", err) + } + if err := randomize.Struct(seed, &foreign, exchangeDBTypes, false, exchangeColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Exchange struct: %s", err) + } + + if err := foreign.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + queries.Assign(&local.SecondaryExchangeID, foreign.ID) + if err := local.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := local.SecondaryExchange().One(ctx, tx) + if err != nil { + t.Fatal(err) + } + + if !queries.Equal(check.ID, foreign.ID) { + t.Errorf("want: %v, got %v", foreign.ID, check.ID) + } + + slice := DatahistoryjobSlice{&local} + if err = local.L.LoadSecondaryExchange(ctx, tx, false, (*[]*Datahistoryjob)(&slice), nil); err != nil { + t.Fatal(err) + } + if local.R.SecondaryExchange == nil { + t.Error("struct should have been eager loaded") + } + + local.R.SecondaryExchange = nil + if err = local.L.LoadSecondaryExchange(ctx, tx, true, &local, nil); err != nil { + t.Fatal(err) + } + if local.R.SecondaryExchange == nil { + t.Error("struct should have been eager loaded") + } +} + func testDatahistoryjobToOneSetOpExchangeUsingExchangeName(t *testing.T) { var err error @@ -755,6 +2086,114 @@ func testDatahistoryjobToOneSetOpExchangeUsingExchangeName(t *testing.T) { } } } +func testDatahistoryjobToOneSetOpExchangeUsingSecondaryExchange(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b, c Exchange + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + for i, x := range []*Exchange{&b, &c} { + err = a.SetSecondaryExchange(ctx, tx, i != 0, x) + if err != nil { + t.Fatal(err) + } + + if a.R.SecondaryExchange != x { + t.Error("relationship struct not set to correct value") + } + + if x.R.SecondaryExchangeDatahistoryjobs[0] != &a { + t.Error("failed to append to foreign relationship struct") + } + if !queries.Equal(a.SecondaryExchangeID, x.ID) { + t.Error("foreign key was wrong value", a.SecondaryExchangeID) + } + + zero := reflect.Zero(reflect.TypeOf(a.SecondaryExchangeID)) + reflect.Indirect(reflect.ValueOf(&a.SecondaryExchangeID)).Set(zero) + + if err = a.Reload(ctx, tx); err != nil { + t.Fatal("failed to reload", err) + } + + if !queries.Equal(a.SecondaryExchangeID, x.ID) { + t.Error("foreign key was wrong value", a.SecondaryExchangeID, x.ID) + } + } +} + +func testDatahistoryjobToOneRemoveOpExchangeUsingSecondaryExchange(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Datahistoryjob + var b Exchange + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = a.SetSecondaryExchange(ctx, tx, true, &b); err != nil { + t.Fatal(err) + } + + if err = a.RemoveSecondaryExchange(ctx, tx, &b); err != nil { + t.Error("failed to remove relationship") + } + + count, err := a.SecondaryExchange().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 0 { + t.Error("want no relationships remaining") + } + + if a.R.SecondaryExchange != nil { + t.Error("R struct entry should be nil") + } + + if !queries.IsValuerNil(a.SecondaryExchangeID) { + t.Error("foreign key value should be nil") + } + + if len(b.R.SecondaryExchangeDatahistoryjobs) != 0 { + t.Error("failed to remove a from b's relationships") + } +} func testDatahistoryjobsReload(t *testing.T) { t.Parallel() @@ -830,7 +2269,7 @@ func testDatahistoryjobsSelect(t *testing.T) { } var ( - datahistoryjobDBTypes = map[string]string{`ID`: `TEXT`, `Nickname`: `TEXT`, `ExchangeNameID`: `TEXT`, `Asset`: `TEXT`, `Base`: `TEXT`, `Quote`: `TEXT`, `StartTime`: `TIMESTAMP`, `EndTime`: `TIMESTAMP`, `Interval`: `REAL`, `DataType`: `REAL`, `RequestSize`: `REAL`, `MaxRetries`: `REAL`, `BatchCount`: `REAL`, `Status`: `REAL`, `Created`: `TIMESTAMP`} + datahistoryjobDBTypes = map[string]string{`ID`: `TEXT`, `Nickname`: `TEXT`, `ExchangeNameID`: `TEXT`, `Asset`: `TEXT`, `Base`: `TEXT`, `Quote`: `TEXT`, `StartTime`: `TIMESTAMP`, `EndTime`: `TIMESTAMP`, `Interval`: `REAL`, `DataType`: `REAL`, `RequestSize`: `REAL`, `MaxRetries`: `REAL`, `BatchCount`: `REAL`, `Status`: `REAL`, `Created`: `TIMESTAMP`, `ConversionInterval`: `REAL`, `OverwriteData`: `INTEGER`, `DecimalPlaceComparison`: `INTEGER`, `SecondaryExchangeID`: `TEXT`, `IssueTolerancePercentage`: `REAL`, `ReplaceOnIssue`: `INTEGER`} _ = bytes.MinRead ) diff --git a/database/models/sqlite3/datahistoryjobresult.go b/database/models/sqlite3/datahistoryjobresult.go index e875d811bfd..841d5620948 100644 --- a/database/models/sqlite3/datahistoryjobresult.go +++ b/database/models/sqlite3/datahistoryjobresult.go @@ -55,29 +55,6 @@ var DatahistoryjobresultColumns = struct { // Generated where -type whereHelpernull_String struct{ field string } - -func (w whereHelpernull_String) EQ(x null.String) qm.QueryMod { - return qmhelper.WhereNullEQ(w.field, false, x) -} -func (w whereHelpernull_String) NEQ(x null.String) qm.QueryMod { - return qmhelper.WhereNullEQ(w.field, true, x) -} -func (w whereHelpernull_String) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } -func (w whereHelpernull_String) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } -func (w whereHelpernull_String) LT(x null.String) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.LT, x) -} -func (w whereHelpernull_String) LTE(x null.String) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.LTE, x) -} -func (w whereHelpernull_String) GT(x null.String) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.GT, x) -} -func (w whereHelpernull_String) GTE(x null.String) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.GTE, x) -} - var DatahistoryjobresultWhere = struct { ID whereHelperstring JobID whereHelperstring diff --git a/database/models/sqlite3/exchange.go b/database/models/sqlite3/exchange.go index c581357f5f4..679fb10fe01 100644 --- a/database/models/sqlite3/exchange.go +++ b/database/models/sqlite3/exchange.go @@ -49,23 +49,26 @@ var ExchangeWhere = struct { // ExchangeRels is where relationship names are stored. var ExchangeRels = struct { - ExchangeNameCandle string - ExchangeNameTrade string - ExchangeNameDatahistoryjobs string - ExchangeNameWithdrawalHistories string + ExchangeNameCandle string + ExchangeNameTrade string + ExchangeNameDatahistoryjobs string + SecondaryExchangeDatahistoryjobs string + ExchangeNameWithdrawalHistories string }{ - ExchangeNameCandle: "ExchangeNameCandle", - ExchangeNameTrade: "ExchangeNameTrade", - ExchangeNameDatahistoryjobs: "ExchangeNameDatahistoryjobs", - ExchangeNameWithdrawalHistories: "ExchangeNameWithdrawalHistories", + ExchangeNameCandle: "ExchangeNameCandle", + ExchangeNameTrade: "ExchangeNameTrade", + ExchangeNameDatahistoryjobs: "ExchangeNameDatahistoryjobs", + SecondaryExchangeDatahistoryjobs: "SecondaryExchangeDatahistoryjobs", + ExchangeNameWithdrawalHistories: "ExchangeNameWithdrawalHistories", } // exchangeR is where relationships are stored. type exchangeR struct { - ExchangeNameCandle *Candle - ExchangeNameTrade *Trade - ExchangeNameDatahistoryjobs DatahistoryjobSlice - ExchangeNameWithdrawalHistories WithdrawalHistorySlice + ExchangeNameCandle *Candle + ExchangeNameTrade *Trade + ExchangeNameDatahistoryjobs DatahistoryjobSlice + SecondaryExchangeDatahistoryjobs DatahistoryjobSlice + ExchangeNameWithdrawalHistories WithdrawalHistorySlice } // NewStruct creates a new relationship struct @@ -407,6 +410,27 @@ func (o *Exchange) ExchangeNameDatahistoryjobs(mods ...qm.QueryMod) datahistoryj return query } +// SecondaryExchangeDatahistoryjobs retrieves all the datahistoryjob's Datahistoryjobs with an executor via secondary_exchange_id column. +func (o *Exchange) SecondaryExchangeDatahistoryjobs(mods ...qm.QueryMod) datahistoryjobQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.Where("\"datahistoryjob\".\"secondary_exchange_id\"=?", o.ID), + ) + + query := Datahistoryjobs(queryMods...) + queries.SetFrom(query.Query, "\"datahistoryjob\"") + + if len(queries.GetSelect(query.Query)) == 0 { + queries.SetSelect(query.Query, []string{"\"datahistoryjob\".*"}) + } + + return query +} + // ExchangeNameWithdrawalHistories retrieves all the withdrawal_history's WithdrawalHistories with an executor via exchange_name_id column. func (o *Exchange) ExchangeNameWithdrawalHistories(mods ...qm.QueryMod) withdrawalHistoryQuery { var queryMods []qm.QueryMod @@ -719,6 +743,101 @@ func (exchangeL) LoadExchangeNameDatahistoryjobs(ctx context.Context, e boil.Con return nil } +// LoadSecondaryExchangeDatahistoryjobs allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (exchangeL) LoadSecondaryExchangeDatahistoryjobs(ctx context.Context, e boil.ContextExecutor, singular bool, maybeExchange interface{}, mods queries.Applicator) error { + var slice []*Exchange + var object *Exchange + + if singular { + object = maybeExchange.(*Exchange) + } else { + slice = *maybeExchange.(*[]*Exchange) + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &exchangeR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &exchangeR{} + } + + for _, a := range args { + if queries.Equal(a, obj.ID) { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery(qm.From(`datahistoryjob`), qm.WhereIn(`datahistoryjob.secondary_exchange_id in ?`, args...)) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load datahistoryjob") + } + + var resultSlice []*Datahistoryjob + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice datahistoryjob") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on datahistoryjob") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for datahistoryjob") + } + + if len(datahistoryjobAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.SecondaryExchangeDatahistoryjobs = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.SecondaryExchange = object + } + return nil + } + + for _, foreign := range resultSlice { + for _, local := range slice { + if queries.Equal(local.ID, foreign.SecondaryExchangeID) { + local.R.SecondaryExchangeDatahistoryjobs = append(local.R.SecondaryExchangeDatahistoryjobs, foreign) + if foreign.R == nil { + foreign.R = &datahistoryjobR{} + } + foreign.R.SecondaryExchange = local + break + } + } + } + + return nil +} + // LoadExchangeNameWithdrawalHistories allows an eager lookup of values, cached into the // loaded structs of the objects. This is for a 1-M or N-M relationship. func (exchangeL) LoadExchangeNameWithdrawalHistories(ctx context.Context, e boil.ContextExecutor, singular bool, maybeExchange interface{}, mods queries.Applicator) error { @@ -969,6 +1088,129 @@ func (o *Exchange) AddExchangeNameDatahistoryjobs(ctx context.Context, exec boil return nil } +// AddSecondaryExchangeDatahistoryjobs adds the given related objects to the existing relationships +// of the exchange, optionally inserting them as new records. +// Appends related to o.R.SecondaryExchangeDatahistoryjobs. +// Sets related.R.SecondaryExchange appropriately. +func (o *Exchange) AddSecondaryExchangeDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + var err error + for _, rel := range related { + if insert { + queries.Assign(&rel.SecondaryExchangeID, o.ID) + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } else { + updateQuery := fmt.Sprintf( + "UPDATE \"datahistoryjob\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, []string{"secondary_exchange_id"}), + strmangle.WhereClause("\"", "\"", 0, datahistoryjobPrimaryKeyColumns), + ) + values := []interface{}{o.ID, rel.ID} + + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, updateQuery) + fmt.Fprintln(boil.DebugWriter, values) + } + + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update foreign table") + } + + queries.Assign(&rel.SecondaryExchangeID, o.ID) + } + } + + if o.R == nil { + o.R = &exchangeR{ + SecondaryExchangeDatahistoryjobs: related, + } + } else { + o.R.SecondaryExchangeDatahistoryjobs = append(o.R.SecondaryExchangeDatahistoryjobs, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &datahistoryjobR{ + SecondaryExchange: o, + } + } else { + rel.R.SecondaryExchange = o + } + } + return nil +} + +// SetSecondaryExchangeDatahistoryjobs removes all previously related items of the +// exchange replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.SecondaryExchange's SecondaryExchangeDatahistoryjobs accordingly. +// Replaces o.R.SecondaryExchangeDatahistoryjobs with related. +// Sets related.R.SecondaryExchange's SecondaryExchangeDatahistoryjobs accordingly. +func (o *Exchange) SetSecondaryExchangeDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Datahistoryjob) error { + query := "update \"datahistoryjob\" set \"secondary_exchange_id\" = null where \"secondary_exchange_id\" = ?" + values := []interface{}{o.ID} + if boil.DebugMode { + fmt.Fprintln(boil.DebugWriter, query) + fmt.Fprintln(boil.DebugWriter, values) + } + + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + if o.R != nil { + for _, rel := range o.R.SecondaryExchangeDatahistoryjobs { + queries.SetScanner(&rel.SecondaryExchangeID, nil) + if rel.R == nil { + continue + } + + rel.R.SecondaryExchange = nil + } + + o.R.SecondaryExchangeDatahistoryjobs = nil + } + return o.AddSecondaryExchangeDatahistoryjobs(ctx, exec, insert, related...) +} + +// RemoveSecondaryExchangeDatahistoryjobs relationships from objects passed in. +// Removes related items from R.SecondaryExchangeDatahistoryjobs (uses pointer comparison, removal does not keep order) +// Sets related.R.SecondaryExchange. +func (o *Exchange) RemoveSecondaryExchangeDatahistoryjobs(ctx context.Context, exec boil.ContextExecutor, related ...*Datahistoryjob) error { + var err error + for _, rel := range related { + queries.SetScanner(&rel.SecondaryExchangeID, nil) + if rel.R != nil { + rel.R.SecondaryExchange = nil + } + if _, err = rel.Update(ctx, exec, boil.Whitelist("secondary_exchange_id")); err != nil { + return err + } + } + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.SecondaryExchangeDatahistoryjobs { + if rel != ri { + continue + } + + ln := len(o.R.SecondaryExchangeDatahistoryjobs) + if ln > 1 && i < ln-1 { + o.R.SecondaryExchangeDatahistoryjobs[i] = o.R.SecondaryExchangeDatahistoryjobs[ln-1] + } + o.R.SecondaryExchangeDatahistoryjobs = o.R.SecondaryExchangeDatahistoryjobs[:ln-1] + break + } + } + + return nil +} + // AddExchangeNameWithdrawalHistories adds the given related objects to the existing relationships // of the exchange, optionally inserting them as new records. // Appends related to o.R.ExchangeNameWithdrawalHistories. diff --git a/database/models/sqlite3/exchange_test.go b/database/models/sqlite3/exchange_test.go index fa0e986e7e3..ede89ceeafb 100644 --- a/database/models/sqlite3/exchange_test.go +++ b/database/models/sqlite3/exchange_test.go @@ -797,6 +797,83 @@ func testExchangeToManyExchangeNameDatahistoryjobs(t *testing.T) { } } +func testExchangeToManySecondaryExchangeDatahistoryjobs(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Exchange + var b, c Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, exchangeDBTypes, true, exchangeColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Exchange struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, datahistoryjobDBTypes, false, datahistoryjobColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + queries.Assign(&b.SecondaryExchangeID, a.ID) + queries.Assign(&c.SecondaryExchangeID, a.ID) + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := a.SecondaryExchangeDatahistoryjobs().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if queries.Equal(v.SecondaryExchangeID, b.SecondaryExchangeID) { + bFound = true + } + if queries.Equal(v.SecondaryExchangeID, c.SecondaryExchangeID) { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := ExchangeSlice{&a} + if err = a.L.LoadSecondaryExchangeDatahistoryjobs(ctx, tx, false, (*[]*Exchange)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.SecondaryExchangeDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.SecondaryExchangeDatahistoryjobs = nil + if err = a.L.LoadSecondaryExchangeDatahistoryjobs(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.SecondaryExchangeDatahistoryjobs); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + func testExchangeToManyExchangeNameWithdrawalHistories(t *testing.T) { var err error ctx := context.Background() @@ -950,6 +1027,257 @@ func testExchangeToManyAddOpExchangeNameDatahistoryjobs(t *testing.T) { } } } +func testExchangeToManyAddOpSecondaryExchangeDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Exchange + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*Datahistoryjob{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddSecondaryExchangeDatahistoryjobs(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if !queries.Equal(a.ID, first.SecondaryExchangeID) { + t.Error("foreign key was wrong value", a.ID, first.SecondaryExchangeID) + } + if !queries.Equal(a.ID, second.SecondaryExchangeID) { + t.Error("foreign key was wrong value", a.ID, second.SecondaryExchangeID) + } + + if first.R.SecondaryExchange != &a { + t.Error("relationship was not added properly to the foreign slice") + } + if second.R.SecondaryExchange != &a { + t.Error("relationship was not added properly to the foreign slice") + } + + if a.R.SecondaryExchangeDatahistoryjobs[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.SecondaryExchangeDatahistoryjobs[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} + +func testExchangeToManySetOpSecondaryExchangeDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Exchange + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err = a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.SetSecondaryExchangeDatahistoryjobs(ctx, tx, false, &b, &c) + if err != nil { + t.Fatal(err) + } + + count, err := a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + err = a.SetSecondaryExchangeDatahistoryjobs(ctx, tx, true, &d, &e) + if err != nil { + t.Fatal(err) + } + + count, err = a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.SecondaryExchangeID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.SecondaryExchangeID) { + t.Error("want c's foreign key value to be nil") + } + if !queries.Equal(a.ID, d.SecondaryExchangeID) { + t.Error("foreign key was wrong value", a.ID, d.SecondaryExchangeID) + } + if !queries.Equal(a.ID, e.SecondaryExchangeID) { + t.Error("foreign key was wrong value", a.ID, e.SecondaryExchangeID) + } + + if b.R.SecondaryExchange != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.SecondaryExchange != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.SecondaryExchange != &a { + t.Error("relationship was not added properly to the foreign struct") + } + if e.R.SecondaryExchange != &a { + t.Error("relationship was not added properly to the foreign struct") + } + + if a.R.SecondaryExchangeDatahistoryjobs[0] != &d { + t.Error("relationship struct slice not set to correct value") + } + if a.R.SecondaryExchangeDatahistoryjobs[1] != &e { + t.Error("relationship struct slice not set to correct value") + } +} + +func testExchangeToManyRemoveOpSecondaryExchangeDatahistoryjobs(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Exchange + var b, c, d, e Datahistoryjob + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, exchangeDBTypes, false, strmangle.SetComplement(exchangePrimaryKeyColumns, exchangeColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*Datahistoryjob{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, datahistoryjobDBTypes, false, strmangle.SetComplement(datahistoryjobPrimaryKeyColumns, datahistoryjobColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + err = a.AddSecondaryExchangeDatahistoryjobs(ctx, tx, true, foreigners...) + if err != nil { + t.Fatal(err) + } + + count, err := a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 4 { + t.Error("count was wrong:", count) + } + + err = a.RemoveSecondaryExchangeDatahistoryjobs(ctx, tx, foreigners[:2]...) + if err != nil { + t.Fatal(err) + } + + count, err = a.SecondaryExchangeDatahistoryjobs().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Error("count was wrong:", count) + } + + if !queries.IsValuerNil(b.SecondaryExchangeID) { + t.Error("want b's foreign key value to be nil") + } + if !queries.IsValuerNil(c.SecondaryExchangeID) { + t.Error("want c's foreign key value to be nil") + } + + if b.R.SecondaryExchange != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if c.R.SecondaryExchange != nil { + t.Error("relationship was not removed properly from the foreign struct") + } + if d.R.SecondaryExchange != &a { + t.Error("relationship to a should have been preserved") + } + if e.R.SecondaryExchange != &a { + t.Error("relationship to a should have been preserved") + } + + if len(a.R.SecondaryExchangeDatahistoryjobs) != 2 { + t.Error("should have preserved two relationships") + } + + // Removal doesn't do a stable deletion for performance so we have to flip the order + if a.R.SecondaryExchangeDatahistoryjobs[1] != &d { + t.Error("relationship to d should have been preserved") + } + if a.R.SecondaryExchangeDatahistoryjobs[0] != &e { + t.Error("relationship to e should have been preserved") + } +} + func testExchangeToManyAddOpExchangeNameWithdrawalHistories(t *testing.T) { var err error diff --git a/database/repository/candle/candle.go b/database/repository/candle/candle.go index 548dc608408..3fc3d587f7b 100644 --- a/database/repository/candle/candle.go +++ b/database/repository/candle/candle.go @@ -21,6 +21,7 @@ import ( "github.com/thrasher-corp/gocryptotrader/log" "github.com/thrasher-corp/sqlboiler/boil" "github.com/thrasher-corp/sqlboiler/queries/qm" + "github.com/volatiletech/null" ) // Series returns candle data @@ -34,6 +35,7 @@ func Series(exchangeName, base, quote string, interval int64, asset string, star qm.Where("quote = ?", strings.ToUpper(quote)), qm.Where("interval = ?", interval), qm.Where("asset = ?", strings.ToLower(asset)), + qm.OrderBy("timestamp"), } exchangeUUID, errS := exchange.UUIDByName(exchangeName) @@ -53,12 +55,15 @@ func Series(exchangeName, base, quote string, interval int64, asset string, star return out, errT } out.Candles = append(out.Candles, Candle{ - Timestamp: t, - Open: retCandle[x].Open, - High: retCandle[x].High, - Low: retCandle[x].Low, - Close: retCandle[x].Close, - Volume: retCandle[x].Volume, + Timestamp: t, + Open: retCandle[x].Open, + High: retCandle[x].High, + Low: retCandle[x].Low, + Close: retCandle[x].Close, + Volume: retCandle[x].Volume, + SourceJobID: retCandle[x].SourceJobID.String, + ValidationJobID: retCandle[x].ValidationJobID.String, + ValidationIssues: retCandle[x].ValidationIssues.String, }) } } else { @@ -70,12 +75,15 @@ func Series(exchangeName, base, quote string, interval int64, asset string, star for x := range retCandle { out.Candles = append(out.Candles, Candle{ - Timestamp: retCandle[x].Timestamp, - Open: retCandle[x].Open, - High: retCandle[x].High, - Low: retCandle[x].Low, - Close: retCandle[x].Close, - Volume: retCandle[x].Volume, + Timestamp: retCandle[x].Timestamp, + Open: retCandle[x].Open, + High: retCandle[x].High, + Low: retCandle[x].Low, + Close: retCandle[x].Close, + Volume: retCandle[x].Volume, + SourceJobID: retCandle[x].SourceJobID.String, + ValidationJobID: retCandle[x].ValidationJobID.String, + ValidationIssues: retCandle[x].ValidationIssues.String, }) } } @@ -229,6 +237,9 @@ func insertSQLite(ctx context.Context, tx *sql.Tx, in *Item) (uint64, error) { return 0, err } tempCandle.ID = tempUUID.String() + tempCandle.ValidationJobID = null.String{String: in.Candles[x].ValidationJobID, Valid: in.Candles[x].ValidationJobID != ""} + tempCandle.ValidationIssues = null.String{String: in.Candles[x].ValidationIssues, Valid: in.Candles[x].ValidationIssues != ""} + tempCandle.SourceJobID = null.String{String: in.Candles[x].SourceJobID, Valid: in.Candles[x].SourceJobID != ""} err = tempCandle.Insert(ctx, tx, boil.Infer()) if err != nil { return 0, err @@ -256,6 +267,9 @@ func insertPostgresSQL(ctx context.Context, tx *sql.Tx, in *Item) (uint64, error Close: in.Candles[x].Close, Volume: in.Candles[x].Volume, } + tempCandle.ValidationJobID = null.String{String: in.Candles[x].ValidationJobID, Valid: in.Candles[x].ValidationJobID != ""} + tempCandle.ValidationIssues = null.String{String: in.Candles[x].ValidationIssues, Valid: in.Candles[x].ValidationIssues != ""} + tempCandle.SourceJobID = null.String{String: in.Candles[x].SourceJobID, Valid: in.Candles[x].SourceJobID != ""} err := tempCandle.Upsert(ctx, tx, true, []string{"timestamp", "exchange_name_id", "base", "quote", "interval", "asset"}, boil.Infer(), boil.Infer()) if err != nil { return 0, err diff --git a/database/repository/candle/candle_test.go b/database/repository/candle/candle_test.go index e12e287fbae..f69fa25f90d 100644 --- a/database/repository/candle/candle_test.go +++ b/database/repository/candle/candle_test.go @@ -298,12 +298,13 @@ func genOHCLVData() (out Item, err error) { start := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) for x := 0; x < 365; x++ { out.Candles = append(out.Candles, Candle{ - Timestamp: start.Add(time.Hour * 24 * time.Duration(x)), - Open: 1000, - High: 1000, - Low: 1000, - Close: 1000, - Volume: 1000, + Timestamp: start.Add(time.Hour * 24 * time.Duration(x)), + Open: 1000, + High: 1000, + Low: 1000, + Close: 1000, + Volume: 1000, + ValidationIssues: "hello world!", }) } diff --git a/database/repository/candle/candle_types.go b/database/repository/candle/candle_types.go index 1da1e353cd6..ad1a5d34761 100644 --- a/database/repository/candle/candle_types.go +++ b/database/repository/candle/candle_types.go @@ -25,10 +25,13 @@ type Item struct { // Candle holds each interval type Candle struct { - Timestamp time.Time - Open float64 - High float64 - Low float64 - Close float64 - Volume float64 + Timestamp time.Time + Open float64 + High float64 + Low float64 + Close float64 + Volume float64 + SourceJobID string + ValidationJobID string + ValidationIssues string } diff --git a/database/repository/datahistoryjob/datahistoryjob.go b/database/repository/datahistoryjob/datahistoryjob.go index 073ea84e037..a7c26c5aa1b 100644 --- a/database/repository/datahistoryjob/datahistoryjob.go +++ b/database/repository/datahistoryjob/datahistoryjob.go @@ -14,6 +14,7 @@ import ( "github.com/thrasher-corp/gocryptotrader/log" "github.com/thrasher-corp/sqlboiler/boil" "github.com/thrasher-corp/sqlboiler/queries/qm" + "github.com/volatiletech/null" ) // Setup returns a DBService @@ -127,29 +128,148 @@ func (db *DBService) GetJobAndAllResults(nickname string) (*DataHistoryJob, erro } } +// GetRelatedUpcomingJobs will return related jobs +func (db *DBService) GetRelatedUpcomingJobs(nickname string) ([]*DataHistoryJob, error) { + switch db.driver { + case database.DBSQLite3, database.DBSQLite: + return db.getRelatedUpcomingJobsSQLite(nickname) + case database.DBPostgreSQL: + return db.getRelatedUpcomingJobsPostgres(nickname) + default: + return nil, database.ErrNoDatabaseProvided + } +} + +// GetPrerequisiteJob will return the job that must complete before the +// referenced job +func (db *DBService) GetPrerequisiteJob(nickname string) (*DataHistoryJob, error) { + switch db.driver { + case database.DBSQLite3, database.DBSQLite: + return db.getPrerequisiteJobSQLite(nickname) + case database.DBPostgreSQL: + return db.getPrerequisiteJobPostgres(nickname) + default: + return nil, database.ErrNoDatabaseProvided + } +} + +// SetRelationshipByID removes a relationship in the event of a changed +// relationship during upsertion +func (db *DBService) SetRelationshipByID(prerequisiteJobID, followingJobID string, status int64) error { + ctx := context.Background() + if strings.EqualFold(prerequisiteJobID, followingJobID) { + return errCannotSetSamePrerequisite + } + tx, err := db.sql.BeginTx(ctx, nil) + if err != nil { + return fmt.Errorf("beginTx %w", err) + } + defer func() { + if err != nil { + errRB := tx.Rollback() + if errRB != nil { + log.Errorf(log.DatabaseMgr, "Insert tx.Rollback %v", errRB) + } + } + }() + + switch db.driver { + case database.DBSQLite3, database.DBSQLite: + err = setRelationshipByIDSQLite(ctx, tx, prerequisiteJobID, followingJobID, status) + case database.DBPostgreSQL: + err = setRelationshipByIDPostgres(ctx, tx, prerequisiteJobID, followingJobID, status) + default: + return database.ErrNoDatabaseProvided + } + if err != nil { + return err + } + + return tx.Commit() +} + +// SetRelationshipByNickname removes a relationship in the event of a changed +// relationship during upsertion +func (db *DBService) SetRelationshipByNickname(prerequisiteNickname, followingNickname string, status int64) error { + ctx := context.Background() + if strings.EqualFold(prerequisiteNickname, followingNickname) { + return errCannotSetSamePrerequisite + } + tx, err := db.sql.BeginTx(ctx, nil) + if err != nil { + return fmt.Errorf("beginTx %w", err) + } + defer func() { + if err != nil { + errRB := tx.Rollback() + if errRB != nil { + log.Errorf(log.DatabaseMgr, "Insert tx.Rollback %v", errRB) + } + } + }() + + switch db.driver { + case database.DBSQLite3, database.DBSQLite: + err = setRelationshipByNicknameSQLite(ctx, tx, prerequisiteNickname, followingNickname, status) + case database.DBPostgreSQL: + err = setRelationshipByNicknamePostgres(ctx, tx, prerequisiteNickname, followingNickname, status) + default: + return database.ErrNoDatabaseProvided + } + if err != nil { + return err + } + + return tx.Commit() +} + func upsertSqlite(ctx context.Context, tx *sql.Tx, jobs ...*DataHistoryJob) error { for i := range jobs { - r, err := sqlite3.Exchanges( + exch, err := sqlite3.Exchanges( qm.Where("name = ?", strings.ToLower(jobs[i].ExchangeName))).One(ctx, tx) if err != nil { - return err + return fmt.Errorf("could not retrieve exchange '%v', %w", jobs[i].ExchangeName, err) + } + var secondaryExch *sqlite3.Exchange + if jobs[i].SecondarySourceExchangeName != "" { + secondaryExch, err = sqlite3.Exchanges( + qm.Where("name = ?", strings.ToLower(jobs[i].SecondarySourceExchangeName))).One(ctx, tx) + if err != nil { + return fmt.Errorf("could not retrieve secondary exchange '%v', %w", jobs[i].SecondarySourceExchangeName, err) + } + } + + var overwrite, replaceOnIssue int64 + if jobs[i].OverwriteData { + overwrite = 1 + } + if jobs[i].ReplaceOnIssue { + replaceOnIssue = 1 } var tempEvent = sqlite3.Datahistoryjob{ - ID: jobs[i].ID, - ExchangeNameID: r.ID, - Nickname: strings.ToLower(jobs[i].Nickname), - Asset: strings.ToLower(jobs[i].Asset), - Base: strings.ToUpper(jobs[i].Base), - Quote: strings.ToUpper(jobs[i].Quote), - StartTime: jobs[i].StartDate.UTC().Format(time.RFC3339), - EndTime: jobs[i].EndDate.UTC().Format(time.RFC3339), - Interval: float64(jobs[i].Interval), - DataType: float64(jobs[i].DataType), - RequestSize: float64(jobs[i].RequestSizeLimit), - MaxRetries: float64(jobs[i].MaxRetryAttempts), - BatchCount: float64(jobs[i].BatchSize), - Status: float64(jobs[i].Status), - Created: time.Now().UTC().Format(time.RFC3339), + ID: jobs[i].ID, + ExchangeNameID: exch.ID, + Nickname: strings.ToLower(jobs[i].Nickname), + Asset: strings.ToLower(jobs[i].Asset), + Base: strings.ToUpper(jobs[i].Base), + Quote: strings.ToUpper(jobs[i].Quote), + StartTime: jobs[i].StartDate.UTC().Format(time.RFC3339), + EndTime: jobs[i].EndDate.UTC().Format(time.RFC3339), + Interval: float64(jobs[i].Interval), + DataType: float64(jobs[i].DataType), + RequestSize: float64(jobs[i].RequestSizeLimit), + MaxRetries: float64(jobs[i].MaxRetryAttempts), + BatchCount: float64(jobs[i].BatchSize), + Status: float64(jobs[i].Status), + Created: time.Now().UTC().Format(time.RFC3339), + ConversionInterval: null.Float64{Float64: float64(jobs[i].ConversionInterval), Valid: jobs[i].ConversionInterval > 0}, + OverwriteData: null.Int64{Int64: overwrite, Valid: overwrite == 1}, + DecimalPlaceComparison: null.Int64{Int64: jobs[i].DecimalPlaceComparison, Valid: jobs[i].DecimalPlaceComparison > 0}, + ReplaceOnIssue: null.Int64{Int64: replaceOnIssue, Valid: replaceOnIssue == 1}, + IssueTolerancePercentage: null.Float64{Float64: jobs[i].IssueTolerancePercentage, Valid: jobs[i].IssueTolerancePercentage > 0}, + } + if secondaryExch != nil { + tempEvent.SecondaryExchangeID = null.String{String: secondaryExch.ID, Valid: true} } err = tempEvent.Insert(ctx, tx, boil.Infer()) @@ -163,27 +283,44 @@ func upsertSqlite(ctx context.Context, tx *sql.Tx, jobs ...*DataHistoryJob) erro func upsertPostgres(ctx context.Context, tx *sql.Tx, jobs ...*DataHistoryJob) error { for i := range jobs { - r, err := postgres.Exchanges( + exch, err := postgres.Exchanges( qm.Where("name = ?", strings.ToLower(jobs[i].ExchangeName))).One(ctx, tx) if err != nil { - return err + return fmt.Errorf("could not retrieve exchange '%v', %w", jobs[i].ExchangeName, err) + } + var secondaryExch *postgres.Exchange + if jobs[i].SecondarySourceExchangeName != "" { + secondaryExch, err = postgres.Exchanges( + qm.Where("name = ?", strings.ToLower(jobs[i].SecondarySourceExchangeName))).One(ctx, tx) + if err != nil { + return fmt.Errorf("could not retrieve secondary exchange '%v', %w", jobs[i].SecondarySourceExchangeName, err) + } } + var tempEvent = postgres.Datahistoryjob{ - ID: jobs[i].ID, - Nickname: strings.ToLower(jobs[i].Nickname), - ExchangeNameID: r.ID, - Asset: strings.ToLower(jobs[i].Asset), - Base: strings.ToUpper(jobs[i].Base), - Quote: strings.ToUpper(jobs[i].Quote), - StartTime: jobs[i].StartDate.UTC(), - EndTime: jobs[i].EndDate.UTC(), - Interval: float64(jobs[i].Interval), - DataType: float64(jobs[i].DataType), - BatchCount: float64(jobs[i].BatchSize), - RequestSize: float64(jobs[i].RequestSizeLimit), - MaxRetries: float64(jobs[i].MaxRetryAttempts), - Status: float64(jobs[i].Status), - Created: time.Now().UTC(), + ID: jobs[i].ID, + Nickname: strings.ToLower(jobs[i].Nickname), + ExchangeNameID: exch.ID, + Asset: strings.ToLower(jobs[i].Asset), + Base: strings.ToUpper(jobs[i].Base), + Quote: strings.ToUpper(jobs[i].Quote), + StartTime: jobs[i].StartDate.UTC(), + EndTime: jobs[i].EndDate.UTC(), + Interval: float64(jobs[i].Interval), + DataType: float64(jobs[i].DataType), + BatchCount: float64(jobs[i].BatchSize), + RequestSize: float64(jobs[i].RequestSizeLimit), + MaxRetries: float64(jobs[i].MaxRetryAttempts), + Status: float64(jobs[i].Status), + Created: time.Now().UTC(), + ConversionInterval: null.Float64{Float64: float64(jobs[i].ConversionInterval), Valid: jobs[i].ConversionInterval > 0}, + OverwriteData: null.Bool{Bool: jobs[i].OverwriteData, Valid: jobs[i].OverwriteData}, + DecimalPlaceComparison: null.Int{Int: int(jobs[i].DecimalPlaceComparison), Valid: jobs[i].DecimalPlaceComparison > 0}, + ReplaceOnIssue: null.Bool{Bool: jobs[i].ReplaceOnIssue, Valid: jobs[i].ReplaceOnIssue}, + IssueTolerancePercentage: null.Float64{Float64: jobs[i].IssueTolerancePercentage, Valid: jobs[i].IssueTolerancePercentage > 0}, + } + if secondaryExch != nil { + tempEvent.SecondaryExchangeID = null.String{String: secondaryExch.ID, Valid: true} } err = tempEvent.Upsert(ctx, tx, true, []string{"nickname"}, boil.Infer(), boil.Infer()) if err != nil { @@ -193,171 +330,41 @@ func upsertPostgres(ctx context.Context, tx *sql.Tx, jobs ...*DataHistoryJob) er return nil } - func (db *DBService) getByNicknameSQLite(nickname string) (*DataHistoryJob, error) { - var job *DataHistoryJob result, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", strings.ToLower(nickname))).One(context.Background(), db.sql) - if err != nil { - return job, err - } - - exchangeResult, err := result.ExchangeName().One(context.Background(), db.sql) - if err != nil { - return job, err - } - - ts, err := time.Parse(time.RFC3339, result.StartTime) if err != nil { return nil, err } - te, err := time.Parse(time.RFC3339, result.EndTime) - if err != nil { - return nil, err - } - - c, err := time.Parse(time.RFC3339, result.Created) - if err != nil { - return nil, err - } - - job = &DataHistoryJob{ - ID: result.ID, - Nickname: result.Nickname, - ExchangeID: result.ExchangeNameID, - ExchangeName: exchangeResult.Name, - Asset: result.Asset, - Base: result.Base, - Quote: result.Quote, - StartDate: ts, - EndDate: te, - Interval: int64(result.Interval), - BatchSize: int64(result.BatchCount), - RequestSizeLimit: int64(result.RequestSize), - DataType: int64(result.DataType), - MaxRetryAttempts: int64(result.MaxRetries), - Status: int64(result.Status), - CreatedDate: c, - } - - return job, nil + return db.createSQLiteDataHistoryJobResponse(result) } func (db *DBService) getByNicknamePostgres(nickname string) (*DataHistoryJob, error) { - var job *DataHistoryJob query := postgres.Datahistoryjobs(qm.Where("nickname = ?", strings.ToLower(nickname))) result, err := query.One(context.Background(), db.sql) if err != nil { - return job, err - } - - exchangeResult, err := result.ExchangeName().One(context.Background(), db.sql) - if err != nil { - return job, err - } - - job = &DataHistoryJob{ - ID: result.ID, - Nickname: result.Nickname, - ExchangeID: result.ExchangeNameID, - ExchangeName: exchangeResult.Name, - Asset: result.Asset, - Base: result.Base, - Quote: result.Quote, - StartDate: result.StartTime, - EndDate: result.EndTime, - Interval: int64(result.Interval), - BatchSize: int64(result.BatchCount), - RequestSizeLimit: int64(result.RequestSize), - DataType: int64(result.DataType), - MaxRetryAttempts: int64(result.MaxRetries), - Status: int64(result.Status), - CreatedDate: result.Created, + return nil, err } - - return job, nil + return db.createPostgresDataHistoryJobResponse(result) } func (db *DBService) getByIDSQLite(id string) (*DataHistoryJob, error) { - var job *DataHistoryJob result, err := sqlite3.Datahistoryjobs(qm.Where("id = ?", id)).One(context.Background(), db.sql) - if err != nil { - return job, err - } - - exchangeResult, err := result.ExchangeName().One(context.Background(), db.sql) - if err != nil { - return job, err - } - - ts, err := time.Parse(time.RFC3339, result.StartTime) - if err != nil { - return nil, err - } - te, err := time.Parse(time.RFC3339, result.EndTime) if err != nil { return nil, err } - c, err := time.Parse(time.RFC3339, result.Created) - if err != nil { - return nil, err - } - - job = &DataHistoryJob{ - ID: result.ID, - Nickname: result.Nickname, - ExchangeID: result.ExchangeNameID, - ExchangeName: exchangeResult.Name, - Asset: result.Asset, - Base: result.Base, - Quote: result.Quote, - StartDate: ts, - EndDate: te, - Interval: int64(result.Interval), - RequestSizeLimit: int64(result.RequestSize), - DataType: int64(result.DataType), - MaxRetryAttempts: int64(result.MaxRetries), - BatchSize: int64(result.BatchCount), - Status: int64(result.Status), - CreatedDate: c, - } - return job, nil + return db.createSQLiteDataHistoryJobResponse(result) } func (db *DBService) getByIDPostgres(id string) (*DataHistoryJob, error) { - var job *DataHistoryJob query := postgres.Datahistoryjobs(qm.Where("id = ?", id)) result, err := query.One(context.Background(), db.sql) if err != nil { - return job, err - } - - exchangeResult, err := result.ExchangeName().One(context.Background(), db.sql) - if err != nil { - return job, err - } - - job = &DataHistoryJob{ - ID: result.ID, - Nickname: result.Nickname, - ExchangeID: result.ExchangeNameID, - ExchangeName: exchangeResult.Name, - Asset: result.Asset, - Base: result.Base, - Quote: result.Quote, - StartDate: result.StartTime, - EndDate: result.EndTime, - Interval: int64(result.Interval), - BatchSize: int64(result.BatchCount), - RequestSizeLimit: int64(result.RequestSize), - DataType: int64(result.DataType), - MaxRetryAttempts: int64(result.MaxRetries), - Status: int64(result.Status), - CreatedDate: result.Created, + return nil, err } - return job, nil + return db.createPostgresDataHistoryJobResponse(result) } func (db *DBService) getJobsBetweenSQLite(startDate, endDate time.Time) ([]DataHistoryJob, error) { @@ -369,43 +376,11 @@ func (db *DBService) getJobsBetweenSQLite(startDate, endDate time.Time) ([]DataH } for i := range results { - exchangeResult, err := results[i].ExchangeName(qm.Where("id = ?", results[i].ExchangeNameID)).One(context.Background(), db.sql) + job, err := db.createSQLiteDataHistoryJobResponse(results[i]) if err != nil { - return nil, err + return nil, fmt.Errorf("could not return job %v: %w", results[i].Nickname, err) } - ts, err := time.Parse(time.RFC3339, results[i].StartTime) - if err != nil { - return nil, err - } - - te, err := time.Parse(time.RFC3339, results[i].EndTime) - if err != nil { - return nil, err - } - - c, err := time.Parse(time.RFC3339, results[i].Created) - if err != nil { - return nil, err - } - - jobs = append(jobs, DataHistoryJob{ - ID: results[i].ID, - Nickname: results[i].Nickname, - ExchangeID: results[i].ExchangeNameID, - ExchangeName: exchangeResult.Name, - Asset: results[i].Asset, - Base: results[i].Base, - Quote: results[i].Quote, - StartDate: ts, - EndDate: te, - Interval: int64(results[i].Interval), - RequestSizeLimit: int64(results[i].RequestSize), - BatchSize: int64(results[i].BatchCount), - DataType: int64(results[i].DataType), - MaxRetryAttempts: int64(results[i].MaxRetries), - Status: int64(results[i].Status), - CreatedDate: c, - }) + jobs = append(jobs, *job) } return jobs, nil @@ -420,35 +395,17 @@ func (db *DBService) getJobsBetweenPostgres(startDate, endDate time.Time) ([]Dat } for i := range results { - exchangeResult, err := results[i].ExchangeName(qm.Where("id = ?", results[i].ExchangeNameID)).One(context.Background(), db.sql) + job, err := db.createPostgresDataHistoryJobResponse(results[i]) if err != nil { return nil, err } - jobs = append(jobs, DataHistoryJob{ - ID: results[i].ID, - Nickname: results[i].Nickname, - ExchangeID: results[i].ExchangeNameID, - ExchangeName: exchangeResult.Name, - Asset: results[i].Asset, - Base: results[i].Base, - Quote: results[i].Quote, - StartDate: results[i].StartTime, - EndDate: results[i].EndTime, - Interval: int64(results[i].Interval), - BatchSize: int64(results[i].BatchCount), - RequestSizeLimit: int64(results[i].RequestSize), - DataType: int64(results[i].DataType), - MaxRetryAttempts: int64(results[i].MaxRetries), - Status: int64(results[i].Status), - CreatedDate: results[i].Created, - }) + jobs = append(jobs, *job) } return jobs, nil } func (db *DBService) getJobAndAllResultsSQLite(nickname string) (*DataHistoryJob, error) { - var job *DataHistoryJob query := sqlite3.Datahistoryjobs( qm.Load(sqlite3.DatahistoryjobRels.JobDatahistoryjobresults), qm.Load(sqlite3.DatahistoryjobRels.ExchangeName), @@ -458,237 +415,394 @@ func (db *DBService) getJobAndAllResultsSQLite(nickname string) (*DataHistoryJob return nil, err } - var jobResults []*datahistoryjobresult.DataHistoryJobResult - for i := range result.R.JobDatahistoryjobresults { - var start, end, run time.Time - start, err = time.Parse(time.RFC3339, result.R.JobDatahistoryjobresults[i].IntervalStartTime) + return db.createSQLiteDataHistoryJobResponse(result) +} + +func (db *DBService) getJobAndAllResultsPostgres(nickname string) (*DataHistoryJob, error) { + query := postgres.Datahistoryjobs( + qm.Load(postgres.DatahistoryjobRels.JobDatahistoryjobresults), + qm.Where("nickname = ?", strings.ToLower(nickname))) + result, err := query.One(context.Background(), db.sql) + if err != nil { + return nil, err + } + + return db.createPostgresDataHistoryJobResponse(result) +} + +func (db *DBService) getAllIncompleteJobsAndResultsSQLite() ([]DataHistoryJob, error) { + query := sqlite3.Datahistoryjobs( + qm.Load(sqlite3.DatahistoryjobRels.ExchangeName), + qm.Load(sqlite3.DatahistoryjobRels.JobDatahistoryjobresults), + qm.Where("status = ?", 0)) + results, err := query.All(context.Background(), db.sql) + if err != nil { + return nil, err + } + + var jobs []DataHistoryJob + for i := range results { + job, err := db.createSQLiteDataHistoryJobResponse(results[i]) if err != nil { - return nil, err + return nil, fmt.Errorf("could not return job %v: %w", results[i].Nickname, err) } - end, err = time.Parse(time.RFC3339, result.R.JobDatahistoryjobresults[i].IntervalEndTime) + + jobs = append(jobs, *job) + } + + return jobs, nil +} + +func (db *DBService) getAllIncompleteJobsAndResultsPostgres() ([]DataHistoryJob, error) { + query := postgres.Datahistoryjobs( + qm.Load(postgres.DatahistoryjobRels.JobDatahistoryjobresults), + qm.Where("status = ?", 0)) + results, err := query.All(context.Background(), db.sql) + if err != nil { + return nil, err + } + + var jobs []DataHistoryJob + for i := range results { + job, err := db.createPostgresDataHistoryJobResponse(results[i]) if err != nil { return nil, err } - run, err = time.Parse(time.RFC3339, result.R.JobDatahistoryjobresults[i].RunTime) + jobs = append(jobs, *job) + } + + return jobs, nil +} + +func (db *DBService) getRelatedUpcomingJobsSQLite(nickname string) ([]*DataHistoryJob, error) { + job, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", nickname)).One(context.Background(), db.sql) + if err != nil { + return nil, err + } + results, err := job.JobDatahistoryjobs().All(context.Background(), db.sql) + if err != nil { + return nil, err + } + var resp []*DataHistoryJob + for i := range results { + job, err := db.createSQLiteDataHistoryJobResponse(results[i]) + if err != nil { + return nil, fmt.Errorf("could not return job %v: %w", results[i].Nickname, err) + } + resp = append(resp, job) + } + return resp, nil +} + +func (db *DBService) getRelatedUpcomingJobsPostgres(nickname string) ([]*DataHistoryJob, error) { + q := postgres.Datahistoryjobs(qm.Load(postgres.DatahistoryjobRels.JobDatahistoryjobs), qm.Where("nickname = ?", nickname)) + jobWithRelations, err := q.One(context.Background(), db.sql) + if err != nil { + return nil, err + } + var response []*DataHistoryJob + for i := range jobWithRelations.R.JobDatahistoryjobs { + job, err := db.getByIDPostgres(jobWithRelations.R.JobDatahistoryjobs[i].ID) if err != nil { return nil, err } + response = append(response, job) + } + return response, nil +} + +func setRelationshipByIDSQLite(ctx context.Context, tx *sql.Tx, prerequisiteJobID, followingJobID string, status int64) error { + job, err := sqlite3.Datahistoryjobs(qm.Where("id = ?", followingJobID)).One(ctx, tx) + if err != nil { + return err + } + job.Status = float64(status) + _, err = job.Update(ctx, tx, boil.Infer()) + if err != nil { + return err + } + + if prerequisiteJobID == "" { + return job.SetPrerequisiteJobDatahistoryjobs(ctx, tx, true) + } + result, err := sqlite3.Datahistoryjobs(qm.Where("id = ?", prerequisiteJobID)).One(ctx, tx) + if err != nil { + return err + } + + return job.SetPrerequisiteJobDatahistoryjobs(ctx, tx, true, result) +} + +func setRelationshipByIDPostgres(ctx context.Context, tx *sql.Tx, prerequisiteJobID, followingJobID string, status int64) error { + job, err := postgres.Datahistoryjobs(qm.Where("id = ?", followingJobID)).One(ctx, tx) + if err != nil { + return err + } + job.Status = float64(status) + _, err = job.Update(ctx, tx, boil.Infer()) + if err != nil { + return err + } - jobResults = append(jobResults, &datahistoryjobresult.DataHistoryJobResult{ - ID: result.R.JobDatahistoryjobresults[i].ID, - JobID: result.R.JobDatahistoryjobresults[i].JobID, - IntervalStartDate: start, - IntervalEndDate: end, - Status: int64(result.R.JobDatahistoryjobresults[i].Status), - Result: result.R.JobDatahistoryjobresults[i].Result.String, - Date: run, - }) + if prerequisiteJobID == "" { + return job.SetPrerequisiteJobDatahistoryjobs(ctx, tx, false) } + result, err := postgres.Datahistoryjobs(qm.Where("id = ?", prerequisiteJobID)).One(ctx, tx) + if err != nil { + return err + } + + return job.SetPrerequisiteJobDatahistoryjobs(ctx, tx, false, result) +} - start, err := time.Parse(time.RFC3339, result.StartTime) +func (db *DBService) getPrerequisiteJobSQLite(nickname string) (*DataHistoryJob, error) { + result, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", nickname)).One(context.Background(), db.sql) if err != nil { return nil, err } - end, err := time.Parse(time.RFC3339, result.EndTime) + job, err := result.PrerequisiteJobDatahistoryjobs().One(context.Background(), db.sql) if err != nil { return nil, err } - created, err := time.Parse(time.RFC3339, result.Created) + + return db.createSQLiteDataHistoryJobResponse(job) +} + +func (db *DBService) getPrerequisiteJobPostgres(nickname string) (*DataHistoryJob, error) { + job, err := postgres.Datahistoryjobs(qm.Where("nickname = ?", nickname)).One(context.Background(), db.sql) + if err != nil { + return nil, err + } + result, err := job.PrerequisiteJobDatahistoryjobs().One(context.Background(), db.sql) if err != nil { return nil, err } - job = &DataHistoryJob{ - ID: result.ID, - Nickname: result.Nickname, - ExchangeID: result.ExchangeNameID, - ExchangeName: result.R.ExchangeName.Name, - Asset: result.Asset, - Base: result.Base, - Quote: result.Quote, - StartDate: start, - EndDate: end, - Interval: int64(result.Interval), - BatchSize: int64(result.BatchCount), - RequestSizeLimit: int64(result.RequestSize), - DataType: int64(result.DataType), - MaxRetryAttempts: int64(result.MaxRetries), - Status: int64(result.Status), - CreatedDate: created, - Results: jobResults, + return db.createPostgresDataHistoryJobResponse(result) +} + +func setRelationshipByNicknameSQLite(ctx context.Context, tx *sql.Tx, prerequisiteJobNickname, followingJobNickname string, status int64) error { + job, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", followingJobNickname)).One(ctx, tx) + if err != nil { + return err + } + job.Status = float64(status) + _, err = job.Update(ctx, tx, boil.Infer()) + if err != nil { + return err } - return job, nil + if prerequisiteJobNickname == "" { + return job.SetPrerequisiteJobDatahistoryjobs(ctx, tx, true) + } + result, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", prerequisiteJobNickname)).One(ctx, tx) + if err != nil { + return err + } + return job.SetPrerequisiteJobDatahistoryjobs(ctx, tx, true, result) } -func (db *DBService) getJobAndAllResultsPostgres(nickname string) (*DataHistoryJob, error) { - var job *DataHistoryJob - query := postgres.Datahistoryjobs( - qm.Load(postgres.DatahistoryjobRels.ExchangeName), - qm.Load(postgres.DatahistoryjobRels.JobDatahistoryjobresults), - qm.Where("nickname = ?", strings.ToLower(nickname))) - result, err := query.One(context.Background(), db.sql) +func setRelationshipByNicknamePostgres(ctx context.Context, tx *sql.Tx, prerequisiteJobNickname, followingJobNickname string, status int64) error { + job, err := postgres.Datahistoryjobs(qm.Where("nickname = ?", followingJobNickname)).One(ctx, tx) if err != nil { - return job, err + return err + } + job.Status = float64(status) + _, err = job.Update(ctx, tx, boil.Infer()) + if err != nil { + return err } - var jobResults []*datahistoryjobresult.DataHistoryJobResult - for i := range result.R.JobDatahistoryjobresults { - jobResults = append(jobResults, &datahistoryjobresult.DataHistoryJobResult{ - ID: result.R.JobDatahistoryjobresults[i].ID, - JobID: result.R.JobDatahistoryjobresults[i].JobID, - IntervalStartDate: result.R.JobDatahistoryjobresults[i].IntervalStartTime, - IntervalEndDate: result.R.JobDatahistoryjobresults[i].IntervalEndTime, - Status: int64(result.R.JobDatahistoryjobresults[i].Status), - Result: result.R.JobDatahistoryjobresults[i].Result.String, - Date: result.R.JobDatahistoryjobresults[i].RunTime, - }) - } - - job = &DataHistoryJob{ - ID: result.ID, - Nickname: result.Nickname, - ExchangeID: result.ExchangeNameID, - ExchangeName: result.R.ExchangeName.Name, - Asset: result.Asset, - Base: result.Base, - Quote: result.Quote, - StartDate: result.StartTime, - EndDate: result.EndTime, - Interval: int64(result.Interval), - BatchSize: int64(result.BatchCount), - RequestSizeLimit: int64(result.RequestSize), - DataType: int64(result.DataType), - MaxRetryAttempts: int64(result.MaxRetries), - Status: int64(result.Status), - CreatedDate: result.Created, - Results: jobResults, - } - - return job, nil + if prerequisiteJobNickname == "" { + return job.SetPrerequisiteJobDatahistoryjobs(ctx, tx, false) + } + result, err := postgres.Datahistoryjobs(qm.Where("nickname = ?", prerequisiteJobNickname)).One(ctx, tx) + if err != nil { + return err + } + return job.SetPrerequisiteJobDatahistoryjobs(ctx, tx, false, result) } -func (db *DBService) getAllIncompleteJobsAndResultsSQLite() ([]DataHistoryJob, error) { - var jobs []DataHistoryJob - query := sqlite3.Datahistoryjobs( - qm.Load(sqlite3.DatahistoryjobRels.ExchangeName), - qm.Load(sqlite3.DatahistoryjobRels.JobDatahistoryjobresults), - qm.Where("status = ?", 0)) - results, err := query.All(context.Background(), db.sql) +// helpers + +func (db *DBService) createSQLiteDataHistoryJobResponse(result *sqlite3.Datahistoryjob) (*DataHistoryJob, error) { + var exchange *sqlite3.Exchange + var err error + if result.R != nil && result.R.ExchangeName != nil { + exchange = result.R.ExchangeName + } else { + exchange, err = result.ExchangeName().One(context.Background(), db.sql) + if err != nil { + return nil, fmt.Errorf("could not retrieve exchange '%v' %w", result.ExchangeNameID, err) + } + } + var secondaryExchangeName string + if result.SecondaryExchangeID.String != "" { + var secondaryExchangeResult *sqlite3.Exchange + secondaryExchangeResult, err = result.SecondaryExchange().One(context.Background(), db.sql) + if err != nil { + return nil, fmt.Errorf("could not retrieve secondary exchange '%v' %w", result.SecondaryExchangeID, err) + } + if secondaryExchangeResult != nil { + secondaryExchangeName = secondaryExchangeResult.Name + } + } + + ts, err := time.Parse(time.RFC3339, result.StartTime) if err != nil { - return jobs, err + return nil, err + } + te, err := time.Parse(time.RFC3339, result.EndTime) + if err != nil { + return nil, err + } + c, err := time.Parse(time.RFC3339, result.Created) + if err != nil { + return nil, err } - for i := range results { - var jobResults []*datahistoryjobresult.DataHistoryJobResult - for j := range results[i].R.JobDatahistoryjobresults { + prereqJob, err := result.PrerequisiteJobDatahistoryjobs().One(context.Background(), db.sql) + if err != nil && err != sql.ErrNoRows { + return nil, err + } + var prereqNickname, prereqID string + if prereqJob != nil { + prereqID = prereqJob.ID + prereqNickname = prereqJob.Nickname + } + + var jobResults []*datahistoryjobresult.DataHistoryJobResult + if result.R != nil { + for i := range result.R.JobDatahistoryjobresults { var start, end, run time.Time - start, err = time.Parse(time.RFC3339, results[i].R.JobDatahistoryjobresults[j].IntervalStartTime) + start, err = time.Parse(time.RFC3339, result.R.JobDatahistoryjobresults[i].IntervalStartTime) if err != nil { return nil, err } - end, err = time.Parse(time.RFC3339, results[i].R.JobDatahistoryjobresults[j].IntervalEndTime) + end, err = time.Parse(time.RFC3339, result.R.JobDatahistoryjobresults[i].IntervalEndTime) if err != nil { return nil, err } - run, err = time.Parse(time.RFC3339, results[i].R.JobDatahistoryjobresults[j].RunTime) + run, err = time.Parse(time.RFC3339, result.R.JobDatahistoryjobresults[i].RunTime) if err != nil { return nil, err } jobResults = append(jobResults, &datahistoryjobresult.DataHistoryJobResult{ - ID: results[i].R.JobDatahistoryjobresults[j].ID, - JobID: results[i].R.JobDatahistoryjobresults[j].JobID, + ID: result.R.JobDatahistoryjobresults[i].ID, + JobID: result.R.JobDatahistoryjobresults[i].JobID, IntervalStartDate: start, IntervalEndDate: end, - Status: int64(results[i].R.JobDatahistoryjobresults[j].Status), - Result: results[i].R.JobDatahistoryjobresults[j].Result.String, + Status: int64(result.R.JobDatahistoryjobresults[i].Status), + Result: result.R.JobDatahistoryjobresults[i].Result.String, Date: run, }) } + } + + return &DataHistoryJob{ + ID: result.ID, + Nickname: result.Nickname, + ExchangeID: exchange.ID, + ExchangeName: exchange.Name, + Asset: result.Asset, + Base: result.Base, + Quote: result.Quote, + StartDate: ts, + EndDate: te, + Interval: int64(result.Interval), + RequestSizeLimit: int64(result.RequestSize), + DataType: int64(result.DataType), + MaxRetryAttempts: int64(result.MaxRetries), + BatchSize: int64(result.BatchCount), + Status: int64(result.Status), + CreatedDate: c, + PrerequisiteJobID: prereqID, + PrerequisiteJobNickname: prereqNickname, + ConversionInterval: int64(result.ConversionInterval.Float64), + OverwriteData: result.OverwriteData.Int64 == 1, + DecimalPlaceComparison: result.DecimalPlaceComparison.Int64, + SecondarySourceExchangeName: secondaryExchangeName, + IssueTolerancePercentage: result.IssueTolerancePercentage.Float64, + ReplaceOnIssue: result.ReplaceOnIssue.Int64 == 1, + Results: jobResults, + }, nil +} - start, err := time.Parse(time.RFC3339, results[i].StartTime) +func (db *DBService) createPostgresDataHistoryJobResponse(result *postgres.Datahistoryjob) (*DataHistoryJob, error) { + var exchange *postgres.Exchange + var err error + if result.R != nil && result.R.ExchangeName != nil { + exchange = result.R.ExchangeName + } else { + exchange, err = result.ExchangeName().One(context.Background(), db.sql) if err != nil { - return nil, err + return nil, fmt.Errorf("could not retrieve exchange '%v' %w", result.ExchangeNameID, err) } - end, err := time.Parse(time.RFC3339, results[i].EndTime) + } + + var secondaryExchangeName string + if result.SecondaryExchangeID.String != "" { + var secondaryExchangeResult *postgres.Exchange + secondaryExchangeResult, err = result.SecondaryExchange().One(context.Background(), db.sql) if err != nil { - return nil, err + return nil, fmt.Errorf("could not retrieve secondary exchange '%v' %w", result.SecondaryExchangeID, err) } - created, err := time.Parse(time.RFC3339, results[i].Created) - if err != nil { - return nil, err + if secondaryExchangeResult != nil { + secondaryExchangeName = secondaryExchangeResult.Name } - - jobs = append(jobs, DataHistoryJob{ - ID: results[i].ID, - Nickname: results[i].Nickname, - ExchangeID: results[i].ExchangeNameID, - ExchangeName: results[i].R.ExchangeName.Name, - Asset: results[i].Asset, - Base: results[i].Base, - Quote: results[i].Quote, - StartDate: start, - EndDate: end, - Interval: int64(results[i].Interval), - BatchSize: int64(results[i].BatchCount), - RequestSizeLimit: int64(results[i].RequestSize), - DataType: int64(results[i].DataType), - MaxRetryAttempts: int64(results[i].MaxRetries), - Status: int64(results[i].Status), - CreatedDate: created, - Results: jobResults, - }) } - return jobs, nil -} - -func (db *DBService) getAllIncompleteJobsAndResultsPostgres() ([]DataHistoryJob, error) { - var jobs []DataHistoryJob - query := postgres.Datahistoryjobs( - qm.Load(postgres.DatahistoryjobRels.ExchangeName), - qm.Load(postgres.DatahistoryjobRels.JobDatahistoryjobresults), - qm.Where("status = ?", 0)) - results, err := query.All(context.Background(), db.sql) - if err != nil { - return jobs, err + prereqJob, err := result.PrerequisiteJobDatahistoryjobs().One(context.Background(), db.sql) + if err != nil && err != sql.ErrNoRows { + return nil, err + } + var prereqNickname, prereqID string + if prereqJob != nil { + prereqID = prereqJob.ID + prereqNickname = prereqJob.Nickname } - for i := range results { - var jobResults []*datahistoryjobresult.DataHistoryJobResult - for j := range results[i].R.JobDatahistoryjobresults { + var jobResults []*datahistoryjobresult.DataHistoryJobResult + if result.R != nil { + for i := range result.R.JobDatahistoryjobresults { jobResults = append(jobResults, &datahistoryjobresult.DataHistoryJobResult{ - ID: results[i].R.JobDatahistoryjobresults[j].ID, - JobID: results[i].R.JobDatahistoryjobresults[j].JobID, - IntervalStartDate: results[i].R.JobDatahistoryjobresults[j].IntervalStartTime, - IntervalEndDate: results[i].R.JobDatahistoryjobresults[j].IntervalEndTime, - Status: int64(results[i].R.JobDatahistoryjobresults[j].Status), - Result: results[i].R.JobDatahistoryjobresults[j].Result.String, - Date: results[i].R.JobDatahistoryjobresults[j].RunTime, + ID: result.R.JobDatahistoryjobresults[i].ID, + JobID: result.R.JobDatahistoryjobresults[i].JobID, + IntervalStartDate: result.R.JobDatahistoryjobresults[i].IntervalStartTime, + IntervalEndDate: result.R.JobDatahistoryjobresults[i].IntervalEndTime, + Status: int64(result.R.JobDatahistoryjobresults[i].Status), + Result: result.R.JobDatahistoryjobresults[i].Result.String, + Date: result.R.JobDatahistoryjobresults[i].RunTime, }) } - - jobs = append(jobs, DataHistoryJob{ - ID: results[i].ID, - Nickname: results[i].Nickname, - ExchangeID: results[i].ExchangeNameID, - ExchangeName: results[i].R.ExchangeName.Name, - Asset: results[i].Asset, - Base: results[i].Base, - Quote: results[i].Quote, - StartDate: results[i].StartTime, - EndDate: results[i].EndTime, - Interval: int64(results[i].Interval), - BatchSize: int64(results[i].BatchCount), - RequestSizeLimit: int64(results[i].RequestSize), - DataType: int64(results[i].DataType), - MaxRetryAttempts: int64(results[i].MaxRetries), - Status: int64(results[i].Status), - CreatedDate: results[i].Created, - Results: jobResults, - }) } - return jobs, nil + return &DataHistoryJob{ + ID: result.ID, + Nickname: result.Nickname, + ExchangeID: exchange.ID, + ExchangeName: exchange.Name, + Asset: result.Asset, + Base: result.Base, + Quote: result.Quote, + StartDate: result.StartTime, + EndDate: result.EndTime, + Interval: int64(result.Interval), + RequestSizeLimit: int64(result.RequestSize), + DataType: int64(result.DataType), + MaxRetryAttempts: int64(result.MaxRetries), + BatchSize: int64(result.BatchCount), + Status: int64(result.Status), + CreatedDate: result.Created, + Results: jobResults, + PrerequisiteJobID: prereqID, + PrerequisiteJobNickname: prereqNickname, + ConversionInterval: int64(result.ConversionInterval.Float64), + OverwriteData: result.OverwriteData.Bool, + DecimalPlaceComparison: int64(result.DecimalPlaceComparison.Int), + SecondarySourceExchangeName: secondaryExchangeName, + IssueTolerancePercentage: result.IssueTolerancePercentage.Float64, + ReplaceOnIssue: result.ReplaceOnIssue.Bool, + }, nil } diff --git a/database/repository/datahistoryjob/datahistoryjob_test.go b/database/repository/datahistoryjob/datahistoryjob_test.go index a3603d82365..3681e018535 100644 --- a/database/repository/datahistoryjob/datahistoryjob_test.go +++ b/database/repository/datahistoryjob/datahistoryjob_test.go @@ -1,6 +1,7 @@ package datahistoryjob import ( + "errors" "fmt" "io/ioutil" "log" @@ -172,8 +173,8 @@ func TestDataHistoryJob(t *testing.T) { } results, err := db.GetAllIncompleteJobsAndResults() - if err != nil { - t.Error(err) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) } if len(results) != 19 { t.Errorf("expected 19, received %v", len(results)) @@ -188,24 +189,112 @@ func TestDataHistoryJob(t *testing.T) { } results, err = db.GetJobsBetween(time.Now().Add(-time.Hour), time.Now()) - if err != nil { - t.Error(err) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) } if len(results) != 20 { t.Errorf("expected 20, received %v", len(results)) } - jerb, err = db.GetJobAndAllResults(jerberoos[0].Nickname) - if err != nil { - t.Error(err) + jerb, err = db.GetJobAndAllResults(results[0].Nickname) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) } - if !strings.EqualFold(jerb.Nickname, jerberoos[0].Nickname) { + if !strings.EqualFold(jerb.Nickname, results[0].Nickname) { t.Errorf("expected %v, received %v", jerb.Nickname, jerberoos[0].Nickname) } + err = db.SetRelationshipByID(results[0].ID, results[1].ID, 1337) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + + jerb, err = db.GetByID(results[1].ID) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if jerb.Status != 1337 { + t.Error("expected 1337") + } + + rel, err := db.GetRelatedUpcomingJobs(results[0].Nickname) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if len(rel) != 1 { + t.Fatal("expected 1") + } + if rel[0].ID != results[1].ID { + t.Errorf("received %v expected %v", rel[0].ID, results[1].ID) + } + + err = db.SetRelationshipByID(results[0].ID, results[2].ID, 1337) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + rel, err = db.GetRelatedUpcomingJobs(results[0].Nickname) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if len(rel) != 2 { + t.Fatal("expected 2") + } + for i := range rel { + if rel[i].ID != results[1].ID && rel[i].ID != results[2].ID { + t.Errorf("received %v expected %v or %v", rel[i].ID, results[1].ID, results[2].ID) + } + } + + jerb, err = db.GetPrerequisiteJob(results[1].Nickname) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if jerb.ID != results[0].ID { + t.Errorf("received %v expected %v", jerb.ID, results[0].ID) + } + + jerb, err = db.GetPrerequisiteJob(results[2].Nickname) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if jerb.ID != results[0].ID { + t.Errorf("received %v expected %v", jerb.ID, results[0].ID) + } + + err = db.SetRelationshipByNickname(results[4].Nickname, results[2].Nickname, 0) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + err = db.SetRelationshipByNickname(results[2].Nickname, results[2].Nickname, 0) + if !errors.Is(err, errCannotSetSamePrerequisite) { + t.Errorf("received %v expected %v", err, errCannotSetSamePrerequisite) + } + err = db.SetRelationshipByNickname(results[3].Nickname, results[2].Nickname, 0) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + + // ensure only one prerequisite can be associated at once + // after setting the prerequisite twice + rel, err = db.GetRelatedUpcomingJobs(results[4].Nickname) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if len(rel) != 0 { + t.Errorf("received %v expected %v", len(rel), 0) + } + + rel, err = db.GetRelatedUpcomingJobs(results[3].Nickname) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if len(rel) != 1 { + t.Errorf("received %v expected %v", len(rel), 1) + } + err = testhelpers.CloseDatabase(dbConn) - if err != nil { - t.Error(err) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) } }) } diff --git a/database/repository/datahistoryjob/datahistoryjob_types.go b/database/repository/datahistoryjob/datahistoryjob_types.go index 15ad65b5dd1..b44fb349620 100644 --- a/database/repository/datahistoryjob/datahistoryjob_types.go +++ b/database/repository/datahistoryjob/datahistoryjob_types.go @@ -1,31 +1,42 @@ package datahistoryjob import ( + "errors" "time" "github.com/thrasher-corp/gocryptotrader/database" "github.com/thrasher-corp/gocryptotrader/database/repository/datahistoryjobresult" ) +var errCannotSetSamePrerequisite = errors.New("prerequisite job cannot be the same as the following job") + // DataHistoryJob is a DTO for database data type DataHistoryJob struct { - ID string - Nickname string - ExchangeID string - ExchangeName string - Asset string - Base string - Quote string - StartDate time.Time - EndDate time.Time - Interval int64 - RequestSizeLimit int64 - DataType int64 - MaxRetryAttempts int64 - BatchSize int64 - Status int64 - CreatedDate time.Time - Results []*datahistoryjobresult.DataHistoryJobResult + ID string + Nickname string + ExchangeID string + ExchangeName string + Asset string + Base string + Quote string + StartDate time.Time + EndDate time.Time + Interval int64 + RequestSizeLimit int64 + DataType int64 + MaxRetryAttempts int64 + BatchSize int64 + Status int64 + CreatedDate time.Time + Results []*datahistoryjobresult.DataHistoryJobResult + PrerequisiteJobID string + PrerequisiteJobNickname string + ConversionInterval int64 + OverwriteData bool + DecimalPlaceComparison int64 + SecondarySourceExchangeName string + IssueTolerancePercentage float64 + ReplaceOnIssue bool } // DBService is a service which allows the interaction with @@ -38,10 +49,13 @@ type DBService struct { // IDBService allows using data history job database service // without needing to care about implementation type IDBService interface { - Upsert(jobs ...*DataHistoryJob) error - GetByNickName(nickname string) (*DataHistoryJob, error) - GetByID(id string) (*DataHistoryJob, error) - GetJobsBetween(startDate, endDate time.Time) ([]DataHistoryJob, error) + Upsert(...*DataHistoryJob) error + GetByNickName(string) (*DataHistoryJob, error) + GetByID(string) (*DataHistoryJob, error) + GetJobsBetween(time.Time, time.Time) ([]DataHistoryJob, error) GetAllIncompleteJobsAndResults() ([]DataHistoryJob, error) - GetJobAndAllResults(nickname string) (*DataHistoryJob, error) + GetJobAndAllResults(string) (*DataHistoryJob, error) + GetRelatedUpcomingJobs(string) ([]*DataHistoryJob, error) + SetRelationshipByID(string, string, int64) error + SetRelationshipByNickname(string, string, int64) error } diff --git a/database/repository/datahistoryjobresult/datahistoryjobresult.go b/database/repository/datahistoryjobresult/datahistoryjobresult.go index 7ef837b2518..1c956b11d95 100644 --- a/database/repository/datahistoryjobresult/datahistoryjobresult.go +++ b/database/repository/datahistoryjobresult/datahistoryjobresult.go @@ -154,7 +154,7 @@ func upsertPostgres(ctx context.Context, tx *sql.Tx, results ...*DataHistoryJobR IntervalEndTime: results[i].IntervalEndDate.UTC(), RunTime: results[i].Date.UTC(), } - err = tempEvent.Upsert(ctx, tx, true, nil, boil.Infer(), boil.Infer()) + err = tempEvent.Upsert(ctx, tx, false, nil, boil.Infer(), boil.Infer()) if err != nil { return err } diff --git a/database/repository/trade/trade.go b/database/repository/trade/trade.go index e7ed382fd22..816140aed5c 100644 --- a/database/repository/trade/trade.go +++ b/database/repository/trade/trade.go @@ -272,7 +272,7 @@ func getByUUIDPostgres(uuid string) (td Data, err error) { td = Data{ ID: result.ID, - Timestamp: result.Timestamp, + Timestamp: result.Timestamp.UTC(), Exchange: result.ExchangeNameID, Base: strings.ToUpper(result.Base), Quote: strings.ToUpper(result.Quote), @@ -315,7 +315,7 @@ func getInRangeSQLite(exchangeName, assetType, base, quote string, startDate, en "base": strings.ToUpper(base), "quote": strings.ToUpper(quote), } - q := generateQuery(wheres, startDate, endDate) + q := generateQuery(wheres, startDate, endDate, true) query := sqlite3.Trades(q...) var result []*sqlite3.Trade result, err = query.All(context.Background(), database.DB.SQL) @@ -357,7 +357,8 @@ func getInRangePostgres(exchangeName, assetType, base, quote string, startDate, "base": strings.ToUpper(base), "quote": strings.ToUpper(quote), } - q := generateQuery(wheres, startDate, endDate) + + q := generateQuery(wheres, startDate, endDate, false) query := postgres.Trades(q...) var result []*postgres.Trade result, err = query.All(context.Background(), database.DB.SQL) @@ -432,12 +433,18 @@ func deleteTradesPostgres(ctx context.Context, tx *sql.Tx, trades ...Data) error return err } -func generateQuery(clauses map[string]interface{}, start, end time.Time) []qm.QueryMod { +func generateQuery(clauses map[string]interface{}, start, end time.Time, isSQLite bool) []qm.QueryMod { query := []qm.QueryMod{ - qm.Where("timestamp BETWEEN ? AND ?", start.UTC().Format(time.RFC3339), end.UTC().Format(time.RFC3339)), + qm.OrderBy("timestamp"), + } + if isSQLite { + query = append(query, qm.Where("timestamp BETWEEN ? AND ?", start.UTC().Format(time.RFC3339), end.UTC().Format(time.RFC3339))) + } else { + query = append(query, qm.Where("timestamp BETWEEN ? AND ?", start.UTC(), end.UTC())) } for k, v := range clauses { query = append(query, qm.Where(k+` = ?`, v)) } + return query } diff --git a/engine/datahistory_manager.go b/engine/datahistory_manager.go index 18506e2a080..7597cb2fb20 100644 --- a/engine/datahistory_manager.go +++ b/engine/datahistory_manager.go @@ -4,17 +4,20 @@ import ( "database/sql" "errors" "fmt" + "math" "strings" "sync/atomic" "time" "github.com/gofrs/uuid" "github.com/thrasher-corp/gocryptotrader/common" + gctmath "github.com/thrasher-corp/gocryptotrader/common/math" "github.com/thrasher-corp/gocryptotrader/config" "github.com/thrasher-corp/gocryptotrader/currency" "github.com/thrasher-corp/gocryptotrader/database/repository/candle" "github.com/thrasher-corp/gocryptotrader/database/repository/datahistoryjob" "github.com/thrasher-corp/gocryptotrader/database/repository/datahistoryjobresult" + exchange "github.com/thrasher-corp/gocryptotrader/exchanges" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" "github.com/thrasher-corp/gocryptotrader/exchanges/kline" "github.com/thrasher-corp/gocryptotrader/exchanges/trade" @@ -35,9 +38,12 @@ func SetupDataHistoryManager(em iExchangeManager, dcm iDatabaseConnectionManager if cfg.CheckInterval <= 0 { cfg.CheckInterval = defaultDataHistoryTicker } - if cfg.MaxJobsPerCycle == 0 { + if cfg.MaxJobsPerCycle <= 0 { cfg.MaxJobsPerCycle = defaultDataHistoryMaxJobsPerCycle } + if cfg.MaxResultInsertions <= 0 { + cfg.MaxResultInsertions = defaultMaxResultInsertions + } db := dcm.GetInstance() dhj, err := datahistoryjob.Setup(db) if err != nil { @@ -57,8 +63,11 @@ func SetupDataHistoryManager(em iExchangeManager, dcm iDatabaseConnectionManager jobResultDB: dhjr, maxJobsPerCycle: cfg.MaxJobsPerCycle, verbose: cfg.Verbose, - tradeLoader: trade.HasTradesInRanges, + maxResultInsertions: cfg.MaxResultInsertions, + tradeLoader: trade.GetTradesInRange, + tradeSaver: trade.SaveTradesToDatabase, candleLoader: kline.LoadFromDatabase, + candleSaver: kline.StoreInDatabase, }, nil } @@ -138,8 +147,6 @@ func (m *DataHistoryManager) PrepareJobs() ([]*DataHistoryJob, error) { if atomic.LoadInt32(&m.started) == 0 { return nil, ErrSubSystemNotStarted } - m.m.Lock() - defer m.m.Unlock() jobs, err := m.retrieveJobs() if err != nil { defer func() { @@ -173,17 +180,36 @@ func (m *DataHistoryManager) compareJobsToData(jobs ...*DataHistoryJob) error { } var candles kline.Item switch jobs[i].DataType { - case dataHistoryCandleDataType: + case dataHistoryCandleDataType, + dataHistoryCandleValidationDataType, + dataHistoryCandleValidationSecondarySourceType, + dataHistoryConvertTradesDataType: candles, err = m.candleLoader(jobs[i].Exchange, jobs[i].Pair, jobs[i].Asset, jobs[i].Interval, jobs[i].StartDate, jobs[i].EndDate) if err != nil && !errors.Is(err, candle.ErrNoCandleDataFound) { return fmt.Errorf("%s could not load candle data: %w", jobs[i].Nickname, err) } jobs[i].rangeHolder.SetHasDataFromCandles(candles.Candles) case dataHistoryTradeDataType: - err := m.tradeLoader(jobs[i].Exchange, jobs[i].Asset.String(), jobs[i].Pair.Base.String(), jobs[i].Pair.Quote.String(), jobs[i].rangeHolder) - if err != nil && err != sql.ErrNoRows { - return fmt.Errorf("%s could not load trade data: %w", jobs[i].Nickname, err) + for x := range jobs[i].rangeHolder.Ranges { + results, ok := jobs[i].Results[jobs[i].rangeHolder.Ranges[x].Start.Time] + if !ok { + continue + } + for y := range results { + if results[y].Status == dataHistoryStatusComplete { + for z := range jobs[i].rangeHolder.Ranges[x].Intervals { + jobs[i].rangeHolder.Ranges[x].Intervals[z].HasData = true + } + break + } + } + } + case dataHistoryConvertCandlesDataType: + candles, err = m.candleLoader(jobs[i].Exchange, jobs[i].Pair, jobs[i].Asset, jobs[i].ConversionInterval, jobs[i].StartDate, jobs[i].EndDate) + if err != nil && !errors.Is(err, candle.ErrNoCandleDataFound) { + return fmt.Errorf("%s could not load candle data: %w", jobs[i].Nickname, err) } + jobs[i].rangeHolder.SetHasDataFromCandles(candles.Candles) default: return fmt.Errorf("%s %w %s", jobs[i].Nickname, errUnknownDataType, jobs[i].DataType) } @@ -193,14 +219,6 @@ func (m *DataHistoryManager) compareJobsToData(jobs ...*DataHistoryJob) error { func (m *DataHistoryManager) run() { go func() { - validJobs, err := m.PrepareJobs() - if err != nil { - log.Error(log.DataHistory, err) - } - m.m.Lock() - m.jobs = validJobs - m.m.Unlock() - for { select { case <-m.shutdown: @@ -227,7 +245,7 @@ func (m *DataHistoryManager) runJobs() error { } if !atomic.CompareAndSwapInt32(&m.processing, 0, 1) { - return fmt.Errorf("runJobs %w", errAlreadyRunning) + return fmt.Errorf("cannot process jobs, %w", errAlreadyRunning) } defer atomic.StoreInt32(&m.processing, 0) @@ -235,20 +253,21 @@ func (m *DataHistoryManager) runJobs() error { if err != nil { return err } + if len(validJobs) == 0 { + if m.verbose { + log.Infof(log.DataHistory, "no data history jobs to process") + } + return nil + } - m.m.Lock() - defer func() { - m.m.Unlock() - }() - m.jobs = validJobs log.Infof(log.DataHistory, "processing data history jobs") - for i := 0; (i < int(m.maxJobsPerCycle) || m.maxJobsPerCycle == -1) && i < len(m.jobs); i++ { - err := m.runJob(m.jobs[i]) + for i := 0; (i < int(m.maxJobsPerCycle) || m.maxJobsPerCycle == -1) && i < len(validJobs); i++ { + err := m.runJob(validJobs[i]) if err != nil { log.Error(log.DataHistory, err) } if m.verbose { - log.Debugf(log.DataHistory, "completed run of data history job %v", m.jobs[i].Nickname) + log.Debugf(log.DataHistory, "completed run of data history job %v", validJobs[i].Nickname) } } log.Infof(log.DataHistory, "completed run of data history jobs") @@ -265,10 +284,12 @@ func (m *DataHistoryManager) runJob(job *DataHistoryJob) error { if atomic.LoadInt32(&m.started) == 0 { return ErrSubSystemNotStarted } + if job == nil { + return errNilJob + } if job.Status != dataHistoryStatusActive { - return nil + return fmt.Errorf("job %s %w", job.Nickname, errJobInvalid) } - var intervalsProcessed int64 if job.rangeHolder == nil || len(job.rangeHolder.Ranges) == 0 { return fmt.Errorf("%s %w invalid start/end range %s-%s", job.Nickname, @@ -277,8 +298,11 @@ func (m *DataHistoryManager) runJob(job *DataHistoryJob) error { job.EndDate.Format(common.SimpleTimeFormatWithTimezone), ) } - - exch := m.exchangeManager.GetExchangeByName(job.Exchange) + exchangeName := job.Exchange + if job.DataType == dataHistoryCandleValidationSecondarySourceType { + exchangeName = job.SecondaryExchangeSource + } + exch := m.exchangeManager.GetExchangeByName(exchangeName) if exch == nil { return fmt.Errorf("%s %w, cannot process job %s for %s %s", job.Exchange, @@ -287,53 +311,117 @@ func (m *DataHistoryManager) runJob(job *DataHistoryJob) error { job.Asset, job.Pair) } - if m.verbose { - log.Debugf(log.DataHistory, "running data history job %v start: %s end: %s interval: %s datatype: %s", - job.Nickname, - job.StartDate, - job.EndDate, - job.Interval, - job.DataType) + + if job.DataType == dataHistoryCandleValidationDataType || + job.DataType == dataHistoryCandleValidationSecondarySourceType { + err := m.runValidationJob(job, exch) + if err != nil { + return err + } + } else { + err := m.runDataJob(job, exch) + if err != nil { + return err + } + } + + dbJob := m.convertJobToDBModel(job) + err := m.jobDB.Upsert(dbJob) + if err != nil { + return fmt.Errorf("job %s failed to update database: %w", job.Nickname, err) + } + + dbJobResults := m.convertJobResultToDBResult(job.Results) + err = m.jobResultDB.Upsert(dbJobResults...) + if err != nil { + return fmt.Errorf("job %s failed to insert job results to database: %w", job.Nickname, err) + } + return nil +} + +// runDataJob will fetch data from an API endpoint or convert existing database data +// into a new candle type +func (m *DataHistoryManager) runDataJob(job *DataHistoryJob, exch exchange.IBotExchange) error { + if !m.IsRunning() { + return ErrSubSystemNotStarted } + var intervalsProcessed int64 + var err error + var result *DataHistoryJobResult ranges: for i := range job.rangeHolder.Ranges { - isCompleted := true + skipProcessing := true for j := range job.rangeHolder.Ranges[i].Intervals { if !job.rangeHolder.Ranges[i].Intervals[j].HasData { - isCompleted = false + skipProcessing = false break } } - if isCompleted || - intervalsProcessed >= job.RunBatchLimit { + if skipProcessing { + _, ok := job.Results[job.rangeHolder.Ranges[i].Start.Time] + if !ok && !job.OverwriteExistingData { + // we have determined that data is there, however it is not reflected in + // this specific job's results, which is required for a job to be complete + var id uuid.UUID + id, err = uuid.NewV4() + if err != nil { + return err + } + job.Results[job.rangeHolder.Ranges[i].Start.Time] = []DataHistoryJobResult{ + { + ID: id, + JobID: job.ID, + IntervalStartDate: job.rangeHolder.Ranges[i].Start.Time, + IntervalEndDate: job.rangeHolder.Ranges[i].End.Time, + Status: dataHistoryStatusComplete, + Date: time.Now(), + }, + } + } + if !job.OverwriteExistingData { + continue + } + } + if intervalsProcessed >= job.RunBatchLimit { continue } + if m.verbose { + log.Debugf(log.DataHistory, "running data history job %v start: %s end: %s interval: %s datatype: %s", + job.Nickname, + job.rangeHolder.Ranges[i].Start.Time, + job.rangeHolder.Ranges[i].End.Time, + job.Interval, + job.DataType) + } + var failures int64 hasDataInRange := false - resultLookup := job.Results[job.rangeHolder.Ranges[i].Start.Time] - for x := range resultLookup { - switch resultLookup[x].Status { - case dataHistoryIntervalMissingData: - continue ranges - case dataHistoryStatusFailed: - failures++ - case dataHistoryStatusComplete: - // this can occur in the scenario where data is missing - // however no errors were encountered when data is missing - // eg an exchange only returns an empty slice - // or the exchange is simply missing the data and does not have an error - hasDataInRange = true - } - } - if failures >= job.MaxRetryAttempts { - // failure threshold reached, we should not attempt - // to check this interval again + resultLookup, ok := job.Results[job.rangeHolder.Ranges[i].Start.Time] + if ok { for x := range resultLookup { - resultLookup[x].Status = dataHistoryIntervalMissingData + switch resultLookup[x].Status { + case dataHistoryIntervalIssuesFound: + continue ranges + case dataHistoryStatusFailed: + failures++ + case dataHistoryStatusComplete: + // this can occur in the scenario where data is missing + // however no errors were encountered when data is missing + // eg an exchange only returns an empty slice + // or the exchange is simply missing the data and does not have an error + hasDataInRange = true + } + } + if failures >= job.MaxRetryAttempts { + // failure threshold reached, we should not attempt + // to check this interval again + for x := range resultLookup { + resultLookup[x].Status = dataHistoryIntervalIssuesFound + } + job.Results[job.rangeHolder.Ranges[i].Start.Time] = resultLookup + continue } - job.Results[job.rangeHolder.Ranges[i].Start.Time] = resultLookup - continue } if hasDataInRange { continue @@ -342,77 +430,31 @@ ranges: log.Debugf(log.DataHistory, "job %s processing range %v-%v", job.Nickname, job.rangeHolder.Ranges[i].Start, job.rangeHolder.Ranges[i].End) } intervalsProcessed++ - id, err := uuid.NewV4() - if err != nil { - return err - } - result := DataHistoryJobResult{ - ID: id, - JobID: job.ID, - IntervalStartDate: job.rangeHolder.Ranges[i].Start.Time, - IntervalEndDate: job.rangeHolder.Ranges[i].End.Time, - Status: dataHistoryStatusComplete, - Date: time.Now(), - } + // processing the job switch job.DataType { case dataHistoryCandleDataType: - candles, err := exch.GetHistoricCandlesExtended(job.Pair, job.Asset, job.rangeHolder.Ranges[i].Start.Time, job.rangeHolder.Ranges[i].End.Time, job.Interval) - if err != nil { - result.Result += "could not get candles: " + err.Error() + ". " - result.Status = dataHistoryStatusFailed - break - } - job.rangeHolder.SetHasDataFromCandles(candles.Candles) - for j := range job.rangeHolder.Ranges[i].Intervals { - if !job.rangeHolder.Ranges[i].Intervals[j].HasData { - result.Status = dataHistoryStatusFailed - result.Result += fmt.Sprintf("missing data from %v - %v. ", - job.rangeHolder.Ranges[i].Intervals[j].Start.Time.Format(common.SimpleTimeFormatWithTimezone), - job.rangeHolder.Ranges[i].Intervals[j].End.Time.Format(common.SimpleTimeFormatWithTimezone)) - } - } - _, err = kline.StoreInDatabase(&candles, true) - if err != nil { - result.Result += "could not save results: " + err.Error() + ". " - result.Status = dataHistoryStatusFailed - } + result, err = m.processCandleData(job, exch, job.rangeHolder.Ranges[i].Start.Time, job.rangeHolder.Ranges[i].End.Time, int64(i)) case dataHistoryTradeDataType: - trades, err := exch.GetHistoricTrades(job.Pair, job.Asset, job.rangeHolder.Ranges[i].Start.Time, job.rangeHolder.Ranges[i].End.Time) - if err != nil { - result.Result += "could not get trades: " + err.Error() + ". " - result.Status = dataHistoryStatusFailed - break - } - candles, err := trade.ConvertTradesToCandles(job.Interval, trades...) - if err != nil { - result.Result += "could not convert candles to trades: " + err.Error() + ". " - result.Status = dataHistoryStatusFailed - break - } - job.rangeHolder.SetHasDataFromCandles(candles.Candles) - for j := range job.rangeHolder.Ranges[i].Intervals { - if !job.rangeHolder.Ranges[i].Intervals[j].HasData { - result.Status = dataHistoryStatusFailed - result.Result += fmt.Sprintf("missing data from %v - %v. ", - job.rangeHolder.Ranges[i].Intervals[j].Start.Time.Format(common.SimpleTimeFormatWithTimezone), - job.rangeHolder.Ranges[i].Intervals[j].End.Time.Format(common.SimpleTimeFormatWithTimezone)) - } - } - err = trade.SaveTradesToDatabase(trades...) - if err != nil { - result.Result += "could not save results: " + err.Error() + ". " - result.Status = dataHistoryStatusFailed - } + result, err = m.processTradeData(job, exch, job.rangeHolder.Ranges[i].Start.Time, job.rangeHolder.Ranges[i].End.Time, int64(i)) + case dataHistoryConvertTradesDataType: + result, err = m.convertTradesToCandles(job, job.rangeHolder.Ranges[i].Start.Time, job.rangeHolder.Ranges[i].End.Time) + case dataHistoryConvertCandlesDataType: + result, err = m.convertCandleData(job, job.rangeHolder.Ranges[i].Start.Time, job.rangeHolder.Ranges[i].End.Time) default: return errUnknownDataType } + if err != nil { + return err + } + if result == nil { + return errNilResult + } lookup := job.Results[result.IntervalStartDate] - lookup = append(lookup, result) + lookup = append(lookup, *result) job.Results[result.IntervalStartDate] = lookup } - completed := true allResultsSuccessful := true allResultsFailed := true @@ -425,7 +467,7 @@ completionCheck: results: for j := range result { switch result[j].Status { - case dataHistoryIntervalMissingData: + case dataHistoryIntervalIssuesFound: allResultsSuccessful = false break results case dataHistoryStatusComplete: @@ -438,29 +480,596 @@ completionCheck: } } if completed { - switch { - case allResultsSuccessful: - job.Status = dataHistoryStatusComplete - case allResultsFailed: - job.Status = dataHistoryStatusFailed - default: - job.Status = dataHistoryIntervalMissingData + err := m.completeJob(job, allResultsSuccessful, allResultsFailed) + if err != nil { + return err } - log.Infof(log.DataHistory, "job %s finished! Status: %s", job.Nickname, job.Status) } + return nil +} - dbJob := m.convertJobToDBModel(job) - err := m.jobDB.Upsert(dbJob) +// runValidationJob verifies existing database candle data against +// the original API's data, or a secondary exchange source +func (m *DataHistoryManager) runValidationJob(job *DataHistoryJob, exch exchange.IBotExchange) error { + if !m.IsRunning() { + return ErrSubSystemNotStarted + } + var intervalsProcessed int64 + var jobIntervals, intervalsToCheck []time.Time + intervalLength := job.Interval.Duration() * time.Duration(job.RequestSizeLimit) + for i := job.StartDate; i.Before(job.EndDate); i = i.Add(intervalLength) { + jobIntervals = append(jobIntervals, i) + } + nextIntervalToProcess := job.StartDate +timesToFetch: + for t, results := range job.Results { + if len(results) < int(job.MaxRetryAttempts) { + for x := range results { + if results[x].Status == dataHistoryStatusComplete { + continue timesToFetch + } + } + intervalsToCheck = append(intervalsToCheck, t) + } else { + for x := range results { + results[x].Status = dataHistoryIntervalIssuesFound + } + job.Results[t] = results + } + if t.After(nextIntervalToProcess) { + nextIntervalToProcess = t.Add(intervalLength) + } + } + for i := nextIntervalToProcess; i.Before(job.EndDate); i = i.Add(intervalLength) { + intervalsToCheck = append(intervalsToCheck, i) + } + + for i := range intervalsToCheck { + if intervalsProcessed >= job.RunBatchLimit { + break + } + if err := common.StartEndTimeCheck(intervalsToCheck[i], job.EndDate); err != nil { + break + } + requestEnd := intervalsToCheck[i].Add(intervalLength) + if requestEnd.After(job.EndDate) { + requestEnd = job.EndDate + } + if m.verbose { + log.Debugf(log.DataHistory, "running data history job %v start: %s end: %s interval: %s datatype: %s", + job.Nickname, + intervalsToCheck[i], + requestEnd, + job.Interval, + job.DataType) + } + intervalsProcessed++ + result, err := m.validateCandles(job, exch, intervalsToCheck[i], requestEnd) + if err != nil { + return err + } + lookup := job.Results[result.IntervalStartDate] + lookup = append(lookup, *result) + job.Results[result.IntervalStartDate] = lookup + } + + completed := true + allResultsSuccessful := true + allResultsFailed := true +completionCheck: + for i := range jobIntervals { + results, ok := job.Results[jobIntervals[i]] + if !ok { + completed = false + break + } + results: + for j := range results { + switch results[j].Status { + case dataHistoryIntervalIssuesFound: + allResultsSuccessful = false + break results + case dataHistoryStatusComplete: + allResultsFailed = false + break results + default: + completed = false + break completionCheck + } + } + } + if completed { + err := m.completeJob(job, allResultsSuccessful, allResultsFailed) + if err != nil { + return err + } + } + + return nil +} + +// completeJob will set the job's overall status and +// set any jobs' status where the current job is a prerequisite to 'active' +func (m *DataHistoryManager) completeJob(job *DataHistoryJob, allResultsSuccessful, allResultsFailed bool) error { + if !m.IsRunning() { + return ErrSubSystemNotStarted + } + if job == nil { + return errNilJob + } + if allResultsSuccessful && allResultsFailed { + return errJobInvalid + } + switch { + case allResultsSuccessful: + job.Status = dataHistoryStatusComplete + case allResultsFailed: + job.Status = dataHistoryStatusFailed + default: + job.Status = dataHistoryIntervalIssuesFound + } + log.Infof(log.DataHistory, "job %s finished! Status: %s", job.Nickname, job.Status) + if job.Status != dataHistoryStatusFailed { + newJobs, err := m.jobDB.GetRelatedUpcomingJobs(job.Nickname) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return err + } + var newJobNames []string + for i := range newJobs { + newJobs[i].Status = int64(dataHistoryStatusActive) + newJobNames = append(newJobNames, newJobs[i].Nickname) + } + if len(newJobNames) > 0 { + log.Infof(log.DataHistory, "setting the following jobs to active: %s", strings.Join(newJobNames, ", ")) + err = m.jobDB.Upsert(newJobs...) + if err != nil { + return err + } + } + } + return nil +} + +func (m *DataHistoryManager) saveCandlesInBatches(job *DataHistoryJob, candles *kline.Item, r *DataHistoryJobResult) error { + if !m.IsRunning() { + return ErrSubSystemNotStarted + } + if job == nil { + return errNilJob + } + if candles == nil { + return errNilCandles + } + if r == nil { + return errNilResult + } + if m.maxResultInsertions <= 0 { + m.maxResultInsertions = defaultMaxResultInsertions + } + var err error + for i := 0; i < len(candles.Candles); i += int(m.maxResultInsertions) { + newCandle := *candles + if i+int(m.maxResultInsertions) > len(newCandle.Candles) { + if m.verbose { + log.Debugf(log.DataHistory, "Saving %v candles. Range %v-%v/%v", len(newCandle.Candles[i:]), i, len(candles.Candles), len(candles.Candles)) + } + newCandle.Candles = newCandle.Candles[i:] + _, err = m.candleSaver(&newCandle, job.OverwriteExistingData) + if err != nil { + r.Result += "could not save results: " + err.Error() + ". " + r.Status = dataHistoryStatusFailed + } + break + } + if m.verbose { + log.Debugf(log.DataHistory, "Saving %v candles. Range %v-%v/%v", m.maxResultInsertions, i, i+int(m.maxResultInsertions), len(candles.Candles)) + } + newCandle.Candles = newCandle.Candles[i : i+int(m.maxResultInsertions)] + _, err = m.candleSaver(&newCandle, job.OverwriteExistingData) + if err != nil { + r.Result += "could not save results: " + err.Error() + ". " + r.Status = dataHistoryStatusFailed + } + } + return nil +} + +func (m *DataHistoryManager) processCandleData(job *DataHistoryJob, exch exchange.IBotExchange, startRange, endRange time.Time, intervalIndex int64) (*DataHistoryJobResult, error) { + if !m.IsRunning() { + return nil, ErrSubSystemNotStarted + } + if job == nil { + return nil, errNilJob + } + if exch == nil { + return nil, ErrExchangeNotFound + } + if err := common.StartEndTimeCheck(startRange, endRange); err != nil { + return nil, err + } + + id, err := uuid.NewV4() if err != nil { - return fmt.Errorf("job %s failed to update database: %w", job.Nickname, err) + return nil, err + } + r := &DataHistoryJobResult{ + ID: id, + JobID: job.ID, + IntervalStartDate: startRange, + IntervalEndDate: endRange, + Status: dataHistoryStatusComplete, + Date: time.Now(), } + candles, err := exch.GetHistoricCandlesExtended(job.Pair, job.Asset, startRange, endRange, job.Interval) + if err != nil { + r.Result += "could not get candles: " + err.Error() + ". " + r.Status = dataHistoryStatusFailed + return r, nil + } + job.rangeHolder.SetHasDataFromCandles(candles.Candles) + for i := range job.rangeHolder.Ranges[intervalIndex].Intervals { + if !job.rangeHolder.Ranges[intervalIndex].Intervals[i].HasData { + r.Status = dataHistoryStatusFailed + r.Result += fmt.Sprintf("missing data from %v - %v. ", + startRange.Format(common.SimpleTimeFormatWithTimezone), + endRange.Format(common.SimpleTimeFormatWithTimezone)) + } + } + candles.SourceJobID = job.ID + err = m.saveCandlesInBatches(job, &candles, r) + return r, err +} - dbJobResults := m.convertJobResultToDBResult(job.Results) - err = m.jobResultDB.Upsert(dbJobResults...) +func (m *DataHistoryManager) processTradeData(job *DataHistoryJob, exch exchange.IBotExchange, startRange, endRange time.Time, intervalIndex int64) (*DataHistoryJobResult, error) { + if !m.IsRunning() { + return nil, ErrSubSystemNotStarted + } + if job == nil { + return nil, errNilJob + } + if exch == nil { + return nil, ErrExchangeNotFound + } + if err := common.StartEndTimeCheck(startRange, endRange); err != nil { + return nil, err + } + id, err := uuid.NewV4() if err != nil { - return fmt.Errorf("job %s failed to insert job results to database: %w", job.Nickname, err) + return nil, err } - return nil + r := &DataHistoryJobResult{ + ID: id, + JobID: job.ID, + IntervalStartDate: startRange, + IntervalEndDate: endRange, + Status: dataHistoryStatusComplete, + Date: time.Now(), + } + trades, err := exch.GetHistoricTrades(job.Pair, job.Asset, startRange, endRange) + if err != nil { + r.Result += "could not get trades: " + err.Error() + ". " + r.Status = dataHistoryStatusFailed + return r, nil + } + candles, err := trade.ConvertTradesToCandles(job.Interval, trades...) + if err != nil { + r.Result += "could not convert candles to trades: " + err.Error() + ". " + r.Status = dataHistoryStatusFailed + return r, nil + } + job.rangeHolder.SetHasDataFromCandles(candles.Candles) + for i := range job.rangeHolder.Ranges[intervalIndex].Intervals { + if !job.rangeHolder.Ranges[intervalIndex].Intervals[i].HasData { + r.Status = dataHistoryStatusFailed + r.Result += fmt.Sprintf("missing data from %v - %v. ", + job.rangeHolder.Ranges[intervalIndex].Intervals[i].Start.Time.Format(common.SimpleTimeFormatWithTimezone), + job.rangeHolder.Ranges[intervalIndex].Intervals[i].End.Time.Format(common.SimpleTimeFormatWithTimezone)) + } + } + for i := 0; i < len(trades); i += int(m.maxResultInsertions) { + if i+int(m.maxResultInsertions) > len(trades) { + if m.verbose { + log.Debugf(log.DataHistory, "Saving %v trades. Range %v-%v/%v", len(trades[i:]), i, len(trades), len(trades)) + } + err = m.tradeSaver(trades[i:]...) + if err != nil { + r.Result += "could not save results: " + err.Error() + ". " + r.Status = dataHistoryStatusFailed + } + break + } + if m.verbose { + log.Debugf(log.DataHistory, "Saving %v trades. Range %v-%v/%v", m.maxResultInsertions, i, i+int(m.maxResultInsertions), len(trades)) + } + err = m.tradeSaver(trades[i : i+int(m.maxResultInsertions)]...) + if err != nil { + r.Result += "could not save results: " + err.Error() + ". " + r.Status = dataHistoryStatusFailed + } + } + return r, nil +} + +func (m *DataHistoryManager) convertTradesToCandles(job *DataHistoryJob, startRange, endRange time.Time) (*DataHistoryJobResult, error) { + if !m.IsRunning() { + return nil, ErrSubSystemNotStarted + } + if job == nil { + return nil, errNilJob + } + if err := common.StartEndTimeCheck(startRange, endRange); err != nil { + return nil, err + } + id, err := uuid.NewV4() + if err != nil { + return nil, err + } + r := &DataHistoryJobResult{ + ID: id, + JobID: job.ID, + IntervalStartDate: startRange, + IntervalEndDate: endRange, + Status: dataHistoryStatusComplete, + Date: time.Now(), + } + trades, err := m.tradeLoader(job.Exchange, job.Asset.String(), job.Pair.Base.String(), job.Pair.Quote.String(), startRange, endRange) + if err != nil { + r.Result = "could not get trades in range: " + err.Error() + r.Status = dataHistoryStatusFailed + return r, nil + } + candles, err := trade.ConvertTradesToCandles(job.Interval, trades...) + if err != nil { + r.Result = "could not convert trades in range: " + err.Error() + r.Status = dataHistoryStatusFailed + return r, nil + } + candles.SourceJobID = job.ID + err = m.saveCandlesInBatches(job, &candles, r) + return r, err +} + +func (m *DataHistoryManager) convertCandleData(job *DataHistoryJob, startRange, endRange time.Time) (*DataHistoryJobResult, error) { + if !m.IsRunning() { + return nil, ErrSubSystemNotStarted + } + if job == nil { + return nil, errNilJob + } + if err := common.StartEndTimeCheck(startRange, endRange); err != nil { + return nil, err + } + id, err := uuid.NewV4() + if err != nil { + return nil, err + } + r := &DataHistoryJobResult{ + ID: id, + JobID: job.ID, + IntervalStartDate: startRange, + IntervalEndDate: endRange, + Status: dataHistoryStatusComplete, + Date: time.Now(), + } + candles, err := m.candleLoader(job.Exchange, job.Pair, job.Asset, job.Interval, startRange, endRange) + if err != nil { + r.Result = "could not get candles in range: " + err.Error() + r.Status = dataHistoryStatusFailed + return r, nil + } + newCandles, err := kline.ConvertToNewInterval(&candles, job.ConversionInterval) + if err != nil { + r.Result = "could not convert candles in range: " + err.Error() + r.Status = dataHistoryStatusFailed + return r, nil + } + newCandles.SourceJobID = job.ID + err = m.saveCandlesInBatches(job, &candles, r) + return r, err +} + +func (m *DataHistoryManager) validateCandles(job *DataHistoryJob, exch exchange.IBotExchange, startRange, endRange time.Time) (*DataHistoryJobResult, error) { + if !m.IsRunning() { + return nil, ErrSubSystemNotStarted + } + if job == nil { + return nil, errNilJob + } + if exch == nil { + return nil, ErrExchangeNotFound + } + if err := common.StartEndTimeCheck(startRange, endRange); err != nil { + return nil, err + } + id, err := uuid.NewV4() + if err != nil { + return nil, err + } + r := &DataHistoryJobResult{ + ID: id, + JobID: job.ID, + IntervalStartDate: startRange, + IntervalEndDate: endRange, + Status: dataHistoryStatusComplete, + Date: time.Now(), + } + + apiCandles, err := exch.GetHistoricCandlesExtended(job.Pair, job.Asset, startRange, endRange, job.Interval) + if err != nil { + r.Result = "could not get API candles: " + err.Error() + r.Status = dataHistoryStatusFailed + return r, nil + } + apiCandles.ValidationJobID = job.ID + dbCandles, err := m.candleLoader(job.Exchange, job.Pair, job.Asset, job.Interval, startRange, endRange) + if err != nil { + r.Result = "could not get database candles: " + err.Error() + r.Status = dataHistoryStatusFailed + return r, nil + } + if len(dbCandles.Candles) == 0 { + r.Result = fmt.Sprintf("missing database candles for period %v-%v", startRange, endRange) + r.Status = dataHistoryIntervalIssuesFound + return r, nil + } + + if len(dbCandles.Candles) > 0 && len(apiCandles.Candles) == 0 { + r.Result = fmt.Sprintf("no matching API data for database candles for period %v-%v", startRange, endRange) + r.Status = dataHistoryStatusFailed + return r, nil + } + if len(dbCandles.Candles) != len(apiCandles.Candles) && m.verbose { + log.Warnf(log.DataHistory, "mismatched candle length for period %v-%v. DB: %v, API: %v", startRange, endRange, len(dbCandles.Candles), len(apiCandles.Candles)) + } + + dbCandleMap := make(map[int64]kline.Candle) + for i := range dbCandles.Candles { + dbCandleMap[dbCandles.Candles[i].Time.Unix()] = dbCandles.Candles[i] + } + var validationIssues []string + multiplier := int64(1) + for i := int64(0); i < job.DecimalPlaceComparison; i++ { + multiplier *= 10 + } + for i := range apiCandles.Candles { + can, ok := dbCandleMap[apiCandles.Candles[i].Time.Unix()] + if !ok { + validationIssues = append(validationIssues, fmt.Sprintf("issues found at %v missing candle data in database", apiCandles.Candles[i].Time.Format(common.SimpleTimeFormatWithTimezone))) + r.Status = dataHistoryIntervalIssuesFound + continue + } + var candleIssues []string + var candleModified bool + + issue, modified := m.CheckCandleIssue(job, multiplier, apiCandles.Candles[i].Open, can.Open, "Open") + if issue != "" { + candleIssues = append(candleIssues, issue) + } + if modified { + candleModified = true + } + issue, modified = m.CheckCandleIssue(job, multiplier, apiCandles.Candles[i].High, can.High, "High") + if issue != "" { + candleIssues = append(candleIssues, issue) + } + if modified { + candleModified = true + } + issue, modified = m.CheckCandleIssue(job, multiplier, apiCandles.Candles[i].Low, can.Low, "Low") + if issue != "" { + candleIssues = append(candleIssues, issue) + } + if modified { + candleModified = true + } + issue, modified = m.CheckCandleIssue(job, multiplier, apiCandles.Candles[i].Close, can.Close, "Close") + if issue != "" { + candleIssues = append(candleIssues, issue) + } + if modified { + candleModified = true + } + if job.SecondaryExchangeSource == "" { + issue, modified = m.CheckCandleIssue(job, multiplier, apiCandles.Candles[i].Volume, can.Volume, "Volume") + if issue != "" { + candleIssues = append(candleIssues, issue) + } + if modified { + candleModified = true + } + } + if candleModified { + candleIssues = append(candleIssues, "replacing mismatched database candle data with API data") + } + // we update candles regardless to link candle to validation job + apiCandles.Candles[i] = can + + if len(candleIssues) > 0 { + candleIssues = append([]string{fmt.Sprintf("issues found at %v", can.Time.Format(common.SimpleTimeFormat))}, candleIssues...) + validationIssues = append(validationIssues, candleIssues...) + r.Status = dataHistoryStatusFailed + apiCandles.Candles[i].ValidationIssues = strings.Join(candleIssues, ", ") + } + } + if len(validationIssues) > 0 { + r.Result = strings.Join(validationIssues, " -- ") + } + err = m.saveCandlesInBatches(job, &apiCandles, r) + return r, err +} + +// CheckCandleIssue verifies that stored data matches API data +// a job can specify a level of rounding along with a tolerance percentage +// a job can also replace data with API data if the database data exceeds the tolerance +func (m *DataHistoryManager) CheckCandleIssue(job *DataHistoryJob, multiplier int64, apiData, dbData float64, candleField string) (issue string, replace bool) { + if m == nil { + return ErrNilSubsystem.Error(), false + } + if atomic.LoadInt32(&m.started) == 0 { + return ErrSubSystemNotStarted.Error(), false + } + if job == nil { + return errNilJob.Error(), false + } + + floatiplier := float64(multiplier) + if floatiplier > 0 { + apiData = math.Round(apiData*floatiplier) / floatiplier + dbData = math.Round(dbData*floatiplier) / floatiplier + } + if apiData != dbData { + var diff float64 + if apiData > dbData { + diff = gctmath.CalculatePercentageGainOrLoss(apiData, dbData) + } else { + diff = gctmath.CalculatePercentageGainOrLoss(dbData, apiData) + } + if diff > job.IssueTolerancePercentage { + issue = fmt.Sprintf("%s api: %v db: %v diff: %v %%", candleField, apiData, dbData, diff) + } + if job.ReplaceOnIssue && + job.IssueTolerancePercentage != 0 && + diff > job.IssueTolerancePercentage && + job.SecondaryExchangeSource == "" { + replace = true + } + } + return issue, replace +} + +// SetJobRelationship will add/modify/delete a relationship with an existing job +// it will add the relationship and set the jobNickname job to paused +// if deleting, it will remove the relationship from the database and set the job to active +func (m *DataHistoryManager) SetJobRelationship(prerequisiteJobNickname, jobNickname string) error { + if m == nil { + return ErrNilSubsystem + } + if atomic.LoadInt32(&m.started) == 0 { + return ErrSubSystemNotStarted + } + if jobNickname == "" { + return errNicknameUnset + } + status := dataHistoryStatusPaused + if prerequisiteJobNickname == "" { + j, err := m.GetByNickname(jobNickname, false) + if err != nil { + return err + } + status = j.Status + if j.Status == dataHistoryStatusPaused { + status = dataHistoryStatusActive + } + } else { + j, err := m.GetByNickname(prerequisiteJobNickname, false) + if err != nil { + return err + } + if j.Status != dataHistoryStatusActive && j.Status != dataHistoryStatusPaused { + return fmt.Errorf("cannot set prerequisite %v to job %v, %w", prerequisiteJobNickname, jobNickname, errJobMustBeActiveOrPaused) + } + } + return m.jobDB.SetRelationshipByNickname(prerequisiteJobNickname, jobNickname, int64(status)) } // UpsertJob allows for GRPC interaction to upsert a job to be processed @@ -477,63 +1086,35 @@ func (m *DataHistoryManager) UpsertJob(job *DataHistoryJob, insertOnly bool) err if job.Nickname == "" { return fmt.Errorf("upsert job %w", errNicknameUnset) } - j, err := m.GetByNickname(job.Nickname, false) if err != nil && !errors.Is(err, errJobNotFound) { return err } - if insertOnly && j != nil || (j != nil && j.Status != dataHistoryStatusActive) { return fmt.Errorf("upsert job %w nickname: %s - status: %s ", errNicknameInUse, j.Nickname, j.Status) } - - m.m.Lock() - defer m.m.Unlock() + if job.PrerequisiteJobNickname != "" { + var p *DataHistoryJob + p, err = m.GetByNickname(job.PrerequisiteJobNickname, false) + if err != nil { + return fmt.Errorf("upsert job %s could not find prerequisite job nickname %v %w", job.Nickname, job.PrerequisiteJobNickname, err) + } + if p.Status != dataHistoryStatusActive && p.Status != dataHistoryStatusPaused { + return fmt.Errorf("upsert job %s prerequisite job nickname %v already completed %w", job.Nickname, p.Nickname, errJobInvalid) + } + } err = m.validateJob(job) if err != nil { return err } - toUpdate := false - if !insertOnly { - for i := range m.jobs { - if !strings.EqualFold(m.jobs[i].Nickname, job.Nickname) { - continue - } - toUpdate = true - job.ID = m.jobs[i].ID - if job.Exchange != "" && m.jobs[i].Exchange != job.Exchange { - m.jobs[i].Exchange = job.Exchange - } - if job.Asset != "" && m.jobs[i].Asset != job.Asset { - m.jobs[i].Asset = job.Asset - } - if !job.Pair.IsEmpty() && !m.jobs[i].Pair.Equal(job.Pair) { - m.jobs[i].Pair = job.Pair - } - if !job.StartDate.IsZero() && !m.jobs[i].StartDate.Equal(job.StartDate) { - m.jobs[i].StartDate = job.StartDate - } - if !job.EndDate.IsZero() && !m.jobs[i].EndDate.Equal(job.EndDate) { - m.jobs[i].EndDate = job.EndDate - } - if job.Interval != 0 && m.jobs[i].Interval != job.Interval { - m.jobs[i].Interval = job.Interval - } - if job.RunBatchLimit != 0 && m.jobs[i].RunBatchLimit != job.RunBatchLimit { - m.jobs[i].RunBatchLimit = job.RunBatchLimit - } - if job.RequestSizeLimit != 0 && m.jobs[i].RequestSizeLimit != job.RequestSizeLimit { - m.jobs[i].RequestSizeLimit = job.RequestSizeLimit - } - if job.MaxRetryAttempts != 0 && m.jobs[i].MaxRetryAttempts != job.MaxRetryAttempts { - m.jobs[i].MaxRetryAttempts = job.MaxRetryAttempts - } - m.jobs[i].DataType = job.DataType - m.jobs[i].Status = job.Status - break - } + existingJob, err := m.GetByNickname(job.Nickname, false) + if err != nil && err != errJobNotFound { + return err + } + if existingJob != nil { + job.ID = existingJob.ID } if job.ID == uuid.Nil { job.ID, err = uuid.NewV4() @@ -541,20 +1122,31 @@ func (m *DataHistoryManager) UpsertJob(job *DataHistoryJob, insertOnly bool) err return err } } - job.rangeHolder, err = kline.CalculateCandleDateRanges(job.StartDate, job.EndDate, job.Interval, uint32(job.RequestSizeLimit)) + interval := job.Interval + if job.DataType == dataHistoryConvertCandlesDataType { + interval = job.ConversionInterval + } + job.rangeHolder, err = kline.CalculateCandleDateRanges(job.StartDate, job.EndDate, interval, uint32(job.RequestSizeLimit)) if err != nil { return err } - if !toUpdate { - m.jobs = append(m.jobs, job) - } - dbJob := m.convertJobToDBModel(job) - return m.jobDB.Upsert(dbJob) + err = m.jobDB.Upsert(dbJob) + if err != nil { + return err + } + if job.PrerequisiteJobNickname == "" { + return nil + } + job.Status = dataHistoryStatusPaused + return m.jobDB.SetRelationshipByNickname(job.PrerequisiteJobNickname, job.Nickname, int64(dataHistoryStatusPaused)) } func (m *DataHistoryManager) validateJob(job *DataHistoryJob) error { + if !m.IsRunning() { + return ErrSubSystemNotStarted + } if job == nil { return errNilJob } @@ -570,7 +1162,17 @@ func (m *DataHistoryManager) validateJob(job *DataHistoryJob) error { if !job.DataType.Valid() { return fmt.Errorf("job %s %w: %s", job.Nickname, errInvalidDataHistoryDataType, job.DataType) } - exch := m.exchangeManager.GetExchangeByName(job.Exchange) + exchangeName := job.Exchange + if job.DataType == dataHistoryCandleValidationSecondarySourceType { + if job.SecondaryExchangeSource == "" { + return fmt.Errorf("job %s %w, secondary exchange name required to lookup existing results", job.Nickname, errExchangeNameUnset) + } + exchangeName = job.SecondaryExchangeSource + if job.Exchange == "" { + return fmt.Errorf("job %s %w, exchange name required to lookup existing results", job.Nickname, errExchangeNameUnset) + } + } + exch := m.exchangeManager.GetExchangeByName(exchangeName) if exch == nil { return fmt.Errorf("job %s cannot process job: %s %w", job.Nickname, @@ -598,15 +1200,42 @@ func (m *DataHistoryManager) validateJob(job *DataHistoryJob) error { if job.RequestSizeLimit <= 0 { job.RequestSizeLimit = defaultDataHistoryRequestSizeLimit } - if job.DataType == dataHistoryTradeDataType && - (job.Interval >= kline.FourHour || job.Interval <= kline.TenMin) { - log.Warnf(log.DataHistory, "job %s interval %v outside limits, defaulting to %v", job.Nickname, job.Interval.Word(), defaultDataHistoryTradeInterval) - job.Interval = defaultDataHistoryTradeInterval + if job.DataType == dataHistoryTradeDataType { + if job.Interval > kline.FourHour { + log.Warnf(log.DataHistory, "job %s interval %v above the limit of 4h, defaulting to %v interval size worth of trades to fetch", job.Nickname, job.Interval.Word(), defaultDataHistoryTradeInterval) + job.Interval = defaultDataHistoryTradeInterval + } else if job.Interval < kline.OneMin { + log.Warnf(log.DataHistory, "job %s interval %v below the limit of 1m, defaulting to %v interval size worth of trades to fetch", job.Nickname, job.Interval.Word(), defaultDataHistoryTradeInterval) + job.Interval = defaultDataHistoryTradeInterval + } + if job.RequestSizeLimit > defaultDataHistoryTradeRequestSize { + log.Warnf(log.DataHistory, "job %s interval request size %v outside limit of %v, defaulting to %v intervals worth of trades per request", job.Nickname, job.RequestSizeLimit, defaultDataHistoryTradeRequestSize, defaultDataHistoryTradeRequestSize) + job.RequestSizeLimit = defaultDataHistoryTradeRequestSize + } } b := exch.GetBase() - if !b.Features.Enabled.Kline.Intervals[job.Interval.Word()] { - return fmt.Errorf("job %s %s %w %s", job.Nickname, job.Interval.Word(), kline.ErrUnsupportedInterval, job.Exchange) + if !b.Features.Enabled.Kline.Intervals[job.Interval.Word()] && + (job.DataType == dataHistoryCandleDataType || job.DataType == dataHistoryCandleValidationDataType) { + return fmt.Errorf("job interval %s %s %w %s", job.Nickname, job.Interval.Word(), kline.ErrUnsupportedInterval, job.Exchange) + } + if job.DataType == dataHistoryConvertTradesDataType && job.Interval <= 0 { + return fmt.Errorf("job conversion interval %s %s %w %s", job.Nickname, job.Interval.Word(), kline.ErrUnsupportedInterval, job.Exchange) + } + + if job.DataType == dataHistoryConvertCandlesDataType && job.ConversionInterval <= 0 { + return fmt.Errorf("job conversion interval %s %s %w %s", job.Nickname, job.ConversionInterval.Word(), kline.ErrUnsupportedInterval, job.Exchange) + } + + if job.DataType == dataHistoryCandleValidationDataType { + if job.DecimalPlaceComparison < 0 { + log.Warnf(log.DataHistory, "job %s decimal place comparison %v invalid. defaulting to %v decimal places when comparing data for validation", job.Nickname, job.DecimalPlaceComparison, defaultDecimalPlaceComparison) + job.DecimalPlaceComparison = defaultDecimalPlaceComparison + } + if job.RequestSizeLimit > defaultDataHistoryRequestSizeLimit { + log.Warnf(log.DataHistory, "job %s validation batch %v above limit of %v. defaulting to %v intervals to process per request", job.Nickname, job.RequestSizeLimit, defaultDataHistoryRequestSizeLimit, defaultDataHistoryRequestSizeLimit) + job.RequestSizeLimit = defaultDataHistoryRequestSizeLimit + } } job.StartDate = job.StartDate.Round(job.Interval.Duration()) @@ -629,15 +1258,6 @@ func (m *DataHistoryManager) GetByID(id uuid.UUID) (*DataHistoryJob, error) { if id == uuid.Nil { return nil, errEmptyID } - m.m.Lock() - for i := range m.jobs { - if m.jobs[i].ID == id { - cpy := *m.jobs[i] - m.m.Unlock() - return &cpy, nil - } - } - m.m.Unlock() dbJ, err := m.jobDB.GetByID(id.String()) if err != nil { return nil, fmt.Errorf("%w with id %s %s", errJobNotFound, id, err) @@ -670,16 +1290,6 @@ func (m *DataHistoryManager) GetByNickname(nickname string, fullDetails bool) (* } return result, nil } - m.m.Lock() - for i := range m.jobs { - if strings.EqualFold(m.jobs[i].Nickname, nickname) { - cpy := m.jobs[i] - m.m.Unlock() - return cpy, nil - } - } - m.m.Unlock() - // now try the database j, err := m.jobDB.GetByNickName(nickname) if err != nil { if err == sql.ErrNoRows { @@ -722,8 +1332,8 @@ func (m *DataHistoryManager) GetAllJobStatusBetween(start, end time.Time) ([]*Da return results, nil } -// DeleteJob helper function to assist in setting a job to deleted -func (m *DataHistoryManager) DeleteJob(nickname, id string) error { +// SetJobStatus helper function to assist in setting a job to deleted +func (m *DataHistoryManager) SetJobStatus(nickname, id string, status dataHistoryStatus) error { if m == nil { return ErrNilSubsystem } @@ -736,41 +1346,46 @@ func (m *DataHistoryManager) DeleteJob(nickname, id string) error { if nickname != "" && id != "" { return errOnlyNicknameOrID } + if status != dataHistoryStatusPaused && + status != dataHistoryStatusRemoved && + status != dataHistoryStatusActive { + return fmt.Errorf("%w received: %s, can only pause, unpause or delete jobs", errBadStatus, status.String()) + } var dbJob *datahistoryjob.DataHistoryJob var err error - m.m.Lock() - defer m.m.Unlock() - for i := range m.jobs { - if strings.EqualFold(m.jobs[i].Nickname, nickname) || - m.jobs[i].ID.String() == id { - dbJob = m.convertJobToDBModel(m.jobs[i]) - m.jobs = append(m.jobs[:i], m.jobs[i+1:]...) - break + if nickname != "" { + dbJob, err = m.jobDB.GetByNickName(nickname) + if err != nil { + return err } - } - if dbJob == nil { - if nickname != "" { - dbJob, err = m.jobDB.GetByNickName(nickname) - if err != nil { - return err - } - } else { - dbJob, err = m.jobDB.GetByID(id) - if err != nil { - return err - } + } else { + dbJob, err = m.jobDB.GetByID(id) + if err != nil { + return err } } - if dbJob.Status != int64(dataHistoryStatusActive) { - status := dataHistoryStatus(dbJob.Status) - return fmt.Errorf("job: %v status: %s error: %w", dbJob.Nickname, status, errCanOnlyDeleteActiveJobs) + if dbJob.Status == int64(status) { + return fmt.Errorf("%w job %v, status already set to %v", errBadStatus, dbJob.Nickname, dataHistoryStatus(dbJob.Status)) } - dbJob.Status = int64(dataHistoryStatusRemoved) + switch dataHistoryStatus(dbJob.Status) { + case dataHistoryStatusActive: + if status != dataHistoryStatusRemoved && status != dataHistoryStatusPaused { + return fmt.Errorf("%w job %v", errBadStatus, dataHistoryStatus(dbJob.Status)) + } + case dataHistoryStatusPaused: + if status != dataHistoryStatusRemoved && status != dataHistoryStatusActive { + return fmt.Errorf("%w job %v", errBadStatus, dataHistoryStatus(dbJob.Status)) + } + default: + return fmt.Errorf("%w job %v, invalid status", errBadStatus, dataHistoryStatus(dbJob.Status)) + } + + dbJob.Status = int64(status) err = m.jobDB.Upsert(dbJob) if err != nil { return err } - log.Infof(log.DataHistory, "deleted job %v", dbJob.Nickname) + log.Infof(log.DataHistory, "set job %v status to %v", dbJob.Nickname, status.String()) return nil } @@ -783,12 +1398,21 @@ func (m *DataHistoryManager) GetActiveJobs() ([]DataHistoryJob, error) { return nil, ErrSubSystemNotStarted } - m.m.Lock() - defer m.m.Unlock() var results []DataHistoryJob - for i := range m.jobs { - if m.jobs[i].Status == dataHistoryStatusActive { - results = append(results, *m.jobs[i]) + jobs, err := m.jobDB.GetAllIncompleteJobsAndResults() + if err != nil { + return nil, err + } + for i := range jobs { + if jobs[i].Status == int64(dataHistoryStatusActive) { + var job *DataHistoryJob + job, err = m.convertDBModelToJob(&jobs[i]) + if err != nil { + return nil, err + } + if job != nil { + results = append(results, *job) + } } } return results, nil @@ -799,6 +1423,9 @@ func (m *DataHistoryManager) GenerateJobSummary(nickname string) (*DataHistoryJo if m == nil { return nil, ErrNilSubsystem } + if !m.IsRunning() { + return nil, ErrSubSystemNotStarted + } job, err := m.GetByNickname(nickname, false) if err != nil { return nil, fmt.Errorf("job: %v %w", nickname, err) @@ -825,6 +1452,9 @@ func (m *DataHistoryManager) GenerateJobSummary(nickname string) (*DataHistoryJo // ----------------------------Lovely-converters---------------------------- func (m *DataHistoryManager) convertDBModelToJob(dbModel *datahistoryjob.DataHistoryJob) (*DataHistoryJob, error) { + if !m.IsRunning() { + return nil, ErrSubSystemNotStarted + } id, err := uuid.FromString(dbModel.ID) if err != nil { return nil, err @@ -833,32 +1463,50 @@ func (m *DataHistoryManager) convertDBModelToJob(dbModel *datahistoryjob.DataHis if err != nil { return nil, fmt.Errorf("job %s could not format pair %s-%s: %w", dbModel.Nickname, dbModel.Base, dbModel.Quote, err) } - jobResults, err := m.convertDBResultToJobResult(dbModel.Results) if err != nil { return nil, fmt.Errorf("job %s could not convert database job: %w", dbModel.Nickname, err) } - return &DataHistoryJob{ - ID: id, - Nickname: dbModel.Nickname, - Exchange: dbModel.ExchangeName, - Asset: asset.Item(dbModel.Asset), - Pair: cp, - StartDate: dbModel.StartDate, - EndDate: dbModel.EndDate, - Interval: kline.Interval(dbModel.Interval), - RunBatchLimit: dbModel.BatchSize, - RequestSizeLimit: dbModel.RequestSizeLimit, - DataType: dataHistoryDataType(dbModel.DataType), - MaxRetryAttempts: dbModel.MaxRetryAttempts, - Status: dataHistoryStatus(dbModel.Status), - CreatedDate: dbModel.CreatedDate, - Results: jobResults, - }, nil + resp := &DataHistoryJob{ + ID: id, + Nickname: dbModel.Nickname, + Exchange: dbModel.ExchangeName, + Asset: asset.Item(dbModel.Asset), + Pair: cp, + StartDate: dbModel.StartDate, + EndDate: dbModel.EndDate, + Interval: kline.Interval(dbModel.Interval), + RunBatchLimit: dbModel.BatchSize, + RequestSizeLimit: dbModel.RequestSizeLimit, + DataType: dataHistoryDataType(dbModel.DataType), + MaxRetryAttempts: dbModel.MaxRetryAttempts, + Status: dataHistoryStatus(dbModel.Status), + CreatedDate: dbModel.CreatedDate, + Results: jobResults, + OverwriteExistingData: dbModel.OverwriteData, + ConversionInterval: kline.Interval(dbModel.ConversionInterval), + DecimalPlaceComparison: dbModel.DecimalPlaceComparison, + SecondaryExchangeSource: dbModel.SecondarySourceExchangeName, + IssueTolerancePercentage: dbModel.IssueTolerancePercentage, + ReplaceOnIssue: dbModel.ReplaceOnIssue, + PrerequisiteJobNickname: dbModel.PrerequisiteJobNickname, + } + if resp.PrerequisiteJobNickname != "" { + prereqID, err := uuid.FromString(dbModel.PrerequisiteJobID) + if err != nil { + return nil, err + } + resp.PrerequisiteJobID = prereqID + } + + return resp, nil } func (m *DataHistoryManager) convertDBResultToJobResult(dbModels []*datahistoryjobresult.DataHistoryJobResult) (map[time.Time][]DataHistoryJobResult, error) { + if !m.IsRunning() { + return nil, ErrSubSystemNotStarted + } result := make(map[time.Time][]DataHistoryJobResult) for i := range dbModels { id, err := uuid.FromString(dbModels[i].ID) @@ -906,25 +1554,35 @@ func (m *DataHistoryManager) convertJobResultToDBResult(results map[time.Time][] func (m *DataHistoryManager) convertJobToDBModel(job *DataHistoryJob) *datahistoryjob.DataHistoryJob { model := &datahistoryjob.DataHistoryJob{ - Nickname: job.Nickname, - ExchangeName: job.Exchange, - Asset: job.Asset.String(), - Base: job.Pair.Base.String(), - Quote: job.Pair.Quote.String(), - StartDate: job.StartDate, - EndDate: job.EndDate, - Interval: int64(job.Interval.Duration()), - RequestSizeLimit: job.RequestSizeLimit, - DataType: int64(job.DataType), - MaxRetryAttempts: job.MaxRetryAttempts, - Status: int64(job.Status), - CreatedDate: job.CreatedDate, - BatchSize: job.RunBatchLimit, - Results: m.convertJobResultToDBResult(job.Results), + Nickname: job.Nickname, + ExchangeName: job.Exchange, + Asset: job.Asset.String(), + Base: job.Pair.Base.String(), + Quote: job.Pair.Quote.String(), + StartDate: job.StartDate, + EndDate: job.EndDate, + Interval: int64(job.Interval.Duration()), + RequestSizeLimit: job.RequestSizeLimit, + DataType: int64(job.DataType), + MaxRetryAttempts: job.MaxRetryAttempts, + BatchSize: job.RunBatchLimit, + Status: int64(job.Status), + CreatedDate: job.CreatedDate, + Results: m.convertJobResultToDBResult(job.Results), + PrerequisiteJobNickname: job.PrerequisiteJobNickname, + ConversionInterval: int64(job.ConversionInterval), + OverwriteData: job.OverwriteExistingData, + DecimalPlaceComparison: job.DecimalPlaceComparison, + SecondarySourceExchangeName: job.SecondaryExchangeSource, + IssueTolerancePercentage: job.IssueTolerancePercentage, + ReplaceOnIssue: job.ReplaceOnIssue, } if job.ID != uuid.Nil { model.ID = job.ID.String() } + if job.PrerequisiteJobID != uuid.Nil { + model.PrerequisiteJobID = job.PrerequisiteJobID.String() + } return model } diff --git a/engine/datahistory_manager.md b/engine/datahistory_manager.md index 1026a4dfa05..22aba35e054 100644 --- a/engine/datahistory_manager.md +++ b/engine/datahistory_manager.md @@ -18,7 +18,7 @@ You can track ideas, planned features and what's in progress on this Trello boar Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTc5ZDE1ZTNiOGM3ZGMyMmY1NTAxYWZhODE0MWM5N2JlZDk1NDU0YTViYzk4NTk3OTRiMDQzNGQ1YTc4YmRlMTk) -## Current Features for Datahistory manager +## What is the data history manager? + The data history manager is an engine subsystem responsible for ensuring that the candle/trade history in the range you define is synchronised to your database + It is a long running synchronisation task designed to not overwhelm resources and ensure that all data requested is accounted for and saved to the database + The data history manager is disabled by default and requires a database connection to function @@ -29,7 +29,19 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader + Jobs will fetch data at sizes you request (which can cater to hardware limitations such as low RAM) + Jobs are completed once all data has been fetched/attempted to be fetched in the time range -## What are the prerequisites? +## Current Features for the data history manager ++ Retrieval and storage of exchange API candle data ++ Retrieval and storage of exchange API trade data ++ Conversion of stored trade data into custom candle data ++ Conversion of stored candle data into custom candle data ++ Validation of stored candle data against exchange API data + + Optionally can replace data when an issue is found on a customisable threshold ++ Validation of stored candle data against a secondary exchange's API data ++ Pausing and unpause jobs ++ Queue jobs via prerequisite jobs ++ GRPC command support for creating/modifying/checking jobs + +## What are the requirements for the data history manager? + Ensure you have a database setup, you can read about that [here](/database) + Ensure you have run dbmigrate under `/cmd/dbmigrate` via `dbmigrate -command=up`, you can read about that [here](/database#create-and-run-migrations) + Ensure you have seeded exchanges to the database via the application dbseed under `/cmd/dbseed`, you can read about it [here](/cmd/dbseed) @@ -38,9 +50,28 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader + Read below on how to enable the data history manager and add data history jobs ## What is a data history job? -A job is a set of parameters which will allow GoCryptoTrader to periodically retrieve historical data. Its purpose is to break up the process of retrieving large sets of data for multiple currencies and exchanges into more manageable chunks in a "set and forget" style. +A job is a set of parameters which will allow GoCryptoTrader to periodically retrieve, convert or validate historical data. Its purpose is to break up the process of retrieving large sets of data for multiple currencies and exchanges into more manageable chunks in a "set and forget" style. For a breakdown of what a job consists of and what each parameter does, please review the database tables and the cycle details below. +### What kind of data jobs are there? +A breakdown of each type is under the Add Jobs command list below + +### What are the different job status types? + +| Job Status | Description | Representative value | +| ---------- | ----------- | -------------------- | +| active | A job that is ready to processed | 0 | +| failed | The job has failed to retrieve/covert/validate the data you have specified. See the associated data history job results to understand why | 1 | +| complete | The job has successfully retrieved/converted/validated all data you have specified | 2 | +| removed | The job has been deleted. No data is removed, but the job can no longer be processed | 3 | +| missing data | The job is complete, however there is some missing data. See the associated data history job results to understand why | 4 | +| paused | The job has been paused and will not be processed. Either it has a prerequisite job that needs to be completed, or a user must unpause the job | 5 | + +### How do I add a job? ++ First ensure that the data history monitor is enabled, you can do this via the config (see table `dataHistoryManager` under Config parameters below), via run time parameter (see table Application run time parameters below) or via the RPC command `enablesubsystem --subsystemname="data_history_manager"` ++ The simplest way of adding a new data history job is via the GCTCLI under `/cmd/gctcli`. + + Modify the following example command to your needs: `.\gctcli.exe datahistory addjob savecandles --nickname=binance-spot-bnb-btc-1h-candles --exchange=binance --asset=spot --pair=BNB-BTC --interval=3600 --start_date="2020-06-02 12:00:00" --end_date="2020-12-02 12:00:00" --request_size_limit=10 --max_retry_attempts=3 --batch_size=3` + ## What happens during a data history cycle? + Once the checkInterval ticker timer has finished, the data history manager will process all jobs considered `active`. + A job's start and end time is broken down into intervals defined by the `interval` variable of a job. For a job beginning `2020-01-01` to `2020-01-02` with an interval of one hour will create 24 chunks to retrieve @@ -53,45 +84,75 @@ For a breakdown of what a job consists of and what each parameter does, please r + The errors for retrieval failures are stored in the database, allowing you to understand why a certain chunk of time is unavailable (eg exchange downtime and missing data) + All results are saved to the database, the data history manager will analyse all results and ready jobs for the next round of processing -## How do I add one? -+ First ensure that the data history monitor is enabled, you can do this via the config (see table `dataHistoryManager` under Config parameters below), via run time parameter (see table Application run time parameters below) or via the RPC command `enablesubsystem --subsystemname="data_history_manager"` -+ The simplest way of adding a new data history job is via the GCTCLI under `/cmd/gctcli`. - + Modify the following example command to your needs: `.\gctcli.exe datahistory upsertjob --nickname=binance-spot-bnb-btc-1h-candles --exchange=binance --asset=spot --pair=BNB-BTC --interval=3600 --start_date="2020-06-02 12:00:00" --end_date="2020-12-02 12:00:00" --request_size_limit=10 --data_type=0 --max_retry_attempts=3 --batch_size=3` - ### Candle intervals and trade fetching + A candle interval is required for a job, even when fetching trade data. This is to appropriately break down requests into time interval chunks. However, it is restricted to only a small range of times. This is to prevent fetching issues as fetching trades over a period of days or weeks will take a significant amount of time. When setting a job to fetch trades, the allowable range is less than 4 hours and greater than 10 minutes. -### Application run time parameters +## Job queuing and prerequisite jobs +You can add jobs which will be paused by default by using the `prerequisite` subcommand containing the associated job nickname. The prerequisite job will be checked to ensure it exists and has not yet completed and add the relationship. ++ Once you have set a prerequisite job, when the prerequisite job status is set to `complete`, the data history manager will search for any jobs which are pending its completion and update their status to `active`. ++ If the prerequisite job is deleted or fails, the upcoming job will _not_ be run. ++ Multiple jobs can use the same prerequisite job, but a job cannot have multiple prerequisites + + Attempting to add a new prerequisite will overwrite the existing prerequisite ++ You can chain many queued jobs together allowing for automated and large scale data retrieval projects. For example: + +| Job Type | Job Name | Description | Prerequisite Job | +| -------- | -------- | ----------- | ---------------- | +| savetrades | save-trades | Save jobs between 01-01-2021 and 01-02-2021 | | +| converttrades | convert-trades | Convert trades to 5m candles | save-trades | +| validatecandles | validate-candles | Ensure the converted trades match the exchange's API data | convert-trades | +| convertcandles | convert-candles-10m | Now that we have confidence in conversion, convert candle to 10m | validate-candles | +| convertcandles | convert-candles-25m | Now that we have confidence in conversion, convert candle to 25m | validate-candles | +| convertcandles | convert-candles-1d | Now that we have confidence in conversion, convert candle to 1d | validate-candles | + +## Application run time parameters | Parameter | Description | Example | | ------ | ----------- | ------- | | datahistorymanager | A boolean value which determines if the data history manager is enabled. Defaults to `false` | `-datahistorymanager=true` | -### Config parameters -#### dataHistoryManager +## Config parameters +### dataHistoryManager | Config | Description | Example | | ------ | ----------- | ------- | | enabled | If enabled will run the data history manager on startup | `true` | | checkInterval | A golang `time.Duration` interval of when to attempt to fetch all active jobs' data | `15000000000` | | maxJobsPerCycle | Allows you to control how many jobs are processed after the `checkInterval` timer finishes. Useful if you have many jobs, but don't wish to constantly be retrieving data | `5` | +| maxResultInsertions | When saving candle/trade results, loop it in batches of this number. | `10000` | | verbose | Displays some extra logs to your logging output to help debug | `false` | -### RPC commands +## RPC commands The below table is a summary of commands. For more details, view the commands in `/cmd/gctcli` or `/gctrpc/rpc.swagger.json` | Command | Description | | ------ | ----------- | -| UpsertDataHistoryJob | Updates or Inserts a job to the manager and database | +| AddJob | Shows a list of subcommands to add a new job type, detailed in the next table | | GetDataHistoryJobDetails | Returns a job's details via its nickname or ID. Can optionally return an array of all run results | | GetActiveDataHistoryJobs | Will return all jobs that have an `active` status | | DeleteJob | Will remove a job for processing. Data is preserved in the database for later reference | | GetDataHistoryJobsBetween | Returns all jobs, of all status types between the dates provided | | GetDataHistoryJobSummary | Will return an executive summary of the progress of your job by nickname | +| PauseDataHistoryJob | Will set a job's status to paused | +| UnpauseDataHistoryJob | Will se a job's status to `active` | + +### AddJob commands + +| Command | Description | DataHistoryJobDataType | +| ------- | ----------- | ---------------------- | +| savecandles | Will fetch candle data from an exchange and save it to the database | 0 | +| savetrades | Will fetch trade data from an exchange and save it to the database | 1 | +| converttrades | Convert trades saved to the database to any candle resolution eg 30min | 2 | +| convertcandles | Convert candles saved to the database to a new resolution eg 1min -> 5min | 3 | +| validatecandles | Will compare database candle data with API candle data - useful for validating converted trades and candles | 4 | +| secondaryvalidatecandles | Will compare database candle data with a different exchange's API candle data | 5 | + -### Database tables -#### datahistoryjob +## Database tables +The following is a screenshot of the relationship between relevant data history job tables +![image](https://user-images.githubusercontent.com/9261323/125889821-954b730a-01fd-4eb0-839d-3cc623178f20.png) + +### datahistoryjob | Field | Description | Example | | ------ | ----------- | ------- | @@ -104,14 +165,20 @@ The below table is a summary of commands. For more details, view the commands in | start_time | When to begin fetching data | `01-01-2017T13:33:37Z` | | end_time | When to finish fetching data | `01-01-2018T13:33:37Z` | | interval | A golang `time.Duration` representation of the candle interval to use. | `30000000000` | -| data_type | The data type to fetch. `0` is candles and `1` is trades | `0` | +| data_type | The data type to fetch. See job types in table `AddJob commands` above | `0` | | request_size | The number of candles to fetch. eg if `500`, the data history manager will break up the request into the appropriate timeframe to ensure the data history run interval will fetch 500 candles to save to the database | `500` | | max_retries | For an interval period, the amount of attempts the data history manager is allowed to attempt to fetch data before moving onto the next period. This can be useful for determining whether the exchange is missing the data in that time period or, if just one failure of three, just means that the data history manager couldn't finish one request | `3` | | batch_count | The number of requests to make when processing a job | `3` | -| status | A numerical representation for the status. `0` is active, `1` is failed `2` is complete, `3` is removed and `4` is missing data | `0` | +| status | A numerical representation for the status. See data history job status subsection | `0` | | created | The date the job was created. | `2020-01-01T13:33:37Z` | +| conversion_interval | When converting data as a job, this determines the resulting interval | `86400000000000` | +| overwrite_data | If data already exists, the setting allows you to overwrite it | `true` | +| secondary_exchange_id | For a `secondaryvalidatecandles` job, the exchange id of the exchange to compare data to. | `ftx` | +| decimal_place_comparison | When validating API candles, this will round the data to the supplied decimal point to check for equality | `3` | +| replace_on_issue | When there is an issue validating candles for a `validatecandles` job, the API data will overwrite the existing candle data | `false` | + +### datahistoryjobresult -#### datahistoryjobresult | Field | Description | Example | | ------ | ----------- | ------- | | id | Unique ID of the job status | `deadbeef-dead-beef-dead-beef13371337` | @@ -122,6 +189,24 @@ The below table is a summary of commands. For more details, view the commands in | interval_end_time | The end date of the period fetched | `2020-01-02T13:33:37Z` | | run_time | The time the job was ran | `2020-01-03T13:33:37Z` | +### datahistoryjobrelations + +| Field | Description | Example | +| ------ | ----------- | ------- | +| prerequisite_job_id | The job that must be completed before `job_id` can be run | `deadbeef-dead-beef-dead-beef13371337` | +| job_id | The job that will be run after `prerequisite_job_id` completes | `deadbeef-dead-beef-dead-beef13371337` | + +### candle +The candle table also has relationships to data history jobs. Only the relevant columns are listed below: + +| Field | Description | Example | +| ------ | ----------- | ------- | +| source_job_id | The source job id for where the candle data came from. | `deadbeef-dead-beef-dead-beef13371337` | +| validation_job_id | When job id for what job validated the candle data | `deadbeef-dead-beef-dead-beef13371337` | +| validation_issues | If any discrepancies are found, the data will be written to the column | `issues found at 2020-07-08 00:00:00, Open api: 9262.62 db: 9262.69 diff: 3%, replacing database candle data with API data` | + + + ### Please click GoDocs chevron above to view current GoDoc information for this package ## Contribution diff --git a/engine/datahistory_manager_test.go b/engine/datahistory_manager_test.go index 216810127e3..82025bc6cd2 100644 --- a/engine/datahistory_manager_test.go +++ b/engine/datahistory_manager_test.go @@ -16,8 +16,11 @@ import ( "github.com/thrasher-corp/gocryptotrader/database" "github.com/thrasher-corp/gocryptotrader/database/repository/datahistoryjob" "github.com/thrasher-corp/gocryptotrader/database/repository/datahistoryjobresult" + exchange "github.com/thrasher-corp/gocryptotrader/exchanges" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" "github.com/thrasher-corp/gocryptotrader/exchanges/kline" + "github.com/thrasher-corp/gocryptotrader/exchanges/order" + "github.com/thrasher-corp/gocryptotrader/exchanges/trade" ) func TestSetupDataHistoryManager(t *testing.T) { @@ -67,7 +70,7 @@ func TestSetupDataHistoryManager(t *testing.T) { func TestDataHistoryManagerIsRunning(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) m.started = 0 if m.IsRunning() { t.Error("expected false") @@ -84,7 +87,7 @@ func TestDataHistoryManagerIsRunning(t *testing.T) { func TestDataHistoryManagerStart(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) m.started = 0 err := m.Start() if !errors.Is(err, nil) { @@ -104,7 +107,7 @@ func TestDataHistoryManagerStart(t *testing.T) { func TestDataHistoryManagerStop(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) m.shutdown = make(chan struct{}) err := m.Stop() if !errors.Is(err, nil) { @@ -123,7 +126,7 @@ func TestDataHistoryManagerStop(t *testing.T) { func TestUpsertJob(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) err := m.UpsertJob(nil, false) if !errors.Is(err, errNilJob) { t.Errorf("error '%v', expected '%v'", err, errNilJob) @@ -146,7 +149,7 @@ func TestUpsertJob(t *testing.T) { } dhj.Exchange = strings.ToLower(testExchange) - dhj.Pair = currency.NewPair(currency.BTC, currency.USDT) + dhj.Pair = currency.NewPair(currency.BTC, currency.DOGE) err = m.UpsertJob(dhj, false) if !errors.Is(err, errCurrencyNotEnabled) { t.Errorf("error '%v', expected '%v'", err, errCurrencyNotEnabled) @@ -170,27 +173,30 @@ func TestUpsertJob(t *testing.T) { if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) } - if len(m.jobs) != 1 { - t.Error("unexpected jerrb") - } - err = m.UpsertJob(dhj, true) if !errors.Is(err, errNicknameInUse) { t.Errorf("error '%v', expected '%v'", err, errNicknameInUse) } newJob := &DataHistoryJob{ - Nickname: dhj.Nickname, - Exchange: testExchange, - Asset: asset.Spot, - Pair: currency.NewPair(currency.BTC, currency.USD), - StartDate: startDate, - EndDate: time.Now().Add(-time.Minute), - Interval: kline.FifteenMin, - RunBatchLimit: 1338, - RequestSizeLimit: 1337, - DataType: 2, - MaxRetryAttempts: 1337, + Nickname: dhj.Nickname, + Exchange: testExchange, + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USD), + StartDate: startDate, + EndDate: time.Now().Add(-time.Minute), + Interval: kline.FifteenMin, + RunBatchLimit: 1338, + RequestSizeLimit: 1337, + DataType: 99, + MaxRetryAttempts: 1337, + OverwriteExistingData: true, + ConversionInterval: 3, + DecimalPlaceComparison: 5, + SecondaryExchangeSource: testExchange, + IssueTolerancePercentage: 3, + ReplaceOnIssue: true, + PrerequisiteJobNickname: "hellomoto", } err = m.UpsertJob(newJob, false) if !errors.Is(err, errInvalidDataHistoryDataType) { @@ -202,16 +208,13 @@ func TestUpsertJob(t *testing.T) { if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) } - if !m.jobs[0].StartDate.Equal(startDate) { - t.Error(err) - } } -func TestDeleteJob(t *testing.T) { +func TestSetJobStatus(t *testing.T) { t.Parallel() - m := createDHM(t) + m, j := createDHM(t) dhj := &DataHistoryJob{ - Nickname: "TestDeleteJob", + Nickname: "TestSetJobStatus", Exchange: testExchange, Asset: asset.Spot, Pair: currency.NewPair(currency.BTC, currency.USD), @@ -224,36 +227,62 @@ func TestDeleteJob(t *testing.T) { t.Errorf("error '%v', expected '%v'", err, nil) } - err = m.DeleteJob("", "") + err = m.SetJobStatus("", "", 0) if !errors.Is(err, errNicknameIDUnset) { t.Errorf("error '%v', expected '%v'", err, errNicknameIDUnset) } - err = m.DeleteJob("1337", "1337") + err = m.SetJobStatus("1337", "1337", 0) if !errors.Is(err, errOnlyNicknameOrID) { t.Errorf("error '%v', expected '%v'", err, errOnlyNicknameOrID) } - err = m.DeleteJob(dhj.Nickname, "") + err = m.SetJobStatus(dhj.Nickname, "", dataHistoryStatusRemoved) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + err = m.SetJobStatus("", dhj.ID.String(), dataHistoryStatusActive) + if !errors.Is(err, errBadStatus) { + t.Errorf("error '%v', expected '%v'", err, errBadStatus) + } + + j.Status = int64(dataHistoryStatusActive) + err = m.SetJobStatus("", dhj.ID.String(), dataHistoryStatusPaused) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + + err = m.SetJobStatus("", dhj.ID.String(), dataHistoryStatusFailed) + if !errors.Is(err, errBadStatus) { + t.Errorf("error '%v', expected '%v'", err, errBadStatus) + } + + dhj.Status = dataHistoryStatusPaused + err = m.SetJobStatus(dhj.Nickname, "", dataHistoryStatusActive) if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) } - if len(m.jobs) != 0 { - t.Error("expected 0") + + dhj.Status = dataHistoryStatusRemoved + err = m.SetJobStatus(dhj.Nickname, "", dataHistoryStatusActive) + if !errors.Is(err, errBadStatus) { + t.Errorf("error '%v', expected '%v'", err, errBadStatus) } - err = m.DeleteJob("", dhj.ID.String()) + + dhj.Status = dataHistoryStatusPaused + err = m.SetJobStatus(dhj.Nickname, "", dataHistoryStatusRemoved) if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) } atomic.StoreInt32(&m.started, 0) - err = m.DeleteJob("", dhj.ID.String()) + err = m.SetJobStatus("", dhj.ID.String(), 0) if !errors.Is(err, ErrSubSystemNotStarted) { t.Errorf("error '%v', expected '%v'", err, ErrSubSystemNotStarted) } m = nil - err = m.DeleteJob("", dhj.ID.String()) + err = m.SetJobStatus("", dhj.ID.String(), 0) if !errors.Is(err, ErrNilSubsystem) { t.Errorf("error '%v', expected '%v'", err, ErrNilSubsystem) } @@ -261,7 +290,7 @@ func TestDeleteJob(t *testing.T) { func TestGetByNickname(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) dhj := &DataHistoryJob{ Nickname: "TestGetByNickname", Exchange: testExchange, @@ -284,7 +313,6 @@ func TestGetByNickname(t *testing.T) { t.Errorf("error '%v', expected '%v'", err, nil) } - m.jobs = []*DataHistoryJob{} _, err = m.GetByNickname(dhj.Nickname, false) if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) @@ -305,7 +333,7 @@ func TestGetByNickname(t *testing.T) { func TestGetByID(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) dhj := &DataHistoryJob{ Nickname: "TestGetByID", Exchange: testExchange, @@ -329,7 +357,6 @@ func TestGetByID(t *testing.T) { t.Errorf("error '%v', expected '%v'", err, errEmptyID) } - m.jobs = []*DataHistoryJob{} _, err = m.GetByID(dhj.ID) if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) @@ -350,7 +377,7 @@ func TestGetByID(t *testing.T) { func TestRetrieveJobs(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) dhj := &DataHistoryJob{ Nickname: "TestRetrieveJobs", Exchange: testExchange, @@ -388,15 +415,7 @@ func TestRetrieveJobs(t *testing.T) { func TestGetActiveJobs(t *testing.T) { t.Parallel() - m := createDHM(t) - - jobs, err := m.GetActiveJobs() - if !errors.Is(err, nil) { - t.Errorf("error '%v', expected '%v'", err, nil) - } - if len(jobs) != 0 { - t.Error("expected 0 jobs") - } + m, j := createDHM(t) dhj := &DataHistoryJob{ Nickname: "TestGetActiveJobs", @@ -407,12 +426,12 @@ func TestGetActiveJobs(t *testing.T) { EndDate: time.Now(), Interval: kline.OneMin, } - err = m.UpsertJob(dhj, false) + err := m.UpsertJob(dhj, false) if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) } - jobs, err = m.GetActiveJobs() + jobs, err := m.GetActiveJobs() if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) } @@ -420,7 +439,7 @@ func TestGetActiveJobs(t *testing.T) { t.Error("expected 1 job") } - dhj.Status = dataHistoryStatusFailed + j.Status = int64(dataHistoryStatusFailed) jobs, err = m.GetActiveJobs() if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) @@ -444,7 +463,7 @@ func TestGetActiveJobs(t *testing.T) { func TestValidateJob(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) err := m.validateJob(nil) if !errors.Is(err, errNilJob) { t.Errorf("error '%v', expected '%v'", err, errNilJob) @@ -462,7 +481,7 @@ func TestValidateJob(t *testing.T) { } dhj.Exchange = testExchange - dhj.Pair = currency.NewPair(currency.BTC, currency.USDT) + dhj.Pair = currency.NewPair(currency.BTC, currency.XRP) err = m.validateJob(dhj) if !errors.Is(err, errCurrencyNotEnabled) { t.Errorf("error '%v', expected '%v'", err, errCurrencyNotEnabled) @@ -487,17 +506,42 @@ func TestValidateJob(t *testing.T) { t.Errorf("error '%v', expected '%v'", err, errInvalidTimes) } - dhj.StartDate = time.Now().Add(-time.Hour) + dhj.StartDate = time.Now().Add(-time.Hour * 60) dhj.EndDate = time.Now().Add(-time.Minute) err = m.validateJob(dhj) if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) } + + dhj.DataType = dataHistoryCandleValidationDataType + dhj.Interval = kline.OneDay + dhj.RequestSizeLimit = 999 + err = m.validateJob(dhj) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + dhj.DataType = dataHistoryTradeDataType + err = m.validateJob(dhj) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + + dhj.DataType = dataHistoryCandleValidationSecondarySourceType + err = m.validateJob(dhj) + if !errors.Is(err, errExchangeNameUnset) { + t.Errorf("error '%v', expected '%v'", err, errExchangeNameUnset) + } + dhj.SecondaryExchangeSource = "lol" + dhj.Exchange = "" + err = m.validateJob(dhj) + if !errors.Is(err, errExchangeNameUnset) { + t.Errorf("error '%v', expected '%v'", err, errExchangeNameUnset) + } } func TestGetAllJobStatusBetween(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) dhj := &DataHistoryJob{ Nickname: "TestGetActiveJobs", @@ -541,7 +585,7 @@ func TestGetAllJobStatusBetween(t *testing.T) { func TestPrepareJobs(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) jobs, err := m.PrepareJobs() if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) @@ -563,15 +607,16 @@ func TestPrepareJobs(t *testing.T) { func TestCompareJobsToData(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) dhj := &DataHistoryJob{ - Nickname: "TestGenerateJobSummary", - Exchange: testExchange, - Asset: asset.Spot, - Pair: currency.NewPair(currency.BTC, currency.USD), - StartDate: time.Now().Add(-time.Minute * 5), - EndDate: time.Now(), - Interval: kline.OneMin, + Nickname: "TestGenerateJobSummary", + Exchange: testExchange, + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USD), + StartDate: time.Now().Add(-time.Minute * 5), + EndDate: time.Now(), + Interval: kline.OneMin, + ConversionInterval: kline.FiveMin, } err := m.compareJobsToData(dhj) if !errors.Is(err, nil) { @@ -589,6 +634,13 @@ func TestCompareJobsToData(t *testing.T) { if !errors.Is(err, errUnknownDataType) { t.Errorf("error '%v', expected '%v'", err, errUnknownDataType) } + + dhj.DataType = dataHistoryConvertCandlesDataType + err = m.compareJobsToData(dhj) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + m.started = 0 err = m.compareJobsToData(dhj) if !errors.Is(err, ErrSubSystemNotStarted) { @@ -602,74 +654,135 @@ func TestCompareJobsToData(t *testing.T) { } func TestRunJob(t *testing.T) { - t.Parallel() - m := createDHM(t) - dhj := &DataHistoryJob{ - Nickname: "TestProcessJobs", - Exchange: "Binance", - Asset: asset.Spot, - Pair: currency.NewPair(currency.BTC, currency.USDT), - StartDate: time.Now().Add(-time.Hour * 2), - EndDate: time.Now(), - Interval: kline.OneHour, - } - err := m.UpsertJob(dhj, false) - if !errors.Is(err, nil) { - t.Errorf("error '%v', expected '%v'", err, nil) - } - - err = m.runJob(dhj) - if !errors.Is(err, nil) { - t.Errorf("error '%v', expected '%v'", err, nil) - } - - dhj.Pair = currency.NewPair(currency.DOGE, currency.USDT) - err = m.runJob(dhj) - if !errors.Is(err, nil) { - t.Errorf("error '%v', expected '%v'", err, nil) - } - - dhjt := &DataHistoryJob{ - Nickname: "TestProcessJobs2", - Exchange: "Binance", - Asset: asset.Spot, - Pair: currency.NewPair(currency.BTC, currency.USDT), - StartDate: time.Now().Add(-time.Hour * 5), - EndDate: time.Now(), - Interval: kline.OneHour, - DataType: dataHistoryTradeDataType, - } - err = m.UpsertJob(dhjt, false) - if !errors.Is(err, nil) { - t.Errorf("error '%v', expected '%v'", err, nil) - } - - err = m.compareJobsToData(dhjt) - if !errors.Is(err, nil) { - t.Errorf("error '%v', expected '%v'", err, nil) - } - - err = m.runJob(dhjt) - if !errors.Is(err, nil) { - t.Errorf("error '%v', expected '%v'", err, nil) - } - - atomic.StoreInt32(&m.started, 0) - err = m.runJob(dhjt) - if !errors.Is(err, ErrSubSystemNotStarted) { - t.Errorf("error '%v', expected '%v'", err, ErrSubSystemNotStarted) + testCases := []*DataHistoryJob{ + { + Nickname: "TestRunJobDataHistoryCandleDataType", + Exchange: "Binance", + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-time.Minute * 30), + EndDate: time.Now(), + Interval: kline.FifteenMin, + DataType: dataHistoryCandleDataType, + }, + { + Nickname: "TestRunJobDataHistoryTradeDataType", + Exchange: "Binance", + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-time.Minute * 15), + EndDate: time.Now(), + Interval: kline.OneMin, + DataType: dataHistoryTradeDataType, + }, + { + Nickname: "TestRunJobDataHistoryConvertCandlesDataType", + Exchange: "Binance", + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-time.Hour * 2), + EndDate: time.Now(), + Interval: kline.FifteenMin, + DataType: dataHistoryConvertCandlesDataType, + ConversionInterval: kline.OneHour, + }, + { + Nickname: "TestRunJobDataHistoryConvertTradesDataType", + Exchange: "Binance", + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-time.Hour * 2), + EndDate: time.Now(), + Interval: kline.FifteenMin, + DataType: dataHistoryConvertTradesDataType, + ConversionInterval: kline.OneHour, + }, + { + Nickname: "TestRunJobDataHistoryCandleValidationDataType", + Exchange: "Binance", + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-time.Hour * 2), + EndDate: time.Now(), + Interval: kline.OneHour, + DataType: dataHistoryCandleValidationDataType, + }, + { + Nickname: "TestRunJobDataHistoryCandleSecondaryValidationDataType", + Exchange: "Binance", + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-time.Hour * 2), + EndDate: time.Now(), + Interval: kline.OneMin, + DataType: dataHistoryCandleValidationSecondarySourceType, + SecondaryExchangeSource: testExchange, + }, } - m = nil - err = m.runJob(dhjt) - if !errors.Is(err, ErrNilSubsystem) { - t.Errorf("error '%v', expected '%v'", err, ErrNilSubsystem) + for x := range testCases { + test := testCases[x] + t.Run(test.Nickname, func(t *testing.T) { + t.Parallel() + m, _ := createDHM(t) + err := m.UpsertJob(test, false) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + m.tradeSaver = dataHistoryTradeSaver + m.candleSaver = dataHistoryCandleSaver + m.tradeLoader = dataHistoryTraderLoader + + err = m.runJob(nil) + if !errors.Is(err, errNilJob) { + t.Errorf("error '%v', expected '%v'", err, errNilJob) + } + + test.Status = dataHistoryIntervalIssuesFound + err = m.runJob(test) + if !errors.Is(err, errJobInvalid) { + t.Errorf("error '%v', expected '%v'", err, errJobInvalid) + } + + rh := test.rangeHolder + test.Status = dataHistoryStatusActive + test.rangeHolder = nil + err = m.runJob(test) + if !errors.Is(err, errJobInvalid) { + t.Errorf("error '%v', expected '%v'", err, errJobInvalid) + } + + test.rangeHolder = rh + err = m.runJob(test) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + + test.Pair = currency.NewPair(currency.DOGE, currency.USDT) + test.Status = dataHistoryStatusActive + err = m.runJob(test) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + + atomic.StoreInt32(&m.started, 0) + err = m.runJob(test) + if !errors.Is(err, ErrSubSystemNotStarted) { + t.Errorf("error '%v', expected '%v'", err, ErrSubSystemNotStarted) + } + + m = nil + err = m.runJob(test) + if !errors.Is(err, ErrNilSubsystem) { + t.Errorf("error '%v', expected '%v'", err, ErrNilSubsystem) + } + }) } } func TestGenerateJobSummaryTest(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) dhj := &DataHistoryJob{ Nickname: "TestGenerateJobSummary", Exchange: testExchange, @@ -707,7 +820,7 @@ func TestGenerateJobSummaryTest(t *testing.T) { func TestRunJobs(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) err := m.runJobs() if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) @@ -727,7 +840,7 @@ func TestRunJobs(t *testing.T) { func TestConverters(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) id, err := uuid.NewV4() if !errors.Is(err, nil) { t.Errorf("error '%v', expected '%v'", err, nil) @@ -808,19 +921,20 @@ func TestConverters(t *testing.T) { } // test helper functions -func createDHM(t *testing.T) *DataHistoryManager { +func createDHM(t *testing.T) (*DataHistoryManager, *datahistoryjob.DataHistoryJob) { em := SetupExchangeManager() exch, err := em.NewExchangeByName(testExchange) if !errors.Is(err, nil) { t.Fatalf("error '%v', expected '%v'", err, nil) } cp := currency.NewPair(currency.BTC, currency.USD) + cp2 := currency.NewPair(currency.BTC, currency.USDT) exch.SetDefaults() b := exch.GetBase() b.CurrencyPairs.Pairs = make(map[asset.Item]*currency.PairStore) b.CurrencyPairs.Pairs[asset.Spot] = ¤cy.PairStore{ - Available: currency.Pairs{cp}, - Enabled: currency.Pairs{cp}, + Available: currency.Pairs{cp, cp2}, + Enabled: currency.Pairs{cp, cp2}, AssetEnabled: convert.BoolPtr(true)} em.Add(exch) @@ -828,26 +942,475 @@ func createDHM(t *testing.T) *DataHistoryManager { if !errors.Is(err, nil) { t.Fatalf("error '%v', expected '%v'", err, nil) } - cp2 := currency.NewPair(currency.BTC, currency.USDT) exch2.SetDefaults() b = exch2.GetBase() b.CurrencyPairs.Pairs = make(map[asset.Item]*currency.PairStore) b.CurrencyPairs.Pairs[asset.Spot] = ¤cy.PairStore{ - Available: currency.Pairs{cp2}, - Enabled: currency.Pairs{cp2}, - AssetEnabled: convert.BoolPtr(true), - ConfigFormat: ¤cy.PairFormat{Uppercase: true}} + Available: currency.Pairs{cp, cp2}, + Enabled: currency.Pairs{cp, cp2}, + AssetEnabled: convert.BoolPtr(true), + ConfigFormat: ¤cy.PairFormat{Uppercase: true}, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + } + em.Add(exch2) + j := &datahistoryjob.DataHistoryJob{ + ID: jobID, + Nickname: "datahistoryjob", + ExchangeName: testExchange, + Asset: "spot", + Base: "btc", + Quote: "usd", + StartDate: startDate, + EndDate: endDate, + Interval: int64(kline.OneHour.Duration()), + RequestSizeLimit: 3, + MaxRetryAttempts: 3, + BatchSize: 3, + CreatedDate: endDate, + Status: 0, + Results: []*datahistoryjobresult.DataHistoryJobResult{ + { + ID: jobID, + JobID: jobID, + }, + }, + } m := &DataHistoryManager{ - jobDB: dataHistoryJobService{}, - jobResultDB: dataHistoryJobResultService{}, - started: 1, - exchangeManager: em, - tradeLoader: dataHistoryTradeLoader, - candleLoader: dataHistoryCandleLoader, - interval: time.NewTicker(time.Minute), + jobDB: dataHistoryJobService{ + job: j, + }, + jobResultDB: dataHistoryJobResultService{}, + started: 1, + exchangeManager: em, + candleLoader: dataHistoryCandleLoader, + interval: time.NewTicker(time.Minute), + verbose: true, + maxResultInsertions: defaultMaxResultInsertions, + } + return m, j +} + +func TestProcessCandleData(t *testing.T) { + t.Parallel() + m, _ := createDHM(t) + _, err := m.processCandleData(nil, nil, time.Time{}, time.Time{}, 0) + if !errors.Is(err, errNilJob) { + t.Errorf("received %v expected %v", err, errNilJob) + } + j := &DataHistoryJob{ + Nickname: "", + Exchange: testExchange, + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-kline.OneHour.Duration() * 2), + EndDate: time.Now(), + Interval: kline.OneHour, + } + _, err = m.processCandleData(j, nil, time.Time{}, time.Time{}, 0) + if !errors.Is(err, ErrExchangeNotFound) { + t.Errorf("received %v expected %v", err, ErrExchangeNotFound) + } + + em := SetupExchangeManager() + exch, err := em.NewExchangeByName(testExchange) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + exch.SetDefaults() + fakeExchange := dhmExchange{ + IBotExchange: exch, + } + _, err = m.processCandleData(j, exch, time.Time{}, time.Time{}, 0) + if !errors.Is(err, common.ErrDateUnset) { + t.Errorf("received %v expected %v", err, common.ErrDateUnset) + } + + m.candleSaver = dataHistoryCandleSaver + j.rangeHolder, err = kline.CalculateCandleDateRanges(j.StartDate, j.EndDate, j.Interval, 1337) + if err != nil { + t.Error(err) + } + r, err := m.processCandleData(j, fakeExchange, j.StartDate, j.EndDate, 0) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if r.Status != dataHistoryStatusComplete { + t.Errorf("received %v expected %v", r.Status, dataHistoryStatusComplete) + } + r, err = m.processCandleData(j, exch, j.StartDate, j.EndDate, 0) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if r.Status != dataHistoryStatusFailed { + t.Errorf("received %v expected %v", r.Status, dataHistoryStatusFailed) + } +} + +func TestProcessTradeData(t *testing.T) { + t.Parallel() + m, _ := createDHM(t) + _, err := m.processTradeData(nil, nil, time.Time{}, time.Time{}, 0) + if !errors.Is(err, errNilJob) { + t.Errorf("received %v expected %v", err, errNilJob) + } + j := &DataHistoryJob{ + Nickname: "", + Exchange: testExchange, + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-kline.OneHour.Duration() * 2), + EndDate: time.Now(), + Interval: kline.OneHour, + } + _, err = m.processTradeData(j, nil, time.Time{}, time.Time{}, 0) + if !errors.Is(err, ErrExchangeNotFound) { + t.Errorf("received %v expected %v", err, ErrExchangeNotFound) + } + + em := SetupExchangeManager() + exch, err := em.NewExchangeByName(testExchange) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + exch.SetDefaults() + fakeExchange := dhmExchange{ + IBotExchange: exch, + } + _, err = m.processTradeData(j, exch, time.Time{}, time.Time{}, 0) + if !errors.Is(err, common.ErrDateUnset) { + t.Errorf("received %v expected %v", err, common.ErrDateUnset) + } + j.rangeHolder, err = kline.CalculateCandleDateRanges(j.StartDate, j.EndDate, j.Interval, 1337) + if err != nil { + t.Error(err) + } + m.tradeSaver = dataHistoryTradeSaver + r, err := m.processTradeData(j, fakeExchange, j.StartDate, j.EndDate, 0) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if r.Status != dataHistoryStatusFailed { + t.Errorf("received %v expected %v", r.Status, dataHistoryStatusFailed) + } + r, err = m.processTradeData(j, exch, j.StartDate, j.EndDate, 0) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if r.Status != dataHistoryStatusFailed { + t.Errorf("received %v expected %v", r.Status, dataHistoryStatusFailed) + } +} + +func TestConvertJobTradesToCandles(t *testing.T) { + t.Parallel() + m, _ := createDHM(t) + _, err := m.convertTradesToCandles(nil, time.Time{}, time.Time{}) + if !errors.Is(err, errNilJob) { + t.Errorf("received %v expected %v", err, errNilJob) + } + j := &DataHistoryJob{ + Nickname: "", + Exchange: testExchange, + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-kline.OneHour.Duration() * 2), + EndDate: time.Now(), + Interval: kline.OneHour, + } + _, err = m.convertTradesToCandles(j, time.Time{}, time.Time{}) + if !errors.Is(err, common.ErrDateUnset) { + t.Errorf("received %v expected %v", err, common.ErrDateUnset) + } + m.tradeLoader = dataHistoryTraderLoader + m.candleSaver = dataHistoryCandleSaver + r, err := m.convertTradesToCandles(j, j.StartDate, j.EndDate) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if r.Status != dataHistoryStatusComplete { + t.Errorf("received %v expected %v", r.Status, dataHistoryStatusComplete) + } +} + +func TestUpscaleJobCandleData(t *testing.T) { + t.Parallel() + m, _ := createDHM(t) + m.candleSaver = dataHistoryCandleSaver + _, err := m.convertCandleData(nil, time.Time{}, time.Time{}) + if !errors.Is(err, errNilJob) { + t.Errorf("received %v expected %v", err, errNilJob) + } + j := &DataHistoryJob{ + Nickname: "", + Exchange: testExchange, + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-kline.OneHour.Duration() * 2), + EndDate: time.Now(), + Interval: kline.OneHour, + ConversionInterval: kline.OneDay, + } + _, err = m.convertCandleData(j, time.Time{}, time.Time{}) + if !errors.Is(err, common.ErrDateUnset) { + t.Errorf("received %v expected %v", err, common.ErrDateUnset) + } + + r, err := m.convertCandleData(j, j.StartDate, j.EndDate) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if r.Status != dataHistoryStatusComplete { + t.Errorf("received %v expected %v", r.Status, dataHistoryStatusComplete) + } +} + +func TestValidateCandles(t *testing.T) { + t.Parallel() + m, _ := createDHM(t) + m.candleSaver = dataHistoryCandleSaver + _, err := m.validateCandles(nil, nil, time.Time{}, time.Time{}) + if !errors.Is(err, errNilJob) { + t.Errorf("received %v expected %v", err, errNilJob) + } + j := &DataHistoryJob{ + Nickname: "", + Exchange: testExchange, + Asset: asset.Spot, + Pair: currency.NewPair(currency.BTC, currency.USDT), + StartDate: time.Now().Add(-kline.OneHour.Duration() * 2), + EndDate: time.Now(), + Interval: kline.OneHour, + } + _, err = m.validateCandles(j, nil, time.Time{}, time.Time{}) + if !errors.Is(err, ErrExchangeNotFound) { + t.Errorf("received %v expected %v", err, ErrExchangeNotFound) + } + + em := SetupExchangeManager() + exch, err := em.NewExchangeByName(testExchange) + if !errors.Is(err, nil) { + t.Errorf("error '%v', expected '%v'", err, nil) + } + exch.SetDefaults() + fakeExchange := dhmExchange{ + IBotExchange: exch, + } + _, err = m.validateCandles(j, exch, time.Time{}, time.Time{}) + if !errors.Is(err, common.ErrDateUnset) { + t.Errorf("received %v expected %v", err, common.ErrDateUnset) + } + j.rangeHolder, err = kline.CalculateCandleDateRanges(j.StartDate, j.EndDate, j.Interval, 1337) + if err != nil { + t.Error(err) + } + r, err := m.validateCandles(j, fakeExchange, j.StartDate, j.EndDate) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if r.Status != dataHistoryIntervalIssuesFound { + t.Errorf("received %v expected %v", r.Status, dataHistoryIntervalIssuesFound) + } + r, err = m.validateCandles(j, exch, j.StartDate, j.EndDate) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if r.Status != dataHistoryStatusFailed { + t.Errorf("received %v expected %v", r.Status, dataHistoryStatusFailed) + } +} + +func TestSetJobRelationship(t *testing.T) { + t.Parallel() + m, j := createDHM(t) + err := m.SetJobRelationship("test", "123") + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + + jID, err := uuid.NewV4() + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + j.ID = jID.String() + j.PrerequisiteJobID = "" + j.PrerequisiteJobNickname = "" + err = m.SetJobRelationship("", "123") + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + + err = m.SetJobRelationship("", "") + if !errors.Is(err, errNicknameUnset) { + t.Errorf("received %v expected %v", err, errNicknameUnset) + } + m.started = 0 + err = m.SetJobRelationship("", "") + if !errors.Is(err, ErrSubSystemNotStarted) { + t.Errorf("received %v expected %v", err, ErrSubSystemNotStarted) + } + + m = nil + err = m.SetJobRelationship("", "") + if !errors.Is(err, ErrNilSubsystem) { + t.Errorf("received %v expected %v", err, ErrNilSubsystem) + } +} + +func TestCheckCandleIssue(t *testing.T) { + t.Parallel() + m, _ := createDHM(t) + issue, replace := m.CheckCandleIssue(nil, 0, 0, 0, "") + if issue != errNilJob.Error() { + t.Errorf("expected 'nil job' received %v", issue) + } + if replace { + t.Errorf("expected %v received %v", false, replace) + } + + job := &DataHistoryJob{ + IssueTolerancePercentage: 0, + ReplaceOnIssue: false, + DecimalPlaceComparison: 0, + } + issue, replace = m.CheckCandleIssue(job, 0, 0, 0, "") + if issue != "" { + t.Errorf("expected 'nil job' received %v", issue) + } + if replace { + t.Errorf("expected %v received %v", false, replace) + } + + issue, replace = m.CheckCandleIssue(job, 0, 1, 2, "Open") + if issue != "Open api: 1 db: 2 diff: 100 %" { + t.Errorf("expected 'Open api: 1 db: 2 diff: 100 %%' received %v", issue) + } + if replace { + t.Errorf("expected %v received %v", false, replace) + } + + job.IssueTolerancePercentage = 100 + issue, replace = m.CheckCandleIssue(job, 0, 1, 1.5, "Open") + if issue != "" { + t.Errorf("expected 'Open api: 1 db: 2 diff: 100 %%' received %v", issue) + } + if replace { + t.Errorf("expected %v received %v", false, replace) + } + + job.IssueTolerancePercentage = 1 + job.ReplaceOnIssue = true + issue, replace = m.CheckCandleIssue(job, 10, 1.5, 1, "Open") + if issue != "Open api: 1.5 db: 1 diff: 50 %" { + t.Errorf("expected 'Open api: 1.5 db: 1 diff: 50 %%' received %v", issue) + } + if !replace { + t.Errorf("expected %v received %v", true, replace) + } + + m.started = 0 + issue, replace = m.CheckCandleIssue(nil, 0, 0, 0, "") + if issue != ErrSubSystemNotStarted.Error() { + t.Errorf("expected %v received %v", ErrSubSystemNotStarted, issue) + } + if replace { + t.Errorf("expected %v received %v", false, replace) + } + + m = nil + issue, replace = m.CheckCandleIssue(nil, 0, 0, 0, "") + if issue != ErrNilSubsystem.Error() { + t.Errorf("expected %v received %v", ErrNilSubsystem, issue) + } + if replace { + t.Errorf("expected %v received %v", false, replace) + } +} + +func TestCompletionCheck(t *testing.T) { + t.Parallel() + m, _ := createDHM(t) + err := m.completeJob(nil, false, false) + if !errors.Is(err, errNilJob) { + t.Errorf("received %v expected %v", err, errNilJob) + } + j := &DataHistoryJob{ + Status: dataHistoryStatusActive, + } + err = m.completeJob(j, false, false) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if j.Status != dataHistoryIntervalIssuesFound { + t.Errorf("received %v expected %v", j.Status, dataHistoryIntervalIssuesFound) + } + + err = m.completeJob(j, true, false) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if j.Status != dataHistoryStatusComplete { + t.Errorf("received %v expected %v", j.Status, dataHistoryStatusComplete) + } + + err = m.completeJob(j, false, true) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + if j.Status != dataHistoryStatusFailed { + t.Errorf("received %v expected %v", j.Status, dataHistoryStatusFailed) + } + + err = m.completeJob(j, true, true) + if !errors.Is(err, errJobInvalid) { + t.Errorf("received %v expected %v", err, errJobInvalid) + } +} + +func TestSaveCandlesInBatches(t *testing.T) { + t.Parallel() + dhm := DataHistoryManager{ + candleSaver: dataHistoryCandleSaver, + } + err := dhm.saveCandlesInBatches(nil, nil, nil) + if !errors.Is(err, ErrSubSystemNotStarted) { + t.Errorf("received %v expected %v", err, ErrSubSystemNotStarted) + } + + dhm.started = 1 + err = dhm.saveCandlesInBatches(nil, nil, nil) + if !errors.Is(err, errNilJob) { + t.Errorf("received %v expected %v", err, errNilJob) + } + + job := &DataHistoryJob{} + err = dhm.saveCandlesInBatches(job, nil, nil) + if !errors.Is(err, errNilCandles) { + t.Errorf("received %v expected %v", err, errNilCandles) + } + + candles := &kline.Item{} + err = dhm.saveCandlesInBatches(job, candles, nil) + if !errors.Is(err, errNilResult) { + t.Errorf("received %v expected %v", err, errNilResult) + } + + result := &DataHistoryJobResult{} + err = dhm.saveCandlesInBatches(job, candles, result) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) + } + + for i := 0; i < 10000; i++ { + candles.Candles = append(candles.Candles, kline.Candle{ + Volume: float64(i), + }) + } + dhm.maxResultInsertions = 1337 + err = dhm.saveCandlesInBatches(job, candles, result) + if !errors.Is(err, nil) { + t.Errorf("received %v expected %v", err, nil) } - return m } // these structs and function implementations are used @@ -855,6 +1418,7 @@ func createDHM(t *testing.T) *DataHistoryManager { // results here. see tests in the database folder type dataHistoryJobService struct { datahistoryjob.IDBService + job *datahistoryjob.DataHistoryJob } type dataHistoryJobResultService struct { @@ -871,32 +1435,48 @@ func (d dataHistoryJobService) Upsert(_ ...*datahistoryjob.DataHistoryJob) error return nil } +func (d dataHistoryJobService) SetRelationshipByID(prereq, _ string, status int64) error { + d.job.PrerequisiteJobID = prereq + d.job.Status = status + return nil +} + +func (d dataHistoryJobService) SetRelationshipByNickname(prereq, _ string, status int64) error { + d.job.PrerequisiteJobNickname = prereq + d.job.Status = status + return nil +} + func (d dataHistoryJobService) GetByNickName(nickname string) (*datahistoryjob.DataHistoryJob, error) { - jc := j - jc.Nickname = nickname - return &jc, nil + d.job.Nickname = nickname + return d.job, nil } func (d dataHistoryJobService) GetJobsBetween(_, _ time.Time) ([]datahistoryjob.DataHistoryJob, error) { - jc := j - return []datahistoryjob.DataHistoryJob{jc}, nil + return []datahistoryjob.DataHistoryJob{*d.job}, nil } func (d dataHistoryJobService) GetByID(id string) (*datahistoryjob.DataHistoryJob, error) { - jc := j - jc.ID = id - return &jc, nil + d.job.ID = id + return d.job, nil } func (d dataHistoryJobService) GetAllIncompleteJobsAndResults() ([]datahistoryjob.DataHistoryJob, error) { - jc := j - return []datahistoryjob.DataHistoryJob{jc}, nil + return []datahistoryjob.DataHistoryJob{*d.job}, nil } func (d dataHistoryJobService) GetJobAndAllResults(nickname string) (*datahistoryjob.DataHistoryJob, error) { - jc := j - jc.Nickname = nickname - return &jc, nil + d.job.Nickname = nickname + return d.job, nil +} + +func (d dataHistoryJobService) GetRelatedUpcomingJobs(_ string) ([]*datahistoryjob.DataHistoryJob, error) { + return []*datahistoryjob.DataHistoryJob{ + { + Nickname: "test123", + Status: int64(dataHistoryStatusPaused), + }, + }, nil } func (d dataHistoryJobResultService) Upsert(_ ...*datahistoryjobresult.DataHistoryJobResult) error { @@ -911,38 +1491,111 @@ func (d dataHistoryJobResultService) GetJobResultsBetween(_ string, _, _ time.Ti return nil, nil } -var j = datahistoryjob.DataHistoryJob{ - ID: jobID, - Nickname: "datahistoryjob", - ExchangeName: testExchange, - Asset: "spot", - Base: "btc", - Quote: "usd", - StartDate: startDate, - EndDate: endDate, - Interval: int64(kline.OneHour.Duration()), - RequestSizeLimit: 3, - MaxRetryAttempts: 3, - BatchSize: 3, - CreatedDate: endDate, - Status: 0, - Results: []*datahistoryjobresult.DataHistoryJobResult{ +func dataHistoryTraderLoader(exch, a, base, quote string, start, _ time.Time) ([]trade.Data, error) { + cp, err := currency.NewPairFromStrings(base, quote) + if err != nil { + return nil, err + } + return []trade.Data{ { - ID: jobID, - JobID: jobID, + Exchange: exch, + CurrencyPair: cp, + AssetType: asset.Item(a), + Side: order.Buy, + Price: 1337, + Amount: 1337, + Timestamp: start, }, - }, + }, nil } -func dataHistoryTradeLoader(_, _, _, _ string, irh *kline.IntervalRangeHolder) error { - for i := range irh.Ranges { - for j := range irh.Ranges[i].Intervals { - irh.Ranges[i].Intervals[j].HasData = true - } - } +func dataHistoryCandleLoader(exch string, cp currency.Pair, a asset.Item, i kline.Interval, start, _ time.Time) (kline.Item, error) { + return kline.Item{ + Exchange: exch, + Pair: cp, + Asset: a, + Interval: i, + Candles: []kline.Candle{ + { + Time: start, + Open: 1, + High: 10, + Low: 1, + Close: 4, + Volume: 8, + }, + }, + }, nil +} + +func dataHistoryTradeSaver(...trade.Data) error { return nil } -func dataHistoryCandleLoader(string, currency.Pair, asset.Item, kline.Interval, time.Time, time.Time) (kline.Item, error) { - return kline.Item{}, nil +func dataHistoryCandleSaver(_ *kline.Item, _ bool) (uint64, error) { + return 0, nil +} + +// dhmExchange aka datahistorymanager fake exchange overrides exchange functions +// we're not testing an actual exchange's implemented functions +type dhmExchange struct { + exchange.IBotExchange +} + +func (f dhmExchange) GetHistoricCandlesExtended(p currency.Pair, a asset.Item, timeStart, _ time.Time, interval kline.Interval) (kline.Item, error) { + return kline.Item{ + Exchange: testExchange, + Pair: p, + Asset: a, + Interval: interval, + Candles: []kline.Candle{ + { + Time: timeStart, + Open: 1, + High: 2, + Low: 3, + Close: 4, + Volume: 5, + }, + { + Time: timeStart.Add(interval.Duration()), + Open: 1, + High: 2, + Low: 3, + Close: 4, + Volume: 5, + }, + { + Time: timeStart.Add(interval.Duration() * 2), + Open: 1, + High: 2, + Low: 3, + Close: 4, + Volume: 5, + }, + }, + }, nil +} + +func (f dhmExchange) GetHistoricTrades(p currency.Pair, a asset.Item, startTime, endTime time.Time) ([]trade.Data, error) { + return []trade.Data{ + { + Exchange: testExchange, + CurrencyPair: p, + AssetType: a, + Side: order.Buy, + Price: 1337, + Amount: 4, + Timestamp: startTime.Add(time.Minute), + }, + { + Exchange: testExchange, + CurrencyPair: p, + AssetType: a, + Side: order.Buy, + Price: 1338, + Amount: 2, + Timestamp: startTime.Add(time.Minute * 2), + }, + }, nil } diff --git a/engine/datahistory_manager_types.go b/engine/datahistory_manager_types.go index f1a181b461d..0401d71891b 100644 --- a/engine/datahistory_manager_types.go +++ b/engine/datahistory_manager_types.go @@ -2,7 +2,6 @@ package engine import ( "errors" - "sync" "time" "github.com/gofrs/uuid" @@ -12,6 +11,7 @@ import ( "github.com/thrasher-corp/gocryptotrader/database/repository/datahistoryjobresult" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" "github.com/thrasher-corp/gocryptotrader/exchanges/kline" + "github.com/thrasher-corp/gocryptotrader/exchanges/trade" ) const dataHistoryManagerName = "data_history_manager" @@ -23,6 +23,10 @@ type dataHistoryDataType int64 const ( dataHistoryCandleDataType dataHistoryDataType = iota dataHistoryTradeDataType + dataHistoryConvertTradesDataType + dataHistoryConvertCandlesDataType + dataHistoryCandleValidationDataType + dataHistoryCandleValidationSecondarySourceType ) // DataHistoryJob status descriptors @@ -31,7 +35,8 @@ const ( dataHistoryStatusFailed dataHistoryStatusComplete dataHistoryStatusRemoved - dataHistoryIntervalMissingData + dataHistoryIntervalIssuesFound + dataHistoryStatusPaused ) // String stringifies iotas to readable @@ -46,30 +51,41 @@ func (d dataHistoryStatus) String() string { case int64(d) == 3: return "removed" case int64(d) == 4: - return "missing data" + return "issues found" + case int64(d) == 5: + return "paused" } return "" } // Valid ensures the value set is legitimate func (d dataHistoryStatus) Valid() bool { - return int64(d) >= 0 && int64(d) <= 4 + return int64(d) >= 0 && int64(d) <= 5 } // String stringifies iotas to readable func (d dataHistoryDataType) String() string { - switch { - case int64(d) == 0: + n := int64(d) + switch n { + case 0: return "candles" - case int64(d) == 1: + case 1: return "trades" + case 2: + return "trade conversion" + case 3: + return "candle conversion" + case 4: + return "conversion validation" + case 5: + return "conversion validation secondary source" } return "" } // Valid ensures the value set is legitimate func (d dataHistoryDataType) Valid() bool { - return int64(d) == 0 || int64(d) == 1 + return int64(d) >= 0 && int64(d) <= 5 } var ( @@ -79,20 +95,27 @@ var ( errNicknameIDUnset = errors.New("must set 'id' OR 'nickname'") errEmptyID = errors.New("id not set") errOnlyNicknameOrID = errors.New("can only set 'id' OR 'nickname'") + errBadStatus = errors.New("cannot set job status") errNicknameInUse = errors.New("cannot continue as nickname already in use") errNicknameUnset = errors.New("cannot continue as nickname unset") errJobInvalid = errors.New("job has not been setup properly and cannot be processed") errInvalidDataHistoryStatus = errors.New("unsupported data history status received") errInvalidDataHistoryDataType = errors.New("unsupported data history data type received") - errCanOnlyDeleteActiveJobs = errors.New("can only delete active jobs") + errNilResult = errors.New("received nil job result") + errJobMustBeActiveOrPaused = errors.New("job must be active or paused to be set as a prerequisite") + errNilCandles = errors.New("received nil candles") + // defaultDataHistoryTradeInterval is the default interval size used to verify whether there is any database data // for a trade job defaultDataHistoryTradeInterval = kline.FifteenMin defaultDataHistoryMaxJobsPerCycle int64 = 5 + defaultMaxResultInsertions int64 = 10000 defaultDataHistoryBatchLimit int64 = 3 defaultDataHistoryRetryAttempts int64 = 3 - defaultDataHistoryRequestSizeLimit int64 = 10 + defaultDataHistoryRequestSizeLimit int64 = 500 defaultDataHistoryTicker = time.Minute + defaultDataHistoryTradeRequestSize int64 = 10 + defaultDecimalPlaceComparison int64 = 3 ) // DataHistoryManager is responsible for synchronising, @@ -104,35 +127,45 @@ type DataHistoryManager struct { processing int32 shutdown chan struct{} interval *time.Ticker - jobs []*DataHistoryJob - m sync.Mutex jobDB datahistoryjob.IDBService jobResultDB datahistoryjobresult.IDBService maxJobsPerCycle int64 + maxResultInsertions int64 verbose bool - tradeLoader func(string, string, string, string, *kline.IntervalRangeHolder) error candleLoader func(string, currency.Pair, asset.Item, kline.Interval, time.Time, time.Time) (kline.Item, error) + tradeLoader func(string, string, string, string, time.Time, time.Time) ([]trade.Data, error) + tradeSaver func(...trade.Data) error + candleSaver func(*kline.Item, bool) (uint64, error) } // DataHistoryJob used to gather candle/trade history and save // to the database type DataHistoryJob struct { - ID uuid.UUID - Nickname string - Exchange string - Asset asset.Item - Pair currency.Pair - StartDate time.Time - EndDate time.Time - Interval kline.Interval - RunBatchLimit int64 - RequestSizeLimit int64 - DataType dataHistoryDataType - MaxRetryAttempts int64 - Status dataHistoryStatus - CreatedDate time.Time - Results map[time.Time][]DataHistoryJobResult - rangeHolder *kline.IntervalRangeHolder + ID uuid.UUID + Nickname string + Exchange string + Asset asset.Item + Pair currency.Pair + StartDate time.Time + EndDate time.Time + Interval kline.Interval + RunBatchLimit int64 + RequestSizeLimit int64 + DataType dataHistoryDataType + MaxRetryAttempts int64 + Status dataHistoryStatus + CreatedDate time.Time + Results map[time.Time][]DataHistoryJobResult + rangeHolder *kline.IntervalRangeHolder + OverwriteExistingData bool + ConversionInterval kline.Interval + DecimalPlaceComparison int64 + SecondaryExchangeSource string + IssueTolerancePercentage float64 + ReplaceOnIssue bool + // Prerequisites mean this job is paused until the prerequisite job is completed + PrerequisiteJobID uuid.UUID + PrerequisiteJobNickname string } // DataHistoryJobResult contains details on @@ -150,14 +183,17 @@ type DataHistoryJobResult struct { // DataHistoryJobSummary is a human readable summary of the job // for quickly understanding the status of a given job type DataHistoryJobSummary struct { - Nickname string - Exchange string - Asset asset.Item - Pair currency.Pair - StartDate time.Time - EndDate time.Time - Interval kline.Interval - Status dataHistoryStatus - DataType dataHistoryDataType - ResultRanges []string + Nickname string + Exchange string + Asset asset.Item + Pair currency.Pair + StartDate time.Time + EndDate time.Time + Interval kline.Interval + Status dataHistoryStatus + DataType dataHistoryDataType + ResultRanges []string + OverwriteExistingData bool + ConversionInterval kline.Interval + PrerequisiteJobNickname string } diff --git a/engine/rpcserver.go b/engine/rpcserver.go index ae5bdbc02c1..4d7fe4d8ab2 100644 --- a/engine/rpcserver.go +++ b/engine/rpcserver.go @@ -3426,18 +3426,25 @@ func (s *RPCServer) UpsertDataHistoryJob(_ context.Context, r *gctrpc.UpsertData } job := DataHistoryJob{ - Nickname: r.Nickname, - Exchange: r.Exchange, - Asset: a, - Pair: p, - StartDate: start, - EndDate: end, - Interval: kline.Interval(r.Interval), - RunBatchLimit: r.BatchSize, - RequestSizeLimit: r.RequestSizeLimit, - DataType: dataHistoryDataType(r.DataType), - Status: dataHistoryStatusActive, - MaxRetryAttempts: r.MaxRetryAttempts, + Nickname: r.Nickname, + Exchange: r.Exchange, + Asset: a, + Pair: p, + StartDate: start, + EndDate: end, + Interval: kline.Interval(r.Interval), + RunBatchLimit: r.BatchSize, + RequestSizeLimit: r.RequestSizeLimit, + DataType: dataHistoryDataType(r.DataType), + MaxRetryAttempts: r.MaxRetryAttempts, + Status: dataHistoryStatusActive, + OverwriteExistingData: r.OverwriteExistingData, + ConversionInterval: kline.Interval(r.ConversionInterval), + DecimalPlaceComparison: r.DecimalPlaceComparison, + SecondaryExchangeSource: r.SecondaryExchangeName, + IssueTolerancePercentage: r.IssueTolerancePercentage, + ReplaceOnIssue: r.ReplaceOnIssue, + PrerequisiteJobNickname: r.PrerequisiteJobNickname, } err = s.dataHistoryManager.UpsertJob(&job, r.InsertOnly) @@ -3513,39 +3520,25 @@ func (s *RPCServer) GetDataHistoryJobDetails(_ context.Context, r *gctrpc.GetDat Base: result.Pair.Base.String(), Quote: result.Pair.Quote.String(), }, - StartDate: result.StartDate.Format(common.SimpleTimeFormat), - EndDate: result.EndDate.Format(common.SimpleTimeFormat), - Interval: int64(result.Interval.Duration()), - RequestSizeLimit: result.RequestSizeLimit, - DataType: result.DataType.String(), - MaxRetryAttempts: result.MaxRetryAttempts, - BatchSize: result.RunBatchLimit, - JobResults: jobResults, - Status: result.Status.String(), + StartDate: result.StartDate.Format(common.SimpleTimeFormat), + EndDate: result.EndDate.Format(common.SimpleTimeFormat), + Interval: int64(result.Interval.Duration()), + RequestSizeLimit: result.RequestSizeLimit, + MaxRetryAttempts: result.MaxRetryAttempts, + BatchSize: result.RunBatchLimit, + Status: result.Status.String(), + DataType: result.DataType.String(), + ConversionInterval: int64(result.ConversionInterval.Duration()), + OverwriteExistingData: result.OverwriteExistingData, + PrerequisiteJobNickname: result.PrerequisiteJobNickname, + DecimalPlaceComparison: result.DecimalPlaceComparison, + SecondaryExchangeName: result.SecondaryExchangeSource, + IssueTolerancePercentage: result.IssueTolerancePercentage, + ReplaceOnIssue: result.ReplaceOnIssue, + JobResults: jobResults, }, nil } -// DeleteDataHistoryJob deletes a data history job from the database -func (s *RPCServer) DeleteDataHistoryJob(_ context.Context, r *gctrpc.GetDataHistoryJobDetailsRequest) (*gctrpc.GenericResponse, error) { - if r == nil { - return nil, errNilRequestData - } - if r.Nickname == "" && r.Id == "" { - return nil, errNicknameIDUnset - } - if r.Nickname != "" && r.Id != "" { - return nil, errOnlyNicknameOrID - } - status := "success" - err := s.dataHistoryManager.DeleteJob(r.Nickname, r.Id) - if err != nil { - log.Error(log.GRPCSys, err) - status = "failed" - } - - return &gctrpc.GenericResponse{Status: status}, err -} - // GetActiveDataHistoryJobs returns any active data history job details func (s *RPCServer) GetActiveDataHistoryJobs(_ context.Context, _ *gctrpc.GetInfoRequest) (*gctrpc.DataHistoryJobs, error) { jobs, err := s.dataHistoryManager.GetActiveJobs() @@ -3565,14 +3558,21 @@ func (s *RPCServer) GetActiveDataHistoryJobs(_ context.Context, _ *gctrpc.GetInf Base: jobs[i].Pair.Base.String(), Quote: jobs[i].Pair.Quote.String(), }, - StartDate: jobs[i].StartDate.Format(common.SimpleTimeFormat), - EndDate: jobs[i].EndDate.Format(common.SimpleTimeFormat), - Interval: int64(jobs[i].Interval.Duration()), - RequestSizeLimit: jobs[i].RequestSizeLimit, - DataType: jobs[i].DataType.String(), - MaxRetryAttempts: jobs[i].MaxRetryAttempts, - BatchSize: jobs[i].RunBatchLimit, - Status: jobs[i].Status.String(), + StartDate: jobs[i].StartDate.Format(common.SimpleTimeFormat), + EndDate: jobs[i].EndDate.Format(common.SimpleTimeFormat), + Interval: int64(jobs[i].Interval.Duration()), + RequestSizeLimit: jobs[i].RequestSizeLimit, + MaxRetryAttempts: jobs[i].MaxRetryAttempts, + BatchSize: jobs[i].RunBatchLimit, + Status: jobs[i].Status.String(), + DataType: jobs[i].DataType.String(), + ConversionInterval: int64(jobs[i].ConversionInterval.Duration()), + OverwriteExistingData: jobs[i].OverwriteExistingData, + PrerequisiteJobNickname: jobs[i].PrerequisiteJobNickname, + DecimalPlaceComparison: jobs[i].DecimalPlaceComparison, + SecondaryExchangeName: jobs[i].SecondaryExchangeSource, + IssueTolerancePercentage: jobs[i].IssueTolerancePercentage, + ReplaceOnIssue: jobs[i].ReplaceOnIssue, }) } return &gctrpc.DataHistoryJobs{Results: response}, nil @@ -3612,14 +3612,21 @@ func (s *RPCServer) GetDataHistoryJobsBetween(_ context.Context, r *gctrpc.GetDa Base: jobs[i].Pair.Base.String(), Quote: jobs[i].Pair.Quote.String(), }, - StartDate: jobs[i].StartDate.Format(common.SimpleTimeFormat), - EndDate: jobs[i].EndDate.Format(common.SimpleTimeFormat), - Interval: int64(jobs[i].Interval.Duration()), - RequestSizeLimit: jobs[i].RequestSizeLimit, - DataType: jobs[i].DataType.String(), - MaxRetryAttempts: jobs[i].MaxRetryAttempts, - BatchSize: jobs[i].RunBatchLimit, - Status: jobs[i].Status.String(), + StartDate: jobs[i].StartDate.Format(common.SimpleTimeFormat), + EndDate: jobs[i].EndDate.Format(common.SimpleTimeFormat), + Interval: int64(jobs[i].Interval.Duration()), + RequestSizeLimit: jobs[i].RequestSizeLimit, + MaxRetryAttempts: jobs[i].MaxRetryAttempts, + BatchSize: jobs[i].RunBatchLimit, + Status: jobs[i].Status.String(), + DataType: jobs[i].DataType.String(), + ConversionInterval: int64(jobs[i].ConversionInterval.Duration()), + OverwriteExistingData: jobs[i].OverwriteExistingData, + PrerequisiteJobNickname: jobs[i].PrerequisiteJobNickname, + DecimalPlaceComparison: jobs[i].DecimalPlaceComparison, + SecondaryExchangeName: jobs[i].SecondaryExchangeSource, + IssueTolerancePercentage: jobs[i].IssueTolerancePercentage, + ReplaceOnIssue: jobs[i].ReplaceOnIssue, }) } return &gctrpc.DataHistoryJobs{ @@ -3648,12 +3655,15 @@ func (s *RPCServer) GetDataHistoryJobSummary(_ context.Context, r *gctrpc.GetDat Base: job.Pair.Base.String(), Quote: job.Pair.Quote.String(), }, - StartDate: job.StartDate.Format(common.SimpleTimeFormat), - EndDate: job.EndDate.Format(common.SimpleTimeFormat), - Interval: int64(job.Interval.Duration()), - DataType: job.DataType.String(), - Status: job.Status.String(), - ResultSummaries: job.ResultRanges, + StartDate: job.StartDate.Format(common.SimpleTimeFormat), + EndDate: job.EndDate.Format(common.SimpleTimeFormat), + Interval: int64(job.Interval.Duration()), + Status: job.Status.String(), + DataType: job.DataType.String(), + ConversionInterval: int64(job.ConversionInterval.Duration()), + OverwriteExistingData: job.OverwriteExistingData, + PrerequisiteJobNickname: job.PrerequisiteJobNickname, + ResultSummaries: job.ResultRanges, }, nil } @@ -3665,3 +3675,44 @@ func (s *RPCServer) unixTimestamp(x time.Time) int64 { } return x.Unix() } + +// SetDataHistoryJobStatus sets a data history job's status +func (s *RPCServer) SetDataHistoryJobStatus(_ context.Context, r *gctrpc.SetDataHistoryJobStatusRequest) (*gctrpc.GenericResponse, error) { + if r == nil { + return nil, errNilRequestData + } + if r.Nickname == "" && r.Id == "" { + return nil, errNicknameIDUnset + } + if r.Nickname != "" && r.Id != "" { + return nil, errOnlyNicknameOrID + } + status := "success" + err := s.dataHistoryManager.SetJobStatus(r.Nickname, r.Id, dataHistoryStatus(r.Status)) + if err != nil { + log.Error(log.GRPCSys, err) + status = "failed" + } + + return &gctrpc.GenericResponse{Status: status}, err +} + +// UpdateDataHistoryJobPrerequisite sets or removes a prerequisite job for an existing job +// if the prerequisite job is "", then the relationship is removed +func (s *RPCServer) UpdateDataHistoryJobPrerequisite(_ context.Context, r *gctrpc.UpdateDataHistoryJobPrerequisiteRequest) (*gctrpc.GenericResponse, error) { + if r == nil { + return nil, errNilRequestData + } + if r.Nickname == "" { + return nil, errNicknameUnset + } + status := "success" + err := s.dataHistoryManager.SetJobRelationship(r.PrerequisiteJobNickname, r.Nickname) + if err != nil { + return nil, err + } + if r.PrerequisiteJobNickname == "" { + return &gctrpc.GenericResponse{Status: status, Data: fmt.Sprintf("Removed prerequisite from job '%v'", r.Nickname)}, nil + } + return &gctrpc.GenericResponse{Status: status, Data: fmt.Sprintf("Set job '%v' prerequisite job to '%v' and set status to paused", r.Nickname, r.PrerequisiteJobNickname)}, nil +} diff --git a/engine/rpcserver_test.go b/engine/rpcserver_test.go index 84a8d297218..b553e4b9259 100644 --- a/engine/rpcserver_test.go +++ b/engine/rpcserver_test.go @@ -1318,7 +1318,7 @@ func TestParseEvents(t *testing.T) { func TestRPCServerUpsertDataHistoryJob(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) em := SetupExchangeManager() exch, err := em.NewExchangeByName(testExchange) if err != nil { @@ -1370,7 +1370,7 @@ func TestRPCServerUpsertDataHistoryJob(t *testing.T) { func TestGetDataHistoryJobDetails(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) s := RPCServer{Engine: &Engine{dataHistoryManager: m}} dhj := &DataHistoryJob{ @@ -1407,7 +1407,7 @@ func TestGetDataHistoryJobDetails(t *testing.T) { t.Errorf("received %v, expected %v", err, nil) } - _, err = s.GetDataHistoryJobDetails(context.Background(), &gctrpc.GetDataHistoryJobDetailsRequest{Id: m.jobs[0].ID.String()}) + _, err = s.GetDataHistoryJobDetails(context.Background(), &gctrpc.GetDataHistoryJobDetailsRequest{Id: dhj.ID.String()}) if !errors.Is(err, nil) { t.Errorf("received %v, expected %v", err, nil) } @@ -1424,9 +1424,9 @@ func TestGetDataHistoryJobDetails(t *testing.T) { } } -func TestDeleteDataHistoryJob(t *testing.T) { +func TestSetDataHistoryJobStatus(t *testing.T) { t.Parallel() - m := createDHM(t) + m, j := createDHM(t) s := RPCServer{Engine: &Engine{dataHistoryManager: m}} dhj := &DataHistoryJob{ @@ -1442,40 +1442,49 @@ func TestDeleteDataHistoryJob(t *testing.T) { if !errors.Is(err, nil) { t.Fatalf("received %v, expected %v", err, nil) } - _, err = s.DeleteDataHistoryJob(context.Background(), nil) + _, err = s.SetDataHistoryJobStatus(context.Background(), nil) if !errors.Is(err, errNilRequestData) { t.Errorf("received %v, expected %v", err, errNilRequestData) } - _, err = s.DeleteDataHistoryJob(context.Background(), &gctrpc.GetDataHistoryJobDetailsRequest{}) + _, err = s.SetDataHistoryJobStatus(context.Background(), &gctrpc.SetDataHistoryJobStatusRequest{}) if !errors.Is(err, errNicknameIDUnset) { t.Errorf("received %v, expected %v", err, errNicknameIDUnset) } - _, err = s.DeleteDataHistoryJob(context.Background(), &gctrpc.GetDataHistoryJobDetailsRequest{Id: "123", Nickname: "123"}) + _, err = s.SetDataHistoryJobStatus(context.Background(), &gctrpc.SetDataHistoryJobStatusRequest{Id: "123", Nickname: "123"}) if !errors.Is(err, errOnlyNicknameOrID) { t.Errorf("received %v, expected %v", err, errOnlyNicknameOrID) } - id := m.jobs[0].ID - _, err = s.DeleteDataHistoryJob(context.Background(), &gctrpc.GetDataHistoryJobDetailsRequest{Nickname: "TestDeleteDataHistoryJob"}) + id := dhj.ID + _, err = s.SetDataHistoryJobStatus(context.Background(), &gctrpc.SetDataHistoryJobStatusRequest{Nickname: "TestDeleteDataHistoryJob", Status: int64(dataHistoryStatusRemoved)}) if !errors.Is(err, nil) { t.Errorf("received %v, expected %v", err, nil) } dhj.ID = id - m.jobs = append(m.jobs, dhj) - _, err = s.DeleteDataHistoryJob(context.Background(), &gctrpc.GetDataHistoryJobDetailsRequest{Id: id.String()}) + j.Status = int64(dataHistoryStatusActive) + _, err = s.SetDataHistoryJobStatus(context.Background(), &gctrpc.SetDataHistoryJobStatusRequest{Id: id.String(), Status: int64(dataHistoryStatusRemoved)}) if !errors.Is(err, nil) { t.Errorf("received %v, expected %v", err, nil) } - if len(m.jobs) != 0 { - t.Errorf("received %v, expected %v", len(m.jobs), 0) + _, err = s.SetDataHistoryJobStatus(context.Background(), &gctrpc.SetDataHistoryJobStatusRequest{Id: id.String(), Status: int64(dataHistoryStatusActive)}) + if !errors.Is(err, errBadStatus) { + t.Errorf("received %v, expected %v", err, errBadStatus) + } + j.Status = int64(dataHistoryStatusActive) + _, err = s.SetDataHistoryJobStatus(context.Background(), &gctrpc.SetDataHistoryJobStatusRequest{Id: id.String(), Status: int64(dataHistoryStatusPaused)}) + if !errors.Is(err, nil) { + t.Errorf("received %v, expected %v", err, nil) + } + if j.Status != int64(dataHistoryStatusPaused) { + t.Errorf("received %v, expected %v", dataHistoryStatus(j.Status), dataHistoryStatusPaused) } } func TestGetActiveDataHistoryJobs(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) s := RPCServer{Engine: &Engine{dataHistoryManager: m}} dhj := &DataHistoryJob{ @@ -1504,7 +1513,7 @@ func TestGetActiveDataHistoryJobs(t *testing.T) { func TestGetDataHistoryJobsBetween(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) s := RPCServer{Engine: &Engine{dataHistoryManager: m}} dhj := &DataHistoryJob{ @@ -1549,7 +1558,7 @@ func TestGetDataHistoryJobsBetween(t *testing.T) { func TestGetDataHistoryJobSummary(t *testing.T) { t.Parallel() - m := createDHM(t) + m, _ := createDHM(t) s := RPCServer{Engine: &Engine{dataHistoryManager: m}} dhj := &DataHistoryJob{ @@ -1782,3 +1791,33 @@ func TestRPCServer_GetTicker_LastUpdatedNanos(t *testing.T) { t.Errorf("have %d, want %d", two.LastUpdated, want) } } + +func TestUpdateDataHistoryJobPrerequisite(t *testing.T) { + t.Parallel() + m, _ := createDHM(t) + s := RPCServer{Engine: &Engine{dataHistoryManager: m}} + _, err := s.UpdateDataHistoryJobPrerequisite(context.Background(), nil) + if !errors.Is(err, errNilRequestData) { + t.Errorf("received %v, expected %v", err, errNilRequestData) + } + + _, err = s.UpdateDataHistoryJobPrerequisite(context.Background(), &gctrpc.UpdateDataHistoryJobPrerequisiteRequest{}) + if !errors.Is(err, errNicknameUnset) { + t.Errorf("received %v, expected %v", err, errNicknameUnset) + } + + _, err = s.UpdateDataHistoryJobPrerequisite(context.Background(), &gctrpc.UpdateDataHistoryJobPrerequisiteRequest{ + Nickname: "test456", + }) + if !errors.Is(err, nil) { + t.Errorf("received %v, expected %v", err, nil) + } + + _, err = s.UpdateDataHistoryJobPrerequisite(context.Background(), &gctrpc.UpdateDataHistoryJobPrerequisiteRequest{ + Nickname: "test456", + PrerequisiteJobNickname: "test123", + }) + if !errors.Is(err, nil) { + t.Errorf("received %v, expected %v", err, nil) + } +} diff --git a/exchanges/binance/binance.go b/exchanges/binance/binance.go index e88ffc9cd03..d51e05377fe 100644 --- a/exchanges/binance/binance.go +++ b/exchanges/binance/binance.go @@ -271,13 +271,16 @@ func (b *Binance) batchAggregateTrades(arg *AggregatedTradeRequestParams, params if arg.FromID > 0 { fromID = arg.FromID } else { - for start := arg.StartTime; len(resp) == 0; start = start.Add(time.Hour) { + // Only 10 seconds is used to prevent limit of 1000 being reached in the first request, + // cutting off trades for high activity pairs + increment := time.Second * 10 + for start := arg.StartTime; len(resp) == 0; start = start.Add(increment) { if !arg.EndTime.IsZero() && !start.Before(arg.EndTime) { // All requests returned empty return nil, nil } params.Set("startTime", timeString(start)) - params.Set("endTime", timeString(start.Add(time.Hour))) + params.Set("endTime", timeString(start.Add(increment))) path := aggregatedTrades + "?" + params.Encode() err := b.SendHTTPRequest(exchange.RestSpotSupplementary, path, spotDefaultRate, &resp) if err != nil { diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index 17be79bbe59..76e8a4859d0 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -1528,10 +1528,6 @@ func TestGetAggregatedTradesBatched(t *testing.T) { if err != nil { t.Fatal(err) } - mockExpectTime, err := time.Parse(time.RFC3339, "2020-01-02T16:19:04.8Z") - if err != nil { - t.Fatal(err) - } expectTime, err := time.Parse(time.RFC3339Nano, "2020-01-02T16:19:04.831Z") if err != nil { t.Fatal(err) @@ -1552,8 +1548,8 @@ func TestGetAggregatedTradesBatched(t *testing.T) { StartTime: start, EndTime: start.Add(75 * time.Minute), }, - numExpected: 3, - lastExpected: mockExpectTime, + numExpected: 1012, + lastExpected: time.Date(2020, 1, 2, 16, 18, 31, int(919*time.Millisecond), time.UTC), }, { name: "batch with timerange", @@ -1562,7 +1558,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) { StartTime: start, EndTime: start.Add(75 * time.Minute), }, - numExpected: 4303, + numExpected: 12130, lastExpected: expectTime, }, { @@ -1573,18 +1569,18 @@ func TestGetAggregatedTradesBatched(t *testing.T) { StartTime: start, Limit: 1001, }, - numExpected: 4, - lastExpected: time.Date(2020, 1, 2, 16, 19, 5, int(200*time.Millisecond), time.UTC), + numExpected: 1001, + lastExpected: time.Date(2020, 1, 2, 15, 18, 39, int(226*time.Millisecond), time.UTC), }, { name: "custom limit with start time set, no end time", args: &AggregatedTradeRequestParams{ Symbol: currency.NewPair(currency.BTC, currency.USDT), - StartTime: time.Date(2020, 11, 18, 12, 0, 0, 0, time.UTC), + StartTime: time.Date(2020, 11, 18, 23, 0, 28, 921, time.UTC), Limit: 1001, }, numExpected: 1001, - lastExpected: time.Date(2020, 11, 18, 13, 0, 0, int(34*time.Millisecond), time.UTC), + lastExpected: time.Date(2020, 11, 18, 23, 1, 33, int(62*time.Millisecond*10), time.UTC), }, { name: "mock recent trades", @@ -1612,7 +1608,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) { } lastTradeTime := result[len(result)-1].TimeStamp if !lastTradeTime.Equal(tt.lastExpected) { - t.Errorf("last trade expected %v, got %v", tt.lastExpected, lastTradeTime) + t.Errorf("last trade expected %v, got %v", tt.lastExpected.UTC(), lastTradeTime.UTC()) } }) } diff --git a/exchanges/kline/kline.go b/exchanges/kline/kline.go index b36bf20d7f3..8ff0de35a40 100644 --- a/exchanges/kline/kline.go +++ b/exchanges/kline/kline.go @@ -331,6 +331,68 @@ func (i *Interval) IntervalsPerYear() float64 { return float64(OneYear.Duration().Nanoseconds()) / float64(i.Duration().Nanoseconds()) } +// ConvertToNewInterval allows the scaling of candles to larger candles +// eg convert OneDay candles to ThreeDay candles, if there are adequate candles +// incomplete candles are NOT converted +// eg an 4 OneDay candles will convert to one ThreeDay candle, skipping the fourth +func ConvertToNewInterval(item *Item, newInterval Interval) (*Item, error) { + if item == nil { + return nil, errNilKline + } + if newInterval <= 0 { + return nil, ErrUnsetInterval + } + if newInterval.Duration() <= item.Interval.Duration() { + return nil, ErrCanOnlyDownscaleCandles + } + if newInterval.Duration()%item.Interval.Duration() != 0 { + return nil, ErrWholeNumberScaling + } + + oldIntervalsPerNewCandle := int64(newInterval / item.Interval) + var candleBundles [][]Candle + var candles []Candle + for i := range item.Candles { + candles = append(candles, item.Candles[i]) + intervalCount := int64(i + 1) + if oldIntervalsPerNewCandle == intervalCount { + candleBundles = append(candleBundles, candles) + candles = []Candle{} + } + } + responseCandle := &Item{ + Exchange: item.Exchange, + Pair: item.Pair, + Asset: item.Asset, + Interval: newInterval, + } + for i := range candleBundles { + var lowest, highest, volume float64 + lowest = candleBundles[i][0].Low + highest = candleBundles[i][0].High + for j := range candleBundles[i] { + volume += candleBundles[i][j].Volume + if candleBundles[i][j].Low < lowest { + lowest = candleBundles[i][j].Low + } + if candleBundles[i][j].High > highest { + lowest = candleBundles[i][j].High + } + volume += candleBundles[i][j].Volume + } + responseCandle.Candles = append(responseCandle.Candles, Candle{ + Time: candleBundles[i][0].Time, + Open: candleBundles[i][0].Open, + High: highest, + Low: lowest, + Close: candleBundles[i][len(candleBundles[i])-1].Close, + Volume: volume, + }) + } + + return responseCandle, nil +} + // CalculateCandleDateRanges will calculate the expected candle data in intervals in a date range // If an API is limited in the amount of candles it can make in a request, it will automatically separate // ranges into the limit diff --git a/exchanges/kline/kline_datastorage.go b/exchanges/kline/kline_datastorage.go index b7e153759f3..e0361b05a17 100644 --- a/exchanges/kline/kline_datastorage.go +++ b/exchanges/kline/kline_datastorage.go @@ -9,6 +9,7 @@ import ( "strconv" "time" + "github.com/gofrs/uuid" "github.com/thrasher-corp/gocryptotrader/currency" "github.com/thrasher-corp/gocryptotrader/database/repository/candle" "github.com/thrasher-corp/gocryptotrader/database/repository/exchange" @@ -33,13 +34,26 @@ func LoadFromDatabase(exchange string, pair currency.Pair, a asset.Item, interva } for x := range retCandle.Candles { + if ret.SourceJobID == uuid.Nil && retCandle.Candles[x].SourceJobID != "" { + ret.SourceJobID, err = uuid.FromString(retCandle.Candles[x].SourceJobID) + if err != nil { + return Item{}, err + } + } + if ret.ValidationJobID == uuid.Nil && retCandle.Candles[x].ValidationJobID != "" { + ret.ValidationJobID, err = uuid.FromString(retCandle.Candles[x].ValidationJobID) + if err != nil { + return Item{}, err + } + } ret.Candles = append(ret.Candles, Candle{ - Time: retCandle.Candles[x].Timestamp, - Open: retCandle.Candles[x].Open, - High: retCandle.Candles[x].High, - Low: retCandle.Candles[x].Low, - Close: retCandle.Candles[x].Close, - Volume: retCandle.Candles[x].Volume, + Time: retCandle.Candles[x].Timestamp, + Open: retCandle.Candles[x].Open, + High: retCandle.Candles[x].High, + Low: retCandle.Candles[x].Low, + Close: retCandle.Candles[x].Close, + Volume: retCandle.Candles[x].Volume, + ValidationIssues: retCandle.Candles[x].ValidationIssues, }) } return ret, nil @@ -50,15 +64,12 @@ func StoreInDatabase(in *Item, force bool) (uint64, error) { if in.Exchange == "" { return 0, errors.New("name cannot be blank") } - - if (in.Pair == currency.Pair{}) { + if in.Pair.IsEmpty() { return 0, errors.New("currency pair cannot be empty") } - - if in.Asset == "" { + if !in.Asset.IsValid() { return 0, errors.New("asset cannot be blank") } - if len(in.Candles) < 1 { return 0, errors.New("candle data is empty") } @@ -77,14 +88,23 @@ func StoreInDatabase(in *Item, force bool) (uint64, error) { } for x := range in.Candles { - databaseCandles.Candles = append(databaseCandles.Candles, candle.Candle{ + can := candle.Candle{ Timestamp: in.Candles[x].Time.Truncate(in.Interval.Duration()), Open: in.Candles[x].Open, High: in.Candles[x].High, Low: in.Candles[x].Low, Close: in.Candles[x].Close, Volume: in.Candles[x].Volume, - }) + } + if in.ValidationJobID != uuid.Nil { + can.ValidationJobID = in.ValidationJobID.String() + can.ValidationIssues = in.Candles[x].ValidationIssues + } + if in.SourceJobID != uuid.Nil { + can.SourceJobID = in.SourceJobID.String() + } + + databaseCandles.Candles = append(databaseCandles.Candles, can) } if force { _, err := candle.DeleteCandles(&databaseCandles) diff --git a/exchanges/kline/kline_test.go b/exchanges/kline/kline_test.go index dfb5cc7eaf8..f0964f95a95 100644 --- a/exchanges/kline/kline_test.go +++ b/exchanges/kline/kline_test.go @@ -890,3 +890,90 @@ func BenchmarkJustifyIntervalTimeStoringUnixValues2(b *testing.B) { } } } + +func TestConvertToNewInterval(t *testing.T) { + _, err := ConvertToNewInterval(nil, OneMin) + if !errors.Is(err, errNilKline) { + t.Errorf("received '%v' expectec '%v'", err, errNilKline) + } + + old := &Item{ + Exchange: "lol", + Pair: currency.NewPair(currency.BTC, currency.USDT), + Asset: asset.Spot, + Interval: OneDay, + Candles: []Candle{ + { + Time: time.Now(), + Open: 1337, + High: 1339, + Low: 1336, + Close: 1338, + Volume: 1337, + }, + { + Time: time.Now().AddDate(0, 0, 1), + Open: 1338, + High: 2000, + Low: 1332, + Close: 1696, + Volume: 6420, + }, + { + Time: time.Now().AddDate(0, 0, 2), + Open: 1696, + High: 1998, + Low: 1337, + Close: 6969, + Volume: 2520, + }, + }, + } + + _, err = ConvertToNewInterval(old, 0) + if !errors.Is(err, ErrUnsetInterval) { + t.Errorf("received '%v' expectec '%v'", err, ErrUnsetInterval) + } + _, err = ConvertToNewInterval(old, OneMin) + if !errors.Is(err, ErrCanOnlyDownscaleCandles) { + t.Errorf("received '%v' expectec '%v'", err, ErrCanOnlyDownscaleCandles) + } + old.Interval = ThreeDay + _, err = ConvertToNewInterval(old, OneWeek) + if !errors.Is(err, ErrWholeNumberScaling) { + t.Errorf("received '%v' expectec '%v'", err, ErrWholeNumberScaling) + } + + old.Interval = OneDay + newInterval := ThreeDay + newCandle, err := ConvertToNewInterval(old, newInterval) + if !errors.Is(err, nil) { + t.Errorf("received '%v' expectec '%v'", err, nil) + } + if len(newCandle.Candles) != 1 { + t.Error("expected one candle") + } + if newCandle.Candles[0].Open != 1337 && + newCandle.Candles[0].High != 2000 && + newCandle.Candles[0].Low != 1332 && + newCandle.Candles[0].Close != 6969 && + newCandle.Candles[0].Volume != (2520+6420+1337) { + t.Error("unexpected updoot") + } + + old.Candles = append(old.Candles, Candle{ + Time: time.Now().AddDate(0, 0, 3), + Open: 6969, + High: 1998, + Low: 2342, + Close: 7777, + Volume: 111, + }) + newCandle, err = ConvertToNewInterval(old, newInterval) + if !errors.Is(err, nil) { + t.Errorf("received '%v' expectec '%v'", err, nil) + } + if len(newCandle.Candles) != 1 { + t.Error("expected one candle") + } +} diff --git a/exchanges/kline/kline_types.go b/exchanges/kline/kline_types.go index fd364299a91..16fc949d52b 100644 --- a/exchanges/kline/kline_types.go +++ b/exchanges/kline/kline_types.go @@ -4,6 +4,7 @@ import ( "errors" "time" + "github.com/gofrs/uuid" "github.com/thrasher-corp/gocryptotrader/currency" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" ) @@ -39,12 +40,15 @@ const ( ) var ( - // ErrMissingCandleData is an error for missing candle data - ErrMissingCandleData = errors.New("missing candle data") // ErrUnsetInterval is an error for date range calculation ErrUnsetInterval = errors.New("cannot calculate range, interval unset") // ErrUnsupportedInterval returns when the provided interval is not supported by an exchange ErrUnsupportedInterval = errors.New("interval unsupported by exchange") + // ErrCanOnlyDownscaleCandles returns when attempting to upscale candles + ErrCanOnlyDownscaleCandles = errors.New("interval must be a longer duration to scale") + // ErrWholeNumberScaling returns when old interval data cannot neatly fit into new interval size + ErrWholeNumberScaling = errors.New("new interval must scale properly into new candle") + errNilKline = errors.New("kline item is nil") // SupportedIntervals is a list of all supported intervals SupportedIntervals = []Interval{ @@ -74,21 +78,24 @@ var ( // Item holds all the relevant information for internal kline elements type Item struct { - Exchange string - Pair currency.Pair - Asset asset.Item - Interval Interval - Candles []Candle + Exchange string + Pair currency.Pair + Asset asset.Item + Interval Interval + Candles []Candle + SourceJobID uuid.UUID + ValidationJobID uuid.UUID } // Candle holds historic rate information. type Candle struct { - Time time.Time - Open float64 - High float64 - Low float64 - Close float64 - Volume float64 + Time time.Time + Open float64 + High float64 + Low float64 + Close float64 + Volume float64 + ValidationIssues string } // ByDate allows for sorting candle entries by date diff --git a/exchanges/okgroup/okgroup_wrapper.go b/exchanges/okgroup/okgroup_wrapper.go index 31949673d4b..e0e9c43b335 100644 --- a/exchanges/okgroup/okgroup_wrapper.go +++ b/exchanges/okgroup/okgroup_wrapper.go @@ -736,7 +736,7 @@ func (o *OKGroup) GetHistoricCandlesExtended(pair currency.Pair, a asset.Item, s dates.SetHasDataFromCandles(ret.Candles) summary := dates.DataSummary(false) if len(summary) > 0 { - log.Warnf(log.ExchangeSys, "%v - %v", o.ExchangeName, summary) + log.Warnf(log.ExchangeSys, "%v - %v", o.Base.Name, summary) } ret.RemoveDuplicates() ret.RemoveOutsideRange(start, end) diff --git a/exchanges/request/request.go b/exchanges/request/request.go index da07ca53c10..c05bb4bc91d 100644 --- a/exchanges/request/request.go +++ b/exchanges/request/request.go @@ -88,7 +88,6 @@ func (i *Item) validateRequest(ctx context.Context, r *Requester) (*http.Request return nil, errors.New("header response is nil") } } - req, err := http.NewRequestWithContext(ctx, i.Method, i.Path, i.Body) if err != nil { return nil, err @@ -110,7 +109,6 @@ func (r *Requester) doRequest(req *http.Request, p *Item) error { if p == nil { return errors.New("request item cannot be nil") } - if p.Verbose { log.Debugf(log.RequestSys, "%s request path: %s", diff --git a/exchanges/trade/trade.go b/exchanges/trade/trade.go index 108d74f8e23..f85c827367e 100644 --- a/exchanges/trade/trade.go +++ b/exchanges/trade/trade.go @@ -129,6 +129,9 @@ func GetTradesInRange(exchangeName, assetType, base, quote string, startDate, en if exchangeName == "" || assetType == "" || base == "" || quote == "" || startDate.IsZero() || endDate.IsZero() { return nil, errors.New("invalid arguments received") } + if !database.DB.IsConnected() { + return nil, fmt.Errorf("cannot process trades in range %s-%s as %w", startDate, endDate, database.ErrDatabaseNotConnected) + } results, err := tradesql.GetInRange(exchangeName, assetType, base, quote, startDate, endDate) if err != nil { return nil, err diff --git a/gctrpc/rpc.pb.go b/gctrpc/rpc.pb.go index 2206219d443..c4239c0f72e 100644 --- a/gctrpc/rpc.pb.go +++ b/gctrpc/rpc.pb.go @@ -9050,18 +9050,25 @@ type UpsertDataHistoryJobRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Nickname string `protobuf:"bytes,1,opt,name=nickname,proto3" json:"nickname,omitempty"` - Exchange string `protobuf:"bytes,2,opt,name=exchange,proto3" json:"exchange,omitempty"` - Asset string `protobuf:"bytes,3,opt,name=asset,proto3" json:"asset,omitempty"` - Pair *CurrencyPair `protobuf:"bytes,4,opt,name=pair,proto3" json:"pair,omitempty"` - StartDate string `protobuf:"bytes,5,opt,name=start_date,json=startDate,proto3" json:"start_date,omitempty"` - EndDate string `protobuf:"bytes,6,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty"` - Interval int64 `protobuf:"varint,7,opt,name=interval,proto3" json:"interval,omitempty"` - RequestSizeLimit int64 `protobuf:"varint,8,opt,name=request_size_limit,json=requestSizeLimit,proto3" json:"request_size_limit,omitempty"` - DataType int64 `protobuf:"varint,9,opt,name=data_type,json=dataType,proto3" json:"data_type,omitempty"` - MaxRetryAttempts int64 `protobuf:"varint,10,opt,name=max_retry_attempts,json=maxRetryAttempts,proto3" json:"max_retry_attempts,omitempty"` - BatchSize int64 `protobuf:"varint,11,opt,name=batch_size,json=batchSize,proto3" json:"batch_size,omitempty"` - InsertOnly bool `protobuf:"varint,12,opt,name=insert_only,json=insertOnly,proto3" json:"insert_only,omitempty"` + Nickname string `protobuf:"bytes,1,opt,name=nickname,proto3" json:"nickname,omitempty"` + Exchange string `protobuf:"bytes,2,opt,name=exchange,proto3" json:"exchange,omitempty"` + Asset string `protobuf:"bytes,3,opt,name=asset,proto3" json:"asset,omitempty"` + Pair *CurrencyPair `protobuf:"bytes,4,opt,name=pair,proto3" json:"pair,omitempty"` + StartDate string `protobuf:"bytes,5,opt,name=start_date,json=startDate,proto3" json:"start_date,omitempty"` + EndDate string `protobuf:"bytes,6,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty"` + Interval int64 `protobuf:"varint,7,opt,name=interval,proto3" json:"interval,omitempty"` + RequestSizeLimit int64 `protobuf:"varint,8,opt,name=request_size_limit,json=requestSizeLimit,proto3" json:"request_size_limit,omitempty"` + DataType int64 `protobuf:"varint,9,opt,name=data_type,json=dataType,proto3" json:"data_type,omitempty"` + MaxRetryAttempts int64 `protobuf:"varint,10,opt,name=max_retry_attempts,json=maxRetryAttempts,proto3" json:"max_retry_attempts,omitempty"` + BatchSize int64 `protobuf:"varint,11,opt,name=batch_size,json=batchSize,proto3" json:"batch_size,omitempty"` + InsertOnly bool `protobuf:"varint,12,opt,name=insert_only,json=insertOnly,proto3" json:"insert_only,omitempty"` + ConversionInterval int64 `protobuf:"varint,13,opt,name=conversion_interval,json=conversionInterval,proto3" json:"conversion_interval,omitempty"` + OverwriteExistingData bool `protobuf:"varint,14,opt,name=overwrite_existing_data,json=overwriteExistingData,proto3" json:"overwrite_existing_data,omitempty"` + PrerequisiteJobNickname string `protobuf:"bytes,15,opt,name=prerequisite_job_nickname,json=prerequisiteJobNickname,proto3" json:"prerequisite_job_nickname,omitempty"` + DecimalPlaceComparison int64 `protobuf:"varint,16,opt,name=decimal_place_comparison,json=decimalPlaceComparison,proto3" json:"decimal_place_comparison,omitempty"` + SecondaryExchangeName string `protobuf:"bytes,17,opt,name=secondary_exchange_name,json=secondaryExchangeName,proto3" json:"secondary_exchange_name,omitempty"` + IssueTolerancePercentage float64 `protobuf:"fixed64,18,opt,name=issue_tolerance_percentage,json=issueTolerancePercentage,proto3" json:"issue_tolerance_percentage,omitempty"` + ReplaceOnIssue bool `protobuf:"varint,19,opt,name=replace_on_issue,json=replaceOnIssue,proto3" json:"replace_on_issue,omitempty"` } func (x *UpsertDataHistoryJobRequest) Reset() { @@ -9180,6 +9187,149 @@ func (x *UpsertDataHistoryJobRequest) GetInsertOnly() bool { return false } +func (x *UpsertDataHistoryJobRequest) GetConversionInterval() int64 { + if x != nil { + return x.ConversionInterval + } + return 0 +} + +func (x *UpsertDataHistoryJobRequest) GetOverwriteExistingData() bool { + if x != nil { + return x.OverwriteExistingData + } + return false +} + +func (x *UpsertDataHistoryJobRequest) GetPrerequisiteJobNickname() string { + if x != nil { + return x.PrerequisiteJobNickname + } + return "" +} + +func (x *UpsertDataHistoryJobRequest) GetDecimalPlaceComparison() int64 { + if x != nil { + return x.DecimalPlaceComparison + } + return 0 +} + +func (x *UpsertDataHistoryJobRequest) GetSecondaryExchangeName() string { + if x != nil { + return x.SecondaryExchangeName + } + return "" +} + +func (x *UpsertDataHistoryJobRequest) GetIssueTolerancePercentage() float64 { + if x != nil { + return x.IssueTolerancePercentage + } + return 0 +} + +func (x *UpsertDataHistoryJobRequest) GetReplaceOnIssue() bool { + if x != nil { + return x.ReplaceOnIssue + } + return false +} + +type InsertSequentialJobsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Jobs []*UpsertDataHistoryJobRequest `protobuf:"bytes,1,rep,name=jobs,proto3" json:"jobs,omitempty"` +} + +func (x *InsertSequentialJobsRequest) Reset() { + *x = InsertSequentialJobsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[146] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InsertSequentialJobsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InsertSequentialJobsRequest) ProtoMessage() {} + +func (x *InsertSequentialJobsRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[146] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InsertSequentialJobsRequest.ProtoReflect.Descriptor instead. +func (*InsertSequentialJobsRequest) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{146} +} + +func (x *InsertSequentialJobsRequest) GetJobs() []*UpsertDataHistoryJobRequest { + if x != nil { + return x.Jobs + } + return nil +} + +type InsertSequentialJobsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Jobs []*UpsertDataHistoryJobResponse `protobuf:"bytes,1,rep,name=jobs,proto3" json:"jobs,omitempty"` +} + +func (x *InsertSequentialJobsResponse) Reset() { + *x = InsertSequentialJobsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[147] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InsertSequentialJobsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InsertSequentialJobsResponse) ProtoMessage() {} + +func (x *InsertSequentialJobsResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[147] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InsertSequentialJobsResponse.ProtoReflect.Descriptor instead. +func (*InsertSequentialJobsResponse) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{147} +} + +func (x *InsertSequentialJobsResponse) GetJobs() []*UpsertDataHistoryJobResponse { + if x != nil { + return x.Jobs + } + return nil +} + type UpsertDataHistoryJobResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -9192,7 +9342,7 @@ type UpsertDataHistoryJobResponse struct { func (x *UpsertDataHistoryJobResponse) Reset() { *x = UpsertDataHistoryJobResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[146] + mi := &file_rpc_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9205,7 +9355,7 @@ func (x *UpsertDataHistoryJobResponse) String() string { func (*UpsertDataHistoryJobResponse) ProtoMessage() {} func (x *UpsertDataHistoryJobResponse) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[146] + mi := &file_rpc_proto_msgTypes[148] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9218,7 +9368,7 @@ func (x *UpsertDataHistoryJobResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpsertDataHistoryJobResponse.ProtoReflect.Descriptor instead. func (*UpsertDataHistoryJobResponse) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{146} + return file_rpc_proto_rawDescGZIP(), []int{148} } func (x *UpsertDataHistoryJobResponse) GetMessage() string { @@ -9248,7 +9398,7 @@ type GetDataHistoryJobDetailsRequest struct { func (x *GetDataHistoryJobDetailsRequest) Reset() { *x = GetDataHistoryJobDetailsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[147] + mi := &file_rpc_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9261,7 +9411,7 @@ func (x *GetDataHistoryJobDetailsRequest) String() string { func (*GetDataHistoryJobDetailsRequest) ProtoMessage() {} func (x *GetDataHistoryJobDetailsRequest) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[147] + mi := &file_rpc_proto_msgTypes[149] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9274,7 +9424,7 @@ func (x *GetDataHistoryJobDetailsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDataHistoryJobDetailsRequest.ProtoReflect.Descriptor instead. func (*GetDataHistoryJobDetailsRequest) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{147} + return file_rpc_proto_rawDescGZIP(), []int{149} } func (x *GetDataHistoryJobDetailsRequest) GetId() string { @@ -9303,27 +9453,34 @@ type DataHistoryJob struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` - Exchange string `protobuf:"bytes,3,opt,name=exchange,proto3" json:"exchange,omitempty"` - Asset string `protobuf:"bytes,4,opt,name=asset,proto3" json:"asset,omitempty"` - Pair *CurrencyPair `protobuf:"bytes,5,opt,name=pair,proto3" json:"pair,omitempty"` - StartDate string `protobuf:"bytes,6,opt,name=start_date,json=startDate,proto3" json:"start_date,omitempty"` - EndDate string `protobuf:"bytes,7,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty"` - Interval int64 `protobuf:"varint,8,opt,name=interval,proto3" json:"interval,omitempty"` - RequestSizeLimit int64 `protobuf:"varint,9,opt,name=request_size_limit,json=requestSizeLimit,proto3" json:"request_size_limit,omitempty"` - MaxRetryAttempts int64 `protobuf:"varint,10,opt,name=max_retry_attempts,json=maxRetryAttempts,proto3" json:"max_retry_attempts,omitempty"` - BatchSize int64 `protobuf:"varint,11,opt,name=batch_size,json=batchSize,proto3" json:"batch_size,omitempty"` - Status string `protobuf:"bytes,12,opt,name=status,proto3" json:"status,omitempty"` - DataType string `protobuf:"bytes,13,opt,name=data_type,json=dataType,proto3" json:"data_type,omitempty"` - JobResults []*DataHistoryJobResult `protobuf:"bytes,14,rep,name=job_results,json=jobResults,proto3" json:"job_results,omitempty"` - ResultSummaries []string `protobuf:"bytes,15,rep,name=result_summaries,json=resultSummaries,proto3" json:"result_summaries,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` + Exchange string `protobuf:"bytes,3,opt,name=exchange,proto3" json:"exchange,omitempty"` + Asset string `protobuf:"bytes,4,opt,name=asset,proto3" json:"asset,omitempty"` + Pair *CurrencyPair `protobuf:"bytes,5,opt,name=pair,proto3" json:"pair,omitempty"` + StartDate string `protobuf:"bytes,6,opt,name=start_date,json=startDate,proto3" json:"start_date,omitempty"` + EndDate string `protobuf:"bytes,7,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty"` + Interval int64 `protobuf:"varint,8,opt,name=interval,proto3" json:"interval,omitempty"` + RequestSizeLimit int64 `protobuf:"varint,9,opt,name=request_size_limit,json=requestSizeLimit,proto3" json:"request_size_limit,omitempty"` + MaxRetryAttempts int64 `protobuf:"varint,10,opt,name=max_retry_attempts,json=maxRetryAttempts,proto3" json:"max_retry_attempts,omitempty"` + BatchSize int64 `protobuf:"varint,11,opt,name=batch_size,json=batchSize,proto3" json:"batch_size,omitempty"` + Status string `protobuf:"bytes,12,opt,name=status,proto3" json:"status,omitempty"` + DataType string `protobuf:"bytes,13,opt,name=data_type,json=dataType,proto3" json:"data_type,omitempty"` + ConversionInterval int64 `protobuf:"varint,14,opt,name=conversion_interval,json=conversionInterval,proto3" json:"conversion_interval,omitempty"` + OverwriteExistingData bool `protobuf:"varint,15,opt,name=overwrite_existing_data,json=overwriteExistingData,proto3" json:"overwrite_existing_data,omitempty"` + PrerequisiteJobNickname string `protobuf:"bytes,16,opt,name=prerequisite_job_nickname,json=prerequisiteJobNickname,proto3" json:"prerequisite_job_nickname,omitempty"` + DecimalPlaceComparison int64 `protobuf:"varint,17,opt,name=decimal_place_comparison,json=decimalPlaceComparison,proto3" json:"decimal_place_comparison,omitempty"` + SecondaryExchangeName string `protobuf:"bytes,18,opt,name=secondary_exchange_name,json=secondaryExchangeName,proto3" json:"secondary_exchange_name,omitempty"` + IssueTolerancePercentage float64 `protobuf:"fixed64,19,opt,name=issue_tolerance_percentage,json=issueTolerancePercentage,proto3" json:"issue_tolerance_percentage,omitempty"` + ReplaceOnIssue bool `protobuf:"varint,20,opt,name=replace_on_issue,json=replaceOnIssue,proto3" json:"replace_on_issue,omitempty"` + JobResults []*DataHistoryJobResult `protobuf:"bytes,21,rep,name=job_results,json=jobResults,proto3" json:"job_results,omitempty"` + ResultSummaries []string `protobuf:"bytes,22,rep,name=result_summaries,json=resultSummaries,proto3" json:"result_summaries,omitempty"` } func (x *DataHistoryJob) Reset() { *x = DataHistoryJob{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[148] + mi := &file_rpc_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9336,7 +9493,7 @@ func (x *DataHistoryJob) String() string { func (*DataHistoryJob) ProtoMessage() {} func (x *DataHistoryJob) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[148] + mi := &file_rpc_proto_msgTypes[150] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9349,7 +9506,7 @@ func (x *DataHistoryJob) ProtoReflect() protoreflect.Message { // Deprecated: Use DataHistoryJob.ProtoReflect.Descriptor instead. func (*DataHistoryJob) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{148} + return file_rpc_proto_rawDescGZIP(), []int{150} } func (x *DataHistoryJob) GetId() string { @@ -9443,6 +9600,55 @@ func (x *DataHistoryJob) GetDataType() string { return "" } +func (x *DataHistoryJob) GetConversionInterval() int64 { + if x != nil { + return x.ConversionInterval + } + return 0 +} + +func (x *DataHistoryJob) GetOverwriteExistingData() bool { + if x != nil { + return x.OverwriteExistingData + } + return false +} + +func (x *DataHistoryJob) GetPrerequisiteJobNickname() string { + if x != nil { + return x.PrerequisiteJobNickname + } + return "" +} + +func (x *DataHistoryJob) GetDecimalPlaceComparison() int64 { + if x != nil { + return x.DecimalPlaceComparison + } + return 0 +} + +func (x *DataHistoryJob) GetSecondaryExchangeName() string { + if x != nil { + return x.SecondaryExchangeName + } + return "" +} + +func (x *DataHistoryJob) GetIssueTolerancePercentage() float64 { + if x != nil { + return x.IssueTolerancePercentage + } + return 0 +} + +func (x *DataHistoryJob) GetReplaceOnIssue() bool { + if x != nil { + return x.ReplaceOnIssue + } + return false +} + func (x *DataHistoryJob) GetJobResults() []*DataHistoryJobResult { if x != nil { return x.JobResults @@ -9472,7 +9678,7 @@ type DataHistoryJobResult struct { func (x *DataHistoryJobResult) Reset() { *x = DataHistoryJobResult{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[149] + mi := &file_rpc_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9485,7 +9691,7 @@ func (x *DataHistoryJobResult) String() string { func (*DataHistoryJobResult) ProtoMessage() {} func (x *DataHistoryJobResult) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[149] + mi := &file_rpc_proto_msgTypes[151] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9498,7 +9704,7 @@ func (x *DataHistoryJobResult) ProtoReflect() protoreflect.Message { // Deprecated: Use DataHistoryJobResult.ProtoReflect.Descriptor instead. func (*DataHistoryJobResult) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{149} + return file_rpc_proto_rawDescGZIP(), []int{151} } func (x *DataHistoryJobResult) GetStartDate() string { @@ -9547,7 +9753,7 @@ type DataHistoryJobs struct { func (x *DataHistoryJobs) Reset() { *x = DataHistoryJobs{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[150] + mi := &file_rpc_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9560,7 +9766,7 @@ func (x *DataHistoryJobs) String() string { func (*DataHistoryJobs) ProtoMessage() {} func (x *DataHistoryJobs) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[150] + mi := &file_rpc_proto_msgTypes[152] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9573,7 +9779,7 @@ func (x *DataHistoryJobs) ProtoReflect() protoreflect.Message { // Deprecated: Use DataHistoryJobs.ProtoReflect.Descriptor instead. func (*DataHistoryJobs) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{150} + return file_rpc_proto_rawDescGZIP(), []int{152} } func (x *DataHistoryJobs) GetResults() []*DataHistoryJob { @@ -9595,7 +9801,7 @@ type GetDataHistoryJobsBetweenRequest struct { func (x *GetDataHistoryJobsBetweenRequest) Reset() { *x = GetDataHistoryJobsBetweenRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[151] + mi := &file_rpc_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9608,7 +9814,7 @@ func (x *GetDataHistoryJobsBetweenRequest) String() string { func (*GetDataHistoryJobsBetweenRequest) ProtoMessage() {} func (x *GetDataHistoryJobsBetweenRequest) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[151] + mi := &file_rpc_proto_msgTypes[153] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9621,7 +9827,7 @@ func (x *GetDataHistoryJobsBetweenRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDataHistoryJobsBetweenRequest.ProtoReflect.Descriptor instead. func (*GetDataHistoryJobsBetweenRequest) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{151} + return file_rpc_proto_rawDescGZIP(), []int{153} } func (x *GetDataHistoryJobsBetweenRequest) GetStartDate() string { @@ -9638,6 +9844,124 @@ func (x *GetDataHistoryJobsBetweenRequest) GetEndDate() string { return "" } +type SetDataHistoryJobStatusRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` + Status int64 `protobuf:"varint,3,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *SetDataHistoryJobStatusRequest) Reset() { + *x = SetDataHistoryJobStatusRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[154] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetDataHistoryJobStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetDataHistoryJobStatusRequest) ProtoMessage() {} + +func (x *SetDataHistoryJobStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[154] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetDataHistoryJobStatusRequest.ProtoReflect.Descriptor instead. +func (*SetDataHistoryJobStatusRequest) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{154} +} + +func (x *SetDataHistoryJobStatusRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SetDataHistoryJobStatusRequest) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *SetDataHistoryJobStatusRequest) GetStatus() int64 { + if x != nil { + return x.Status + } + return 0 +} + +type UpdateDataHistoryJobPrerequisiteRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Nickname string `protobuf:"bytes,1,opt,name=nickname,proto3" json:"nickname,omitempty"` + PrerequisiteJobNickname string `protobuf:"bytes,2,opt,name=prerequisite_job_nickname,json=prerequisiteJobNickname,proto3" json:"prerequisite_job_nickname,omitempty"` +} + +func (x *UpdateDataHistoryJobPrerequisiteRequest) Reset() { + *x = UpdateDataHistoryJobPrerequisiteRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[155] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateDataHistoryJobPrerequisiteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateDataHistoryJobPrerequisiteRequest) ProtoMessage() {} + +func (x *UpdateDataHistoryJobPrerequisiteRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[155] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateDataHistoryJobPrerequisiteRequest.ProtoReflect.Descriptor instead. +func (*UpdateDataHistoryJobPrerequisiteRequest) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{155} +} + +func (x *UpdateDataHistoryJobPrerequisiteRequest) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *UpdateDataHistoryJobPrerequisiteRequest) GetPrerequisiteJobNickname() string { + if x != nil { + return x.PrerequisiteJobNickname + } + return "" +} + type CancelBatchOrdersResponse_Orders struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -9649,7 +9973,7 @@ type CancelBatchOrdersResponse_Orders struct { func (x *CancelBatchOrdersResponse_Orders) Reset() { *x = CancelBatchOrdersResponse_Orders{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[162] + mi := &file_rpc_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9662,7 +9986,7 @@ func (x *CancelBatchOrdersResponse_Orders) String() string { func (*CancelBatchOrdersResponse_Orders) ProtoMessage() {} func (x *CancelBatchOrdersResponse_Orders) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[162] + mi := &file_rpc_proto_msgTypes[166] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9697,7 +10021,7 @@ type CancelAllOrdersResponse_Orders struct { func (x *CancelAllOrdersResponse_Orders) Reset() { *x = CancelAllOrdersResponse_Orders{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[164] + mi := &file_rpc_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9710,7 +10034,7 @@ func (x *CancelAllOrdersResponse_Orders) String() string { func (*CancelAllOrdersResponse_Orders) ProtoMessage() {} func (x *CancelAllOrdersResponse_Orders) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[164] + mi := &file_rpc_proto_msgTypes[168] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10923,7 +11247,7 @@ var file_rpc_proto_rawDesc = []byte{ 0x12, 0x1a, 0x0a, 0x08, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x22, 0xa4, 0x03, 0x0a, 0x1b, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, + 0x61, 0x74, 0x75, 0x73, 0x22, 0xa3, 0x06, 0x0a, 0x1b, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, @@ -10949,51 +11273,110 @@ var file_rpc_proto_rawDesc = []byte{ 0x61, 0x74, 0x63, 0x68, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0a, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x4f, 0x0a, 0x1c, 0x55, - 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x6f, 0x0a, 0x1f, - 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, - 0x62, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x66, - 0x75, 0x6c, 0x6c, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0b, 0x66, 0x75, 0x6c, 0x6c, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x88, 0x04, - 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, + 0x0a, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x2f, 0x0a, 0x13, 0x63, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x17, + 0x6f, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x6f, + 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x3a, 0x0a, 0x19, 0x70, 0x72, 0x65, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x73, 0x69, 0x74, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x70, 0x72, 0x65, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x73, 0x69, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x38, 0x0a, 0x18, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x16, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x50, 0x6c, 0x61, 0x63, 0x65, + 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x17, 0x73, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x1a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, 0x74, 0x6f, 0x6c, 0x65, + 0x72, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, + 0x18, 0x12, 0x20, 0x01, 0x28, 0x01, 0x52, 0x18, 0x69, 0x73, 0x73, 0x75, 0x65, 0x54, 0x6f, 0x6c, + 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, + 0x12, 0x28, 0x0a, 0x10, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x6e, 0x5f, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x4f, 0x6e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x22, 0x56, 0x0a, 0x1b, 0x49, 0x6e, + 0x73, 0x65, 0x72, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4a, 0x6f, + 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x37, 0x0a, 0x04, 0x6a, 0x6f, 0x62, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x04, 0x6a, 0x6f, + 0x62, 0x73, 0x22, 0x58, 0x0a, 0x1c, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x53, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x38, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, + 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x4f, 0x0a, 0x1c, + 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x6f, 0x0a, + 0x1f, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, + 0x6f, 0x62, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x73, 0x65, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x12, 0x28, - 0x0a, 0x04, 0x70, 0x61, 0x69, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, - 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x61, - 0x69, 0x72, 0x52, 0x04, 0x70, 0x61, 0x69, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x64, - 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x44, 0x61, - 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2c, - 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2c, 0x0a, 0x12, - 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, - 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x74, - 0x72, 0x79, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, - 0x74, 0x63, 0x68, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, - 0x62, 0x61, 0x74, 0x63, 0x68, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x3d, - 0x0a, 0x0b, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x0e, 0x20, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, + 0x66, 0x75, 0x6c, 0x6c, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0b, 0x66, 0x75, 0x6c, 0x6c, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x87, + 0x07, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, + 0x62, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x73, + 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x12, + 0x28, 0x0a, 0x04, 0x70, 0x61, 0x69, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x50, + 0x61, 0x69, 0x72, 0x52, 0x04, 0x70, 0x61, 0x69, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, + 0x64, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x44, + 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, + 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2c, 0x0a, + 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x6d, + 0x70, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x52, 0x65, + 0x74, 0x72, 0x79, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, + 0x61, 0x74, 0x63, 0x68, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x2f, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x63, 0x6f, + 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, + 0x12, 0x36, 0x0a, 0x17, 0x6f, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x65, 0x78, + 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x15, 0x6f, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, 0x69, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x3a, 0x0a, 0x19, 0x70, 0x72, 0x65, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x73, 0x69, 0x74, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x69, 0x63, + 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x70, 0x72, 0x65, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x73, 0x69, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x4e, 0x69, 0x63, 0x6b, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x5f, + 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, + 0x18, 0x11, 0x20, 0x01, 0x28, 0x03, 0x52, 0x16, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x50, + 0x6c, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x12, 0x36, + 0x0a, 0x17, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x15, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x1a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, + 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x61, 0x67, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x01, 0x52, 0x18, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, + 0x6f, 0x6e, 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, + 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x4f, 0x6e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x3d, + 0x0a, 0x0b, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0a, 0x6a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x69, 0x65, - 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x53, + 0x73, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x69, 0x65, 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x14, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, @@ -11014,643 +11397,668 @@ var file_rpc_proto_rawDesc = []byte{ 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x44, 0x61, 0x74, 0x65, 0x32, 0x82, - 0x4f, 0x0a, 0x0e, 0x47, 0x6f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x64, 0x65, - 0x72, 0x12, 0x4f, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x67, - 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, - 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x69, 0x6e, - 0x66, 0x6f, 0x12, 0x67, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x73, 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, - 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, - 0x73, 0x62, 0x73, 0x79, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, - 0x74, 0x73, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x68, 0x0a, 0x0f, 0x45, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x53, - 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, - 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x75, 0x62, 0x73, - 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x6a, 0x0a, 0x10, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, - 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, - 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, - 0x2f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, - 0x6d, 0x12, 0x6f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x50, 0x43, 0x45, 0x6e, 0x64, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, - 0x74, 0x52, 0x50, 0x43, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, - 0x74, 0x52, 0x50, 0x43, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, - 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x72, 0x70, 0x63, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x73, 0x12, 0x93, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, - 0x27, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, - 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, - 0x67, 0x65, 0x74, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x63, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x45, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, - 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, - 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x6e, 0x0a, - 0x0f, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, - 0x63, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x44, 0x61, 0x74, 0x65, 0x22, 0x64, + 0x0a, 0x1e, 0x53, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x22, 0x81, 0x01, 0x0a, 0x27, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, + 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x65, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x73, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x19, + 0x70, 0x72, 0x65, 0x72, 0x65, 0x71, 0x75, 0x69, 0x73, 0x69, 0x74, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x5f, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x17, 0x70, 0x72, 0x65, 0x72, 0x65, 0x71, 0x75, 0x69, 0x73, 0x69, 0x74, 0x65, 0x4a, 0x6f, 0x62, + 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xab, 0x50, 0x0a, 0x0e, 0x47, 0x6f, 0x43, + 0x72, 0x79, 0x70, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x64, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x07, 0x47, + 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, + 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, + 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x67, 0x0a, 0x0d, + 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x1c, 0x2e, + 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x73, 0x62, 0x73, 0x79, 0x74, 0x65, + 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x73, 0x75, 0x62, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x68, 0x0a, 0x0f, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, + 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, + 0x6a, 0x0a, 0x10, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, - 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x65, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, - 0x0f, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, - 0x63, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, - 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, - 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x69, 0x6e, - 0x66, 0x6f, 0x12, 0x73, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x4f, 0x54, 0x50, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, - 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x4f, 0x54, 0x50, 0x52, 0x65, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x6f, 0x74, 0x70, 0x12, 0x73, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x45, 0x78, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x54, 0x50, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x1e, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x4f, 0x54, 0x50, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, + 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x69, 0x73, 0x61, 0x62, + 0x6c, 0x65, 0x73, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x6f, 0x0a, 0x0f, 0x47, + 0x65, 0x74, 0x52, 0x50, 0x43, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x1e, + 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x50, 0x43, 0x45, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, + 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x50, 0x43, 0x45, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, + 0x72, 0x70, 0x63, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x93, 0x01, 0x0a, + 0x18, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x27, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x63, 0x6f, 0x6d, + 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, + 0x72, 0x73, 0x12, 0x63, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, + 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x6e, 0x0a, 0x0f, 0x44, 0x69, 0x73, 0x61, 0x62, + 0x6c, 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x45, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, + 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, + 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x65, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x45, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x45, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x4f, 0x54, 0x50, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x6e, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, - 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6f, 0x74, 0x70, 0x73, 0x12, 0x6c, 0x0a, 0x0e, - 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x22, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x45, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, - 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x65, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x57, 0x0a, 0x09, 0x47, 0x65, - 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x69, 0x63, 0x6b, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x12, 0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, - 0x3a, 0x01, 0x2a, 0x12, 0x5b, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, - 0x73, 0x12, 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, - 0x63, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, - 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, - 0x12, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, - 0x12, 0x63, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, - 0x12, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, - 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, - 0x6f, 0x6b, 0x3a, 0x01, 0x2a, 0x12, 0x67, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, - 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, - 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, - 0x2f, 0x67, 0x65, 0x74, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x6b, - 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, - 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x71, 0x0a, 0x11, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x73, 0x0a, 0x12, + 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x54, 0x50, 0x43, 0x6f, + 0x64, 0x65, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x69, 0x63, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x54, 0x50, 0x52, 0x65, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, + 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6f, 0x74, + 0x70, 0x12, 0x73, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x4f, 0x54, 0x50, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x54, 0x50, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x54, 0x50, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x6f, 0x74, 0x70, 0x73, 0x12, 0x6c, 0x0a, 0x0e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, + 0x76, 0x31, 0x2f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x57, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, + 0x72, 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, + 0x63, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22, 0x0d, 0x2f, 0x76, 0x31, + 0x2f, 0x67, 0x65, 0x74, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x5b, 0x0a, + 0x0a, 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x19, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x76, 0x31, 0x2f, + 0x67, 0x65, 0x74, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x63, 0x0a, 0x0c, 0x47, 0x65, + 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x12, 0x1b, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, + 0x67, 0x65, 0x74, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, 0x01, 0x2a, 0x12, + 0x67, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x73, + 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, + 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, + 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x6b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x71, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x61, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x79, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x79, - 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, - 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, - 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x69, 0x6e, 0x66, - 0x6f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x30, 0x01, 0x12, 0x57, 0x0a, 0x09, 0x47, 0x65, 0x74, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x0f, 0x12, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x63, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, - 0x69, 0x6f, 0x12, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, - 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x70, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, 0x7f, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x22, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, - 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x76, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x50, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x72, 0x74, - 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x64, 0x70, 0x6f, 0x72, - 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x01, 0x2a, - 0x12, 0x7f, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, - 0x6c, 0x69, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, - 0x6c, 0x69, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, - 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x01, - 0x2a, 0x12, 0x77, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x65, 0x78, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x65, 0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x65, 0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x66, 0x6f, 0x72, 0x65, - 0x78, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x67, 0x0a, 0x0d, 0x47, 0x65, - 0x74, 0x46, 0x6f, 0x72, 0x65, 0x78, 0x52, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x67, 0x63, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x65, 0x78, 0x52, 0x61, 0x74, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x65, 0x78, 0x52, 0x61, 0x74, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, - 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x66, 0x6f, 0x72, 0x65, 0x78, 0x72, 0x61, - 0x74, 0x65, 0x73, 0x12, 0x5a, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, - 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22, 0x0d, 0x2f, - 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x12, - 0x52, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x67, 0x63, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x11, 0x22, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6f, 0x72, 0x64, 0x65, 0x72, - 0x3a, 0x01, 0x2a, 0x12, 0x62, 0x0a, 0x0b, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x6f, - 0x72, 0x64, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x6a, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x75, 0x6c, - 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, - 0x76, 0x31, 0x2f, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x6f, 0x72, 0x64, 0x65, 0x72, - 0x3a, 0x01, 0x2a, 0x12, 0x5e, 0x0a, 0x09, 0x57, 0x68, 0x61, 0x6c, 0x65, 0x42, 0x6f, 0x6d, 0x62, - 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x68, 0x61, 0x6c, 0x65, 0x42, - 0x6f, 0x6d, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x12, 0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x68, 0x61, 0x6c, 0x65, 0x62, 0x6f, 0x6d, 0x62, - 0x3a, 0x01, 0x2a, 0x12, 0x5e, 0x0a, 0x0b, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, - 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6f, 0x72, 0x64, 0x65, 0x72, - 0x3a, 0x01, 0x2a, 0x12, 0x7a, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x12, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, - 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x62, 0x61, 0x74, 0x63, 0x68, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x12, - 0x72, 0x0a, 0x0f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x6c, 0x6c, 0x4f, 0x72, 0x64, 0x65, - 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x41, 0x6c, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x41, 0x6c, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x76, 0x31, - 0x2f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x61, 0x6c, 0x6c, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x73, - 0x3a, 0x01, 0x2a, 0x12, 0x57, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x30, 0x01, 0x12, 0x57, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x12, 0x0d, 0x2f, - 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x56, 0x0a, 0x08, - 0x41, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x41, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x11, 0x22, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x64, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5e, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, - 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xb2, 0x01, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, - 0x74, 0x6f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x30, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x63, 0x75, 0x72, - 0x72, 0x65, 0x6e, 0x63, 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x67, - 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x22, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0xaa, 0x01, 0x0a, 0x1f, 0x47, 0x65, + 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x63, 0x0a, 0x0c, + 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, 0x1b, 0x2e, 0x67, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, + 0x69, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, + 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, + 0x6f, 0x12, 0x7f, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, + 0x6f, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x75, + 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x67, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, + 0x69, 0x6f, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x67, + 0x65, 0x74, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x12, 0x76, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, + 0x69, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, + 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, + 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x64, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x7f, 0x0a, 0x16, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x76, + 0x31, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, + 0x6f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x77, 0x0a, 0x11, 0x47, + 0x65, 0x74, 0x46, 0x6f, 0x72, 0x65, 0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, + 0x12, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, + 0x65, 0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x46, + 0x6f, 0x72, 0x65, 0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, + 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x66, 0x6f, 0x72, 0x65, 0x78, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x73, 0x12, 0x67, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x65, 0x78, + 0x52, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x46, 0x6f, 0x72, 0x65, 0x78, 0x52, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, + 0x46, 0x6f, 0x72, 0x65, 0x78, 0x52, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, + 0x67, 0x65, 0x74, 0x66, 0x6f, 0x72, 0x65, 0x78, 0x72, 0x61, 0x74, 0x65, 0x73, 0x12, 0x5a, 0x0a, + 0x09, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x52, 0x0a, 0x08, 0x47, 0x65, 0x74, + 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, + 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x22, 0x0c, 0x2f, 0x76, + 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x62, 0x0a, + 0x0b, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x67, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, + 0x76, 0x31, 0x2f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x01, + 0x2a, 0x12, 0x6a, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, + 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x6d, 0x75, + 0x6c, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x6d, 0x75, 0x6c, 0x61, + 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x69, 0x6d, + 0x75, 0x6c, 0x61, 0x74, 0x65, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x5e, 0x0a, + 0x09, 0x57, 0x68, 0x61, 0x6c, 0x65, 0x42, 0x6f, 0x6d, 0x62, 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x57, 0x68, 0x61, 0x6c, 0x65, 0x42, 0x6f, 0x6d, 0x62, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, + 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22, 0x0d, 0x2f, 0x76, 0x31, + 0x2f, 0x77, 0x68, 0x61, 0x6c, 0x65, 0x62, 0x6f, 0x6d, 0x62, 0x3a, 0x01, 0x2a, 0x12, 0x5e, 0x0a, + 0x0b, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x67, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x63, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x7a, 0x0a, + 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x73, 0x12, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, + 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x62, 0x61, 0x74, 0x63, 0x68, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x72, 0x0a, 0x0f, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x41, 0x6c, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x67, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x6c, 0x6c, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x6c, 0x6c, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x61, 0x6e, 0x63, 0x65, + 0x6c, 0x61, 0x6c, 0x6c, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x57, 0x0a, + 0x09, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x12, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x56, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x22, 0x0c, 0x2f, + 0x76, 0x31, 0x2f, 0x61, 0x64, 0x64, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5e, + 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x2e, + 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, + 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xb2, + 0x01, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x63, 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x12, 0x30, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x44, - 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x22, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x6c, 0x0a, 0x11, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, - 0x61, 0x77, 0x46, 0x69, 0x61, 0x74, 0x46, 0x75, 0x6e, 0x64, 0x73, 0x12, 0x1b, 0x2e, 0x67, 0x63, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x46, 0x69, 0x61, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, - 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x66, 0x69, 0x61, 0x74, 0x66, 0x75, 0x6e, 0x64, - 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x8b, 0x01, 0x0a, 0x1b, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, - 0x77, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x46, - 0x75, 0x6e, 0x64, 0x73, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, - 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, - 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x22, 0x28, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, - 0x72, 0x61, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x66, 0x75, 0x6e, 0x64, 0x73, 0x77, 0x66, 0x69, 0x61, 0x74, 0x66, 0x75, 0x6e, 0x64, 0x73, 0x3a, - 0x01, 0x2a, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, - 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x44, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, + 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x22, 0x22, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x3a, 0x01, 0x2a, 0x12, 0xaa, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, + 0x22, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x64, + 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x01, 0x2a, + 0x12, 0x6c, 0x0a, 0x11, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x46, 0x69, 0x61, 0x74, + 0x46, 0x75, 0x6e, 0x64, 0x73, 0x12, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x46, 0x69, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, + 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x66, 0x69, 0x61, 0x74, 0x66, 0x75, 0x6e, 0x64, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x8b, + 0x01, 0x0a, 0x1b, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x43, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x46, 0x75, 0x6e, 0x64, 0x73, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, - 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x76, 0x31, - 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x62, 0x79, 0x69, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x97, 0x01, 0x0a, 0x1a, 0x57, 0x69, 0x74, 0x68, - 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x45, 0x78, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x29, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x42, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2a, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, - 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x45, 0x78, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, + 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, + 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x22, + 0x28, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x69, 0x74, 0x68, + 0x64, 0x72, 0x61, 0x77, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x66, 0x75, 0x6e, 0x64, 0x73, 0x77, + 0x66, 0x69, 0x61, 0x74, 0x66, 0x75, 0x6e, 0x64, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x82, 0x01, 0x0a, + 0x13, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x42, 0x79, 0x49, 0x44, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, + 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, + 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x79, 0x69, 0x64, 0x3a, 0x01, - 0x2a, 0x12, 0x91, 0x01, 0x0a, 0x16, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x44, 0x61, 0x74, 0x65, 0x12, 0x25, 0x2e, 0x67, - 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x44, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, - 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x45, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x22, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x69, 0x74, - 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x79, 0x64, 0x61, - 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x67, - 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x2a, 0x12, 0x97, 0x01, 0x0a, 0x1a, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x12, 0x29, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x45, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, + 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x62, 0x79, 0x69, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x91, 0x01, 0x0a, 0x16, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x42, 0x79, 0x44, 0x61, 0x74, 0x65, 0x12, 0x25, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x42, 0x79, 0x44, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, + 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, + 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1e, 0x22, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, + 0x6c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x79, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, + 0x73, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, + 0x69, 0x6c, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, + 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, + 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x64, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x12, 0x76, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, + 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6c, 0x6f, 0x67, - 0x67, 0x65, 0x72, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x76, 0x0a, 0x10, 0x53, 0x65, - 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1f, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, - 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x67, - 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x73, - 0x65, 0x74, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x3a, - 0x01, 0x2a, 0x12, 0x76, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x19, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x67, 0x67, + 0x65, 0x72, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x76, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x19, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x70, 0x61, 0x69, 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x6a, 0x0a, 0x0f, 0x53, 0x65, - 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x1e, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, - 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x70, - 0x61, 0x69, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x21, 0x2e, 0x67, - 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, - 0x6f, 0x6b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, - 0x6f, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x18, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6f, 0x72, 0x64, 0x65, 0x72, - 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x30, 0x01, 0x12, 0x8c, 0x01, 0x0a, - 0x1a, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, - 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x29, 0x2e, 0x67, 0x63, + 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x14, 0x2f, 0x76, 0x31, + 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x70, 0x61, 0x69, 0x72, + 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x6a, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, + 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x70, 0x61, 0x69, 0x72, 0x3a, 0x01, 0x2a, + 0x12, 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x21, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x76, + 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x30, 0x01, 0x12, 0x8c, 0x01, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x45, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x29, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, + 0x6f, 0x6f, 0x6b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, + 0x6f, 0x6f, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x30, 0x01, 0x12, 0x68, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, + 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, + 0x74, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x30, 0x01, 0x12, + 0x80, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, + 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x26, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x67, - 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x62, - 0x6f, 0x6f, 0x6b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x30, 0x01, 0x12, 0x68, 0x0a, 0x0f, 0x47, - 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1e, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, - 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, - 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x30, 0x01, 0x12, 0x80, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x12, 0x26, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x67, - 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, - 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x30, 0x01, 0x12, 0x67, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x41, - 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, - 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x61, 0x75, 0x64, 0x69, 0x74, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x6b, 0x0a, 0x10, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x45, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, - 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x6b, - 0x0a, 0x0f, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x12, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, - 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x19, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x2f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x78, 0x0a, 0x13, 0x47, - 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x61, 0x64, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x61, 0x64, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, - 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x72, 0x65, - 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x70, 0x0a, 0x0f, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x6c, 0x0a, 0x0e, 0x47, 0x43, 0x54, 0x53, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, - 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x65, 0x0a, 0x0d, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, - 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x70, 0x3a, 0x01, 0x2a, 0x12, 0x6b, 0x0a, 0x10, - 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x6f, 0x70, 0x41, 0x6c, 0x6c, - 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x53, 0x74, 0x6f, 0x70, 0x41, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, - 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x17, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x70, 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x10, 0x47, 0x43, 0x54, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x12, 0x1f, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x70, 0x3a, 0x01, 0x2a, 0x12, 0x77, - 0x0a, 0x17, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x4c, - 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x12, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x75, 0x74, 0x6f, - 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, + 0x54, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x69, 0x63, + 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x30, 0x01, 0x12, 0x67, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, + 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, + 0x74, 0x61, 0x75, 0x64, 0x69, 0x74, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x6b, 0x0a, 0x10, 0x47, + 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, + 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, + 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x6b, 0x0a, 0x0f, 0x47, 0x43, 0x54, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1e, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x55, 0x70, + 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x76, - 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x61, 0x75, 0x74, 0x6f, - 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x7b, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x12, 0x21, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, - 0x69, 0x63, 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, - 0x74, 0x6f, 0x72, 0x69, 0x63, 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x76, - 0x31, 0x2f, 0x67, 0x65, 0x74, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x63, 0x61, 0x6e, - 0x64, 0x6c, 0x65, 0x73, 0x12, 0x6a, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x73, 0x73, - 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, - 0x73, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x61, 0x73, 0x73, 0x65, 0x74, - 0x12, 0x73, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x6c, 0x6c, 0x50, - 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x14, 0x2f, 0x76, + 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x75, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x78, 0x0a, 0x13, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x52, 0x65, 0x61, 0x64, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x22, 0x2e, 0x67, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, + 0x65, 0x61, 0x64, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, + 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, + 0x70, 0x0a, 0x0f, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, + 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x6c, 0x0a, 0x0e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, + 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, + 0x65, 0x0a, 0x0d, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x6f, 0x70, + 0x12, 0x1c, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, + 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, + 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x73, + 0x74, 0x6f, 0x70, 0x3a, 0x01, 0x2a, 0x12, 0x6b, 0x0a, 0x10, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x53, 0x74, 0x6f, 0x70, 0x41, 0x6c, 0x6c, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x6f, + 0x70, 0x41, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, - 0x31, 0x2f, 0x73, 0x65, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x70, 0x61, 0x69, 0x72, 0x73, 0x12, 0x8e, 0x01, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x69, 0x72, 0x73, 0x12, 0x2b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x76, + 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x70, + 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x10, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, + 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x43, 0x54, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x17, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x2f, 0x73, 0x74, 0x6f, 0x70, 0x3a, 0x01, 0x2a, 0x12, 0x77, 0x0a, 0x17, 0x47, 0x43, 0x54, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x4c, 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x67, + 0x67, 0x6c, 0x65, 0x12, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x43, 0x54, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x63, 0x74, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x01, + 0x2a, 0x12, 0x7b, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, + 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x43, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x43, + 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x68, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x63, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x12, 0x6a, + 0x0a, 0x10, 0x53, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x45, + 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x70, 0x61, 0x69, 0x72, 0x73, 0x12, 0x77, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x12, 0x20, 0x2e, 0x67, 0x63, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, - 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x12, - 0x73, 0x0a, 0x10, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x47, 0x65, 0x74, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, 0x62, - 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, - 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, + 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x74, 0x65, 0x78, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x61, 0x73, 0x73, 0x65, 0x74, 0x12, 0x73, 0x0a, 0x13, 0x53, 0x65, + 0x74, 0x41, 0x6c, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, + 0x73, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x45, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x74, 0x61, + 0x6c, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x70, 0x61, 0x69, 0x72, 0x73, 0x12, + 0x8e, 0x01, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x50, 0x61, 0x69, 0x72, 0x73, + 0x12, 0x2b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, + 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, + 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x70, 0x61, 0x69, 0x72, 0x73, + 0x12, 0x77, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x73, 0x12, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x12, 0x73, 0x0a, 0x10, 0x57, 0x65, 0x62, + 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x2e, + 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, + 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, + 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, + 0x74, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x65, + 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x67, 0x65, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x73, + 0x0a, 0x13, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74, 0x45, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, + 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, + 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x65, 0x74, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x12, 0x97, 0x01, 0x0a, 0x19, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, + 0x74, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x28, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, + 0x63, 0x6b, 0x65, 0x74, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x47, 0x65, + 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x67, 0x65, 0x74, - 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x73, 0x0a, 0x13, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, - 0x74, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x22, 0x2e, 0x67, 0x63, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, - 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x6d, 0x0a, + 0x11, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, + 0x78, 0x79, 0x12, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, 0x62, 0x73, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x65, 0x62, 0x73, 0x6f, + 0x63, 0x6b, 0x65, 0x74, 0x73, 0x65, 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x67, 0x0a, 0x0f, + 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74, 0x55, 0x52, 0x4c, 0x12, + 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, + 0x65, 0x74, 0x53, 0x65, 0x74, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, - 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, - 0x65, 0x74, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x97, 0x01, 0x0a, 0x19, 0x57, 0x65, - 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x28, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x29, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, - 0x6b, 0x65, 0x74, 0x67, 0x65, 0x74, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x6d, 0x0a, 0x11, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, - 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x20, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74, 0x50, 0x72, - 0x6f, 0x78, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, + 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, + 0x65, 0x74, 0x75, 0x72, 0x6c, 0x12, 0x69, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, + 0x6e, 0x74, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, + 0x31, 0x2f, 0x67, 0x65, 0x74, 0x73, 0x61, 0x76, 0x65, 0x64, 0x74, 0x72, 0x61, 0x64, 0x65, 0x73, + 0x12, 0x6d, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x54, + 0x72, 0x61, 0x64, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x61, + 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, + 0x65, 0x74, 0x73, 0x61, 0x76, 0x65, 0x64, 0x74, 0x72, 0x61, 0x64, 0x65, 0x73, 0x30, 0x01, 0x12, + 0x68, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, + 0x73, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x61, + 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, + 0x72, 0x61, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x73, 0x61, + 0x76, 0x65, 0x64, 0x74, 0x72, 0x61, 0x64, 0x65, 0x73, 0x12, 0x87, 0x01, 0x0a, 0x16, 0x43, 0x6f, + 0x6e, 0x76, 0x65, 0x72, 0x74, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x54, 0x6f, 0x43, 0x61, 0x6e, + 0x64, 0x6c, 0x65, 0x73, 0x12, 0x25, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, + 0x6e, 0x76, 0x65, 0x72, 0x74, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x54, 0x6f, 0x43, 0x61, 0x6e, + 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, + 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x74, 0x74, 0x72, 0x61, 0x64, 0x65, 0x73, 0x74, 0x6f, 0x63, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x73, 0x12, 0x9d, 0x01, 0x0a, 0x1f, 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, + 0x69, 0x6e, 0x67, 0x53, 0x61, 0x76, 0x65, 0x64, 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x27, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x24, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, + 0x73, 0x73, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, + 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x73, + 0x61, 0x76, 0x65, 0x64, 0x63, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x73, 0x12, 0x9a, 0x01, 0x0a, 0x1e, 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, + 0x69, 0x6e, 0x67, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x26, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x64, 0x65, + 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, + 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, + 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x12, 0x22, 0x2f, 0x76, + 0x31, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x73, 0x61, 0x76, + 0x65, 0x64, 0x74, 0x72, 0x61, 0x64, 0x65, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, + 0x12, 0x88, 0x01, 0x0a, 0x1a, 0x53, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x54, 0x72, 0x61, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x12, + 0x29, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x54, 0x72, 0x61, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, + 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, - 0x2f, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x65, 0x74, 0x70, 0x72, 0x6f, - 0x78, 0x79, 0x12, 0x67, 0x0a, 0x0f, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, - 0x65, 0x74, 0x55, 0x52, 0x4c, 0x12, 0x1e, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x57, - 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74, 0x55, 0x52, 0x4c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, - 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x65, 0x62, 0x73, - 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x65, 0x74, 0x75, 0x72, 0x6c, 0x12, 0x69, 0x0a, 0x0f, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x12, 0x1d, - 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x61, 0x76, 0x65, 0x64, - 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x73, 0x61, 0x76, 0x65, 0x64, - 0x74, 0x72, 0x61, 0x64, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x48, 0x69, 0x73, - 0x74, 0x6f, 0x72, 0x69, 0x63, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x67, 0x63, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, - 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, - 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x73, 0x61, 0x76, 0x65, 0x64, 0x74, 0x72, 0x61, - 0x64, 0x65, 0x73, 0x30, 0x01, 0x12, 0x68, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x53, 0x61, 0x76, 0x65, - 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, - 0x2f, 0x67, 0x65, 0x74, 0x73, 0x61, 0x76, 0x65, 0x64, 0x74, 0x72, 0x61, 0x64, 0x65, 0x73, 0x12, - 0x87, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x54, 0x72, 0x61, 0x64, 0x65, - 0x73, 0x54, 0x6f, 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x12, 0x25, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x54, 0x72, 0x61, 0x64, 0x65, - 0x73, 0x54, 0x6f, 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, - 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x74, 0x72, 0x61, 0x64, 0x65, 0x73, - 0x74, 0x6f, 0x63, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x12, 0x9d, 0x01, 0x0a, 0x1f, 0x46, 0x69, - 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x61, 0x76, 0x65, 0x64, 0x43, 0x61, - 0x6e, 0x64, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x27, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, - 0x6e, 0x67, 0x43, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x74, 0x65, 0x72, - 0x76, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6e, 0x67, 0x73, 0x61, 0x76, 0x65, 0x64, 0x63, 0x61, 0x6e, 0x64, 0x6c, 0x65, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x9a, 0x01, 0x0a, 0x1e, 0x46, 0x69, - 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x61, 0x76, 0x65, 0x64, 0x54, 0x72, - 0x61, 0x64, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x26, 0x2e, 0x67, - 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, - 0x67, 0x54, 0x72, 0x61, 0x64, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, - 0x6e, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6e, 0x67, 0x73, 0x61, 0x76, 0x65, 0x64, 0x74, 0x72, 0x61, 0x64, 0x65, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x88, 0x01, 0x0a, 0x1a, 0x53, 0x65, 0x74, 0x45, 0x78, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x72, 0x61, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x63, 0x65, - 0x73, 0x73, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x72, 0x61, 0x64, 0x65, 0x50, - 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, - 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x74, 0x72, 0x61, 0x64, 0x65, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, - 0x67, 0x12, 0x86, 0x01, 0x0a, 0x14, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, - 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x12, 0x23, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x24, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, - 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, - 0x76, 0x31, 0x2f, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x64, 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, - 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, 0x62, 0x3a, 0x01, 0x2a, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x47, - 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x27, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, - 0x6f, 0x62, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x16, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, - 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x64, 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, - 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, 0x62, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x71, - 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, - 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x63, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x61, 0x74, 0x61, - 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x24, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x61, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x64, 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, 0x62, - 0x73, 0x12, 0x7a, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, - 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x12, 0x27, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x31, + 0x2f, 0x73, 0x65, 0x74, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x74, 0x72, 0x61, 0x64, + 0x65, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x12, 0x86, 0x01, 0x0a, 0x14, + 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x4a, 0x6f, 0x62, 0x12, 0x23, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, + 0x73, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x70, 0x73, + 0x65, 0x72, 0x74, 0x64, 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, + 0x62, 0x3a, 0x01, 0x2a, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, + 0x73, 0x12, 0x27, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, + 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x74, 0x61, + 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, + 0x6f, 0x62, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, + 0x67, 0x65, 0x74, 0x64, 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, + 0x62, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x71, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, + 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, + 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x64, 0x61, 0x74, 0x61, + 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x85, 0x01, 0x0a, 0x19, + 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, + 0x62, 0x73, 0x42, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x12, 0x28, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, - 0x79, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x42, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x61, 0x74, + 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x25, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x64, 0x61, 0x74, + 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, 0x62, 0x73, 0x62, 0x65, 0x74, 0x77, + 0x65, 0x65, 0x6e, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x12, 0x27, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, + 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x63, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, + 0x62, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x67, + 0x65, 0x74, 0x64, 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, 0x62, + 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x82, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x44, + 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x26, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, + 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x22, 0x1b, 0x2f, 0x76, + 0x31, 0x2f, 0x73, 0x65, 0x74, 0x64, 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x6a, 0x6f, 0x62, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x9d, 0x01, 0x0a, + 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x65, 0x72, 0x65, 0x71, 0x75, 0x69, 0x73, 0x69, 0x74, + 0x65, 0x12, 0x2f, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x50, + 0x72, 0x65, 0x72, 0x65, 0x71, 0x75, 0x69, 0x73, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, - 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1a, 0x2a, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, - 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, 0x62, 0x12, 0x85, 0x01, - 0x0a, 0x19, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x4a, 0x6f, 0x62, 0x73, 0x42, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x12, 0x28, 0x2e, 0x67, 0x63, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, - 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x42, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x25, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x64, - 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, 0x62, 0x73, 0x62, 0x65, - 0x74, 0x77, 0x65, 0x65, 0x6e, 0x12, 0x81, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, - 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x12, 0x27, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, - 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x63, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x4a, 0x6f, 0x62, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, - 0x2f, 0x67, 0x65, 0x74, 0x64, 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, - 0x6f, 0x62, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x68, 0x0a, 0x10, 0x47, 0x65, 0x74, - 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x12, 0x18, 0x2e, - 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, - 0x67, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x73, - 0x3a, 0x01, 0x2a, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x74, 0x68, 0x72, 0x61, 0x73, 0x68, 0x65, 0x72, 0x2d, 0x63, 0x6f, 0x72, 0x70, 0x2f, - 0x67, 0x6f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x74, 0x72, 0x61, 0x64, 0x65, 0x72, 0x2f, 0x67, - 0x63, 0x74, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x29, 0x22, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x61, 0x74, 0x61, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x6a, 0x6f, 0x62, 0x70, 0x72, 0x65, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x73, 0x69, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x68, 0x0a, 0x10, + 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, + 0x12, 0x18, 0x2e, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x63, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x14, 0x2f, + 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x68, 0x72, 0x61, 0x73, 0x68, 0x65, 0x72, 0x2d, 0x63, 0x6f, + 0x72, 0x70, 0x2f, 0x67, 0x6f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x74, 0x72, 0x61, 0x64, 0x65, + 0x72, 0x2f, 0x67, 0x63, 0x74, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -11665,7 +12073,7 @@ func file_rpc_proto_rawDescGZIP() []byte { return file_rpc_proto_rawDescData } -var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 168) +var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 172) var file_rpc_proto_goTypes = []interface{}{ (*GetInfoRequest)(nil), // 0: gctrpc.GetInfoRequest (*GetInfoResponse)(nil), // 1: gctrpc.GetInfoResponse @@ -11813,38 +12221,42 @@ var file_rpc_proto_goTypes = []interface{}{ (*FindMissingIntervalsResponse)(nil), // 143: gctrpc.FindMissingIntervalsResponse (*SetExchangeTradeProcessingRequest)(nil), // 144: gctrpc.SetExchangeTradeProcessingRequest (*UpsertDataHistoryJobRequest)(nil), // 145: gctrpc.UpsertDataHistoryJobRequest - (*UpsertDataHistoryJobResponse)(nil), // 146: gctrpc.UpsertDataHistoryJobResponse - (*GetDataHistoryJobDetailsRequest)(nil), // 147: gctrpc.GetDataHistoryJobDetailsRequest - (*DataHistoryJob)(nil), // 148: gctrpc.DataHistoryJob - (*DataHistoryJobResult)(nil), // 149: gctrpc.DataHistoryJobResult - (*DataHistoryJobs)(nil), // 150: gctrpc.DataHistoryJobs - (*GetDataHistoryJobsBetweenRequest)(nil), // 151: gctrpc.GetDataHistoryJobsBetweenRequest - nil, // 152: gctrpc.GetInfoResponse.SubsystemStatusEntry - nil, // 153: gctrpc.GetInfoResponse.RpcEndpointsEntry - nil, // 154: gctrpc.GetCommunicationRelayersResponse.CommunicationRelayersEntry - nil, // 155: gctrpc.GetSusbsytemsResponse.SubsystemsStatusEntry - nil, // 156: gctrpc.GetRPCEndpointsResponse.EndpointsEntry - nil, // 157: gctrpc.GetExchangeOTPsResponse.OtpCodesEntry - nil, // 158: gctrpc.GetExchangeInfoResponse.SupportedAssetsEntry - nil, // 159: gctrpc.OnlineCoins.CoinsEntry - nil, // 160: gctrpc.GetPortfolioSummaryResponse.CoinsOfflineSummaryEntry - nil, // 161: gctrpc.GetPortfolioSummaryResponse.CoinsOnlineSummaryEntry - (*CancelBatchOrdersResponse_Orders)(nil), // 162: gctrpc.CancelBatchOrdersResponse.Orders - nil, // 163: gctrpc.CancelBatchOrdersResponse.Orders.OrderStatusEntry - (*CancelAllOrdersResponse_Orders)(nil), // 164: gctrpc.CancelAllOrdersResponse.Orders - nil, // 165: gctrpc.CancelAllOrdersResponse.Orders.OrderStatusEntry - nil, // 166: gctrpc.GetCryptocurrencyDepositAddressesResponse.AddressesEntry - nil, // 167: gctrpc.GetExchangePairsResponse.SupportedAssetsEntry - (*timestamppb.Timestamp)(nil), // 168: google.protobuf.Timestamp + (*InsertSequentialJobsRequest)(nil), // 146: gctrpc.InsertSequentialJobsRequest + (*InsertSequentialJobsResponse)(nil), // 147: gctrpc.InsertSequentialJobsResponse + (*UpsertDataHistoryJobResponse)(nil), // 148: gctrpc.UpsertDataHistoryJobResponse + (*GetDataHistoryJobDetailsRequest)(nil), // 149: gctrpc.GetDataHistoryJobDetailsRequest + (*DataHistoryJob)(nil), // 150: gctrpc.DataHistoryJob + (*DataHistoryJobResult)(nil), // 151: gctrpc.DataHistoryJobResult + (*DataHistoryJobs)(nil), // 152: gctrpc.DataHistoryJobs + (*GetDataHistoryJobsBetweenRequest)(nil), // 153: gctrpc.GetDataHistoryJobsBetweenRequest + (*SetDataHistoryJobStatusRequest)(nil), // 154: gctrpc.SetDataHistoryJobStatusRequest + (*UpdateDataHistoryJobPrerequisiteRequest)(nil), // 155: gctrpc.UpdateDataHistoryJobPrerequisiteRequest + nil, // 156: gctrpc.GetInfoResponse.SubsystemStatusEntry + nil, // 157: gctrpc.GetInfoResponse.RpcEndpointsEntry + nil, // 158: gctrpc.GetCommunicationRelayersResponse.CommunicationRelayersEntry + nil, // 159: gctrpc.GetSusbsytemsResponse.SubsystemsStatusEntry + nil, // 160: gctrpc.GetRPCEndpointsResponse.EndpointsEntry + nil, // 161: gctrpc.GetExchangeOTPsResponse.OtpCodesEntry + nil, // 162: gctrpc.GetExchangeInfoResponse.SupportedAssetsEntry + nil, // 163: gctrpc.OnlineCoins.CoinsEntry + nil, // 164: gctrpc.GetPortfolioSummaryResponse.CoinsOfflineSummaryEntry + nil, // 165: gctrpc.GetPortfolioSummaryResponse.CoinsOnlineSummaryEntry + (*CancelBatchOrdersResponse_Orders)(nil), // 166: gctrpc.CancelBatchOrdersResponse.Orders + nil, // 167: gctrpc.CancelBatchOrdersResponse.Orders.OrderStatusEntry + (*CancelAllOrdersResponse_Orders)(nil), // 168: gctrpc.CancelAllOrdersResponse.Orders + nil, // 169: gctrpc.CancelAllOrdersResponse.Orders.OrderStatusEntry + nil, // 170: gctrpc.GetCryptocurrencyDepositAddressesResponse.AddressesEntry + nil, // 171: gctrpc.GetExchangePairsResponse.SupportedAssetsEntry + (*timestamppb.Timestamp)(nil), // 172: google.protobuf.Timestamp } var file_rpc_proto_depIdxs = []int32{ - 152, // 0: gctrpc.GetInfoResponse.subsystem_status:type_name -> gctrpc.GetInfoResponse.SubsystemStatusEntry - 153, // 1: gctrpc.GetInfoResponse.rpc_endpoints:type_name -> gctrpc.GetInfoResponse.RpcEndpointsEntry - 154, // 2: gctrpc.GetCommunicationRelayersResponse.communication_relayers:type_name -> gctrpc.GetCommunicationRelayersResponse.CommunicationRelayersEntry - 155, // 3: gctrpc.GetSusbsytemsResponse.subsystems_status:type_name -> gctrpc.GetSusbsytemsResponse.SubsystemsStatusEntry - 156, // 4: gctrpc.GetRPCEndpointsResponse.endpoints:type_name -> gctrpc.GetRPCEndpointsResponse.EndpointsEntry - 157, // 5: gctrpc.GetExchangeOTPsResponse.otp_codes:type_name -> gctrpc.GetExchangeOTPsResponse.OtpCodesEntry - 158, // 6: gctrpc.GetExchangeInfoResponse.supported_assets:type_name -> gctrpc.GetExchangeInfoResponse.SupportedAssetsEntry + 156, // 0: gctrpc.GetInfoResponse.subsystem_status:type_name -> gctrpc.GetInfoResponse.SubsystemStatusEntry + 157, // 1: gctrpc.GetInfoResponse.rpc_endpoints:type_name -> gctrpc.GetInfoResponse.RpcEndpointsEntry + 158, // 2: gctrpc.GetCommunicationRelayersResponse.communication_relayers:type_name -> gctrpc.GetCommunicationRelayersResponse.CommunicationRelayersEntry + 159, // 3: gctrpc.GetSusbsytemsResponse.subsystems_status:type_name -> gctrpc.GetSusbsytemsResponse.SubsystemsStatusEntry + 160, // 4: gctrpc.GetRPCEndpointsResponse.endpoints:type_name -> gctrpc.GetRPCEndpointsResponse.EndpointsEntry + 161, // 5: gctrpc.GetExchangeOTPsResponse.otp_codes:type_name -> gctrpc.GetExchangeOTPsResponse.OtpCodesEntry + 162, // 6: gctrpc.GetExchangeInfoResponse.supported_assets:type_name -> gctrpc.GetExchangeInfoResponse.SupportedAssetsEntry 21, // 7: gctrpc.GetTickerRequest.pair:type_name -> gctrpc.CurrencyPair 21, // 8: gctrpc.TickerResponse.pair:type_name -> gctrpc.CurrencyPair 22, // 9: gctrpc.Tickers.tickers:type_name -> gctrpc.TickerResponse @@ -11859,12 +12271,12 @@ var file_rpc_proto_depIdxs = []int32{ 33, // 18: gctrpc.GetAccountInfoResponse.accounts:type_name -> gctrpc.Account 38, // 19: gctrpc.GetPortfolioResponse.portfolio:type_name -> gctrpc.PortfolioAddress 43, // 20: gctrpc.OfflineCoins.addresses:type_name -> gctrpc.OfflineCoinSummary - 159, // 21: gctrpc.OnlineCoins.coins:type_name -> gctrpc.OnlineCoins.CoinsEntry + 163, // 21: gctrpc.OnlineCoins.coins:type_name -> gctrpc.OnlineCoins.CoinsEntry 42, // 22: gctrpc.GetPortfolioSummaryResponse.coin_totals:type_name -> gctrpc.Coin 42, // 23: gctrpc.GetPortfolioSummaryResponse.coins_offline:type_name -> gctrpc.Coin - 160, // 24: gctrpc.GetPortfolioSummaryResponse.coins_offline_summary:type_name -> gctrpc.GetPortfolioSummaryResponse.CoinsOfflineSummaryEntry + 164, // 24: gctrpc.GetPortfolioSummaryResponse.coins_offline_summary:type_name -> gctrpc.GetPortfolioSummaryResponse.CoinsOfflineSummaryEntry 42, // 25: gctrpc.GetPortfolioSummaryResponse.coins_online:type_name -> gctrpc.Coin - 161, // 26: gctrpc.GetPortfolioSummaryResponse.coins_online_summary:type_name -> gctrpc.GetPortfolioSummaryResponse.CoinsOnlineSummaryEntry + 165, // 26: gctrpc.GetPortfolioSummaryResponse.coins_online_summary:type_name -> gctrpc.GetPortfolioSummaryResponse.CoinsOnlineSummaryEntry 51, // 27: gctrpc.GetForexProvidersResponse.forex_providers:type_name -> gctrpc.ForexProvider 54, // 28: gctrpc.GetForexRatesResponse.forex_rates:type_name -> gctrpc.ForexRatesConversion 57, // 29: gctrpc.OrderDetails.trades:type_name -> gctrpc.TradeHistory @@ -11878,22 +12290,22 @@ var file_rpc_proto_depIdxs = []int32{ 21, // 37: gctrpc.WhaleBombRequest.pair:type_name -> gctrpc.CurrencyPair 21, // 38: gctrpc.CancelOrderRequest.pair:type_name -> gctrpc.CurrencyPair 21, // 39: gctrpc.CancelBatchOrdersRequest.pair:type_name -> gctrpc.CurrencyPair - 162, // 40: gctrpc.CancelBatchOrdersResponse.orders:type_name -> gctrpc.CancelBatchOrdersResponse.Orders - 164, // 41: gctrpc.CancelAllOrdersResponse.orders:type_name -> gctrpc.CancelAllOrdersResponse.Orders + 166, // 40: gctrpc.CancelBatchOrdersResponse.orders:type_name -> gctrpc.CancelBatchOrdersResponse.Orders + 168, // 41: gctrpc.CancelAllOrdersResponse.orders:type_name -> gctrpc.CancelAllOrdersResponse.Orders 73, // 42: gctrpc.GetEventsResponse.condition_params:type_name -> gctrpc.ConditionParams 21, // 43: gctrpc.GetEventsResponse.pair:type_name -> gctrpc.CurrencyPair 73, // 44: gctrpc.AddEventRequest.condition_params:type_name -> gctrpc.ConditionParams 21, // 45: gctrpc.AddEventRequest.pair:type_name -> gctrpc.CurrencyPair - 166, // 46: gctrpc.GetCryptocurrencyDepositAddressesResponse.addresses:type_name -> gctrpc.GetCryptocurrencyDepositAddressesResponse.AddressesEntry + 170, // 46: gctrpc.GetCryptocurrencyDepositAddressesResponse.addresses:type_name -> gctrpc.GetCryptocurrencyDepositAddressesResponse.AddressesEntry 90, // 47: gctrpc.WithdrawalEventByIDResponse.event:type_name -> gctrpc.WithdrawalEventResponse 90, // 48: gctrpc.WithdrawalEventsByExchangeResponse.event:type_name -> gctrpc.WithdrawalEventResponse 91, // 49: gctrpc.WithdrawalEventResponse.exchange:type_name -> gctrpc.WithdrawlExchangeEvent 92, // 50: gctrpc.WithdrawalEventResponse.request:type_name -> gctrpc.WithdrawalRequestEvent - 168, // 51: gctrpc.WithdrawalEventResponse.created_at:type_name -> google.protobuf.Timestamp - 168, // 52: gctrpc.WithdrawalEventResponse.updated_at:type_name -> google.protobuf.Timestamp + 172, // 51: gctrpc.WithdrawalEventResponse.created_at:type_name -> google.protobuf.Timestamp + 172, // 52: gctrpc.WithdrawalEventResponse.updated_at:type_name -> google.protobuf.Timestamp 93, // 53: gctrpc.WithdrawalRequestEvent.fiat:type_name -> gctrpc.FiatWithdrawalEvent 94, // 54: gctrpc.WithdrawalRequestEvent.crypto:type_name -> gctrpc.CryptoWithdrawalEvent - 167, // 55: gctrpc.GetExchangePairsResponse.supported_assets:type_name -> gctrpc.GetExchangePairsResponse.SupportedAssetsEntry + 171, // 55: gctrpc.GetExchangePairsResponse.supported_assets:type_name -> gctrpc.GetExchangePairsResponse.SupportedAssetsEntry 21, // 56: gctrpc.SetExchangePairRequest.pairs:type_name -> gctrpc.CurrencyPair 21, // 57: gctrpc.GetOrderbookStreamRequest.pair:type_name -> gctrpc.CurrencyPair 21, // 58: gctrpc.GetTickerStreamRequest.pair:type_name -> gctrpc.CurrencyPair @@ -11916,196 +12328,200 @@ var file_rpc_proto_depIdxs = []int32{ 21, // 75: gctrpc.FindMissingTradePeriodsRequest.pair:type_name -> gctrpc.CurrencyPair 21, // 76: gctrpc.FindMissingIntervalsResponse.pair:type_name -> gctrpc.CurrencyPair 21, // 77: gctrpc.UpsertDataHistoryJobRequest.pair:type_name -> gctrpc.CurrencyPair - 21, // 78: gctrpc.DataHistoryJob.pair:type_name -> gctrpc.CurrencyPair - 149, // 79: gctrpc.DataHistoryJob.job_results:type_name -> gctrpc.DataHistoryJobResult - 148, // 80: gctrpc.DataHistoryJobs.results:type_name -> gctrpc.DataHistoryJob - 9, // 81: gctrpc.GetInfoResponse.RpcEndpointsEntry.value:type_name -> gctrpc.RPCEndpoint - 3, // 82: gctrpc.GetCommunicationRelayersResponse.CommunicationRelayersEntry.value:type_name -> gctrpc.CommunicationRelayer - 9, // 83: gctrpc.GetRPCEndpointsResponse.EndpointsEntry.value:type_name -> gctrpc.RPCEndpoint - 18, // 84: gctrpc.GetExchangeInfoResponse.SupportedAssetsEntry.value:type_name -> gctrpc.PairsSupported - 44, // 85: gctrpc.OnlineCoins.CoinsEntry.value:type_name -> gctrpc.OnlineCoinSummary - 45, // 86: gctrpc.GetPortfolioSummaryResponse.CoinsOfflineSummaryEntry.value:type_name -> gctrpc.OfflineCoins - 46, // 87: gctrpc.GetPortfolioSummaryResponse.CoinsOnlineSummaryEntry.value:type_name -> gctrpc.OnlineCoins - 163, // 88: gctrpc.CancelBatchOrdersResponse.Orders.order_status:type_name -> gctrpc.CancelBatchOrdersResponse.Orders.OrderStatusEntry - 165, // 89: gctrpc.CancelAllOrdersResponse.Orders.order_status:type_name -> gctrpc.CancelAllOrdersResponse.Orders.OrderStatusEntry - 18, // 90: gctrpc.GetExchangePairsResponse.SupportedAssetsEntry.value:type_name -> gctrpc.PairsSupported - 0, // 91: gctrpc.GoCryptoTrader.GetInfo:input_type -> gctrpc.GetInfoRequest - 6, // 92: gctrpc.GoCryptoTrader.GetSubsystems:input_type -> gctrpc.GetSubsystemsRequest - 5, // 93: gctrpc.GoCryptoTrader.EnableSubsystem:input_type -> gctrpc.GenericSubsystemRequest - 5, // 94: gctrpc.GoCryptoTrader.DisableSubsystem:input_type -> gctrpc.GenericSubsystemRequest - 8, // 95: gctrpc.GoCryptoTrader.GetRPCEndpoints:input_type -> gctrpc.GetRPCEndpointsRequest - 2, // 96: gctrpc.GoCryptoTrader.GetCommunicationRelayers:input_type -> gctrpc.GetCommunicationRelayersRequest - 12, // 97: gctrpc.GoCryptoTrader.GetExchanges:input_type -> gctrpc.GetExchangesRequest - 11, // 98: gctrpc.GoCryptoTrader.DisableExchange:input_type -> gctrpc.GenericExchangeNameRequest - 11, // 99: gctrpc.GoCryptoTrader.GetExchangeInfo:input_type -> gctrpc.GenericExchangeNameRequest - 11, // 100: gctrpc.GoCryptoTrader.GetExchangeOTPCode:input_type -> gctrpc.GenericExchangeNameRequest - 15, // 101: gctrpc.GoCryptoTrader.GetExchangeOTPCodes:input_type -> gctrpc.GetExchangeOTPsRequest - 11, // 102: gctrpc.GoCryptoTrader.EnableExchange:input_type -> gctrpc.GenericExchangeNameRequest - 20, // 103: gctrpc.GoCryptoTrader.GetTicker:input_type -> gctrpc.GetTickerRequest - 23, // 104: gctrpc.GoCryptoTrader.GetTickers:input_type -> gctrpc.GetTickersRequest - 26, // 105: gctrpc.GoCryptoTrader.GetOrderbook:input_type -> gctrpc.GetOrderbookRequest - 29, // 106: gctrpc.GoCryptoTrader.GetOrderbooks:input_type -> gctrpc.GetOrderbooksRequest - 32, // 107: gctrpc.GoCryptoTrader.GetAccountInfo:input_type -> gctrpc.GetAccountInfoRequest - 32, // 108: gctrpc.GoCryptoTrader.UpdateAccountInfo:input_type -> gctrpc.GetAccountInfoRequest - 32, // 109: gctrpc.GoCryptoTrader.GetAccountInfoStream:input_type -> gctrpc.GetAccountInfoRequest - 36, // 110: gctrpc.GoCryptoTrader.GetConfig:input_type -> gctrpc.GetConfigRequest - 39, // 111: gctrpc.GoCryptoTrader.GetPortfolio:input_type -> gctrpc.GetPortfolioRequest - 41, // 112: gctrpc.GoCryptoTrader.GetPortfolioSummary:input_type -> gctrpc.GetPortfolioSummaryRequest - 48, // 113: gctrpc.GoCryptoTrader.AddPortfolioAddress:input_type -> gctrpc.AddPortfolioAddressRequest - 49, // 114: gctrpc.GoCryptoTrader.RemovePortfolioAddress:input_type -> gctrpc.RemovePortfolioAddressRequest - 50, // 115: gctrpc.GoCryptoTrader.GetForexProviders:input_type -> gctrpc.GetForexProvidersRequest - 53, // 116: gctrpc.GoCryptoTrader.GetForexRates:input_type -> gctrpc.GetForexRatesRequest - 58, // 117: gctrpc.GoCryptoTrader.GetOrders:input_type -> gctrpc.GetOrdersRequest - 60, // 118: gctrpc.GoCryptoTrader.GetOrder:input_type -> gctrpc.GetOrderRequest - 61, // 119: gctrpc.GoCryptoTrader.SubmitOrder:input_type -> gctrpc.SubmitOrderRequest - 64, // 120: gctrpc.GoCryptoTrader.SimulateOrder:input_type -> gctrpc.SimulateOrderRequest - 66, // 121: gctrpc.GoCryptoTrader.WhaleBomb:input_type -> gctrpc.WhaleBombRequest - 67, // 122: gctrpc.GoCryptoTrader.CancelOrder:input_type -> gctrpc.CancelOrderRequest - 68, // 123: gctrpc.GoCryptoTrader.CancelBatchOrders:input_type -> gctrpc.CancelBatchOrdersRequest - 70, // 124: gctrpc.GoCryptoTrader.CancelAllOrders:input_type -> gctrpc.CancelAllOrdersRequest - 72, // 125: gctrpc.GoCryptoTrader.GetEvents:input_type -> gctrpc.GetEventsRequest - 75, // 126: gctrpc.GoCryptoTrader.AddEvent:input_type -> gctrpc.AddEventRequest - 77, // 127: gctrpc.GoCryptoTrader.RemoveEvent:input_type -> gctrpc.RemoveEventRequest - 78, // 128: gctrpc.GoCryptoTrader.GetCryptocurrencyDepositAddresses:input_type -> gctrpc.GetCryptocurrencyDepositAddressesRequest - 80, // 129: gctrpc.GoCryptoTrader.GetCryptocurrencyDepositAddress:input_type -> gctrpc.GetCryptocurrencyDepositAddressRequest - 82, // 130: gctrpc.GoCryptoTrader.WithdrawFiatFunds:input_type -> gctrpc.WithdrawFiatRequest - 83, // 131: gctrpc.GoCryptoTrader.WithdrawCryptocurrencyFunds:input_type -> gctrpc.WithdrawCryptoRequest - 85, // 132: gctrpc.GoCryptoTrader.WithdrawalEventByID:input_type -> gctrpc.WithdrawalEventByIDRequest - 87, // 133: gctrpc.GoCryptoTrader.WithdrawalEventsByExchange:input_type -> gctrpc.WithdrawalEventsByExchangeRequest - 88, // 134: gctrpc.GoCryptoTrader.WithdrawalEventsByDate:input_type -> gctrpc.WithdrawalEventsByDateRequest - 95, // 135: gctrpc.GoCryptoTrader.GetLoggerDetails:input_type -> gctrpc.GetLoggerDetailsRequest - 97, // 136: gctrpc.GoCryptoTrader.SetLoggerDetails:input_type -> gctrpc.SetLoggerDetailsRequest - 98, // 137: gctrpc.GoCryptoTrader.GetExchangePairs:input_type -> gctrpc.GetExchangePairsRequest - 100, // 138: gctrpc.GoCryptoTrader.SetExchangePair:input_type -> gctrpc.SetExchangePairRequest - 101, // 139: gctrpc.GoCryptoTrader.GetOrderbookStream:input_type -> gctrpc.GetOrderbookStreamRequest - 102, // 140: gctrpc.GoCryptoTrader.GetExchangeOrderbookStream:input_type -> gctrpc.GetExchangeOrderbookStreamRequest - 103, // 141: gctrpc.GoCryptoTrader.GetTickerStream:input_type -> gctrpc.GetTickerStreamRequest - 104, // 142: gctrpc.GoCryptoTrader.GetExchangeTickerStream:input_type -> gctrpc.GetExchangeTickerStreamRequest - 105, // 143: gctrpc.GoCryptoTrader.GetAuditEvent:input_type -> gctrpc.GetAuditEventRequest - 116, // 144: gctrpc.GoCryptoTrader.GCTScriptExecute:input_type -> gctrpc.GCTScriptExecuteRequest - 121, // 145: gctrpc.GoCryptoTrader.GCTScriptUpload:input_type -> gctrpc.GCTScriptUploadRequest - 122, // 146: gctrpc.GoCryptoTrader.GCTScriptReadScript:input_type -> gctrpc.GCTScriptReadScriptRequest - 119, // 147: gctrpc.GoCryptoTrader.GCTScriptStatus:input_type -> gctrpc.GCTScriptStatusRequest - 123, // 148: gctrpc.GoCryptoTrader.GCTScriptQuery:input_type -> gctrpc.GCTScriptQueryRequest - 117, // 149: gctrpc.GoCryptoTrader.GCTScriptStop:input_type -> gctrpc.GCTScriptStopRequest - 118, // 150: gctrpc.GoCryptoTrader.GCTScriptStopAll:input_type -> gctrpc.GCTScriptStopAllRequest - 120, // 151: gctrpc.GoCryptoTrader.GCTScriptListAll:input_type -> gctrpc.GCTScriptListAllRequest - 124, // 152: gctrpc.GoCryptoTrader.GCTScriptAutoLoadToggle:input_type -> gctrpc.GCTScriptAutoLoadRequest - 111, // 153: gctrpc.GoCryptoTrader.GetHistoricCandles:input_type -> gctrpc.GetHistoricCandlesRequest - 128, // 154: gctrpc.GoCryptoTrader.SetExchangeAsset:input_type -> gctrpc.SetExchangeAssetRequest - 129, // 155: gctrpc.GoCryptoTrader.SetAllExchangePairs:input_type -> gctrpc.SetExchangeAllPairsRequest - 130, // 156: gctrpc.GoCryptoTrader.UpdateExchangeSupportedPairs:input_type -> gctrpc.UpdateExchangeSupportedPairsRequest - 131, // 157: gctrpc.GoCryptoTrader.GetExchangeAssets:input_type -> gctrpc.GetExchangeAssetsRequest - 133, // 158: gctrpc.GoCryptoTrader.WebsocketGetInfo:input_type -> gctrpc.WebsocketGetInfoRequest - 135, // 159: gctrpc.GoCryptoTrader.WebsocketSetEnabled:input_type -> gctrpc.WebsocketSetEnabledRequest - 136, // 160: gctrpc.GoCryptoTrader.WebsocketGetSubscriptions:input_type -> gctrpc.WebsocketGetSubscriptionsRequest - 139, // 161: gctrpc.GoCryptoTrader.WebsocketSetProxy:input_type -> gctrpc.WebsocketSetProxyRequest - 140, // 162: gctrpc.GoCryptoTrader.WebsocketSetURL:input_type -> gctrpc.WebsocketSetURLRequest - 107, // 163: gctrpc.GoCryptoTrader.GetRecentTrades:input_type -> gctrpc.GetSavedTradesRequest - 107, // 164: gctrpc.GoCryptoTrader.GetHistoricTrades:input_type -> gctrpc.GetSavedTradesRequest - 107, // 165: gctrpc.GoCryptoTrader.GetSavedTrades:input_type -> gctrpc.GetSavedTradesRequest - 110, // 166: gctrpc.GoCryptoTrader.ConvertTradesToCandles:input_type -> gctrpc.ConvertTradesToCandlesRequest - 141, // 167: gctrpc.GoCryptoTrader.FindMissingSavedCandleIntervals:input_type -> gctrpc.FindMissingCandlePeriodsRequest - 142, // 168: gctrpc.GoCryptoTrader.FindMissingSavedTradeIntervals:input_type -> gctrpc.FindMissingTradePeriodsRequest - 144, // 169: gctrpc.GoCryptoTrader.SetExchangeTradeProcessing:input_type -> gctrpc.SetExchangeTradeProcessingRequest - 145, // 170: gctrpc.GoCryptoTrader.UpsertDataHistoryJob:input_type -> gctrpc.UpsertDataHistoryJobRequest - 147, // 171: gctrpc.GoCryptoTrader.GetDataHistoryJobDetails:input_type -> gctrpc.GetDataHistoryJobDetailsRequest - 0, // 172: gctrpc.GoCryptoTrader.GetActiveDataHistoryJobs:input_type -> gctrpc.GetInfoRequest - 147, // 173: gctrpc.GoCryptoTrader.DeleteDataHistoryJob:input_type -> gctrpc.GetDataHistoryJobDetailsRequest - 151, // 174: gctrpc.GoCryptoTrader.GetDataHistoryJobsBetween:input_type -> gctrpc.GetDataHistoryJobsBetweenRequest - 147, // 175: gctrpc.GoCryptoTrader.GetDataHistoryJobSummary:input_type -> gctrpc.GetDataHistoryJobDetailsRequest - 58, // 176: gctrpc.GoCryptoTrader.GetManagedOrders:input_type -> gctrpc.GetOrdersRequest - 1, // 177: gctrpc.GoCryptoTrader.GetInfo:output_type -> gctrpc.GetInfoResponse - 7, // 178: gctrpc.GoCryptoTrader.GetSubsystems:output_type -> gctrpc.GetSusbsytemsResponse - 127, // 179: gctrpc.GoCryptoTrader.EnableSubsystem:output_type -> gctrpc.GenericResponse - 127, // 180: gctrpc.GoCryptoTrader.DisableSubsystem:output_type -> gctrpc.GenericResponse - 10, // 181: gctrpc.GoCryptoTrader.GetRPCEndpoints:output_type -> gctrpc.GetRPCEndpointsResponse - 4, // 182: gctrpc.GoCryptoTrader.GetCommunicationRelayers:output_type -> gctrpc.GetCommunicationRelayersResponse - 13, // 183: gctrpc.GoCryptoTrader.GetExchanges:output_type -> gctrpc.GetExchangesResponse - 127, // 184: gctrpc.GoCryptoTrader.DisableExchange:output_type -> gctrpc.GenericResponse - 19, // 185: gctrpc.GoCryptoTrader.GetExchangeInfo:output_type -> gctrpc.GetExchangeInfoResponse - 14, // 186: gctrpc.GoCryptoTrader.GetExchangeOTPCode:output_type -> gctrpc.GetExchangeOTPReponse - 16, // 187: gctrpc.GoCryptoTrader.GetExchangeOTPCodes:output_type -> gctrpc.GetExchangeOTPsResponse - 127, // 188: gctrpc.GoCryptoTrader.EnableExchange:output_type -> gctrpc.GenericResponse - 22, // 189: gctrpc.GoCryptoTrader.GetTicker:output_type -> gctrpc.TickerResponse - 25, // 190: gctrpc.GoCryptoTrader.GetTickers:output_type -> gctrpc.GetTickersResponse - 28, // 191: gctrpc.GoCryptoTrader.GetOrderbook:output_type -> gctrpc.OrderbookResponse - 31, // 192: gctrpc.GoCryptoTrader.GetOrderbooks:output_type -> gctrpc.GetOrderbooksResponse - 35, // 193: gctrpc.GoCryptoTrader.GetAccountInfo:output_type -> gctrpc.GetAccountInfoResponse - 35, // 194: gctrpc.GoCryptoTrader.UpdateAccountInfo:output_type -> gctrpc.GetAccountInfoResponse - 35, // 195: gctrpc.GoCryptoTrader.GetAccountInfoStream:output_type -> gctrpc.GetAccountInfoResponse - 37, // 196: gctrpc.GoCryptoTrader.GetConfig:output_type -> gctrpc.GetConfigResponse - 40, // 197: gctrpc.GoCryptoTrader.GetPortfolio:output_type -> gctrpc.GetPortfolioResponse - 47, // 198: gctrpc.GoCryptoTrader.GetPortfolioSummary:output_type -> gctrpc.GetPortfolioSummaryResponse - 127, // 199: gctrpc.GoCryptoTrader.AddPortfolioAddress:output_type -> gctrpc.GenericResponse - 127, // 200: gctrpc.GoCryptoTrader.RemovePortfolioAddress:output_type -> gctrpc.GenericResponse - 52, // 201: gctrpc.GoCryptoTrader.GetForexProviders:output_type -> gctrpc.GetForexProvidersResponse - 55, // 202: gctrpc.GoCryptoTrader.GetForexRates:output_type -> gctrpc.GetForexRatesResponse - 59, // 203: gctrpc.GoCryptoTrader.GetOrders:output_type -> gctrpc.GetOrdersResponse - 56, // 204: gctrpc.GoCryptoTrader.GetOrder:output_type -> gctrpc.OrderDetails - 63, // 205: gctrpc.GoCryptoTrader.SubmitOrder:output_type -> gctrpc.SubmitOrderResponse - 65, // 206: gctrpc.GoCryptoTrader.SimulateOrder:output_type -> gctrpc.SimulateOrderResponse - 65, // 207: gctrpc.GoCryptoTrader.WhaleBomb:output_type -> gctrpc.SimulateOrderResponse - 127, // 208: gctrpc.GoCryptoTrader.CancelOrder:output_type -> gctrpc.GenericResponse - 69, // 209: gctrpc.GoCryptoTrader.CancelBatchOrders:output_type -> gctrpc.CancelBatchOrdersResponse - 71, // 210: gctrpc.GoCryptoTrader.CancelAllOrders:output_type -> gctrpc.CancelAllOrdersResponse - 74, // 211: gctrpc.GoCryptoTrader.GetEvents:output_type -> gctrpc.GetEventsResponse - 76, // 212: gctrpc.GoCryptoTrader.AddEvent:output_type -> gctrpc.AddEventResponse - 127, // 213: gctrpc.GoCryptoTrader.RemoveEvent:output_type -> gctrpc.GenericResponse - 79, // 214: gctrpc.GoCryptoTrader.GetCryptocurrencyDepositAddresses:output_type -> gctrpc.GetCryptocurrencyDepositAddressesResponse - 81, // 215: gctrpc.GoCryptoTrader.GetCryptocurrencyDepositAddress:output_type -> gctrpc.GetCryptocurrencyDepositAddressResponse - 84, // 216: gctrpc.GoCryptoTrader.WithdrawFiatFunds:output_type -> gctrpc.WithdrawResponse - 84, // 217: gctrpc.GoCryptoTrader.WithdrawCryptocurrencyFunds:output_type -> gctrpc.WithdrawResponse - 86, // 218: gctrpc.GoCryptoTrader.WithdrawalEventByID:output_type -> gctrpc.WithdrawalEventByIDResponse - 89, // 219: gctrpc.GoCryptoTrader.WithdrawalEventsByExchange:output_type -> gctrpc.WithdrawalEventsByExchangeResponse - 89, // 220: gctrpc.GoCryptoTrader.WithdrawalEventsByDate:output_type -> gctrpc.WithdrawalEventsByExchangeResponse - 96, // 221: gctrpc.GoCryptoTrader.GetLoggerDetails:output_type -> gctrpc.GetLoggerDetailsResponse - 96, // 222: gctrpc.GoCryptoTrader.SetLoggerDetails:output_type -> gctrpc.GetLoggerDetailsResponse - 99, // 223: gctrpc.GoCryptoTrader.GetExchangePairs:output_type -> gctrpc.GetExchangePairsResponse - 127, // 224: gctrpc.GoCryptoTrader.SetExchangePair:output_type -> gctrpc.GenericResponse - 28, // 225: gctrpc.GoCryptoTrader.GetOrderbookStream:output_type -> gctrpc.OrderbookResponse - 28, // 226: gctrpc.GoCryptoTrader.GetExchangeOrderbookStream:output_type -> gctrpc.OrderbookResponse - 22, // 227: gctrpc.GoCryptoTrader.GetTickerStream:output_type -> gctrpc.TickerResponse - 22, // 228: gctrpc.GoCryptoTrader.GetExchangeTickerStream:output_type -> gctrpc.TickerResponse - 106, // 229: gctrpc.GoCryptoTrader.GetAuditEvent:output_type -> gctrpc.GetAuditEventResponse - 127, // 230: gctrpc.GoCryptoTrader.GCTScriptExecute:output_type -> gctrpc.GenericResponse - 127, // 231: gctrpc.GoCryptoTrader.GCTScriptUpload:output_type -> gctrpc.GenericResponse - 126, // 232: gctrpc.GoCryptoTrader.GCTScriptReadScript:output_type -> gctrpc.GCTScriptQueryResponse - 125, // 233: gctrpc.GoCryptoTrader.GCTScriptStatus:output_type -> gctrpc.GCTScriptStatusResponse - 126, // 234: gctrpc.GoCryptoTrader.GCTScriptQuery:output_type -> gctrpc.GCTScriptQueryResponse - 127, // 235: gctrpc.GoCryptoTrader.GCTScriptStop:output_type -> gctrpc.GenericResponse - 127, // 236: gctrpc.GoCryptoTrader.GCTScriptStopAll:output_type -> gctrpc.GenericResponse - 125, // 237: gctrpc.GoCryptoTrader.GCTScriptListAll:output_type -> gctrpc.GCTScriptStatusResponse - 127, // 238: gctrpc.GoCryptoTrader.GCTScriptAutoLoadToggle:output_type -> gctrpc.GenericResponse - 112, // 239: gctrpc.GoCryptoTrader.GetHistoricCandles:output_type -> gctrpc.GetHistoricCandlesResponse - 127, // 240: gctrpc.GoCryptoTrader.SetExchangeAsset:output_type -> gctrpc.GenericResponse - 127, // 241: gctrpc.GoCryptoTrader.SetAllExchangePairs:output_type -> gctrpc.GenericResponse - 127, // 242: gctrpc.GoCryptoTrader.UpdateExchangeSupportedPairs:output_type -> gctrpc.GenericResponse - 132, // 243: gctrpc.GoCryptoTrader.GetExchangeAssets:output_type -> gctrpc.GetExchangeAssetsResponse - 134, // 244: gctrpc.GoCryptoTrader.WebsocketGetInfo:output_type -> gctrpc.WebsocketGetInfoResponse - 127, // 245: gctrpc.GoCryptoTrader.WebsocketSetEnabled:output_type -> gctrpc.GenericResponse - 138, // 246: gctrpc.GoCryptoTrader.WebsocketGetSubscriptions:output_type -> gctrpc.WebsocketGetSubscriptionsResponse - 127, // 247: gctrpc.GoCryptoTrader.WebsocketSetProxy:output_type -> gctrpc.GenericResponse - 127, // 248: gctrpc.GoCryptoTrader.WebsocketSetURL:output_type -> gctrpc.GenericResponse - 109, // 249: gctrpc.GoCryptoTrader.GetRecentTrades:output_type -> gctrpc.SavedTradesResponse - 109, // 250: gctrpc.GoCryptoTrader.GetHistoricTrades:output_type -> gctrpc.SavedTradesResponse - 109, // 251: gctrpc.GoCryptoTrader.GetSavedTrades:output_type -> gctrpc.SavedTradesResponse - 112, // 252: gctrpc.GoCryptoTrader.ConvertTradesToCandles:output_type -> gctrpc.GetHistoricCandlesResponse - 143, // 253: gctrpc.GoCryptoTrader.FindMissingSavedCandleIntervals:output_type -> gctrpc.FindMissingIntervalsResponse - 143, // 254: gctrpc.GoCryptoTrader.FindMissingSavedTradeIntervals:output_type -> gctrpc.FindMissingIntervalsResponse - 127, // 255: gctrpc.GoCryptoTrader.SetExchangeTradeProcessing:output_type -> gctrpc.GenericResponse - 146, // 256: gctrpc.GoCryptoTrader.UpsertDataHistoryJob:output_type -> gctrpc.UpsertDataHistoryJobResponse - 148, // 257: gctrpc.GoCryptoTrader.GetDataHistoryJobDetails:output_type -> gctrpc.DataHistoryJob - 150, // 258: gctrpc.GoCryptoTrader.GetActiveDataHistoryJobs:output_type -> gctrpc.DataHistoryJobs - 127, // 259: gctrpc.GoCryptoTrader.DeleteDataHistoryJob:output_type -> gctrpc.GenericResponse - 150, // 260: gctrpc.GoCryptoTrader.GetDataHistoryJobsBetween:output_type -> gctrpc.DataHistoryJobs - 148, // 261: gctrpc.GoCryptoTrader.GetDataHistoryJobSummary:output_type -> gctrpc.DataHistoryJob - 59, // 262: gctrpc.GoCryptoTrader.GetManagedOrders:output_type -> gctrpc.GetOrdersResponse - 177, // [177:263] is the sub-list for method output_type - 91, // [91:177] is the sub-list for method input_type - 91, // [91:91] is the sub-list for extension type_name - 91, // [91:91] is the sub-list for extension extendee - 0, // [0:91] is the sub-list for field type_name + 145, // 78: gctrpc.InsertSequentialJobsRequest.jobs:type_name -> gctrpc.UpsertDataHistoryJobRequest + 148, // 79: gctrpc.InsertSequentialJobsResponse.jobs:type_name -> gctrpc.UpsertDataHistoryJobResponse + 21, // 80: gctrpc.DataHistoryJob.pair:type_name -> gctrpc.CurrencyPair + 151, // 81: gctrpc.DataHistoryJob.job_results:type_name -> gctrpc.DataHistoryJobResult + 150, // 82: gctrpc.DataHistoryJobs.results:type_name -> gctrpc.DataHistoryJob + 9, // 83: gctrpc.GetInfoResponse.RpcEndpointsEntry.value:type_name -> gctrpc.RPCEndpoint + 3, // 84: gctrpc.GetCommunicationRelayersResponse.CommunicationRelayersEntry.value:type_name -> gctrpc.CommunicationRelayer + 9, // 85: gctrpc.GetRPCEndpointsResponse.EndpointsEntry.value:type_name -> gctrpc.RPCEndpoint + 18, // 86: gctrpc.GetExchangeInfoResponse.SupportedAssetsEntry.value:type_name -> gctrpc.PairsSupported + 44, // 87: gctrpc.OnlineCoins.CoinsEntry.value:type_name -> gctrpc.OnlineCoinSummary + 45, // 88: gctrpc.GetPortfolioSummaryResponse.CoinsOfflineSummaryEntry.value:type_name -> gctrpc.OfflineCoins + 46, // 89: gctrpc.GetPortfolioSummaryResponse.CoinsOnlineSummaryEntry.value:type_name -> gctrpc.OnlineCoins + 167, // 90: gctrpc.CancelBatchOrdersResponse.Orders.order_status:type_name -> gctrpc.CancelBatchOrdersResponse.Orders.OrderStatusEntry + 169, // 91: gctrpc.CancelAllOrdersResponse.Orders.order_status:type_name -> gctrpc.CancelAllOrdersResponse.Orders.OrderStatusEntry + 18, // 92: gctrpc.GetExchangePairsResponse.SupportedAssetsEntry.value:type_name -> gctrpc.PairsSupported + 0, // 93: gctrpc.GoCryptoTrader.GetInfo:input_type -> gctrpc.GetInfoRequest + 6, // 94: gctrpc.GoCryptoTrader.GetSubsystems:input_type -> gctrpc.GetSubsystemsRequest + 5, // 95: gctrpc.GoCryptoTrader.EnableSubsystem:input_type -> gctrpc.GenericSubsystemRequest + 5, // 96: gctrpc.GoCryptoTrader.DisableSubsystem:input_type -> gctrpc.GenericSubsystemRequest + 8, // 97: gctrpc.GoCryptoTrader.GetRPCEndpoints:input_type -> gctrpc.GetRPCEndpointsRequest + 2, // 98: gctrpc.GoCryptoTrader.GetCommunicationRelayers:input_type -> gctrpc.GetCommunicationRelayersRequest + 12, // 99: gctrpc.GoCryptoTrader.GetExchanges:input_type -> gctrpc.GetExchangesRequest + 11, // 100: gctrpc.GoCryptoTrader.DisableExchange:input_type -> gctrpc.GenericExchangeNameRequest + 11, // 101: gctrpc.GoCryptoTrader.GetExchangeInfo:input_type -> gctrpc.GenericExchangeNameRequest + 11, // 102: gctrpc.GoCryptoTrader.GetExchangeOTPCode:input_type -> gctrpc.GenericExchangeNameRequest + 15, // 103: gctrpc.GoCryptoTrader.GetExchangeOTPCodes:input_type -> gctrpc.GetExchangeOTPsRequest + 11, // 104: gctrpc.GoCryptoTrader.EnableExchange:input_type -> gctrpc.GenericExchangeNameRequest + 20, // 105: gctrpc.GoCryptoTrader.GetTicker:input_type -> gctrpc.GetTickerRequest + 23, // 106: gctrpc.GoCryptoTrader.GetTickers:input_type -> gctrpc.GetTickersRequest + 26, // 107: gctrpc.GoCryptoTrader.GetOrderbook:input_type -> gctrpc.GetOrderbookRequest + 29, // 108: gctrpc.GoCryptoTrader.GetOrderbooks:input_type -> gctrpc.GetOrderbooksRequest + 32, // 109: gctrpc.GoCryptoTrader.GetAccountInfo:input_type -> gctrpc.GetAccountInfoRequest + 32, // 110: gctrpc.GoCryptoTrader.UpdateAccountInfo:input_type -> gctrpc.GetAccountInfoRequest + 32, // 111: gctrpc.GoCryptoTrader.GetAccountInfoStream:input_type -> gctrpc.GetAccountInfoRequest + 36, // 112: gctrpc.GoCryptoTrader.GetConfig:input_type -> gctrpc.GetConfigRequest + 39, // 113: gctrpc.GoCryptoTrader.GetPortfolio:input_type -> gctrpc.GetPortfolioRequest + 41, // 114: gctrpc.GoCryptoTrader.GetPortfolioSummary:input_type -> gctrpc.GetPortfolioSummaryRequest + 48, // 115: gctrpc.GoCryptoTrader.AddPortfolioAddress:input_type -> gctrpc.AddPortfolioAddressRequest + 49, // 116: gctrpc.GoCryptoTrader.RemovePortfolioAddress:input_type -> gctrpc.RemovePortfolioAddressRequest + 50, // 117: gctrpc.GoCryptoTrader.GetForexProviders:input_type -> gctrpc.GetForexProvidersRequest + 53, // 118: gctrpc.GoCryptoTrader.GetForexRates:input_type -> gctrpc.GetForexRatesRequest + 58, // 119: gctrpc.GoCryptoTrader.GetOrders:input_type -> gctrpc.GetOrdersRequest + 60, // 120: gctrpc.GoCryptoTrader.GetOrder:input_type -> gctrpc.GetOrderRequest + 61, // 121: gctrpc.GoCryptoTrader.SubmitOrder:input_type -> gctrpc.SubmitOrderRequest + 64, // 122: gctrpc.GoCryptoTrader.SimulateOrder:input_type -> gctrpc.SimulateOrderRequest + 66, // 123: gctrpc.GoCryptoTrader.WhaleBomb:input_type -> gctrpc.WhaleBombRequest + 67, // 124: gctrpc.GoCryptoTrader.CancelOrder:input_type -> gctrpc.CancelOrderRequest + 68, // 125: gctrpc.GoCryptoTrader.CancelBatchOrders:input_type -> gctrpc.CancelBatchOrdersRequest + 70, // 126: gctrpc.GoCryptoTrader.CancelAllOrders:input_type -> gctrpc.CancelAllOrdersRequest + 72, // 127: gctrpc.GoCryptoTrader.GetEvents:input_type -> gctrpc.GetEventsRequest + 75, // 128: gctrpc.GoCryptoTrader.AddEvent:input_type -> gctrpc.AddEventRequest + 77, // 129: gctrpc.GoCryptoTrader.RemoveEvent:input_type -> gctrpc.RemoveEventRequest + 78, // 130: gctrpc.GoCryptoTrader.GetCryptocurrencyDepositAddresses:input_type -> gctrpc.GetCryptocurrencyDepositAddressesRequest + 80, // 131: gctrpc.GoCryptoTrader.GetCryptocurrencyDepositAddress:input_type -> gctrpc.GetCryptocurrencyDepositAddressRequest + 82, // 132: gctrpc.GoCryptoTrader.WithdrawFiatFunds:input_type -> gctrpc.WithdrawFiatRequest + 83, // 133: gctrpc.GoCryptoTrader.WithdrawCryptocurrencyFunds:input_type -> gctrpc.WithdrawCryptoRequest + 85, // 134: gctrpc.GoCryptoTrader.WithdrawalEventByID:input_type -> gctrpc.WithdrawalEventByIDRequest + 87, // 135: gctrpc.GoCryptoTrader.WithdrawalEventsByExchange:input_type -> gctrpc.WithdrawalEventsByExchangeRequest + 88, // 136: gctrpc.GoCryptoTrader.WithdrawalEventsByDate:input_type -> gctrpc.WithdrawalEventsByDateRequest + 95, // 137: gctrpc.GoCryptoTrader.GetLoggerDetails:input_type -> gctrpc.GetLoggerDetailsRequest + 97, // 138: gctrpc.GoCryptoTrader.SetLoggerDetails:input_type -> gctrpc.SetLoggerDetailsRequest + 98, // 139: gctrpc.GoCryptoTrader.GetExchangePairs:input_type -> gctrpc.GetExchangePairsRequest + 100, // 140: gctrpc.GoCryptoTrader.SetExchangePair:input_type -> gctrpc.SetExchangePairRequest + 101, // 141: gctrpc.GoCryptoTrader.GetOrderbookStream:input_type -> gctrpc.GetOrderbookStreamRequest + 102, // 142: gctrpc.GoCryptoTrader.GetExchangeOrderbookStream:input_type -> gctrpc.GetExchangeOrderbookStreamRequest + 103, // 143: gctrpc.GoCryptoTrader.GetTickerStream:input_type -> gctrpc.GetTickerStreamRequest + 104, // 144: gctrpc.GoCryptoTrader.GetExchangeTickerStream:input_type -> gctrpc.GetExchangeTickerStreamRequest + 105, // 145: gctrpc.GoCryptoTrader.GetAuditEvent:input_type -> gctrpc.GetAuditEventRequest + 116, // 146: gctrpc.GoCryptoTrader.GCTScriptExecute:input_type -> gctrpc.GCTScriptExecuteRequest + 121, // 147: gctrpc.GoCryptoTrader.GCTScriptUpload:input_type -> gctrpc.GCTScriptUploadRequest + 122, // 148: gctrpc.GoCryptoTrader.GCTScriptReadScript:input_type -> gctrpc.GCTScriptReadScriptRequest + 119, // 149: gctrpc.GoCryptoTrader.GCTScriptStatus:input_type -> gctrpc.GCTScriptStatusRequest + 123, // 150: gctrpc.GoCryptoTrader.GCTScriptQuery:input_type -> gctrpc.GCTScriptQueryRequest + 117, // 151: gctrpc.GoCryptoTrader.GCTScriptStop:input_type -> gctrpc.GCTScriptStopRequest + 118, // 152: gctrpc.GoCryptoTrader.GCTScriptStopAll:input_type -> gctrpc.GCTScriptStopAllRequest + 120, // 153: gctrpc.GoCryptoTrader.GCTScriptListAll:input_type -> gctrpc.GCTScriptListAllRequest + 124, // 154: gctrpc.GoCryptoTrader.GCTScriptAutoLoadToggle:input_type -> gctrpc.GCTScriptAutoLoadRequest + 111, // 155: gctrpc.GoCryptoTrader.GetHistoricCandles:input_type -> gctrpc.GetHistoricCandlesRequest + 128, // 156: gctrpc.GoCryptoTrader.SetExchangeAsset:input_type -> gctrpc.SetExchangeAssetRequest + 129, // 157: gctrpc.GoCryptoTrader.SetAllExchangePairs:input_type -> gctrpc.SetExchangeAllPairsRequest + 130, // 158: gctrpc.GoCryptoTrader.UpdateExchangeSupportedPairs:input_type -> gctrpc.UpdateExchangeSupportedPairsRequest + 131, // 159: gctrpc.GoCryptoTrader.GetExchangeAssets:input_type -> gctrpc.GetExchangeAssetsRequest + 133, // 160: gctrpc.GoCryptoTrader.WebsocketGetInfo:input_type -> gctrpc.WebsocketGetInfoRequest + 135, // 161: gctrpc.GoCryptoTrader.WebsocketSetEnabled:input_type -> gctrpc.WebsocketSetEnabledRequest + 136, // 162: gctrpc.GoCryptoTrader.WebsocketGetSubscriptions:input_type -> gctrpc.WebsocketGetSubscriptionsRequest + 139, // 163: gctrpc.GoCryptoTrader.WebsocketSetProxy:input_type -> gctrpc.WebsocketSetProxyRequest + 140, // 164: gctrpc.GoCryptoTrader.WebsocketSetURL:input_type -> gctrpc.WebsocketSetURLRequest + 107, // 165: gctrpc.GoCryptoTrader.GetRecentTrades:input_type -> gctrpc.GetSavedTradesRequest + 107, // 166: gctrpc.GoCryptoTrader.GetHistoricTrades:input_type -> gctrpc.GetSavedTradesRequest + 107, // 167: gctrpc.GoCryptoTrader.GetSavedTrades:input_type -> gctrpc.GetSavedTradesRequest + 110, // 168: gctrpc.GoCryptoTrader.ConvertTradesToCandles:input_type -> gctrpc.ConvertTradesToCandlesRequest + 141, // 169: gctrpc.GoCryptoTrader.FindMissingSavedCandleIntervals:input_type -> gctrpc.FindMissingCandlePeriodsRequest + 142, // 170: gctrpc.GoCryptoTrader.FindMissingSavedTradeIntervals:input_type -> gctrpc.FindMissingTradePeriodsRequest + 144, // 171: gctrpc.GoCryptoTrader.SetExchangeTradeProcessing:input_type -> gctrpc.SetExchangeTradeProcessingRequest + 145, // 172: gctrpc.GoCryptoTrader.UpsertDataHistoryJob:input_type -> gctrpc.UpsertDataHistoryJobRequest + 149, // 173: gctrpc.GoCryptoTrader.GetDataHistoryJobDetails:input_type -> gctrpc.GetDataHistoryJobDetailsRequest + 0, // 174: gctrpc.GoCryptoTrader.GetActiveDataHistoryJobs:input_type -> gctrpc.GetInfoRequest + 153, // 175: gctrpc.GoCryptoTrader.GetDataHistoryJobsBetween:input_type -> gctrpc.GetDataHistoryJobsBetweenRequest + 149, // 176: gctrpc.GoCryptoTrader.GetDataHistoryJobSummary:input_type -> gctrpc.GetDataHistoryJobDetailsRequest + 154, // 177: gctrpc.GoCryptoTrader.SetDataHistoryJobStatus:input_type -> gctrpc.SetDataHistoryJobStatusRequest + 155, // 178: gctrpc.GoCryptoTrader.UpdateDataHistoryJobPrerequisite:input_type -> gctrpc.UpdateDataHistoryJobPrerequisiteRequest + 58, // 179: gctrpc.GoCryptoTrader.GetManagedOrders:input_type -> gctrpc.GetOrdersRequest + 1, // 180: gctrpc.GoCryptoTrader.GetInfo:output_type -> gctrpc.GetInfoResponse + 7, // 181: gctrpc.GoCryptoTrader.GetSubsystems:output_type -> gctrpc.GetSusbsytemsResponse + 127, // 182: gctrpc.GoCryptoTrader.EnableSubsystem:output_type -> gctrpc.GenericResponse + 127, // 183: gctrpc.GoCryptoTrader.DisableSubsystem:output_type -> gctrpc.GenericResponse + 10, // 184: gctrpc.GoCryptoTrader.GetRPCEndpoints:output_type -> gctrpc.GetRPCEndpointsResponse + 4, // 185: gctrpc.GoCryptoTrader.GetCommunicationRelayers:output_type -> gctrpc.GetCommunicationRelayersResponse + 13, // 186: gctrpc.GoCryptoTrader.GetExchanges:output_type -> gctrpc.GetExchangesResponse + 127, // 187: gctrpc.GoCryptoTrader.DisableExchange:output_type -> gctrpc.GenericResponse + 19, // 188: gctrpc.GoCryptoTrader.GetExchangeInfo:output_type -> gctrpc.GetExchangeInfoResponse + 14, // 189: gctrpc.GoCryptoTrader.GetExchangeOTPCode:output_type -> gctrpc.GetExchangeOTPReponse + 16, // 190: gctrpc.GoCryptoTrader.GetExchangeOTPCodes:output_type -> gctrpc.GetExchangeOTPsResponse + 127, // 191: gctrpc.GoCryptoTrader.EnableExchange:output_type -> gctrpc.GenericResponse + 22, // 192: gctrpc.GoCryptoTrader.GetTicker:output_type -> gctrpc.TickerResponse + 25, // 193: gctrpc.GoCryptoTrader.GetTickers:output_type -> gctrpc.GetTickersResponse + 28, // 194: gctrpc.GoCryptoTrader.GetOrderbook:output_type -> gctrpc.OrderbookResponse + 31, // 195: gctrpc.GoCryptoTrader.GetOrderbooks:output_type -> gctrpc.GetOrderbooksResponse + 35, // 196: gctrpc.GoCryptoTrader.GetAccountInfo:output_type -> gctrpc.GetAccountInfoResponse + 35, // 197: gctrpc.GoCryptoTrader.UpdateAccountInfo:output_type -> gctrpc.GetAccountInfoResponse + 35, // 198: gctrpc.GoCryptoTrader.GetAccountInfoStream:output_type -> gctrpc.GetAccountInfoResponse + 37, // 199: gctrpc.GoCryptoTrader.GetConfig:output_type -> gctrpc.GetConfigResponse + 40, // 200: gctrpc.GoCryptoTrader.GetPortfolio:output_type -> gctrpc.GetPortfolioResponse + 47, // 201: gctrpc.GoCryptoTrader.GetPortfolioSummary:output_type -> gctrpc.GetPortfolioSummaryResponse + 127, // 202: gctrpc.GoCryptoTrader.AddPortfolioAddress:output_type -> gctrpc.GenericResponse + 127, // 203: gctrpc.GoCryptoTrader.RemovePortfolioAddress:output_type -> gctrpc.GenericResponse + 52, // 204: gctrpc.GoCryptoTrader.GetForexProviders:output_type -> gctrpc.GetForexProvidersResponse + 55, // 205: gctrpc.GoCryptoTrader.GetForexRates:output_type -> gctrpc.GetForexRatesResponse + 59, // 206: gctrpc.GoCryptoTrader.GetOrders:output_type -> gctrpc.GetOrdersResponse + 56, // 207: gctrpc.GoCryptoTrader.GetOrder:output_type -> gctrpc.OrderDetails + 63, // 208: gctrpc.GoCryptoTrader.SubmitOrder:output_type -> gctrpc.SubmitOrderResponse + 65, // 209: gctrpc.GoCryptoTrader.SimulateOrder:output_type -> gctrpc.SimulateOrderResponse + 65, // 210: gctrpc.GoCryptoTrader.WhaleBomb:output_type -> gctrpc.SimulateOrderResponse + 127, // 211: gctrpc.GoCryptoTrader.CancelOrder:output_type -> gctrpc.GenericResponse + 69, // 212: gctrpc.GoCryptoTrader.CancelBatchOrders:output_type -> gctrpc.CancelBatchOrdersResponse + 71, // 213: gctrpc.GoCryptoTrader.CancelAllOrders:output_type -> gctrpc.CancelAllOrdersResponse + 74, // 214: gctrpc.GoCryptoTrader.GetEvents:output_type -> gctrpc.GetEventsResponse + 76, // 215: gctrpc.GoCryptoTrader.AddEvent:output_type -> gctrpc.AddEventResponse + 127, // 216: gctrpc.GoCryptoTrader.RemoveEvent:output_type -> gctrpc.GenericResponse + 79, // 217: gctrpc.GoCryptoTrader.GetCryptocurrencyDepositAddresses:output_type -> gctrpc.GetCryptocurrencyDepositAddressesResponse + 81, // 218: gctrpc.GoCryptoTrader.GetCryptocurrencyDepositAddress:output_type -> gctrpc.GetCryptocurrencyDepositAddressResponse + 84, // 219: gctrpc.GoCryptoTrader.WithdrawFiatFunds:output_type -> gctrpc.WithdrawResponse + 84, // 220: gctrpc.GoCryptoTrader.WithdrawCryptocurrencyFunds:output_type -> gctrpc.WithdrawResponse + 86, // 221: gctrpc.GoCryptoTrader.WithdrawalEventByID:output_type -> gctrpc.WithdrawalEventByIDResponse + 89, // 222: gctrpc.GoCryptoTrader.WithdrawalEventsByExchange:output_type -> gctrpc.WithdrawalEventsByExchangeResponse + 89, // 223: gctrpc.GoCryptoTrader.WithdrawalEventsByDate:output_type -> gctrpc.WithdrawalEventsByExchangeResponse + 96, // 224: gctrpc.GoCryptoTrader.GetLoggerDetails:output_type -> gctrpc.GetLoggerDetailsResponse + 96, // 225: gctrpc.GoCryptoTrader.SetLoggerDetails:output_type -> gctrpc.GetLoggerDetailsResponse + 99, // 226: gctrpc.GoCryptoTrader.GetExchangePairs:output_type -> gctrpc.GetExchangePairsResponse + 127, // 227: gctrpc.GoCryptoTrader.SetExchangePair:output_type -> gctrpc.GenericResponse + 28, // 228: gctrpc.GoCryptoTrader.GetOrderbookStream:output_type -> gctrpc.OrderbookResponse + 28, // 229: gctrpc.GoCryptoTrader.GetExchangeOrderbookStream:output_type -> gctrpc.OrderbookResponse + 22, // 230: gctrpc.GoCryptoTrader.GetTickerStream:output_type -> gctrpc.TickerResponse + 22, // 231: gctrpc.GoCryptoTrader.GetExchangeTickerStream:output_type -> gctrpc.TickerResponse + 106, // 232: gctrpc.GoCryptoTrader.GetAuditEvent:output_type -> gctrpc.GetAuditEventResponse + 127, // 233: gctrpc.GoCryptoTrader.GCTScriptExecute:output_type -> gctrpc.GenericResponse + 127, // 234: gctrpc.GoCryptoTrader.GCTScriptUpload:output_type -> gctrpc.GenericResponse + 126, // 235: gctrpc.GoCryptoTrader.GCTScriptReadScript:output_type -> gctrpc.GCTScriptQueryResponse + 125, // 236: gctrpc.GoCryptoTrader.GCTScriptStatus:output_type -> gctrpc.GCTScriptStatusResponse + 126, // 237: gctrpc.GoCryptoTrader.GCTScriptQuery:output_type -> gctrpc.GCTScriptQueryResponse + 127, // 238: gctrpc.GoCryptoTrader.GCTScriptStop:output_type -> gctrpc.GenericResponse + 127, // 239: gctrpc.GoCryptoTrader.GCTScriptStopAll:output_type -> gctrpc.GenericResponse + 125, // 240: gctrpc.GoCryptoTrader.GCTScriptListAll:output_type -> gctrpc.GCTScriptStatusResponse + 127, // 241: gctrpc.GoCryptoTrader.GCTScriptAutoLoadToggle:output_type -> gctrpc.GenericResponse + 112, // 242: gctrpc.GoCryptoTrader.GetHistoricCandles:output_type -> gctrpc.GetHistoricCandlesResponse + 127, // 243: gctrpc.GoCryptoTrader.SetExchangeAsset:output_type -> gctrpc.GenericResponse + 127, // 244: gctrpc.GoCryptoTrader.SetAllExchangePairs:output_type -> gctrpc.GenericResponse + 127, // 245: gctrpc.GoCryptoTrader.UpdateExchangeSupportedPairs:output_type -> gctrpc.GenericResponse + 132, // 246: gctrpc.GoCryptoTrader.GetExchangeAssets:output_type -> gctrpc.GetExchangeAssetsResponse + 134, // 247: gctrpc.GoCryptoTrader.WebsocketGetInfo:output_type -> gctrpc.WebsocketGetInfoResponse + 127, // 248: gctrpc.GoCryptoTrader.WebsocketSetEnabled:output_type -> gctrpc.GenericResponse + 138, // 249: gctrpc.GoCryptoTrader.WebsocketGetSubscriptions:output_type -> gctrpc.WebsocketGetSubscriptionsResponse + 127, // 250: gctrpc.GoCryptoTrader.WebsocketSetProxy:output_type -> gctrpc.GenericResponse + 127, // 251: gctrpc.GoCryptoTrader.WebsocketSetURL:output_type -> gctrpc.GenericResponse + 109, // 252: gctrpc.GoCryptoTrader.GetRecentTrades:output_type -> gctrpc.SavedTradesResponse + 109, // 253: gctrpc.GoCryptoTrader.GetHistoricTrades:output_type -> gctrpc.SavedTradesResponse + 109, // 254: gctrpc.GoCryptoTrader.GetSavedTrades:output_type -> gctrpc.SavedTradesResponse + 112, // 255: gctrpc.GoCryptoTrader.ConvertTradesToCandles:output_type -> gctrpc.GetHistoricCandlesResponse + 143, // 256: gctrpc.GoCryptoTrader.FindMissingSavedCandleIntervals:output_type -> gctrpc.FindMissingIntervalsResponse + 143, // 257: gctrpc.GoCryptoTrader.FindMissingSavedTradeIntervals:output_type -> gctrpc.FindMissingIntervalsResponse + 127, // 258: gctrpc.GoCryptoTrader.SetExchangeTradeProcessing:output_type -> gctrpc.GenericResponse + 148, // 259: gctrpc.GoCryptoTrader.UpsertDataHistoryJob:output_type -> gctrpc.UpsertDataHistoryJobResponse + 150, // 260: gctrpc.GoCryptoTrader.GetDataHistoryJobDetails:output_type -> gctrpc.DataHistoryJob + 152, // 261: gctrpc.GoCryptoTrader.GetActiveDataHistoryJobs:output_type -> gctrpc.DataHistoryJobs + 152, // 262: gctrpc.GoCryptoTrader.GetDataHistoryJobsBetween:output_type -> gctrpc.DataHistoryJobs + 150, // 263: gctrpc.GoCryptoTrader.GetDataHistoryJobSummary:output_type -> gctrpc.DataHistoryJob + 127, // 264: gctrpc.GoCryptoTrader.SetDataHistoryJobStatus:output_type -> gctrpc.GenericResponse + 127, // 265: gctrpc.GoCryptoTrader.UpdateDataHistoryJobPrerequisite:output_type -> gctrpc.GenericResponse + 59, // 266: gctrpc.GoCryptoTrader.GetManagedOrders:output_type -> gctrpc.GetOrdersResponse + 180, // [180:267] is the sub-list for method output_type + 93, // [93:180] is the sub-list for method input_type + 93, // [93:93] is the sub-list for extension type_name + 93, // [93:93] is the sub-list for extension extendee + 0, // [0:93] is the sub-list for field type_name } func init() { file_rpc_proto_init() } @@ -13867,7 +14283,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[146].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpsertDataHistoryJobResponse); i { + switch v := v.(*InsertSequentialJobsRequest); i { case 0: return &v.state case 1: @@ -13879,7 +14295,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[147].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetDataHistoryJobDetailsRequest); i { + switch v := v.(*InsertSequentialJobsResponse); i { case 0: return &v.state case 1: @@ -13891,7 +14307,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[148].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DataHistoryJob); i { + switch v := v.(*UpsertDataHistoryJobResponse); i { case 0: return &v.state case 1: @@ -13903,7 +14319,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[149].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DataHistoryJobResult); i { + switch v := v.(*GetDataHistoryJobDetailsRequest); i { case 0: return &v.state case 1: @@ -13915,7 +14331,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[150].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DataHistoryJobs); i { + switch v := v.(*DataHistoryJob); i { case 0: return &v.state case 1: @@ -13927,6 +14343,30 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[151].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DataHistoryJobResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[152].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DataHistoryJobs); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[153].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDataHistoryJobsBetweenRequest); i { case 0: return &v.state @@ -13938,7 +14378,31 @@ func file_rpc_proto_init() { return nil } } - file_rpc_proto_msgTypes[162].Exporter = func(v interface{}, i int) interface{} { + file_rpc_proto_msgTypes[154].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetDataHistoryJobStatusRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[155].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateDataHistoryJobPrerequisiteRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[166].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CancelBatchOrdersResponse_Orders); i { case 0: return &v.state @@ -13950,7 +14414,7 @@ func file_rpc_proto_init() { return nil } } - file_rpc_proto_msgTypes[164].Exporter = func(v interface{}, i int) interface{} { + file_rpc_proto_msgTypes[168].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CancelAllOrdersResponse_Orders); i { case 0: return &v.state @@ -13969,7 +14433,7 @@ func file_rpc_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rpc_proto_rawDesc, NumEnums: 0, - NumMessages: 168, + NumMessages: 172, NumExtensions: 0, NumServices: 1, }, diff --git a/gctrpc/rpc.pb.gw.go b/gctrpc/rpc.pb.gw.go index 51691efbe14..23fa13acf7f 100644 --- a/gctrpc/rpc.pb.gw.go +++ b/gctrpc/rpc.pb.gw.go @@ -2600,109 +2600,141 @@ func local_request_GoCryptoTrader_GetActiveDataHistoryJobs_0(ctx context.Context } var ( - filter_GoCryptoTrader_DeleteDataHistoryJob_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + filter_GoCryptoTrader_GetDataHistoryJobsBetween_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) -func request_GoCryptoTrader_DeleteDataHistoryJob_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetDataHistoryJobDetailsRequest +func request_GoCryptoTrader_GetDataHistoryJobsBetween_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetDataHistoryJobsBetweenRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_DeleteDataHistoryJob_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetDataHistoryJobsBetween_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.DeleteDataHistoryJob(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetDataHistoryJobsBetween(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_GoCryptoTrader_DeleteDataHistoryJob_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetDataHistoryJobDetailsRequest +func local_request_GoCryptoTrader_GetDataHistoryJobsBetween_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetDataHistoryJobsBetweenRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_DeleteDataHistoryJob_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetDataHistoryJobsBetween_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.DeleteDataHistoryJob(ctx, &protoReq) + msg, err := server.GetDataHistoryJobsBetween(ctx, &protoReq) return msg, metadata, err } var ( - filter_GoCryptoTrader_GetDataHistoryJobsBetween_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + filter_GoCryptoTrader_GetDataHistoryJobSummary_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) -func request_GoCryptoTrader_GetDataHistoryJobsBetween_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetDataHistoryJobsBetweenRequest +func request_GoCryptoTrader_GetDataHistoryJobSummary_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetDataHistoryJobDetailsRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetDataHistoryJobsBetween_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetDataHistoryJobSummary_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.GetDataHistoryJobsBetween(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetDataHistoryJobSummary(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_GoCryptoTrader_GetDataHistoryJobsBetween_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetDataHistoryJobsBetweenRequest +func local_request_GoCryptoTrader_GetDataHistoryJobSummary_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetDataHistoryJobDetailsRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetDataHistoryJobsBetween_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetDataHistoryJobSummary_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.GetDataHistoryJobsBetween(ctx, &protoReq) + msg, err := server.GetDataHistoryJobSummary(ctx, &protoReq) return msg, metadata, err } -var ( - filter_GoCryptoTrader_GetDataHistoryJobSummary_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_GoCryptoTrader_GetDataHistoryJobSummary_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetDataHistoryJobDetailsRequest +func request_GoCryptoTrader_SetDataHistoryJobStatus_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SetDataHistoryJobStatusRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetDataHistoryJobSummary_0); err != nil { + + msg, err := client.SetDataHistoryJobStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_GoCryptoTrader_SetDataHistoryJobStatus_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SetDataHistoryJobStatusRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.GetDataHistoryJobSummary(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := server.SetDataHistoryJobStatus(ctx, &protoReq) return msg, metadata, err } -func local_request_GoCryptoTrader_GetDataHistoryJobSummary_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetDataHistoryJobDetailsRequest +func request_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateDataHistoryJobPrerequisiteRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetDataHistoryJobSummary_0); err != nil { + + msg, err := client.UpdateDataHistoryJobPrerequisite(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0(ctx context.Context, marshaler runtime.Marshaler, server GoCryptoTraderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateDataHistoryJobPrerequisiteRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.GetDataHistoryJobSummary(ctx, &protoReq) + msg, err := server.UpdateDataHistoryJobPrerequisite(ctx, &protoReq) return msg, metadata, err } @@ -4537,18 +4569,18 @@ func RegisterGoCryptoTraderHandlerServer(ctx context.Context, mux *runtime.Serve }) - mux.Handle("DELETE", pattern_GoCryptoTrader_DeleteDataHistoryJob_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_GoCryptoTrader_GetDataHistoryJobsBetween_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/DeleteDataHistoryJob", runtime.WithHTTPPathPattern("/v1/deletedatahistoryjob")) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/GetDataHistoryJobsBetween", runtime.WithHTTPPathPattern("/v1/getdatahistoryjobsbetween")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_GoCryptoTrader_DeleteDataHistoryJob_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_GoCryptoTrader_GetDataHistoryJobsBetween_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -4556,22 +4588,22 @@ func RegisterGoCryptoTraderHandlerServer(ctx context.Context, mux *runtime.Serve return } - forward_GoCryptoTrader_DeleteDataHistoryJob_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_GoCryptoTrader_GetDataHistoryJobsBetween_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_GoCryptoTrader_GetDataHistoryJobsBetween_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_GoCryptoTrader_GetDataHistoryJobSummary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/GetDataHistoryJobsBetween", runtime.WithHTTPPathPattern("/v1/getdatahistoryjobsbetween")) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/GetDataHistoryJobSummary", runtime.WithHTTPPathPattern("/v1/getdatahistoryjobsummary")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_GoCryptoTrader_GetDataHistoryJobsBetween_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_GoCryptoTrader_GetDataHistoryJobSummary_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -4579,22 +4611,22 @@ func RegisterGoCryptoTraderHandlerServer(ctx context.Context, mux *runtime.Serve return } - forward_GoCryptoTrader_GetDataHistoryJobsBetween_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_GoCryptoTrader_GetDataHistoryJobSummary_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_GoCryptoTrader_GetDataHistoryJobSummary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_GoCryptoTrader_SetDataHistoryJobStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/GetDataHistoryJobSummary", runtime.WithHTTPPathPattern("/v1/getdatahistoryjobsummary")) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/SetDataHistoryJobStatus", runtime.WithHTTPPathPattern("/v1/setdatahistoryjobstatus")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_GoCryptoTrader_GetDataHistoryJobSummary_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_GoCryptoTrader_SetDataHistoryJobStatus_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -4602,7 +4634,30 @@ func RegisterGoCryptoTraderHandlerServer(ctx context.Context, mux *runtime.Serve return } - forward_GoCryptoTrader_GetDataHistoryJobSummary_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_GoCryptoTrader_SetDataHistoryJobStatus_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/UpdateDataHistoryJobPrerequisite", runtime.WithHTTPPathPattern("/v1/updatedatahistoryjobprerequisite")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -6310,63 +6365,83 @@ func RegisterGoCryptoTraderHandlerClient(ctx context.Context, mux *runtime.Serve }) - mux.Handle("DELETE", pattern_GoCryptoTrader_DeleteDataHistoryJob_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_GoCryptoTrader_GetDataHistoryJobsBetween_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/DeleteDataHistoryJob", runtime.WithHTTPPathPattern("/v1/deletedatahistoryjob")) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/GetDataHistoryJobsBetween", runtime.WithHTTPPathPattern("/v1/getdatahistoryjobsbetween")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_GoCryptoTrader_DeleteDataHistoryJob_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_GoCryptoTrader_GetDataHistoryJobsBetween_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_GoCryptoTrader_DeleteDataHistoryJob_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_GoCryptoTrader_GetDataHistoryJobsBetween_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_GoCryptoTrader_GetDataHistoryJobsBetween_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_GoCryptoTrader_GetDataHistoryJobSummary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/GetDataHistoryJobsBetween", runtime.WithHTTPPathPattern("/v1/getdatahistoryjobsbetween")) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/GetDataHistoryJobSummary", runtime.WithHTTPPathPattern("/v1/getdatahistoryjobsummary")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_GoCryptoTrader_GetDataHistoryJobsBetween_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_GoCryptoTrader_GetDataHistoryJobSummary_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_GoCryptoTrader_GetDataHistoryJobsBetween_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_GoCryptoTrader_GetDataHistoryJobSummary_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_GoCryptoTrader_GetDataHistoryJobSummary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_GoCryptoTrader_SetDataHistoryJobStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/GetDataHistoryJobSummary", runtime.WithHTTPPathPattern("/v1/getdatahistoryjobsummary")) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/SetDataHistoryJobStatus", runtime.WithHTTPPathPattern("/v1/setdatahistoryjobstatus")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_GoCryptoTrader_GetDataHistoryJobSummary_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_GoCryptoTrader_SetDataHistoryJobStatus_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_GoCryptoTrader_GetDataHistoryJobSummary_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_GoCryptoTrader_SetDataHistoryJobStatus_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gctrpc.GoCryptoTrader/UpdateDataHistoryJobPrerequisite", runtime.WithHTTPPathPattern("/v1/updatedatahistoryjobprerequisite")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -6558,12 +6633,14 @@ var ( pattern_GoCryptoTrader_GetActiveDataHistoryJobs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getactivedatahistoryjobs"}, "")) - pattern_GoCryptoTrader_DeleteDataHistoryJob_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "deletedatahistoryjob"}, "")) - pattern_GoCryptoTrader_GetDataHistoryJobsBetween_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getdatahistoryjobsbetween"}, "")) pattern_GoCryptoTrader_GetDataHistoryJobSummary_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getdatahistoryjobsummary"}, "")) + pattern_GoCryptoTrader_SetDataHistoryJobStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "setdatahistoryjobstatus"}, "")) + + pattern_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "updatedatahistoryjobprerequisite"}, "")) + pattern_GoCryptoTrader_GetManagedOrders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getmanagedorders"}, "")) ) @@ -6732,11 +6809,13 @@ var ( forward_GoCryptoTrader_GetActiveDataHistoryJobs_0 = runtime.ForwardResponseMessage - forward_GoCryptoTrader_DeleteDataHistoryJob_0 = runtime.ForwardResponseMessage - forward_GoCryptoTrader_GetDataHistoryJobsBetween_0 = runtime.ForwardResponseMessage forward_GoCryptoTrader_GetDataHistoryJobSummary_0 = runtime.ForwardResponseMessage + forward_GoCryptoTrader_SetDataHistoryJobStatus_0 = runtime.ForwardResponseMessage + + forward_GoCryptoTrader_UpdateDataHistoryJobPrerequisite_0 = runtime.ForwardResponseMessage + forward_GoCryptoTrader_GetManagedOrders_0 = runtime.ForwardResponseMessage ) diff --git a/gctrpc/rpc.proto b/gctrpc/rpc.proto index ab288198e33..bd28dec13bd 100644 --- a/gctrpc/rpc.proto +++ b/gctrpc/rpc.proto @@ -866,11 +866,26 @@ message UpsertDataHistoryJobRequest { int64 max_retry_attempts = 10; int64 batch_size = 11; bool insert_only = 12; + int64 conversion_interval = 13; + bool overwrite_existing_data = 14; + string prerequisite_job_nickname = 15; + int64 decimal_place_comparison = 16; + string secondary_exchange_name = 17; + double issue_tolerance_percentage = 18; + bool replace_on_issue = 19; +} + +message InsertSequentialJobsRequest { + repeated UpsertDataHistoryJobRequest jobs = 1; +} + +message InsertSequentialJobsResponse { + repeated UpsertDataHistoryJobResponse jobs = 1; } message UpsertDataHistoryJobResponse { - string message = 1; - string job_id = 2; + string message = 1; + string job_id = 2; } message GetDataHistoryJobDetailsRequest { @@ -893,11 +908,17 @@ message DataHistoryJob { int64 batch_size = 11; string status = 12; string data_type = 13; - repeated DataHistoryJobResult job_results = 14; - repeated string result_summaries = 15; + int64 conversion_interval = 14; + bool overwrite_existing_data = 15; + string prerequisite_job_nickname = 16; + int64 decimal_place_comparison = 17; + string secondary_exchange_name = 18; + double issue_tolerance_percentage = 19; + bool replace_on_issue = 20; + repeated DataHistoryJobResult job_results = 21; + repeated string result_summaries = 22; } - message DataHistoryJobResult { string start_date = 1; string end_date = 2; @@ -915,6 +936,18 @@ message GetDataHistoryJobsBetweenRequest { string end_date = 2; } +message SetDataHistoryJobStatusRequest { + string id = 1; + string nickname = 2; + int64 status = 3; +} + +message UpdateDataHistoryJobPrerequisiteRequest { + string nickname = 1; + string prerequisite_job_nickname = 2; +} + + service GoCryptoTrader { rpc GetInfo (GetInfoRequest) returns (GetInfoResponse) { option (google.api.http) = { @@ -1424,8 +1457,8 @@ service GoCryptoTrader { rpc UpsertDataHistoryJob (UpsertDataHistoryJobRequest) returns (UpsertDataHistoryJobResponse) { option (google.api.http) = { - post: "/v1/upsertdatahistoryjob" - body: "*" + post: "/v1/upsertdatahistoryjob", + body: "*" }; } @@ -1439,11 +1472,6 @@ service GoCryptoTrader { get: "/v1/getactivedatahistoryjobs" }; } - rpc DeleteDataHistoryJob (GetDataHistoryJobDetailsRequest) returns (GenericResponse) { - option (google.api.http) = { - delete: "/v1/deletedatahistoryjob" - }; - } rpc GetDataHistoryJobsBetween (GetDataHistoryJobsBetweenRequest) returns (DataHistoryJobs) { option (google.api.http) = { get: "/v1/getdatahistoryjobsbetween" @@ -1454,6 +1482,18 @@ service GoCryptoTrader { get: "/v1/getdatahistoryjobsummary" }; } + rpc SetDataHistoryJobStatus (SetDataHistoryJobStatusRequest) returns (GenericResponse) { + option (google.api.http) = { + post: "/v1/setdatahistoryjobstatus", + body: "*" + }; + } + rpc UpdateDataHistoryJobPrerequisite (UpdateDataHistoryJobPrerequisiteRequest) returns (GenericResponse) { + option (google.api.http) = { + post: "/v1/updatedatahistoryjobprerequisite", + body: "*" + }; + } rpc GetManagedOrders (GetOrdersRequest) returns (GetOrdersResponse) { option (google.api.http) = { post: "/v1/getmanagedorders" diff --git a/gctrpc/rpc.swagger.json b/gctrpc/rpc.swagger.json index d07451dc211..5f4cc5fcc2f 100644 --- a/gctrpc/rpc.swagger.json +++ b/gctrpc/rpc.swagger.json @@ -261,48 +261,6 @@ ] } }, - "/v1/deletedatahistoryjob": { - "delete": { - "operationId": "GoCryptoTrader_DeleteDataHistoryJob", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/gctrpcGenericResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "id", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "nickname", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "fullDetails", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "GoCryptoTrader" - ] - } - }, "/v1/disableexchange": { "post": { "operationId": "GoCryptoTrader_DisableExchange", @@ -2256,6 +2214,38 @@ ] } }, + "/v1/setdatahistoryjobstatus": { + "post": { + "operationId": "GoCryptoTrader_SetDataHistoryJobStatus", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/gctrpcGenericResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/gctrpcSetDataHistoryJobStatusRequest" + } + } + ], + "tags": [ + "GoCryptoTrader" + ] + } + }, "/v1/setexchangeasset": { "get": { "operationId": "GoCryptoTrader_SetExchangeAsset", @@ -2498,6 +2488,38 @@ ] } }, + "/v1/updatedatahistoryjobprerequisite": { + "post": { + "operationId": "GoCryptoTrader_UpdateDataHistoryJobPrerequisite", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/gctrpcGenericResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/gctrpcUpdateDataHistoryJobPrerequisiteRequest" + } + } + ], + "tags": [ + "GoCryptoTrader" + ] + } + }, "/v1/updateexchangesupportedpairs": { "get": { "operationId": "GoCryptoTrader_UpdateExchangeSupportedPairs", @@ -3262,6 +3284,30 @@ "dataType": { "type": "string" }, + "conversionInterval": { + "type": "string", + "format": "int64" + }, + "overwriteExistingData": { + "type": "boolean" + }, + "prerequisiteJobNickname": { + "type": "string" + }, + "decimalPlaceComparison": { + "type": "string", + "format": "int64" + }, + "secondaryExchangeName": { + "type": "string" + }, + "issueTolerancePercentage": { + "type": "number", + "format": "double" + }, + "replaceOnIssue": { + "type": "boolean" + }, "jobResults": { "type": "array", "items": { @@ -4270,6 +4316,21 @@ } } }, + "gctrpcSetDataHistoryJobStatusRequest": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "nickname": { + "type": "string" + }, + "status": { + "type": "string", + "format": "int64" + } + } + }, "gctrpcSetExchangePairRequest": { "type": "object", "properties": { @@ -4511,6 +4572,17 @@ } } }, + "gctrpcUpdateDataHistoryJobPrerequisiteRequest": { + "type": "object", + "properties": { + "nickname": { + "type": "string" + }, + "prerequisiteJobNickname": { + "type": "string" + } + } + }, "gctrpcUpsertDataHistoryJobRequest": { "type": "object", "properties": { @@ -4554,6 +4626,30 @@ }, "insertOnly": { "type": "boolean" + }, + "conversionInterval": { + "type": "string", + "format": "int64" + }, + "overwriteExistingData": { + "type": "boolean" + }, + "prerequisiteJobNickname": { + "type": "string" + }, + "decimalPlaceComparison": { + "type": "string", + "format": "int64" + }, + "secondaryExchangeName": { + "type": "string" + }, + "issueTolerancePercentage": { + "type": "number", + "format": "double" + }, + "replaceOnIssue": { + "type": "boolean" } } }, diff --git a/gctrpc/rpc_grpc.pb.go b/gctrpc/rpc_grpc.pb.go index e6b4fc9b40d..3d58947d437 100644 --- a/gctrpc/rpc_grpc.pb.go +++ b/gctrpc/rpc_grpc.pb.go @@ -100,9 +100,10 @@ type GoCryptoTraderClient interface { UpsertDataHistoryJob(ctx context.Context, in *UpsertDataHistoryJobRequest, opts ...grpc.CallOption) (*UpsertDataHistoryJobResponse, error) GetDataHistoryJobDetails(ctx context.Context, in *GetDataHistoryJobDetailsRequest, opts ...grpc.CallOption) (*DataHistoryJob, error) GetActiveDataHistoryJobs(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*DataHistoryJobs, error) - DeleteDataHistoryJob(ctx context.Context, in *GetDataHistoryJobDetailsRequest, opts ...grpc.CallOption) (*GenericResponse, error) GetDataHistoryJobsBetween(ctx context.Context, in *GetDataHistoryJobsBetweenRequest, opts ...grpc.CallOption) (*DataHistoryJobs, error) GetDataHistoryJobSummary(ctx context.Context, in *GetDataHistoryJobDetailsRequest, opts ...grpc.CallOption) (*DataHistoryJob, error) + SetDataHistoryJobStatus(ctx context.Context, in *SetDataHistoryJobStatusRequest, opts ...grpc.CallOption) (*GenericResponse, error) + UpdateDataHistoryJobPrerequisite(ctx context.Context, in *UpdateDataHistoryJobPrerequisiteRequest, opts ...grpc.CallOption) (*GenericResponse, error) GetManagedOrders(ctx context.Context, in *GetOrdersRequest, opts ...grpc.CallOption) (*GetOrdersResponse, error) } @@ -990,15 +991,6 @@ func (c *goCryptoTraderClient) GetActiveDataHistoryJobs(ctx context.Context, in return out, nil } -func (c *goCryptoTraderClient) DeleteDataHistoryJob(ctx context.Context, in *GetDataHistoryJobDetailsRequest, opts ...grpc.CallOption) (*GenericResponse, error) { - out := new(GenericResponse) - err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/DeleteDataHistoryJob", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *goCryptoTraderClient) GetDataHistoryJobsBetween(ctx context.Context, in *GetDataHistoryJobsBetweenRequest, opts ...grpc.CallOption) (*DataHistoryJobs, error) { out := new(DataHistoryJobs) err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/GetDataHistoryJobsBetween", in, out, opts...) @@ -1017,6 +1009,24 @@ func (c *goCryptoTraderClient) GetDataHistoryJobSummary(ctx context.Context, in return out, nil } +func (c *goCryptoTraderClient) SetDataHistoryJobStatus(ctx context.Context, in *SetDataHistoryJobStatusRequest, opts ...grpc.CallOption) (*GenericResponse, error) { + out := new(GenericResponse) + err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/SetDataHistoryJobStatus", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *goCryptoTraderClient) UpdateDataHistoryJobPrerequisite(ctx context.Context, in *UpdateDataHistoryJobPrerequisiteRequest, opts ...grpc.CallOption) (*GenericResponse, error) { + out := new(GenericResponse) + err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/UpdateDataHistoryJobPrerequisite", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *goCryptoTraderClient) GetManagedOrders(ctx context.Context, in *GetOrdersRequest, opts ...grpc.CallOption) (*GetOrdersResponse, error) { out := new(GetOrdersResponse) err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/GetManagedOrders", in, out, opts...) @@ -1112,9 +1122,10 @@ type GoCryptoTraderServer interface { UpsertDataHistoryJob(context.Context, *UpsertDataHistoryJobRequest) (*UpsertDataHistoryJobResponse, error) GetDataHistoryJobDetails(context.Context, *GetDataHistoryJobDetailsRequest) (*DataHistoryJob, error) GetActiveDataHistoryJobs(context.Context, *GetInfoRequest) (*DataHistoryJobs, error) - DeleteDataHistoryJob(context.Context, *GetDataHistoryJobDetailsRequest) (*GenericResponse, error) GetDataHistoryJobsBetween(context.Context, *GetDataHistoryJobsBetweenRequest) (*DataHistoryJobs, error) GetDataHistoryJobSummary(context.Context, *GetDataHistoryJobDetailsRequest) (*DataHistoryJob, error) + SetDataHistoryJobStatus(context.Context, *SetDataHistoryJobStatusRequest) (*GenericResponse, error) + UpdateDataHistoryJobPrerequisite(context.Context, *UpdateDataHistoryJobPrerequisiteRequest) (*GenericResponse, error) GetManagedOrders(context.Context, *GetOrdersRequest) (*GetOrdersResponse, error) mustEmbedUnimplementedGoCryptoTraderServer() } @@ -1369,15 +1380,18 @@ func (UnimplementedGoCryptoTraderServer) GetDataHistoryJobDetails(context.Contex func (UnimplementedGoCryptoTraderServer) GetActiveDataHistoryJobs(context.Context, *GetInfoRequest) (*DataHistoryJobs, error) { return nil, status.Errorf(codes.Unimplemented, "method GetActiveDataHistoryJobs not implemented") } -func (UnimplementedGoCryptoTraderServer) DeleteDataHistoryJob(context.Context, *GetDataHistoryJobDetailsRequest) (*GenericResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method DeleteDataHistoryJob not implemented") -} func (UnimplementedGoCryptoTraderServer) GetDataHistoryJobsBetween(context.Context, *GetDataHistoryJobsBetweenRequest) (*DataHistoryJobs, error) { return nil, status.Errorf(codes.Unimplemented, "method GetDataHistoryJobsBetween not implemented") } func (UnimplementedGoCryptoTraderServer) GetDataHistoryJobSummary(context.Context, *GetDataHistoryJobDetailsRequest) (*DataHistoryJob, error) { return nil, status.Errorf(codes.Unimplemented, "method GetDataHistoryJobSummary not implemented") } +func (UnimplementedGoCryptoTraderServer) SetDataHistoryJobStatus(context.Context, *SetDataHistoryJobStatusRequest) (*GenericResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetDataHistoryJobStatus not implemented") +} +func (UnimplementedGoCryptoTraderServer) UpdateDataHistoryJobPrerequisite(context.Context, *UpdateDataHistoryJobPrerequisiteRequest) (*GenericResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateDataHistoryJobPrerequisite not implemented") +} func (UnimplementedGoCryptoTraderServer) GetManagedOrders(context.Context, *GetOrdersRequest) (*GetOrdersResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetManagedOrders not implemented") } @@ -2888,56 +2902,74 @@ func _GoCryptoTrader_GetActiveDataHistoryJobs_Handler(srv interface{}, ctx conte return interceptor(ctx, in, info, handler) } -func _GoCryptoTrader_DeleteDataHistoryJob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _GoCryptoTrader_GetDataHistoryJobsBetween_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetDataHistoryJobsBetweenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GoCryptoTraderServer).GetDataHistoryJobsBetween(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gctrpc.GoCryptoTrader/GetDataHistoryJobsBetween", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GoCryptoTraderServer).GetDataHistoryJobsBetween(ctx, req.(*GetDataHistoryJobsBetweenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _GoCryptoTrader_GetDataHistoryJobSummary_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetDataHistoryJobDetailsRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(GoCryptoTraderServer).DeleteDataHistoryJob(ctx, in) + return srv.(GoCryptoTraderServer).GetDataHistoryJobSummary(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/gctrpc.GoCryptoTrader/DeleteDataHistoryJob", + FullMethod: "/gctrpc.GoCryptoTrader/GetDataHistoryJobSummary", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(GoCryptoTraderServer).DeleteDataHistoryJob(ctx, req.(*GetDataHistoryJobDetailsRequest)) + return srv.(GoCryptoTraderServer).GetDataHistoryJobSummary(ctx, req.(*GetDataHistoryJobDetailsRequest)) } return interceptor(ctx, in, info, handler) } -func _GoCryptoTrader_GetDataHistoryJobsBetween_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetDataHistoryJobsBetweenRequest) +func _GoCryptoTrader_SetDataHistoryJobStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetDataHistoryJobStatusRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(GoCryptoTraderServer).GetDataHistoryJobsBetween(ctx, in) + return srv.(GoCryptoTraderServer).SetDataHistoryJobStatus(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/gctrpc.GoCryptoTrader/GetDataHistoryJobsBetween", + FullMethod: "/gctrpc.GoCryptoTrader/SetDataHistoryJobStatus", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(GoCryptoTraderServer).GetDataHistoryJobsBetween(ctx, req.(*GetDataHistoryJobsBetweenRequest)) + return srv.(GoCryptoTraderServer).SetDataHistoryJobStatus(ctx, req.(*SetDataHistoryJobStatusRequest)) } return interceptor(ctx, in, info, handler) } -func _GoCryptoTrader_GetDataHistoryJobSummary_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetDataHistoryJobDetailsRequest) +func _GoCryptoTrader_UpdateDataHistoryJobPrerequisite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateDataHistoryJobPrerequisiteRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(GoCryptoTraderServer).GetDataHistoryJobSummary(ctx, in) + return srv.(GoCryptoTraderServer).UpdateDataHistoryJobPrerequisite(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/gctrpc.GoCryptoTrader/GetDataHistoryJobSummary", + FullMethod: "/gctrpc.GoCryptoTrader/UpdateDataHistoryJobPrerequisite", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(GoCryptoTraderServer).GetDataHistoryJobSummary(ctx, req.(*GetDataHistoryJobDetailsRequest)) + return srv.(GoCryptoTraderServer).UpdateDataHistoryJobPrerequisite(ctx, req.(*UpdateDataHistoryJobPrerequisiteRequest)) } return interceptor(ctx, in, info, handler) } @@ -3271,10 +3303,6 @@ var GoCryptoTrader_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetActiveDataHistoryJobs", Handler: _GoCryptoTrader_GetActiveDataHistoryJobs_Handler, }, - { - MethodName: "DeleteDataHistoryJob", - Handler: _GoCryptoTrader_DeleteDataHistoryJob_Handler, - }, { MethodName: "GetDataHistoryJobsBetween", Handler: _GoCryptoTrader_GetDataHistoryJobsBetween_Handler, @@ -3283,6 +3311,14 @@ var GoCryptoTrader_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetDataHistoryJobSummary", Handler: _GoCryptoTrader_GetDataHistoryJobSummary_Handler, }, + { + MethodName: "SetDataHistoryJobStatus", + Handler: _GoCryptoTrader_SetDataHistoryJobStatus_Handler, + }, + { + MethodName: "UpdateDataHistoryJobPrerequisite", + Handler: _GoCryptoTrader_UpdateDataHistoryJobPrerequisite_Handler, + }, { MethodName: "GetManagedOrders", Handler: _GoCryptoTrader_GetManagedOrders_Handler, diff --git a/testdata/http_mock/binance/binance.json b/testdata/http_mock/binance/binance.json index c6ae7e48ab6..19780d69669 100644 --- a/testdata/http_mock/binance/binance.json +++ b/testdata/http_mock/binance/binance.json @@ -892,9996 +892,10417 @@ }, { "M": true, - "T": 1588749117459, - "a": 284861206, - "f": 310207485, - "l": 310207485, + "T": 1588749263231, + "a": 284862204, + "f": 310208534, + "l": 310208534, + "m": false, + "p": "9034.00000000", + "q": "0.06546300" + } + ], + "queryString": "limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1590640145871, + "a": 303004096, + "f": 329755557, + "l": 329755557, + "m": false, + "p": "9195.09000000", + "q": "0.10000000" + }, + { + "M": true, + "T": 1590640145901, + "a": 303004097, + "f": 329755558, + "l": 329755558, + "m": true, + "p": "9194.99000000", + "q": "0.00000700" + }, + { + "M": true, + "T": 1590640145901, + "a": 303004098, + "f": 329755559, + "l": 329755559, "m": true, - "p": "9039.71000000", - "q": "2.34574600" + "p": "9194.98000000", + "q": "0.01963500" }, { "M": true, - "T": 1588749117474, - "a": 284861207, - "f": 310207486, - "l": 310207486, + "T": 1590640145980, + "a": 303004099, + "f": 329755560, + "l": 329755560, "m": false, - "p": "9039.96000000", - "q": "0.17681100" + "p": "9194.99000000", + "q": "0.00490700" }, { "M": true, - "T": 1588749117474, - "a": 284861208, - "f": 310207487, - "l": 310207487, + "T": 1590640146110, + "a": 303004100, + "f": 329755561, + "l": 329755561, "m": false, - "p": "9040.00000000", - "q": "0.02318900" + "p": "9194.99000000", + "q": "0.09509300" + } + ], + "queryString": "limit=5\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1590640145871, + "a": 303004096, + "f": 329755557, + "l": 329755557, + "m": false, + "p": "9195.09000000", + "q": "0.10000000" }, { "M": true, - "T": 1588749117507, - "a": 284861209, - "f": 310207488, - "l": 310207488, + "T": 1590640145901, + "a": 303004097, + "f": 329755558, + "l": 329755558, "m": true, - "p": "9039.78000000", - "q": "0.06639000" + "p": "9194.99000000", + "q": "0.00000700" }, { "M": true, - "T": 1588749117507, - "a": 284861210, - "f": 310207489, - "l": 310207489, + "T": 1590640145901, + "a": 303004098, + "f": 329755559, + "l": 329755559, "m": true, - "p": "9039.70000000", - "q": "0.00221100" + "p": "9194.98000000", + "q": "0.01963500" }, { "M": true, - "T": 1588749117507, - "a": 284861211, - "f": 310207490, - "l": 310207490, - "m": true, - "p": "9039.20000000", - "q": "0.11318000" + "T": 1590640145980, + "a": 303004099, + "f": 329755560, + "l": 329755560, + "m": false, + "p": "9194.99000000", + "q": "0.00490700" }, { "M": true, - "T": 1588749117568, - "a": 284861212, - "f": 310207491, - "l": 310207491, + "T": 1590640146110, + "a": 303004100, + "f": 329755561, + "l": 329755561, "m": false, - "p": "9039.23000000", - "q": "0.00307900" + "p": "9194.99000000", + "q": "0.09509300" + } + ], + "queryString": "endTime=1577978345000\u0026startTime=1577977445000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1577977445200, + "a": 303004095, + "f": 329755557, + "l": 329755557, + "": false, + "p": "9195.09000000", + "q": "0.10000000" }, { "M": true, - "T": 1588749117615, - "a": 284861213, - "f": 310207492, - "l": 310207492, - "m": true, - "p": "9039.22000000", - "q": "0.17682400" + "T": 1577977445500, + "a": 303004096, + "f": 329755557, + "l": 329755557, + "": false, + "p": "9195.09000000", + "q": "0.10000000" + } + ], + "queryString": "endTime=1577981045000\u0026limit=1000\u0026startTime=1577977445000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1577977445500, + "a": 303004096, + "f": 329755557, + "l": 329755557, + "": false, + "p": "9195.09000000", + "q": "0.10000000" }, { "M": true, - "T": 1588749117615, - "a": 284861214, - "f": 310207493, - "l": 310207493, - "m": true, - "p": "9038.87000000", - "q": "0.09340000" + "T": 1577981944800, + "a": 303004097, + "f": 329755557, + "l": 329755557, + "": false, + "p": "9195.09000000", + "q": "0.10000000" }, { "M": true, - "T": 1588749117615, - "a": 284861215, - "f": 310207494, - "l": 310207494, - "m": true, - "p": "9038.84000000", - "q": "0.00300000" + "T": 1577981945200, + "a": 303004098, + "f": 329755557, + "l": 329755557, + "": false, + "p": "9195.09000000", + "q": "0.10000000" + } + ], + "queryString": "fromId=303004096\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1577977445500, + "a": 303004096, + "f": 329755557, + "l": 329755557, + "": false, + "p": "9195.09000000", + "q": "0.10000000" }, { "M": true, - "T": 1588749117615, - "a": 284861216, - "f": 310207495, - "l": 310207495, - "m": true, - "p": "9038.78000000", - "q": "0.09037600" + "T": 1577981944800, + "a": 303004097, + "f": 329755557, + "l": 329755557, + "": false, + "p": "9195.09000000", + "q": "0.10000000" + }, + { + "M": true, + "T": 1577981945200, + "a": 303004098, + "f": 329755557, + "l": 329755557, + "": false, + "p": "9195.09000000", + "q": "0.10000000" + } + ], + "queryString": "limit=3\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1577981945200, + "a": 303004098, + "f": 329755557, + "l": 329755557, + "": false, + "p": "9195.09000000", + "q": "0.10000000" + } + ], + "queryString": "fromId=303004098\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1577977446915, + "a": 202789181, + "f": 222824260, + "l": 222824260, + "m": false, + "p": "7143.44000000", + "q": "0.00167500" }, { "M": true, - "T": 1588749117615, - "a": 284861217, - "f": 310207496, - "l": 310207496, + "T": 1577977453080, + "a": 202789191, + "f": 222824270, + "l": 222824270, + "m": true, + "p": "7142.80000000", + "q": "0.05935700" + } + ], + "queryString": "endTime=1577977455000\u0026limit=1000\u0026startTime=1577977445000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1577977453080, + "a": 202789191, + "f": 222824270, + "l": 222824270, "m": true, - "p": "9038.76000000", - "q": "0.09317400" + "p": "7142.80000000", + "q": "0.05935700" }, { "M": true, - "T": 1588749117685, - "a": 284861218, - "f": 310207497, - "l": 310207497, + "T": 1577977823305, + "a": 202790190, + "f": 222825297, + "l": 222825297, "m": false, - "p": "9038.91000000", - "q": "0.05962000" + "p": "7139.89000000", + "q": "0.06702300" + } + ], + "queryString": "fromId=202789191\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1577977823305, + "a": 202790190, + "f": 222825297, + "l": 222825297, + "m": false, + "p": "7139.89000000", + "q": "0.06702300" }, { "M": true, - "T": 1588749117691, - "a": 284861219, - "f": 310207498, - "l": 310207498, - "m": true, - "p": "9038.77000000", - "q": "0.06019900" + "T": 1577977824874, + "a": 202790191, + "f": 222825298, + "l": 222825298, + "m": false, + "p": "7139.97000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749117731, - "a": 284861220, - "f": 310207499, - "l": 310207499, + "T": 1577977824990, + "a": 202790192, + "f": 222825299, + "l": 222825299, "m": true, - "p": "9038.76000000", - "q": "0.06000000" + "p": "7139.93000000", + "q": "0.01437800" }, { "M": true, - "T": 1588749117786, - "a": 284861221, - "f": 310207500, - "l": 310207500, + "T": 1577977825043, + "a": 202790193, + "f": 222825300, + "l": 222825300, "m": false, - "p": "9038.77000000", - "q": "0.00307900" + "p": "7139.97000000", + "q": "0.04121700" }, { "M": true, - "T": 1588749117821, - "a": 284861222, - "f": 310207501, - "l": 310207501, - "m": true, - "p": "9038.76000000", - "q": "0.02000000" + "T": 1577977825043, + "a": 202790194, + "f": 222825301, + "l": 222825301, + "m": false, + "p": "7140.00000000", + "q": "0.02097000" }, { "M": true, - "T": 1588749117928, - "a": 284861223, - "f": 310207502, - "l": 310207502, + "T": 1577977825043, + "a": 202790195, + "f": 222825302, + "l": 222825302, "m": false, - "p": "9038.77000000", - "q": "0.02139400" + "p": "7140.96000000", + "q": "0.08572400" }, { "M": true, - "T": 1588749118015, - "a": 284861224, - "f": 310207503, - "l": 310207503, + "T": 1577977825353, + "a": 202790196, + "f": 222825303, + "l": 222825303, "m": true, - "p": "9038.80000000", - "q": "0.06019700" + "p": "7139.92000000", + "q": "0.00184000" }, { "M": true, - "T": 1588749118019, - "a": 284861225, - "f": 310207504, - "l": 310207504, + "T": 1577977827688, + "a": 202790197, + "f": 222825304, + "l": 222825304, "m": false, - "p": "9039.20000000", - "q": "0.00319200" + "p": "7139.99000000", + "q": "0.00150000" }, { "M": true, - "T": 1588749118128, - "a": 284861226, - "f": 310207505, - "l": 310207505, + "T": 1577977827688, + "a": 202790198, + "f": 222825305, + "l": 222825305, "m": false, - "p": "9038.89000000", - "q": "0.01303300" + "p": "7140.95000000", + "q": "0.39850000" }, { "M": true, - "T": 1588749118341, - "a": 284861227, - "f": 310207506, - "l": 310207506, - "m": true, - "p": "9038.76000000", - "q": "0.06032200" + "T": 1577977828068, + "a": 202790199, + "f": 222825306, + "l": 222825306, + "m": false, + "p": "7140.71000000", + "q": "0.19575000" }, { "M": true, - "T": 1588749118447, - "a": 284861228, - "f": 310207507, - "l": 310207507, + "T": 1577977829347, + "a": 202790200, + "f": 222825307, + "l": 222825307, "m": true, - "p": "9038.76000000", - "q": "0.78000000" + "p": "7140.44000000", + "q": "0.00951600" }, { "M": true, - "T": 1588749118447, - "a": 284861229, - "f": 310207508, - "l": 310207508, - "m": true, - "p": "9038.76000000", - "q": "0.40000000" + "T": 1577977829464, + "a": 202790201, + "f": 222825308, + "l": 222825308, + "m": false, + "p": "7140.96000000", + "q": "0.00154600" }, { "M": true, - "T": 1588749118628, - "a": 284861230, - "f": 310207509, - "l": 310207509, + "T": 1577977829835, + "a": 202790202, + "f": 222825309, + "l": 222825309, "m": true, - "p": "9038.76000000", - "q": "0.00221300" + "p": "7140.56000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749118629, - "a": 284861231, - "f": 310207510, - "l": 310207510, + "T": 1577977830674, + "a": 202790203, + "f": 222825310, + "l": 222825310, "m": true, - "p": "9038.76000000", - "q": "0.00221300" + "p": "7140.73000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749118661, - "a": 284861232, - "f": 310207511, - "l": 310207511, + "T": 1577977831252, + "a": 202790204, + "f": 222825311, + "l": 222825311, "m": true, - "p": "9038.76000000", - "q": "0.06021500" + "p": "7140.73000000", + "q": "0.01774600" }, { "M": true, - "T": 1588749118728, - "a": 284861233, - "f": 310207512, - "l": 310207512, + "T": 1577977831252, + "a": 202790205, + "f": 222825312, + "l": 222825312, "m": true, - "p": "9038.76000000", - "q": "0.00221300" + "p": "7140.56000000", + "q": "0.02257400" }, { "M": true, - "T": 1588749118735, - "a": 284861234, - "f": 310207513, - "l": 310207513, - "m": true, - "p": "9038.76000000", - "q": "0.00221300" + "T": 1577977831493, + "a": 202790206, + "f": 222825313, + "l": 222825313, + "m": false, + "p": "7140.84000000", + "q": "0.21980800" + }, + { + "M": true, + "T": 1577977832173, + "a": 202790207, + "f": 222825314, + "l": 222825314, + "m": false, + "p": "7140.96000000", + "q": "0.00672000" }, { "M": true, - "T": 1588749118973, - "a": 284861235, - "f": 310207514, - "l": 310207514, + "T": 1577977832302, + "a": 202790208, + "f": 222825315, + "l": 222825315, "m": true, - "p": "9038.76000000", - "q": "0.06015900" + "p": "7140.86000000", + "q": "0.05757000" }, { "M": true, - "T": 1588749119287, - "a": 284861236, - "f": 310207515, - "l": 310207515, + "T": 1577977832718, + "a": 202790209, + "f": 222825316, + "l": 222825316, "m": true, - "p": "9038.76000000", - "q": "0.06003300" + "p": "7140.97000000", + "q": "0.05757000" }, { "M": true, - "T": 1588749119296, - "a": 284861237, - "f": 310207516, - "l": 310207516, + "T": 1577977833000, + "a": 202790210, + "f": 222825317, + "l": 222825317, "m": true, - "p": "9038.76000000", - "q": "0.05104000" + "p": "7141.01000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749119391, - "a": 284861238, - "f": 310207517, - "l": 310207517, + "T": 1577977833571, + "a": 202790211, + "f": 222825318, + "l": 222825318, "m": true, - "p": "9038.76000000", - "q": "0.13839600" + "p": "7141.06000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749119611, - "a": 284861239, - "f": 310207518, - "l": 310207518, + "T": 1577977834292, + "a": 202790212, + "f": 222825319, + "l": 222825319, "m": true, - "p": "9038.76000000", - "q": "0.06011900" + "p": "7141.14000000", + "q": "0.01403800" }, { "M": true, - "T": 1588749119633, - "a": 284861240, - "f": 310207519, - "l": 310207519, + "T": 1577977835092, + "a": 202790213, + "f": 222825320, + "l": 222825320, "m": false, - "p": "9038.77000000", - "q": "0.00132800" + "p": "7141.76000000", + "q": "0.15998800" }, { "M": true, - "T": 1588749119932, - "a": 284861241, - "f": 310207520, - "l": 310207520, + "T": 1577977837684, + "a": 202790214, + "f": 222825321, + "l": 222825321, + "m": false, + "p": "7141.99000000", + "q": "0.00160800" + }, + { + "M": true, + "T": 1577977838885, + "a": 202790215, + "f": 222825322, + "l": 222825322, + "m": false, + "p": "7141.77000000", + "q": "0.04714300" + }, + { + "M": true, + "T": 1577977838887, + "a": 202790216, + "f": 222825323, + "l": 222825323, "m": true, - "p": "9038.76000000", - "q": "0.06043200" + "p": "7141.23000000", + "q": "0.10381000" }, { "M": true, - "T": 1588749120021, - "a": 284861242, - "f": 310207521, - "l": 310207521, + "T": 1577977841231, + "a": 202790217, + "f": 222825324, + "l": 222825324, "m": true, - "p": "9038.76000000", - "q": "0.15659300" + "p": "7141.43000000", + "q": "0.23267200" }, { "M": true, - "T": 1588749120258, - "a": 284861243, - "f": 310207522, - "l": 310207522, + "T": 1577977841235, + "a": 202790218, + "f": 222825325, + "l": 222825325, "m": true, - "p": "9038.76000000", - "q": "0.06027900" + "p": "7141.19000000", + "q": "0.02609600" }, { "M": true, - "T": 1588749120485, - "a": 284861244, - "f": 310207523, - "l": 310207523, + "T": 1577977842688, + "a": 202790219, + "f": 222825326, + "l": 222825326, "m": false, - "p": "9038.77000000", - "q": "0.24000000" + "p": "7141.99000000", + "q": "0.05441300" }, { "M": true, - "T": 1588749120583, - "a": 284861245, - "f": 310207524, - "l": 310207524, + "T": 1577977842822, + "a": 202790220, + "f": 222825327, + "l": 222825327, "m": true, - "p": "9038.76000000", - "q": "0.06031200" + "p": "7141.99000000", + "q": "0.04554200" }, { "M": true, - "T": 1588749120737, - "a": 284861246, - "f": 310207525, - "l": 310207525, + "T": 1577977845894, + "a": 202790221, + "f": 222825328, + "l": 222825328, "m": false, - "p": "9038.77000000", - "q": "0.00300000" + "p": "7142.00000000", + "q": "0.00161100" }, { "M": true, - "T": 1588749120903, - "a": 284861247, - "f": 310207526, - "l": 310207526, - "m": true, - "p": "9038.76000000", - "q": "0.06007300" + "T": 1577977846867, + "a": 202790222, + "f": 222825329, + "l": 222825329, + "m": false, + "p": "7142.00000000", + "q": "0.02606000" }, { "M": true, - "T": 1588749121221, - "a": 284861248, - "f": 310207527, - "l": 310207527, - "m": true, - "p": "9038.76000000", - "q": "0.06049600" + "T": 1577977852112, + "a": 202790223, + "f": 222825330, + "l": 222825330, + "m": false, + "p": "7142.00000000", + "q": "0.00156200" }, { "M": true, - "T": 1588749121610, - "a": 284861249, - "f": 310207528, - "l": 310207528, - "m": true, - "p": "9038.76000000", - "q": "0.06003700" + "T": 1577977853887, + "a": 202790224, + "f": 222825331, + "l": 222825331, + "m": false, + "p": "7142.00000000", + "q": "0.00989900" }, { "M": true, - "T": 1588749121777, - "a": 284861250, - "f": 310207529, - "l": 310207529, + "T": 1577977853977, + "a": 202790225, + "f": 222825332, + "l": 222825333, "m": true, - "p": "9038.76000000", - "q": "0.06010100" + "p": "7141.99000000", + "q": "0.02372100" }, { "M": true, - "T": 1588749121863, - "a": 284861251, - "f": 310207530, - "l": 310207530, + "T": 1577977854245, + "a": 202790226, + "f": 222825334, + "l": 222825334, "m": true, - "p": "9038.76000000", - "q": "0.06006800" + "p": "7141.99000000", + "q": "0.26413300" }, { "M": true, - "T": 1588749122186, - "a": 284861252, - "f": 310207531, - "l": 310207531, - "m": true, - "p": "9038.76000000", - "q": "0.06039700" + "T": 1577977857117, + "a": 202790227, + "f": 222825335, + "l": 222825335, + "m": false, + "p": "7141.98000000", + "q": "0.12908000" }, { "M": true, - "T": 1588749122237, - "a": 284861253, - "f": 310207532, - "l": 310207532, + "T": 1577977857120, + "a": 202790228, + "f": 222825336, + "l": 222825336, "m": true, - "p": "9038.76000000", - "q": "0.05021100" + "p": "7141.54000000", + "q": "0.35037600" }, { "M": true, - "T": 1588749122516, - "a": 284861254, - "f": 310207533, - "l": 310207533, - "m": true, - "p": "9038.76000000", - "q": "0.06011400" + "T": 1577977858555, + "a": 202790229, + "f": 222825337, + "l": 222825337, + "m": false, + "p": "7142.00000000", + "q": "0.00158800" }, { "M": true, - "T": 1588749122830, - "a": 284861255, - "f": 310207534, - "l": 310207534, + "T": 1577977861153, + "a": 202790230, + "f": 222825338, + "l": 222825338, "m": true, - "p": "9038.76000000", - "q": "0.06002000" + "p": "7141.75000000", + "q": "0.35531200" }, { "M": true, - "T": 1588749122886, - "a": 284861256, - "f": 310207535, - "l": 310207535, - "m": true, - "p": "9038.76000000", - "q": "0.01400900" + "T": 1577977861158, + "a": 202790231, + "f": 222825339, + "l": 222825339, + "m": false, + "p": "7141.97000000", + "q": "0.02392000" }, { "M": true, - "T": 1588749122964, - "a": 284861257, - "f": 310207536, - "l": 310207536, + "T": 1577977861301, + "a": 202790232, + "f": 222825340, + "l": 222825340, "m": true, - "p": "9038.76000000", - "q": "0.15541900" + "p": "7141.80000000", + "q": "0.03633100" }, { "M": true, - "T": 1588749122990, - "a": 284861258, - "f": 310207537, - "l": 310207537, + "T": 1577977861396, + "a": 202790233, + "f": 222825341, + "l": 222825341, "m": true, - "p": "9038.76000000", - "q": "0.14735300" + "p": "7141.54000000", + "q": "0.03276200" }, { "M": true, - "T": 1588749123163, - "a": 284861259, - "f": 310207538, - "l": 310207538, - "m": true, - "p": "9038.76000000", - "q": "0.06022500" + "T": 1577977862782, + "a": 202790234, + "f": 222825342, + "l": 222825342, + "m": false, + "p": "7141.98000000", + "q": "0.03534500" + }, + { + "M": true, + "T": 1577977863266, + "a": 202790235, + "f": 222825343, + "l": 222825343, + "m": false, + "p": "7141.60000000", + "q": "0.13100700" + }, + { + "M": true, + "T": 1577977864754, + "a": 202790236, + "f": 222825344, + "l": 222825344, + "m": false, + "p": "7141.97000000", + "q": "0.01992100" }, { "M": true, - "T": 1588749123248, - "a": 284861260, - "f": 310207539, - "l": 310207539, + "T": 1577977864767, + "a": 202790237, + "f": 222825345, + "l": 222825345, "m": false, - "p": "9038.77000000", - "q": "0.02255000" + "p": "7141.97000000", + "q": "0.00002000" }, { "M": true, - "T": 1588749123498, - "a": 284861261, - "f": 310207540, - "l": 310207540, + "T": 1577977864767, + "a": 202790238, + "f": 222825346, + "l": 222825346, + "m": false, + "p": "7141.98000000", + "q": "0.00163600" + }, + { + "M": true, + "T": 1577977864861, + "a": 202790239, + "f": 222825347, + "l": 222825347, + "m": false, + "p": "7141.98000000", + "q": "0.04508000" + }, + { + "M": true, + "T": 1577977864964, + "a": 202790240, + "f": 222825348, + "l": 222825348, "m": true, - "p": "9038.76000000", - "q": "0.06024900" + "p": "7141.37000000", + "q": "0.06909600" }, { "M": true, - "T": 1588749123831, - "a": 284861262, - "f": 310207541, - "l": 310207541, + "T": 1577977865488, + "a": 202790241, + "f": 222825349, + "l": 222825349, "m": true, - "p": "9038.76000000", - "q": "0.06005900" + "p": "7141.37000000", + "q": "0.06909600" }, { "M": true, - "T": 1588749124170, - "a": 284861263, - "f": 310207542, - "l": 310207542, + "T": 1577977865791, + "a": 202790242, + "f": 222825350, + "l": 222825350, "m": true, - "p": "9038.76000000", - "q": "0.06033100" + "p": "7141.37000000", + "q": "0.06909600" }, { "M": true, - "T": 1588749124175, - "a": 284861264, - "f": 310207543, - "l": 310207543, + "T": 1577977866255, + "a": 202790243, + "f": 222825351, + "l": 222825351, + "m": true, + "p": "7141.43000000", + "q": "0.10865500" + }, + { + "M": true, + "T": 1577977866315, + "a": 202790244, + "f": 222825352, + "l": 222825352, + "m": true, + "p": "7141.43000000", + "q": "0.06909500" + }, + { + "M": true, + "T": 1577977867184, + "a": 202790245, + "f": 222825353, + "l": 222825353, "m": false, - "p": "9038.77000000", - "q": "0.02706800" + "p": "7141.96000000", + "q": "0.03800600" }, { "M": true, - "T": 1588749124310, - "a": 284861265, - "f": 310207544, - "l": 310207544, + "T": 1577977867184, + "a": 202790246, + "f": 222825354, + "l": 222825354, "m": false, - "p": "9039.22000000", - "q": "0.00660100" + "p": "7142.00000000", + "q": "0.03477300" }, { "M": true, - "T": 1588749124310, - "a": 284861266, - "f": 310207545, - "l": 310207545, + "T": 1577977867184, + "a": 202790247, + "f": 222825355, + "l": 222825355, "m": false, - "p": "9039.83000000", - "q": "0.45355500" + "p": "7142.34000000", + "q": "0.05000000" }, { "M": true, - "T": 1588749124310, - "a": 284861267, - "f": 310207546, - "l": 310207546, + "T": 1577977867184, + "a": 202790248, + "f": 222825356, + "l": 222825356, "m": false, - "p": "9039.84000000", - "q": "0.98320600" + "p": "7143.34000000", + "q": "0.27722100" }, { "M": true, - "T": 1588749124500, - "a": 284861268, - "f": 310207547, - "l": 310207547, - "m": true, - "p": "9038.77000000", - "q": "0.00221200" + "T": 1577977867270, + "a": 202790249, + "f": 222825357, + "l": 222825357, + "m": false, + "p": "7142.40000000", + "q": "0.27703000" }, { "M": true, - "T": 1588749124500, - "a": 284861269, - "f": 310207548, - "l": 310207548, + "T": 1577977867561, + "a": 202790250, + "f": 222825358, + "l": 222825358, "m": true, - "p": "9038.76000000", - "q": "0.01281200" + "p": "7141.62000000", + "q": "0.01155300" }, { "M": true, - "T": 1588749124500, - "a": 284861270, - "f": 310207549, - "l": 310207549, + "T": 1577977867998, + "a": 202790251, + "f": 222825359, + "l": 222825359, "m": true, - "p": "9038.52000000", - "q": "0.04526100" + "p": "7141.77000000", + "q": "0.05251000" }, { "M": true, - "T": 1588749124635, - "a": 284861271, - "f": 310207550, - "l": 310207550, + "T": 1577977871968, + "a": 202790252, + "f": 222825360, + "l": 222825360, "m": true, - "p": "9038.51000000", - "q": "0.09591100" + "p": "7143.41000000", + "q": "0.17702800" }, { "M": true, - "T": 1588749124641, - "a": 284861272, - "f": 310207551, - "l": 310207551, + "T": 1577977871968, + "a": 202790253, + "f": 222825361, + "l": 222825361, "m": true, - "p": "9038.51000000", - "q": "0.17274000" + "p": "7142.59000000", + "q": "0.02799500" }, { "M": true, - "T": 1588749124646, - "a": 284861273, - "f": 310207552, - "l": 310207552, + "T": 1577977871968, + "a": 202790254, + "f": 222825362, + "l": 222825362, "m": true, - "p": "9038.51000000", - "q": "0.01917700" + "p": "7142.58000000", + "q": "0.11774100" }, { "M": true, - "T": 1588749124680, - "a": 284861274, - "f": 310207553, - "l": 310207553, + "T": 1577977871968, + "a": 202790255, + "f": 222825363, + "l": 222825363, "m": true, - "p": "9038.51000000", - "q": "0.04136300" + "p": "7142.55000000", + "q": "0.03526200" }, { "M": true, - "T": 1588749124682, - "a": 284861275, - "f": 310207554, - "l": 310207554, + "T": 1577977871968, + "a": 202790256, + "f": 222825364, + "l": 222825364, "m": true, - "p": "9038.51000000", - "q": "0.17276600" + "p": "7142.41000000", + "q": "0.05526000" }, { "M": true, - "T": 1588749126091, - "a": 284861276, - "f": 310207555, - "l": 310207555, + "T": 1577977871968, + "a": 202790257, + "f": 222825365, + "l": 222825365, "m": true, - "p": "9038.51000000", - "q": "0.02909700" + "p": "7142.31000000", + "q": "0.00592600" }, { "M": true, - "T": 1588749126412, - "a": 284861277, - "f": 310207556, - "l": 310207556, + "T": 1577977873198, + "a": 202790258, + "f": 222825366, + "l": 222825366, "m": false, - "p": "9038.68000000", - "q": "0.01149400" + "p": "7143.36000000", + "q": "0.00160000" + }, + { + "M": true, + "T": 1577977873882, + "a": 202790259, + "f": 222825367, + "l": 222825367, + "m": true, + "p": "7142.32000000", + "q": "0.01697600" + }, + { + "M": true, + "T": 1577977874664, + "a": 202790260, + "f": 222825368, + "l": 222825368, + "m": true, + "p": "7142.32000000", + "q": "0.01101900" }, { "M": true, - "T": 1588749126423, - "a": 284861278, - "f": 310207557, - "l": 310207557, + "T": 1577977874664, + "a": 202790261, + "f": 222825369, + "l": 222825369, "m": true, - "p": "9038.52000000", - "q": "0.00789400" + "p": "7142.25000000", + "q": "0.03898100" }, { "M": true, - "T": 1588749126440, - "a": 284861279, - "f": 310207558, - "l": 310207558, + "T": 1577977874956, + "a": 202790262, + "f": 222825370, + "l": 222825370, "m": false, - "p": "9038.68000000", - "q": "0.16534100" + "p": "7142.71000000", + "q": "0.05370200" }, { "M": true, - "T": 1588749126440, - "a": 284861280, - "f": 310207559, - "l": 310207559, + "T": 1577977879424, + "a": 202790263, + "f": 222825371, + "l": 222825371, "m": false, - "p": "9038.72000000", - "q": "0.17287700" + "p": "7143.23000000", + "q": "0.00160200" + }, + { + "M": true, + "T": 1577977880711, + "a": 202790264, + "f": 222825372, + "l": 222825372, + "m": true, + "p": "7142.33000000", + "q": "0.00275400" }, { "M": true, - "T": 1588749126440, - "a": 284861281, - "f": 310207560, - "l": 310207560, + "T": 1577977881638, + "a": 202790265, + "f": 222825373, + "l": 222825373, "m": false, - "p": "9038.77000000", - "q": "0.01000000" + "p": "7143.18000000", + "q": "0.00727100" }, { "M": true, - "T": 1588749126518, - "a": 284861282, - "f": 310207561, - "l": 310207561, + "T": 1577977882615, + "a": 202790266, + "f": 222825374, + "l": 222825374, "m": true, - "p": "9039.12000000", - "q": "0.04112400" + "p": "7142.28000000", + "q": "0.04586600" }, { "M": true, - "T": 1588749126609, - "a": 284861283, - "f": 310207562, - "l": 310207562, + "T": 1577977884427, + "a": 202790267, + "f": 222825375, + "l": 222825375, "m": true, - "p": "9039.12000000", - "q": "0.06232200" + "p": "7142.29000000", + "q": "0.01288700" }, { "M": true, - "T": 1588749126706, - "a": 284861284, - "f": 310207563, - "l": 310207563, + "T": 1577977885630, + "a": 202790268, + "f": 222825376, + "l": 222825376, "m": false, - "p": "9039.51000000", - "q": "0.06400000" + "p": "7143.18000000", + "q": "0.00164200" }, { "M": true, - "T": 1588749126724, - "a": 284861285, - "f": 310207564, - "l": 310207564, - "m": true, - "p": "9039.12000000", - "q": "0.01038700" + "T": 1577977887305, + "a": 202790269, + "f": 222825377, + "l": 222825377, + "m": false, + "p": "7142.87000000", + "q": "0.24538600" }, { "M": true, - "T": 1588749126842, - "a": 284861286, - "f": 310207565, - "l": 310207565, - "m": true, - "p": "9039.12000000", - "q": "0.01038700" + "T": 1577977888040, + "a": 202790270, + "f": 222825378, + "l": 222825378, + "m": false, + "p": "7143.12000000", + "q": "0.02863400" }, { "M": true, - "T": 1588749126927, - "a": 284861287, - "f": 310207566, - "l": 310207566, - "m": true, - "p": "9039.12000000", - "q": "0.01038700" + "T": 1577977891199, + "a": 202790271, + "f": 222825379, + "l": 222825379, + "m": false, + "p": "7142.87000000", + "q": "0.33497600" }, { "M": true, - "T": 1588749127043, - "a": 284861288, - "f": 310207567, - "l": 310207567, + "T": 1577977893862, + "a": 202790272, + "f": 222825380, + "l": 222825380, "m": false, - "p": "9039.13000000", - "q": "0.00472000" + "p": "7143.07000000", + "q": "0.00162800" }, { "M": true, - "T": 1588749127053, - "a": 284861289, - "f": 310207568, - "l": 310207568, - "m": true, - "p": "9039.12000000", - "q": "0.01038700" + "T": 1577977894560, + "a": 202790273, + "f": 222825381, + "l": 222825381, + "m": false, + "p": "7143.07000000", + "q": "0.10226000" }, { "M": true, - "T": 1588749127137, - "a": 284861290, - "f": 310207569, - "l": 310207569, - "m": true, - "p": "9039.12000000", - "q": "0.01038700" + "T": 1577977894900, + "a": 202790274, + "f": 222825382, + "l": 222825382, + "m": false, + "p": "7142.30000000", + "q": "0.07266600" }, { "M": true, - "T": 1588749127249, - "a": 284861291, - "f": 310207570, - "l": 310207570, - "m": true, - "p": "9039.12000000", - "q": "0.00629000" + "T": 1577977894900, + "a": 202790275, + "f": 222825383, + "l": 222825384, + "m": false, + "p": "7143.32000000", + "q": "0.07386100" }, { "M": true, - "T": 1588749128000, - "a": 284861292, - "f": 310207571, - "l": 310207571, - "m": true, - "p": "9039.12000000", - "q": "0.00002100" + "T": 1577977894900, + "a": 202790276, + "f": 222825385, + "l": 222825385, + "m": false, + "p": "7143.38000000", + "q": "0.05000000" }, { "M": true, - "T": 1588749128000, - "a": 284861293, - "f": 310207572, - "l": 310207572, - "m": true, - "p": "9038.52000000", - "q": "0.00587900" + "T": 1577977894900, + "a": 202790277, + "f": 222825386, + "l": 222825386, + "m": false, + "p": "7143.44000000", + "q": "0.14971500" }, { "M": true, - "T": 1588749128000, - "a": 284861294, - "f": 310207573, - "l": 310207573, - "m": true, - "p": "9038.51000000", - "q": "0.21894600" + "T": 1577977894900, + "a": 202790278, + "f": 222825387, + "l": 222825387, + "m": false, + "p": "7144.03000000", + "q": "0.05375800" }, { "M": true, - "T": 1588749128000, - "a": 284861295, - "f": 310207574, - "l": 310207574, - "m": true, - "p": "9038.48000000", - "q": "0.17515400" + "T": 1577977896135, + "a": 202790279, + "f": 222825388, + "l": 222825388, + "m": false, + "p": "7143.94000000", + "q": "0.00349800" }, { "M": true, - "T": 1588749128334, - "a": 284861296, - "f": 310207575, - "l": 310207575, - "m": true, - "p": "9037.86000000", - "q": "0.00749700" + "T": 1577977897536, + "a": 202790280, + "f": 222825389, + "l": 222825389, + "m": false, + "p": "7142.99000000", + "q": "0.31642700" }, { "M": true, - "T": 1588749128334, - "a": 284861297, - "f": 310207576, - "l": 310207576, + "T": 1577977898226, + "a": 202790281, + "f": 222825390, + "l": 222825390, "m": true, - "p": "9037.82000000", - "q": "0.00300000" + "p": "7142.42000000", + "q": "0.00339400" }, { "M": true, - "T": 1588749128334, - "a": 284861298, - "f": 310207577, - "l": 310207577, + "T": 1577977900980, + "a": 202790282, + "f": 222825391, + "l": 222825391, "m": true, - "p": "9037.75000000", - "q": "0.00300000" + "p": "7142.48000000", + "q": "0.00240200" }, { "M": true, - "T": 1588749128334, - "a": 284861299, - "f": 310207578, - "l": 310207578, - "m": true, - "p": "9037.33000000", - "q": "0.00199300" + "T": 1577977902096, + "a": 202790283, + "f": 222825392, + "l": 222825392, + "m": false, + "p": "7143.85000000", + "q": "0.00158400" }, { "M": true, - "T": 1588749128334, - "a": 284861300, - "f": 310207579, - "l": 310207579, - "m": true, - "p": "9037.29000000", - "q": "0.00150000" + "T": 1577977902129, + "a": 202790284, + "f": 222825393, + "l": 222825393, + "m": false, + "p": "7143.85000000", + "q": "0.00148400" }, { "M": true, - "T": 1588749128334, - "a": 284861301, - "f": 310207580, - "l": 310207580, - "m": true, - "p": "9037.21000000", - "q": "0.03319600" + "T": 1577977902376, + "a": 202790285, + "f": 222825394, + "l": 222825394, + "m": false, + "p": "7143.33000000", + "q": "0.20940800" }, { "M": true, - "T": 1588749128334, - "a": 284861302, - "f": 310207581, - "l": 310207581, + "T": 1577977908022, + "a": 202790286, + "f": 222825395, + "l": 222825395, "m": true, - "p": "9037.20000000", - "q": "0.00985700" + "p": "7142.69000000", + "q": "0.00753900" }, { "M": true, - "T": 1588749128582, - "a": 284861303, - "f": 310207582, - "l": 310207582, - "m": true, - "p": "9038.00000000", - "q": "0.02010600" + "T": 1577977908316, + "a": 202790287, + "f": 222825396, + "l": 222825396, + "m": false, + "p": "7143.70000000", + "q": "0.00167500" }, { "M": true, - "T": 1588749128582, - "a": 284861304, - "f": 310207583, - "l": 310207583, - "m": true, - "p": "9037.28000000", - "q": "0.01963800" + "T": 1577977908628, + "a": 202790288, + "f": 222825397, + "l": 222825397, + "m": false, + "p": "7143.41000000", + "q": "0.36287100" }, { "M": true, - "T": 1588749128968, - "a": 284861305, - "f": 310207584, - "l": 310207584, - "m": true, - "p": "9037.78000000", - "q": "0.11461100" + "T": 1577977911160, + "a": 202790289, + "f": 222825398, + "l": 222825398, + "m": false, + "p": "7142.98000000", + "q": "0.41503000" }, { "M": true, - "T": 1588749129293, - "a": 284861306, - "f": 310207585, - "l": 310207585, - "m": true, - "p": "9038.00000000", - "q": "0.00252000" + "T": 1577977914514, + "a": 202790290, + "f": 222825399, + "l": 222825399, + "m": false, + "p": "7143.55000000", + "q": "0.00161500" }, { "M": true, - "T": 1588749129293, - "a": 284861307, - "f": 310207586, - "l": 310207586, - "m": true, - "p": "9037.25000000", - "q": "0.05790500" + "T": 1577977914607, + "a": 202790291, + "f": 222825400, + "l": 222825400, + "m": false, + "p": "7143.27000000", + "q": "0.13019500" }, { "M": true, - "T": 1588749129629, - "a": 284861308, - "f": 310207587, - "l": 310207587, + "T": 1577977914615, + "a": 202790292, + "f": 222825401, + "l": 222825401, + "m": false, + "p": "7143.55000000", + "q": "0.04862600" + }, + { + "M": true, + "T": 1577977917527, + "a": 202790293, + "f": 222825402, + "l": 222825402, + "m": false, + "p": "7143.67000000", + "q": "0.00437000" + }, + { + "M": true, + "T": 1577977917647, + "a": 202790294, + "f": 222825403, + "l": 222825403, + "m": false, + "p": "7143.67000000", + "q": "0.01516200" + }, + { + "M": true, + "T": 1577977917704, + "a": 202790295, + "f": 222825404, + "l": 222825404, "m": true, - "p": "9037.37000000", - "q": "0.06019900" + "p": "7143.66000000", + "q": "0.01516200" }, { "M": true, - "T": 1588749129863, - "a": 284861309, - "f": 310207588, - "l": 310207588, + "T": 1577977917822, + "a": 202790296, + "f": 222825405, + "l": 222825405, "m": true, - "p": "9037.29000000", - "q": "0.05527600" + "p": "7143.56000000", + "q": "0.01387400" + }, + { + "M": true, + "T": 1577977918343, + "a": 202790297, + "f": 222825406, + "l": 222825406, + "m": false, + "p": "7143.66000000", + "q": "0.01199900" }, { "M": true, - "T": 1588749129956, - "a": 284861310, - "f": 310207589, - "l": 310207589, + "T": 1577977919352, + "a": 202790298, + "f": 222825407, + "l": 222825407, "m": true, - "p": "9037.21000000", - "q": "0.06020500" + "p": "7143.61000000", + "q": "0.09579600" }, { "M": true, - "T": 1588749129973, - "a": 284861311, - "f": 310207590, - "l": 310207590, + "T": 1577977919388, + "a": 202790299, + "f": 222825408, + "l": 222825408, "m": true, - "p": "9037.20000000", - "q": "0.08867100" + "p": "7143.56000000", + "q": "0.00128800" }, { "M": true, - "T": 1588749129973, - "a": 284861312, - "f": 310207591, - "l": 310207592, + "T": 1577977919388, + "a": 202790300, + "f": 222825409, + "l": 222825410, "m": true, - "p": "9037.18000000", - "q": "0.05504700" + "p": "7142.69000000", + "q": "0.04082800" }, { "M": true, - "T": 1588749130121, - "a": 284861313, - "f": 310207593, - "l": 310207593, + "T": 1577977920731, + "a": 202790301, + "f": 222825411, + "l": 222825411, "m": false, - "p": "9037.74000000", - "q": "0.05422300" + "p": "7143.65000000", + "q": "0.00164300" }, { "M": true, - "T": 1588749130169, - "a": 284861314, - "f": 310207594, - "l": 310207594, + "T": 1577977921363, + "a": 202790302, + "f": 222825412, + "l": 222825412, "m": false, - "p": "9037.74000000", - "q": "0.00845000" + "p": "7143.65000000", + "q": "0.01199800" }, { "M": true, - "T": 1588749130229, - "a": 284861315, - "f": 310207595, - "l": 310207595, + "T": 1577977921401, + "a": 202790303, + "f": 222825413, + "l": 222825413, "m": false, - "p": "9038.06000000", - "q": "0.00165800" + "p": "7143.65000000", + "q": "0.01199800" }, { "M": true, - "T": 1588749130288, - "a": 284861316, - "f": 310207596, - "l": 310207596, + "T": 1577977922663, + "a": 202790304, + "f": 222825414, + "l": 222825414, "m": true, - "p": "9037.30000000", - "q": "0.06004500" + "p": "7143.12000000", + "q": "0.25303400" }, { "M": true, - "T": 1588749130333, - "a": 284861317, - "f": 310207597, - "l": 310207597, + "T": 1577977923198, + "a": 202790305, + "f": 222825415, + "l": 222825415, "m": false, - "p": "9038.10000000", - "q": "0.00307900" + "p": "7143.56000000", + "q": "0.00697100" }, { "M": true, - "T": 1588749130456, - "a": 284861318, - "f": 310207598, - "l": 310207598, + "T": 1577977923289, + "a": 202790306, + "f": 222825416, + "l": 222825416, "m": false, - "p": "9037.71000000", - "q": "0.00325100" + "p": "7143.56000000", + "q": "0.00255300" }, { "M": true, - "T": 1588749130542, - "a": 284861319, - "f": 310207599, - "l": 310207599, + "T": 1577977924023, + "a": 202790307, + "f": 222825417, + "l": 222825417, "m": false, - "p": "9037.71000000", - "q": "0.00674900" + "p": "7143.55000000", + "q": "0.00279700" }, { "M": true, - "T": 1588749130607, - "a": 284861320, - "f": 310207600, - "l": 310207600, - "m": true, - "p": "9037.56000000", - "q": "0.06008000" + "T": 1577977924367, + "a": 202790308, + "f": 222825418, + "l": 222825418, + "m": false, + "p": "7143.55000000", + "q": "0.01199800" }, { "M": true, - "T": 1588749130931, - "a": 284861321, - "f": 310207601, - "l": 310207601, - "m": true, - "p": "9037.82000000", - "q": "0.06033800" + "T": 1577977925204, + "a": 202790309, + "f": 222825419, + "l": 222825419, + "m": false, + "p": "7143.55000000", + "q": "0.02097100" }, { "M": true, - "T": 1588749131260, - "a": 284861322, - "f": 310207602, - "l": 310207602, - "m": true, - "p": "9037.94000000", - "q": "0.06023400" + "T": 1577977925204, + "a": 202790310, + "f": 222825420, + "l": 222825420, + "m": false, + "p": "7143.56000000", + "q": "0.00002700" }, { "M": true, - "T": 1588749131587, - "a": 284861323, - "f": 310207603, - "l": 310207603, - "m": true, - "p": "9037.94000000", - "q": "0.06034600" + "T": 1577977925415, + "a": 202790311, + "f": 222825421, + "l": 222825421, + "m": false, + "p": "7143.10000000", + "q": "0.01199900" }, { "M": true, - "T": 1588749131600, - "a": 284861324, - "f": 310207604, - "l": 310207604, - "m": true, - "p": "9037.83000000", - "q": "0.00221300" + "T": 1577977926038, + "a": 202790312, + "f": 222825422, + "l": 222825422, + "m": false, + "p": "7142.80000000", + "q": "0.08981200" }, { "M": true, - "T": 1588749131605, - "a": 284861325, - "f": 310207605, - "l": 310207605, + "T": 1577977928634, + "a": 202790313, + "f": 222825423, + "l": 222825423, "m": true, - "p": "9037.46000000", - "q": "0.00221300" + "p": "7142.69000000", + "q": "0.03500000" }, { "M": true, - "T": 1588749131606, - "a": 284861326, - "f": 310207606, - "l": 310207606, - "m": true, - "p": "9037.46000000", - "q": "0.00221300" + "T": 1577977928951, + "a": 202790314, + "f": 222825424, + "l": 222825424, + "m": false, + "p": "7143.04000000", + "q": "0.00167400" }, { "M": true, - "T": 1588749131714, - "a": 284861327, - "f": 310207607, - "l": 310207607, - "m": true, - "p": "9037.14000000", - "q": "0.00221300" + "T": 1577977929483, + "a": 202790315, + "f": 222825425, + "l": 222825425, + "m": false, + "p": "7142.89000000", + "q": "0.04580200" }, { "M": true, - "T": 1588749131926, - "a": 284861328, - "f": 310207608, - "l": 310207608, - "m": true, - "p": "9037.15000000", - "q": "0.06039700" + "T": 1577977931482, + "a": 202790316, + "f": 222825426, + "l": 222825426, + "m": false, + "p": "7143.04000000", + "q": "0.06988100" }, { "M": true, - "T": 1588749132182, - "a": 284861329, - "f": 310207609, - "l": 310207609, - "m": true, - "p": "9037.42000000", - "q": "0.00785700" + "T": 1577977933509, + "a": 202790317, + "f": 222825427, + "l": 222825427, + "m": false, + "p": "7143.02000000", + "q": "0.12355800" }, { "M": true, - "T": 1588749132182, - "a": 284861330, - "f": 310207610, - "l": 310207610, + "T": 1577977933511, + "a": 202790318, + "f": 222825428, + "l": 222825428, "m": true, - "p": "9037.30000000", - "q": "0.09791900" + "p": "7142.92000000", + "q": "0.15900300" }, { "M": true, - "T": 1588749132248, - "a": 284861331, - "f": 310207611, - "l": 310207611, + "T": 1577977934277, + "a": 202790319, + "f": 222825429, + "l": 222825429, "m": false, - "p": "9037.30000000", - "q": "0.00307900" + "p": "7142.70000000", + "q": "0.01572300" }, { "M": true, - "T": 1588749132259, - "a": 284861332, - "f": 310207612, - "l": 310207612, - "m": true, - "p": "9037.29000000", - "q": "0.06024100" + "T": 1577977934277, + "a": 202790320, + "f": 222825430, + "l": 222825430, + "m": false, + "p": "7143.10000000", + "q": "0.00280600" }, { "M": true, - "T": 1588749132341, - "a": 284861333, - "f": 310207613, - "l": 310207613, + "T": 1577977936592, + "a": 202790321, + "f": 222825431, + "l": 222825431, "m": false, - "p": "9037.30000000", - "q": "0.00899300" + "p": "7143.09000000", + "q": "0.00141500" }, { "M": true, - "T": 1588749132374, - "a": 284861334, - "f": 310207614, - "l": 310207614, + "T": 1577977936927, + "a": 202790322, + "f": 222825432, + "l": 222825432, + "m": false, + "p": "7143.09000000", + "q": "0.00504100" + }, + { + "M": true, + "T": 1577977936934, + "a": 202790323, + "f": 222825433, + "l": 222825433, "m": true, - "p": "9037.29000000", - "q": "0.01105600" + "p": "7143.06000000", + "q": "0.16065000" }, { "M": true, - "T": 1588749132759, - "a": 284861335, - "f": 310207615, - "l": 310207615, + "T": 1577977937170, + "a": 202790324, + "f": 222825434, + "l": 222825434, "m": false, - "p": "9037.30000000", - "q": "0.22374600" + "p": "7143.09000000", + "q": "0.00155300" }, { "M": true, - "T": 1588749133292, - "a": 284861336, - "f": 310207616, - "l": 310207616, + "T": 1577977937453, + "a": 202790325, + "f": 222825435, + "l": 222825435, "m": true, - "p": "9037.29000000", - "q": "0.19051300" + "p": "7143.08000000", + "q": "0.00416200" + }, + { + "M": true, + "T": 1577977938272, + "a": 202790326, + "f": 222825436, + "l": 222825436, + "m": false, + "p": "7143.09000000", + "q": "0.04200400" }, { "M": true, - "T": 1588749133623, - "a": 284861337, - "f": 310207617, - "l": 310207617, + "T": 1577977938346, + "a": 202790327, + "f": 222825437, + "l": 222825437, "m": true, - "p": "9037.20000000", - "q": "0.06022800" + "p": "7143.09000000", + "q": "0.02756300" }, { "M": true, - "T": 1588749133959, - "a": 284861338, - "f": 310207618, - "l": 310207618, + "T": 1577977938380, + "a": 202790328, + "f": 222825438, + "l": 222825438, "m": true, - "p": "9037.17000000", - "q": "0.06010000" + "p": "7143.08000000", + "q": "0.02061500" }, { "M": true, - "T": 1588749134144, - "a": 284861339, - "f": 310207619, - "l": 310207619, + "T": 1577977938382, + "a": 202790329, + "f": 222825439, + "l": 222825439, "m": false, - "p": "9037.29000000", - "q": "0.00364100" + "p": "7143.10000000", + "q": "0.01346500" }, { "M": true, - "T": 1588749134294, - "a": 284861340, - "f": 310207620, - "l": 310207620, + "T": 1577977938485, + "a": 202790330, + "f": 222825440, + "l": 222825440, + "m": false, + "p": "7143.10000000", + "q": "0.30000000" + }, + { + "M": true, + "T": 1577977940190, + "a": 202790331, + "f": 222825441, + "l": 222825441, "m": true, - "p": "9037.29000000", - "q": "0.06037500" + "p": "7143.08000000", + "q": "0.00284800" }, { "M": true, - "T": 1588749134419, - "a": 284861341, - "f": 310207621, - "l": 310207621, + "T": 1577977943381, + "a": 202790332, + "f": 222825442, + "l": 222825442, "m": false, - "p": "9037.30000000", - "q": "0.05651800" + "p": "7143.10000000", + "q": "0.00155800" }, { "M": true, - "T": 1588749134626, - "a": 284861342, - "f": 310207622, - "l": 310207622, + "T": 1577977946595, + "a": 202790333, + "f": 222825443, + "l": 222825443, "m": true, - "p": "9037.29000000", - "q": "0.06062200" + "p": "7143.08000000", + "q": "0.00280000" }, { "M": true, - "T": 1588749134958, - "a": 284861343, - "f": 310207623, - "l": 310207623, - "m": true, - "p": "9037.29000000", - "q": "0.06014300" + "T": 1577977948130, + "a": 202790334, + "f": 222825444, + "l": 222825444, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749135127, - "a": 284861344, - "f": 310207624, - "l": 310207624, + "T": 1577977948130, + "a": 202790335, + "f": 222825445, + "l": 222825445, "m": false, - "p": "9037.30000000", - "q": "0.09014200" + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749135127, - "a": 284861345, - "f": 310207625, - "l": 310207625, + "T": 1577977948130, + "a": 202790336, + "f": 222825446, + "l": 222825446, "m": false, - "p": "9037.79000000", - "q": "0.00794200" + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749135127, - "a": 284861346, - "f": 310207626, - "l": 310207626, + "T": 1577977948131, + "a": 202790337, + "f": 222825447, + "l": 222825447, "m": false, - "p": "9037.91000000", - "q": "0.01860900" + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749135389, - "a": 284861347, - "f": 310207627, - "l": 310207627, - "m": true, - "p": "9037.85000000", - "q": "0.07777600" + "T": 1577977948131, + "a": 202790338, + "f": 222825448, + "l": 222825448, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749135792, - "a": 284861348, - "f": 310207628, - "l": 310207628, - "m": true, - "p": "9037.71000000", - "q": "0.07261300" + "T": 1577977948131, + "a": 202790339, + "f": 222825449, + "l": 222825449, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749136486, - "a": 284861349, - "f": 310207629, - "l": 310207629, - "m": true, - "p": "9037.23000000", - "q": "0.08758800" + "T": 1577977948131, + "a": 202790340, + "f": 222825450, + "l": 222825450, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749136641, - "a": 284861350, - "f": 310207630, - "l": 310207630, - "m": true, - "p": "9037.46000000", - "q": "0.00615500" + "T": 1577977948131, + "a": 202790341, + "f": 222825451, + "l": 222825451, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749136826, - "a": 284861351, - "f": 310207631, - "l": 310207632, - "m": true, - "p": "9037.46000000", - "q": "0.18594400" + "T": 1577977948133, + "a": 202790342, + "f": 222825452, + "l": 222825452, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749136959, - "a": 284861352, - "f": 310207633, - "l": 310207633, - "m": true, - "p": "9037.46000000", - "q": "0.00221300" + "T": 1577977948134, + "a": 202790343, + "f": 222825453, + "l": 222825453, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749136960, - "a": 284861353, - "f": 310207634, - "l": 310207634, - "m": true, - "p": "9037.46000000", - "q": "0.00221300" + "T": 1577977948135, + "a": 202790344, + "f": 222825454, + "l": 222825454, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749136964, - "a": 284861354, - "f": 310207635, - "l": 310207635, - "m": true, - "p": "9037.46000000", - "q": "0.00221300" + "T": 1577977948135, + "a": 202790345, + "f": 222825455, + "l": 222825455, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749136968, - "a": 284861355, - "f": 310207636, - "l": 310207636, - "m": true, - "p": "9037.46000000", - "q": "0.00221300" + "T": 1577977948135, + "a": 202790346, + "f": 222825456, + "l": 222825456, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137022, - "a": 284861356, - "f": 310207637, - "l": 310207637, - "m": true, - "p": "9037.25000000", - "q": "0.05000000" + "T": 1577977948136, + "a": 202790347, + "f": 222825457, + "l": 222825457, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137045, - "a": 284861357, - "f": 310207638, - "l": 310207638, + "T": 1577977948136, + "a": 202790348, + "f": 222825458, + "l": 222825458, "m": false, - "p": "9037.26000000", - "q": "0.24375000" + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137142, - "a": 284861358, - "f": 310207639, - "l": 310207639, - "m": true, - "p": "9037.25000000", - "q": "0.03306000" + "T": 1577977948136, + "a": 202790349, + "f": 222825459, + "l": 222825459, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137151, - "a": 284861359, - "f": 310207640, - "l": 310207640, - "m": true, - "p": "9037.25000000", - "q": "0.06020900" + "T": 1577977948136, + "a": 202790350, + "f": 222825460, + "l": 222825460, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137238, - "a": 284861360, - "f": 310207641, - "l": 310207641, - "m": true, - "p": "9037.25000000", - "q": "0.00221300" + "T": 1577977948136, + "a": 202790351, + "f": 222825461, + "l": 222825461, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137240, - "a": 284861361, - "f": 310207642, - "l": 310207642, - "m": true, - "p": "9037.25000000", - "q": "0.00221300" + "T": 1577977948136, + "a": 202790352, + "f": 222825462, + "l": 222825462, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137264, - "a": 284861362, - "f": 310207643, - "l": 310207643, - "m": true, - "p": "9037.25000000", - "q": "0.02000000" + "T": 1577977948141, + "a": 202790353, + "f": 222825463, + "l": 222825463, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137302, - "a": 284861363, - "f": 310207644, - "l": 310207644, - "m": true, - "p": "9037.25000000", - "q": "0.01000000" + "T": 1577977948142, + "a": 202790354, + "f": 222825464, + "l": 222825464, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137342, - "a": 284861364, - "f": 310207645, - "l": 310207645, - "m": true, - "p": "9037.25000000", - "q": "0.00221300" + "T": 1577977948142, + "a": 202790355, + "f": 222825465, + "l": 222825465, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137347, - "a": 284861365, - "f": 310207646, - "l": 310207646, - "m": true, - "p": "9037.25000000", - "q": "0.00221300" + "T": 1577977948146, + "a": 202790356, + "f": 222825466, + "l": 222825466, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137417, - "a": 284861366, - "f": 310207647, - "l": 310207647, - "m": true, - "p": "9037.25000000", - "q": "0.05710500" + "T": 1577977948147, + "a": 202790357, + "f": 222825467, + "l": 222825467, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" }, { "M": true, - "T": 1588749137417, - "a": 284861367, - "f": 310207648, - "l": 310207648, - "m": true, - "p": "9037.13000000", - "q": "0.00221200" + "T": 1577977948147, + "a": 202790358, + "f": 222825468, + "l": 222825468, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" + }, + { + "M": true, + "T": 1577977948147, + "a": 202790359, + "f": 222825469, + "l": 222825469, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" + }, + { + "M": true, + "T": 1577977948147, + "a": 202790360, + "f": 222825470, + "l": 222825470, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" + }, + { + "M": true, + "T": 1577977948148, + "a": 202790361, + "f": 222825471, + "l": 222825471, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" + }, + { + "M": true, + "T": 1577977948148, + "a": 202790362, + "f": 222825472, + "l": 222825472, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" + }, + { + "M": true, + "T": 1577977948153, + "a": 202790363, + "f": 222825473, + "l": 222825473, + "m": false, + "p": "7143.08000000", + "q": "0.01110000" + }, + { + "M": true, + "T": 1577977948319, + "a": 202790364, + "f": 222825474, + "l": 222825474, + "m": false, + "p": "7143.10000000", + "q": "0.01234500" + }, + { + "M": true, + "T": 1577977949665, + "a": 202790365, + "f": 222825475, + "l": 222825475, + "m": false, + "p": "7143.09000000", + "q": "0.26107300" + }, + { + "M": true, + "T": 1577977949709, + "a": 202790366, + "f": 222825476, + "l": 222825477, + "m": false, + "p": "7143.10000000", + "q": "0.25000000" + }, + { + "M": true, + "T": 1577977951600, + "a": 202790367, + "f": 222825478, + "l": 222825478, + "m": false, + "p": "7143.10000000", + "q": "0.00159200" }, { "M": true, - "T": 1588749137417, - "a": 284861368, - "f": 310207649, - "l": 310207649, - "m": true, - "p": "9036.81000000", - "q": "0.00300000" + "T": 1577977953305, + "a": 202790368, + "f": 222825479, + "l": 222825479, + "m": false, + "p": "7143.09000000", + "q": "0.00141500" }, { "M": true, - "T": 1588749137417, - "a": 284861369, - "f": 310207650, - "l": 310207650, - "m": true, - "p": "9036.46000000", - "q": "0.02613400" + "T": 1577977954780, + "a": 202790369, + "f": 222825480, + "l": 222825481, + "m": false, + "p": "7143.10000000", + "q": "0.79533300" }, { "M": true, - "T": 1588749137457, - "a": 284861370, - "f": 310207651, - "l": 310207651, - "m": true, - "p": "9035.79000000", - "q": "0.00300000" + "T": 1577977957096, + "a": 202790370, + "f": 222825482, + "l": 222825482, + "m": false, + "p": "7143.55000000", + "q": "0.13095800" }, { "M": true, - "T": 1588749137457, - "a": 284861371, - "f": 310207652, - "l": 310207652, - "m": true, - "p": "9035.44000000", - "q": "0.06332000" + "T": 1577977957596, + "a": 202790371, + "f": 222825483, + "l": 222825483, + "m": false, + "p": "7143.56000000", + "q": "0.07954500" }, { "M": true, - "T": 1588749137480, - "a": 284861372, - "f": 310207653, - "l": 310207653, - "m": true, - "p": "9035.44000000", - "q": "0.03193400" + "T": 1577977957596, + "a": 202790372, + "f": 222825484, + "l": 222825484, + "m": false, + "p": "7143.76000000", + "q": "0.02799500" }, { "M": true, - "T": 1588749137480, - "a": 284861373, - "f": 310207654, - "l": 310207654, - "m": true, - "p": "9035.38000000", - "q": "0.00115500" + "T": 1577977957596, + "a": 202790373, + "f": 222825485, + "l": 222825485, + "m": false, + "p": "7144.11000000", + "q": "0.29246000" }, { "M": true, - "T": 1588749137480, - "a": 284861374, - "f": 310207655, - "l": 310207655, + "T": 1577977957751, + "a": 202790374, + "f": 222825486, + "l": 222825486, "m": true, - "p": "9035.30000000", - "q": "0.02693800" + "p": "7143.57000000", + "q": "0.06295200" }, { "M": true, - "T": 1588749137515, - "a": 284861375, - "f": 310207656, - "l": 310207656, + "T": 1577977957820, + "a": 202790375, + "f": 222825487, + "l": 222825487, "m": false, - "p": "9035.39000000", - "q": "0.00307900" + "p": "7144.11000000", + "q": "0.00163200" }, { "M": true, - "T": 1588749137541, - "a": 284861376, - "f": 310207657, - "l": 310207657, - "m": true, - "p": "9035.30000000", - "q": "0.05528000" + "T": 1577977959902, + "a": 202790376, + "f": 222825488, + "l": 222825488, + "m": false, + "p": "7143.88000000", + "q": "0.18884400" }, { "M": true, - "T": 1588749137571, - "a": 284861377, - "f": 310207658, - "l": 310207658, - "m": true, - "p": "9035.30000000", - "q": "0.01105200" + "T": 1577977960139, + "a": 202790377, + "f": 222825489, + "l": 222825489, + "m": false, + "p": "7144.11000000", + "q": "0.12912900" }, { "M": true, - "T": 1588749137611, - "a": 284861378, - "f": 310207659, - "l": 310207659, + "T": 1577977963494, + "a": 202790378, + "f": 222825490, + "l": 222825490, "m": true, - "p": "9035.30000000", - "q": "0.00197700" + "p": "7143.87000000", + "q": "0.15859900" }, { "M": true, - "T": 1588749137611, - "a": 284861379, - "f": 310207660, - "l": 310207660, - "m": true, - "p": "9035.20000000", - "q": "0.00300000" + "T": 1577977964030, + "a": 202790379, + "f": 222825491, + "l": 222825491, + "m": false, + "p": "7143.65000000", + "q": "0.00157800" }, { "M": true, - "T": 1588749137611, - "a": 284861380, - "f": 310207661, - "l": 310207661, + "T": 1577977965850, + "a": 202790380, + "f": 222825492, + "l": 222825492, "m": true, - "p": "9035.15000000", - "q": "0.10558900" + "p": "7143.64000000", + "q": "0.09259000" }, { "M": true, - "T": 1588749137620, - "a": 284861381, - "f": 310207662, - "l": 310207662, - "m": false, - "p": "9035.35000000", - "q": "0.00307900" + "T": 1577977967670, + "a": 202790381, + "f": 222825493, + "l": 222825494, + "m": true, + "p": "7143.64000000", + "q": "1.27008500" }, { "M": true, - "T": 1588749137647, - "a": 284861382, - "f": 310207663, - "l": 310207663, + "T": 1577977967670, + "a": 202790382, + "f": 222825495, + "l": 222825495, "m": true, - "p": "9035.15000000", - "q": "0.00481200" + "p": "7143.59000000", + "q": "0.30000000" }, { "M": true, - "T": 1588749137815, - "a": 284861383, - "f": 310207664, - "l": 310207664, + "T": 1577977967670, + "a": 202790383, + "f": 222825496, + "l": 222825496, "m": true, - "p": "9035.19000000", - "q": "0.06015400" + "p": "7143.57000000", + "q": "0.53704800" }, { "M": true, - "T": 1588749137826, - "a": 284861384, - "f": 310207665, - "l": 310207665, - "m": false, - "p": "9035.20000000", - "q": "0.00307900" + "T": 1577977967670, + "a": 202790384, + "f": 222825497, + "l": 222825497, + "m": true, + "p": "7143.37000000", + "q": "0.15215300" }, { "M": true, - "T": 1588749137866, - "a": 284861385, - "f": 310207666, - "l": 310207666, + "T": 1577977967670, + "a": 202790385, + "f": 222825498, + "l": 222825498, "m": true, - "p": "9035.19000000", - "q": "0.07271100" + "p": "7143.23000000", + "q": "0.06839100" }, { "M": true, - "T": 1588749137866, - "a": 284861386, - "f": 310207667, - "l": 310207667, - "m": true, - "p": "9035.10000000", - "q": "0.65861500" + "T": 1577977967894, + "a": 202790386, + "f": 222825499, + "l": 222825499, + "m": false, + "p": "7143.65000000", + "q": "0.00596100" }, { "M": true, - "T": 1588749137918, - "a": 284861387, - "f": 310207668, - "l": 310207668, + "T": 1577977968553, + "a": 202790387, + "f": 222825500, + "l": 222825500, "m": true, - "p": "9035.10000000", - "q": "0.13269900" + "p": "7144.00000000", + "q": "0.00566100" }, { "M": true, - "T": 1588749137964, - "a": 284861388, - "f": 310207669, - "l": 310207669, + "T": 1577977970345, + "a": 202790388, + "f": 222825501, + "l": 222825501, "m": false, - "p": "9035.11000000", - "q": "0.03567100" + "p": "7144.08000000", + "q": "0.14571300" }, { "M": true, - "T": 1588749138058, - "a": 284861389, - "f": 310207670, - "l": 310207670, - "m": false, - "p": "9035.11000000", - "q": "0.01597200" + "T": 1577977970571, + "a": 202790389, + "f": 222825502, + "l": 222825502, + "m": true, + "p": "7144.00000000", + "q": "0.02582900" }, { "M": true, - "T": 1588749138141, - "a": 284861390, - "f": 310207671, - "l": 310207671, + "T": 1577977971571, + "a": 202790390, + "f": 222825503, + "l": 222825503, "m": true, - "p": "9035.10000000", - "q": "0.06013100" + "p": "7144.00000000", + "q": "0.01029400" }, { "M": true, - "T": 1588749138159, - "a": 284861391, - "f": 310207672, - "l": 310207672, + "T": 1577977972251, + "a": 202790391, + "f": 222825504, + "l": 222825504, "m": false, - "p": "9035.11000000", - "q": "0.00199300" + "p": "7144.10000000", + "q": "0.00161200" }, { "M": true, - "T": 1588749138460, - "a": 284861392, - "f": 310207673, - "l": 310207673, - "m": true, - "p": "9035.10000000", - "q": "0.06002900" + "T": 1577977972992, + "a": 202790392, + "f": 222825505, + "l": 222825505, + "m": false, + "p": "7144.08000000", + "q": "0.39680700" }, { "M": true, - "T": 1588749138671, - "a": 284861393, - "f": 310207674, - "l": 310207674, + "T": 1577977976975, + "a": 202790393, + "f": 222825506, + "l": 222825506, "m": true, - "p": "9035.10000000", - "q": "0.00486200" + "p": "7144.00000000", + "q": "0.37538500" }, { "M": true, - "T": 1588749138789, - "a": 284861394, - "f": 310207675, - "l": 310207675, + "T": 1577977976975, + "a": 202790394, + "f": 222825507, + "l": 222825507, "m": true, - "p": "9035.10000000", - "q": "0.06033000" + "p": "7143.23000000", + "q": "1.13160900" }, { "M": true, - "T": 1588749139119, - "a": 284861395, - "f": 310207676, - "l": 310207676, + "T": 1577977976975, + "a": 202790395, + "f": 222825508, + "l": 222825508, "m": true, - "p": "9035.10000000", - "q": "0.06044400" + "p": "7143.16000000", + "q": "0.05005000" }, { "M": true, - "T": 1588749139347, - "a": 284861396, - "f": 310207677, - "l": 310207677, + "T": 1577977976975, + "a": 202790396, + "f": 222825509, + "l": 222825509, "m": true, - "p": "9035.10000000", - "q": "0.05000000" + "p": "7143.13000000", + "q": "0.14888200" }, { "M": true, - "T": 1588749139448, - "a": 284861397, - "f": 310207678, - "l": 310207678, + "T": 1577977976975, + "a": 202790397, + "f": 222825510, + "l": 222825510, "m": true, - "p": "9035.10000000", - "q": "0.06039900" + "p": "7143.09000000", + "q": "0.03983200" }, { "M": true, - "T": 1588749139768, - "a": 284861398, - "f": 310207679, - "l": 310207679, - "m": true, - "p": "9035.10000000", - "q": "0.06002700" + "T": 1577977977634, + "a": 202790398, + "f": 222825511, + "l": 222825511, + "m": false, + "p": "7143.96000000", + "q": "0.00655000" }, { "M": true, - "T": 1588749139812, - "a": 284861399, - "f": 310207680, - "l": 310207680, + "T": 1577977977739, + "a": 202790399, + "f": 222825512, + "l": 222825512, "m": false, - "p": "9035.11000000", - "q": "0.01196300" + "p": "7143.96000000", + "q": "0.03847100" }, { "M": true, - "T": 1588749140083, - "a": 284861400, - "f": 310207681, - "l": 310207681, - "m": true, - "p": "9035.10000000", - "q": "0.06028700" + "T": 1577977977779, + "a": 202790400, + "f": 222825513, + "l": 222825513, + "m": false, + "p": "7143.96000000", + "q": "0.00141500" }, { "M": true, - "T": 1588749140267, - "a": 284861401, - "f": 310207682, - "l": 310207682, + "T": 1577977977886, + "a": 202790401, + "f": 222825514, + "l": 222825514, "m": true, - "p": "9035.10000000", - "q": "0.01921100" + "p": "7143.08000000", + "q": "0.00280000" }, { "M": true, - "T": 1588749140273, - "a": 284861402, - "f": 310207683, - "l": 310207683, - "m": true, - "p": "9035.10000000", - "q": "0.03842800" + "T": 1577977978524, + "a": 202790402, + "f": 222825515, + "l": 222825515, + "m": false, + "p": "7143.94000000", + "q": "0.00141500" }, { "M": true, - "T": 1588749140284, - "a": 284861403, - "f": 310207684, - "l": 310207684, - "m": true, - "p": "9035.10000000", - "q": "0.74159200" + "T": 1577977979447, + "a": 202790403, + "f": 222825516, + "l": 222825516, + "m": false, + "p": "7143.94000000", + "q": "0.03181600" }, { "M": true, - "T": 1588749140370, - "a": 284861404, - "f": 310207685, - "l": 310207685, - "m": true, - "p": "9035.10000000", - "q": "0.08846900" + "T": 1577977980467, + "a": 202790404, + "f": 222825517, + "l": 222825517, + "m": false, + "p": "7143.96000000", + "q": "0.00168300" }, { "M": true, - "T": 1588749140411, - "a": 284861405, - "f": 310207686, - "l": 310207686, - "m": true, - "p": "9035.10000000", - "q": "0.06027500" + "T": 1577977981556, + "a": 202790405, + "f": 222825518, + "l": 222825518, + "m": false, + "p": "7143.49000000", + "q": "0.40246200" }, { "M": true, - "T": 1588749140434, - "a": 284861406, - "f": 310207687, - "l": 310207687, - "m": true, - "p": "9035.10000000", - "q": "0.01918600" + "T": 1577977986690, + "a": 202790406, + "f": 222825519, + "l": 222825519, + "m": false, + "p": "7143.62000000", + "q": "0.00167300" }, { "M": true, - "T": 1588749140494, - "a": 284861407, - "f": 310207688, - "l": 310207688, - "m": true, - "p": "9035.10000000", - "q": "0.00999700" + "T": 1577977986780, + "a": 202790407, + "f": 222825520, + "l": 222825520, + "m": false, + "p": "7143.58000000", + "q": "0.34997600" }, { "M": true, - "T": 1588749140495, - "a": 284861408, - "f": 310207689, - "l": 310207689, - "m": true, - "p": "9035.10000000", - "q": "0.00924500" + "T": 1577977986780, + "a": 202790408, + "f": 222825521, + "l": 222825521, + "m": false, + "p": "7143.59000000", + "q": "0.05002400" }, { "M": true, - "T": 1588749140640, - "a": 284861409, - "f": 310207690, - "l": 310207690, - "m": true, - "p": "9035.10000000", - "q": "0.63900000" + "T": 1577977987080, + "a": 202790409, + "f": 222825522, + "l": 222825522, + "m": false, + "p": "7143.62000000", + "q": "0.00833700" }, { "M": true, - "T": 1588749140733, - "a": 284861410, - "f": 310207691, - "l": 310207691, - "m": true, - "p": "9035.10000000", - "q": "0.06041400" + "T": 1577977988663, + "a": 202790410, + "f": 222825523, + "l": 222825523, + "m": false, + "p": "7143.62000000", + "q": "0.01014400" }, { "M": true, - "T": 1588749141054, - "a": 284861411, - "f": 310207692, - "l": 310207692, - "m": true, - "p": "9035.10000000", - "q": "0.06037300" + "T": 1577977989447, + "a": 202790411, + "f": 222825524, + "l": 222825524, + "m": false, + "p": "7143.62000000", + "q": "0.00380000" }, { "M": true, - "T": 1588749141138, - "a": 284861412, - "f": 310207693, - "l": 310207693, + "T": 1577977989544, + "a": 202790412, + "f": 222825525, + "l": 222825525, "m": false, - "p": "9035.11000000", - "q": "0.00128200" + "p": "7143.58000000", + "q": "0.16091000" }, { "M": true, - "T": 1588749141196, - "a": 284861413, - "f": 310207694, - "l": 310207694, + "T": 1577977989544, + "a": 202790413, + "f": 222825526, + "l": 222825526, "m": false, - "p": "9035.11000000", - "q": "0.01926700" + "p": "7143.62000000", + "q": "0.09209300" }, { "M": true, - "T": 1588749141369, - "a": 284861414, - "f": 310207695, - "l": 310207695, - "m": true, - "p": "9035.10000000", - "q": "0.06011900" + "T": 1577977989544, + "a": 202790414, + "f": 222825527, + "l": 222825527, + "m": false, + "p": "7143.66000000", + "q": "0.00262800" }, { "M": true, - "T": 1588749141404, - "a": 284861415, - "f": 310207696, - "l": 310207696, + "T": 1577977989544, + "a": 202790415, + "f": 222825528, + "l": 222825529, "m": false, - "p": "9035.11000000", - "q": "0.01926700" + "p": "7143.68000000", + "q": "0.14436900" }, { "M": true, - "T": 1588749141690, - "a": 284861416, - "f": 310207697, - "l": 310207697, + "T": 1577977990685, + "a": 202790416, + "f": 222825530, + "l": 222825530, "m": true, - "p": "9035.10000000", - "q": "0.06021000" + "p": "7143.09000000", + "q": "0.07131300" }, { "M": true, - "T": 1588749142014, - "a": 284861417, - "f": 310207698, - "l": 310207698, + "T": 1577977990685, + "a": 202790417, + "f": 222825531, + "l": 222825531, "m": true, - "p": "9035.10000000", - "q": "0.06025800" + "p": "7143.08000000", + "q": "0.06710800" }, { "M": true, - "T": 1588749142330, - "a": 284861418, - "f": 310207699, - "l": 310207699, + "T": 1577977990685, + "a": 202790418, + "f": 222825532, + "l": 222825532, "m": true, - "p": "9035.10000000", - "q": "0.06043800" + "p": "7143.04000000", + "q": "0.14746900" }, { "M": true, - "T": 1588749142382, - "a": 284861419, - "f": 310207700, - "l": 310207700, + "T": 1577977992903, + "a": 202790419, + "f": 222825533, + "l": 222825533, "m": false, - "p": "9035.11000000", - "q": "0.00297800" + "p": "7144.03000000", + "q": "0.00156900" }, { "M": true, - "T": 1588749142652, - "a": 284861420, - "f": 310207701, - "l": 310207701, + "T": 1577977994608, + "a": 202790420, + "f": 222825534, + "l": 222825534, "m": true, - "p": "9035.10000000", - "q": "0.06007700" + "p": "7143.07000000", + "q": "0.14861600" }, { "M": true, - "T": 1588749142705, - "a": 284861421, - "f": 310207702, - "l": 310207702, - "m": true, - "p": "9035.10000000", - "q": "0.10263900" + "T": 1577977994614, + "a": 202790421, + "f": 222825535, + "l": 222825535, + "m": false, + "p": "7143.59000000", + "q": "0.24300200" }, { "M": true, - "T": 1588749142917, - "a": 284861422, - "f": 310207703, - "l": 310207703, + "T": 1577977995635, + "a": 202790422, + "f": 222825536, + "l": 222825536, "m": true, - "p": "9035.10000000", - "q": "0.00251400" + "p": "7143.05000000", + "q": "0.08092500" }, { "M": true, - "T": 1588749142982, - "a": 284861423, - "f": 310207704, - "l": 310207704, + "T": 1577977997604, + "a": 202790423, + "f": 222825537, + "l": 222825537, "m": true, - "p": "9035.10000000", - "q": "0.06013900" + "p": "7143.06000000", + "q": "0.07958700" }, { "M": true, - "T": 1588749143231, - "a": 284861424, - "f": 310207705, - "l": 310207705, + "T": 1577977997678, + "a": 202790424, + "f": 222825538, + "l": 222825538, "m": true, - "p": "9035.10000000", - "q": "0.04368200" + "p": "7143.04000000", + "q": "0.11253400" }, { "M": true, - "T": 1588749143292, - "a": 284861425, - "f": 310207706, - "l": 310207706, + "T": 1577977997678, + "a": 202790425, + "f": 222825539, + "l": 222825539, "m": true, - "p": "9035.10000000", - "q": "0.06018200" + "p": "7142.85000000", + "q": "0.05592500" }, { "M": true, - "T": 1588749143412, - "a": 284861426, - "f": 310207707, - "l": 310207707, + "T": 1577977997678, + "a": 202790426, + "f": 222825540, + "l": 222825540, "m": true, - "p": "9035.10000000", - "q": "0.00128000" + "p": "7142.52000000", + "q": "0.09383000" }, { "M": true, - "T": 1588749143412, - "a": 284861427, - "f": 310207708, - "l": 310207708, + "T": 1577977997678, + "a": 202790427, + "f": 222825541, + "l": 222825541, "m": true, - "p": "9035.10000000", - "q": "0.00267100" + "p": "7142.33000000", + "q": "0.12081100" }, { "M": true, - "T": 1588749143437, - "a": 284861428, - "f": 310207709, - "l": 310207709, + "T": 1577977997678, + "a": 202790428, + "f": 222825542, + "l": 222825542, "m": true, - "p": "9035.10000000", - "q": "0.53386600" + "p": "7142.32000000", + "q": "0.19880000" }, { "M": true, - "T": 1588749143542, - "a": 284861429, - "f": 310207710, - "l": 310207710, - "m": true, - "p": "9035.10000000", - "q": "0.16380000" + "T": 1577977998209, + "a": 202790429, + "f": 222825543, + "l": 222825543, + "m": false, + "p": "7143.60000000", + "q": "0.03039800" }, { "M": true, - "T": 1588749143609, - "a": 284861430, - "f": 310207711, - "l": 310207711, - "m": true, - "p": "9035.10000000", - "q": "0.06048100" + "T": 1577977998209, + "a": 202790430, + "f": 222825544, + "l": 222825544, + "m": false, + "p": "7143.61000000", + "q": "0.14606800" }, { "M": true, - "T": 1588749143704, - "a": 284861431, - "f": 310207712, - "l": 310207715, + "T": 1577977998209, + "a": 202790431, + "f": 222825545, + "l": 222825546, "m": false, - "p": "9035.11000000", - "q": "2.80965100" + "p": "7143.78000000", + "q": "0.22353400" }, { "M": true, - "T": 1588749143936, - "a": 284861432, - "f": 310207716, - "l": 310207716, + "T": 1577977998613, + "a": 202790432, + "f": 222825547, + "l": 222825547, "m": true, - "p": "9035.10000000", - "q": "0.06012300" + "p": "7143.04000000", + "q": "0.08544900" }, { "M": true, - "T": 1588749143975, - "a": 284861433, - "f": 310207717, - "l": 310207717, - "m": false, - "p": "9035.11000000", - "q": "0.00798400" + "T": 1577977998746, + "a": 202790433, + "f": 222825548, + "l": 222825548, + "m": true, + "p": "7143.04000000", + "q": "0.00835100" }, { "M": true, - "T": 1588749143975, - "a": 284861434, - "f": 310207718, - "l": 310207718, + "T": 1577977998900, + "a": 202790434, + "f": 222825549, + "l": 222825549, "m": true, - "p": "9035.10000000", - "q": "0.04432700" + "p": "7142.37000000", + "q": "0.02799700" }, { "M": true, - "T": 1588749144145, - "a": 284861435, - "f": 310207719, - "l": 310207719, + "T": 1577977998950, + "a": 202790435, + "f": 222825550, + "l": 222825550, "m": true, - "p": "9035.10000000", - "q": "0.07603200" + "p": "7142.27000000", + "q": "0.00630100" }, { "M": true, - "T": 1588749144258, - "a": 284861436, - "f": 310207720, - "l": 310207720, - "m": true, - "p": "9035.10000000", - "q": "0.06010000" + "T": 1577977998995, + "a": 202790436, + "f": 222825551, + "l": 222825551, + "m": false, + "p": "7143.18000000", + "q": "0.15023100" }, { "M": true, - "T": 1588749144336, - "a": 284861437, - "f": 310207721, - "l": 310207721, - "m": true, - "p": "9035.10000000", - "q": "0.00221400" + "T": 1577977998995, + "a": 202790437, + "f": 222825552, + "l": 222825553, + "m": false, + "p": "7143.20000000", + "q": "0.32799700" }, { "M": true, - "T": 1588749144339, - "a": 284861438, - "f": 310207722, - "l": 310207722, - "m": true, - "p": "9035.10000000", - "q": "0.00221400" + "T": 1577977998995, + "a": 202790438, + "f": 222825554, + "l": 222825554, + "m": false, + "p": "7143.23000000", + "q": "0.36754100" }, { "M": true, - "T": 1588749144340, - "a": 284861439, - "f": 310207723, - "l": 310207723, - "m": true, - "p": "9035.10000000", - "q": "0.00221400" + "T": 1577977998995, + "a": 202790439, + "f": 222825555, + "l": 222825555, + "m": false, + "p": "7143.28000000", + "q": "0.50000000" }, { "M": true, - "T": 1588749144588, - "a": 284861440, - "f": 310207724, - "l": 310207724, - "m": true, - "p": "9035.10000000", - "q": "0.06012100" + "T": 1577977998995, + "a": 202790440, + "f": 222825556, + "l": 222825556, + "m": false, + "p": "7143.29000000", + "q": "0.25000000" }, { "M": true, - "T": 1588749144605, - "a": 284861441, - "f": 310207725, - "l": 310207725, - "m": true, - "p": "9035.10000000", - "q": "0.00465400" + "T": 1577977998995, + "a": 202790441, + "f": 222825557, + "l": 222825557, + "m": false, + "p": "7143.54000000", + "q": "1.20000000" }, { "M": true, - "T": 1588749144904, - "a": 284861442, - "f": 310207726, - "l": 310207726, - "m": true, - "p": "9035.10000000", - "q": "0.06003300" + "T": 1577977998995, + "a": 202790442, + "f": 222825558, + "l": 222825558, + "m": false, + "p": "7143.57000000", + "q": "1.20000000" }, { "M": true, - "T": 1588749145216, - "a": 284861443, - "f": 310207727, - "l": 310207727, - "m": true, - "p": "9035.10000000", - "q": "0.55800000" + "T": 1577977998995, + "a": 202790443, + "f": 222825559, + "l": 222825559, + "m": false, + "p": "7143.87000000", + "q": "1.20000000" }, { "M": true, - "T": 1588749145226, - "a": 284861444, - "f": 310207728, - "l": 310207728, - "m": true, - "p": "9035.10000000", - "q": "0.06077500" + "T": 1577977998995, + "a": 202790444, + "f": 222825560, + "l": 222825560, + "m": false, + "p": "7143.89000000", + "q": "1.20000000" }, { "M": true, - "T": 1588749145235, - "a": 284861445, - "f": 310207729, - "l": 310207729, - "m": true, - "p": "9035.10000000", - "q": "0.06264300" + "T": 1577977998995, + "a": 202790445, + "f": 222825561, + "l": 222825561, + "m": false, + "p": "7143.91000000", + "q": "0.60000000" }, { "M": true, - "T": 1588749145359, - "a": 284861446, - "f": 310207730, - "l": 310207730, - "m": true, - "p": "9035.10000000", - "q": "0.03128600" + "T": 1577977998995, + "a": 202790446, + "f": 222825562, + "l": 222825562, + "m": false, + "p": "7143.93000000", + "q": "1.20000000" }, { "M": true, - "T": 1588749145539, - "a": 284861447, - "f": 310207731, - "l": 310207731, - "m": true, - "p": "9035.10000000", - "q": "0.06000500" + "T": 1577977998995, + "a": 202790447, + "f": 222825563, + "l": 222825563, + "m": false, + "p": "7143.95000000", + "q": "0.51421600" }, { "M": true, - "T": 1588749145855, - "a": 284861448, - "f": 310207732, - "l": 310207732, - "m": true, - "p": "9035.10000000", - "q": "0.06001100" + "T": 1577977998995, + "a": 202790448, + "f": 222825564, + "l": 222825564, + "m": false, + "p": "7143.97000000", + "q": "1.20000000" }, { "M": true, - "T": 1588749145952, - "a": 284861449, - "f": 310207733, - "l": 310207733, + "T": 1577977998995, + "a": 202790449, + "f": 222825565, + "l": 222825565, "m": false, - "p": "9035.11000000", - "q": "0.33130000" + "p": "7143.98000000", + "q": "2.00000000" }, { "M": true, - "T": 1588749146184, - "a": 284861450, - "f": 310207734, - "l": 310207734, - "m": true, - "p": "9035.10000000", - "q": "0.06002900" + "T": 1577977998995, + "a": 202790450, + "f": 222825566, + "l": 222825566, + "m": false, + "p": "7144.00000000", + "q": "0.30000000" }, { "M": true, - "T": 1588749146499, - "a": 284861451, - "f": 310207735, - "l": 310207735, - "m": true, - "p": "9035.10000000", - "q": "0.06008100" + "T": 1577977998995, + "a": 202790451, + "f": 222825567, + "l": 222825569, + "m": false, + "p": "7144.08000000", + "q": "3.70000000" }, { "M": true, - "T": 1588749146823, - "a": 284861452, - "f": 310207736, - "l": 310207736, - "m": true, - "p": "9035.10000000", - "q": "0.06024000" + "T": 1577977998995, + "a": 202790452, + "f": 222825570, + "l": 222825570, + "m": false, + "p": "7144.11000000", + "q": "1.09051500" }, { "M": true, - "T": 1588749147159, - "a": 284861453, - "f": 310207737, - "l": 310207737, + "T": 1577977999013, + "a": 202790453, + "f": 222825571, + "l": 222825571, "m": true, - "p": "9035.10000000", - "q": "0.06118300" + "p": "7141.91000000", + "q": "0.02799800" }, { "M": true, - "T": 1588749147249, - "a": 284861454, - "f": 310207738, - "l": 310207738, + "T": 1577977999013, + "a": 202790454, + "f": 222825572, + "l": 222825572, "m": true, - "p": "9035.10000000", - "q": "0.03595700" + "p": "7141.90000000", + "q": "0.08748600" + }, + { + "M": true, + "T": 1577977999111, + "a": 202790455, + "f": 222825573, + "l": 222825573, + "m": false, + "p": "7143.85000000", + "q": "0.00154400" }, { "M": true, - "T": 1588749147257, - "a": 284861455, - "f": 310207739, - "l": 310207739, + "T": 1577977999116, + "a": 202790456, + "f": 222825574, + "l": 222825574, "m": true, - "p": "9035.10000000", - "q": "0.18138900" + "p": "7142.00000000", + "q": "0.00280000" }, { "M": true, - "T": 1588749147277, - "a": 284861456, - "f": 310207740, - "l": 310207740, + "T": 1577977999499, + "a": 202790457, + "f": 222825575, + "l": 222825575, "m": true, - "p": "9035.00000000", - "q": "0.05982400" + "p": "7142.05000000", + "q": "0.00280000" }, { "M": true, - "T": 1588749147349, - "a": 284861457, - "f": 310207741, - "l": 310207741, + "T": 1577978000776, + "a": 202790458, + "f": 222825576, + "l": 222825576, "m": false, - "p": "9035.01000000", - "q": "0.06466000" + "p": "7142.78000000", + "q": "0.05242900" }, { "M": true, - "T": 1588749147448, - "a": 284861458, - "f": 310207742, - "l": 310207744, + "T": 1577978000878, + "a": 202790459, + "f": 222825577, + "l": 222825577, "m": false, - "p": "9035.01000000", - "q": "2.80965500" + "p": "7142.69000000", + "q": "0.04783200" }, { "M": true, - "T": 1588749147479, - "a": 284861459, - "f": 310207745, - "l": 310207747, - "m": true, - "p": "9035.00000000", - "q": "0.06003600" + "T": 1577978000970, + "a": 202790460, + "f": 222825578, + "l": 222825578, + "m": false, + "p": "7142.59000000", + "q": "0.00490000" }, { "M": true, - "T": 1588749147487, - "a": 284861460, - "f": 310207748, - "l": 310207748, - "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "T": 1577978001086, + "a": 202790461, + "f": 222825579, + "l": 222825579, + "m": false, + "p": "7142.51000000", + "q": "0.05187000" }, { "M": true, - "T": 1588749147489, - "a": 284861461, - "f": 310207749, - "l": 310207749, - "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "T": 1577978001187, + "a": 202790462, + "f": 222825580, + "l": 222825580, + "m": false, + "p": "7142.46000000", + "q": "0.01982200" }, { "M": true, - "T": 1588749147489, - "a": 284861462, - "f": 310207750, - "l": 310207750, + "T": 1577978001218, + "a": 202790463, + "f": 222825581, + "l": 222825581, "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "p": "7142.12000000", + "q": "0.02799800" }, { "M": true, - "T": 1588749147489, - "a": 284861463, - "f": 310207751, - "l": 310207751, + "T": 1577978001356, + "a": 202790464, + "f": 222825582, + "l": 222825582, "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "p": "7140.64000000", + "q": "0.02800100" }, { "M": true, - "T": 1588749147796, - "a": 284861464, - "f": 310207752, - "l": 310207752, + "T": 1577978001356, + "a": 202790465, + "f": 222825583, + "l": 222825583, "m": true, - "p": "9035.00000000", - "q": "0.06014900" + "p": "7140.63000000", + "q": "0.01231900" }, { "M": true, - "T": 1588749147968, - "a": 284861465, - "f": 310207753, - "l": 310207753, + "T": 1577978001818, + "a": 202790466, + "f": 222825584, + "l": 222825584, "m": true, - "p": "9035.00000000", - "q": "0.04173300" + "p": "7141.89000000", + "q": "0.22148200" }, { "M": true, - "T": 1588749148119, - "a": 284861466, - "f": 310207754, - "l": 310207755, - "m": true, - "p": "9035.00000000", - "q": "0.06035800" + "T": 1577978002129, + "a": 202790467, + "f": 222825585, + "l": 222825585, + "m": false, + "p": "7142.38000000", + "q": "0.06800000" }, { "M": true, - "T": 1588749148151, - "a": 284861467, - "f": 310207756, - "l": 310207756, + "T": 1577978002251, + "a": 202790468, + "f": 222825586, + "l": 222825586, "m": false, - "p": "9035.01000000", - "q": "0.01875800" + "p": "7142.37000000", + "q": "0.00413800" }, { "M": true, - "T": 1588749148251, - "a": 284861468, - "f": 310207757, - "l": 310207757, - "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "T": 1577978003999, + "a": 202790469, + "f": 222825587, + "l": 222825587, + "m": false, + "p": "7142.37000000", + "q": "0.00182500" }, { "M": true, - "T": 1588749148255, - "a": 284861469, - "f": 310207758, - "l": 310207758, - "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "T": 1577978004095, + "a": 202790470, + "f": 222825588, + "l": 222825588, + "m": false, + "p": "7142.37000000", + "q": "0.00800000" }, { "M": true, - "T": 1588749148255, - "a": 284861470, - "f": 310207759, - "l": 310207759, + "T": 1577978004415, + "a": 202790471, + "f": 222825589, + "l": 222825589, "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "p": "7140.97000000", + "q": "0.00200200" + }, + { + "M": true, + "T": 1577978005335, + "a": 202790472, + "f": 222825590, + "l": 222825590, + "m": false, + "p": "7142.33000000", + "q": "0.00155300" }, { "M": true, - "T": 1588749148274, - "a": 284861471, - "f": 310207760, - "l": 310207762, + "T": 1577978005967, + "a": 202790473, + "f": 222825591, + "l": 222825591, "m": true, - "p": "9035.00000000", - "q": "0.06200000" + "p": "7140.97000000", + "q": "0.02596400" }, { "M": true, - "T": 1588749148279, - "a": 284861472, - "f": 310207763, - "l": 310207763, + "T": 1577978006072, + "a": 202790474, + "f": 222825592, + "l": 222825592, "m": true, - "p": "9035.00000000", - "q": "0.33300000" + "p": "7140.97000000", + "q": "0.00003500" }, { "M": true, - "T": 1588749148326, - "a": 284861473, - "f": 310207764, - "l": 310207764, + "T": 1577978006072, + "a": 202790475, + "f": 222825593, + "l": 222825593, "m": true, - "p": "9035.00000000", - "q": "0.00213400" + "p": "7140.96000000", + "q": "0.04028500" }, { "M": true, - "T": 1588749148353, - "a": 284861474, - "f": 310207765, - "l": 310207765, + "T": 1577978006267, + "a": 202790476, + "f": 222825594, + "l": 222825594, "m": true, - "p": "9035.00000000", - "q": "0.04511600" + "p": "7140.96000000", + "q": "0.05895100" }, { "M": true, - "T": 1588749148430, - "a": 284861475, - "f": 310207766, - "l": 310207766, + "T": 1577978006498, + "a": 202790477, + "f": 222825595, + "l": 222825595, "m": true, - "p": "9035.00000000", - "q": "0.06017200" + "p": "7140.96000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749148594, - "a": 284861476, - "f": 310207767, - "l": 310207767, + "T": 1577978006670, + "a": 202790478, + "f": 222825596, + "l": 222825596, "m": false, - "p": "9035.01000000", - "q": "0.01932600" + "p": "7141.85000000", + "q": "0.03913000" }, { "M": true, - "T": 1588749148741, - "a": 284861477, - "f": 310207768, - "l": 310207768, + "T": 1577978006912, + "a": 202790479, + "f": 222825597, + "l": 222825597, "m": true, - "p": "9035.00000000", - "q": "0.06009800" + "p": "7140.96000000", + "q": "0.01692100" }, { "M": true, - "T": 1588749148888, - "a": 284861478, - "f": 310207769, - "l": 310207769, - "m": false, - "p": "9035.01000000", - "q": "0.00140000" + "T": 1577978006912, + "a": 202790480, + "f": 222825598, + "l": 222825598, + "m": true, + "p": "7140.93000000", + "q": "0.02339900" }, { "M": true, - "T": 1588749149056, - "a": 284861479, - "f": 310207770, - "l": 310207770, + "T": 1577978007384, + "a": 202790481, + "f": 222825599, + "l": 222825599, "m": true, - "p": "9035.00000000", - "q": "0.06046200" + "p": "7140.94000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749149383, - "a": 284861480, - "f": 310207771, - "l": 310207771, + "T": 1577978007527, + "a": 202790482, + "f": 222825600, + "l": 222825600, "m": true, - "p": "9035.00000000", - "q": "0.06052800" + "p": "7140.94000000", + "q": "0.05756900" }, { "M": true, - "T": 1588749149705, - "a": 284861481, - "f": 310207772, - "l": 310207772, + "T": 1577978007645, + "a": 202790483, + "f": 222825601, + "l": 222825601, "m": true, - "p": "9035.00000000", - "q": "0.06036600" + "p": "7140.94000000", + "q": "0.01151400" }, { "M": true, - "T": 1588749149784, - "a": 284861482, - "f": 310207773, - "l": 310207773, + "T": 1577978007739, + "a": 202790484, + "f": 222825602, + "l": 222825602, "m": true, - "p": "9035.00000000", - "q": "0.01834700" + "p": "7140.94000000", + "q": "0.02400600" }, { "M": true, - "T": 1588749150018, - "a": 284861483, - "f": 310207774, - "l": 310207774, + "T": 1577978008168, + "a": 202790485, + "f": 222825603, + "l": 222825603, "m": true, - "p": "9035.00000000", - "q": "0.06009600" + "p": "7140.95000000", + "q": "0.00236000" }, { "M": true, - "T": 1588749150227, - "a": 284861484, - "f": 310207775, - "l": 310207775, - "m": true, - "p": "9035.00000000", - "q": "0.31000000" + "T": 1577978008806, + "a": 202790486, + "f": 222825604, + "l": 222825604, + "m": false, + "p": "7141.82000000", + "q": "0.00629000" }, { "M": true, - "T": 1588749150342, - "a": 284861485, - "f": 310207776, - "l": 310207776, - "m": true, - "p": "9035.00000000", - "q": "0.06024300" + "T": 1577978013109, + "a": 202790487, + "f": 222825605, + "l": 222825605, + "m": false, + "p": "7141.73000000", + "q": "0.00530000" }, { "M": true, - "T": 1588749150488, - "a": 284861486, - "f": 310207777, - "l": 310207777, + "T": 1577978013213, + "a": 202790488, + "f": 222825606, + "l": 222825606, "m": false, - "p": "9035.01000000", - "q": "0.00565300" + "p": "7141.73000000", + "q": "0.10395300" }, { "M": true, - "T": 1588749150664, - "a": 284861487, - "f": 310207778, - "l": 310207778, + "T": 1577978013258, + "a": 202790489, + "f": 222825607, + "l": 222825607, "m": true, - "p": "9035.00000000", - "q": "0.06012800" + "p": "7140.84000000", + "q": "0.06672400" }, { "M": true, - "T": 1588749150984, - "a": 284861488, - "f": 310207779, - "l": 310207779, - "m": true, - "p": "9035.00000000", - "q": "0.06086100" + "T": 1577978013310, + "a": 202790490, + "f": 222825608, + "l": 222825608, + "m": false, + "p": "7141.75000000", + "q": "0.03264900" }, { "M": true, - "T": 1588749151306, - "a": 284861489, - "f": 310207780, - "l": 310207780, + "T": 1577978013430, + "a": 202790491, + "f": 222825609, + "l": 222825609, "m": false, - "p": "9035.01000000", - "q": "0.02213400" + "p": "7141.77000000", + "q": "0.01403500" }, { "M": true, - "T": 1588749151320, - "a": 284861490, - "f": 310207781, - "l": 310207781, - "m": true, - "p": "9035.00000000", - "q": "0.06064400" + "T": 1577978013551, + "a": 202790492, + "f": 222825610, + "l": 222825610, + "m": false, + "p": "7142.31000000", + "q": "0.00159600" }, { "M": true, - "T": 1588749151570, - "a": 284861491, - "f": 310207782, - "l": 310207782, + "T": 1577978014093, + "a": 202790493, + "f": 222825611, + "l": 222825611, "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749151570, - "a": 284861492, - "f": 310207783, - "l": 310207783, + "T": 1577978014094, + "a": 202790494, + "f": 222825612, + "l": 222825612, "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749151571, - "a": 284861493, - "f": 310207784, - "l": 310207784, + "T": 1577978014094, + "a": 202790495, + "f": 222825613, + "l": 222825613, "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749151574, - "a": 284861494, - "f": 310207785, - "l": 310207785, + "T": 1577978014094, + "a": 202790496, + "f": 222825614, + "l": 222825614, "m": true, - "p": "9035.00000000", - "q": "0.00221400" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749151646, - "a": 284861495, - "f": 310207786, - "l": 310207786, + "T": 1577978014094, + "a": 202790497, + "f": 222825615, + "l": 222825615, "m": true, - "p": "9035.00000000", - "q": "0.06016600" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749151968, - "a": 284861496, - "f": 310207787, - "l": 310207787, + "T": 1577978014094, + "a": 202790498, + "f": 222825616, + "l": 222825616, "m": true, - "p": "9035.00000000", - "q": "0.06071900" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152071, - "a": 284861497, - "f": 310207788, - "l": 310207788, + "T": 1577978014094, + "a": 202790499, + "f": 222825617, + "l": 222825617, "m": true, - "p": "9035.00000000", - "q": "0.11058600" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152298, - "a": 284861498, - "f": 310207789, - "l": 310207789, + "T": 1577978014095, + "a": 202790500, + "f": 222825618, + "l": 222825618, "m": true, - "p": "9035.00000000", - "q": "2.30900000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152299, - "a": 284861499, - "f": 310207790, - "l": 310207790, + "T": 1577978014096, + "a": 202790501, + "f": 222825619, + "l": 222825619, "m": true, - "p": "9035.00000000", - "q": "0.06019600" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152312, - "a": 284861500, - "f": 310207791, - "l": 310207791, + "T": 1577978014097, + "a": 202790502, + "f": 222825620, + "l": 222825621, "m": true, - "p": "9035.00000000", - "q": "0.36720500" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152316, - "a": 284861501, - "f": 310207792, - "l": 310207792, + "T": 1577978014097, + "a": 202790503, + "f": 222825622, + "l": 222825622, "m": true, - "p": "9035.00000000", - "q": "5.66050000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152316, - "a": 284861502, - "f": 310207793, - "l": 310207793, + "T": 1577978014103, + "a": 202790504, + "f": 222825623, + "l": 222825623, "m": true, - "p": "9034.78000000", - "q": "0.00300000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861503, - "f": 310207794, - "l": 310207794, + "T": 1577978014104, + "a": 202790505, + "f": 222825624, + "l": 222825624, "m": true, - "p": "9034.69000000", - "q": "0.00113500" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861504, - "f": 310207795, - "l": 310207795, + "T": 1577978014104, + "a": 202790506, + "f": 222825625, + "l": 222825625, "m": true, - "p": "9034.52000000", - "q": "0.00833700" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861505, - "f": 310207796, - "l": 310207796, + "T": 1577978014104, + "a": 202790507, + "f": 222825626, + "l": 222825626, "m": true, - "p": "9034.14000000", - "q": "0.03320700" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861506, - "f": 310207797, - "l": 310207797, + "T": 1577978014104, + "a": 202790508, + "f": 222825627, + "l": 222825627, "m": true, - "p": "9034.11000000", - "q": "0.00332400" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861507, - "f": 310207798, - "l": 310207798, + "T": 1577978014105, + "a": 202790509, + "f": 222825628, + "l": 222825628, "m": true, - "p": "9034.00000000", - "q": "0.01500000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861508, - "f": 310207799, - "l": 310207799, + "T": 1577978014105, + "a": 202790510, + "f": 222825629, + "l": 222825629, "m": true, - "p": "9033.76000000", - "q": "0.00300000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861509, - "f": 310207800, - "l": 310207800, + "T": 1577978014105, + "a": 202790511, + "f": 222825630, + "l": 222825630, "m": true, - "p": "9033.26000000", - "q": "0.00608900" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861510, - "f": 310207801, - "l": 310207801, + "T": 1577978014106, + "a": 202790512, + "f": 222825631, + "l": 222825631, "m": true, - "p": "9033.00000000", - "q": "0.07749300" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861511, - "f": 310207802, - "l": 310207803, + "T": 1577978014106, + "a": 202790513, + "f": 222825632, + "l": 222825632, "m": true, - "p": "9032.75000000", - "q": "0.30300000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861512, - "f": 310207804, - "l": 310207804, + "T": 1577978014107, + "a": 202790514, + "f": 222825633, + "l": 222825633, "m": true, - "p": "9032.65000000", - "q": "0.00300000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152348, - "a": 284861513, - "f": 310207805, - "l": 310207805, + "T": 1577978014108, + "a": 202790515, + "f": 222825634, + "l": 222825634, "m": true, - "p": "9032.39000000", - "q": "0.24641500" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152361, - "a": 284861514, - "f": 310207806, - "l": 310207806, + "T": 1577978014108, + "a": 202790516, + "f": 222825635, + "l": 222825635, "m": true, - "p": "9032.14000000", - "q": "0.12403000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152361, - "a": 284861515, - "f": 310207807, - "l": 310207808, + "T": 1577978014108, + "a": 202790517, + "f": 222825636, + "l": 222825636, "m": true, - "p": "9032.08000000", - "q": "0.15503500" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152361, - "a": 284861516, - "f": 310207809, - "l": 310207809, + "T": 1577978014108, + "a": 202790518, + "f": 222825637, + "l": 222825637, "m": true, - "p": "9032.00000000", - "q": "0.11071700" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152361, - "a": 284861517, - "f": 310207810, - "l": 310207810, + "T": 1577978014108, + "a": 202790519, + "f": 222825638, + "l": 222825638, "m": true, - "p": "9031.73000000", - "q": "0.00300000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152361, - "a": 284861518, - "f": 310207811, - "l": 310207811, + "T": 1577978014109, + "a": 202790520, + "f": 222825639, + "l": 222825639, "m": true, - "p": "9031.48000000", - "q": "0.08000000" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152361, - "a": 284861519, - "f": 310207812, - "l": 310207812, + "T": 1577978014109, + "a": 202790521, + "f": 222825640, + "l": 222825640, "m": true, - "p": "9031.36000000", - "q": "0.12721800" + "p": "7141.03000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152372, - "a": 284861520, - "f": 310207813, - "l": 310207813, + "T": 1577978014124, + "a": 202790522, + "f": 222825641, + "l": 222825641, "m": true, - "p": "9032.40000000", - "q": "0.02000000" + "p": "7141.07000000", + "q": "0.00501100" }, { "M": true, - "T": 1588749152376, - "a": 284861521, - "f": 310207814, - "l": 310207814, + "T": 1577978014145, + "a": 202790523, + "f": 222825642, + "l": 222825642, "m": true, - "p": "9032.40000000", - "q": "0.03832400" + "p": "7141.07000000", + "q": "0.34505200" }, { "M": true, - "T": 1588749152376, - "a": 284861522, - "f": 310207815, - "l": 310207815, + "T": 1577978014145, + "a": 202790524, + "f": 222825643, + "l": 222825643, "m": true, - "p": "9031.49000000", - "q": "0.08004200" + "p": "7141.06000000", + "q": "0.35006300" }, { "M": true, - "T": 1588749152376, - "a": 284861523, - "f": 310207816, - "l": 310207816, + "T": 1577978014145, + "a": 202790525, + "f": 222825644, + "l": 222825644, "m": true, - "p": "9031.41000000", - "q": "0.58163400" + "p": "7141.03000000", + "q": "0.02800200" }, { "M": true, - "T": 1588749152376, - "a": 284861524, - "f": 310207817, - "l": 310207817, + "T": 1577978014196, + "a": 202790526, + "f": 222825645, + "l": 222825645, "m": true, - "p": "9031.41000000", - "q": "0.66036600" + "p": "7141.08000000", + "q": "0.00182500" }, { "M": true, - "T": 1588749152376, - "a": 284861525, - "f": 310207818, - "l": 310207818, + "T": 1577978014243, + "a": 202790527, + "f": 222825646, + "l": 222825646, "m": true, - "p": "9031.36000000", - "q": "0.08963400" + "p": "7141.09000000", + "q": "0.00600700" }, { "M": true, - "T": 1588749152378, - "a": 284861526, - "f": 310207819, - "l": 310207819, + "T": 1577978014264, + "a": 202790528, + "f": 222825647, + "l": 222825647, "m": true, - "p": "9031.36000000", - "q": "0.02000000" + "p": "7141.09000000", + "q": "0.00294000" }, { "M": true, - "T": 1588749152394, - "a": 284861527, - "f": 310207820, - "l": 310207820, + "T": 1577978014492, + "a": 202790529, + "f": 222825648, + "l": 222825648, "m": true, - "p": "9031.50000000", - "q": "0.26500000" + "p": "7141.09000000", + "q": "0.00400000" }, { "M": true, - "T": 1588749152394, - "a": 284861528, - "f": 310207821, - "l": 310207821, + "T": 1577978014628, + "a": 202790530, + "f": 222825649, + "l": 222825649, "m": true, - "p": "9031.42000000", - "q": "0.01100000" + "p": "7140.90000000", + "q": "0.05440000" }, { "M": true, - "T": 1588749152406, - "a": 284861529, - "f": 310207822, - "l": 310207822, - "m": true, - "p": "9033.34000000", - "q": "0.00719200" + "T": 1577978014654, + "a": 202790531, + "f": 222825650, + "l": 222825650, + "m": false, + "p": "7141.46000000", + "q": "0.17741700" }, { "M": true, - "T": 1588749152406, - "a": 284861530, - "f": 310207823, - "l": 310207823, - "m": true, - "p": "9031.42000000", - "q": "0.04732400" + "T": 1577978014688, + "a": 202790532, + "f": 222825651, + "l": 222825651, + "m": false, + "p": "7141.42000000", + "q": "0.14936300" }, { "M": true, - "T": 1588749152406, - "a": 284861531, - "f": 310207824, - "l": 310207825, - "m": true, - "p": "9031.23000000", - "q": "0.25529300" + "T": 1577978014718, + "a": 202790533, + "f": 222825652, + "l": 222825652, + "m": false, + "p": "7141.42000000", + "q": "0.20071900" }, { "M": true, - "T": 1588749152406, - "a": 284861532, - "f": 310207826, - "l": 310207826, - "m": true, - "p": "9031.22000000", - "q": "0.00551900" + "T": 1577978014718, + "a": 202790534, + "f": 222825653, + "l": 222825653, + "m": false, + "p": "7141.43000000", + "q": "0.19928100" }, { "M": true, - "T": 1588749152406, - "a": 284861533, - "f": 310207827, - "l": 310207827, + "T": 1577978016096, + "a": 202790535, + "f": 222825654, + "l": 222825654, "m": true, - "p": "9031.15000000", - "q": "0.04530000" + "p": "7140.94000000", + "q": "0.00220000" }, { "M": true, - "T": 1588749152406, - "a": 284861534, - "f": 310207828, - "l": 310207828, + "T": 1577978016145, + "a": 202790536, + "f": 222825655, + "l": 222825655, "m": true, - "p": "9031.10000000", - "q": "0.00282500" + "p": "7140.90000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749152406, - "a": 284861535, - "f": 310207829, - "l": 310207829, + "T": 1577978016185, + "a": 202790537, + "f": 222825656, + "l": 222825656, "m": true, - "p": "9031.00000000", - "q": "0.01500000" + "p": "7140.90000000", + "q": "0.02800000" }, { "M": true, - "T": 1588749152406, - "a": 284861536, - "f": 310207830, - "l": 310207830, + "T": 1577978017618, + "a": 202790538, + "f": 222825657, + "l": 222825657, "m": true, - "p": "9030.97000000", - "q": "0.05454700" + "p": "7140.91000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749152411, - "a": 284861537, - "f": 310207831, - "l": 310207831, + "T": 1577978018076, + "a": 202790539, + "f": 222825658, + "l": 222825658, "m": true, - "p": "9030.97000000", - "q": "0.04483200" + "p": "7140.91000000", + "q": "0.00224700" }, { "M": true, - "T": 1588749152411, - "a": 284861538, - "f": 310207832, - "l": 310207832, + "T": 1577978018076, + "a": 202790540, + "f": 222825659, + "l": 222825659, "m": true, - "p": "9030.78000000", - "q": "0.00110800" + "p": "7140.90000000", + "q": "0.03807300" }, { "M": true, - "T": 1588749152411, - "a": 284861539, - "f": 310207833, - "l": 310207833, + "T": 1577978018475, + "a": 202790541, + "f": 222825660, + "l": 222825660, "m": true, - "p": "9030.72000000", - "q": "0.00300000" + "p": "7140.90000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749152411, - "a": 284861540, - "f": 310207834, - "l": 310207834, - "m": true, - "p": "9030.50000000", - "q": "0.60106000" + "T": 1577978018742, + "a": 202790542, + "f": 222825661, + "l": 222825661, + "m": false, + "p": "7141.50000000", + "q": "0.16495300" }, { "M": true, - "T": 1588749152430, - "a": 284861541, - "f": 310207835, - "l": 310207835, - "m": true, - "p": "9031.55000000", - "q": "0.01000000" + "T": 1577978018912, + "a": 202790543, + "f": 222825662, + "l": 222825662, + "m": false, + "p": "7141.90000000", + "q": "0.01007900" }, { "M": true, - "T": 1588749152460, - "a": 284861542, - "f": 310207836, - "l": 310207836, - "m": true, - "p": "9030.47000000", - "q": "0.08000000" + "T": 1577978019286, + "a": 202790544, + "f": 222825663, + "l": 222825663, + "m": false, + "p": "7141.90000000", + "q": "0.00146300" }, { "M": true, - "T": 1588749152460, - "a": 284861543, - "f": 310207837, - "l": 310207837, - "m": true, - "p": "9030.33000000", - "q": "0.03841200" + "T": 1577978019492, + "a": 202790545, + "f": 222825664, + "l": 222825664, + "m": false, + "p": "7141.90000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749152460, - "a": 284861544, - "f": 310207838, - "l": 310207838, - "m": true, - "p": "9030.24000000", - "q": "0.00490000" + "T": 1577978019770, + "a": 202790546, + "f": 222825665, + "l": 222825665, + "m": false, + "p": "7141.86000000", + "q": "0.00162300" }, { "M": true, - "T": 1588749152460, - "a": 284861545, - "f": 310207839, - "l": 310207839, - "m": true, - "p": "9030.18000000", - "q": "0.00567700" + "T": 1577978021842, + "a": 202790547, + "f": 222825666, + "l": 222825666, + "m": false, + "p": "7141.05000000", + "q": "0.11440600" }, { "M": true, - "T": 1588749152460, - "a": 284861546, - "f": 310207840, - "l": 310207840, - "m": true, - "p": "9030.17000000", - "q": "0.10000000" + "T": 1577978021927, + "a": 202790548, + "f": 222825667, + "l": 222825667, + "m": false, + "p": "7141.83000000", + "q": "0.15603300" }, { "M": true, - "T": 1588749152460, - "a": 284861547, - "f": 310207841, - "l": 310207841, - "m": true, - "p": "9030.16000000", - "q": "0.06201100" + "T": 1577978021927, + "a": 202790549, + "f": 222825668, + "l": 222825668, + "m": false, + "p": "7141.84000000", + "q": "0.13471900" }, { "M": true, - "T": 1588749152463, - "a": 284861548, - "f": 310207842, - "l": 310207842, - "m": true, - "p": "9030.58000000", - "q": "0.02930800" + "T": 1577978021927, + "a": 202790550, + "f": 222825669, + "l": 222825669, + "m": false, + "p": "7141.87000000", + "q": "0.10924800" }, { "M": true, - "T": 1588749152463, - "a": 284861549, - "f": 310207843, - "l": 310207843, + "T": 1577978024293, + "a": 202790551, + "f": 222825670, + "l": 222825670, "m": true, - "p": "9030.18000000", - "q": "0.05542000" + "p": "7140.78000000", + "q": "0.10500000" }, { "M": true, - "T": 1588749152463, - "a": 284861550, - "f": 310207844, - "l": 310207844, - "m": true, - "p": "9030.16000000", - "q": "0.04868700" + "T": 1577978024849, + "a": 202790552, + "f": 222825671, + "l": 222825671, + "m": false, + "p": "7141.84000000", + "q": "0.01677400" }, { "M": true, - "T": 1588749152463, - "a": 284861551, - "f": 310207845, - "l": 310207845, - "m": true, - "p": "9030.14000000", - "q": "0.02486800" + "T": 1577978025993, + "a": 202790553, + "f": 222825672, + "l": 222825672, + "m": false, + "p": "7141.86000000", + "q": "0.00162700" }, { "M": true, - "T": 1588749152463, - "a": 284861552, - "f": 310207846, - "l": 310207846, - "m": true, - "p": "9030.10000000", - "q": "0.00300000" + "T": 1577978026308, + "a": 202790554, + "f": 222825673, + "l": 222825673, + "m": false, + "p": "7141.86000000", + "q": "0.00154000" }, { "M": true, - "T": 1588749152463, - "a": 284861553, - "f": 310207847, - "l": 310207851, - "m": true, - "p": "9030.00000000", - "q": "0.12971700" + "T": 1577978027730, + "a": 202790555, + "f": 222825674, + "l": 222825674, + "m": false, + "p": "7141.56000000", + "q": "0.23680200" }, { "M": true, - "T": 1588749152477, - "a": 284861554, - "f": 310207852, - "l": 310207852, + "T": 1577978027738, + "a": 202790556, + "f": 222825675, + "l": 222825675, "m": true, - "p": "9030.21000000", - "q": "0.04000000" + "p": "7140.80000000", + "q": "0.12132600" }, { "M": true, - "T": 1588749152478, - "a": 284861555, - "f": 310207853, - "l": 310207853, - "m": true, - "p": "9030.21000000", - "q": "0.07079300" + "T": 1577978027933, + "a": 202790557, + "f": 222825676, + "l": 222825676, + "m": false, + "p": "7141.71000000", + "q": "0.10500000" }, { "M": true, - "T": 1588749152478, - "a": 284861556, - "f": 310207854, - "l": 310207854, - "m": true, - "p": "9030.05000000", - "q": "0.15058100" + "T": 1577978027952, + "a": 202790558, + "f": 222825677, + "l": 222825677, + "m": false, + "p": "7141.71000000", + "q": "0.02479500" }, { "M": true, - "T": 1588749152487, - "a": 284861557, - "f": 310207855, - "l": 310207855, - "m": true, - "p": "9030.00000000", - "q": "0.00221400" + "T": 1577978028109, + "a": 202790559, + "f": 222825678, + "l": 222825678, + "m": false, + "p": "7141.71000000", + "q": "0.01399800" }, { "M": true, - "T": 1588749152491, - "a": 284861558, - "f": 310207856, - "l": 310207856, + "T": 1577978030849, + "a": 202790560, + "f": 222825679, + "l": 222825679, "m": true, - "p": "9030.51000000", - "q": "0.00221400" + "p": "7141.61000000", + "q": "0.12850400" }, { "M": true, - "T": 1588749152491, - "a": 284861559, - "f": 310207857, - "l": 310207857, - "m": true, - "p": "9030.51000000", - "q": "0.00221400" + "T": 1577978032220, + "a": 202790561, + "f": 222825680, + "l": 222825680, + "m": false, + "p": "7141.86000000", + "q": "0.00163500" }, { "M": true, - "T": 1588749152492, - "a": 284861560, - "f": 310207858, - "l": 310207858, + "T": 1577978032902, + "a": 202790562, + "f": 222825681, + "l": 222825681, "m": true, - "p": "9030.51000000", - "q": "0.00221400" + "p": "7141.41000000", + "q": "0.05758000" }, { "M": true, - "T": 1588749152492, - "a": 284861561, - "f": 310207859, - "l": 310207859, + "T": 1577978033005, + "a": 202790563, + "f": 222825682, + "l": 222825682, "m": true, - "p": "9030.51000000", - "q": "0.11522200" + "p": "7141.46000000", + "q": "0.01151600" }, { "M": true, - "T": 1588749152492, - "a": 284861562, - "f": 310207860, - "l": 310207860, + "T": 1577978033187, + "a": 202790564, + "f": 222825683, + "l": 222825683, "m": true, - "p": "9030.07000000", - "q": "0.30430200" + "p": "7141.46000000", + "q": "0.06909500" }, { "M": true, - "T": 1588749152507, - "a": 284861563, - "f": 310207861, - "l": 310207861, - "m": true, - "p": "9031.77000000", - "q": "0.00887200" + "T": 1577978033224, + "a": 202790565, + "f": 222825684, + "l": 222825684, + "m": false, + "p": "7141.86000000", + "q": "0.00290000" }, { "M": true, - "T": 1588749152507, - "a": 284861564, - "f": 310207862, - "l": 310207862, + "T": 1577978033405, + "a": 202790566, + "f": 222825685, + "l": 222825685, "m": true, - "p": "9030.09000000", - "q": "0.00112800" + "p": "7141.53000000", + "q": "0.02919200" }, { "M": true, - "T": 1588749152595, - "a": 284861565, - "f": 310207863, - "l": 310207863, - "m": true, - "p": "9030.09000000", - "q": "0.07758000" + "T": 1577978034250, + "a": 202790567, + "f": 222825686, + "l": 222825686, + "m": false, + "p": "7141.64000000", + "q": "0.22623200" }, { "M": true, - "T": 1588749152595, - "a": 284861566, - "f": 310207864, - "l": 310207864, + "T": 1577978034467, + "a": 202790568, + "f": 222825687, + "l": 222825687, "m": true, - "p": "9030.01000000", - "q": "0.04576400" + "p": "7141.54000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749152595, - "a": 284861567, - "f": 310207865, - "l": 310207865, - "m": true, - "p": "9030.00000000", - "q": "0.26373000" + "T": 1577978034705, + "a": 202790569, + "f": 222825688, + "l": 222825688, + "m": false, + "p": "7141.86000000", + "q": "0.00171700" }, { "M": true, - "T": 1588749152615, - "a": 284861568, - "f": 310207866, - "l": 310207866, + "T": 1577978034738, + "a": 202790570, + "f": 222825689, + "l": 222825689, "m": true, - "p": "9030.10000000", - "q": "0.06007100" + "p": "7141.58000000", + "q": "0.00469100" }, { "M": true, - "T": 1588749152645, - "a": 284861569, - "f": 310207867, - "l": 310207867, + "T": 1577978034812, + "a": 202790571, + "f": 222825690, + "l": 222825690, "m": true, - "p": "9030.10000000", - "q": "0.21684600" + "p": "7141.59000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749152645, - "a": 284861570, - "f": 310207868, - "l": 310207868, - "m": true, - "p": "9030.00000000", - "q": "0.22550000" + "T": 1577978035887, + "a": 202790572, + "f": 222825691, + "l": 222825691, + "m": false, + "p": "7141.86000000", + "q": "0.04737300" }, { "M": true, - "T": 1588749152657, - "a": 284861571, - "f": 310207869, - "l": 310207869, - "m": true, - "p": "9030.48000000", - "q": "0.03322100" + "T": 1577978036266, + "a": 202790573, + "f": 222825692, + "l": 222825692, + "m": false, + "p": "7141.86000000", + "q": "0.00947600" }, { "M": true, - "T": 1588749152657, - "a": 284861572, - "f": 310207870, - "l": 310207870, - "m": true, - "p": "9030.00000000", - "q": "0.17690500" + "T": 1577978036316, + "a": 202790574, + "f": 222825693, + "l": 222825693, + "m": false, + "p": "7141.86000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749152700, - "a": 284861573, - "f": 310207871, - "l": 310207871, + "T": 1577978036506, + "a": 202790575, + "f": 222825694, + "l": 222825694, "m": true, - "p": "9030.00000000", - "q": "0.01106000" + "p": "7141.69000000", + "q": "0.03990100" }, { "M": true, - "T": 1588749152704, - "a": 284861574, - "f": 310207872, - "l": 310207872, + "T": 1577978036835, + "a": 202790576, + "f": 222825695, + "l": 222825695, "m": true, - "p": "9030.01000000", - "q": "0.34283700" + "p": "7141.57000000", + "q": "0.01767700" }, { "M": true, - "T": 1588749152822, - "a": 284861575, - "f": 310207873, - "l": 310207873, + "T": 1577978037561, + "a": 202790577, + "f": 222825696, + "l": 222825696, "m": true, - "p": "9030.15000000", - "q": "0.00646400" + "p": "7141.57000000", + "q": "0.00414500" }, { "M": true, - "T": 1588749152822, - "a": 284861576, - "f": 310207874, - "l": 310207874, - "m": true, - "p": "9030.04000000", - "q": "0.10377700" + "T": 1577978037746, + "a": 202790578, + "f": 222825697, + "l": 222825697, + "m": false, + "p": "7141.86000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749152940, - "a": 284861577, - "f": 310207875, - "l": 310207875, - "m": true, - "p": "9030.00000000", - "q": "0.06042800" + "T": 1577978038425, + "a": 202790579, + "f": 222825698, + "l": 222825698, + "m": false, + "p": "7141.86000000", + "q": "0.00166500" }, { "M": true, - "T": 1588749152944, - "a": 284861578, - "f": 310207876, - "l": 310207876, - "m": false, - "p": "9030.71000000", - "q": "0.01000000" + "T": 1577978041128, + "a": 202790580, + "f": 222825699, + "l": 222825699, + "m": true, + "p": "7141.58000000", + "q": "0.11484900" }, { "M": true, - "T": 1588749152944, - "a": 284861579, - "f": 310207877, - "l": 310207877, + "T": 1577978041133, + "a": 202790581, + "f": 222825700, + "l": 222825700, "m": false, - "p": "9031.06000000", - "q": "0.04309900" + "p": "7141.69000000", + "q": "0.11991400" }, { "M": true, - "T": 1588749153067, - "a": 284861580, - "f": 310207878, - "l": 310207878, + "T": 1577978042032, + "a": 202790582, + "f": 222825701, + "l": 222825701, "m": true, - "p": "9030.00000000", - "q": "1.75824600" + "p": "7141.31000000", + "q": "0.00305700" }, { "M": true, - "T": 1588749153183, - "a": 284861581, - "f": 310207879, - "l": 310207879, + "T": 1577978043232, + "a": 202790583, + "f": 222825702, + "l": 222825702, "m": false, - "p": "9030.65000000", - "q": "0.00883000" + "p": "7141.84000000", + "q": "0.14465800" }, { "M": true, - "T": 1588749153233, - "a": 284861582, - "f": 310207880, - "l": 310207880, + "T": 1577978044070, + "a": 202790584, + "f": 222825703, + "l": 222825703, "m": true, - "p": "9030.00000000", - "q": "4.11348600" + "p": "7141.42000000", + "q": "0.05141900" }, { "M": true, - "T": 1588749153268, - "a": 284861583, - "f": 310207881, - "l": 310207881, + "T": 1577978044402, + "a": 202790585, + "f": 222825704, + "l": 222825704, "m": true, - "p": "9030.00000000", - "q": "0.06025200" + "p": "7141.49000000", + "q": "0.00754300" }, { "M": true, - "T": 1588749153370, - "a": 284861584, - "f": 310207882, - "l": 310207882, + "T": 1577978046175, + "a": 202790586, + "f": 222825705, + "l": 222825705, "m": false, - "p": "9030.56000000", - "q": "0.03764900" + "p": "7141.83000000", + "q": "0.06149700" }, { "M": true, - "T": 1588749153464, - "a": 284861585, - "f": 310207883, - "l": 310207883, - "m": true, - "p": "9030.00000000", - "q": "0.21386000" + "T": 1577978046242, + "a": 202790587, + "f": 222825706, + "l": 222825706, + "m": false, + "p": "7141.49000000", + "q": "0.03421600" }, { "M": true, - "T": 1588749153580, - "a": 284861586, - "f": 310207884, - "l": 310207884, - "m": true, - "p": "9030.00000000", - "q": "0.02000000" + "T": 1577978046248, + "a": 202790588, + "f": 222825707, + "l": 222825707, + "m": false, + "p": "7141.49000000", + "q": "0.35061400" }, { "M": true, - "T": 1588749153588, - "a": 284861587, - "f": 310207885, - "l": 310207885, + "T": 1577978046637, + "a": 202790589, + "f": 222825708, + "l": 222825708, "m": false, - "p": "9030.46000000", - "q": "0.00661100" + "p": "7141.83000000", + "q": "0.00158000" }, { "M": true, - "T": 1588749153596, - "a": 284861588, - "f": 310207886, - "l": 310207886, + "T": 1577978048116, + "a": 202790590, + "f": 222825709, + "l": 222825709, "m": true, - "p": "9030.00000000", - "q": "0.06007300" + "p": "7141.50000000", + "q": "0.00460900" }, { "M": true, - "T": 1588749153599, - "a": 284861589, - "f": 310207887, - "l": 310207887, - "m": true, - "p": "9030.00000000", - "q": "0.03155700" + "T": 1577978048752, + "a": 202790591, + "f": 222825710, + "l": 222825710, + "m": false, + "p": "7141.68000000", + "q": "0.05180400" }, { "M": true, - "T": 1588749153879, - "a": 284861590, - "f": 310207888, - "l": 310207888, - "m": true, - "p": "9030.00000000", - "q": "0.01076700" + "T": 1577978048752, + "a": 202790592, + "f": 222825711, + "l": 222825711, + "m": false, + "p": "7141.68000000", + "q": "0.00889400" }, { "M": true, - "T": 1588749153918, - "a": 284861591, - "f": 310207889, - "l": 310207889, - "m": true, - "p": "9030.00000000", - "q": "0.06000800" + "T": 1577978050096, + "a": 202790593, + "f": 222825712, + "l": 222825712, + "m": false, + "p": "7141.79000000", + "q": "0.00190500" }, { "M": true, - "T": 1588749154009, - "a": 284861592, - "f": 310207890, - "l": 310207890, - "m": true, - "p": "9030.00000000", - "q": "0.00221400" + "T": 1577978050096, + "a": 202790594, + "f": 222825713, + "l": 222825713, + "m": false, + "p": "7141.80000000", + "q": "0.05180400" }, { "M": true, - "T": 1588749154014, - "a": 284861593, - "f": 310207891, - "l": 310207891, - "m": true, - "p": "9030.00000000", - "q": "0.00221400" + "T": 1577978050096, + "a": 202790595, + "f": 222825714, + "l": 222825714, + "m": false, + "p": "7141.86000000", + "q": "0.01603500" }, { "M": true, - "T": 1588749154014, - "a": 284861594, - "f": 310207892, - "l": 310207892, - "m": true, - "p": "9030.00000000", - "q": "0.00221400" + "T": 1577978050096, + "a": 202790596, + "f": 222825715, + "l": 222825715, + "m": false, + "p": "7142.73000000", + "q": "0.01385200" }, { "M": true, - "T": 1588749154016, - "a": 284861595, - "f": 310207893, - "l": 310207893, - "m": true, - "p": "9030.00000000", - "q": "0.00221400" + "T": 1577978050817, + "a": 202790597, + "f": 222825716, + "l": 222825716, + "m": false, + "p": "7142.36000000", + "q": "0.15079600" }, { "M": true, - "T": 1588749154198, - "a": 284861596, - "f": 310207894, - "l": 310207894, - "m": true, - "p": "9030.00000000", - "q": "0.51193200" + "T": 1577978050817, + "a": 202790598, + "f": 222825717, + "l": 222825717, + "m": false, + "p": "7142.47000000", + "q": "0.04372800" }, { "M": true, - "T": 1588749154238, - "a": 284861597, - "f": 310207895, - "l": 310207895, - "m": true, - "p": "9030.00000000", - "q": "0.19464900" + "T": 1577978050817, + "a": 202790599, + "f": 222825718, + "l": 222825718, + "m": false, + "p": "7142.48000000", + "q": "0.72292400" }, { "M": true, - "T": 1588749154242, - "a": 284861598, - "f": 310207896, - "l": 310207896, + "T": 1577978052277, + "a": 202790600, + "f": 222825719, + "l": 222825719, "m": true, - "p": "9030.00000000", - "q": "0.06028500" + "p": "7141.73000000", + "q": "0.02105300" }, { "M": true, - "T": 1588749154387, - "a": 284861599, - "f": 310207897, - "l": 310207897, - "m": true, - "p": "9030.00000000", - "q": "0.24213300" + "T": 1577978052862, + "a": 202790601, + "f": 222825720, + "l": 222825720, + "m": false, + "p": "7142.52000000", + "q": "0.00164500" }, { "M": true, - "T": 1588749154491, - "a": 284861600, - "f": 310207898, - "l": 310207898, - "m": true, - "p": "9030.00000000", - "q": "0.01246600" + "T": 1577978054203, + "a": 202790602, + "f": 222825721, + "l": 222825721, + "m": false, + "p": "7142.52000000", + "q": "0.00216500" }, { "M": true, - "T": 1588749154558, - "a": 284861601, - "f": 310207899, - "l": 310207899, + "T": 1577978054407, + "a": 202790603, + "f": 222825722, + "l": 222825722, "m": true, - "p": "9030.00000000", - "q": "0.06013400" + "p": "7141.73000000", + "q": "0.11511100" }, { "M": true, - "T": 1588749154879, - "a": 284861602, - "f": 310207900, - "l": 310207900, + "T": 1577978056947, + "a": 202790604, + "f": 222825723, + "l": 222825723, "m": true, - "p": "9030.00000000", - "q": "0.06014600" + "p": "7141.53000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155013, - "a": 284861603, - "f": 310207901, - "l": 310207901, + "T": 1577978056948, + "a": 202790605, + "f": 222825724, + "l": 222825724, "m": true, - "p": "9030.00000000", - "q": "0.01009500" + "p": "7141.53000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155031, - "a": 284861604, - "f": 310207902, - "l": 310207902, + "T": 1577978056948, + "a": 202790606, + "f": 222825725, + "l": 222825725, "m": true, - "p": "9030.00000000", - "q": "0.01009500" + "p": "7141.53000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155049, - "a": 284861605, - "f": 310207903, - "l": 310207903, + "T": 1577978056948, + "a": 202790607, + "f": 222825726, + "l": 222825726, "m": true, - "p": "9030.00000000", - "q": "0.18295200" + "p": "7141.53000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155193, - "a": 284861606, - "f": 310207904, - "l": 310207904, + "T": 1577978056948, + "a": 202790608, + "f": 222825727, + "l": 222825727, "m": true, - "p": "9030.00000000", - "q": "0.06021600" + "p": "7141.53000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155440, - "a": 284861607, - "f": 310207905, - "l": 310207905, + "T": 1577978056948, + "a": 202790609, + "f": 222825728, + "l": 222825728, "m": true, - "p": "9030.00000000", - "q": "0.05764100" + "p": "7141.53000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155520, - "a": 284861608, - "f": 310207906, - "l": 310207906, + "T": 1577978056948, + "a": 202790610, + "f": 222825729, + "l": 222825729, "m": true, - "p": "9030.00000000", - "q": "0.01923300" + "p": "7141.53000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155522, - "a": 284861609, - "f": 310207907, - "l": 310207907, + "T": 1577978056948, + "a": 202790611, + "f": 222825730, + "l": 222825730, "m": true, - "p": "9030.00000000", - "q": "0.06022900" + "p": "7141.53000000", + "q": "0.00559700" }, { "M": true, - "T": 1588749155523, - "a": 284861610, - "f": 310207908, - "l": 310207908, + "T": 1577978056948, + "a": 202790612, + "f": 222825731, + "l": 222825731, "m": true, - "p": "9030.00000000", - "q": "0.07692800" + "p": "7141.52000000", + "q": "0.00076300" }, { "M": true, - "T": 1588749155593, - "a": 284861611, - "f": 310207909, - "l": 310207909, + "T": 1577978056948, + "a": 202790613, + "f": 222825732, + "l": 222825732, "m": true, - "p": "9030.00000000", - "q": "0.16911100" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155640, - "a": 284861612, - "f": 310207910, - "l": 310207910, + "T": 1577978056948, + "a": 202790614, + "f": 222825733, + "l": 222825733, "m": true, - "p": "9030.00000000", - "q": "0.00127900" - }, - { - "M": true, - "T": 1588749155655, - "a": 284861613, - "f": 310207911, - "l": 310207911, - "m": false, - "p": "9030.01000000", - "q": "0.00923800" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155758, - "a": 284861614, - "f": 310207912, - "l": 310207912, + "T": 1577978056949, + "a": 202790615, + "f": 222825734, + "l": 222825734, "m": true, - "p": "9030.00000000", - "q": "0.01550200" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155759, - "a": 284861615, - "f": 310207913, - "l": 310207913, + "T": 1577978056952, + "a": 202790616, + "f": 222825735, + "l": 222825735, "m": true, - "p": "9030.00000000", - "q": "0.06137400" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155838, - "a": 284861616, - "f": 310207914, - "l": 310207914, + "T": 1577978056952, + "a": 202790617, + "f": 222825736, + "l": 222825736, "m": true, - "p": "9030.00000000", - "q": "0.06012400" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749155844, - "a": 284861617, - "f": 310207915, - "l": 310207915, + "T": 1577978056952, + "a": 202790618, + "f": 222825737, + "l": 222825737, "m": true, - "p": "9030.00000000", - "q": "0.01105000" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749156021, - "a": 284861618, - "f": 310207916, - "l": 310207916, + "T": 1577978056952, + "a": 202790619, + "f": 222825738, + "l": 222825738, "m": true, - "p": "9030.00000000", - "q": "0.05082900" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749156072, - "a": 284861619, - "f": 310207917, - "l": 310207917, + "T": 1577978056952, + "a": 202790620, + "f": 222825739, + "l": 222825739, "m": true, - "p": "9030.00000000", - "q": "0.00707900" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749156308, - "a": 284861620, - "f": 310207918, - "l": 310207918, + "T": 1577978056952, + "a": 202790621, + "f": 222825740, + "l": 222825740, "m": true, - "p": "9030.00000000", - "q": "0.08380100" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749156393, - "a": 284861621, - "f": 310207919, - "l": 310207919, + "T": 1577978056953, + "a": 202790622, + "f": 222825741, + "l": 222825741, "m": true, - "p": "9030.00000000", - "q": "0.00848500" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749156488, - "a": 284861622, - "f": 310207920, - "l": 310207920, + "T": 1577978056955, + "a": 202790623, + "f": 222825742, + "l": 222825742, "m": true, - "p": "9030.00000000", - "q": "0.01010100" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749156602, - "a": 284861623, - "f": 310207921, - "l": 310207921, + "T": 1577978056958, + "a": 202790624, + "f": 222825743, + "l": 222825743, "m": true, - "p": "9030.00000000", - "q": "0.01010100" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749156632, - "a": 284861624, - "f": 310207922, - "l": 310207922, + "T": 1577978056958, + "a": 202790625, + "f": 222825744, + "l": 222825744, "m": true, - "p": "9030.00000000", - "q": "0.06001300" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749156921, - "a": 284861625, - "f": 310207923, - "l": 310207923, + "T": 1577978056958, + "a": 202790626, + "f": 222825745, + "l": 222825745, "m": true, - "p": "9030.00000000", - "q": "0.01558500" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749156960, - "a": 284861626, - "f": 310207924, - "l": 310207924, + "T": 1577978056958, + "a": 202790627, + "f": 222825746, + "l": 222825746, "m": true, - "p": "9030.00000000", - "q": "0.06025000" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749157124, - "a": 284861627, - "f": 310207925, - "l": 310207925, - "m": false, - "p": "9030.10000000", - "q": "0.00838400" + "T": 1577978056962, + "a": 202790628, + "f": 222825747, + "l": 222825747, + "m": true, + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749157222, - "a": 284861628, - "f": 310207926, - "l": 310207926, - "m": false, - "p": "9030.14000000", - "q": "0.00850000" + "T": 1577978056962, + "a": 202790629, + "f": 222825748, + "l": 222825748, + "m": true, + "p": "7141.52000000", + "q": "0.01099200" }, { "M": true, - "T": 1588749157292, - "a": 284861629, - "f": 310207927, - "l": 310207927, + "T": 1577978056962, + "a": 202790630, + "f": 222825749, + "l": 222825749, "m": true, - "p": "9030.13000000", - "q": "0.06004200" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749157327, - "a": 284861630, - "f": 310207928, - "l": 310207928, - "m": false, - "p": "9030.14000000", - "q": "0.00149100" + "T": 1577978056962, + "a": 202790631, + "f": 222825750, + "l": 222825750, + "m": true, + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749157337, - "a": 284861631, - "f": 310207929, - "l": 310207929, + "T": 1577978056962, + "a": 202790632, + "f": 222825751, + "l": 222825751, "m": true, - "p": "9030.13000000", - "q": "0.01010500" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749157514, - "a": 284861632, - "f": 310207930, - "l": 310207930, + "T": 1577978056963, + "a": 202790633, + "f": 222825752, + "l": 222825752, "m": true, - "p": "9030.13000000", - "q": "0.08157400" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749157620, - "a": 284861633, - "f": 310207931, - "l": 310207931, + "T": 1577978056963, + "a": 202790634, + "f": 222825753, + "l": 222825753, "m": true, - "p": "9030.13000000", - "q": "0.06024800" + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749157729, - "a": 284861634, - "f": 310207932, - "l": 310207932, - "m": false, - "p": "9030.14000000", - "q": "0.00000900" + "T": 1577978056967, + "a": 202790635, + "f": 222825754, + "l": 222825754, + "m": true, + "p": "7141.52000000", + "q": "0.00636000" }, { "M": true, - "T": 1588749157729, - "a": 284861635, - "f": 310207933, - "l": 310207933, + "T": 1577978059069, + "a": 202790636, + "f": 222825755, + "l": 222825755, "m": false, - "p": "9031.27000000", - "q": "0.00134200" + "p": "7142.37000000", + "q": "0.00156300" }, { "M": true, - "T": 1588749157729, - "a": 284861636, - "f": 310207934, - "l": 310207934, + "T": 1577978059425, + "a": 202790637, + "f": 222825756, + "l": 222825756, "m": false, - "p": "9031.40000000", - "q": "0.00063700" + "p": "7141.86000000", + "q": "0.04320300" }, { "M": true, - "T": 1588749157855, - "a": 284861637, - "f": 310207935, - "l": 310207935, + "T": 1577978059426, + "a": 202790638, + "f": 222825757, + "l": 222825757, "m": false, - "p": "9031.02000000", - "q": "0.00700900" + "p": "7142.37000000", + "q": "0.07479000" }, { "M": true, - "T": 1588749157953, - "a": 284861638, - "f": 310207936, - "l": 310207936, + "T": 1577978060046, + "a": 202790639, + "f": 222825758, + "l": 222825758, "m": true, - "p": "9030.14000000", - "q": "0.00221400" + "p": "7141.51000000", + "q": "0.01433400" }, { "M": true, - "T": 1588749157953, - "a": 284861639, - "f": 310207937, - "l": 310207937, + "T": 1577978060157, + "a": 202790640, + "f": 222825759, + "l": 222825759, "m": true, - "p": "9030.00000000", - "q": "0.05814100" + "p": "7141.51000000", + "q": "0.01364300" }, { "M": true, - "T": 1588749157970, - "a": 284861640, - "f": 310207938, - "l": 310207938, - "m": false, - "p": "9030.82000000", - "q": "0.00783600" + "T": 1577978060509, + "a": 202790641, + "f": 222825760, + "l": 222825760, + "m": true, + "p": "7141.51000000", + "q": "0.00002300" }, { "M": true, - "T": 1588749157970, - "a": 284861641, - "f": 310207939, - "l": 310207939, - "m": false, - "p": "9030.95000000", - "q": "0.00066400" + "T": 1577978060509, + "a": 202790642, + "f": 222825761, + "l": 222825761, + "m": true, + "p": "7141.29000000", + "q": "0.04029700" }, { "M": true, - "T": 1588749158064, - "a": 284861642, - "f": 310207940, - "l": 310207940, - "m": false, - "p": "9030.88000000", - "q": "0.00594900" + "T": 1577978060571, + "a": 202790643, + "f": 222825762, + "l": 222825762, + "m": true, + "p": "7140.80000000", + "q": "0.00518100" }, { "M": true, - "T": 1588749158129, - "a": 284861643, - "f": 310207941, - "l": 310207941, + "T": 1577978060802, + "a": 202790644, + "f": 222825763, + "l": 222825763, "m": true, - "p": "9030.00000000", - "q": "0.03350300" + "p": "7140.82000000", + "q": "0.05757000" }, { "M": true, - "T": 1588749158283, - "a": 284861644, - "f": 310207942, - "l": 310207942, + "T": 1577978060905, + "a": 202790645, + "f": 222825764, + "l": 222825764, "m": true, - "p": "9030.00000000", - "q": "0.06016200" + "p": "7140.82000000", + "q": "0.01151400" }, { "M": true, - "T": 1588749158896, - "a": 284861645, - "f": 310207943, - "l": 310207943, - "m": true, - "p": "9030.00000000", - "q": "0.03124800" + "T": 1577978062289, + "a": 202790646, + "f": 222825765, + "l": 222825765, + "m": false, + "p": "7142.16000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749159319, - "a": 284861646, - "f": 310207944, - "l": 310207944, + "T": 1577978062698, + "a": 202790647, + "f": 222825766, + "l": 222825766, "m": true, - "p": "9030.01000000", - "q": "0.03108500" + "p": "7141.42000000", + "q": "0.32291000" }, { "M": true, - "T": 1588749159449, - "a": 284861647, - "f": 310207945, - "l": 310207945, + "T": 1577978063243, + "a": 202790648, + "f": 222825767, + "l": 222825767, "m": false, - "p": "9030.29000000", - "q": "0.00999800" + "p": "7142.10000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749159451, - "a": 284861648, - "f": 310207946, - "l": 310207946, + "T": 1577978063272, + "a": 202790649, + "f": 222825768, + "l": 222825768, "m": true, - "p": "9030.01000000", - "q": "0.00486000" + "p": "7141.01000000", + "q": "0.03080300" }, { "M": true, - "T": 1588749159647, - "a": 284861649, - "f": 310207947, - "l": 310207947, + "T": 1577978063272, + "a": 202790650, + "f": 222825769, + "l": 222825769, "m": true, - "p": "9030.01000000", - "q": "0.05024000" + "p": "7140.99000000", + "q": "0.00951700" }, { "M": true, - "T": 1588749159750, - "a": 284861650, - "f": 310207948, - "l": 310207948, + "T": 1577978063358, + "a": 202790651, + "f": 222825770, + "l": 222825770, "m": false, - "p": "9030.25000000", - "q": "0.00123100" + "p": "7141.02000000", + "q": "0.00179800" }, { "M": true, - "T": 1588749160405, - "a": 284861651, - "f": 310207949, - "l": 310207949, - "m": true, - "p": "9030.01000000", - "q": "0.27841000" + "T": 1577978063358, + "a": 202790652, + "f": 222825771, + "l": 222825771, + "m": false, + "p": "7142.10000000", + "q": "0.02517000" }, { "M": true, - "T": 1588749160405, - "a": 284861652, - "f": 310207950, - "l": 310207950, - "m": true, - "p": "9030.00000000", - "q": "0.12159000" + "T": 1577978063358, + "a": 202790653, + "f": 222825772, + "l": 222825772, + "m": false, + "p": "7142.17000000", + "q": "0.14444300" + }, + { + "M": true, + "T": 1577978063358, + "a": 202790654, + "f": 222825773, + "l": 222825773, + "m": false, + "p": "7142.18000000", + "q": "0.05837500" }, { "M": true, - "T": 1588749160493, - "a": 284861653, - "f": 310207951, - "l": 310207951, - "m": true, - "p": "9030.00000000", - "q": "0.04555600" + "T": 1577978063358, + "a": 202790655, + "f": 222825774, + "l": 222825774, + "m": false, + "p": "7142.32000000", + "q": "0.17021400" }, { "M": true, - "T": 1588749160588, - "a": 284861654, - "f": 310207952, - "l": 310207952, + "T": 1577978063562, + "a": 202790656, + "f": 222825775, + "l": 222825775, "m": true, - "p": "9030.00000000", - "q": "0.00442000" + "p": "7141.04000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749160702, - "a": 284861655, - "f": 310207953, - "l": 310207953, + "T": 1577978063951, + "a": 202790657, + "f": 222825776, + "l": 222825776, "m": true, - "p": "9030.00000000", - "q": "0.00416700" + "p": "7141.08000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749160719, - "a": 284861656, - "f": 310207954, - "l": 310207954, - "m": true, - "p": "9030.00000000", - "q": "0.06012800" + "T": 1577978067258, + "a": 202790658, + "f": 222825777, + "l": 222825777, + "m": false, + "p": "7141.75000000", + "q": "0.18981900" }, { "M": true, - "T": 1588749160811, - "a": 284861657, - "f": 310207955, - "l": 310207955, - "m": true, - "p": "9030.00000000", - "q": "0.00392600" + "T": 1577978067294, + "a": 202790659, + "f": 222825778, + "l": 222825778, + "m": false, + "p": "7141.98000000", + "q": "0.00161900" }, { "M": true, - "T": 1588749160999, - "a": 284861658, - "f": 310207956, - "l": 310207956, + "T": 1577978070056, + "a": 202790660, + "f": 222825779, + "l": 222825779, "m": false, - "p": "9030.01000000", - "q": "0.01159900" + "p": "7141.85000000", + "q": "0.00210000" }, { "M": true, - "T": 1588749161003, - "a": 284861659, - "f": 310207957, - "l": 310207957, - "m": true, - "p": "9030.00000000", - "q": "0.03930800" + "T": 1577978073435, + "a": 202790661, + "f": 222825780, + "l": 222825780, + "m": false, + "p": "7141.48000000", + "q": "0.06045000" }, { "M": true, - "T": 1588749161025, - "a": 284861660, - "f": 310207958, - "l": 310207958, - "m": true, - "p": "9030.00000000", - "q": "0.06053000" + "T": 1577978073440, + "a": 202790662, + "f": 222825781, + "l": 222825781, + "m": false, + "p": "7141.48000000", + "q": "0.16933300" }, { "M": true, - "T": 1588749161337, - "a": 284861661, - "f": 310207959, - "l": 310207959, + "T": 1577978073505, + "a": 202790663, + "f": 222825782, + "l": 222825782, "m": true, - "p": "9030.00000000", - "q": "0.06054300" + "p": "7141.48000000", + "q": "0.05757900" }, { "M": true, - "T": 1588749161443, - "a": 284861662, - "f": 310207960, - "l": 310207960, + "T": 1577978073605, + "a": 202790664, + "f": 222825783, + "l": 222825783, "m": true, - "p": "9030.00000000", - "q": "0.00306400" + "p": "7141.48000000", + "q": "0.00282100" }, { "M": true, - "T": 1588749161651, - "a": 284861663, - "f": 310207961, - "l": 310207961, + "T": 1577978073668, + "a": 202790665, + "f": 222825784, + "l": 222825784, "m": true, - "p": "9030.00000000", - "q": "0.06004300" + "p": "7141.48000000", + "q": "0.00005000" }, { "M": true, - "T": 1588749161749, - "a": 284861664, - "f": 310207962, - "l": 310207962, + "T": 1577978073668, + "a": 202790666, + "f": 222825785, + "l": 222825785, "m": true, - "p": "9030.00000000", - "q": "0.00221500" + "p": "7141.08000000", + "q": "0.03080200" }, { "M": true, - "T": 1588749161753, - "a": 284861665, - "f": 310207963, - "l": 310207963, + "T": 1577978073668, + "a": 202790667, + "f": 222825786, + "l": 222825786, "m": true, - "p": "9030.00000000", - "q": "0.00221500" + "p": "7140.79000000", + "q": "0.00946800" }, { "M": true, - "T": 1588749161757, - "a": 284861666, - "f": 310207964, - "l": 310207964, + "T": 1577978074982, + "a": 202790668, + "f": 222825787, + "l": 222825787, "m": true, - "p": "9030.00000000", - "q": "0.00221500" + "p": "7141.61000000", + "q": "0.00869400" }, { "M": true, - "T": 1588749161857, - "a": 284861667, - "f": 310207965, - "l": 310207966, + "T": 1577978075373, + "a": 202790669, + "f": 222825788, + "l": 222825788, "m": true, - "p": "9030.00000000", - "q": "0.00221500" + "p": "7141.61000000", + "q": "0.00060000" }, { "M": true, - "T": 1588749161960, - "a": 284861668, - "f": 310207967, - "l": 310207967, + "T": 1577978075373, + "a": 202790670, + "f": 222825789, + "l": 222825789, "m": true, - "p": "9030.00000000", - "q": "0.06018100" + "p": "7140.78000000", + "q": "0.03972000" }, { "M": true, - "T": 1588749162264, - "a": 284861669, - "f": 310207968, - "l": 310207969, - "m": true, - "p": "9030.00000000", - "q": "0.06023400" + "T": 1577978075511, + "a": 202790671, + "f": 222825790, + "l": 222825790, + "m": false, + "p": "7141.69000000", + "q": "0.00163600" }, { "M": true, - "T": 1588749162311, - "a": 284861670, - "f": 310207970, - "l": 310207974, - "m": true, - "p": "9030.00000000", - "q": "0.11818400" + "T": 1577978077433, + "a": 202790672, + "f": 222825791, + "l": 222825791, + "m": false, + "p": "7141.72000000", + "q": "0.07890400" }, { "M": true, - "T": 1588749162370, - "a": 284861671, - "f": 310207975, - "l": 310207975, - "m": true, - "p": "9030.00000000", - "q": "0.00000900" + "T": 1577978077437, + "a": 202790673, + "f": 222825792, + "l": 222825792, + "m": false, + "p": "7141.33000000", + "q": "0.04632100" }, { "M": true, - "T": 1588749162415, - "a": 284861672, - "f": 310207976, - "l": 310207976, - "m": true, - "p": "9029.71000000", - "q": "0.00299300" + "T": 1577978077714, + "a": 202790674, + "f": 222825793, + "l": 222825793, + "m": false, + "p": "7141.74000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749162529, - "a": 284861673, - "f": 310207977, - "l": 310207977, + "T": 1577978078654, + "a": 202790675, + "f": 222825794, + "l": 222825794, "m": false, - "p": "9029.72000000", - "q": "0.00735500" + "p": "7141.74000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749162580, - "a": 284861674, - "f": 310207978, - "l": 310207978, + "T": 1577978079066, + "a": 202790676, + "f": 222825795, + "l": 222825795, "m": true, - "p": "9029.71000000", - "q": "0.00000700" + "p": "7141.61000000", + "q": "0.01998000" }, { "M": true, - "T": 1588749162580, - "a": 284861675, - "f": 310207979, - "l": 310207979, + "T": 1577978079183, + "a": 202790677, + "f": 222825796, + "l": 222825796, "m": true, - "p": "9029.23000000", - "q": "0.06015900" + "p": "7141.61000000", + "q": "0.00002000" }, { "M": true, - "T": 1588749162901, - "a": 284861676, - "f": 310207980, - "l": 310207980, + "T": 1577978079183, + "a": 202790678, + "f": 222825797, + "l": 222825797, "m": true, - "p": "9029.00000000", - "q": "0.00228000" + "p": "7140.80000000", + "q": "0.04030000" }, { "M": true, - "T": 1588749162901, - "a": 284861677, - "f": 310207981, - "l": 310207981, + "T": 1577978079815, + "a": 202790679, + "f": 222825798, + "l": 222825798, "m": true, - "p": "9028.69000000", - "q": "0.00300000" + "p": "7140.61000000", + "q": "0.03080300" }, { "M": true, - "T": 1588749162901, - "a": 284861678, - "f": 310207982, - "l": 310207982, - "m": true, - "p": "9028.62000000", - "q": "0.01250000" + "T": 1577978083739, + "a": 202790680, + "f": 222825799, + "l": 222825799, + "m": false, + "p": "7141.56000000", + "q": "0.00156800" }, { "M": true, - "T": 1588749162901, - "a": 284861679, - "f": 310207983, - "l": 310207983, + "T": 1577978083959, + "a": 202790681, + "f": 222825800, + "l": 222825800, "m": true, - "p": "9028.57000000", - "q": "0.00113500" + "p": "7140.61000000", + "q": "0.00000200" }, { "M": true, - "T": 1588749162901, - "a": 284861680, - "f": 310207984, - "l": 310207984, + "T": 1577978083959, + "a": 202790682, + "f": 222825801, + "l": 222825801, "m": true, - "p": "9028.07000000", - "q": "0.04154100" + "p": "7140.60000000", + "q": "0.00430000" }, { "M": true, - "T": 1588749163133, - "a": 284861681, - "f": 310207985, - "l": 310207985, - "m": false, - "p": "9029.06000000", - "q": "0.00358300" + "T": 1577978083959, + "a": 202790683, + "f": 222825802, + "l": 222825802, + "m": true, + "p": "7140.05000000", + "q": "0.04866900" }, { "M": true, - "T": 1588749163230, - "a": 284861682, - "f": 310207986, - "l": 310207986, + "T": 1577978084036, + "a": 202790684, + "f": 222825803, + "l": 222825803, "m": true, - "p": "9028.05000000", - "q": "0.06013300" + "p": "7141.12000000", + "q": "0.40097400" }, { "M": true, - "T": 1588749163239, - "a": 284861683, - "f": 310207987, - "l": 310207987, + "T": 1577978084486, + "a": 202790685, + "f": 222825804, + "l": 222825804, "m": false, - "p": "9028.53000000", - "q": "0.00400600" + "p": "7141.34000000", + "q": "0.00302200" }, { "M": true, - "T": 1588749163275, - "a": 284861684, - "f": 310207988, - "l": 310207988, + "T": 1577978088674, + "a": 202790686, + "f": 222825805, + "l": 222825805, "m": false, - "p": "9028.52000000", - "q": "0.00221500" + "p": "7141.18000000", + "q": "0.03249000" }, { "M": true, - "T": 1588749163337, - "a": 284861685, - "f": 310207989, - "l": 310207989, + "T": 1577978088842, + "a": 202790687, + "f": 222825806, + "l": 222825806, "m": false, - "p": "9028.52000000", - "q": "0.00837900" + "p": "7141.15000000", + "q": "0.14875100" }, { "M": true, - "T": 1588749163467, - "a": 284861686, - "f": 310207990, - "l": 310207990, + "T": 1577978088842, + "a": 202790688, + "f": 222825807, + "l": 222825807, "m": false, - "p": "9028.53000000", - "q": "0.00292400" - }, - { - "M": true, - "T": 1588749163559, - "a": 284861687, - "f": 310207991, - "l": 310207991, - "m": true, - "p": "9028.27000000", - "q": "0.06025000" - }, - { - "M": true, - "T": 1588749163881, - "a": 284861688, - "f": 310207992, - "l": 310207992, - "m": true, - "p": "9028.46000000", - "q": "0.06006900" + "p": "7141.16000000", + "q": "0.14058000" }, { "M": true, - "T": 1588749164130, - "a": 284861689, - "f": 310207993, - "l": 310207993, + "T": 1577978088842, + "a": 202790689, + "f": 222825808, + "l": 222825808, "m": false, - "p": "9028.53000000", - "q": "0.00307000" + "p": "7141.18000000", + "q": "0.05880300" }, { "M": true, - "T": 1588749164130, - "a": 284861690, - "f": 310207994, - "l": 310207994, + "T": 1577978088842, + "a": 202790690, + "f": 222825809, + "l": 222825809, "m": false, - "p": "9029.01000000", - "q": "0.00305300" + "p": "7141.19000000", + "q": "0.04030000" }, { "M": true, - "T": 1588749164130, - "a": 284861691, - "f": 310207995, - "l": 310207995, + "T": 1577978088842, + "a": 202790691, + "f": 222825810, + "l": 222825810, "m": false, - "p": "9029.62000000", - "q": "0.00663900" + "p": "7141.20000000", + "q": "0.01156600" }, { "M": true, - "T": 1588749164130, - "a": 284861692, - "f": 310207996, - "l": 310207996, - "m": false, - "p": "9029.99000000", - "q": "0.01606500" + "T": 1577978089802, + "a": 202790692, + "f": 222825811, + "l": 222825811, + "m": true, + "p": "7140.09000000", + "q": "0.01615000" }, { "M": true, - "T": 1588749164130, - "a": 284861693, - "f": 310207997, - "l": 310207997, + "T": 1577978089936, + "a": 202790693, + "f": 222825812, + "l": 222825812, "m": false, - "p": "9030.22000000", - "q": "0.07117300" - }, - { - "M": true, - "T": 1588749164256, - "a": 284861694, - "f": 310207998, - "l": 310207998, - "m": true, - "p": "9029.59000000", - "q": "0.06667600" + "p": "7141.09000000", + "q": "0.00159000" }, { "M": true, - "T": 1588749164351, - "a": 284861695, - "f": 310207999, - "l": 310207999, + "T": 1577978089968, + "a": 202790694, + "f": 222825813, + "l": 222825813, "m": false, - "p": "9029.60000000", - "q": "0.00221000" + "p": "7141.09000000", + "q": "0.00982600" }, { "M": true, - "T": 1588749164583, - "a": 284861696, - "f": 310208000, - "l": 310208000, + "T": 1577978090137, + "a": 202790695, + "f": 222825814, + "l": 222825814, "m": true, - "p": "9029.59000000", - "q": "0.06000800" + "p": "7140.76000000", + "q": "0.18398900" }, { "M": true, - "T": 1588749164626, - "a": 284861697, - "f": 310208001, - "l": 310208001, + "T": 1577978090565, + "a": 202790696, + "f": 222825815, + "l": 222825815, "m": true, - "p": "9029.59000000", - "q": "0.10000000" + "p": "7140.09000000", + "q": "0.08175800" }, { "M": true, - "T": 1588749164727, - "a": 284861698, - "f": 310208002, - "l": 310208003, + "T": 1577978092870, + "a": 202790697, + "f": 222825816, + "l": 222825816, "m": false, - "p": "9029.60000000", - "q": "0.00273300" - }, - { - "M": true, - "T": 1588749164911, - "a": 284861699, - "f": 310208004, - "l": 310208004, - "m": true, - "p": "9029.66000000", - "q": "0.06038200" + "p": "7141.04000000", + "q": "0.03017000" }, { "M": true, - "T": 1588749165074, - "a": 284861700, - "f": 310208005, - "l": 310208005, + "T": 1577978093264, + "a": 202790698, + "f": 222825817, + "l": 222825817, "m": false, - "p": "9029.71000000", - "q": "0.00299000" + "p": "7141.04000000", + "q": "0.03500000" }, { "M": true, - "T": 1588749165238, - "a": 284861701, - "f": 310208006, - "l": 310208006, + "T": 1577978093615, + "a": 202790699, + "f": 222825818, + "l": 222825818, "m": true, - "p": "9029.70000000", - "q": "0.06034200" + "p": "7140.09000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749165807, - "a": 284861702, - "f": 310208007, - "l": 310208007, + "T": 1577978094037, + "a": 202790700, + "f": 222825819, + "l": 222825820, "m": true, - "p": "9029.70000000", - "q": "0.05960000" + "p": "7140.09000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749165894, - "a": 284861703, - "f": 310208008, - "l": 310208008, - "m": true, - "p": "9029.70000000", - "q": "0.00442600" + "T": 1577978094220, + "a": 202790701, + "f": 222825821, + "l": 222825821, + "m": false, + "p": "7140.34000000", + "q": "0.29834800" }, { "M": true, - "T": 1588749165943, - "a": 284861704, - "f": 310208009, - "l": 310208010, - "m": true, - "p": "9029.70000000", - "q": "1.00000000" + "T": 1577978096943, + "a": 202790702, + "f": 222825822, + "l": 222825822, + "m": false, + "p": "7140.98000000", + "q": "0.30000000" }, { "M": true, - "T": 1588749165991, - "a": 284861705, - "f": 310208011, - "l": 310208011, - "m": true, - "p": "9029.70000000", - "q": "0.00882800" + "T": 1577978096943, + "a": 202790703, + "f": 222825823, + "l": 222825823, + "m": false, + "p": "7141.03000000", + "q": "0.14608300" }, { "M": true, - "T": 1588749166124, - "a": 284861706, - "f": 310208012, - "l": 310208013, + "T": 1577978097077, + "a": 202790704, + "f": 222825824, + "l": 222825824, "m": false, - "p": "9029.71000000", - "q": "0.17700100" + "p": "7141.02000000", + "q": "0.06807200" }, { "M": true, - "T": 1588749166313, - "a": 284861707, - "f": 310208014, - "l": 310208014, - "m": true, - "p": "9030.28000000", - "q": "0.00823000" + "T": 1577978097088, + "a": 202790705, + "f": 222825825, + "l": 222825825, + "m": false, + "p": "7141.02000000", + "q": "0.03688700" }, { "M": true, - "T": 1588749166325, - "a": 284861708, - "f": 310208015, - "l": 310208016, + "T": 1577978097092, + "a": 202790706, + "f": 222825826, + "l": 222825826, "m": false, - "p": "9030.29000000", - "q": "0.00303900" + "p": "7141.02000000", + "q": "0.01775400" }, { "M": true, - "T": 1588749166452, - "a": 284861709, - "f": 310208017, - "l": 310208017, - "m": true, - "p": "9030.28000000", - "q": "0.26800000" + "T": 1577978098164, + "a": 202790707, + "f": 222825827, + "l": 222825827, + "m": false, + "p": "7141.03000000", + "q": "0.00156200" }, { "M": true, - "T": 1588749166511, - "a": 284861710, - "f": 310208018, - "l": 310208018, + "T": 1577978098720, + "a": 202790708, + "f": 222825828, + "l": 222825828, "m": true, - "p": "9030.28000000", - "q": "0.00684500" + "p": "7140.11000000", + "q": "0.02799300" }, { "M": true, - "T": 1588749166622, - "a": 284861711, - "f": 310208019, - "l": 310208020, + "T": 1577978101217, + "a": 202790709, + "f": 222825829, + "l": 222825829, "m": false, - "p": "9030.29000000", - "q": "0.06007000" - }, - { - "M": true, - "T": 1588749166727, - "a": 284861712, - "f": 310208021, - "l": 310208021, - "m": true, - "p": "9029.86000000", - "q": "0.12132600" + "p": "7140.13000000", + "q": "0.00947500" }, { "M": true, - "T": 1588749166939, - "a": 284861713, - "f": 310208022, - "l": 310208022, - "m": true, - "p": "9030.00000000", - "q": "0.00553700" + "T": 1577978101314, + "a": 202790710, + "f": 222825830, + "l": 222825830, + "m": false, + "p": "7140.13000000", + "q": "0.00618100" }, { "M": true, - "T": 1588749166965, - "a": 284861714, - "f": 310208023, - "l": 310208023, - "m": true, - "p": "9030.00000000", - "q": "0.00457000" + "T": 1577978101472, + "a": 202790711, + "f": 222825831, + "l": 222825831, + "m": false, + "p": "7140.71000000", + "q": "0.01549800" }, { "M": true, - "T": 1588749167035, - "a": 284861715, - "f": 310208024, - "l": 310208024, + "T": 1577978102208, + "a": 202790712, + "f": 222825832, + "l": 222825832, "m": true, - "p": "9030.00000000", - "q": "0.00166200" + "p": "7140.09000000", + "q": "0.00148200" }, { "M": true, - "T": 1588749167223, - "a": 284861716, - "f": 310208025, - "l": 310208025, + "T": 1577978102265, + "a": 202790713, + "f": 222825833, + "l": 222825833, "m": false, - "p": "9030.50000000", - "q": "0.00925000" + "p": "7140.69000000", + "q": "0.00299700" }, { "M": true, - "T": 1588749167270, - "a": 284861717, - "f": 310208026, - "l": 310208026, + "T": 1577978102602, + "a": 202790714, + "f": 222825834, + "l": 222825834, "m": true, - "p": "9030.64000000", - "q": "0.01935600" + "p": "7140.09000000", + "q": "0.02126900" }, { "M": true, - "T": 1588749167270, - "a": 284861718, - "f": 310208027, - "l": 310208027, - "m": true, - "p": "9030.01000000", - "q": "0.35077700" + "T": 1577978102744, + "a": 202790715, + "f": 222825835, + "l": 222825835, + "m": false, + "p": "7140.69000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749167778, - "a": 284861719, - "f": 310208028, - "l": 310208028, - "m": true, - "p": "9030.00000000", - "q": "0.00005900" + "T": 1577978102776, + "a": 202790716, + "f": 222825836, + "l": 222825836, + "m": false, + "p": "7140.69000000", + "q": "0.09024100" }, { "M": true, - "T": 1588749167778, - "a": 284861720, - "f": 310208029, - "l": 310208029, + "T": 1577978103003, + "a": 202790717, + "f": 222825837, + "l": 222825837, "m": true, - "p": "9029.71000000", - "q": "0.00221500" + "p": "7140.09000000", + "q": "0.00341400" }, { "M": true, - "T": 1588749167778, - "a": 284861721, - "f": 310208030, - "l": 310208030, + "T": 1577978103412, + "a": 202790718, + "f": 222825838, + "l": 222825838, "m": true, - "p": "9029.67000000", - "q": "0.00789600" + "p": "7140.09000000", + "q": "0.00306700" }, { "M": true, - "T": 1588749167778, - "a": 284861722, - "f": 310208031, - "l": 310208031, + "T": 1577978103791, + "a": 202790719, + "f": 222825839, + "l": 222825839, "m": true, - "p": "9029.55000000", - "q": "0.08241600" + "p": "7140.09000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749168088, - "a": 284861723, - "f": 310208032, - "l": 310208032, + "T": 1577978103835, + "a": 202790720, + "f": 222825840, + "l": 222825840, "m": true, - "p": "9029.28000000", - "q": "0.00219700" + "p": "7140.09000000", + "q": "0.01559800" }, { "M": true, - "T": 1588749168181, - "a": 284861724, - "f": 310208033, - "l": 310208033, - "m": true, - "p": "9029.28000000", - "q": "0.00001700" + "T": 1577978104178, + "a": 202790721, + "f": 222825841, + "l": 222825841, + "m": false, + "p": "7140.69000000", + "q": "0.00140300" }, { "M": true, - "T": 1588749168181, - "a": 284861725, - "f": 310208034, - "l": 310208034, + "T": 1577978104247, + "a": 202790722, + "f": 222825842, + "l": 222825842, "m": true, - "p": "9028.69000000", - "q": "0.00300000" + "p": "7140.09000000", + "q": "0.00464500" }, { "M": true, - "T": 1588749168181, - "a": 284861726, - "f": 310208035, - "l": 310208035, - "m": true, - "p": "9028.60000000", - "q": "0.06910600" + "T": 1577978104292, + "a": 202790723, + "f": 222825843, + "l": 222825843, + "m": false, + "p": "7140.65000000", + "q": "0.01733700" }, { "M": true, - "T": 1588749168419, - "a": 284861727, - "f": 310208036, - "l": 310208036, - "m": true, - "p": "9028.69000000", - "q": "0.00673500" + "T": 1577978104366, + "a": 202790724, + "f": 222825844, + "l": 222825844, + "m": false, + "p": "7140.65000000", + "q": "0.00165300" }, { "M": true, - "T": 1588749168656, - "a": 284861728, - "f": 310208037, - "l": 310208037, + "T": 1577978104651, + "a": 202790725, + "f": 222825845, + "l": 222825845, "m": true, - "p": "9028.72000000", - "q": "0.00221400" + "p": "7140.09000000", + "q": "0.00133000" }, { "M": true, - "T": 1588749168656, - "a": 284861729, - "f": 310208038, - "l": 310208038, + "T": 1577978104651, + "a": 202790726, + "f": 222825846, + "l": 222825846, "m": true, - "p": "9028.71000000", - "q": "0.07357200" + "p": "7140.00000000", + "q": "0.01235500" }, { "M": true, - "T": 1588749168702, - "a": 284861730, - "f": 310208039, - "l": 310208039, - "m": true, - "p": "9028.87000000", - "q": "0.00664800" + "T": 1577978104718, + "a": 202790727, + "f": 222825847, + "l": 222825847, + "m": false, + "p": "7140.64000000", + "q": "0.00947600" }, { "M": true, - "T": 1588749168702, - "a": 284861731, - "f": 310208040, - "l": 310208040, + "T": 1577978105087, + "a": 202790728, + "f": 222825848, + "l": 222825848, "m": true, - "p": "9028.78000000", - "q": "0.08819000" + "p": "7140.00000000", + "q": "0.00210300" }, { "M": true, - "T": 1588749168818, - "a": 284861732, - "f": 310208041, - "l": 310208041, + "T": 1577978105258, + "a": 202790729, + "f": 222825849, + "l": 222825849, "m": false, - "p": "9029.63000000", - "q": "0.00221400" + "p": "7140.66000000", + "q": "0.00296600" }, { "M": true, - "T": 1588749168922, - "a": 284861733, - "f": 310208042, - "l": 310208042, + "T": 1577978105506, + "a": 202790730, + "f": 222825850, + "l": 222825850, "m": true, - "p": "9030.14000000", - "q": "0.01921500" + "p": "7140.00000000", + "q": "0.02661600" }, { "M": true, - "T": 1588749168954, - "a": 284861734, - "f": 310208043, - "l": 310208043, - "m": true, - "p": "9030.14000000", - "q": "0.01263700" + "T": 1577978106080, + "a": 202790731, + "f": 222825851, + "l": 222825851, + "m": false, + "p": "7140.34000000", + "q": "0.33646500" }, { "M": true, - "T": 1588749168954, - "a": 284861735, - "f": 310208044, - "l": 310208044, - "m": true, - "p": "9029.28000000", - "q": "0.01920800" + "T": 1577978106080, + "a": 202790732, + "f": 222825852, + "l": 222825852, + "m": false, + "p": "7140.66000000", + "q": "0.01462500" }, { "M": true, - "T": 1588749169018, - "a": 284861736, - "f": 310208045, - "l": 310208045, + "T": 1577978106578, + "a": 202790733, + "f": 222825853, + "l": 222825853, "m": true, - "p": "9029.28000000", - "q": "0.01925200" + "p": "7140.00000000", + "q": "0.01300000" }, { "M": true, - "T": 1588749169035, - "a": 284861737, - "f": 310208046, - "l": 310208046, - "m": true, - "p": "9029.28000000", - "q": "0.06029800" + "T": 1577978107241, + "a": 202790734, + "f": 222825854, + "l": 222825854, + "m": false, + "p": "7140.67000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749169131, - "a": 284861738, - "f": 310208047, - "l": 310208047, - "m": true, - "p": "9029.29000000", - "q": "0.01918300" + "T": 1577978107949, + "a": 202790735, + "f": 222825855, + "l": 222825855, + "m": false, + "p": "7140.67000000", + "q": "0.00254000" }, { "M": true, - "T": 1588749169359, - "a": 284861739, - "f": 310208048, - "l": 310208048, - "m": true, - "p": "9029.29000000", - "q": "0.06021300" + "T": 1577978107949, + "a": 202790736, + "f": 222825856, + "l": 222825856, + "m": false, + "p": "7140.71000000", + "q": "0.28450200" }, { "M": true, - "T": 1588749169408, - "a": 284861740, - "f": 310208049, - "l": 310208049, - "m": false, - "p": "9029.99000000", - "q": "0.10580000" + "T": 1577978107962, + "a": 202790737, + "f": 222825857, + "l": 222825857, + "m": true, + "p": "7140.71000000", + "q": "0.01875800" }, { "M": true, - "T": 1588749169473, - "a": 284861741, - "f": 310208050, - "l": 310208050, + "T": 1577978107962, + "a": 202790738, + "f": 222825858, + "l": 222825860, "m": true, - "p": "9029.33000000", - "q": "0.17701100" + "p": "7140.00000000", + "q": "0.28168600" }, { "M": true, - "T": 1588749169473, - "a": 284861742, - "f": 310208051, - "l": 310208051, + "T": 1577978107962, + "a": 202790739, + "f": 222825861, + "l": 222825861, "m": true, - "p": "9029.29000000", - "q": "0.03196700" + "p": "7139.83000000", + "q": "0.09955600" }, { "M": true, - "T": 1588749169918, - "a": 284861743, - "f": 310208052, - "l": 310208052, + "T": 1577978108489, + "a": 202790740, + "f": 222825862, + "l": 222825862, "m": false, - "p": "9030.22000000", - "q": "0.00221400" + "p": "7140.76000000", + "q": "0.00328900" }, { "M": true, - "T": 1588749169918, - "a": 284861744, - "f": 310208053, - "l": 310208053, + "T": 1577978108539, + "a": 202790741, + "f": 222825863, + "l": 222825863, "m": false, - "p": "9030.23000000", - "q": "0.01057900" + "p": "7140.74000000", + "q": "0.12788700" }, { "M": true, - "T": 1588749170467, - "a": 284861745, - "f": 310208054, - "l": 310208054, + "T": 1577978108677, + "a": 202790742, + "f": 222825864, + "l": 222825864, "m": true, - "p": "9029.35000000", - "q": "0.32759400" + "p": "7140.84000000", + "q": "0.00159700" }, { "M": true, - "T": 1588749170467, - "a": 284861746, - "f": 310208055, - "l": 310208055, + "T": 1577978109662, + "a": 202790743, + "f": 222825865, + "l": 222825865, "m": true, - "p": "9029.30000000", - "q": "0.00221400" - }, - { - "M": true, - "T": 1588749170619, - "a": 284861747, - "f": 310208056, - "l": 310208056, - "m": false, - "p": "9029.71000000", - "q": "0.00299300" + "p": "7140.84000000", + "q": "0.05861700" }, { "M": true, - "T": 1588749170629, - "a": 284861748, - "f": 310208057, - "l": 310208057, + "T": 1577978109662, + "a": 202790744, + "f": 222825866, + "l": 222825866, "m": true, - "p": "9029.05000000", - "q": "0.00128200" + "p": "7140.82000000", + "q": "0.00143000" }, { "M": true, - "T": 1588749170758, - "a": 284861749, - "f": 310208058, - "l": 310208058, + "T": 1577978109769, + "a": 202790745, + "f": 222825867, + "l": 222825867, "m": true, - "p": "9029.14000000", - "q": "0.17701600" + "p": "7140.86000000", + "q": "0.29538400" }, { "M": true, - "T": 1588749170758, - "a": 284861750, - "f": 310208059, - "l": 310208059, + "T": 1577978110988, + "a": 202790746, + "f": 222825868, + "l": 222825868, "m": true, - "p": "9029.10000000", - "q": "0.07728000" + "p": "7140.82000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749171148, - "a": 284861751, - "f": 310208060, - "l": 310208061, - "m": true, - "p": "9029.14000000", - "q": "0.00397000" + "T": 1577978111119, + "a": 202790747, + "f": 222825869, + "l": 222825869, + "m": false, + "p": "7140.87000000", + "q": "0.00853500" }, { "M": true, - "T": 1588749171148, - "a": 284861752, - "f": 310208062, - "l": 310208062, + "T": 1577978111363, + "a": 202790748, + "f": 222825870, + "l": 222825870, "m": true, - "p": "9029.13000000", - "q": "0.06616600" + "p": "7140.82000000", + "q": "0.06005000" }, { "M": true, - "T": 1588749171458, - "a": 284861753, - "f": 310208063, - "l": 310208063, + "T": 1577978111423, + "a": 202790749, + "f": 222825871, + "l": 222825871, "m": true, - "p": "9029.00000000", - "q": "0.01107500" + "p": "7140.82000000", + "q": "0.03718800" }, { "M": true, - "T": 1588749171667, - "a": 284861754, - "f": 310208064, - "l": 310208064, + "T": 1577978112091, + "a": 202790750, + "f": 222825872, + "l": 222825872, "m": true, - "p": "9029.14000000", - "q": "0.01107500" + "p": "7140.84000000", + "q": "0.01039500" }, { "M": true, - "T": 1588749171667, - "a": 284861755, - "f": 310208065, - "l": 310208065, + "T": 1577978112333, + "a": 202790751, + "f": 222825873, + "l": 222825873, "m": true, - "p": "9028.63000000", - "q": "0.08284200" + "p": "7140.84000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749172462, - "a": 284861756, - "f": 310208066, - "l": 310208066, + "T": 1577978112454, + "a": 202790752, + "f": 222825874, + "l": 222825874, "m": true, - "p": "9029.69000000", - "q": "0.59892900" - }, - { - "M": true, - "T": 1588749172668, - "a": 284861757, - "f": 310208067, - "l": 310208067, - "m": false, - "p": "9029.70000000", - "q": "0.00221400" + "p": "7140.84000000", + "q": "0.00594100" }, { "M": true, - "T": 1588749172759, - "a": 284861758, - "f": 310208068, - "l": 310208068, + "T": 1577978112597, + "a": 202790753, + "f": 222825875, + "l": 222825875, "m": false, - "p": "9029.71000000", - "q": "0.00000700" + "p": "7140.85000000", + "q": "0.00165200" }, { "M": true, - "T": 1588749172759, - "a": 284861759, - "f": 310208069, - "l": 310208069, - "m": false, - "p": "9030.15000000", - "q": "0.00283300" + "T": 1577978113011, + "a": 202790754, + "f": 222825876, + "l": 222825876, + "m": true, + "p": "7140.84000000", + "q": "0.02792700" }, { "M": true, - "T": 1588749172770, - "a": 284861760, - "f": 310208070, - "l": 310208070, - "m": false, - "p": "9030.15000000", - "q": "0.00581000" + "T": 1577978113056, + "a": 202790755, + "f": 222825877, + "l": 222825877, + "m": true, + "p": "7140.82000000", + "q": "0.05585500" }, { "M": true, - "T": 1588749172770, - "a": 284861761, - "f": 310208071, - "l": 310208071, - "m": false, - "p": "9030.15000000", - "q": "0.00001100" + "T": 1577978113056, + "a": 202790756, + "f": 222825878, + "l": 222825878, + "m": true, + "p": "7139.29000000", + "q": "0.00420100" }, { "M": true, - "T": 1588749172770, - "a": 284861762, - "f": 310208072, - "l": 310208072, - "m": false, - "p": "9030.22000000", - "q": "0.00284200" + "T": 1577978115012, + "a": 202790757, + "f": 222825879, + "l": 222825879, + "m": true, + "p": "7139.68000000", + "q": "0.00251600" }, { "M": true, - "T": 1588749172770, - "a": 284861763, - "f": 310208073, - "l": 310208073, + "T": 1577978116558, + "a": 202790758, + "f": 222825880, + "l": 222825880, "m": false, - "p": "9030.48000000", - "q": "0.13826700" + "p": "7140.42000000", + "q": "0.23441900" }, { "M": true, - "T": 1588749172770, - "a": 284861764, - "f": 310208074, - "l": 310208074, + "T": 1577978116567, + "a": 202790759, + "f": 222825881, + "l": 222825881, "m": false, - "p": "9030.72000000", - "q": "0.00300000" + "p": "7140.67000000", + "q": "0.04918800" }, { "M": true, - "T": 1588749172770, - "a": 284861765, - "f": 310208075, - "l": 310208075, - "m": false, - "p": "9030.92000000", - "q": "1.09097100" + "T": 1577978117155, + "a": 202790760, + "f": 222825882, + "l": 222825882, + "m": true, + "p": "7140.35000000", + "q": "0.14011700" }, { "M": true, - "T": 1588749172855, - "a": 284861766, - "f": 310208076, - "l": 310208076, + "T": 1577978118660, + "a": 202790761, + "f": 222825883, + "l": 222825883, "m": true, - "p": "9030.91000000", - "q": "0.00471100" + "p": "7140.50000000", + "q": "0.04774700" }, { "M": true, - "T": 1588749172895, - "a": 284861767, - "f": 310208077, - "l": 310208077, + "T": 1577978118802, + "a": 202790762, + "f": 222825884, + "l": 222825884, "m": false, - "p": "9030.92000000", - "q": "0.04000000" + "p": "7140.67000000", + "q": "0.00157300" }, { "M": true, - "T": 1588749172903, - "a": 284861768, - "f": 310208078, - "l": 310208078, + "T": 1577978119548, + "a": 202790763, + "f": 222825885, + "l": 222825885, "m": false, - "p": "9030.92000000", - "q": "0.01000000" + "p": "7140.67000000", + "q": "0.03653700" }, { "M": true, - "T": 1588749172925, - "a": 284861769, - "f": 310208079, - "l": 310208079, + "T": 1577978119555, + "a": 202790764, + "f": 222825886, + "l": 222825886, "m": false, - "p": "9030.92000000", - "q": "0.02000000" + "p": "7140.44000000", + "q": "0.26441200" }, { "M": true, - "T": 1588749172935, - "a": 284861770, - "f": 310208080, - "l": 310208080, + "T": 1577978120246, + "a": 202790765, + "f": 222825887, + "l": 222825887, "m": false, - "p": "9030.92000000", - "q": "0.38343400" + "p": "7139.94000000", + "q": "0.00800000" }, { "M": true, - "T": 1588749172935, - "a": 284861771, - "f": 310208081, - "l": 310208081, + "T": 1577978120343, + "a": 202790766, + "f": 222825888, + "l": 222825888, "m": false, - "p": "9031.55000000", - "q": "0.15145900" + "p": "7139.94000000", + "q": "0.00947500" }, { "M": true, - "T": 1588749172935, - "a": 284861772, - "f": 310208082, - "l": 310208082, + "T": 1577978120563, + "a": 202790767, + "f": 222825889, + "l": 222825889, "m": false, - "p": "9031.73000000", - "q": "0.00300000" + "p": "7139.94000000", + "q": "0.00947500" }, { "M": true, - "T": 1588749172935, - "a": 284861773, - "f": 310208083, - "l": 310208083, + "T": 1577978121213, + "a": 202790768, + "f": 222825890, + "l": 222825890, "m": false, - "p": "9031.84000000", - "q": "0.14823200" + "p": "7139.94000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749172935, - "a": 284861774, - "f": 310208084, - "l": 310208084, + "T": 1577978122178, + "a": 202790769, + "f": 222825891, + "l": 222825891, "m": false, - "p": "9031.95000000", - "q": "0.00551900" + "p": "7139.94000000", + "q": "0.00025200" }, { "M": true, - "T": 1588749172935, - "a": 284861775, - "f": 310208085, - "l": 310208085, - "m": false, - "p": "9032.60000000", - "q": "0.28786800" + "T": 1577978122200, + "a": 202790770, + "f": 222825892, + "l": 222825892, + "m": true, + "p": "7140.09000000", + "q": "0.13577500" }, { "M": true, - "T": 1588749172948, - "a": 284861776, - "f": 310208086, - "l": 310208086, - "m": false, - "p": "9032.60000000", - "q": "0.01106100" + "T": 1577978122200, + "a": 202790771, + "f": 222825893, + "l": 222825893, + "m": true, + "p": "7140.02000000", + "q": "0.03701400" }, { "M": true, - "T": 1588749172985, - "a": 284861777, - "f": 310208087, - "l": 310208087, + "T": 1577978123942, + "a": 202790772, + "f": 222825894, + "l": 222825894, "m": true, - "p": "9030.95000000", - "q": "0.00386600" + "p": "7140.14000000", + "q": "0.05142400" }, { "M": true, - "T": 1588749174034, - "a": 284861778, - "f": 310208088, - "l": 310208088, + "T": 1577978123942, + "a": 202790773, + "f": 222825895, + "l": 222825895, "m": true, - "p": "9031.60000000", - "q": "0.40000000" + "p": "7140.09000000", + "q": "0.00858300" + }, + { + "M": true, + "T": 1577978124261, + "a": 202790774, + "f": 222825896, + "l": 222825896, + "m": false, + "p": "7140.69000000", + "q": "0.06160700" }, { "M": true, - "T": 1588749174144, - "a": 284861779, - "f": 310208089, - "l": 310208089, + "T": 1577978124782, + "a": 202790775, + "f": 222825897, + "l": 222825897, "m": true, - "p": "9031.69000000", - "q": "0.00221400" + "p": "7140.86000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749174144, - "a": 284861780, - "f": 310208090, - "l": 310208090, + "T": 1577978124921, + "a": 202790776, + "f": 222825898, + "l": 222825898, "m": true, - "p": "9031.68000000", - "q": "0.01907000" + "p": "7140.86000000", + "q": "0.02700000" }, { "M": true, - "T": 1588749174360, - "a": 284861781, - "f": 310208091, - "l": 310208091, + "T": 1577978125165, + "a": 202790777, + "f": 222825899, + "l": 222825899, "m": true, - "p": "9031.73000000", - "q": "0.06025900" + "p": "7140.86000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749174470, - "a": 284861782, - "f": 310208092, - "l": 310208092, + "T": 1577978125603, + "a": 202790778, + "f": 222825900, + "l": 222825900, "m": true, - "p": "9031.74000000", - "q": "0.07190000" + "p": "7140.87000000", + "q": "0.01610700" }, { "M": true, - "T": 1588749174471, - "a": 284861783, - "f": 310208093, - "l": 310208093, + "T": 1577978125603, + "a": 202790779, + "f": 222825901, + "l": 222825901, "m": true, - "p": "9031.74000000", - "q": "0.01012100" + "p": "7140.86000000", + "q": "0.04075400" }, { "M": true, - "T": 1588749174691, - "a": 284861784, - "f": 310208094, - "l": 310208094, + "T": 1577978125603, + "a": 202790780, + "f": 222825902, + "l": 222825902, "m": true, - "p": "9031.76000000", - "q": "0.06018300" + "p": "7140.84000000", + "q": "0.00319000" }, { "M": true, - "T": 1588749174893, - "a": 284861785, - "f": 310208095, - "l": 310208095, + "T": 1577978125901, + "a": 202790781, + "f": 222825903, + "l": 222825903, "m": true, - "p": "9031.71000000", - "q": "0.00183500" + "p": "7140.84000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749174951, - "a": 284861786, - "f": 310208096, - "l": 310208096, + "T": 1577978125964, + "a": 202790782, + "f": 222825904, + "l": 222825904, "m": false, - "p": "9032.38000000", - "q": "0.00813600" + "p": "7140.86000000", + "q": "0.04075400" }, { "M": true, - "T": 1588749174951, - "a": 284861787, - "f": 310208097, - "l": 310208097, + "T": 1577978125964, + "a": 202790783, + "f": 222825905, + "l": 222825905, "m": false, - "p": "9032.41000000", - "q": "0.08561700" + "p": "7140.94000000", + "q": "0.30117600" }, { "M": true, - "T": 1588749175014, - "a": 284861788, - "f": 310208098, - "l": 310208098, + "T": 1577978126584, + "a": 202790784, + "f": 222825906, + "l": 222825906, "m": true, - "p": "9031.72000000", - "q": "0.00833700" + "p": "7140.84000000", + "q": "0.02091800" }, { "M": true, - "T": 1588749175027, - "a": 284861789, - "f": 310208099, - "l": 310208099, + "T": 1577978126584, + "a": 202790785, + "f": 222825907, + "l": 222825907, "m": true, - "p": "9031.72000000", - "q": "0.06007900" + "p": "7139.77000000", + "q": "0.05118200" }, { "M": true, - "T": 1588749175413, - "a": 284861790, - "f": 310208100, - "l": 310208100, + "T": 1577978126584, + "a": 202790786, + "f": 222825908, + "l": 222825908, "m": true, - "p": "9031.73000000", - "q": "0.00361500" + "p": "7139.76000000", + "q": "0.00386300" }, { "M": true, - "T": 1588749175521, - "a": 284861791, - "f": 310208101, - "l": 310208101, - "m": true, - "p": "9031.72000000", - "q": "0.01195000" + "T": 1577978127016, + "a": 202790787, + "f": 222825909, + "l": 222825909, + "m": false, + "p": "7140.88000000", + "q": "0.00156900" }, { "M": true, - "T": 1588749175638, - "a": 284861792, - "f": 310208102, - "l": 310208102, - "m": true, - "p": "9031.72000000", - "q": "0.01195000" + "T": 1577978127282, + "a": 202790788, + "f": 222825910, + "l": 222825910, + "m": false, + "p": "7140.88000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749175738, - "a": 284861793, - "f": 310208103, - "l": 310208103, - "m": true, - "p": "9031.72000000", - "q": "0.00620400" + "T": 1577978128486, + "a": 202790789, + "f": 222825911, + "l": 222825911, + "m": false, + "p": "7140.86000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749175859, - "a": 284861794, - "f": 310208104, - "l": 310208104, - "m": true, - "p": "9031.71000000", - "q": "0.00037900" + "T": 1577978128803, + "a": 202790790, + "f": 222825912, + "l": 222825912, + "m": false, + "p": "7140.86000000", + "q": "0.06382100" }, { "M": true, - "T": 1588749175859, - "a": 284861795, - "f": 310208105, - "l": 310208105, + "T": 1577978128841, + "a": 202790791, + "f": 222825913, + "l": 222825913, "m": true, - "p": "9031.18000000", - "q": "0.14937600" + "p": "7140.86000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749176155, - "a": 284861796, - "f": 310208106, - "l": 310208106, + "T": 1577978128841, + "a": 202790792, + "f": 222825914, + "l": 222825915, "m": true, - "p": "9031.23000000", - "q": "0.00200000" + "p": "7139.85000000", + "q": "0.11610500" }, { "M": true, - "T": 1588749176260, - "a": 284861797, - "f": 310208107, - "l": 310208107, - "m": true, - "p": "9031.34000000", - "q": "0.00404000" + "T": 1577978130044, + "a": 202790793, + "f": 222825916, + "l": 222825916, + "m": false, + "p": "7140.87000000", + "q": "0.00199800" }, { "M": true, - "T": 1588749176571, - "a": 284861798, - "f": 310208108, - "l": 310208108, - "m": true, - "p": "9031.29000000", - "q": "0.00362200" + "T": 1577978130553, + "a": 202790794, + "f": 222825917, + "l": 222825917, + "m": false, + "p": "7140.85000000", + "q": "0.00182100" }, { "M": true, - "T": 1588749177264, - "a": 284861799, - "f": 310208109, - "l": 310208109, - "m": true, - "p": "9032.16000000", - "q": "0.25585300" + "T": 1577978131895, + "a": 202790795, + "f": 222825918, + "l": 222825918, + "m": false, + "p": "7140.20000000", + "q": "0.08567000" }, { "M": true, - "T": 1588749177530, - "a": 284861800, - "f": 310208110, - "l": 310208110, + "T": 1577978131896, + "a": 202790796, + "f": 222825919, + "l": 222825919, "m": false, - "p": "9032.17000000", - "q": "0.00118200" + "p": "7140.85000000", + "q": "0.06020400" }, { "M": true, - "T": 1588749178041, - "a": 284861801, - "f": 310208111, - "l": 310208111, - "m": true, - "p": "9032.16000000", - "q": "0.00767600" + "T": 1577978133238, + "a": 202790797, + "f": 222825920, + "l": 222825920, + "m": false, + "p": "7139.94000000", + "q": "0.00162200" }, { "M": true, - "T": 1588749178152, - "a": 284861802, - "f": 310208112, - "l": 310208112, - "m": true, - "p": "9032.16000000", - "q": "0.04455800" + "T": 1577978133397, + "a": 202790798, + "f": 222825921, + "l": 222825921, + "m": false, + "p": "7139.92000000", + "q": "0.03601100" }, { "M": true, - "T": 1588749179063, - "a": 284861803, - "f": 310208113, - "l": 310208113, + "T": 1577978133475, + "a": 202790799, + "f": 222825922, + "l": 222825922, "m": false, - "p": "9032.17000000", - "q": "0.00103200" + "p": "7139.94000000", + "q": "0.02995500" }, { "M": true, - "T": 1588749179063, - "a": 284861804, - "f": 310208114, - "l": 310208114, + "T": 1577978133507, + "a": 202790800, + "f": 222825923, + "l": 222825923, "m": false, - "p": "9032.65000000", - "q": "0.00018500" + "p": "7139.94000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749179079, - "a": 284861805, - "f": 310208115, - "l": 310208115, + "T": 1577978134007, + "a": 202790801, + "f": 222825924, + "l": 222825924, "m": false, - "p": "9032.65000000", - "q": "0.00277000" + "p": "7139.87000000", + "q": "0.22551500" }, { "M": true, - "T": 1588749179107, - "a": 284861806, - "f": 310208116, - "l": 310208116, + "T": 1577978135512, + "a": 202790802, + "f": 222825925, + "l": 222825925, "m": false, - "p": "9032.65000000", - "q": "0.00004500" + "p": "7139.92000000", + "q": "0.04257900" }, { "M": true, - "T": 1588749179107, - "a": 284861807, - "f": 310208117, - "l": 310208117, + "T": 1577978135615, + "a": 202790803, + "f": 222825926, + "l": 222825926, "m": false, - "p": "9032.75000000", - "q": "0.00216600" + "p": "7139.92000000", + "q": "0.02053600" }, { "M": true, - "T": 1588749179209, - "a": 284861808, - "f": 310208118, - "l": 310208118, - "m": true, - "p": "9032.74000000", - "q": "0.00208000" + "T": 1577978136037, + "a": 202790804, + "f": 222825927, + "l": 222825927, + "m": false, + "p": "7139.90000000", + "q": "0.07928600" }, { "M": true, - "T": 1588749179484, - "a": 284861809, - "f": 310208119, - "l": 310208119, - "m": true, - "p": "9032.74000000", - "q": "0.00330000" + "T": 1577978136125, + "a": 202790805, + "f": 222825928, + "l": 222825928, + "m": false, + "p": "7139.90000000", + "q": "0.19001900" }, { "M": true, - "T": 1588749180143, - "a": 284861810, - "f": 310208120, - "l": 310208120, + "T": 1577978136238, + "a": 202790806, + "f": 222825929, + "l": 222825929, "m": true, - "p": "9032.74000000", - "q": "0.01435000" + "p": "7139.81000000", + "q": "0.00310500" }, { "M": true, - "T": 1588749180560, - "a": 284861811, - "f": 310208121, - "l": 310208121, + "T": 1577978136495, + "a": 202790807, + "f": 222825930, + "l": 222825930, "m": false, - "p": "9032.75000000", - "q": "0.00083400" + "p": "7139.94000000", + "q": "0.21937400" }, { "M": true, - "T": 1588749180560, - "a": 284861812, - "f": 310208122, - "l": 310208122, + "T": 1577978137176, + "a": 202790808, + "f": 222825931, + "l": 222825931, "m": false, - "p": "9033.76000000", - "q": "0.00300000" + "p": "7139.94000000", + "q": "0.09545100" }, { "M": true, - "T": 1588749180560, - "a": 284861813, - "f": 310208123, - "l": 310208123, + "T": 1577978137850, + "a": 202790809, + "f": 222825932, + "l": 222825932, "m": false, - "p": "9034.18000000", - "q": "0.00883000" + "p": "7140.83000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749180560, - "a": 284861814, - "f": 310208124, - "l": 310208124, + "T": 1577978137899, + "a": 202790810, + "f": 222825933, + "l": 222825933, "m": false, - "p": "9034.26000000", - "q": "0.02900000" + "p": "7140.02000000", + "q": "0.08979800" }, { "M": true, - "T": 1588749180560, - "a": 284861815, - "f": 310208125, - "l": 310208125, - "m": false, - "p": "9034.69000000", - "q": "0.00113500" + "T": 1577978139902, + "a": 202790811, + "f": 222825934, + "l": 222825934, + "m": true, + "p": "7139.82000000", + "q": "0.20000000" }, { "M": true, - "T": 1588749180560, - "a": 284861816, - "f": 310208126, - "l": 310208126, + "T": 1577978140956, + "a": 202790812, + "f": 222825935, + "l": 222825935, "m": false, - "p": "9034.77000000", - "q": "0.00957400" + "p": "7140.00000000", + "q": "0.07832500" }, { "M": true, - "T": 1588749180560, - "a": 284861817, - "f": 310208127, - "l": 310208129, + "T": 1577978140959, + "a": 202790813, + "f": 222825936, + "l": 222825936, "m": false, - "p": "9034.78000000", - "q": "0.10237900" + "p": "7139.92000000", + "q": "0.12189600" }, { "M": true, - "T": 1588749180560, - "a": 284861818, - "f": 310208130, - "l": 310208130, + "T": 1577978141459, + "a": 202790814, + "f": 222825937, + "l": 222825937, "m": false, - "p": "9034.81000000", - "q": "0.20000000" + "p": "7140.02000000", + "q": "0.00163800" }, { "M": true, - "T": 1588749180560, - "a": 284861819, - "f": 310208131, - "l": 310208131, + "T": 1577978142860, + "a": 202790815, + "f": 222825938, + "l": 222825938, "m": false, - "p": "9035.00000000", - "q": "0.15961000" + "p": "7140.02000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749180560, - "a": 284861820, - "f": 310208132, - "l": 310208132, + "T": 1577978143948, + "a": 202790816, + "f": 222825939, + "l": 222825939, "m": false, - "p": "9035.06000000", - "q": "1.03374700" - }, - { - "M": true, - "T": 1588749180606, - "a": 284861821, - "f": 310208133, - "l": 310208133, - "m": true, - "p": "9032.88000000", - "q": "0.00350000" + "p": "7140.02000000", + "q": "0.00182100" }, { "M": true, - "T": 1588749180904, - "a": 284861822, - "f": 310208134, - "l": 310208134, - "m": true, - "p": "9033.19000000", - "q": "0.00221300" + "T": 1577978145219, + "a": 202790817, + "f": 222825940, + "l": 222825940, + "m": false, + "p": "7140.00000000", + "q": "0.00151000" }, { "M": true, - "T": 1588749180904, - "a": 284861823, - "f": 310208135, - "l": 310208135, - "m": true, - "p": "9033.18000000", - "q": "0.00633000" + "T": 1577978145469, + "a": 202790818, + "f": 222825941, + "l": 222825941, + "m": false, + "p": "7140.00000000", + "q": "0.06189600" }, { "M": true, - "T": 1588749181631, - "a": 284861824, - "f": 310208136, - "l": 310208136, - "m": true, - "p": "9033.21000000", - "q": "0.00182700" + "T": 1577978145472, + "a": 202790819, + "f": 222825942, + "l": 222825942, + "m": false, + "p": "7139.98000000", + "q": "0.09891600" }, { "M": true, - "T": 1588749181792, - "a": 284861825, - "f": 310208137, - "l": 310208137, - "m": true, - "p": "9033.21000000", - "q": "0.00038600" + "T": 1577978146249, + "a": 202790820, + "f": 222825943, + "l": 222825943, + "m": false, + "p": "7140.02000000", + "q": "0.00151000" }, { "M": true, - "T": 1588749181792, - "a": 284861826, - "f": 310208138, - "l": 310208138, + "T": 1577978148060, + "a": 202790821, + "f": 222825944, + "l": 222825944, "m": true, - "p": "9032.76000000", - "q": "0.00085100" + "p": "7139.81000000", + "q": "0.02565100" }, { "M": true, - "T": 1588749181841, - "a": 284861827, - "f": 310208139, - "l": 310208139, - "m": true, - "p": "9032.76000000", - "q": "0.00307900" + "T": 1577978148518, + "a": 202790822, + "f": 222825945, + "l": 222825945, + "m": false, + "p": "7140.00000000", + "q": "0.04562600" }, { "M": true, - "T": 1588749181949, - "a": 284861828, - "f": 310208140, - "l": 310208140, + "T": 1577978148520, + "a": 202790823, + "f": 222825946, + "l": 222825946, "m": true, - "p": "9033.22000000", - "q": "0.00307900" + "p": "7139.92000000", + "q": "0.09580500" }, { "M": true, - "T": 1588749181998, - "a": 284861829, - "f": 310208141, - "l": 310208141, + "T": 1577978149671, + "a": 202790824, + "f": 222825947, + "l": 222825947, "m": false, - "p": "9033.71000000", - "q": "0.00421400" + "p": "7140.02000000", + "q": "0.00155100" }, { "M": true, - "T": 1588749182068, - "a": 284861830, - "f": 310208142, - "l": 310208142, + "T": 1577978149880, + "a": 202790825, + "f": 222825948, + "l": 222825948, "m": false, - "p": "9033.71000000", - "q": "0.00317800" + "p": "7140.02000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749182072, - "a": 284861831, - "f": 310208143, - "l": 310208143, + "T": 1577978149907, + "a": 202790826, + "f": 222825949, + "l": 222825949, "m": true, - "p": "9033.24000000", - "q": "0.00765400" + "p": "7139.91000000", + "q": "0.06266400" }, { "M": true, - "T": 1588749182581, - "a": 284861832, - "f": 310208144, - "l": 310208144, - "m": true, - "p": "9033.75000000", - "q": "0.24648500" + "T": 1577978152753, + "a": 202790827, + "f": 222825950, + "l": 222825950, + "m": false, + "p": "7140.02000000", + "q": "0.02806000" }, { "M": true, - "T": 1588749182790, - "a": 284861833, - "f": 310208145, - "l": 310208145, + "T": 1577978153506, + "a": 202790828, + "f": 222825951, + "l": 222825951, "m": false, - "p": "9033.76000000", - "q": "0.00421400" + "p": "7140.02000000", + "q": "0.01163200" }, { "M": true, - "T": 1588749182891, - "a": 284861834, - "f": 310208146, - "l": 310208146, - "m": true, - "p": "9033.76000000", - "q": "0.00221300" + "T": 1577978153597, + "a": 202790829, + "f": 222825952, + "l": 222825952, + "m": false, + "p": "7140.02000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749182893, - "a": 284861835, - "f": 310208147, - "l": 310208147, - "m": true, - "p": "9033.64000000", - "q": "0.00955500" + "T": 1577978153816, + "a": 202790830, + "f": 222825953, + "l": 222825953, + "m": false, + "p": "7140.02000000", + "q": "0.00337700" }, { "M": true, - "T": 1588749182893, - "a": 284861836, - "f": 310208148, - "l": 310208148, - "m": true, - "p": "9033.22000000", - "q": "0.00010600" + "T": 1577978155892, + "a": 202790831, + "f": 222825954, + "l": 222825954, + "m": false, + "p": "7140.02000000", + "q": "0.00165600" }, { "M": true, - "T": 1588749182893, - "a": 284861837, - "f": 310208149, - "l": 310208149, - "m": true, - "p": "9032.77000000", - "q": "0.29499900" + "T": 1577978156835, + "a": 202790832, + "f": 222825955, + "l": 222825955, + "m": false, + "p": "7140.02000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749182893, - "a": 284861838, - "f": 310208150, - "l": 310208150, - "m": true, - "p": "9032.18000000", - "q": "0.09534000" + "T": 1577978159142, + "a": 202790833, + "f": 222825956, + "l": 222825956, + "m": false, + "p": "7140.02000000", + "q": "0.00511800" }, { "M": true, - "T": 1588749183145, - "a": 284861839, - "f": 310208151, - "l": 310208151, - "m": true, - "p": "9033.39000000", - "q": "0.00221300" + "T": 1577978160733, + "a": 202790834, + "f": 222825957, + "l": 222825957, + "m": false, + "p": "7140.02000000", + "q": "0.12358400" }, { "M": true, - "T": 1588749183145, - "a": 284861840, - "f": 310208152, - "l": 310208152, + "T": 1577978161099, + "a": 202790835, + "f": 222825958, + "l": 222825958, "m": true, - "p": "9032.28000000", - "q": "0.01702400" + "p": "7139.95000000", + "q": "0.13831700" }, { "M": true, - "T": 1588749183147, - "a": 284861841, - "f": 310208153, - "l": 310208153, - "m": true, - "p": "9032.28000000", - "q": "0.07709700" + "T": 1577978161103, + "a": 202790836, + "f": 222825959, + "l": 222825959, + "m": false, + "p": "7139.97000000", + "q": "0.21114500" }, { "M": true, - "T": 1588749183156, - "a": 284861842, - "f": 310208154, - "l": 310208154, - "m": true, - "p": "9032.28000000", - "q": "0.17355100" + "T": 1577978161966, + "a": 202790837, + "f": 222825960, + "l": 222825960, + "m": false, + "p": "7140.02000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749183277, - "a": 284861843, - "f": 310208155, - "l": 310208155, - "m": true, - "p": "9032.36000000", - "q": "0.06949500" + "T": 1577978162105, + "a": 202790838, + "f": 222825961, + "l": 222825961, + "m": false, + "p": "7140.02000000", + "q": "0.00167200" }, { "M": true, - "T": 1588749183300, - "a": 284861844, - "f": 310208156, - "l": 310208156, + "T": 1577978162652, + "a": 202790839, + "f": 222825962, + "l": 222825962, "m": false, - "p": "9033.73000000", - "q": "0.00300000" + "p": "7140.02000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749183418, - "a": 284861845, - "f": 310208157, - "l": 310208157, + "T": 1577978163568, + "a": 202790840, + "f": 222825963, + "l": 222825963, "m": false, - "p": "9033.15000000", - "q": "0.00719000" + "p": "7140.02000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749183418, - "a": 284861846, - "f": 310208158, - "l": 310208159, + "T": 1577978166916, + "a": 202790841, + "f": 222825964, + "l": 222825964, "m": false, - "p": "9033.66000000", - "q": "0.14309000" + "p": "7140.00000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749183418, - "a": 284861847, - "f": 310208160, - "l": 310208160, + "T": 1577978167424, + "a": 202790842, + "f": 222825965, + "l": 222825965, "m": false, - "p": "9033.67000000", - "q": "0.02665900" + "p": "7139.91000000", + "q": "0.19755000" }, { "M": true, - "T": 1588749183515, - "a": 284861848, - "f": 310208161, - "l": 310208161, + "T": 1577978167427, + "a": 202790843, + "f": 222825966, + "l": 222825966, "m": false, - "p": "9033.28000000", - "q": "0.00839500" + "p": "7140.00000000", + "q": "0.02044200" }, { "M": true, - "T": 1588749183515, - "a": 284861849, - "f": 310208162, - "l": 310208162, + "T": 1577978168331, + "a": 202790844, + "f": 222825967, + "l": 222825967, "m": false, - "p": "9033.65000000", - "q": "0.15058300" + "p": "7139.99000000", + "q": "0.00155000" }, { "M": true, - "T": 1588749183603, - "a": 284861850, - "f": 310208163, - "l": 310208163, + "T": 1577978169400, + "a": 202790845, + "f": 222825968, + "l": 222825968, "m": true, - "p": "9032.10000000", - "q": "0.00953500" + "p": "7139.83000000", + "q": "0.01607100" }, { "M": true, - "T": 1588749183603, - "a": 284861851, - "f": 310208164, - "l": 310208164, - "m": true, - "p": "9032.03000000", - "q": "0.00221300" + "T": 1577978169499, + "a": 202790846, + "f": 222825969, + "l": 222825969, + "m": false, + "p": "7140.02000000", + "q": "0.00381200" }, { "M": true, - "T": 1588749183603, - "a": 284861852, - "f": 310208165, - "l": 310208165, - "m": true, - "p": "9031.86000000", - "q": "0.04825900" + "T": 1577978170138, + "a": 202790847, + "f": 222825970, + "l": 222825970, + "m": false, + "p": "7140.02000000", + "q": "0.00161600" }, { "M": true, - "T": 1588749183915, - "a": 284861853, - "f": 310208166, - "l": 310208166, + "T": 1577978171872, + "a": 202790848, + "f": 222825971, + "l": 222825971, "m": false, - "p": "9033.01000000", - "q": "0.01927000" + "p": "7140.02000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749183932, - "a": 284861854, - "f": 310208167, - "l": 310208167, + "T": 1577978172140, + "a": 202790849, + "f": 222825972, + "l": 222825972, "m": true, - "p": "9032.75000000", - "q": "0.00300000" + "p": "7140.01000000", + "q": "0.05732200" }, { "M": true, - "T": 1588749183932, - "a": 284861855, - "f": 310208168, - "l": 310208168, - "m": true, - "p": "9031.87000000", - "q": "0.00221400" + "T": 1577978172989, + "a": 202790850, + "f": 222825973, + "l": 222825973, + "m": false, + "p": "7140.02000000", + "q": "0.00867600" }, { "M": true, - "T": 1588749183932, - "a": 284861856, - "f": 310208169, - "l": 310208169, + "T": 1577978173824, + "a": 202790851, + "f": 222825974, + "l": 222825974, "m": true, - "p": "9031.73000000", - "q": "0.00300000" + "p": "7140.01000000", + "q": "0.13749600" }, { "M": true, - "T": 1588749183932, - "a": 284861857, - "f": 310208170, - "l": 310208170, - "m": true, - "p": "9031.71000000", - "q": "0.05227700" + "T": 1577978174535, + "a": 202790852, + "f": 222825975, + "l": 222825975, + "m": false, + "p": "7140.02000000", + "q": "0.00166600" }, { "M": true, - "T": 1588749183942, - "a": 284861858, - "f": 310208171, - "l": 310208171, + "T": 1577978175080, + "a": 202790853, + "f": 222825976, + "l": 222825976, "m": true, - "p": "9031.71000000", - "q": "0.00290800" + "p": "7140.01000000", + "q": "0.84151400" }, { "M": true, - "T": 1588749184156, - "a": 284861859, - "f": 310208172, - "l": 310208172, + "T": 1577978176878, + "a": 202790854, + "f": 222825977, + "l": 222825977, "m": false, - "p": "9032.90000000", - "q": "0.00442600" + "p": "7140.00000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749184156, - "a": 284861860, - "f": 310208173, - "l": 310208173, + "T": 1577978176928, + "a": 202790855, + "f": 222825978, + "l": 222825978, "m": false, - "p": "9032.91000000", - "q": "0.00272300" - }, - { - "M": true, - "T": 1588749184261, - "a": 284861861, - "f": 310208174, - "l": 310208174, - "m": true, - "p": "9031.97000000", - "q": "0.06045200" + "p": "7140.00000000", + "q": "0.07686500" }, { "M": true, - "T": 1588749184474, - "a": 284861862, - "f": 310208175, - "l": 310208175, + "T": 1577978177186, + "a": 202790856, + "f": 222825979, + "l": 222825979, "m": true, - "p": "9032.33000000", - "q": "0.00920000" + "p": "7139.83000000", + "q": "0.02437600" }, { "M": true, - "T": 1588749184588, - "a": 284861863, - "f": 310208176, - "l": 310208176, + "T": 1577978177559, + "a": 202790857, + "f": 222825980, + "l": 222825980, "m": true, - "p": "9032.33000000", - "q": "0.00003500" + "p": "7139.83000000", + "q": "0.01945700" }, { "M": true, - "T": 1588749184588, - "a": 284861864, - "f": 310208177, - "l": 310208177, - "m": true, - "p": "9032.25000000", - "q": "0.06015000" + "T": 1577978179327, + "a": 202790858, + "f": 222825981, + "l": 222825981, + "m": false, + "p": "7140.02000000", + "q": "0.00579000" }, { "M": true, - "T": 1588749184914, - "a": 284861865, - "f": 310208178, - "l": 310208178, - "m": true, - "p": "9031.99000000", - "q": "0.00221400" + "T": 1577978181189, + "a": 202790859, + "f": 222825982, + "l": 222825982, + "m": false, + "p": "7140.00000000", + "q": "0.09726100" }, { "M": true, - "T": 1588749184914, - "a": 284861866, - "f": 310208179, - "l": 310208179, - "m": true, - "p": "9031.74000000", - "q": "0.05806900" + "T": 1577978181189, + "a": 202790860, + "f": 222825983, + "l": 222825983, + "m": false, + "p": "7140.02000000", + "q": "0.18285000" }, { "M": true, - "T": 1588749185212, - "a": 284861867, - "f": 310208180, - "l": 310208180, - "m": true, - "p": "9031.80000000", - "q": "0.00885800" + "T": 1577978181601, + "a": 202790861, + "f": 222825984, + "l": 222825984, + "m": false, + "p": "7139.88000000", + "q": "0.26607200" }, { "M": true, - "T": 1588749185242, - "a": 284861868, - "f": 310208181, - "l": 310208181, - "m": true, - "p": "9031.81000000", - "q": "0.06019800" + "T": 1577978181886, + "a": 202790862, + "f": 222825985, + "l": 222825985, + "m": false, + "p": "7140.02000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749185555, - "a": 284861869, - "f": 310208182, - "l": 310208182, - "m": true, - "p": "9031.82000000", - "q": "0.00120000" + "T": 1577978182073, + "a": 202790863, + "f": 222825986, + "l": 222825986, + "m": false, + "p": "7140.02000000", + "q": "0.00154000" }, { "M": true, - "T": 1588749185571, - "a": 284861870, - "f": 310208183, - "l": 310208183, - "m": true, - "p": "9031.83000000", - "q": "0.06025900" + "T": 1577978182762, + "a": 202790864, + "f": 222825987, + "l": 222825987, + "m": false, + "p": "7140.02000000", + "q": "0.00160000" }, { "M": true, - "T": 1588749185911, - "a": 284861871, - "f": 310208184, - "l": 310208184, + "T": 1577978184426, + "a": 202790865, + "f": 222825988, + "l": 222825988, "m": true, - "p": "9031.80000000", - "q": "0.06062400" + "p": "7140.01000000", + "q": "0.02804100" }, { "M": true, - "T": 1588749186223, - "a": 284861872, - "f": 310208185, - "l": 310208185, + "T": 1577978184426, + "a": 202790866, + "f": 222825989, + "l": 222825989, "m": true, - "p": "9032.53000000", - "q": "0.06027700" + "p": "7139.94000000", + "q": "0.07508100" }, { "M": true, - "T": 1588749186551, - "a": 284861873, - "f": 310208186, - "l": 310208186, + "T": 1577978184636, + "a": 202790867, + "f": 222825990, + "l": 222825990, "m": true, - "p": "9032.53000000", - "q": "0.06019100" + "p": "7139.86000000", + "q": "0.05120700" }, { "M": true, - "T": 1588749186865, - "a": 284861874, - "f": 310208187, - "l": 310208187, + "T": 1577978185003, + "a": 202790868, + "f": 222825991, + "l": 222825991, "m": true, - "p": "9032.53000000", - "q": "0.06023900" + "p": "7139.81000000", + "q": "0.00205100" }, { "M": true, - "T": 1588749186900, - "a": 284861875, - "f": 310208188, - "l": 310208188, - "m": true, - "p": "9032.53000000", - "q": "0.01619300" + "T": 1577978185684, + "a": 202790869, + "f": 222825992, + "l": 222825992, + "m": false, + "p": "7140.01000000", + "q": "0.00990000" }, { "M": true, - "T": 1588749187078, - "a": 284861876, - "f": 310208189, - "l": 310208189, + "T": 1577978186071, + "a": 202790870, + "f": 222825993, + "l": 222825993, "m": true, - "p": "9032.53000000", - "q": "0.24595300" + "p": "7139.82000000", + "q": "0.02162000" }, { "M": true, - "T": 1588749187182, - "a": 284861877, - "f": 310208190, - "l": 310208190, + "T": 1577978186183, + "a": 202790871, + "f": 222825994, + "l": 222825994, "m": true, - "p": "9032.53000000", - "q": "0.06012200" + "p": "7139.82000000", + "q": "0.00931200" }, { "M": true, - "T": 1588749187502, - "a": 284861878, - "f": 310208191, - "l": 310208191, + "T": 1577978186311, + "a": 202790872, + "f": 222825995, + "l": 222825995, "m": true, - "p": "9032.53000000", - "q": "0.00730100" + "p": "7139.82000000", + "q": "0.03067900" }, { "M": true, - "T": 1588749187510, - "a": 284861879, - "f": 310208192, - "l": 310208192, - "m": true, - "p": "9032.53000000", - "q": "0.00000300" + "T": 1577978186946, + "a": 202790873, + "f": 222825996, + "l": 222825996, + "m": false, + "p": "7140.02000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749187510, - "a": 284861880, - "f": 310208193, - "l": 310208193, - "m": true, - "p": "9031.79000000", - "q": "0.00221400" + "T": 1577978187538, + "a": 202790874, + "f": 222825997, + "l": 222825997, + "m": false, + "p": "7140.02000000", + "q": "0.19320000" }, { "M": true, - "T": 1588749187510, - "a": 284861881, - "f": 310208194, - "l": 310208194, + "T": 1577978187926, + "a": 202790875, + "f": 222825998, + "l": 222825998, "m": true, - "p": "9031.71000000", - "q": "0.05812700" + "p": "7140.01000000", + "q": "0.00216700" }, { "M": true, - "T": 1588749187746, - "a": 284861882, - "f": 310208195, - "l": 310208195, - "m": true, - "p": "9031.71000000", - "q": "0.00221400" + "T": 1577978191140, + "a": 202790876, + "f": 222825999, + "l": 222825999, + "m": false, + "p": "7140.02000000", + "q": "0.00156400" }, { "M": true, - "T": 1588749187746, - "a": 284861883, - "f": 310208196, - "l": 310208196, - "m": true, - "p": "9031.71000000", - "q": "0.00221400" + "T": 1577978191872, + "a": 202790877, + "f": 222826000, + "l": 222826000, + "m": false, + "p": "7140.02000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749187821, - "a": 284861884, - "f": 310208197, - "l": 310208197, + "T": 1577978193456, + "a": 202790878, + "f": 222826001, + "l": 222826001, "m": true, - "p": "9031.71000000", - "q": "0.06015000" + "p": "7139.93000000", + "q": "0.02538200" }, { "M": true, - "T": 1588749187829, - "a": 284861885, - "f": 310208198, - "l": 310208198, + "T": 1577978193782, + "a": 202790879, + "f": 222826002, + "l": 222826002, "m": true, - "p": "9031.71000000", - "q": "0.37458200" + "p": "7139.82000000", + "q": "0.02899500" }, { "M": true, - "T": 1588749187834, - "a": 284861886, - "f": 310208199, - "l": 310208199, + "T": 1577978196155, + "a": 202790880, + "f": 222826003, + "l": 222826003, "m": false, - "p": "9031.72000000", - "q": "0.05319600" + "p": "7140.00000000", + "q": "0.13960400" }, { "M": true, - "T": 1588749187847, - "a": 284861887, - "f": 310208200, - "l": 310208200, - "m": true, - "p": "9031.71000000", - "q": "0.00221400" + "T": 1577978196158, + "a": 202790881, + "f": 222826004, + "l": 222826004, + "m": false, + "p": "7139.91000000", + "q": "0.18814400" }, { "M": true, - "T": 1588749187850, - "a": 284861888, - "f": 310208201, - "l": 310208201, - "m": true, - "p": "9031.71000000", - "q": "0.00221400" + "T": 1577978196227, + "a": 202790882, + "f": 222826005, + "l": 222826005, + "m": false, + "p": "7140.02000000", + "q": "0.02899400" }, { "M": true, - "T": 1588749187930, - "a": 284861889, - "f": 310208202, - "l": 310208202, + "T": 1577978196358, + "a": 202790883, + "f": 222826006, + "l": 222826006, "m": true, - "p": "9031.71000000", - "q": "0.00621200" + "p": "7139.85000000", + "q": "0.06743600" }, { "M": true, - "T": 1588749187969, - "a": 284861890, - "f": 310208203, - "l": 310208203, - "m": true, - "p": "9031.71000000", - "q": "0.01000000" + "T": 1577978196879, + "a": 202790884, + "f": 222826007, + "l": 222826007, + "m": false, + "p": "7140.02000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749188021, - "a": 284861891, - "f": 310208204, - "l": 310208204, - "m": true, - "p": "9031.71000000", - "q": "0.00199400" + "T": 1577978198125, + "a": 202790885, + "f": 222826008, + "l": 222826008, + "m": false, + "p": "7140.02000000", + "q": "0.02899400" }, { "M": true, - "T": 1588749188137, - "a": 284861892, - "f": 310208205, - "l": 310208205, + "T": 1577978198982, + "a": 202790886, + "f": 222826009, + "l": 222826009, "m": true, - "p": "9031.71000000", - "q": "0.00199400" + "p": "7139.88000000", + "q": "0.04423900" }, { "M": true, - "T": 1588749188141, - "a": 284861893, - "f": 310208206, - "l": 310208206, - "m": true, - "p": "9031.71000000", - "q": "0.06028800" + "T": 1577978199359, + "a": 202790887, + "f": 222826010, + "l": 222826010, + "m": false, + "p": "7140.02000000", + "q": "0.00161600" }, { "M": true, - "T": 1588749188167, - "a": 284861894, - "f": 310208207, - "l": 310208207, - "m": true, - "p": "9031.71000000", - "q": "0.93346800" + "T": 1577978200234, + "a": 202790888, + "f": 222826011, + "l": 222826011, + "m": false, + "p": "7139.91000000", + "q": "0.03397800" }, { "M": true, - "T": 1588749188360, - "a": 284861895, - "f": 310208208, - "l": 310208208, - "m": true, - "p": "9030.72000000", - "q": "0.00299700" + "T": 1577978200234, + "a": 202790889, + "f": 222826012, + "l": 222826012, + "m": false, + "p": "7140.00000000", + "q": "0.01226300" }, { "M": true, - "T": 1588749188412, - "a": 284861896, - "f": 310208209, - "l": 310208209, - "m": true, - "p": "9030.72000000", - "q": "0.00000300" + "T": 1577978200542, + "a": 202790890, + "f": 222826013, + "l": 222826013, + "m": false, + "p": "7140.00000000", + "q": "0.01163700" }, { "M": true, - "T": 1588749188412, - "a": 284861897, - "f": 310208210, - "l": 310208210, - "m": true, - "p": "9030.10000000", - "q": "0.00221100" + "T": 1577978201892, + "a": 202790891, + "f": 222826014, + "l": 222826014, + "m": false, + "p": "7140.00000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749188417, - "a": 284861898, - "f": 310208211, - "l": 310208211, - "m": true, - "p": "9030.10000000", - "q": "0.00078900" + "T": 1577978202620, + "a": 202790892, + "f": 222826015, + "l": 222826018, + "m": false, + "p": "7140.02000000", + "q": "0.10000000" }, { "M": true, - "T": 1588749188417, - "a": 284861899, - "f": 310208212, - "l": 310208212, - "m": true, - "p": "9029.71000000", - "q": "0.00142500" + "T": 1577978202635, + "a": 202790893, + "f": 222826019, + "l": 222826019, + "m": false, + "p": "7140.02000000", + "q": "0.05743000" }, { "M": true, - "T": 1588749188417, - "a": 284861900, - "f": 310208213, - "l": 310208213, - "m": true, - "p": "9029.71000000", - "q": "0.00157500" + "T": 1577978202635, + "a": 202790894, + "f": 222826020, + "l": 222826020, + "m": false, + "p": "7140.09000000", + "q": "0.01969500" }, { "M": true, - "T": 1588749188417, - "a": 284861901, - "f": 310208214, - "l": 310208214, - "m": true, - "p": "9029.63000000", - "q": "0.00063900" + "T": 1577978202635, + "a": 202790895, + "f": 222826021, + "l": 222826021, + "m": false, + "p": "7141.20000000", + "q": "0.00220000" }, { "M": true, - "T": 1588749188418, - "a": 284861902, - "f": 310208215, - "l": 310208215, - "m": true, - "p": "9029.63000000", - "q": "0.00221400" + "T": 1577978202635, + "a": 202790896, + "f": 222826022, + "l": 222826022, + "m": false, + "p": "7141.35000000", + "q": "0.11382600" }, { "M": true, - "T": 1588749188476, - "a": 284861903, - "f": 310208216, - "l": 310208216, - "m": true, - "p": "9029.63000000", - "q": "0.06170800" + "T": 1577978202635, + "a": 202790897, + "f": 222826023, + "l": 222826023, + "m": false, + "p": "7141.67000000", + "q": "0.20684900" }, { "M": true, - "T": 1588749188538, - "a": 284861904, - "f": 310208217, - "l": 310208217, + "T": 1577978202745, + "a": 202790898, + "f": 222826024, + "l": 222826024, "m": false, - "p": "9029.64000000", - "q": "0.00307900" + "p": "7140.77000000", + "q": "0.10414900" }, { "M": true, - "T": 1588749188562, - "a": 284861905, - "f": 310208218, - "l": 310208218, + "T": 1577978202868, + "a": 202790899, + "f": 222826025, + "l": 222826025, "m": true, - "p": "9029.63000000", - "q": "0.03884100" + "p": "7140.58000000", + "q": "0.06035100" }, { "M": true, - "T": 1588749188966, - "a": 284861906, - "f": 310208219, - "l": 310208219, + "T": 1577978203085, + "a": 202790900, + "f": 222826026, + "l": 222826026, "m": true, - "p": "9028.83000000", - "q": "0.08963200" + "p": "7141.15000000", + "q": "0.01740000" }, { "M": true, - "T": 1588749189292, - "a": 284861907, - "f": 310208220, - "l": 310208220, + "T": 1577978203184, + "a": 202790901, + "f": 222826027, + "l": 222826027, "m": true, - "p": "9028.96000000", - "q": "0.06004700" + "p": "7141.16000000", + "q": "0.07520000" }, { "M": true, - "T": 1588749189334, - "a": 284861908, - "f": 310208221, - "l": 310208221, + "T": 1577978203267, + "a": 202790902, + "f": 222826028, + "l": 222826028, "m": true, - "p": "9028.96000000", - "q": "0.02612300" + "p": "7141.20000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749189334, - "a": 284861909, - "f": 310208222, - "l": 310208223, + "T": 1577978203279, + "a": 202790903, + "f": 222826029, + "l": 222826029, "m": true, - "p": "9028.95000000", - "q": "0.27271600" + "p": "7141.20000000", + "q": "0.01520000" }, { "M": true, - "T": 1588749189422, - "a": 284861910, - "f": 310208224, - "l": 310208224, - "m": true, - "p": "9028.69000000", - "q": "0.00299600" + "T": 1577978203362, + "a": 202790904, + "f": 222826030, + "l": 222826030, + "m": false, + "p": "7141.64000000", + "q": "0.03080700" }, { "M": true, - "T": 1588749189622, - "a": 284861911, - "f": 310208225, - "l": 310208225, + "T": 1577978203380, + "a": 202790905, + "f": 222826031, + "l": 222826031, "m": true, - "p": "9028.69000000", - "q": "0.00000400" + "p": "7141.22000000", + "q": "0.00376300" }, { "M": true, - "T": 1588749189622, - "a": 284861912, - "f": 310208226, - "l": 310208226, + "T": 1577978203665, + "a": 202790906, + "f": 222826032, + "l": 222826032, "m": true, - "p": "9028.57000000", - "q": "0.00113500" + "p": "7141.45000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749189622, - "a": 284861913, - "f": 310208227, - "l": 310208227, + "T": 1577978204446, + "a": 202790907, + "f": 222826033, + "l": 222826033, "m": true, - "p": "9028.03000000", - "q": "0.05906800" + "p": "7141.85000000", + "q": "0.01667500" }, { "M": true, - "T": 1588749189726, - "a": 284861914, - "f": 310208228, - "l": 310208228, + "T": 1577978204572, + "a": 202790908, + "f": 222826034, + "l": 222826034, "m": true, - "p": "9028.01000000", - "q": "0.00698500" + "p": "7141.91000000", + "q": "0.01589500" }, { "M": true, - "T": 1588749189803, - "a": 284861915, - "f": 310208229, - "l": 310208229, + "T": 1577978205794, + "a": 202790909, + "f": 222826035, + "l": 222826035, "m": false, - "p": "9028.84000000", - "q": "0.00307900" + "p": "7142.68000000", + "q": "0.00158500" }, { "M": true, - "T": 1588749189830, - "a": 284861916, - "f": 310208230, - "l": 310208230, + "T": 1577978205942, + "a": 202790910, + "f": 222826036, + "l": 222826036, "m": true, - "p": "9028.04000000", - "q": "0.00698400" + "p": "7142.06000000", + "q": "0.05003300" }, { "M": true, - "T": 1588749189931, - "a": 284861917, - "f": 310208231, - "l": 310208231, + "T": 1577978206038, + "a": 202790911, + "f": 222826037, + "l": 222826037, "m": true, - "p": "9028.09000000", - "q": "0.01127800" + "p": "7142.14000000", + "q": "0.01667500" }, { "M": true, - "T": 1588749190033, - "a": 284861918, - "f": 310208232, - "l": 310208232, - "m": false, - "p": "9029.10000000", - "q": "0.00442700" - }, - { - "M": true, - "T": 1588749190033, - "a": 284861919, - "f": 310208233, - "l": 310208233, - "m": false, - "p": "9030.11000000", - "q": "0.00166900" - }, - { - "M": true, - "T": 1588749190045, - "a": 284861920, - "f": 310208234, - "l": 310208234, + "T": 1577978206155, + "a": 202790912, + "f": 222826038, + "l": 222826038, "m": true, - "p": "9028.14000000", - "q": "0.00919400" + "p": "7142.20000000", + "q": "0.01551900" }, { "M": true, - "T": 1588749190149, - "a": 284861921, - "f": 310208235, - "l": 310208236, - "m": false, - "p": "9029.37000000", - "q": "0.03229900" + "T": 1577978206647, + "a": 202790913, + "f": 222826039, + "l": 222826039, + "m": true, + "p": "7142.32000000", + "q": "0.03079700" }, { "M": true, - "T": 1588749190151, - "a": 284861922, - "f": 310208237, - "l": 310208237, + "T": 1577978206647, + "a": 202790914, + "f": 222826040, + "l": 222826040, "m": true, - "p": "9028.20000000", - "q": "0.03402300" + "p": "7142.31000000", + "q": "0.00952300" }, { "M": true, - "T": 1588749190154, - "a": 284861923, - "f": 310208238, - "l": 310208238, + "T": 1577978206899, + "a": 202790915, + "f": 222826041, + "l": 222826042, "m": false, - "p": "9029.37000000", - "q": "0.37212900" + "p": "7143.42000000", + "q": "0.05348100" }, { "M": true, - "T": 1588749190154, - "a": 284861924, - "f": 310208239, - "l": 310208239, + "T": 1577978206995, + "a": 202790916, + "f": 222826043, + "l": 222826043, "m": false, - "p": "9029.38000000", - "q": "0.00974200" + "p": "7143.42000000", + "q": "0.00420000" }, { "M": true, - "T": 1588749190154, - "a": 284861925, - "f": 310208240, - "l": 310208240, - "m": false, - "p": "9029.58000000", - "q": "0.14198900" + "T": 1577978207056, + "a": 202790917, + "f": 222826044, + "l": 222826044, + "m": true, + "p": "7142.32000000", + "q": "0.03079700" }, { "M": true, - "T": 1588749190154, - "a": 284861926, - "f": 310208241, - "l": 310208241, - "m": false, - "p": "9030.12000000", - "q": "0.30000000" + "T": 1577978207056, + "a": 202790918, + "f": 222826045, + "l": 222826045, + "m": true, + "p": "7142.31000000", + "q": "0.00952300" }, { "M": true, - "T": 1588749190154, - "a": 284861927, - "f": 310208242, - "l": 310208242, + "T": 1577978207122, + "a": 202790919, + "f": 222826046, + "l": 222826046, "m": false, - "p": "9030.95000000", - "q": "0.22905500" + "p": "7142.94000000", + "q": "0.19980900" }, { "M": true, - "T": 1588749190154, - "a": 284861928, - "f": 310208243, - "l": 310208243, - "m": false, - "p": "9030.98000000", - "q": "0.02900000" + "T": 1577978209539, + "a": 202790920, + "f": 222826047, + "l": 222826047, + "m": true, + "p": "7142.59000000", + "q": "0.01424500" }, { "M": true, - "T": 1588749190154, - "a": 284861929, - "f": 310208244, - "l": 310208244, - "m": false, - "p": "9031.00000000", - "q": "0.20000000" + "T": 1577978209646, + "a": 202790921, + "f": 222826048, + "l": 222826048, + "m": true, + "p": "7142.59000000", + "q": "0.09262400" }, { "M": true, - "T": 1588749190154, - "a": 284861930, - "f": 310208245, - "l": 310208245, - "m": false, - "p": "9031.42000000", - "q": "0.50000000" + "T": 1577978210727, + "a": 202790922, + "f": 222826049, + "l": 222826049, + "m": true, + "p": "7142.61000000", + "q": "0.00283900" }, { "M": true, - "T": 1588749190154, - "a": 284861931, - "f": 310208246, - "l": 310208246, - "m": false, - "p": "9031.45000000", - "q": "0.20004600" + "T": 1577978211726, + "a": 202790923, + "f": 222826050, + "l": 222826050, + "m": true, + "p": "7142.61000000", + "q": "0.05216500" }, { "M": true, - "T": 1588749190154, - "a": 284861932, - "f": 310208247, - "l": 310208247, - "m": false, - "p": "9031.46000000", - "q": "0.20000000" + "T": 1577978211748, + "a": 202790924, + "f": 222826051, + "l": 222826051, + "m": true, + "p": "7143.09000000", + "q": "0.05892500" }, { "M": true, - "T": 1588749190154, - "a": 284861933, - "f": 310208248, - "l": 310208248, - "m": false, - "p": "9031.68000000", - "q": "1.00005200" + "T": 1577978211752, + "a": 202790925, + "f": 222826052, + "l": 222826052, + "m": true, + "p": "7142.61000000", + "q": "0.00000400" }, { "M": true, - "T": 1588749190154, - "a": 284861934, - "f": 310208249, - "l": 310208249, - "m": false, - "p": "9031.69000000", - "q": "0.08000000" + "T": 1577978211835, + "a": 202790926, + "f": 222826053, + "l": 222826053, + "m": true, + "p": "7142.58000000", + "q": "0.01424600" }, { "M": true, - "T": 1588749190154, - "a": 284861935, - "f": 310208250, - "l": 310208250, - "m": false, - "p": "9031.72000000", - "q": "0.35984500" + "T": 1577978212570, + "a": 202790927, + "f": 222826054, + "l": 222826054, + "m": true, + "p": "7142.44000000", + "q": "0.02430100" }, { "M": true, - "T": 1588749190201, - "a": 284861936, - "f": 310208251, - "l": 310208251, + "T": 1577978212575, + "a": 202790928, + "f": 222826055, + "l": 222826055, "m": true, - "p": "9028.46000000", - "q": "0.10490800" + "p": "7142.44000000", + "q": "0.04857800" }, { "M": true, - "T": 1588749190252, - "a": 284861937, - "f": 310208252, - "l": 310208252, + "T": 1577978212697, + "a": 202790929, + "f": 222826056, + "l": 222826056, "m": true, - "p": "9028.49000000", - "q": "0.00199400" + "p": "7142.47000000", + "q": "0.21035500" }, { "M": true, - "T": 1588749190397, - "a": 284861938, - "f": 310208253, - "l": 310208253, + "T": 1577978212723, + "a": 202790930, + "f": 222826057, + "l": 222826057, "m": true, - "p": "9029.01000000", - "q": "4.00000000" + "p": "7142.49000000", + "q": "0.35062500" }, { "M": true, - "T": 1588749190397, - "a": 284861939, - "f": 310208254, - "l": 310208254, - "m": true, - "p": "9028.60000000", - "q": "0.09706700" + "T": 1577978213222, + "a": 202790931, + "f": 222826058, + "l": 222826058, + "m": false, + "p": "7142.61000000", + "q": "0.01312800" }, { "M": true, - "T": 1588749190397, - "a": 284861940, - "f": 310208255, - "l": 310208257, - "m": true, - "p": "9028.58000000", - "q": "3.26721400" + "T": 1577978214018, + "a": 202790932, + "f": 222826059, + "l": 222826059, + "m": false, + "p": "7142.61000000", + "q": "0.00165400" }, { "M": true, - "T": 1588749190397, - "a": 284861941, - "f": 310208258, - "l": 310208258, + "T": 1577978214242, + "a": 202790933, + "f": 222826060, + "l": 222826060, "m": true, - "p": "9028.55000000", - "q": "0.17701700" + "p": "7142.60000000", + "q": "0.00545400" }, { "M": true, - "T": 1588749190397, - "a": 284861942, - "f": 310208259, - "l": 310208259, + "T": 1577978216570, + "a": 202790934, + "f": 222826061, + "l": 222826061, "m": true, - "p": "9028.41000000", - "q": "4.00000000" + "p": "7142.93000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749190397, - "a": 284861943, - "f": 310208260, - "l": 310208260, + "T": 1577978217001, + "a": 202790935, + "f": 222826062, + "l": 222826062, "m": true, - "p": "9028.21000000", - "q": "5.10113600" + "p": "7143.02000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749190465, - "a": 284861944, - "f": 310208261, - "l": 310208261, + "T": 1577978217204, + "a": 202790936, + "f": 222826063, + "l": 222826063, "m": false, - "p": "9030.16000000", - "q": "0.00220800" + "p": "7143.39000000", + "q": "0.03079700" }, { "M": true, - "T": 1588749190470, - "a": 284861945, - "f": 310208262, - "l": 310208262, + "T": 1577978217449, + "a": 202790937, + "f": 222826064, + "l": 222826064, "m": true, - "p": "9028.94000000", - "q": "0.02839700" + "p": "7143.06000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749190564, - "a": 284861946, - "f": 310208263, - "l": 310208263, + "T": 1577978217823, + "a": 202790938, + "f": 222826065, + "l": 222826065, "m": true, - "p": "9028.95000000", - "q": "0.00221000" + "p": "7143.37000000", + "q": "0.05189100" }, { "M": true, - "T": 1588749190677, - "a": 284861947, - "f": 310208264, - "l": 310208264, + "T": 1577978217841, + "a": 202790939, + "f": 222826066, + "l": 222826066, "m": true, - "p": "9029.14000000", - "q": "0.00974500" + "p": "7143.09000000", + "q": "0.02414700" }, { "M": true, - "T": 1588749190765, - "a": 284861948, - "f": 310208265, - "l": 310208265, + "T": 1577978217879, + "a": 202790940, + "f": 222826067, + "l": 222826067, "m": true, - "p": "9029.14000000", - "q": "0.01195500" + "p": "7143.09000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749190870, - "a": 284861949, - "f": 310208266, - "l": 310208266, + "T": 1577978218312, + "a": 202790941, + "f": 222826068, + "l": 222826068, "m": true, - "p": "9029.14000000", - "q": "0.01195500" + "p": "7143.09000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749190874, - "a": 284861950, - "f": 310208267, - "l": 310208267, - "m": false, - "p": "9029.15000000", - "q": "0.00265100" + "T": 1577978218585, + "a": 202790942, + "f": 222826069, + "l": 222826069, + "m": true, + "p": "7143.11000000", + "q": "0.06909600" }, { "M": true, - "T": 1588749191013, - "a": 284861951, - "f": 310208268, - "l": 310208268, + "T": 1577978218625, + "a": 202790943, + "f": 222826070, + "l": 222826070, "m": true, - "p": "9029.14000000", - "q": "0.01195700" + "p": "7143.15000000", + "q": "0.21033500" + }, + { + "M": true, + "T": 1577978218800, + "a": 202790944, + "f": 222826071, + "l": 222826071, + "m": false, + "p": "7143.49000000", + "q": "0.00377600" }, { "M": true, - "T": 1588749191082, - "a": 284861952, - "f": 310208269, - "l": 310208269, + "T": 1577978218806, + "a": 202790945, + "f": 222826072, + "l": 222826072, "m": true, - "p": "9029.14000000", - "q": "0.01195700" + "p": "7143.11000000", + "q": "0.00783100" }, { "M": true, - "T": 1588749191189, - "a": 284861953, - "f": 310208270, - "l": 310208270, + "T": 1577978218828, + "a": 202790946, + "f": 222826073, + "l": 222826073, "m": true, - "p": "9029.14000000", - "q": "0.01195900" + "p": "7143.15000000", + "q": "0.26186500" }, { "M": true, - "T": 1588749191197, - "a": 284861954, - "f": 310208271, - "l": 310208272, + "T": 1577978219488, + "a": 202790947, + "f": 222826074, + "l": 222826074, "m": false, - "p": "9029.15000000", - "q": "0.00133800" + "p": "7143.49000000", + "q": "0.00001300" }, { "M": true, - "T": 1588749191278, - "a": 284861955, - "f": 310208273, - "l": 310208273, - "m": true, - "p": "9029.14000000", - "q": "0.01916400" + "T": 1577978219488, + "a": 202790948, + "f": 222826075, + "l": 222826075, + "m": false, + "p": "7143.97000000", + "q": "0.01198600" }, { "M": true, - "T": 1588749191304, - "a": 284861956, - "f": 310208274, - "l": 310208274, + "T": 1577978219786, + "a": 202790949, + "f": 222826076, + "l": 222826076, "m": true, - "p": "9029.14000000", - "q": "0.01195900" + "p": "7143.16000000", + "q": "0.04032000" }, { "M": true, - "T": 1588749191766, - "a": 284861957, - "f": 310208275, - "l": 310208275, + "T": 1577978220237, + "a": 202790950, + "f": 222826077, + "l": 222826077, "m": false, - "p": "9030.00000000", - "q": "0.00460200" + "p": "7143.97000000", + "q": "0.00167600" }, { "M": true, - "T": 1588749191819, - "a": 284861958, - "f": 310208276, - "l": 310208276, + "T": 1577978221383, + "a": 202790951, + "f": 222826078, + "l": 222826078, "m": true, - "p": "9029.56000000", - "q": "0.03379500" + "p": "7143.74000000", + "q": "0.27253200" }, { "M": true, - "T": 1588749191861, - "a": 284861959, - "f": 310208277, - "l": 310208277, + "T": 1577978224368, + "a": 202790952, + "f": 222826079, + "l": 222826079, "m": true, - "p": "9029.57000000", - "q": "0.29780800" + "p": "7143.25000000", + "q": "0.10093800" }, { "M": true, - "T": 1588749192032, - "a": 284861960, - "f": 310208278, - "l": 310208278, + "T": 1577978224437, + "a": 202790953, + "f": 222826080, + "l": 222826080, "m": true, - "p": "9029.64000000", - "q": "0.01350000" + "p": "7143.27000000", + "q": "0.09567900" }, { "M": true, - "T": 1588749192142, - "a": 284861961, - "f": 310208279, - "l": 310208279, + "T": 1577978224474, + "a": 202790954, + "f": 222826081, + "l": 222826081, "m": true, - "p": "9029.67000000", - "q": "0.01195800" + "p": "7143.27000000", + "q": "0.00223200" }, { "M": true, - "T": 1588749192193, - "a": 284861962, - "f": 310208280, - "l": 310208280, + "T": 1577978224474, + "a": 202790955, + "f": 222826082, + "l": 222826082, "m": true, - "p": "9029.69000000", - "q": "0.06011400" + "p": "7143.25000000", + "q": "0.00676400" }, { "M": true, - "T": 1588749192260, - "a": 284861963, - "f": 310208281, - "l": 310208281, + "T": 1577978224474, + "a": 202790956, + "f": 222826083, + "l": 222826083, "m": true, - "p": "9029.72000000", - "q": "0.01195600" + "p": "7143.11000000", + "q": "0.59100400" }, { "M": true, - "T": 1588749192458, - "a": 284861964, - "f": 310208282, - "l": 310208282, + "T": 1577978224522, + "a": 202790957, + "f": 222826084, + "l": 222826084, "m": true, - "p": "9029.93000000", - "q": "0.00442600" + "p": "7143.11000000", + "q": "0.05196900" }, { "M": true, - "T": 1588749192524, - "a": 284861965, - "f": 310208283, - "l": 310208283, + "T": 1577978225200, + "a": 202790958, + "f": 222826085, + "l": 222826085, "m": true, - "p": "9029.93000000", - "q": "0.06026100" + "p": "7143.38000000", + "q": "0.22180000" }, { "M": true, - "T": 1588749192593, - "a": 284861966, - "f": 310208284, - "l": 310208284, + "T": 1577978225537, + "a": 202790959, + "f": 222826086, + "l": 222826086, "m": true, - "p": "9029.93000000", - "q": "0.00884600" + "p": "7142.62000000", + "q": "0.03478300" }, { "M": true, - "T": 1588749192694, - "a": 284861967, - "f": 310208285, - "l": 310208285, - "m": true, - "p": "9029.93000000", - "q": "0.01362500" - }, - { - "M": true, - "T": 1588749192782, - "a": 284861968, - "f": 310208286, - "l": 310208286, - "m": true, - "p": "9029.93000000", - "q": "0.00641500" + "T": 1577978226682, + "a": 202790960, + "f": 222826087, + "l": 222826087, + "m": false, + "p": "7143.67000000", + "q": "0.00166600" }, { "M": true, - "T": 1588749192852, - "a": 284861969, - "f": 310208287, - "l": 310208287, + "T": 1577978228129, + "a": 202790961, + "f": 222826088, + "l": 222826088, "m": true, - "p": "9029.93000000", - "q": "0.06030700" + "p": "7142.67000000", + "q": "0.02867400" }, { "M": true, - "T": 1588749192884, - "a": 284861970, - "f": 310208288, - "l": 310208288, + "T": 1577978228257, + "a": 202790962, + "f": 222826089, + "l": 222826089, "m": true, - "p": "9029.93000000", - "q": "0.00810800" + "p": "7142.68000000", + "q": "0.02863800" }, { "M": true, - "T": 1588749192911, - "a": 284861971, - "f": 310208289, - "l": 310208289, + "T": 1577978229290, + "a": 202790963, + "f": 222826090, + "l": 222826090, "m": false, - "p": "9029.94000000", - "q": "0.03682600" + "p": "7143.58000000", + "q": "0.03473400" }, { "M": true, - "T": 1588749193101, - "a": 284861972, - "f": 310208290, - "l": 310208290, + "T": 1577978230929, + "a": 202790964, + "f": 222826091, + "l": 222826091, "m": true, - "p": "9030.02000000", - "q": "0.01918000" + "p": "7142.66000000", + "q": "0.00442700" }, { "M": true, - "T": 1588749193178, - "a": 284861973, - "f": 310208291, - "l": 310208291, - "m": true, - "p": "9030.02000000", - "q": "0.06004500" + "T": 1577978232893, + "a": 202790965, + "f": 222826092, + "l": 222826092, + "m": false, + "p": "7143.26000000", + "q": "0.00157200" }, { "M": true, - "T": 1588749193507, - "a": 284861974, - "f": 310208292, - "l": 310208292, - "m": true, - "p": "9030.02000000", - "q": "0.06025700" + "T": 1577978233317, + "a": 202790966, + "f": 222826093, + "l": 222826093, + "m": false, + "p": "7143.05000000", + "q": "0.05552200" }, { "M": true, - "T": 1588749193517, - "a": 284861975, - "f": 310208293, - "l": 310208293, - "m": false, - "p": "9030.03000000", - "q": "0.17700400" + "T": 1577978233701, + "a": 202790967, + "f": 222826094, + "l": 222826094, + "m": true, + "p": "7142.65000000", + "q": "0.00990400" }, { "M": true, - "T": 1588749193517, - "a": 284861976, - "f": 310208294, - "l": 310208294, + "T": 1577978234226, + "a": 202790968, + "f": 222826095, + "l": 222826095, "m": false, - "p": "9030.09000000", - "q": "0.00221600" + "p": "7143.35000000", + "q": "0.07237800" }, { "M": true, - "T": 1588749193630, - "a": 284861977, - "f": 310208295, - "l": 310208295, + "T": 1577978234562, + "a": 202790969, + "f": 222826096, + "l": 222826096, "m": true, - "p": "9030.43000000", - "q": "0.00540100" + "p": "7142.68000000", + "q": "0.04270000" }, { "M": true, - "T": 1588749193837, - "a": 284861978, - "f": 310208296, - "l": 310208296, - "m": true, - "p": "9031.70000000", - "q": "0.06000200" + "T": 1577978235930, + "a": 202790970, + "f": 222826097, + "l": 222826097, + "m": false, + "p": "7142.96000000", + "q": "0.23392700" }, { "M": true, - "T": 1588749193842, - "a": 284861979, - "f": 310208297, - "l": 310208297, - "m": true, - "p": "9031.70000000", - "q": "0.00307900" + "T": 1577978235940, + "a": 202790971, + "f": 222826098, + "l": 222826098, + "m": false, + "p": "7143.29000000", + "q": "0.14359500" }, { "M": true, - "T": 1588749193941, - "a": 284861980, - "f": 310208298, - "l": 310208298, + "T": 1577978236234, + "a": 202790972, + "f": 222826099, + "l": 222826099, "m": true, - "p": "9031.70000000", - "q": "0.00307900" + "p": "7142.72000000", + "q": "0.00379600" }, { "M": true, - "T": 1588749194150, - "a": 284861981, - "f": 310208299, - "l": 310208299, + "T": 1577978236377, + "a": 202790973, + "f": 222826100, + "l": 222826100, "m": true, - "p": "9031.17000000", - "q": "0.00854500" + "p": "7142.65000000", + "q": "1.63354500" }, { "M": true, - "T": 1588749194201, - "a": 284861982, - "f": 310208300, - "l": 310208300, + "T": 1577978236980, + "a": 202790974, + "f": 222826101, + "l": 222826101, "m": true, - "p": "9031.42000000", - "q": "0.06523400" + "p": "7142.62000000", + "q": "0.00295000" }, { "M": true, - "T": 1588749194215, - "a": 284861983, - "f": 310208301, - "l": 310208301, - "m": false, - "p": "9031.66000000", - "q": "0.06951000" + "T": 1577978238751, + "a": 202790975, + "f": 222826102, + "l": 222826102, + "m": true, + "p": "7142.62000000", + "q": "0.00176500" }, { "M": true, - "T": 1588749194254, - "a": 284861984, - "f": 310208302, - "l": 310208302, - "m": true, - "p": "9031.65000000", - "q": "0.01355300" + "T": 1577978238794, + "a": 202790976, + "f": 222826103, + "l": 222826103, + "m": false, + "p": "7142.82000000", + "q": "0.35000000" }, { "M": true, - "T": 1588749194364, - "a": 284861985, - "f": 310208303, - "l": 310208303, - "m": true, - "p": "9031.66000000", - "q": "0.01195800" + "T": 1577978238794, + "a": 202790977, + "f": 222826104, + "l": 222826104, + "m": false, + "p": "7142.85000000", + "q": "0.03814300" }, { "M": true, - "T": 1588749194471, - "a": 284861986, - "f": 310208304, - "l": 310208304, + "T": 1577978238794, + "a": 202790978, + "f": 222826105, + "l": 222826105, "m": false, - "p": "9031.70000000", - "q": "0.01274300" + "p": "7142.89000000", + "q": "0.01185700" }, { "M": true, - "T": 1588749194525, - "a": 284861987, - "f": 310208305, - "l": 310208305, + "T": 1577978238856, + "a": 202790979, + "f": 222826106, + "l": 222826106, "m": true, - "p": "9031.69000000", - "q": "0.06002000" + "p": "7142.62000000", + "q": "0.00176500" }, { "M": true, - "T": 1588749194581, - "a": 284861988, - "f": 310208306, - "l": 310208306, - "m": true, - "p": "9031.69000000", - "q": "0.00290900" + "T": 1577978239102, + "a": 202790980, + "f": 222826107, + "l": 222826107, + "m": false, + "p": "7142.89000000", + "q": "0.00158800" }, { "M": true, - "T": 1588749194623, - "a": 284861989, - "f": 310208307, - "l": 310208307, + "T": 1577978239253, + "a": 202790981, + "f": 222826108, + "l": 222826108, "m": true, - "p": "9031.69000000", - "q": "0.01918900" + "p": "7142.62000000", + "q": "0.02000000" }, { "M": true, - "T": 1588749194793, - "a": 284861990, - "f": 310208308, - "l": 310208308, + "T": 1577978239300, + "a": 202790982, + "f": 222826109, + "l": 222826109, "m": true, - "p": "9031.69000000", - "q": "0.01038700" + "p": "7142.62000000", + "q": "0.00431500" }, { "M": true, - "T": 1588749194898, - "a": 284861991, - "f": 310208309, - "l": 310208309, + "T": 1577978239548, + "a": 202790983, + "f": 222826110, + "l": 222826110, "m": true, - "p": "9031.69000000", - "q": "0.01038700" + "p": "7142.61000000", + "q": "0.04052000" }, { "M": true, - "T": 1588749195004, - "a": 284861992, - "f": 310208310, - "l": 310208311, + "T": 1577978239745, + "a": 202790984, + "f": 222826111, + "l": 222826111, "m": false, - "p": "9031.70000000", - "q": "0.00221000" + "p": "7142.75000000", + "q": "0.24386600" }, { "M": true, - "T": 1588749195006, - "a": 284861993, - "f": 310208312, - "l": 310208312, + "T": 1577978239816, + "a": 202790985, + "f": 222826112, + "l": 222826112, "m": true, - "p": "9031.69000000", - "q": "0.01038700" + "p": "7142.61000000", + "q": "0.04052000" }, { "M": true, - "T": 1588749195110, - "a": 284861994, - "f": 310208313, - "l": 310208313, + "T": 1577978239825, + "a": 202790986, + "f": 222826113, + "l": 222826113, "m": true, - "p": "9031.69000000", - "q": "0.01038700" + "p": "7142.61000000", + "q": "0.00280000" }, { "M": true, - "T": 1588749195213, - "a": 284861995, - "f": 310208314, - "l": 310208314, + "T": 1577978239908, + "a": 202790987, + "f": 222826114, + "l": 222826114, "m": true, - "p": "9031.69000000", - "q": "0.01038700" + "p": "7142.61000000", + "q": "0.01183900" }, { "M": true, - "T": 1588749195325, - "a": 284861996, - "f": 310208315, - "l": 310208315, - "m": true, - "p": "9031.69000000", - "q": "0.00997200" + "T": 1577978239950, + "a": 202790988, + "f": 222826115, + "l": 222826115, + "m": false, + "p": "7142.57000000", + "q": "0.02240000" }, { "M": true, - "T": 1588749195365, - "a": 284861997, - "f": 310208316, - "l": 310208316, + "T": 1577978240277, + "a": 202790989, + "f": 222826116, + "l": 222826116, "m": true, - "p": "9031.69000000", - "q": "0.00300000" + "p": "7141.61000000", + "q": "0.00280000" }, { "M": true, - "T": 1588749195434, - "a": 284861998, - "f": 310208317, - "l": 310208317, + "T": 1577978240951, + "a": 202790990, + "f": 222826117, + "l": 222826117, "m": true, - "p": "9031.69000000", - "q": "0.00476600" + "p": "7141.61000000", + "q": "0.03771400" }, { "M": true, - "T": 1588749195529, - "a": 284861999, - "f": 310208318, - "l": 310208318, - "m": true, - "p": "9031.69000000", - "q": "0.00221000" + "T": 1577978241585, + "a": 202790991, + "f": 222826118, + "l": 222826118, + "m": false, + "p": "7141.73000000", + "q": "0.07684900" }, { "M": true, - "T": 1588749195844, - "a": 284862000, - "f": 310208319, - "l": 310208319, - "m": true, - "p": "9031.69000000", - "q": "0.00300000" + "T": 1577978242491, + "a": 202790992, + "f": 222826119, + "l": 222826119, + "m": false, + "p": "7141.66000000", + "q": "0.06329000" }, { "M": true, - "T": 1588749196180, - "a": 284862001, - "f": 310208320, - "l": 310208320, - "m": true, - "p": "9031.70000000", - "q": "0.01014300" + "T": 1577978244015, + "a": 202790993, + "f": 222826120, + "l": 222826120, + "m": false, + "p": "7141.62000000", + "q": "0.02284100" }, { "M": true, - "T": 1588749196492, - "a": 284862002, - "f": 310208321, - "l": 310208321, - "m": true, - "p": "9031.70000000", - "q": "0.00211800" + "T": 1577978247331, + "a": 202790994, + "f": 222826121, + "l": 222826121, + "m": false, + "p": "7141.93000000", + "q": "0.00164400" }, { "M": true, - "T": 1588749196588, - "a": 284862003, - "f": 310208322, - "l": 310208322, - "m": true, - "p": "9031.70000000", - "q": "0.00524300" + "T": 1577978247761, + "a": 202790995, + "f": 222826122, + "l": 222826122, + "m": false, + "p": "7141.76000000", + "q": "0.14245300" }, { "M": true, - "T": 1588749196638, - "a": 284862004, - "f": 310208323, - "l": 310208323, + "T": 1577978249898, + "a": 202790996, + "f": 222826123, + "l": 222826123, "m": false, - "p": "9031.71000000", - "q": "0.05563300" + "p": "7141.79000000", + "q": "0.04114500" }, { "M": true, - "T": 1588749196703, - "a": 284862005, - "f": 310208324, - "l": 310208324, - "m": true, - "p": "9031.70000000", - "q": "0.00524300" + "T": 1577978253542, + "a": 202790997, + "f": 222826124, + "l": 222826124, + "m": false, + "p": "7141.63000000", + "q": "0.00155900" }, { "M": true, - "T": 1588749196800, - "a": 284862006, - "f": 310208325, - "l": 310208325, - "m": true, - "p": "9031.70000000", - "q": "0.00524300" + "T": 1577978255027, + "a": 202790998, + "f": 222826125, + "l": 222826125, + "m": false, + "p": "7141.63000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749197323, - "a": 284862007, - "f": 310208326, - "l": 310208326, - "m": true, - "p": "9031.70000000", - "q": "0.03250000" + "T": 1577978255027, + "a": 202790999, + "f": 222826126, + "l": 222826126, + "m": false, + "p": "7141.63000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749198338, - "a": 284862008, - "f": 310208327, - "l": 310208327, + "T": 1577978255028, + "a": 202791000, + "f": 222826127, + "l": 222826127, "m": false, - "p": "9031.71000000", - "q": "0.00112700" + "p": "7141.63000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749198338, - "a": 284862009, - "f": 310208328, - "l": 310208328, + "T": 1577978255031, + "a": 202791001, + "f": 222826128, + "l": 222826128, "m": false, - "p": "9031.73000000", - "q": "0.00108700" + "p": "7141.63000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749198339, - "a": 284862010, - "f": 310208329, - "l": 310208329, + "T": 1577978255031, + "a": 202791002, + "f": 222826129, + "l": 222826129, "m": false, - "p": "9031.73000000", - "q": "0.00191300" + "p": "7141.63000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749198339, - "a": 284862011, - "f": 310208330, - "l": 310208330, + "T": 1577978255031, + "a": 202791003, + "f": 222826130, + "l": 222826130, "m": false, - "p": "9031.89000000", - "q": "0.00030100" + "p": "7141.63000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749198425, - "a": 284862012, - "f": 310208331, - "l": 310208331, - "m": true, - "p": "9031.88000000", - "q": "0.03142100" + "T": 1577978255034, + "a": 202791004, + "f": 222826131, + "l": 222826131, + "m": false, + "p": "7141.63000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749199174, - "a": 284862013, - "f": 310208332, - "l": 310208332, - "m": true, - "p": "9031.88000000", - "q": "0.02128800" + "T": 1577978255037, + "a": 202791005, + "f": 222826132, + "l": 222826132, + "m": false, + "p": "7141.63000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749199205, - "a": 284862014, - "f": 310208333, - "l": 310208333, - "m": true, - "p": "9031.88000000", - "q": "0.02126600" + "T": 1577978255038, + "a": 202791006, + "f": 222826133, + "l": 222826133, + "m": false, + "p": "7141.63000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749199260, - "a": 284862015, - "f": 310208334, - "l": 310208334, - "m": true, - "p": "9031.88000000", - "q": "0.02125100" + "T": 1577978255038, + "a": 202791007, + "f": 222826134, + "l": 222826134, + "m": false, + "p": "7141.63000000", + "q": "0.06037200" }, { "M": true, - "T": 1588749199410, - "a": 284862016, - "f": 310208335, - "l": 310208336, + "T": 1577978255038, + "a": 202791008, + "f": 222826135, + "l": 222826135, "m": false, - "p": "9031.89000000", - "q": "0.06255800" + "p": "7141.63000000", + "q": "0.00572500" }, { "M": true, - "T": 1588749199538, - "a": 284862017, - "f": 310208337, - "l": 310208337, - "m": true, - "p": "9032.48000000", - "q": "0.00307900" + "T": 1577978255038, + "a": 202791009, + "f": 222826136, + "l": 222826136, + "m": false, + "p": "7141.64000000", + "q": "0.00299100" }, { "M": true, - "T": 1588749199956, - "a": 284862018, - "f": 310208338, - "l": 310208338, - "m": true, - "p": "9032.63000000", - "q": "0.01014200" + "T": 1577978255038, + "a": 202791010, + "f": 222826137, + "l": 222826137, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749200060, - "a": 284862019, - "f": 310208339, - "l": 310208339, - "m": true, - "p": "9032.63000000", - "q": "0.00910000" + "T": 1577978255039, + "a": 202791011, + "f": 222826138, + "l": 222826138, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749200589, - "a": 284862020, - "f": 310208340, - "l": 310208340, - "m": true, - "p": "9032.63000000", - "q": "0.00271600" + "T": 1577978255039, + "a": 202791012, + "f": 222826139, + "l": 222826139, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749200992, - "a": 284862021, - "f": 310208341, - "l": 310208341, - "m": true, - "p": "9032.60000000", - "q": "0.05614900" + "T": 1577978255039, + "a": 202791013, + "f": 222826140, + "l": 222826140, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201044, - "a": 284862022, - "f": 310208342, - "l": 310208342, - "m": true, - "p": "9032.62000000", - "q": "0.00523200" + "T": 1577978255039, + "a": 202791014, + "f": 222826141, + "l": 222826141, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201125, - "a": 284862023, - "f": 310208343, - "l": 310208343, - "m": true, - "p": "9032.63000000", - "q": "0.01299900" + "T": 1577978255041, + "a": 202791015, + "f": 222826142, + "l": 222826142, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201211, - "a": 284862024, - "f": 310208344, - "l": 310208344, - "m": true, - "p": "9032.63000000", - "q": "0.01195800" + "T": 1577978255042, + "a": 202791016, + "f": 222826143, + "l": 222826143, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201317, - "a": 284862025, - "f": 310208345, - "l": 310208345, - "m": true, - "p": "9032.63000000", - "q": "0.01195800" + "T": 1577978255042, + "a": 202791017, + "f": 222826144, + "l": 222826144, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201355, - "a": 284862026, - "f": 310208346, - "l": 310208346, - "m": true, - "p": "9032.63000000", - "q": "0.00147600" + "T": 1577978255042, + "a": 202791018, + "f": 222826145, + "l": 222826145, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201425, - "a": 284862027, - "f": 310208347, - "l": 310208347, - "m": true, - "p": "9032.63000000", - "q": "0.01195800" + "T": 1577978255042, + "a": 202791019, + "f": 222826146, + "l": 222826146, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201532, - "a": 284862028, - "f": 310208348, - "l": 310208348, - "m": true, - "p": "9032.63000000", - "q": "0.00709100" + "T": 1577978255042, + "a": 202791020, + "f": 222826147, + "l": 222826147, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201606, - "a": 284862029, - "f": 310208349, - "l": 310208349, - "m": true, - "p": "9032.63000000", - "q": "0.05601900" + "T": 1577978255042, + "a": 202791021, + "f": 222826148, + "l": 222826148, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201607, - "a": 284862030, - "f": 310208350, - "l": 310208350, - "m": true, - "p": "9032.63000000", - "q": "0.15163400" + "T": 1577978255042, + "a": 202791022, + "f": 222826149, + "l": 222826149, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749201607, - "a": 284862031, - "f": 310208351, - "l": 310208351, - "m": true, - "p": "9032.62000000", - "q": "0.05601800" + "T": 1577978255042, + "a": 202791023, + "f": 222826150, + "l": 222826150, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749202148, - "a": 284862032, - "f": 310208352, - "l": 310208352, - "m": true, - "p": "9032.62000000", - "q": "0.01100000" + "T": 1577978255043, + "a": 202791024, + "f": 222826151, + "l": 222826151, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749202331, - "a": 284862033, - "f": 310208353, - "l": 310208353, + "T": 1577978255043, + "a": 202791025, + "f": 222826152, + "l": 222826152, "m": false, - "p": "9032.63000000", - "q": "0.00273900" + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749203024, - "a": 284862034, - "f": 310208354, - "l": 310208354, - "m": true, - "p": "9032.63000000", - "q": "0.00906400" + "T": 1577978255043, + "a": 202791026, + "f": 222826153, + "l": 222826153, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749204119, - "a": 284862035, - "f": 310208355, - "l": 310208355, - "m": true, - "p": "9032.63000000", - "q": "0.00919400" + "T": 1577978255045, + "a": 202791027, + "f": 222826154, + "l": 222826154, + "m": false, + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749204602, - "a": 284862036, - "f": 310208356, - "l": 310208356, + "T": 1577978255045, + "a": 202791028, + "f": 222826155, + "l": 222826155, "m": false, - "p": "9032.64000000", - "q": "0.00401000" + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749205675, - "a": 284862037, - "f": 310208357, - "l": 310208357, + "T": 1577978255051, + "a": 202791029, + "f": 222826156, + "l": 222826156, "m": false, - "p": "9032.64000000", - "q": "0.00713000" + "p": "7141.64000000", + "q": "0.00871600" }, { "M": true, - "T": 1588749206828, - "a": 284862038, - "f": 310208358, - "l": 310208358, + "T": 1577978255062, + "a": 202791030, + "f": 222826157, + "l": 222826157, "m": false, - "p": "9032.65000000", - "q": "0.00299300" + "p": "7141.64000000", + "q": "0.14984100" }, { "M": true, - "T": 1588749206834, - "a": 284862039, - "f": 310208359, - "l": 310208359, + "T": 1577978255062, + "a": 202791031, + "f": 222826158, + "l": 222826158, "m": false, - "p": "9032.65000000", - "q": "0.00000700" + "p": "7141.68000000", + "q": "0.03639900" }, { "M": true, - "T": 1588749206939, - "a": 284862040, - "f": 310208360, - "l": 310208361, - "m": false, - "p": "9032.75000000", - "q": "0.01423300" + "T": 1577978255198, + "a": 202791032, + "f": 222826159, + "l": 222826159, + "m": true, + "p": "7141.64000000", + "q": "0.00695200" + }, + { + "M": true, + "T": 1577978255281, + "a": 202791033, + "f": 222826160, + "l": 222826160, + "m": true, + "p": "7141.64000000", + "q": "0.00428700" }, { "M": true, - "T": 1588749207763, - "a": 284862041, - "f": 310208362, - "l": 310208362, + "T": 1577978255578, + "a": 202791034, + "f": 222826161, + "l": 222826161, "m": false, - "p": "9032.75000000", - "q": "0.00002100" + "p": "7141.92000000", + "q": "0.15584000" }, { "M": true, - "T": 1588749207763, - "a": 284862042, - "f": 310208363, - "l": 310208363, + "T": 1577978256106, + "a": 202791035, + "f": 222826162, + "l": 222826162, "m": false, - "p": "9033.76000000", - "q": "0.00300000" + "p": "7142.04000000", + "q": "0.07492900" }, { "M": true, - "T": 1588749207763, - "a": 284862043, - "f": 310208364, - "l": 310208364, + "T": 1577978256106, + "a": 202791036, + "f": 222826163, + "l": 222826163, "m": false, - "p": "9034.10000000", - "q": "0.00795500" + "p": "7142.05000000", + "q": "0.13816000" }, { "M": true, - "T": 1588749207763, - "a": 284862044, - "f": 310208365, - "l": 310208365, + "T": 1577978256494, + "a": 202791037, + "f": 222826164, + "l": 222826164, "m": false, - "p": "9034.29000000", - "q": "0.02587400" + "p": "7142.10000000", + "q": "0.03800000" }, { "M": true, - "T": 1588749208721, - "a": 284862045, - "f": 310208366, - "l": 310208366, + "T": 1577978257795, + "a": 202791038, + "f": 222826165, + "l": 222826165, "m": true, - "p": "9033.37000000", - "q": "0.00715900" + "p": "7141.64000000", + "q": "0.01259000" }, { "M": true, - "T": 1588749208721, - "a": 284862046, - "f": 310208367, - "l": 310208367, + "T": 1577978257947, + "a": 202791039, + "f": 222826166, + "l": 222826166, "m": true, - "p": "9033.26000000", - "q": "0.05434800" + "p": "7141.64000000", + "q": "0.02885800" }, { "M": true, - "T": 1588749208721, - "a": 284862047, - "f": 310208368, - "l": 310208368, + "T": 1577978259066, + "a": 202791040, + "f": 222826167, + "l": 222826167, "m": true, - "p": "9033.23000000", - "q": "0.06284000" + "p": "7141.64000000", + "q": "0.00025800" }, { "M": true, - "T": 1588749208721, - "a": 284862048, - "f": 310208369, - "l": 310208370, + "T": 1577978259066, + "a": 202791041, + "f": 222826168, + "l": 222826168, "m": true, - "p": "9033.22000000", - "q": "0.27565300" + "p": "7141.61000000", + "q": "0.00000600" }, { "M": true, - "T": 1588749208760, - "a": 284862049, - "f": 310208371, - "l": 310208371, + "T": 1577978259066, + "a": 202791042, + "f": 222826169, + "l": 222826169, "m": true, - "p": "9033.46000000", - "q": "0.01774100" + "p": "7140.60000000", + "q": "0.05525600" }, { "M": true, - "T": 1588749208957, - "a": 284862050, - "f": 310208372, - "l": 310208372, + "T": 1577978259950, + "a": 202791043, + "f": 222826170, + "l": 222826170, "m": false, - "p": "9034.58000000", - "q": "0.02405200" + "p": "7141.16000000", + "q": "0.23130900" }, { "M": true, - "T": 1588749209051, - "a": 284862051, - "f": 310208373, - "l": 310208373, + "T": 1577978260651, + "a": 202791044, + "f": 222826171, + "l": 222826171, "m": true, - "p": "9033.47000000", - "q": "0.00221300" + "p": "7140.80000000", + "q": "0.02898700" }, { "M": true, - "T": 1588749209051, - "a": 284862052, - "f": 310208374, - "l": 310208374, - "m": true, - "p": "9033.24000000", - "q": "0.00964300" + "T": 1577978261186, + "a": 202791045, + "f": 222826172, + "l": 222826172, + "m": false, + "p": "7141.52000000", + "q": "0.01329700" }, { "M": true, - "T": 1588749209051, - "a": 284862053, - "f": 310208375, - "l": 310208375, + "T": 1577978261251, + "a": 202791046, + "f": 222826173, + "l": 222826173, "m": true, - "p": "9032.95000000", - "q": "0.04823900" + "p": "7140.75000000", + "q": "0.03080300" }, { "M": true, - "T": 1588749209055, - "a": 284862054, - "f": 310208376, - "l": 310208376, + "T": 1577978261359, + "a": 202791047, + "f": 222826174, + "l": 222826174, "m": false, - "p": "9034.47000000", - "q": "0.00896200" + "p": "7140.75000000", + "q": "0.00947500" }, { "M": true, - "T": 1588749209483, - "a": 284862055, - "f": 310208377, - "l": 310208377, + "T": 1577978261465, + "a": 202791048, + "f": 222826175, + "l": 222826175, "m": false, - "p": "9034.31000000", - "q": "0.10685700" - }, - { - "M": true, - "T": 1588749209499, - "a": 284862056, - "f": 310208378, - "l": 310208379, - "m": true, - "p": "9033.06000000", - "q": "0.07333800" + "p": "7140.74000000", + "q": "0.00947500" }, { "M": true, - "T": 1588749209596, - "a": 284862057, - "f": 310208380, - "l": 310208380, + "T": 1577978261579, + "a": 202791049, + "f": 222826176, + "l": 222826176, "m": false, - "p": "9033.99000000", - "q": "0.00219000" - }, - { - "M": true, - "T": 1588749209991, - "a": 284862058, - "f": 310208381, - "l": 310208381, - "m": true, - "p": "9033.27000000", - "q": "0.05416900" + "p": "7140.74000000", + "q": "0.00800000" }, { "M": true, - "T": 1588749210418, - "a": 284862059, - "f": 310208382, - "l": 310208382, - "m": true, - "p": "9033.29000000", - "q": "0.02034600" + "T": 1577978261724, + "a": 202791050, + "f": 222826177, + "l": 222826177, + "m": false, + "p": "7140.68000000", + "q": "0.00800000" }, { "M": true, - "T": 1588749210524, - "a": 284862060, - "f": 310208383, - "l": 310208383, + "T": 1577978261763, + "a": 202791051, + "f": 222826178, + "l": 222826178, "m": true, - "p": "9033.29000000", - "q": "0.00769400" + "p": "7139.81000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749210723, - "a": 284862061, - "f": 310208384, - "l": 310208384, + "T": 1577978261770, + "a": 202791052, + "f": 222826179, + "l": 222826179, "m": false, - "p": "9033.84000000", - "q": "0.01698000" + "p": "7140.65000000", + "q": "0.00161400" }, { "M": true, - "T": 1588749211103, - "a": 284862062, - "f": 310208385, - "l": 310208385, + "T": 1577978261810, + "a": 202791053, + "f": 222826180, + "l": 222826180, "m": false, - "p": "9033.99000000", - "q": "0.00002300" + "p": "7140.64000000", + "q": "0.03294300" }, { "M": true, - "T": 1588749211103, - "a": 284862063, - "f": 310208386, - "l": 310208386, + "T": 1577978261982, + "a": 202791054, + "f": 222826181, + "l": 222826181, "m": false, - "p": "9034.69000000", - "q": "0.00113500" + "p": "7140.58000000", + "q": "0.00299600" }, { "M": true, - "T": 1588749211103, - "a": 284862064, - "f": 310208387, - "l": 310208387, - "m": false, - "p": "9034.78000000", - "q": "0.00300000" + "T": 1577978262460, + "a": 202791055, + "f": 222826182, + "l": 222826182, + "m": true, + "p": "7139.81000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749211103, - "a": 284862065, - "f": 310208388, - "l": 310208388, + "T": 1577978262507, + "a": 202791056, + "f": 222826183, + "l": 222826183, "m": false, - "p": "9034.96000000", - "q": "0.00328600" + "p": "7140.43000000", + "q": "0.00490500" }, { "M": true, - "T": 1588749211181, - "a": 284862066, - "f": 310208389, - "l": 310208389, + "T": 1577978262821, + "a": 202791057, + "f": 222826184, + "l": 222826184, "m": true, - "p": "9034.00000000", - "q": "0.00221300" + "p": "7139.81000000", + "q": "0.02219100" }, { "M": true, - "T": 1588749211181, - "a": 284862067, - "f": 310208390, - "l": 310208390, - "m": true, - "p": "9033.99000000", - "q": "0.03797000" + "T": 1577978262888, + "a": 202791058, + "f": 222826185, + "l": 222826185, + "m": false, + "p": "7140.29000000", + "q": "0.13872800" }, { "M": true, - "T": 1588749211181, - "a": 284862068, - "f": 310208391, - "l": 310208391, + "T": 1577978263847, + "a": 202791059, + "f": 222826186, + "l": 222826186, "m": true, - "p": "9033.36000000", - "q": "0.30000000" + "p": "7139.81000000", + "q": "0.00184100" }, { "M": true, - "T": 1588749211181, - "a": 284862069, - "f": 310208392, - "l": 310208392, + "T": 1577978264082, + "a": 202791060, + "f": 222826187, + "l": 222826187, "m": true, - "p": "9033.35000000", - "q": "0.05275200" + "p": "7139.81000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749211918, - "a": 284862070, - "f": 310208393, - "l": 310208393, + "T": 1577978264236, + "a": 202791061, + "f": 222826188, + "l": 222826188, "m": false, - "p": "9033.87000000", - "q": "0.06810800" + "p": "7140.65000000", + "q": "0.01640800" }, { "M": true, - "T": 1588749212020, - "a": 284862071, - "f": 310208394, - "l": 310208394, + "T": 1577978264576, + "a": 202791062, + "f": 222826189, + "l": 222826189, "m": true, - "p": "9034.27000000", - "q": "0.15108700" + "p": "7139.81000000", + "q": "0.01629300" }, { "M": true, - "T": 1588749212150, - "a": 284862072, - "f": 310208395, - "l": 310208395, - "m": false, - "p": "9034.29000000", - "q": "0.00221300" + "T": 1577978264866, + "a": 202791063, + "f": 222826190, + "l": 222826190, + "m": true, + "p": "7139.81000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749212150, - "a": 284862073, - "f": 310208396, - "l": 310208396, + "T": 1577978265223, + "a": 202791064, + "f": 222826191, + "l": 222826191, "m": false, - "p": "9034.34000000", - "q": "0.00050300" + "p": "7140.25000000", + "q": "0.12517900" }, { "M": true, - "T": 1588749212539, - "a": 284862074, - "f": 310208397, - "l": 310208397, - "m": true, - "p": "9034.36000000", - "q": "0.09449800" + "T": 1577978265342, + "a": 202791065, + "f": 222826192, + "l": 222826192, + "m": false, + "p": "7140.24000000", + "q": "0.06821500" }, { "M": true, - "T": 1588749212863, - "a": 284862075, - "f": 310208398, - "l": 310208398, - "m": true, - "p": "9034.36000000", - "q": "0.06005600" + "T": 1577978265342, + "a": 202791066, + "f": 222826193, + "l": 222826193, + "m": false, + "p": "7140.35000000", + "q": "0.15135900" }, { "M": true, - "T": 1588749212948, - "a": 284862076, - "f": 310208399, - "l": 310208399, + "T": 1577978265342, + "a": 202791067, + "f": 222826194, + "l": 222826194, "m": false, - "p": "9034.37000000", - "q": "0.17691900" + "p": "7140.63000000", + "q": "0.09630900" }, { "M": true, - "T": 1588749212948, - "a": 284862077, - "f": 310208400, - "l": 310208400, + "T": 1577978265342, + "a": 202791068, + "f": 222826195, + "l": 222826195, "m": false, - "p": "9034.72000000", - "q": "0.15438100" + "p": "7140.67000000", + "q": "0.00240000" }, { "M": true, - "T": 1588749213196, - "a": 284862078, - "f": 310208401, - "l": 310208401, - "m": true, - "p": "9034.36000000", - "q": "0.06034800" + "T": 1577978265342, + "a": 202791069, + "f": 222826196, + "l": 222826196, + "m": false, + "p": "7140.75000000", + "q": "0.08171700" }, { "M": true, - "T": 1588749213287, - "a": 284862079, - "f": 310208402, - "l": 310208402, - "m": true, - "p": "9034.36000000", - "q": "0.64000000" + "T": 1577978266316, + "a": 202791070, + "f": 222826197, + "l": 222826197, + "m": false, + "p": "7140.73000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749213530, - "a": 284862080, - "f": 310208403, - "l": 310208403, + "T": 1577978266797, + "a": 202791071, + "f": 222826198, + "l": 222826198, "m": true, - "p": "9034.36000000", - "q": "0.06040300" + "p": "7139.84000000", + "q": "0.01187100" }, { "M": true, - "T": 1588749213795, - "a": 284862081, - "f": 310208404, - "l": 310208404, + "T": 1577978266990, + "a": 202791072, + "f": 222826199, + "l": 222826199, "m": true, - "p": "9034.36000000", - "q": "0.00767900" + "p": "7139.84000000", + "q": "0.02214800" }, { "M": true, - "T": 1588749213868, - "a": 284862082, - "f": 310208405, - "l": 310208405, + "T": 1577978267028, + "a": 202791073, + "f": 222826200, + "l": 222826200, "m": true, - "p": "9034.36000000", - "q": "0.06015600" + "p": "7139.84000000", + "q": "0.16461800" }, { "M": true, - "T": 1588749214047, - "a": 284862083, - "f": 310208406, - "l": 310208406, + "T": 1577978267635, + "a": 202791074, + "f": 222826201, + "l": 222826201, "m": true, - "p": "9034.36000000", - "q": "0.01686000" + "p": "7139.81000000", + "q": "0.02110800" }, { "M": true, - "T": 1588749214047, - "a": 284862084, - "f": 310208407, - "l": 310208407, - "m": true, - "p": "9033.76000000", - "q": "0.00300000" + "T": 1577978268266, + "a": 202791075, + "f": 222826202, + "l": 222826202, + "m": false, + "p": "7140.18000000", + "q": "0.26064700" }, { "M": true, - "T": 1588749214047, - "a": 284862085, - "f": 310208408, - "l": 310208408, + "T": 1577978268444, + "a": 202791076, + "f": 222826203, + "l": 222826203, "m": true, - "p": "9033.39000000", - "q": "0.00221300" + "p": "7139.81000000", + "q": "0.02115800" }, { "M": true, - "T": 1588749214047, - "a": 284862086, - "f": 310208409, - "l": 310208409, - "m": true, - "p": "9032.75000000", - "q": "0.00300000" + "T": 1577978268468, + "a": 202791077, + "f": 222826204, + "l": 222826204, + "m": false, + "p": "7139.81000000", + "q": "0.01298700" }, { "M": true, - "T": 1588749214047, - "a": 284862087, - "f": 310208410, - "l": 310208410, - "m": true, - "p": "9032.70000000", - "q": "0.01492700" + "T": 1577978268494, + "a": 202791078, + "f": 222826205, + "l": 222826205, + "m": false, + "p": "7140.68000000", + "q": "0.07018200" }, { "M": true, - "T": 1588749214231, - "a": 284862088, - "f": 310208411, - "l": 310208411, - "m": true, - "p": "9034.35000000", - "q": "0.06732400" + "T": 1577978268494, + "a": 202791079, + "f": 222826206, + "l": 222826206, + "m": false, + "p": "7140.69000000", + "q": "0.13979100" }, { "M": true, - "T": 1588749214650, - "a": 284862089, - "f": 310208412, - "l": 310208412, + "T": 1577978268494, + "a": 202791080, + "f": 222826207, + "l": 222826207, "m": false, - "p": "9033.97000000", - "q": "0.00221200" + "p": "7140.71000000", + "q": "0.08850700" }, { "M": true, - "T": 1588749214752, - "a": 284862090, - "f": 310208413, - "l": 310208413, + "T": 1577978268494, + "a": 202791081, + "f": 222826208, + "l": 222826208, "m": false, - "p": "9033.92000000", - "q": "0.00628100" + "p": "7140.75000000", + "q": "0.10152000" }, { "M": true, - "T": 1588749215533, - "a": 284862091, - "f": 310208414, - "l": 310208414, + "T": 1577978268899, + "a": 202791082, + "f": 222826209, + "l": 222826209, "m": true, - "p": "9033.43000000", - "q": "0.00408600" + "p": "7139.82000000", + "q": "0.01407600" }, { "M": true, - "T": 1588749215533, - "a": 284862092, - "f": 310208415, - "l": 310208415, + "T": 1577978269253, + "a": 202791083, + "f": 222826210, + "l": 222826210, "m": true, - "p": "9033.42000000", - "q": "0.00510400" + "p": "7139.82000000", + "q": "0.41961700" }, { "M": true, - "T": 1588749215916, - "a": 284862093, - "f": 310208416, - "l": 310208416, + "T": 1577978269448, + "a": 202791084, + "f": 222826211, + "l": 222826211, "m": true, - "p": "9033.45000000", - "q": "0.00375300" + "p": "7139.82000000", + "q": "0.00931100" }, { "M": true, - "T": 1588749216016, - "a": 284862094, - "f": 310208417, - "l": 310208417, - "m": true, - "p": "9033.46000000", - "q": "0.00192000" + "T": 1577978269945, + "a": 202791085, + "f": 222826212, + "l": 222826212, + "m": false, + "p": "7140.75000000", + "q": "0.11880000" }, { "M": true, - "T": 1588749216129, - "a": 284862095, - "f": 310208418, - "l": 310208418, + "T": 1577978269982, + "a": 202791086, + "f": 222826213, + "l": 222826213, "m": false, - "p": "9033.76000000", - "q": "0.00299900" + "p": "7140.75000000", + "q": "0.00168900" }, { "M": true, - "T": 1588749216139, - "a": 284862096, - "f": 310208419, - "l": 310208419, + "T": 1577978270796, + "a": 202791087, + "f": 222826214, + "l": 222826214, "m": true, - "p": "9033.49000000", - "q": "0.01195400" + "p": "7139.81000000", + "q": "0.00206900" }, { "M": true, - "T": 1588749216981, - "a": 284862097, - "f": 310208420, - "l": 310208420, + "T": 1577978271139, + "a": 202791088, + "f": 222826215, + "l": 222826215, "m": true, - "p": "9033.52000000", - "q": "0.01196100" + "p": "7139.81000000", + "q": "0.01336800" }, { "M": true, - "T": 1588749217173, - "a": 284862098, - "f": 310208421, - "l": 310208421, + "T": 1577978271488, + "a": 202791089, + "f": 222826216, + "l": 222826216, "m": true, - "p": "9033.58000000", - "q": "0.01082500" + "p": "7139.81000000", + "q": "0.06369700" }, { "M": true, - "T": 1588749217445, - "a": 284862099, - "f": 310208422, - "l": 310208422, - "m": false, - "p": "9033.76000000", - "q": "0.00000100" - }, - { - "M": true, - "T": 1588749217615, - "a": 284862100, - "f": 310208423, - "l": 310208423, + "T": 1577978271879, + "a": 202791090, + "f": 222826217, + "l": 222826217, "m": true, - "p": "9033.59000000", - "q": "0.00310300" + "p": "7139.81000000", + "q": "0.11528200" }, { "M": true, - "T": 1588749217735, - "a": 284862101, - "f": 310208424, - "l": 310208424, + "T": 1577978271925, + "a": 202791091, + "f": 222826218, + "l": 222826218, "m": true, - "p": "9033.59000000", - "q": "0.01054800" + "p": "7139.81000000", + "q": "0.03553400" }, { "M": true, - "T": 1588749219343, - "a": 284862102, - "f": 310208425, - "l": 310208425, + "T": 1577978272719, + "a": 202791092, + "f": 222826219, + "l": 222826219, "m": true, - "p": "9033.59000000", - "q": "0.00141300" + "p": "7139.81000000", + "q": "0.34470400" }, { "M": true, - "T": 1588749219456, - "a": 284862103, - "f": 310208426, - "l": 310208426, + "T": 1577978273605, + "a": 202791093, + "f": 222826220, + "l": 222826220, "m": false, - "p": "9033.93000000", - "q": "0.10427300" + "p": "7139.78000000", + "q": "0.09878300" }, { "M": true, - "T": 1588749219468, - "a": 284862104, - "f": 310208427, - "l": 310208427, + "T": 1577978275581, + "a": 202791094, + "f": 222826221, + "l": 222826222, "m": true, - "p": "9033.59000000", - "q": "0.01196100" + "p": "7139.33000000", + "q": "0.18289300" }, { "M": true, - "T": 1588749219554, - "a": 284862105, - "f": 310208428, - "l": 310208428, + "T": 1577978276486, + "a": 202791095, + "f": 222826223, + "l": 222826223, "m": false, - "p": "9033.93000000", - "q": "0.06354800" + "p": "7140.34000000", + "q": "0.00342500" }, { "M": true, - "T": 1588749219595, - "a": 284862106, - "f": 310208429, - "l": 310208429, - "m": true, - "p": "9033.59000000", - "q": "0.01000800" + "T": 1577978276782, + "a": 202791096, + "f": 222826224, + "l": 222826224, + "m": false, + "p": "7139.62000000", + "q": "0.10444200" }, { "M": true, - "T": 1588749219674, - "a": 284862107, - "f": 310208430, - "l": 310208430, + "T": 1577978276798, + "a": 202791097, + "f": 222826225, + "l": 222826225, "m": false, - "p": "9033.89000000", - "q": "0.00477700" + "p": "7140.34000000", + "q": "0.02737000" }, { "M": true, - "T": 1588749219718, - "a": 284862108, - "f": 310208431, - "l": 310208431, + "T": 1577978276798, + "a": 202791098, + "f": 222826226, + "l": 222826226, "m": false, - "p": "9033.89000000", - "q": "0.17215400" + "p": "7140.35000000", + "q": "0.08072100" }, { "M": true, - "T": 1588749219718, - "a": 284862109, - "f": 310208432, - "l": 310208432, + "T": 1577978276798, + "a": 202791099, + "f": 222826227, + "l": 222826227, "m": false, - "p": "9033.93000000", - "q": "0.11564800" + "p": "7140.36000000", + "q": "0.07276600" }, { "M": true, - "T": 1588749222023, - "a": 284862110, - "f": 310208433, - "l": 310208433, - "m": true, - "p": "9033.72000000", - "q": "0.00600900" + "T": 1577978276798, + "a": 202791100, + "f": 222826228, + "l": 222826228, + "m": false, + "p": "7140.38000000", + "q": "0.09493800" }, { "M": true, - "T": 1588749222214, - "a": 284862111, - "f": 310208434, - "l": 310208434, - "m": true, - "p": "9033.72000000", - "q": "0.01325500" + "T": 1577978276798, + "a": 202791101, + "f": 222826229, + "l": 222826229, + "m": false, + "p": "7140.71000000", + "q": "0.12420500" }, { "M": true, - "T": 1588749222458, - "a": 284862112, - "f": 310208435, - "l": 310208435, - "m": true, - "p": "9033.69000000", - "q": "0.17693000" + "T": 1577978277044, + "a": 202791102, + "f": 222826230, + "l": 222826230, + "m": false, + "p": "7140.56000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749222458, - "a": 284862113, - "f": 310208436, - "l": 310208436, - "m": true, - "p": "9033.65000000", - "q": "0.17263000" + "T": 1577978278200, + "a": 202791103, + "f": 222826231, + "l": 222826231, + "m": false, + "p": "7140.35000000", + "q": "0.00161600" }, { "M": true, - "T": 1588749222660, - "a": 284862114, - "f": 310208437, - "l": 310208437, - "m": false, - "p": "9033.92000000", - "q": "0.00285300" + "T": 1577978280239, + "a": 202791104, + "f": 222826232, + "l": 222826232, + "m": true, + "p": "7139.54000000", + "q": "0.06113400" }, { "M": true, - "T": 1588749222781, - "a": 284862115, - "f": 310208438, - "l": 310208438, + "T": 1577978280408, + "a": 202791105, + "f": 222826233, + "l": 222826233, "m": false, - "p": "9033.97000000", - "q": "0.00000100" + "p": "7140.30000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749222781, - "a": 284862116, - "f": 310208439, - "l": 310208439, + "T": 1577978280603, + "a": 202791106, + "f": 222826234, + "l": 222826234, "m": false, - "p": "9034.05000000", - "q": "0.00840200" + "p": "7140.30000000", + "q": "0.05326000" }, { "M": true, - "T": 1588749222781, - "a": 284862117, - "f": 310208440, - "l": 310208440, + "T": 1577978280630, + "a": 202791107, + "f": 222826235, + "l": 222826235, "m": false, - "p": "9034.73000000", - "q": "0.12175200" + "p": "7140.30000000", + "q": "0.00532100" }, { "M": true, - "T": 1588749222781, - "a": 284862118, - "f": 310208441, - "l": 310208441, + "T": 1577978280630, + "a": 202791108, + "f": 222826236, + "l": 222826236, "m": false, - "p": "9034.78000000", - "q": "0.00300000" + "p": "7140.31000000", + "q": "0.11189500" }, { "M": true, - "T": 1588749222781, - "a": 284862119, - "f": 310208442, - "l": 310208442, + "T": 1577978280630, + "a": 202791109, + "f": 222826237, + "l": 222826237, "m": false, - "p": "9034.82000000", - "q": "0.16684500" + "p": "7140.33000000", + "q": "0.03976300" }, { "M": true, - "T": 1588749224258, - "a": 284862120, - "f": 310208443, - "l": 310208443, + "T": 1577978280630, + "a": 202791110, + "f": 222826238, + "l": 222826238, "m": false, - "p": "9033.77000000", - "q": "0.02419200" + "p": "7140.34000000", + "q": "0.06707500" }, { "M": true, - "T": 1588749225293, - "a": 284862121, - "f": 310208444, - "l": 310208444, + "T": 1577978280630, + "a": 202791111, + "f": 222826239, + "l": 222826239, "m": false, - "p": "9033.77000000", - "q": "0.10000000" + "p": "7140.71000000", + "q": "0.05325800" }, { "M": true, - "T": 1588749225794, - "a": 284862122, - "f": 310208445, - "l": 310208446, + "T": 1577978281279, + "a": 202791112, + "f": 222826240, + "l": 222826240, "m": true, - "p": "9033.76000000", - "q": "0.00521300" + "p": "7139.38000000", + "q": "0.00166700" }, { "M": true, - "T": 1588749225794, - "a": 284862123, - "f": 310208447, - "l": 310208447, - "m": true, - "p": "9033.28000000", - "q": "0.08762000" + "T": 1577978281885, + "a": 202791113, + "f": 222826241, + "l": 222826241, + "m": false, + "p": "7140.67000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749225794, - "a": 284862124, - "f": 310208448, - "l": 310208448, + "T": 1577978285688, + "a": 202791114, + "f": 222826242, + "l": 222826242, "m": true, - "p": "9033.26000000", - "q": "0.00716700" + "p": "7140.10000000", + "q": "0.22129100" }, { "M": true, - "T": 1588749226839, - "a": 284862125, - "f": 310208449, - "l": 310208449, + "T": 1577978285718, + "a": 202791115, + "f": 222826243, + "l": 222826243, "m": false, - "p": "9033.63000000", - "q": "0.14333200" + "p": "7140.28000000", + "q": "0.14489000" }, { "M": true, - "T": 1588749227213, - "a": 284862126, - "f": 310208450, - "l": 310208450, - "m": true, - "p": "9033.30000000", - "q": "0.02214100" + "T": 1577978286028, + "a": 202791116, + "f": 222826244, + "l": 222826244, + "m": false, + "p": "7140.30000000", + "q": "0.09378500" }, { "M": true, - "T": 1588749228758, - "a": 284862127, - "f": 310208451, - "l": 310208451, + "T": 1577978286115, + "a": 202791117, + "f": 222826245, + "l": 222826245, "m": false, - "p": "9033.70000000", - "q": "0.19302600" + "p": "7140.75000000", + "q": "0.10289800" }, { "M": true, - "T": 1588749228758, - "a": 284862128, - "f": 310208452, - "l": 310208452, + "T": 1577978286421, + "a": 202791118, + "f": 222826246, + "l": 222826246, "m": false, - "p": "9033.72000000", - "q": "0.00755100" + "p": "7140.75000000", + "q": "0.00154300" }, { "M": true, - "T": 1588749228758, - "a": 284862129, - "f": 310208453, - "l": 310208453, + "T": 1577978286886, + "a": 202791119, + "f": 222826247, + "l": 222826247, "m": false, - "p": "9033.79000000", - "q": "0.09488700" + "p": "7140.75000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749230513, - "a": 284862130, - "f": 310208454, - "l": 310208454, + "T": 1577978287759, + "a": 202791120, + "f": 222826248, + "l": 222826248, "m": true, - "p": "9033.34000000", - "q": "0.00221300" + "p": "7140.67000000", + "q": "0.01948600" }, { "M": true, - "T": 1588749230513, - "a": 284862131, - "f": 310208455, - "l": 310208456, + "T": 1577978287759, + "a": 202791121, + "f": 222826249, + "l": 222826249, "m": true, - "p": "9033.26000000", - "q": "0.09554300" + "p": "7139.83000000", + "q": "0.15106700" }, { "M": true, - "T": 1588749230513, - "a": 284862132, - "f": 310208457, - "l": 310208457, + "T": 1577978287759, + "a": 202791122, + "f": 222826250, + "l": 222826250, "m": true, - "p": "9032.76000000", - "q": "0.18248800" + "p": "7139.69000000", + "q": "0.22504600" }, { "M": true, - "T": 1588749230513, - "a": 284862133, - "f": 310208458, - "l": 310208460, + "T": 1577978289291, + "a": 202791123, + "f": 222826251, + "l": 222826251, "m": true, - "p": "9032.75000000", - "q": "0.01452300" + "p": "7140.01000000", + "q": "0.05342300" }, { "M": true, - "T": 1588749230513, - "a": 284862134, - "f": 310208461, - "l": 310208461, + "T": 1577978289291, + "a": 202791124, + "f": 222826252, + "l": 222826252, "m": true, - "p": "9032.18000000", - "q": "0.10523300" + "p": "7139.70000000", + "q": "0.04199700" }, { "M": true, - "T": 1588749230737, - "a": 284862135, - "f": 310208462, - "l": 310208462, - "m": false, - "p": "9033.03000000", - "q": "0.01910900" + "T": 1577978289517, + "a": 202791125, + "f": 222826253, + "l": 222826253, + "m": true, + "p": "7139.70000000", + "q": "0.05342300" + }, + { + "M": true, + "T": 1577978289517, + "a": 202791126, + "f": 222826254, + "l": 222826254, + "m": true, + "p": "7139.58000000", + "q": "0.00663900" + }, + { + "M": true, + "T": 1577978291268, + "a": 202791127, + "f": 222826255, + "l": 222826256, + "m": true, + "p": "7139.58000000", + "q": "0.04103100" + }, + { + "M": true, + "T": 1577978291268, + "a": 202791128, + "f": 222826257, + "l": 222826257, + "m": true, + "p": "7139.30000000", + "q": "0.01899100" }, { "M": true, - "T": 1588749230744, - "a": 284862136, - "f": 310208463, - "l": 310208463, + "T": 1577978291852, + "a": 202791129, + "f": 222826258, + "l": 222826258, "m": false, - "p": "9033.03000000", - "q": "0.02392000" + "p": "7140.01000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749230847, - "a": 284862137, - "f": 310208464, - "l": 310208464, + "T": 1577978292637, + "a": 202791130, + "f": 222826259, + "l": 222826259, "m": false, - "p": "9032.99000000", - "q": "0.01869300" + "p": "7139.99000000", + "q": "0.00168700" }, { "M": true, - "T": 1588749230859, - "a": 284862138, - "f": 310208465, - "l": 310208465, + "T": 1577978293649, + "a": 202791131, + "f": 222826260, + "l": 222826260, "m": true, - "p": "9032.21000000", - "q": "0.00221400" + "p": "7139.70000000", + "q": "0.06283300" }, { "M": true, - "T": 1588749230859, - "a": 284862139, - "f": 310208466, - "l": 310208466, + "T": 1577978293738, + "a": 202791132, + "f": 222826261, + "l": 222826261, "m": true, - "p": "9031.92000000", - "q": "0.00001200" + "p": "7139.17000000", + "q": "0.00404600" }, { "M": true, - "T": 1588749231463, - "a": 284862140, - "f": 310208467, - "l": 310208467, + "T": 1577978296281, + "a": 202791133, + "f": 222826262, + "l": 222826262, "m": false, - "p": "9032.91000000", - "q": "0.00149300" + "p": "7139.61000000", + "q": "0.03924200" }, { "M": true, - "T": 1588749232655, - "a": 284862141, - "f": 310208468, - "l": 310208468, - "m": true, - "p": "9032.78000000", - "q": "0.03052400" + "T": 1577978296359, + "a": 202791134, + "f": 222826263, + "l": 222826263, + "m": false, + "p": "7139.86000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749232806, - "a": 284862142, - "f": 310208469, - "l": 310208469, - "m": true, - "p": "9032.89000000", - "q": "0.17694800" + "T": 1577978296849, + "a": 202791135, + "f": 222826264, + "l": 222826264, + "m": false, + "p": "7139.86000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749232806, - "a": 284862143, - "f": 310208470, - "l": 310208470, + "T": 1577978298193, + "a": 202791136, + "f": 222826265, + "l": 222826265, "m": true, - "p": "9032.78000000", - "q": "0.22305200" + "p": "7139.17000000", + "q": "0.02675600" }, { "M": true, - "T": 1588749234556, - "a": 284862144, - "f": 310208471, - "l": 310208471, + "T": 1577978298875, + "a": 202791137, + "f": 222826266, + "l": 222826266, "m": false, - "p": "9032.79000000", - "q": "0.00736000" + "p": "7139.85000000", + "q": "0.00168500" }, { "M": true, - "T": 1588749234556, - "a": 284862145, - "f": 310208472, - "l": 310208472, + "T": 1577978300712, + "a": 202791138, + "f": 222826267, + "l": 222826267, "m": false, - "p": "9033.00000000", - "q": "0.05323400" + "p": "7139.61000000", + "q": "0.30272300" }, { "M": true, - "T": 1588749235418, - "a": 284862146, - "f": 310208473, - "l": 310208473, + "T": 1577978303838, + "a": 202791139, + "f": 222826268, + "l": 222826268, "m": false, - "p": "9033.00000000", - "q": "0.04675200" + "p": "7139.70000000", + "q": "0.00141600" }, { "M": true, - "T": 1588749235620, - "a": 284862147, - "f": 310208474, - "l": 310208474, + "T": 1577978303907, + "a": 202791140, + "f": 222826269, + "l": 222826269, "m": false, - "p": "9033.00000000", - "q": "0.00001400" + "p": "7139.70000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749235620, - "a": 284862148, - "f": 310208475, - "l": 310208475, + "T": 1577978304362, + "a": 202791141, + "f": 222826270, + "l": 222826270, "m": false, - "p": "9033.26000000", - "q": "0.00254400" + "p": "7139.49000000", + "q": "0.11049200" }, { "M": true, - "T": 1588749235641, - "a": 284862149, - "f": 310208476, - "l": 310208476, + "T": 1577978305481, + "a": 202791142, + "f": 222826271, + "l": 222826271, "m": true, - "p": "9033.03000000", - "q": "0.17694300" + "p": "7139.17000000", + "q": "0.00000800" }, { "M": true, - "T": 1588749235641, - "a": 284862150, - "f": 310208477, - "l": 310208477, + "T": 1577978305481, + "a": 202791143, + "f": 222826272, + "l": 222826272, "m": true, - "p": "9033.00000000", - "q": "0.38752300" + "p": "7139.00000000", + "q": "0.00279300" }, { "M": true, - "T": 1588749235641, - "a": 284862151, - "f": 310208478, - "l": 310208478, + "T": 1577978305533, + "a": 202791144, + "f": 222826273, + "l": 222826273, "m": true, - "p": "9032.99000000", - "q": "0.15113500" + "p": "7139.00000000", + "q": "0.02614300" }, { "M": true, - "T": 1588749237197, - "a": 284862152, - "f": 310208479, - "l": 310208479, + "T": 1577978306009, + "a": 202791145, + "f": 222826274, + "l": 222826274, "m": false, - "p": "9033.14000000", - "q": "0.01370900" + "p": "7139.68000000", + "q": "0.00931000" }, { "M": true, - "T": 1588749238872, - "a": 284862153, - "f": 310208480, - "l": 310208480, - "m": false, - "p": "9033.26000000", - "q": "0.00221400" + "T": 1577978306512, + "a": 202791146, + "f": 222826275, + "l": 222826276, + "m": true, + "p": "7139.00000000", + "q": "0.00643300" + }, + { + "M": true, + "T": 1577978306761, + "a": 202791147, + "f": 222826277, + "l": 222826277, + "m": true, + "p": "7139.00000000", + "q": "0.04523700" + }, + { + "M": true, + "T": 1577978306837, + "a": 202791148, + "f": 222826278, + "l": 222826278, + "m": true, + "p": "7139.00000000", + "q": "0.02038100" }, { "M": true, - "T": 1588749238873, - "a": 284862154, - "f": 310208481, - "l": 310208481, + "T": 1577978307089, + "a": 202791149, + "f": 222826279, + "l": 222826279, "m": false, - "p": "9033.26000000", - "q": "0.00221400" + "p": "7139.69000000", + "q": "0.00154600" }, { "M": true, - "T": 1588749239695, - "a": 284862155, - "f": 310208482, - "l": 310208482, - "m": true, - "p": "9033.25000000", - "q": "0.00326000" + "T": 1577978308155, + "a": 202791150, + "f": 222826280, + "l": 222826280, + "m": false, + "p": "7139.39000000", + "q": "0.12714800" }, { "M": true, - "T": 1588749240265, - "a": 284862156, - "f": 310208483, - "l": 310208483, + "T": 1577978308157, + "a": 202791151, + "f": 222826281, + "l": 222826281, "m": false, - "p": "9033.26000000", - "q": "0.01936800" + "p": "7139.69000000", + "q": "0.04712100" }, { "M": true, - "T": 1588749241110, - "a": 284862157, - "f": 310208484, - "l": 310208484, + "T": 1577978308912, + "a": 202791152, + "f": 222826282, + "l": 222826282, "m": false, - "p": "9033.26000000", - "q": "0.00000700" + "p": "7140.06000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749241417, - "a": 284862158, - "f": 310208485, - "l": 310208485, + "T": 1577978309782, + "a": 202791153, + "f": 222826283, + "l": 222826283, "m": true, - "p": "9033.75000000", - "q": "0.00216600" + "p": "7139.16000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749241521, - "a": 284862159, - "f": 310208486, - "l": 310208486, + "T": 1577978310429, + "a": 202791154, + "f": 222826284, + "l": 222826284, "m": true, - "p": "9033.75000000", - "q": "0.03234900" - }, - { - "M": true, - "T": 1588749241658, - "a": 284862160, - "f": 310208487, - "l": 310208487, - "m": false, - "p": "9033.76000000", - "q": "0.00300000" + "p": "7139.17000000", + "q": "0.03861100" }, { "M": true, - "T": 1588749241658, - "a": 284862161, - "f": 310208488, - "l": 310208488, + "T": 1577978311653, + "a": 202791155, + "f": 222826285, + "l": 222826285, "m": false, - "p": "9034.50000000", - "q": "0.00887200" + "p": "7139.74000000", + "q": "0.07362500" }, { "M": true, - "T": 1588749241658, - "a": 284862162, - "f": 310208489, - "l": 310208489, - "m": false, - "p": "9034.70000000", - "q": "0.00213800" + "T": 1577978311656, + "a": 202791156, + "f": 222826286, + "l": 222826286, + "m": true, + "p": "7139.19000000", + "q": "0.04873200" }, { "M": true, - "T": 1588749242084, - "a": 284862163, - "f": 310208490, - "l": 310208490, + "T": 1577978311915, + "a": 202791157, + "f": 222826287, + "l": 222826287, "m": true, - "p": "9033.53000000", - "q": "0.00207700" + "p": "7139.16000000", + "q": "0.03081100" }, { "M": true, - "T": 1588749242207, - "a": 284862164, - "f": 310208491, - "l": 310208491, + "T": 1577978311915, + "a": 202791158, + "f": 222826288, + "l": 222826288, "m": true, - "p": "9033.53000000", - "q": "0.00013600" + "p": "7139.12000000", + "q": "0.15682700" }, { "M": true, - "T": 1588749242207, - "a": 284862165, - "f": 310208492, - "l": 310208492, + "T": 1577978311915, + "a": 202791159, + "f": 222826289, + "l": 222826289, "m": true, - "p": "9033.30000000", - "q": "0.00326000" + "p": "7139.00000000", + "q": "0.21236200" }, { "M": true, - "T": 1588749242245, - "a": 284862166, - "f": 310208493, - "l": 310208493, + "T": 1577978312126, + "a": 202791160, + "f": 222826290, + "l": 222826290, "m": true, - "p": "9033.30000000", - "q": "0.01163000" + "p": "7139.00000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749242387, - "a": 284862167, - "f": 310208494, - "l": 310208494, + "T": 1577978313680, + "a": 202791161, + "f": 222826291, + "l": 222826291, "m": true, - "p": "9033.30000000", - "q": "0.00326900" + "p": "7139.00000000", + "q": "0.06054400" }, { "M": true, - "T": 1588749242387, - "a": 284862168, - "f": 310208495, - "l": 310208495, + "T": 1577978313719, + "a": 202791162, + "f": 222826292, + "l": 222826292, "m": true, - "p": "9032.78000000", - "q": "0.01887100" + "p": "7139.00000000", + "q": "0.09675700" }, { "M": true, - "T": 1588749243106, - "a": 284862169, - "f": 310208496, - "l": 310208496, - "m": true, - "p": "9033.67000000", - "q": "0.08647100" + "T": 1577978313882, + "a": 202791163, + "f": 222826293, + "l": 222826293, + "m": false, + "p": "7139.96000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749244280, - "a": 284862170, - "f": 310208497, - "l": 310208497, + "T": 1577978314082, + "a": 202791164, + "f": 222826294, + "l": 222826294, "m": true, - "p": "9033.10000000", - "q": "0.00473900" + "p": "7139.00000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749245682, - "a": 284862171, - "f": 310208498, - "l": 310208498, + "T": 1577978314841, + "a": 202791165, + "f": 222826295, + "l": 222826295, "m": true, - "p": "9033.48000000", - "q": "0.05043800" + "p": "7139.02000000", + "q": "0.06003000" }, { "M": true, - "T": 1588749245832, - "a": 284862172, - "f": 310208499, - "l": 310208499, - "m": false, - "p": "9033.72000000", - "q": "0.00221300" + "T": 1577978314854, + "a": 202791166, + "f": 222826296, + "l": 222826296, + "m": true, + "p": "7139.02000000", + "q": "0.04546700" }, { "M": true, - "T": 1588749245880, - "a": 284862173, - "f": 310208500, - "l": 310208500, + "T": 1577978314854, + "a": 202791167, + "f": 222826297, + "l": 222826297, "m": true, - "p": "9033.82000000", - "q": "0.00221300" + "p": "7139.00000000", + "q": "1.55269400" }, { "M": true, - "T": 1588749245880, - "a": 284862174, - "f": 310208501, - "l": 310208501, + "T": 1577978314854, + "a": 202791168, + "f": 222826298, + "l": 222826298, "m": true, - "p": "9033.81000000", - "q": "0.00086600" + "p": "7138.93000000", + "q": "0.05129000" }, { "M": true, - "T": 1588749247456, - "a": 284862175, - "f": 310208502, - "l": 310208502, - "m": false, - "p": "9033.82000000", - "q": "0.14939100" + "T": 1577978315035, + "a": 202791169, + "f": 222826299, + "l": 222826299, + "m": true, + "p": "7138.11000000", + "q": "0.00280100" }, { "M": true, - "T": 1588749249172, - "a": 284862176, - "f": 310208503, - "l": 310208503, - "m": false, - "p": "9034.63000000", - "q": "0.02153500" + "T": 1577978315125, + "a": 202791170, + "f": 222826300, + "l": 222826300, + "m": true, + "p": "7138.11000000", + "q": "0.06206900" }, { "M": true, - "T": 1588749249988, - "a": 284862177, - "f": 310208504, - "l": 310208504, + "T": 1577978315313, + "a": 202791171, + "f": 222826301, + "l": 222826301, "m": false, - "p": "9034.33000000", - "q": "0.00130000" + "p": "7138.96000000", + "q": "0.00166500" }, { "M": true, - "T": 1588749250605, - "a": 284862178, - "f": 310208505, - "l": 310208505, - "m": false, - "p": "9034.11000000", - "q": "0.01617000" + "T": 1577978315730, + "a": 202791172, + "f": 222826302, + "l": 222826302, + "m": true, + "p": "7138.51000000", + "q": "0.30675000" }, { "M": true, - "T": 1588749251227, - "a": 284862179, - "f": 310208506, - "l": 310208506, - "m": false, - "p": "9034.11000000", - "q": "0.01906100" + "T": 1577978315973, + "a": 202791173, + "f": 222826303, + "l": 222826303, + "m": true, + "p": "7137.98000000", + "q": "0.00280200" }, { "M": true, - "T": 1588749251452, - "a": 284862180, - "f": 310208507, - "l": 310208507, + "T": 1577978315988, + "a": 202791174, + "f": 222826304, + "l": 222826304, "m": true, - "p": "9034.41000000", - "q": "0.40000000" + "p": "7137.98000000", + "q": "0.02801400" }, { "M": true, - "T": 1588749251512, - "a": 284862181, - "f": 310208508, - "l": 310208508, + "T": 1577978316014, + "a": 202791175, + "f": 222826305, + "l": 222826306, "m": true, - "p": "9034.61000000", - "q": "0.00646800" + "p": "7137.97000000", + "q": "0.48142600" }, { "M": true, - "T": 1588749253390, - "a": 284862182, - "f": 310208509, - "l": 310208509, + "T": 1577978316026, + "a": 202791176, + "f": 222826307, + "l": 222826307, "m": true, - "p": "9034.23000000", - "q": "0.00221400" + "p": "7137.97000000", + "q": "0.11471100" }, { "M": true, - "T": 1588749256526, - "a": 284862183, - "f": 310208510, - "l": 310208510, + "T": 1577978316043, + "a": 202791177, + "f": 222826308, + "l": 222826308, "m": true, - "p": "9034.23000000", - "q": "0.00221400" + "p": "7137.97000000", + "q": "0.11471100" }, { "M": true, - "T": 1588749256529, - "a": 284862184, - "f": 310208511, - "l": 310208511, + "T": 1577978316047, + "a": 202791178, + "f": 222826309, + "l": 222826309, "m": true, - "p": "9034.23000000", - "q": "0.00221400" + "p": "7137.97000000", + "q": "0.42612500" }, { "M": true, - "T": 1588749256534, - "a": 284862185, - "f": 310208512, - "l": 310208512, + "T": 1577978316059, + "a": 202791179, + "f": 222826310, + "l": 222826310, "m": true, - "p": "9034.23000000", - "q": "0.00221400" + "p": "7137.97000000", + "q": "0.02974700" }, { "M": true, - "T": 1588749256534, - "a": 284862186, - "f": 310208513, - "l": 310208513, + "T": 1577978316188, + "a": 202791180, + "f": 222826311, + "l": 222826311, "m": true, - "p": "9034.23000000", - "q": "0.00221400" + "p": "7137.79000000", + "q": "0.00280200" }, { "M": true, - "T": 1588749256755, - "a": 284862187, - "f": 310208514, - "l": 310208514, + "T": 1577978316399, + "a": 202791181, + "f": 222826312, + "l": 222826312, "m": true, - "p": "9034.23000000", - "q": "0.03371300" + "p": "7137.63000000", + "q": "0.00280200" }, { "M": true, - "T": 1588749256755, - "a": 284862188, - "f": 310208515, - "l": 310208516, + "T": 1577978317402, + "a": 202791182, + "f": 222826313, + "l": 222826313, "m": true, - "p": "9033.84000000", - "q": "0.01628700" + "p": "7137.64000000", + "q": "0.02097700" }, { "M": true, - "T": 1588749258021, - "a": 284862189, - "f": 310208517, - "l": 310208518, - "m": false, - "p": "9033.85000000", - "q": "0.36724000" + "T": 1577978318500, + "a": 202791183, + "f": 222826314, + "l": 222826314, + "m": true, + "p": "7137.63000000", + "q": "0.00154000" }, { "M": true, - "T": 1588749258021, - "a": 284862190, - "f": 310208519, - "l": 310208519, + "T": 1577978318780, + "a": 202791184, + "f": 222826315, + "l": 222826315, "m": false, - "p": "9034.00000000", - "q": "0.15371900" + "p": "7137.64000000", + "q": "0.01025400" }, { "M": true, - "T": 1588749258144, - "a": 284862191, - "f": 310208520, - "l": 310208520, + "T": 1577978318903, + "a": 202791185, + "f": 222826316, + "l": 222826316, "m": true, - "p": "9033.84000000", - "q": "0.00479400" + "p": "7137.63000000", + "q": "0.40000000" }, { "M": true, - "T": 1588749258271, - "a": 284862192, - "f": 310208521, - "l": 310208521, + "T": 1577978318905, + "a": 202791186, + "f": 222826317, + "l": 222826317, "m": false, - "p": "9033.93000000", - "q": "0.01212200" + "p": "7137.64000000", + "q": "0.00200000" }, { "M": true, - "T": 1588749260187, - "a": 284862193, - "f": 310208522, - "l": 310208522, + "T": 1577978319226, + "a": 202791187, + "f": 222826318, + "l": 222826318, "m": true, - "p": "9033.84000000", - "q": "0.00221400" + "p": "7137.50000000", + "q": "0.02119800" }, { "M": true, - "T": 1588749260193, - "a": 284862194, - "f": 310208523, - "l": 310208523, + "T": 1577978319226, + "a": 202791188, + "f": 222826319, + "l": 222826319, "m": true, - "p": "9033.84000000", - "q": "0.00221400" + "p": "7137.20000000", + "q": "0.03881400" }, { "M": true, - "T": 1588749260193, - "a": 284862195, - "f": 310208524, - "l": 310208524, + "T": 1577978319811, + "a": 202791189, + "f": 222826320, + "l": 222826320, "m": true, - "p": "9033.84000000", - "q": "0.00221400" - }, + "p": "7137.19000000", + "q": "0.10400100" + } + ], + "queryString": "fromId=202790190\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ { "M": true, - "T": 1588749260212, - "a": 284862196, - "f": 310208525, - "l": 310208525, + "T": 1577978319811, + "a": 202791189, + "f": 222826320, + "l": 222826320, "m": true, - "p": "9033.84000000", - "q": "0.00221400" + "p": "7137.19000000", + "q": "0.10400100" }, { "M": true, - "T": 1588749260493, - "a": 284862197, - "f": 310208526, - "l": 310208527, + "T": 1577978656080, + "a": 202792188, + "f": 222827352, + "l": 222827352, "m": false, - "p": "9033.85000000", - "q": "0.21682400" - }, - { - "M": true, - "T": 1588749261522, - "a": 284862198, - "f": 310208528, - "l": 310208528, - "m": true, - "p": "9033.84000000", - "q": "0.00166900" - }, - { + "p": "7133.73000000", + "q": "0.00165100" + } + ], + "queryString": "fromId=202791189\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { "M": true, - "T": 1588749262305, - "a": 284862199, - "f": 310208529, - "l": 310208529, + "T": 1577978657562, + "a": 202792189, + "f": 222827353, + "l": 222827353, "m": true, - "p": "9033.84000000", - "q": "0.05665300" + "p": "7133.06000000", + "q": "0.09997800" }, { "M": true, - "T": 1588749262305, - "a": 284862200, - "f": 310208530, - "l": 310208530, + "T": 1577979074285, + "a": 202793187, + "f": 222828406, + "l": 222828406, "m": true, - "p": "9033.82000000", - "q": "0.00221300" - }, + "p": "7131.15000000", + "q": "0.01687000" + } + ], + "queryString": "fromId=202792188\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ { "M": true, - "T": 1588749262305, - "a": 284862201, - "f": 310208531, - "l": 310208531, + "T": 1577979074285, + "a": 202793187, + "f": 222828406, + "l": 222828406, "m": true, - "p": "9033.81000000", - "q": "0.01113400" + "p": "7131.15000000", + "q": "0.01687000" }, { "M": true, - "T": 1588749262616, - "a": 284862202, - "f": 310208532, - "l": 310208532, + "T": 1577979542071, + "a": 202794186, + "f": 222829449, + "l": 222829449, "m": false, - "p": "9034.00000000", - "q": "0.04755900" - }, + "p": "7123.22000000", + "q": "0.00897400" + } + ], + "queryString": "fromId=202793187\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ { "M": true, - "T": 1588749262719, - "a": 284862203, - "f": 310208533, - "l": 310208533, + "T": 1577979542071, + "a": 202794186, + "f": 222829449, + "l": 222829449, "m": false, - "p": "9034.00000000", - "q": "0.00755800" + "p": "7123.22000000", + "q": "0.00897400" }, { "M": true, - "T": 1588749263231, - "a": 284862204, - "f": 310208534, - "l": 310208534, + "T": 1577979948649, + "a": 202795185, + "f": 222830503, + "l": 222830503, "m": false, - "p": "9034.00000000", - "q": "0.06546300" + "p": "7132.63000000", + "q": "0.00854300" } ], - "queryString": "limit=1000\u0026symbol=BTCUSDT", + "queryString": "fromId=202794186\u0026limit=1000\u0026symbol=BTCUSDT", "bodyParams": "", "headers": {} }, @@ -10889,56 +11310,53 @@ "data": [ { "M": true, - "T": 1590640145871, - "a": 303004096, - "f": 329755557, - "l": 329755557, + "T": 1577979948649, + "a": 202795185, + "f": 222830503, + "l": 222830503, "m": false, - "p": "9195.09000000", - "q": "0.10000000" + "p": "7132.63000000", + "q": "0.00854300" }, { "M": true, - "T": 1590640145901, - "a": 303004097, - "f": 329755558, - "l": 329755558, + "T": 1577980432803, + "a": 202796184, + "f": 222831557, + "l": 222831557, "m": true, - "p": "9194.99000000", - "q": "0.00000700" - }, + "p": "7132.89000000", + "q": "0.02328500" + } + ], + "queryString": "fromId=202795185\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ { "M": true, - "T": 1590640145901, - "a": 303004098, - "f": 329755559, - "l": 329755559, + "T": 1577980432803, + "a": 202796184, + "f": 222831557, + "l": 222831557, "m": true, - "p": "9194.98000000", - "q": "0.01963500" - }, - { - "M": true, - "T": 1590640145980, - "a": 303004099, - "f": 329755560, - "l": 329755560, - "m": false, - "p": "9194.99000000", - "q": "0.00490700" + "p": "7132.89000000", + "q": "0.02328500" }, { "M": true, - "T": 1590640146110, - "a": 303004100, - "f": 329755561, - "l": 329755561, + "T": 1577980864995, + "a": 202797183, + "f": 222832591, + "l": 222832591, "m": false, - "p": "9194.99000000", - "q": "0.09509300" + "p": "7133.33000000", + "q": "0.01179400" } ], - "queryString": "limit=5\u0026symbol=BTCUSDT", + "queryString": "fromId=202796184\u0026limit=1000\u0026symbol=BTCUSDT", "bodyParams": "", "headers": {} }, @@ -10946,56 +11364,53 @@ "data": [ { "M": true, - "T": 1590640145871, - "a": 303004096, - "f": 329755557, - "l": 329755557, + "T": 1577980864995, + "a": 202797183, + "f": 222832591, + "l": 222832591, "m": false, - "p": "9195.09000000", - "q": "0.10000000" + "p": "7133.33000000", + "q": "0.01179400" }, { "M": true, - "T": 1590640145901, - "a": 303004097, - "f": 329755558, - "l": 329755558, + "T": 1577981093925, + "a": 202798182, + "f": 222833662, + "l": 222833662, "m": true, - "p": "9194.99000000", - "q": "0.00000700" - }, + "p": "7133.54000000", + "q": "0.00169000" + } + ], + "queryString": "fromId=202797183\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ { "M": true, - "T": 1590640145901, - "a": 303004098, - "f": 329755559, - "l": 329755559, + "T": 1577981093925, + "a": 202798182, + "f": 222833662, + "l": 222833662, "m": true, - "p": "9194.98000000", - "q": "0.01963500" - }, - { - "M": true, - "T": 1590640145980, - "a": 303004099, - "f": 329755560, - "l": 329755560, - "m": false, - "p": "9194.99000000", - "q": "0.00490700" + "p": "7133.54000000", + "q": "0.00169000" }, { "M": true, - "T": 1590640146110, - "a": 303004100, - "f": 329755561, - "l": 329755561, - "m": false, - "p": "9194.99000000", - "q": "0.09509300" + "T": 1577981472010, + "a": 202799181, + "f": 222834707, + "l": 222834707, + "m": true, + "p": "7121.39000000", + "q": "0.01520000" } ], - "queryString": "endTime=1577978345000\u0026startTime=1577977445000\u0026symbol=BTCUSDT", + "queryString": "fromId=202798182\u0026limit=1000\u0026symbol=BTCUSDT", "bodyParams": "", "headers": {} }, @@ -11003,26 +11418,26 @@ "data": [ { "M": true, - "T": 1577977445200, - "a": 303004095, - "f": 329755557, - "l": 329755557, - "": false, - "p": "9195.09000000", - "q": "0.10000000" + "T": 1577981472010, + "a": 202799181, + "f": 222834707, + "l": 222834707, + "m": true, + "p": "7121.39000000", + "q": "0.01520000" }, { "M": true, - "T": 1577977445500, - "a": 303004096, - "f": 329755557, - "l": 329755557, - "": false, - "p": "9195.09000000", - "q": "0.10000000" + "T": 1577981710731, + "a": 202800180, + "f": 222835773, + "l": 222835773, + "m": true, + "p": "7117.40000000", + "q": "0.00928300" } ], - "queryString": "endTime=1577981045000\u0026limit=1000\u0026startTime=1577977445000\u0026symbol=BTCUSDT", + "queryString": "fromId=202799181\u0026limit=1000\u0026symbol=BTCUSDT", "bodyParams": "", "headers": {} }, @@ -11030,36 +11445,26 @@ "data": [ { "M": true, - "T": 1577977445500, - "a": 303004096, - "f": 329755557, - "l": 329755557, - "": false, - "p": "9195.09000000", - "q": "0.10000000" - }, - { - "M": true, - "T": 1577981944800, - "a": 303004097, - "f": 329755557, - "l": 329755557, - "": false, - "p": "9195.09000000", - "q": "0.10000000" + "T": 1577981710731, + "a": 202800180, + "f": 222835773, + "l": 222835773, + "m": true, + "p": "7117.40000000", + "q": "0.00928300" }, { "M": true, - "T": 1577981945200, - "a": 303004098, - "f": 329755557, - "l": 329755557, - "": false, - "p": "9195.09000000", - "q": "0.10000000" + "T": 1577981911919, + "a": 202801179, + "f": 222836824, + "l": 222836824, + "m": true, + "p": "7116.35000000", + "q": "0.04711200" } ], - "queryString": "fromId=303004096\u0026limit=1000\u0026symbol=BTCUSDT", + "queryString": "fromId=202800180\u0026limit=1000\u0026symbol=BTCUSDT", "bodyParams": "", "headers": {} }, @@ -11067,36 +11472,53 @@ "data": [ { "M": true, - "T": 1577977445500, - "a": 303004096, - "f": 329755557, - "l": 329755557, - "": false, - "p": "9195.09000000", - "q": "0.10000000" + "T": 1577981911919, + "a": 202801179, + "f": 222836824, + "l": 222836824, + "m": true, + "p": "7116.35000000", + "q": "0.04711200" }, { "M": true, - "T": 1577981944800, - "a": 303004097, - "f": 329755557, - "l": 329755557, - "": false, - "p": "9195.09000000", - "q": "0.10000000" + "T": 1577982176413, + "a": 202802178, + "f": 222837855, + "l": 222837855, + "m": true, + "p": "7118.05000000", + "q": "0.03511400" + } + ], + "queryString": "fromId=202801179\u0026limit=1000\u0026symbol=BTCUSDT", + "bodyParams": "", + "headers": {} + }, + { + "data": [ + { + "M": true, + "T": 1605740428136, + "a": 426856438, + "f": 471418857, + "l": 471418859, + "m": true, + "p": "17829.75000000", + "q": "0.04121300" }, { "M": true, - "T": 1577981945200, - "a": 303004098, - "f": 329755557, - "l": 329755557, - "": false, - "p": "9195.09000000", - "q": "0.10000000" + "T": 1605740437964, + "a": 426856605, + "f": 471419050, + "l": 471419050, + "m": false, + "p": "17824.14000000", + "q": "0.00091900" } ], - "queryString": "limit=3\u0026symbol=BTCUSDT", + "queryString": "endTime=1605740438000\u0026limit=1000\u0026startTime=1605740428000\u0026symbol=BTCUSDT", "bodyParams": "", "headers": {} }, @@ -11104,16 +11526,26 @@ "data": [ { "M": true, - "T": 1577981945200, - "a": 303004098, - "f": 329755557, - "l": 329755557, - "": false, - "p": "9195.09000000", - "q": "0.10000000" + "T": 1605740437964, + "a": 426856605, + "f": 471419050, + "l": 471419050, + "m": false, + "p": "17824.14000000", + "q": "0.00091900" + }, + { + "M": true, + "T": 1605740503449, + "a": 426857604, + "f": 471420258, + "l": 471420258, + "m": true, + "p": "17788.36000000", + "q": "0.01622700" } ], - "queryString": "fromId=303004098\u0026limit=1000\u0026symbol=BTCUSDT", + "queryString": "fromId=426856605\u0026limit=1000\u0026symbol=BTCUSDT", "bodyParams": "", "headers": {} }