From 8d2feb8433410fcd18f97816d1bb44983b30e3ae Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Wed, 7 Oct 2020 11:04:55 -0400 Subject: [PATCH 01/11] test(sim): connext collateralization with wait This restores the logic to request collateral in the custom xud builds used for instability tests by adding a one second wait after adding an order on the maker side (who then requests collateralization) but before placing a matching order on the taker side. This appears to work around a brief, transient inability to send a connext payment to a node immediately after that node requests collateral. Related PR #1916 - specifically the persistent simulation test failures that were eventually avoided by removing the collateral requests from custom-xud, which is being restored here. --- test/simulation/custom-xud.patch | 31 ---------------------------- test/simulation/tests-instability.go | 9 ++++++++ 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/test/simulation/custom-xud.patch b/test/simulation/custom-xud.patch index fb1334834..a4edd93a1 100644 --- a/test/simulation/custom-xud.patch +++ b/test/simulation/custom-xud.patch @@ -14,37 +14,6 @@ index 489a50a4..f9391527 100644 try { if (!this.config.rpc.disable) { // start rpc server first, it will respond with UNAVAILABLE error -diff --git a/lib/connextclient/ConnextClient.ts b/lib/connextclient/ConnextClient.ts -index 7fe05a71..240ad137 100644 ---- a/lib/connextclient/ConnextClient.ts -+++ b/lib/connextclient/ConnextClient.ts -@@ -309,24 +309,8 @@ class ConnextClient extends SwapClient { - } - } - -- public setReservedInboundAmount = (reservedInboundAmount: number, currency: string) => { -- const inboundCapacity = this._maxChannelInboundAmount.get(currency) || 0; -- if (inboundCapacity < reservedInboundAmount) { -- // we do not have enough inbound capacity to fill all open orders, so we will request more -- this.logger.debug(`collateral of ${inboundCapacity} for ${currency} is insufficient for reserved order amount of ${reservedInboundAmount}`); -- -- // we want to make a request for the current collateral plus the greater of any -- // minimum request size for the currency or the capacity shortage + 3% buffer -- const quantityToRequest = inboundCapacity + Math.max( -- reservedInboundAmount * 1.03 - inboundCapacity, -- ConnextClient.MIN_COLLATERAL_REQUEST_SIZES[currency] ?? 0, -- ); -- const unitsToRequest = this.unitConverter.amountToUnits({ currency, amount: quantityToRequest }); -- -- // we don't await this request - instead we allow for "lazy collateralization" to complete since -- // we don't expect all orders to be filled at once, we can be patient -- this.requestCollateralInBackground(currency, unitsToRequest); -- } -+ public setReservedInboundAmount = (_reservedInboundAmount: number, _currency: string) => { -+ // we don't request collateral for custom xud simulation tests - } - - protected updateCapacity = async () => { diff --git a/lib/swaps/SwapRecovery.ts b/lib/swaps/SwapRecovery.ts index 3759f6a3..4089dc94 100644 --- a/lib/swaps/SwapRecovery.ts diff --git a/test/simulation/tests-instability.go b/test/simulation/tests-instability.go index 9274cff72..f6a787eab 100644 --- a/test/simulation/tests-instability.go +++ b/test/simulation/tests-instability.go @@ -154,6 +154,9 @@ func testMakerCrashedDuringSwapConnextIn(net *xudtest.NetworkHarness, ht *harnes } ht.act.placeOrderAndBroadcast(net.Alice, net.Bob, aliceOrderReq) + // brief wait for collateralization to complete for Alice + time.Sleep(1 * time.Second) + // Place a matching order on Bob. bobOrderReq := &xudrpc.PlaceOrderRequest{ OrderId: "testMakerCrashedDuringSwapConnextIn", @@ -287,6 +290,9 @@ func testMakerConnextClientCrashedBeforeSettlement(net *xudtest.NetworkHarness, } ht.act.placeOrderAndBroadcast(net.Alice, net.Bob, aliceOrderReq) + // brief wait for collateralization to complete for Alice + time.Sleep(1 * time.Second) + // Place a matching order on Bob. bobOrderReq := &xudrpc.PlaceOrderRequest{ OrderId: "testMakerConnextClientCrashedBeforeSettlement", @@ -519,6 +525,9 @@ func testMakerCrashedAfterSendDelayedSettlementConnextIn(net *xudtest.NetworkHar } ht.act.placeOrderAndBroadcast(net.Alice, net.Bob, aliceOrderReq) + // brief wait for collateralization to complete for Alice + time.Sleep(1 * time.Second) + // Place a matching order on Bob. bobOrderReq := &xudrpc.PlaceOrderRequest{ OrderId: "testMakerCrashedAfterSendDelayedSettlementConnextIn", From be4121fd04156318c68dba28ee5f1a2483fd0c07 Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Fri, 9 Oct 2020 04:35:55 -0400 Subject: [PATCH 02/11] feat: derive child seed for swap clients This change uses separate mnemonics and seeds for each swap client that are unique to that client, rather than using a single seed and mnemonic across all clients. To accomplish this, a new method is added to the seedutil tool to derive a child mnemonic from a provided mnemonic. This is done by extracting the 16 bytes of entropy from the provided seed, concatenating the entropy with the name of the client (e.g. "LND-BTC") and then hashing the concatenation and taking 16 bytes from the resulting hash. Closes #1576. --- lib/lndclient/LndClient.ts | 9 ++++-- lib/nodekey/NodeKey.ts | 3 +- lib/utils/seedutil.ts | 14 +++++++- seedutil/SeedUtil.spec.ts | 30 +++++++++++++++++ seedutil/__snapshots__/SeedUtil.spec.ts.snap | 10 ++++++ seedutil/main.go | 34 ++++++++++++++++++++ 6 files changed, 96 insertions(+), 4 deletions(-) diff --git a/lib/lndclient/LndClient.ts b/lib/lndclient/LndClient.ts index e48230595..1ba7164f0 100644 --- a/lib/lndclient/LndClient.ts +++ b/lib/lndclient/LndClient.ts @@ -11,7 +11,8 @@ import { LightningClient, WalletUnlockerClient } from '../proto/lndrpc_grpc_pb'; import * as lndrpc from '../proto/lndrpc_pb'; import swapErrors from '../swaps/errors'; import SwapClient, { ChannelBalance, ClientStatus, PaymentState, SwapClientInfo, TradingLimits, WithdrawArguments } from '../swaps/SwapClient'; -import { SwapDeal, CloseChannelParams, OpenChannelParams } from '../swaps/types'; +import { CloseChannelParams, OpenChannelParams, SwapDeal } from '../swaps/types'; +import { deriveChild } from '../utils/seedutil'; import { base64ToHex, hexToUint8Array } from '../utils/utils'; import errors from './errors'; import { Chain, ChannelCount, ClientMethods, LndClientConfig, LndInfo } from './types'; @@ -918,7 +919,11 @@ class LndClient extends SwapClient { public initWallet = async (walletPassword: string, seedMnemonic: string[], restore = false, backup?: Uint8Array): Promise => { const request = new lndrpc.InitWalletRequest(); - request.setCipherSeedMnemonicList(seedMnemonic); + + // from the master seed/mnemonic we derive a child mnemonic for this specific client + const childMnemonic = await deriveChild(seedMnemonic, this.label); + request.setCipherSeedMnemonicList(childMnemonic); + request.setWalletPassword(Uint8Array.from(Buffer.from(walletPassword, 'utf8'))); if (restore) { request.setRecoveryWindow(2500); diff --git a/lib/nodekey/NodeKey.ts b/lib/nodekey/NodeKey.ts index de6b7857a..1f571d0a9 100644 --- a/lib/nodekey/NodeKey.ts +++ b/lib/nodekey/NodeKey.ts @@ -116,8 +116,9 @@ class NodeKey { } /** - * Derives a child seed from the private key for the swap client + * Derives a child mnemonic seed from the private key for the swap client. * @param swapClient the swap client to create the seed for + * @returns a BIP39 mnemonic */ public childSeed = (swapClient: SwapClientType) => { const privKeyHex = this.privKey.toString('hex'); diff --git a/lib/utils/seedutil.ts b/lib/utils/seedutil.ts index 31b1a630d..56f3f49cb 100644 --- a/lib/utils/seedutil.ts +++ b/lib/utils/seedutil.ts @@ -53,6 +53,18 @@ async function decipher(mnemonic: string[]) { return Buffer.from(decipheredSeed, 'hex'); } +async function deriveChild(mnemonic: string[], clientType: string) { + const { stdout, stderr } = await exec(`${seedutilPath} derivechild -client ${clientType} ${mnemonic.join(' ')}`); + + if (stderr) { + throw new Error(stderr); + } + + const childMnenomic = stdout.trim().split(' '); + assert.equal(childMnenomic.length, 24, 'seedutil did not derive child mnemonic of exactly 24 words'); + return childMnenomic; +} + async function generate() { const { stdout, stderr } = await exec(`${seedutilPath} generate`); @@ -65,4 +77,4 @@ async function generate() { return mnemonic; } -export { keystore, encipher, decipher, generate }; +export { keystore, encipher, decipher, deriveChild, generate }; diff --git a/seedutil/SeedUtil.spec.ts b/seedutil/SeedUtil.spec.ts index cc30a4584..adec48150 100644 --- a/seedutil/SeedUtil.spec.ts +++ b/seedutil/SeedUtil.spec.ts @@ -143,6 +143,36 @@ describe('SeedUtil generate', () => { }); }); +describe('SeedUtil derivechild', () => { + test('it errors without a client type', async () => { + const cmd = `./seedutil/seedutil derivechild ${VALID_SEED.seedWords.slice(0, 24).join(' ')}`; + await expect(executeCommand(cmd)) + .rejects.toThrow('client is required'); + }); + + test('it errors with 23 words', async () => { + const cmd = `./seedutil/seedutil derivechild -client BTC ${VALID_SEED.seedWords.slice(0, 23).join(' ')}`; + await expect(executeCommand(cmd)) + .rejects.toThrow(ERRORS.INVALID_ARGS_LENGTH); + }); + + test('it succeeds with 24 words, no aezeed password', async () => { + const cmd = `./seedutil/seedutil derivechild -client BTC ${VALID_SEED_NO_PASS.seedWords.join(' ')}`; + const result = await executeCommand(cmd); + // the mnemonic will change each time due to the salt, but the deciphered seed should stay the same + const decipherCmd = `./seedutil/seedutil decipher ${result}`; + await expect(executeCommand(decipherCmd)).resolves.toMatchSnapshot(); + }); + + test('it succeeds with 24 words, valid aezeed password', async () => { + const cmd = `./seedutil/seedutil derivechild -aezeedpass=${VALID_SEED.seedPassword} -client BTC ${VALID_SEED.seedWords.join(' ')}`; + const result = await executeCommand(cmd); + // the mnemonic will change each time due to the salt, but the deciphered seed should stay the same + const decipherCmd = `./seedutil/seedutil decipher -aezeedpass=${VALID_SEED.seedPassword} ${result}`; + await expect(executeCommand(decipherCmd)).resolves.toMatchSnapshot(); + }); +}); + describe('SeedUtil keystore', () => { beforeEach(async () => { await deleteDir(DEFAULT_KEYSTORE_PATH); diff --git a/seedutil/__snapshots__/SeedUtil.spec.ts.snap b/seedutil/__snapshots__/SeedUtil.spec.ts.snap index 32a2858fc..5c1805510 100644 --- a/seedutil/__snapshots__/SeedUtil.spec.ts.snap +++ b/seedutil/__snapshots__/SeedUtil.spec.ts.snap @@ -10,6 +10,16 @@ exports[`SeedUtil decipher it succeeds with 24 words, valid aezeed password 1`] " `; +exports[`SeedUtil derivechild it succeeds with 24 words, no aezeed password 1`] = ` +"000f4b90d9f9720bfac78aaea09a5193b34811 +" +`; + +exports[`SeedUtil derivechild it succeeds with 24 words, valid aezeed password 1`] = ` +"000ecdef333ecf9054ccb4fb843a3dbbf4ac6a +" +`; + exports[`SeedUtil encipher it succeeds with 24 words, no aezeed password 1`] = ` "00738860374692022c462027a35aaaef3c3289aa0a057e2600000000002cad2e2b " diff --git a/seedutil/main.go b/seedutil/main.go index 2dbedb21d..b247d6493 100644 --- a/seedutil/main.go +++ b/seedutil/main.go @@ -58,6 +58,7 @@ func main() { encipherCommand := flag.NewFlagSet("encipher", flag.ExitOnError) decipherCommand := flag.NewFlagSet("decipher", flag.ExitOnError) generateCommand := flag.NewFlagSet("generate", flag.ExitOnError) + deriveChildCommand := flag.NewFlagSet("derivechild", flag.ExitOnError) if len(os.Args) < 2 { fmt.Println("subcommand is required") @@ -132,6 +133,39 @@ func main() { } fmt.Println(hex.EncodeToString(decipheredSeed[:])) + case "derivechild": + client := deriveChildCommand.String("client", "", "client type") + aezeedPassphrase := deriveChildCommand.String("aezeedpass", defaultAezeedPassphrase, "aezeed passphrase") + deriveChildCommand.Parse(os.Args[2:]) + args = deriveChildCommand.Args() + + if client == nil || len(*client) == 0 { + fmt.Fprintf(os.Stderr, "client is required") + os.Exit(1) + } + + mnemonic := parseMnemonic(args) + cipherSeed := mnemonicToCipherSeed(mnemonic, aezeedPassphrase) + + // derive 64-byte hash from client type + cipherSeed's 16 bytes of entropy + hash := sha512.Sum512(append([]byte(*client), cipherSeed.Entropy[:]...)) + + // use the first 16 byte of the hash as the new entropy + var newEntropy [16]byte + copy(newEntropy[:], hash[:16]) + + childCipherSeed, err := aezeed.New(0, &newEntropy, cipherSeed.BirthdayTime()) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + childMnemonic, err := childCipherSeed.ToMnemonic([]byte(*aezeedPassphrase)) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + fmt.Println(strings.Join([]string(childMnemonic[:]), " ")) case "generate": aezeedPassphrase := generateCommand.String("aezeedpass", defaultAezeedPassphrase, "aezeed passphrase") generateCommand.Parse(os.Args[2:]) From 8b18dd7426f01a760e571a0a5bb2310759229b64 Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Tue, 13 Oct 2020 14:17:29 -0400 Subject: [PATCH 03/11] feat(rpc): expose reserved balance for GetBalance (#1925) This adds a field to the `GetBalance` response to return the balance that is reserved for open orders. --- docs/api.md | 1 + lib/cli/commands/getbalance.ts | 38 +- lib/grpc/GrpcService.ts | 3 + lib/proto/xudrpc.swagger.json | 5 + lib/proto/xudrpc_pb.d.ts | 4 + lib/proto/xudrpc_pb.js | 29 +- lib/service/Service.ts | 11 +- lib/swaps/SwapClient.ts | 2 + lib/swaps/SwapClientManager.ts | 12 +- proto/xudrpc.proto | 2 + test/jest/Service.spec.ts | 56 ++ test/jest/SwapClientManager.spec.ts | 12 +- .../cli/__snapshots__/getbalance.spec.ts.snap | 81 +++ test/jest/cli/getbalance.spec.ts | 96 ++++ test/simulation/tests-integration.go | 9 +- test/simulation/xudrpc/xudrpc.pb.go | 498 +++++++++--------- 16 files changed, 585 insertions(+), 274 deletions(-) create mode 100644 test/jest/cli/__snapshots__/getbalance.spec.ts.snap create mode 100644 test/jest/cli/getbalance.spec.ts diff --git a/docs/api.md b/docs/api.md index 14334d1d9..9a3224af7 100644 --- a/docs/api.md +++ b/docs/api.md @@ -156,6 +156,7 @@ | inactive_channel_balance | [uint64](#uint64) | | Sum of inactive channel balances denominated in satoshis. | | wallet_balance | [uint64](#uint64) | | Confirmed wallet balance in satoshis. | | unconfirmed_wallet_balance | [uint64](#uint64) | | Unconfirmed wallet balance in satoshis. | +| reserved_balance | [uint64](#uint64) | | The balance that's reserved for open orders. | diff --git a/lib/cli/commands/getbalance.ts b/lib/cli/commands/getbalance.ts index 9a98fbc7d..c058a2b53 100644 --- a/lib/cli/commands/getbalance.ts +++ b/lib/cli/commands/getbalance.ts @@ -8,40 +8,46 @@ import { satsToCoinsStr } from '../utils'; const HEADERS = [ colors.blue('Currency'), colors.blue('Total Balance'), - colors.blue('Channel Balance (Tradable)'), colors.blue('Wallet Balance (Not Tradable)'), + colors.blue('Channel Balance (Tradable)'), + colors.blue('In Orders'), ]; const formatBalances = (balances: GetBalanceResponse.AsObject) => { const formatted: any[] = []; - balances.balancesMap.forEach((balance) => { + balances.balancesMap.forEach((balanceElement) => { + const currency = balanceElement[0]; + const balance = balanceElement[1]; const element = []; element.push( - balance[0], - `${satsToCoinsStr(balance[1].totalBalance)}`, - formatBalance(balance[1].channelBalance, balance[1].pendingChannelBalance, balance[1].inactiveChannelBalance), - formatBalance(balance[1].walletBalance, balance[1].unconfirmedWalletBalance), + currency, + satsToCoinsStr(balance.totalBalance), + formatBalance(balance.channelBalance, balance.pendingChannelBalance, balance.inactiveChannelBalance), + formatBalance(balance.walletBalance, balance.unconfirmedWalletBalance), + satsToCoinsStr(balance.reservedBalance), ); formatted.push(element); }); return formatted; }; -const formatBalance = (confirmedBalance: number, unconfirmedBalance: number, inactiveBalance = 0) => { - const confirmedBalanceStr = satsToCoinsStr(confirmedBalance); - const unconfirmedBalanceStr = unconfirmedBalance > 0 ? `${satsToCoinsStr(unconfirmedBalance)} pending` : undefined; +const formatBalance = (availableBalance: number, pendingBalance: number, inactiveBalance = 0) => { + const availableBalanceStr = satsToCoinsStr(availableBalance); + const unconfirmedBalanceStr = pendingBalance > 0 ? `${satsToCoinsStr(pendingBalance)} pending` : undefined; const inactiveBalanceStr = inactiveBalance > 0 ? `${satsToCoinsStr(inactiveBalance)} inactive` : undefined; if (unconfirmedBalanceStr || inactiveBalanceStr) { - let str = `${confirmedBalanceStr} (`; + let str = availableBalanceStr; + let paranthetical = ''; if (unconfirmedBalanceStr) { - str += inactiveBalanceStr ? `${inactiveBalanceStr} | ${unconfirmedBalanceStr}` : unconfirmedBalanceStr; - } else { - str += inactiveBalanceStr; + paranthetical += paranthetical ? ` | ${unconfirmedBalanceStr}` : unconfirmedBalanceStr; + } + if (inactiveBalanceStr) { + paranthetical += paranthetical ? ` | ${inactiveBalanceStr}` : inactiveBalanceStr; } - str += ')'; + str += ` (${paranthetical})`; return str; } - return confirmedBalanceStr; + return availableBalanceStr; }; const createTable = () => { @@ -51,7 +57,7 @@ const createTable = () => { return table; }; -const displayBalances = (balances: GetBalanceResponse.AsObject) => { +export const displayBalances = (balances: GetBalanceResponse.AsObject) => { const table = createTable(); const formatted = formatBalances(balances); formatted.forEach(balance => table.push(balance)); diff --git a/lib/grpc/GrpcService.ts b/lib/grpc/GrpcService.ts index 2a79d3acb..45a8ca430 100644 --- a/lib/grpc/GrpcService.ts +++ b/lib/grpc/GrpcService.ts @@ -307,6 +307,9 @@ class GrpcService { balance.setInactiveChannelBalance(balanceObj.inactiveChannelBalance); balance.setWalletBalance(balanceObj.walletBalance); balance.setUnconfirmedWalletBalance(balanceObj.unconfirmedWalletBalance); + if (balanceObj.reservedBalance) { + balance.setReservedBalance(balanceObj.reservedBalance); + } balancesMap.set(currency, balance); }); callback(null, response); diff --git a/lib/proto/xudrpc.swagger.json b/lib/proto/xudrpc.swagger.json index bdd789be3..0a1c485ae 100644 --- a/lib/proto/xudrpc.swagger.json +++ b/lib/proto/xudrpc.swagger.json @@ -887,6 +887,11 @@ "type": "string", "format": "uint64", "description": "Unconfirmed wallet balance in satoshis." + }, + "reserved_balance": { + "type": "string", + "format": "uint64", + "description": "The balance that's reserved for open orders." } } }, diff --git a/lib/proto/xudrpc_pb.d.ts b/lib/proto/xudrpc_pb.d.ts index 0c450920a..93e2eb745 100644 --- a/lib/proto/xudrpc_pb.d.ts +++ b/lib/proto/xudrpc_pb.d.ts @@ -84,6 +84,9 @@ export class Balance extends jspb.Message { getUnconfirmedWalletBalance(): number; setUnconfirmedWalletBalance(value: number): void; + getReservedBalance(): number; + setReservedBalance(value: number): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): Balance.AsObject; @@ -103,6 +106,7 @@ export namespace Balance { inactiveChannelBalance: number, walletBalance: number, unconfirmedWalletBalance: number, + reservedBalance: number, } } diff --git a/lib/proto/xudrpc_pb.js b/lib/proto/xudrpc_pb.js index e02967cec..08518fe93 100644 --- a/lib/proto/xudrpc_pb.js +++ b/lib/proto/xudrpc_pb.js @@ -546,7 +546,8 @@ proto.xudrpc.Balance.toObject = function(includeInstance, msg) { pendingChannelBalance: jspb.Message.getFieldWithDefault(msg, 3, 0), inactiveChannelBalance: jspb.Message.getFieldWithDefault(msg, 4, 0), walletBalance: jspb.Message.getFieldWithDefault(msg, 5, 0), - unconfirmedWalletBalance: jspb.Message.getFieldWithDefault(msg, 6, 0) + unconfirmedWalletBalance: jspb.Message.getFieldWithDefault(msg, 6, 0), + reservedBalance: jspb.Message.getFieldWithDefault(msg, 7, 0) }; if (includeInstance) { @@ -607,6 +608,10 @@ proto.xudrpc.Balance.deserializeBinaryFromReader = function(msg, reader) { var value = /** @type {number} */ (reader.readUint64()); msg.setUnconfirmedWalletBalance(value); break; + case 7: + var value = /** @type {number} */ (reader.readUint64()); + msg.setReservedBalance(value); + break; default: reader.skipField(); break; @@ -678,6 +683,13 @@ proto.xudrpc.Balance.serializeBinaryToWriter = function(message, writer) { f ); } + f = message.getReservedBalance(); + if (f !== 0) { + writer.writeUint64( + 7, + f + ); + } }; @@ -771,6 +783,21 @@ proto.xudrpc.Balance.prototype.setUnconfirmedWalletBalance = function(value) { }; +/** + * optional uint64 reserved_balance = 7; + * @return {number} + */ +proto.xudrpc.Balance.prototype.getReservedBalance = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 7, 0)); +}; + + +/** @param {number} value */ +proto.xudrpc.Balance.prototype.setReservedBalance = function(value) { + jspb.Message.setProto3IntField(this, 7, value); +}; + + /** * Generated by JsPbCodeGenerator. diff --git a/lib/service/Service.ts b/lib/service/Service.ts index 41d9924ae..2c49b2207 100644 --- a/lib/service/Service.ts +++ b/lib/service/Service.ts @@ -8,10 +8,10 @@ import OrderBook from '../orderbook/OrderBook'; import { Currency, isOwnOrder, Order, OrderPortion, OwnLimitOrder, OwnMarketOrder, OwnOrder, PeerOrder, PlaceOrderEvent } from '../orderbook/types'; import Pool from '../p2p/Pool'; import swapsErrors from '../swaps/errors'; -import { TradingLimits } from '../swaps/SwapClient'; +import { ChannelBalance, TradingLimits } from '../swaps/SwapClient'; import SwapClientManager from '../swaps/SwapClientManager'; import Swaps from '../swaps/Swaps'; -import { ResolveRequest, SwapDeal, SwapFailure, SwapSuccess, SwapAccepted } from '../swaps/types'; +import { ResolveRequest, SwapAccepted, SwapDeal, SwapFailure, SwapSuccess } from '../swaps/types'; import { isNodePubKey } from '../utils/aliasUtils'; import { parseUri, toUri, UriParts } from '../utils/uriUtils'; import { checkDecimalPlaces, sortOrders, toEip55Address } from '../utils/utils'; @@ -113,7 +113,7 @@ class Service { /** Gets the total balance for one or all currencies. */ public getBalance = async (args: { currency: string }) => { const { currency } = args; - const channelBalances = new Map(); + const channelBalances = new Map(); const walletBalances = new Map(); if (currency) { @@ -125,6 +125,7 @@ class Service { await swapClient.channelBalance(currency), await swapClient.walletBalance(currency), ]); + channelBalance.reservedBalance = this.swapClientManager.getOutboundReservedAmount(currency); channelBalances.set(currency, channelBalance); walletBalances.set(currency, walletBalance); } else { @@ -135,6 +136,7 @@ class Service { this.swapClientManager.swapClients.forEach((swapClient, currency) => { if (swapClient.isConnected()) { balancePromises.push(swapClient.channelBalance(currency).then((channelBalance) => { + channelBalance.reservedBalance = this.swapClientManager.getOutboundReservedAmount(currency); channelBalances.set(currency, channelBalance); }).catch(this.logger.error)); balancePromises.push(swapClient.walletBalance(currency).then((walletBalance) => { @@ -147,7 +149,7 @@ class Service { const balances = new Map(); channelBalances.forEach((channelBalance, currency) => { const walletBalance = walletBalances.get(currency); @@ -162,6 +164,7 @@ class Service { channelBalance: channelBalance.balance, pendingChannelBalance: channelBalance.pendingOpenBalance, inactiveChannelBalance: channelBalance.inactiveBalance, + reservedBalance: channelBalance.reservedBalance, walletBalance: walletBalance.confirmedBalance, unconfirmedWalletBalance: walletBalance.unconfirmedBalance, }); diff --git a/lib/swaps/SwapClient.ts b/lib/swaps/SwapClient.ts index 14fe24c41..bf158052a 100644 --- a/lib/swaps/SwapClient.ts +++ b/lib/swaps/SwapClient.ts @@ -34,6 +34,8 @@ type ChannelBalance = { pendingOpenBalance: number, /** The cumulative balance of inactive channels denominated in satoshis. */ inactiveBalance: number, + /** The balance that is reserved for open orders denominated in satoshis. */ + reservedBalance?: number, }; type WalletBalance = { diff --git a/lib/swaps/SwapClientManager.ts b/lib/swaps/SwapClientManager.ts index d38fea186..2d76a4bae 100644 --- a/lib/swaps/SwapClientManager.ts +++ b/lib/swaps/SwapClientManager.ts @@ -163,6 +163,14 @@ class SwapClientManager extends EventEmitter { } } + public getOutboundReservedAmount = (currency: string) => { + return this.outboundReservedAmounts.get(currency); + } + + public getInboundReservedAmount = (currency: string) => { + return this.inboundReservedAmounts.get(currency); + } + public addOutboundReservedAmount = (currency: string, amount: number) => { const outboundReservedAmount = this.outboundReservedAmounts.get(currency); const newOutboundReservedAmount = (outboundReservedAmount ?? 0) + amount; @@ -180,13 +188,13 @@ class SwapClientManager extends EventEmitter { public subtractOutboundReservedAmount = (currency: string, amount: number) => { const outboundReservedAmount = this.outboundReservedAmounts.get(currency); assert(outboundReservedAmount && outboundReservedAmount >= amount); - this.outboundReservedAmounts.set(currency, (outboundReservedAmount ?? 0) - amount); + this.outboundReservedAmounts.set(currency, outboundReservedAmount - amount); } public subtractInboundReservedAmount = (currency: string, amount: number) => { const inboundReservedAmount = this.inboundReservedAmounts.get(currency); assert(inboundReservedAmount && inboundReservedAmount >= amount); - this.inboundReservedAmounts.set(currency, (inboundReservedAmount ?? 0) - amount); + this.inboundReservedAmounts.set(currency, inboundReservedAmount - amount); } /** diff --git a/proto/xudrpc.proto b/proto/xudrpc.proto index 15ca3f27b..fce3113a7 100644 --- a/proto/xudrpc.proto +++ b/proto/xudrpc.proto @@ -359,6 +359,8 @@ message Balance { uint64 wallet_balance = 5 [json_name = "wallet_balance"]; // Unconfirmed wallet balance in satoshis. uint64 unconfirmed_wallet_balance = 6 [json_name = "unconfirmed_wallet_balance"]; + // The balance that's reserved for open orders. + uint64 reserved_balance = 7 [json_name = "reserved_balance"]; } message BanRequest { diff --git a/test/jest/Service.spec.ts b/test/jest/Service.spec.ts index a0b5d749a..d50e6a1bb 100644 --- a/test/jest/Service.spec.ts +++ b/test/jest/Service.spec.ts @@ -17,6 +17,7 @@ jest.mock('../../lib/swaps/SwapClientManager', () => { return jest.fn().mockImplementation(() => { return { getType: () => SwapClientType.Lnd, + getOutboundReservedAmount: () => 0, }; }); }); @@ -189,6 +190,61 @@ describe('Service', () => { expect(btcBalance.totalBalance).toEqual(289008); }); + test('returns balance with reserved amounts', async () => { + setup(); + const reservedBalance = 10000; + service['swapClientManager'].getOutboundReservedAmount = jest.fn().mockReturnValue(reservedBalance); + const result = await service.getBalance({ currency: 'BTC' }); + expect(result.size).toEqual(1); + + const btcBalance = result.get('BTC')!; + expect(btcBalance).toBeTruthy(); + expect(btcBalance.channelBalance).toEqual(70000); + expect(btcBalance.pendingChannelBalance).toEqual(190191); + expect(btcBalance.inactiveChannelBalance).toEqual(18817); + expect(btcBalance.walletBalance).toEqual(10000); + expect(btcBalance.unconfirmedWalletBalance).toEqual(0); + expect(btcBalance.totalBalance).toEqual(289008); + expect(btcBalance.reservedBalance).toEqual(reservedBalance); + }); + + test('returns balance with reserved amounts for multiple currencies', async () => { + setup(); + const btcReservedBalance = 10000; + const ltcReservedBalance = 2345; + service['swapClientManager'].getOutboundReservedAmount = jest.fn().mockImplementation((currency) => { + if (currency === 'BTC') { + return btcReservedBalance; + } + if (currency === 'LTC') { + return ltcReservedBalance; + } + return undefined; + }); + const result = await service.getBalance({ currency: '' }); + expect(result.size).toEqual(2); + + const btcBalance = result.get('BTC')!; + expect(btcBalance).toBeTruthy(); + expect(btcBalance.channelBalance).toEqual(70000); + expect(btcBalance.pendingChannelBalance).toEqual(190191); + expect(btcBalance.inactiveChannelBalance).toEqual(18817); + expect(btcBalance.walletBalance).toEqual(10000); + expect(btcBalance.unconfirmedWalletBalance).toEqual(0); + expect(btcBalance.totalBalance).toEqual(289008); + expect(btcBalance.reservedBalance).toEqual(btcReservedBalance); + + const ltcBalance = result.get('LTC')!; + expect(ltcBalance).toBeTruthy(); + expect(ltcBalance.channelBalance).toEqual(0); + expect(ltcBalance.pendingChannelBalance).toEqual(0); + expect(ltcBalance.inactiveChannelBalance).toEqual(12345); + expect(ltcBalance.walletBalance).toEqual(1500); + expect(ltcBalance.unconfirmedWalletBalance).toEqual(500); + expect(ltcBalance.totalBalance).toEqual(14345); + expect(ltcBalance.reservedBalance).toEqual(ltcReservedBalance); + }); + test('throws in case of invalid currency', async () => { setup(); await expect(service.getBalance({ currency: 'A' })).rejects.toMatchSnapshot(); diff --git a/test/jest/SwapClientManager.spec.ts b/test/jest/SwapClientManager.spec.ts index a7fc413a8..d2fe9be39 100644 --- a/test/jest/SwapClientManager.spec.ts +++ b/test/jest/SwapClientManager.spec.ts @@ -185,19 +185,19 @@ describe('Swaps.SwapClientManager', () => { }); test('it adds outbound reserved amounts', () => { - expect(swapClientManager['outboundReservedAmounts'].get(currency)).toBeUndefined(); + expect(swapClientManager.getOutboundReservedAmount(currency)).toBeUndefined(); swapClientManager.addOutboundReservedAmount(currency, amount); - expect(swapClientManager['outboundReservedAmounts'].get(currency)).toEqual(amount); + expect(swapClientManager.getOutboundReservedAmount(currency)).toEqual(amount); swapClientManager.addOutboundReservedAmount(currency, amount); - expect(swapClientManager['outboundReservedAmounts'].get(currency)).toEqual(amount * 2); + expect(swapClientManager.getOutboundReservedAmount(currency)).toEqual(amount * 2); }); test('it subtracts outbound reserved amounts', () => { - expect(swapClientManager['outboundReservedAmounts'].get(currency)).toBeUndefined(); + expect(swapClientManager.getOutboundReservedAmount(currency)).toBeUndefined(); swapClientManager.addOutboundReservedAmount(currency, amount); - expect(swapClientManager['outboundReservedAmounts'].get(currency)).toEqual(amount); + expect(swapClientManager.getOutboundReservedAmount(currency)).toEqual(amount); swapClientManager.subtractOutboundReservedAmount(currency, amount); - expect(swapClientManager['outboundReservedAmounts'].get(currency)).toEqual(0); + expect(swapClientManager.getOutboundReservedAmount(currency)).toEqual(0); }); test('it adds inbound reserved amounts and sets amount on swap client', () => { diff --git a/test/jest/cli/__snapshots__/getbalance.spec.ts.snap b/test/jest/cli/__snapshots__/getbalance.spec.ts.snap new file mode 100644 index 000000000..707c6bd5a --- /dev/null +++ b/test/jest/cli/__snapshots__/getbalance.spec.ts.snap @@ -0,0 +1,81 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`displayBalances should print a table 1`] = ` +Array [ + Array [ + " +Balance:", + ], + Array [ + "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┬───────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ +├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┼───────────┤ +│ BTC │ 0.005 │ 0.004 │ 0.001 │ 0 │ +└──────────┴───────────────┴───────────────────────────────┴────────────────────────────┴───────────┘", + ], +] +`; + +exports[`displayBalances should print a table with balance reserved for orders 1`] = ` +Array [ + Array [ + " +Balance:", + ], + Array [ + "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┬───────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ +├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┼───────────┤ +│ BTC │ 0.005 │ 0.004 │ 0.001 │ 0.0008 │ +└──────────┴───────────────┴───────────────────────────────┴────────────────────────────┴───────────┘", + ], +] +`; + +exports[`displayBalances should print a table with pending and inactive balances 1`] = ` +Array [ + Array [ + " +Balance:", + ], + Array [ + "┌──────────┬───────────────┬──────────────────────────────────────────┬────────────────────────────┬───────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ +├──────────┼───────────────┼──────────────────────────────────────────┼────────────────────────────┼───────────┤ +│ BTC │ 0.005 │ 0.004 (0.00075 pending | 0.001 inactive) │ 0.001 (0.00025 pending) │ 0 │ +└──────────┴───────────────┴──────────────────────────────────────────┴────────────────────────────┴───────────┘", + ], +] +`; + +exports[`displayBalances should print a table with pending balances 1`] = ` +Array [ + Array [ + " +Balance:", + ], + Array [ + "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┬───────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ +├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┼───────────┤ +│ BTC │ 0.005 │ 0.004 (0.00075 pending) │ 0.001 (0.00025 pending) │ 0 │ +└──────────┴───────────────┴───────────────────────────────┴────────────────────────────┴───────────┘", + ], +] +`; + +exports[`displayBalances should print a table with pending, inactive, and reserved balances 1`] = ` +Array [ + Array [ + " +Balance:", + ], + Array [ + "┌──────────┬───────────────┬──────────────────────────────────────────┬────────────────────────────┬───────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ +├──────────┼───────────────┼──────────────────────────────────────────┼────────────────────────────┼───────────┤ +│ BTC │ 0.005 │ 0.004 (0.00075 pending | 0.001 inactive) │ 0.001 (0.00025 pending) │ 0.0008 │ +└──────────┴───────────────┴──────────────────────────────────────────┴────────────────────────────┴───────────┘", + ], +] +`; diff --git a/test/jest/cli/getbalance.spec.ts b/test/jest/cli/getbalance.spec.ts new file mode 100644 index 000000000..647f7509c --- /dev/null +++ b/test/jest/cli/getbalance.spec.ts @@ -0,0 +1,96 @@ +import { displayBalances } from '../../../lib/cli/commands/getbalance'; + +jest.mock('colors/safe', () => { + return { + blue: (str: string) => str, + underline: (str: string) => str, + bold: (str: string) => str, + }; +}); + +describe('displayBalances', () => { + const mockLog = jest.fn(); + console.log = mockLog; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should print a table', () => { + displayBalances({ + balancesMap: [['BTC', { + totalBalance: 500000, + channelBalance: 400000, + pendingChannelBalance: 0, + inactiveChannelBalance: 0, + walletBalance: 100000, + unconfirmedWalletBalance: 0, + reservedBalance: 0, + }]], + }); + + expect(mockLog.mock.calls).toMatchSnapshot(); + }); + + it('should print a table with pending balances', () => { + displayBalances({ + balancesMap: [['BTC', { + totalBalance: 500000, + channelBalance: 400000, + pendingChannelBalance: 75000, + inactiveChannelBalance: 0, + walletBalance: 100000, + unconfirmedWalletBalance: 25000, + reservedBalance: 0, + }]], + }); + expect(mockLog.mock.calls).toMatchSnapshot(); + }); + + it('should print a table with pending and inactive balances', () => { + displayBalances({ + balancesMap: [['BTC', { + totalBalance: 500000, + channelBalance: 400000, + pendingChannelBalance: 75000, + inactiveChannelBalance: 100000, + walletBalance: 100000, + unconfirmedWalletBalance: 25000, + reservedBalance: 0, + }]], + }); + + expect(mockLog.mock.calls).toMatchSnapshot(); + }); + + it('should print a table with balance reserved for orders', () => { + displayBalances({ + balancesMap: [['BTC', { + totalBalance: 500000, + channelBalance: 400000, + pendingChannelBalance: 0, + inactiveChannelBalance: 0, + walletBalance: 100000, + unconfirmedWalletBalance: 0, + reservedBalance: 80000, + }]], + }); + expect(mockLog.mock.calls).toMatchSnapshot(); + }); + + it('should print a table with pending, inactive, and reserved balances', () => { + displayBalances({ + balancesMap: [['BTC', { + totalBalance: 500000, + channelBalance: 400000, + pendingChannelBalance: 75000, + inactiveChannelBalance: 100000, + walletBalance: 100000, + unconfirmedWalletBalance: 25000, + reservedBalance: 80000, + }]], + }); + expect(mockLog.mock.calls).toMatchSnapshot(); + }); + +}); diff --git a/test/simulation/tests-integration.go b/test/simulation/tests-integration.go index 86ad4d804..1414ef6eb 100644 --- a/test/simulation/tests-integration.go +++ b/test/simulation/tests-integration.go @@ -198,12 +198,19 @@ func testOrderBroadcastAndInvalidation(net *xudtest.NetworkHarness, ht *harnessT Price: 0.02, Quantity: 1000000, PairId: "LTC/BTC", - OrderId: "random_order_id", + OrderId: "testOrderBroadcastAndInvalidation", Side: xudrpc.OrderSide_BUY, } order := ht.act.placeOrderAndBroadcast(net.Alice, net.Bob, req) + resBal, err := net.Alice.Client.GetBalance(ht.ctx, &xudrpc.GetBalanceRequest{Currency: "BTC"}) + ht.assert.NoError(err) + ht.assert.Equal(20000, int(resBal.Balances["BTC"].ReservedBalance)) + ht.act.removeOrderAndInvalidate(net.Alice, net.Bob, order) + resBal, err = net.Alice.Client.GetBalance(ht.ctx, &xudrpc.GetBalanceRequest{Currency: "BTC"}) + ht.assert.NoError(err) + ht.assert.Equal(0, int(resBal.Balances["BTC"].ReservedBalance)) // Cleanup. ht.act.disconnect(net.Alice, net.Bob) diff --git a/test/simulation/xudrpc/xudrpc.pb.go b/test/simulation/xudrpc/xudrpc.pb.go index ecd863ce4..3f484b720 100644 --- a/test/simulation/xudrpc/xudrpc.pb.go +++ b/test/simulation/xudrpc/xudrpc.pb.go @@ -255,10 +255,12 @@ type Balance struct { // Confirmed wallet balance in satoshis. WalletBalance uint64 `protobuf:"varint,5,opt,name=wallet_balance,proto3" json:"wallet_balance,omitempty"` // Unconfirmed wallet balance in satoshis. - UnconfirmedWalletBalance uint64 `protobuf:"varint,6,opt,name=unconfirmed_wallet_balance,proto3" json:"unconfirmed_wallet_balance,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + UnconfirmedWalletBalance uint64 `protobuf:"varint,6,opt,name=unconfirmed_wallet_balance,proto3" json:"unconfirmed_wallet_balance,omitempty"` + // The balance that's reserved for open orders. + ReservedBalance uint64 `protobuf:"varint,7,opt,name=reserved_balance,proto3" json:"reserved_balance,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Balance) Reset() { *m = Balance{} } @@ -328,6 +330,13 @@ func (m *Balance) GetUnconfirmedWalletBalance() uint64 { return 0 } +func (m *Balance) GetReservedBalance() uint64 { + if m != nil { + return m.ReservedBalance + } + return 0 +} + type BanRequest struct { // The node pub key or alias of the node to ban. NodeIdentifier string `protobuf:"bytes,1,opt,name=node_identifier,proto3" json:"node_identifier,omitempty"` @@ -4413,246 +4422,247 @@ func init() { func init() { proto.RegisterFile("xudrpc.proto", fileDescriptor_6960a02cc0a63cf6) } var fileDescriptor_6960a02cc0a63cf6 = []byte{ - // 3823 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3a, 0x4d, 0x8f, 0x1d, 0xc7, - 0x56, 0xd3, 0xf7, 0xce, 0x9d, 0x7b, 0xe7, 0xdc, 0xcf, 0xa9, 0xf9, 0xf0, 0xf5, 0x8d, 0x93, 0xf8, - 0x15, 0x71, 0xe4, 0x38, 0x89, 0x6d, 0x26, 0x84, 0xbc, 0x18, 0x1c, 0xc5, 0x33, 0x1e, 0x62, 0x27, - 0x13, 0xdb, 0xea, 0x71, 0x9e, 0xcd, 0x13, 0xa4, 0xd5, 0xb7, 0xbb, 0xec, 0x69, 0xdc, 0x53, 0x7d, - 0xd3, 0x1f, 0x1e, 0x0f, 0x6c, 0xd0, 0x13, 0x2b, 0x58, 0x22, 0xd6, 0xb0, 0x42, 0x48, 0x20, 0xb6, - 0x88, 0x05, 0x12, 0x6b, 0xb6, 0x2c, 0x90, 0x80, 0x0d, 0x12, 0xbf, 0x00, 0xb1, 0x45, 0x42, 0xf5, - 0xd5, 0x55, 0xd5, 0xdd, 0x77, 0x9e, 0xfd, 0x04, 0x6f, 0xd7, 0x75, 0xea, 0xd4, 0xa9, 0x3a, 0x1f, - 0x75, 0xea, 0x7c, 0x34, 0x0c, 0x5e, 0x15, 0x61, 0xba, 0x08, 0xae, 0x2f, 0xd2, 0x24, 0x4f, 0xd0, - 0x9a, 0x18, 0xcd, 0x36, 0x7c, 0x4a, 0x93, 0xdc, 0xcf, 0xa3, 0x84, 0x66, 0x62, 0x0a, 0x6f, 0xc3, - 0xe6, 0x9d, 0x30, 0xdc, 0x2f, 0xd2, 0x94, 0xd0, 0xe0, 0xcc, 0x25, 0xd9, 0x22, 0xa1, 0x19, 0xc1, - 0xdf, 0xc3, 0xe8, 0x4e, 0x18, 0x3e, 0xf2, 0xa3, 0xd4, 0x25, 0x3f, 0x14, 0x24, 0xcb, 0xd1, 0x7b, - 0x30, 0x9c, 0xfb, 0x19, 0xf1, 0x02, 0x89, 0x3a, 0x75, 0x2e, 0x3b, 0x57, 0xd7, 0x5d, 0x1b, 0x88, - 0xde, 0x87, 0xd1, 0x0f, 0x45, 0x92, 0x1b, 0x68, 0x2d, 0x8e, 0x56, 0x81, 0xe2, 0x0d, 0x18, 0x97, - 0xf4, 0xe5, 0x96, 0x7f, 0xd7, 0x82, 0xee, 0x9e, 0x1f, 0xfb, 0x34, 0x20, 0x6c, 0xb3, 0x3c, 0xc9, - 0xfd, 0xd8, 0x9b, 0x0b, 0x00, 0xdf, 0x6c, 0xd5, 0xb5, 0x81, 0xe8, 0x2a, 0x8c, 0x83, 0x63, 0x9f, - 0x52, 0xa2, 0xf1, 0x5a, 0x1c, 0xaf, 0x0a, 0x46, 0x3f, 0x86, 0x0b, 0x0b, 0x42, 0xc3, 0x88, 0x3e, - 0xf7, 0xaa, 0x2b, 0xda, 0x7c, 0xc5, 0xb2, 0x69, 0x74, 0x0b, 0xa6, 0x11, 0xf5, 0x83, 0x3c, 0x7a, - 0x49, 0x6a, 0x4b, 0x57, 0xf9, 0xd2, 0xa5, 0xf3, 0x4c, 0x18, 0xa7, 0x7e, 0x1c, 0x93, 0xbc, 0x5c, - 0xd1, 0xe1, 0x2b, 0x2a, 0x50, 0xf4, 0x05, 0xcc, 0x0a, 0x1a, 0x24, 0xf4, 0x59, 0x94, 0x9e, 0x90, - 0xd0, 0xab, 0xac, 0x59, 0xe3, 0x6b, 0xce, 0xc1, 0xc0, 0xbf, 0x0e, 0xb0, 0xe7, 0x53, 0xa5, 0xa8, - 0xab, 0x30, 0xa6, 0x49, 0x48, 0xbc, 0x28, 0x24, 0x34, 0x8f, 0x9e, 0x45, 0x24, 0x95, 0xaa, 0xaa, - 0x82, 0xf1, 0x10, 0xfa, 0x7c, 0x9d, 0x54, 0xc0, 0x67, 0xd0, 0xd9, 0x3f, 0xf6, 0x23, 0x8a, 0xb6, - 0xa0, 0x13, 0xb0, 0x0f, 0xb9, 0x4e, 0x0c, 0xd0, 0x14, 0xba, 0x94, 0xe4, 0xa7, 0x49, 0xfa, 0x42, - 0xea, 0x54, 0x0d, 0xf1, 0x02, 0x7a, 0xfb, 0x82, 0xf5, 0x0c, 0xed, 0xc0, 0x9a, 0x90, 0x06, 0x5f, - 0x3c, 0x74, 0xe5, 0x08, 0xcd, 0xa0, 0xa7, 0xe4, 0xc4, 0x97, 0x0f, 0xdd, 0x72, 0xcc, 0x28, 0x4b, - 0xf1, 0x73, 0x6d, 0x0c, 0x5d, 0x35, 0x64, 0xd4, 0x82, 0x38, 0xc9, 0x48, 0xc8, 0x65, 0x3d, 0x74, - 0xe5, 0x08, 0xff, 0x83, 0x03, 0x9b, 0xfb, 0xec, 0x53, 0xee, 0xfb, 0xc6, 0xbc, 0xb3, 0xf3, 0x54, - 0x4c, 0xb4, 0x1c, 0x33, 0xfe, 0x9f, 0x25, 0xa9, 0xb4, 0x8d, 0x9e, 0x2b, 0x06, 0xe8, 0x32, 0xf4, - 0x43, 0x92, 0xe5, 0x11, 0xe5, 0xf7, 0x87, 0x1f, 0x68, 0xdd, 0x35, 0x41, 0x9c, 0xf7, 0x93, 0xa4, - 0xa0, 0xb9, 0xd4, 0xb3, 0x1c, 0xa1, 0x09, 0xb4, 0x9f, 0x11, 0xa5, 0x48, 0xf6, 0x89, 0xbf, 0x84, - 0x2d, 0xfb, 0xf8, 0x42, 0x05, 0xec, 0xfc, 0x79, 0xea, 0xd3, 0x8c, 0x09, 0x26, 0xa1, 0x5e, 0x14, - 0x66, 0x53, 0xe7, 0x72, 0x9b, 0x9d, 0xbf, 0x02, 0xc6, 0x1f, 0xc1, 0x68, 0x3f, 0xa1, 0x94, 0x04, - 0xb9, 0xe2, 0x7d, 0x06, 0x3d, 0xce, 0x64, 0x91, 0x46, 0x92, 0xe9, 0x72, 0xcc, 0xae, 0x5b, 0x89, - 0x2d, 0xb5, 0x7d, 0x03, 0x36, 0xf6, 0x53, 0xe2, 0xe7, 0xe4, 0x41, 0x12, 0x12, 0x83, 0xc6, 0xc2, - 0xcf, 0xb2, 0xd3, 0x24, 0x0d, 0x15, 0x0d, 0x35, 0xc6, 0x7f, 0xe6, 0x00, 0x32, 0x57, 0xc8, 0x23, - 0xff, 0x0a, 0x0c, 0x33, 0x42, 0x42, 0xef, 0x84, 0x92, 0x93, 0x84, 0x46, 0x81, 0x3c, 0xf0, 0x80, - 0x01, 0xbf, 0x95, 0x30, 0xf4, 0x01, 0x4c, 0x22, 0x1a, 0xe5, 0x91, 0x1f, 0x47, 0xbf, 0x4f, 0x42, - 0x2f, 0xa6, 0x61, 0x36, 0x6d, 0x09, 0xc6, 0x0c, 0xf8, 0x21, 0x0d, 0x33, 0x74, 0x03, 0x36, 0x4d, - 0xd4, 0x80, 0x1d, 0xfb, 0x55, 0x2e, 0x55, 0x81, 0x8c, 0xa9, 0x7d, 0x31, 0x83, 0xff, 0xc5, 0x81, - 0x9e, 0xf2, 0x5f, 0x96, 0x5a, 0x9d, 0x8a, 0x5a, 0x6f, 0x43, 0x3f, 0x3b, 0xf5, 0x17, 0x5e, 0x10, - 0x47, 0x84, 0xe6, 0x5c, 0xeb, 0xa3, 0xdd, 0xb7, 0xae, 0x4b, 0x4f, 0xa9, 0x48, 0x5c, 0x3f, 0x3a, - 0xf5, 0x17, 0xfb, 0x1c, 0xc5, 0x35, 0xf1, 0x85, 0x4f, 0x7a, 0x41, 0xa8, 0xe7, 0x87, 0x61, 0x4a, - 0xb2, 0x8c, 0x1f, 0x69, 0xdd, 0xb5, 0x81, 0xec, 0xce, 0x87, 0x24, 0x88, 0x4e, 0xfc, 0xd8, 0x5b, - 0xc4, 0x7e, 0x40, 0x32, 0x69, 0xb9, 0x15, 0x28, 0xc6, 0x00, 0x7a, 0x23, 0xd4, 0x85, 0xf6, 0xe1, - 0x83, 0xbb, 0x93, 0x15, 0xd4, 0x87, 0xee, 0xfe, 0xc3, 0x07, 0x0f, 0x0e, 0x9e, 0x3e, 0x9e, 0xb4, - 0x98, 0x8e, 0xef, 0x92, 0x45, 0x92, 0x45, 0xa6, 0x8e, 0x97, 0xb1, 0x87, 0x3f, 0x84, 0x71, 0x89, - 0x2d, 0x75, 0x33, 0x85, 0xae, 0x3a, 0xac, 0xc0, 0x56, 0x43, 0x66, 0x80, 0x77, 0xa3, 0x2c, 0x48, - 0x5e, 0x92, 0x94, 0x69, 0x33, 0x7b, 0x73, 0xe7, 0xf1, 0x29, 0x6c, 0x57, 0x28, 0xc8, 0x4d, 0x2f, - 0xc1, 0x3a, 0x2d, 0x4e, 0x3c, 0x86, 0x9f, 0x49, 0x27, 0xa0, 0x01, 0xf8, 0x8f, 0x1d, 0x40, 0x07, - 0xaf, 0x48, 0x50, 0xe4, 0x84, 0xf1, 0x6f, 0x30, 0x96, 0xa4, 0x21, 0x49, 0xbd, 0xa8, 0x34, 0x3c, - 0x35, 0xe6, 0xee, 0xc1, 0x8f, 0xf8, 0x94, 0x74, 0x3c, 0x72, 0x88, 0x30, 0x0c, 0x16, 0x84, 0xa4, - 0xde, 0xa2, 0x98, 0x7b, 0x2f, 0xc8, 0x99, 0xd4, 0x88, 0x05, 0x63, 0x94, 0x7f, 0x28, 0x7c, 0x9a, - 0x47, 0xf9, 0x99, 0x74, 0xd8, 0xe5, 0x98, 0xdd, 0x81, 0xaf, 0x48, 0x2e, 0x1f, 0x9d, 0xd7, 0x91, - 0xf1, 0x5f, 0x39, 0x80, 0xcc, 0x15, 0x92, 0xe5, 0xbb, 0xd0, 0x93, 0xbe, 0x58, 0xdc, 0xd7, 0xfe, - 0xee, 0x55, 0x65, 0x56, 0x75, 0xec, 0xeb, 0x72, 0x9c, 0x1d, 0xd0, 0x3c, 0x3d, 0x73, 0xcb, 0x95, - 0xb3, 0x43, 0x18, 0x5a, 0x53, 0xcc, 0x6f, 0x30, 0xae, 0xc4, 0x21, 0xd8, 0x27, 0xba, 0x02, 0x9d, - 0x97, 0x7e, 0x5c, 0x08, 0x17, 0xda, 0xdf, 0x1d, 0xab, 0x5d, 0xd4, 0x16, 0x62, 0xf6, 0x56, 0xeb, - 0xc7, 0x0e, 0x9e, 0xc0, 0xe8, 0x2b, 0x92, 0xdf, 0xa7, 0xcf, 0x12, 0xc9, 0x18, 0xfe, 0xd7, 0x36, - 0x8c, 0x4b, 0x90, 0xb6, 0x90, 0x97, 0x24, 0xcd, 0x98, 0x43, 0x93, 0x16, 0x22, 0x87, 0x4c, 0xb6, - 0x5c, 0xe5, 0x4a, 0xb6, 0x42, 0xf4, 0x16, 0x0c, 0x21, 0x58, 0x2d, 0xd2, 0x88, 0xdd, 0x04, 0x76, - 0x95, 0xf9, 0xb7, 0x52, 0x3f, 0xd3, 0x81, 0xb2, 0x7d, 0x0d, 0x28, 0x67, 0xfd, 0x28, 0xcd, 0xb8, - 0x97, 0x54, 0xb3, 0x0c, 0x80, 0x3e, 0x84, 0x35, 0xae, 0xf5, 0x8c, 0xfb, 0xca, 0xfe, 0xee, 0xa6, - 0xe2, 0xef, 0x21, 0x87, 0xee, 0x33, 0x6f, 0xea, 0x4a, 0x14, 0xb4, 0x0b, 0xed, 0x98, 0x86, 0xd3, - 0x2e, 0x97, 0xf7, 0x65, 0x43, 0xde, 0x26, 0x83, 0xd7, 0x0f, 0x69, 0x28, 0xe4, 0xcc, 0x90, 0x99, - 0x67, 0xf7, 0xe3, 0xc8, 0xcf, 0xa6, 0xeb, 0xe2, 0x65, 0xe3, 0x03, 0xf3, 0x65, 0x03, 0xeb, 0x65, - 0x43, 0x37, 0x61, 0x53, 0x05, 0x06, 0xdc, 0x15, 0x1c, 0xfb, 0xd9, 0x31, 0xc9, 0xa6, 0x7d, 0xce, - 0x6f, 0xd3, 0x14, 0xfa, 0x18, 0xba, 0xca, 0x65, 0x0d, 0x6c, 0x1e, 0xa4, 0xbf, 0xe2, 0xa7, 0x53, - 0x38, 0xb3, 0xaf, 0xa0, 0xa7, 0x4e, 0xf8, 0x06, 0xea, 0x3e, 0xa4, 0x21, 0x27, 0x63, 0xa8, 0xfb, - 0x0b, 0x6e, 0x98, 0xec, 0x26, 0x1a, 0x2a, 0x7f, 0x83, 0xeb, 0xec, 0xc2, 0xa6, 0xb5, 0xbe, 0xf4, - 0xee, 0xe3, 0x94, 0x2c, 0x0a, 0x11, 0x33, 0x1e, 0x05, 0x49, 0x2a, 0xde, 0xf5, 0x0d, 0x17, 0x34, - 0x98, 0xbd, 0x7b, 0x73, 0xf6, 0x8e, 0x89, 0xfb, 0xd9, 0x73, 0xe5, 0x08, 0x5f, 0x80, 0xed, 0xc3, - 0x28, 0xcb, 0xa5, 0x67, 0x8d, 0x4a, 0x2f, 0x83, 0xbf, 0x86, 0x9d, 0xea, 0x84, 0xdc, 0xef, 0x26, - 0x40, 0x50, 0x42, 0xe5, 0x5d, 0x9a, 0x54, 0x5d, 0xb4, 0x6b, 0xe0, 0xe0, 0x7f, 0x72, 0x60, 0x83, - 0x11, 0x13, 0x26, 0xa2, 0x18, 0x37, 0x7c, 0x86, 0x63, 0xfb, 0x8c, 0x4f, 0xa1, 0x93, 0x9c, 0x52, - 0x92, 0x4a, 0xff, 0xff, 0x6e, 0x29, 0xd3, 0x2a, 0x8d, 0xeb, 0x0f, 0x19, 0x9a, 0x2b, 0xb0, 0x99, - 0xe5, 0xc4, 0xd1, 0x49, 0x94, 0xcb, 0x08, 0x45, 0x0c, 0x98, 0x7c, 0x23, 0x1a, 0xc4, 0x45, 0x48, - 0x3c, 0x6e, 0x4a, 0xd2, 0xdd, 0xf7, 0xdc, 0x2a, 0x18, 0xbf, 0x07, 0x1d, 0x4e, 0x0f, 0xf5, 0x60, - 0x75, 0xef, 0xe1, 0xe3, 0x7b, 0x93, 0x15, 0xe6, 0xf4, 0x1f, 0x3e, 0x79, 0x30, 0x71, 0x18, 0xe8, - 0xd1, 0xc1, 0x81, 0x3b, 0x69, 0xe1, 0x3f, 0x77, 0x00, 0x99, 0x07, 0x91, 0x52, 0xf9, 0xa2, 0xbc, - 0x17, 0x42, 0x22, 0xef, 0x37, 0x1d, 0x5a, 0x1a, 0xbc, 0x18, 0x0a, 0x9b, 0x97, 0xab, 0x66, 0xf7, - 0xa1, 0x6f, 0x80, 0x1b, 0x0c, 0xed, 0x3d, 0xdb, 0xd0, 0x46, 0xf6, 0xbd, 0x33, 0xed, 0x0c, 0xc1, - 0x84, 0x6d, 0xca, 0x22, 0xf7, 0x52, 0x9d, 0x1f, 0x08, 0x0d, 0x48, 0x98, 0x3c, 0xf3, 0x16, 0x74, - 0xc4, 0x2d, 0x17, 0xf1, 0x80, 0x18, 0x94, 0xcb, 0x89, 0x96, 0x33, 0xfe, 0x4c, 0x2e, 0x27, 0x26, - 0xcb, 0x18, 0x3a, 0xc2, 0x85, 0x08, 0x8e, 0x07, 0xea, 0x44, 0x0c, 0xcb, 0x15, 0x53, 0xf8, 0xdf, - 0x1d, 0xe8, 0xca, 0xab, 0xc0, 0x6c, 0x30, 0xcb, 0xfd, 0xbc, 0x50, 0x2f, 0x9d, 0x1c, 0xa1, 0x8f, - 0xa0, 0x27, 0xc3, 0xf2, 0x4c, 0x32, 0xa7, 0xcd, 0x49, 0xc2, 0xdd, 0x12, 0x03, 0x5d, 0x81, 0x35, - 0x1e, 0xec, 0x0a, 0x97, 0xd6, 0xdf, 0x1d, 0x1a, 0xb8, 0x11, 0x75, 0xe5, 0x24, 0x0b, 0x05, 0xe7, - 0x71, 0x12, 0xbc, 0x38, 0x26, 0xd1, 0xf3, 0xe3, 0x5c, 0x7a, 0x39, 0x13, 0x54, 0x7a, 0xc6, 0x8e, - 0xe1, 0x19, 0x0d, 0x5f, 0xbb, 0x66, 0xfb, 0xda, 0xd2, 0x2d, 0x75, 0x0d, 0xb7, 0x84, 0xbf, 0x86, - 0x11, 0xbf, 0x8f, 0x3a, 0x68, 0xad, 0xfa, 0x64, 0xa7, 0xc1, 0x27, 0x97, 0xb4, 0x5a, 0x26, 0xad, - 0xbf, 0x74, 0x00, 0x3d, 0x5c, 0x10, 0xfa, 0xff, 0x12, 0x2f, 0xeb, 0xb8, 0xb7, 0x6d, 0xc5, 0xbd, - 0x97, 0xa1, 0xbf, 0x28, 0xb2, 0x63, 0x4f, 0x4e, 0x8a, 0xd7, 0xd7, 0x04, 0xa9, 0xc8, 0xb8, 0xa3, - 0x23, 0xe3, 0xdb, 0xb0, 0x69, 0x9d, 0x53, 0x9a, 0xc3, 0xfb, 0x30, 0xb2, 0x23, 0x60, 0x79, 0xce, - 0x0a, 0x14, 0xff, 0x63, 0x0b, 0x3a, 0xdc, 0x68, 0xb9, 0xfd, 0xa5, 0x91, 0x4c, 0x1d, 0x1d, 0x57, - 0x0c, 0xac, 0x68, 0xa0, 0x65, 0x47, 0x03, 0xa6, 0xcf, 0x68, 0xdb, 0x3e, 0x63, 0x04, 0xad, 0x28, - 0x94, 0x11, 0x7f, 0x2b, 0x0a, 0xd1, 0x97, 0x75, 0xb1, 0x75, 0xb8, 0x6d, 0xed, 0x28, 0x7b, 0xb1, - 0x15, 0xd7, 0x28, 0xce, 0x38, 0x09, 0xfc, 0x98, 0x6d, 0x26, 0x8c, 0xa1, 0x1c, 0xa3, 0x77, 0x00, - 0x02, 0x1e, 0x67, 0x87, 0x9e, 0x9f, 0x73, 0x93, 0x58, 0x75, 0x0d, 0x08, 0xba, 0x02, 0xab, 0x59, - 0x14, 0x92, 0x69, 0x8f, 0x3b, 0xb0, 0x0d, 0xeb, 0xae, 0x1e, 0x45, 0x21, 0x71, 0xf9, 0x34, 0x33, - 0x96, 0x28, 0xf3, 0x92, 0x53, 0xea, 0x71, 0x2f, 0xc0, 0x9f, 0xbc, 0x9e, 0x6b, 0xc1, 0x98, 0x99, - 0x1e, 0x27, 0x71, 0xc8, 0x9f, 0xbd, 0x55, 0x97, 0x7f, 0xe3, 0xbf, 0x70, 0x60, 0xc0, 0x69, 0xb9, - 0xe4, 0x24, 0x79, 0xe9, 0xc7, 0x96, 0xcc, 0x9c, 0xe5, 0x32, 0xab, 0xc4, 0x66, 0x66, 0x44, 0xd7, - 0xae, 0x44, 0x74, 0x26, 0xf7, 0xab, 0x15, 0xee, 0xab, 0xc7, 0xee, 0xd4, 0x8f, 0x8d, 0x8f, 0x61, - 0x4d, 0x78, 0x26, 0xf4, 0x31, 0xc0, 0xbc, 0x38, 0xf3, 0x2c, 0xef, 0x38, 0xb4, 0x24, 0xe2, 0x1a, - 0x08, 0xe8, 0x06, 0xf4, 0x33, 0x12, 0xc7, 0x0a, 0xbf, 0xd5, 0x84, 0x6f, 0x62, 0xe0, 0x4f, 0x94, - 0xe7, 0xe4, 0xb1, 0x07, 0x93, 0x17, 0x73, 0x3d, 0x32, 0xac, 0xe5, 0xdf, 0xcc, 0x86, 0x93, 0x53, - 0x2a, 0x93, 0x5a, 0xf6, 0x89, 0x7f, 0xe6, 0xc8, 0x55, 0xdf, 0x2d, 0x42, 0x3f, 0x27, 0xec, 0x19, - 0x17, 0xbc, 0x38, 0xdc, 0x48, 0xec, 0xfd, 0xee, 0xad, 0xb8, 0x62, 0x16, 0xfd, 0x26, 0x0c, 0x85, - 0x84, 0x52, 0x21, 0x78, 0xe9, 0xaf, 0xb6, 0xec, 0xe3, 0x89, 0xb9, 0x7b, 0x2b, 0xae, 0x8d, 0xbc, - 0x37, 0x82, 0x81, 0x00, 0x14, 0x7c, 0x53, 0xfc, 0x6f, 0x2d, 0x58, 0x65, 0xce, 0x72, 0x79, 0x12, - 0xf0, 0x5a, 0x21, 0xde, 0x97, 0x30, 0x88, 0x69, 0xa8, 0x86, 0xca, 0x2f, 0x5e, 0x32, 0xdd, 0x31, - 0x0b, 0x47, 0x1e, 0x15, 0xf3, 0x6f, 0xc8, 0x99, 0x7c, 0x76, 0xac, 0x15, 0x6c, 0xff, 0x88, 0xce, - 0x93, 0x82, 0x86, 0xf2, 0x6d, 0x54, 0x43, 0xfd, 0x44, 0x74, 0x8c, 0x27, 0x82, 0x79, 0x8d, 0x57, - 0x45, 0xe8, 0xd9, 0xae, 0xd2, 0x04, 0xa1, 0x8f, 0x60, 0x23, 0x23, 0x41, 0x42, 0xc3, 0x4c, 0xa4, - 0x87, 0x41, 0x4e, 0x42, 0x7e, 0x4f, 0x86, 0x6e, 0x7d, 0xa2, 0x39, 0xe6, 0x9b, 0xdd, 0x86, 0x71, - 0xe5, 0xd8, 0x0d, 0xcf, 0xe2, 0x96, 0xf9, 0x2c, 0xae, 0x9b, 0xcf, 0xe0, 0x1f, 0xb6, 0x60, 0xe3, - 0x11, 0xcb, 0xe4, 0xa4, 0x52, 0x84, 0x3b, 0xfd, 0xbf, 0xf4, 0x39, 0xe6, 0xfd, 0x59, 0xad, 0xdc, - 0x1f, 0xe5, 0x01, 0x3a, 0xe7, 0x7b, 0x80, 0x6b, 0x30, 0x49, 0x09, 0xcf, 0x37, 0xbd, 0x92, 0x94, - 0x10, 0x67, 0x0d, 0xce, 0x22, 0xdd, 0xe8, 0xe4, 0x84, 0x84, 0x91, 0x9f, 0x33, 0xa8, 0x17, 0xb0, - 0x7c, 0x22, 0xe6, 0x52, 0xed, 0xb9, 0x4d, 0x53, 0x4c, 0x04, 0xc8, 0x14, 0x81, 0xf4, 0xd4, 0x9f, - 0xb3, 0x54, 0x3f, 0x27, 0x29, 0xf5, 0x63, 0xef, 0xc4, 0xcf, 0x83, 0x63, 0xb2, 0xe4, 0x5e, 0xd6, - 0xd0, 0xd0, 0x6f, 0xc0, 0x88, 0x87, 0xd2, 0x59, 0x11, 0x04, 0x24, 0x63, 0xc1, 0x94, 0xb8, 0xa0, - 0x65, 0x08, 0xcd, 0x32, 0xc6, 0x23, 0x31, 0xe9, 0x56, 0x50, 0xd1, 0x67, 0x2c, 0x52, 0x3d, 0xf1, - 0x23, 0xca, 0x22, 0x72, 0x71, 0xdd, 0xda, 0x0d, 0xd7, 0xcd, 0xad, 0x62, 0xa1, 0xcf, 0x61, 0xc8, - 0x49, 0x3d, 0xf3, 0xa3, 0xb8, 0x48, 0x79, 0x04, 0x57, 0xdb, 0xf4, 0xb7, 0xc4, 0x9c, 0x6b, 0x63, - 0xe2, 0xff, 0x72, 0x60, 0xac, 0x45, 0x70, 0xf0, 0x92, 0xa5, 0xf2, 0x57, 0xa0, 0xc3, 0xf9, 0x59, - 0x7a, 0xd9, 0xf9, 0x2c, 0xfa, 0x1c, 0x06, 0x26, 0x03, 0xf2, 0xae, 0x37, 0x71, 0x7a, 0x6f, 0xc5, - 0xb5, 0x50, 0xd1, 0xe7, 0xaf, 0xc7, 0xe9, 0xbd, 0x95, 0x26, 0x5e, 0x07, 0x26, 0x07, 0xdc, 0xb0, - 0x9a, 0x59, 0x2d, 0x77, 0x95, 0xa8, 0x7b, 0x5d, 0xe8, 0x10, 0xc6, 0x20, 0x4e, 0xa0, 0x6f, 0xa4, - 0x32, 0x4b, 0x03, 0x2f, 0xc3, 0xed, 0xb4, 0x6c, 0xb7, 0x63, 0xc4, 0x41, 0xab, 0xb5, 0x38, 0x48, - 0x14, 0x1e, 0x3b, 0x46, 0xe1, 0x11, 0x7f, 0x02, 0xdb, 0xdc, 0xeb, 0x11, 0x5d, 0xa5, 0xfe, 0xf9, - 0x99, 0xfa, 0x14, 0x76, 0xaa, 0x8b, 0x64, 0xe1, 0xeb, 0x10, 0x90, 0x98, 0xb1, 0xae, 0xee, 0x79, - 0x05, 0x88, 0x73, 0x2e, 0x30, 0xfe, 0x14, 0x36, 0x2d, 0x6a, 0xf2, 0x16, 0xbc, 0x03, 0x13, 0x85, - 0xe2, 0x25, 0xd4, 0xe3, 0x8f, 0xac, 0x63, 0x3c, 0xb2, 0x1f, 0xc3, 0x86, 0x58, 0x66, 0x96, 0xd8, - 0x97, 0x26, 0x2d, 0x78, 0x4b, 0x9d, 0xd9, 0xaa, 0x98, 0xff, 0x51, 0x8b, 0x81, 0xb3, 0x3c, 0x49, - 0xad, 0x22, 0xde, 0x6b, 0x55, 0xe4, 0xcc, 0x4a, 0x5f, 0xcb, 0xae, 0xf4, 0xa1, 0x6f, 0xa0, 0xcf, - 0x3c, 0xf8, 0xdc, 0x0f, 0x5e, 0x14, 0x0b, 0xe5, 0xf2, 0xaf, 0x29, 0x23, 0xa9, 0xef, 0xc8, 0x1e, - 0x80, 0x3d, 0x81, 0x2c, 0x1e, 0x00, 0x88, 0x4b, 0x00, 0xfa, 0x11, 0xef, 0x45, 0x78, 0xa1, 0x9f, - 0xfb, 0x73, 0x3f, 0x13, 0x55, 0xd0, 0x01, 0xf7, 0xe7, 0x77, 0x25, 0x48, 0xfa, 0x62, 0x93, 0xc2, - 0xcf, 0xf3, 0xc5, 0x03, 0xd3, 0x17, 0x13, 0xa6, 0x02, 0xe3, 0x4c, 0xba, 0x30, 0x99, 0x0a, 0xb0, - 0x2c, 0x38, 0x4a, 0x31, 0x28, 0x20, 0xaf, 0x36, 0x7e, 0xc0, 0x5c, 0xa4, 0x44, 0x52, 0x79, 0xbb, - 0x48, 0x62, 0xc7, 0x0a, 0xae, 0xea, 0x8c, 0x1b, 0x30, 0x3e, 0x3a, 0x2e, 0xf2, 0x30, 0x39, 0x55, - 0xa5, 0x76, 0x96, 0xcd, 0x68, 0x90, 0x54, 0xca, 0xaf, 0xc1, 0xce, 0x51, 0x31, 0xcf, 0x82, 0x34, - 0x9a, 0x13, 0x3b, 0x27, 0x9d, 0x41, 0x8f, 0xbc, 0x8a, 0xb2, 0x3c, 0xa2, 0xcf, 0x39, 0x63, 0x3d, - 0xb7, 0x1c, 0xe3, 0x77, 0xe1, 0xed, 0x72, 0x15, 0xbb, 0x85, 0xd9, 0x9d, 0x20, 0x20, 0x8b, 0x9c, - 0x84, 0x6a, 0xab, 0xdb, 0xb0, 0x6d, 0x23, 0x18, 0x7d, 0x19, 0x95, 0x6b, 0xe6, 0xfe, 0x0b, 0x19, - 0x64, 0xf4, 0x5c, 0x1b, 0x88, 0xff, 0xa7, 0x05, 0x03, 0xb6, 0x4c, 0x91, 0x45, 0x17, 0x6b, 0xf6, - 0xde, 0xe5, 0xe3, 0xfb, 0x76, 0x74, 0xd6, 0xaa, 0x44, 0x67, 0xe7, 0xbe, 0x57, 0xcb, 0xea, 0x6c, - 0xfa, 0x5d, 0xec, 0x98, 0xef, 0x62, 0xb5, 0x7a, 0xb7, 0xd6, 0x50, 0xbd, 0xdb, 0x81, 0xb5, 0x94, - 0x97, 0x56, 0x64, 0x6a, 0x24, 0x47, 0xec, 0x69, 0x13, 0x29, 0x84, 0x97, 0x92, 0x80, 0x44, 0x2f, - 0x99, 0x4c, 0x7b, 0x7c, 0xd7, 0x1a, 0x9c, 0xe5, 0x0e, 0x12, 0x96, 0xc9, 0x2e, 0xc3, 0xba, 0x68, - 0xc3, 0xd8, 0x50, 0x74, 0x1d, 0x90, 0x72, 0x1f, 0x06, 0x55, 0x51, 0x11, 0x6a, 0x98, 0x61, 0x67, - 0x28, 0xa1, 0x8a, 0x72, 0x5f, 0x3c, 0xaf, 0x55, 0x38, 0xfe, 0x6b, 0x07, 0xfa, 0x86, 0x77, 0xfd, - 0x05, 0xeb, 0x9d, 0xa6, 0x8c, 0xdb, 0x15, 0x19, 0x57, 0xa5, 0xb9, 0xda, 0x20, 0xcd, 0xf7, 0x61, - 0x24, 0xdd, 0xb9, 0x97, 0x12, 0x3f, 0x4b, 0x94, 0xa3, 0xad, 0x40, 0xf1, 0xdf, 0xb6, 0xc5, 0x69, - 0xe5, 0x0b, 0xf4, 0xcb, 0x35, 0x16, 0xad, 0xf2, 0x8e, 0xa5, 0xf2, 0xab, 0x30, 0xb6, 0x54, 0x4b, - 0x42, 0xa9, 0xf1, 0x2a, 0x98, 0x45, 0x90, 0x5a, 0xb5, 0xb9, 0xd4, 0xb6, 0x09, 0xaa, 0x09, 0x0b, - 0x1a, 0x84, 0x75, 0x19, 0x56, 0xd3, 0x24, 0x26, 0x5c, 0xa5, 0x23, 0x5d, 0x80, 0x70, 0x93, 0x98, - 0xb8, 0x7c, 0x86, 0xc5, 0xa1, 0x15, 0xb3, 0x20, 0x21, 0xaf, 0xfa, 0xad, 0xbb, 0xf5, 0x09, 0x76, - 0x51, 0x4d, 0xb3, 0xc8, 0xa7, 0x43, 0xd1, 0x3f, 0xb0, 0x80, 0x2c, 0xf9, 0x4b, 0xbd, 0x45, 0x4a, - 0xa2, 0x13, 0xff, 0x39, 0x99, 0x8e, 0x38, 0x8a, 0x01, 0xd1, 0x57, 0x69, 0x6c, 0x5c, 0x25, 0xfc, - 0xdf, 0x2d, 0xe8, 0x3c, 0x4e, 0xfd, 0x90, 0xb0, 0x0c, 0xe7, 0x84, 0xdd, 0x78, 0x6f, 0x79, 0xc6, - 0xe1, 0x9a, 0x18, 0x6c, 0x41, 0x6e, 0x2c, 0x68, 0x35, 0x2e, 0x30, 0x30, 0x0c, 0xfd, 0xb4, 0x2d, - 0xfd, 0x9c, 0xa7, 0x53, 0xc3, 0x12, 0x3a, 0xb6, 0x25, 0x94, 0xfc, 0xac, 0x99, 0xae, 0x41, 0xc9, - 0xbe, 0xbb, 0x54, 0xf6, 0x97, 0xa1, 0x4f, 0x44, 0x1b, 0x81, 0x67, 0xc9, 0xc2, 0x12, 0x4c, 0x50, - 0x19, 0x24, 0xaf, 0x9f, 0x1f, 0x24, 0xdf, 0x82, 0x41, 0xc0, 0x0c, 0x83, 0xa4, 0x0b, 0x3f, 0xcd, - 0x85, 0x29, 0x2c, 0x4f, 0xe4, 0x2d, 0x5c, 0xfc, 0x21, 0x6c, 0x72, 0xa9, 0xdf, 0x8b, 0xd8, 0x53, - 0x71, 0x66, 0xa4, 0x01, 0xa2, 0x56, 0xe8, 0x18, 0xb5, 0x42, 0x7c, 0x1b, 0xb6, 0x6c, 0x64, 0xf9, - 0x4e, 0x5d, 0x81, 0xb5, 0x9c, 0xc1, 0x6b, 0x61, 0x32, 0xc7, 0x76, 0xe5, 0x24, 0xde, 0x87, 0x21, - 0x03, 0x44, 0xf4, 0xf9, 0x21, 0x23, 0xc7, 0x2e, 0x65, 0xf7, 0x5b, 0xff, 0xd5, 0x11, 0x89, 0x63, - 0x95, 0x95, 0x9f, 0xf8, 0xaf, 0x3c, 0x96, 0xbc, 0xa2, 0x0b, 0xb0, 0xf6, 0xad, 0xff, 0x6a, 0xaf, - 0x50, 0xe1, 0x4a, 0x97, 0xcd, 0xcc, 0x8b, 0x33, 0xbc, 0x2b, 0xce, 0x50, 0x12, 0x79, 0x9d, 0x48, - 0xea, 0x6f, 0x1c, 0xd8, 0xae, 0x2c, 0x92, 0x27, 0xbf, 0x03, 0x6b, 0x9c, 0x35, 0x75, 0xf2, 0x0f, - 0xcc, 0x93, 0xd7, 0xd0, 0xaf, 0x8b, 0xa1, 0xac, 0x4c, 0x8a, 0x85, 0xb3, 0x47, 0xd0, 0x37, 0xc0, - 0x0d, 0xcf, 0xfe, 0x87, 0x76, 0x65, 0x72, 0xbb, 0x79, 0x0b, 0x23, 0x1a, 0xf8, 0x09, 0x0c, 0xbe, - 0xa3, 0xf3, 0x5f, 0xa0, 0x1d, 0x8e, 0x2e, 0xc1, 0x7a, 0x4a, 0x64, 0xde, 0x28, 0x83, 0x00, 0x0d, - 0xc0, 0x63, 0x18, 0x4a, 0xba, 0xba, 0x81, 0xfa, 0x1d, 0x8d, 0x93, 0xe0, 0xc5, 0xeb, 0x36, 0x50, - 0x7f, 0x0a, 0xc8, 0x5c, 0xa0, 0xc3, 0x94, 0x82, 0x43, 0x2b, 0x61, 0x8a, 0x02, 0xf2, 0x30, 0xe5, - 0x5d, 0xe8, 0x9b, 0x28, 0xa2, 0xdf, 0x02, 0x1a, 0x01, 0xff, 0x89, 0x03, 0xe3, 0x27, 0x51, 0x7e, - 0x1c, 0xa6, 0xfe, 0xe9, 0x6b, 0x28, 0xb5, 0xda, 0xcc, 0x6e, 0x9d, 0xd7, 0xcc, 0x6e, 0x57, 0x9b, - 0xd9, 0x7e, 0x1c, 0xcb, 0x54, 0x9e, 0x7d, 0x9a, 0x45, 0xbc, 0xa1, 0x28, 0xe2, 0xdd, 0x82, 0x89, - 0x3e, 0xcc, 0x9b, 0x55, 0xf0, 0xae, 0x5d, 0x85, 0xf5, 0xf2, 0x8a, 0xa2, 0x2e, 0xb4, 0xf7, 0xbe, - 0xfb, 0xed, 0xc9, 0x0a, 0xea, 0xc1, 0xea, 0xd1, 0xc1, 0xe1, 0xa1, 0x28, 0x96, 0xf3, 0xfa, 0x79, - 0xeb, 0xda, 0x35, 0x58, 0x65, 0x0e, 0x01, 0xad, 0x43, 0xe7, 0xf1, 0x9d, 0x6f, 0x0e, 0xdc, 0xc9, - 0x0a, 0xfb, 0xfc, 0x96, 0x7f, 0x3a, 0x68, 0x00, 0xbd, 0xfb, 0x0f, 0x1e, 0x1f, 0xb8, 0x0f, 0xee, - 0x1c, 0x4e, 0x5a, 0xbb, 0xff, 0xe1, 0x40, 0xf7, 0x69, 0x11, 0xde, 0xa7, 0x51, 0x8e, 0x0e, 0x00, - 0x74, 0x1f, 0x1b, 0x5d, 0x2c, 0x4b, 0xbc, 0xd5, 0x6e, 0xf8, 0x6c, 0xd6, 0x34, 0x25, 0xb5, 0xbf, - 0x82, 0xee, 0x41, 0xdf, 0x08, 0x3b, 0xd1, 0x6c, 0x79, 0x7c, 0x3c, 0x7b, 0xab, 0x71, 0xae, 0xa4, - 0x74, 0x00, 0xa0, 0x0d, 0x43, 0x1f, 0xa8, 0x66, 0x5d, 0xfa, 0x40, 0x75, 0x3b, 0xc2, 0x2b, 0xbb, - 0x7f, 0xbf, 0x03, 0xed, 0xa7, 0x45, 0x88, 0x9e, 0x42, 0xdf, 0xf8, 0xa5, 0x07, 0xd5, 0xda, 0x27, - 0xfa, 0x38, 0x4d, 0x7f, 0xfe, 0xcc, 0x7e, 0xf6, 0xcf, 0xff, 0xf9, 0xa7, 0xad, 0x2d, 0x3c, 0xbe, - 0xf1, 0xf2, 0x57, 0x6f, 0xf8, 0x61, 0xa8, 0x4c, 0xe6, 0x96, 0x73, 0x0d, 0xb9, 0xd0, 0x95, 0x7f, - 0xed, 0xa0, 0x1d, 0x83, 0x86, 0x91, 0xc3, 0xcc, 0x2e, 0xd4, 0xe0, 0x92, 0xee, 0x0e, 0xa7, 0x3b, - 0xc1, 0x7d, 0x49, 0x97, 0x3d, 0x00, 0x8c, 0xe6, 0x1e, 0xb4, 0xf7, 0x7c, 0x8a, 0x90, 0x6e, 0x65, - 0xaa, 0xab, 0x3b, 0xdb, 0xb4, 0x60, 0x92, 0x0e, 0xe2, 0x74, 0x06, 0xb8, 0xcb, 0xe8, 0xcc, 0x7d, - 0xca, 0x68, 0x04, 0x30, 0x30, 0x7f, 0xa7, 0x40, 0xba, 0xa9, 0x5f, 0xff, 0x47, 0x64, 0x76, 0xa9, - 0x79, 0x52, 0x92, 0x9f, 0x72, 0xf2, 0x08, 0x4f, 0x18, 0x79, 0xfe, 0xb7, 0x89, 0x6c, 0x0e, 0x30, - 0xe6, 0xe5, 0x3f, 0x14, 0x9a, 0x79, 0xfb, 0x17, 0x0c, 0xcd, 0x7c, 0xf5, 0x67, 0x0b, 0x8b, 0x79, - 0xe9, 0x51, 0xd8, 0xc1, 0xbf, 0x87, 0xe1, 0x13, 0xfe, 0x2f, 0x8f, 0xec, 0xdc, 0x6b, 0xca, 0x76, - 0xe3, 0x5f, 0x53, 0xae, 0xb4, 0xf8, 0xf1, 0x25, 0x4e, 0x79, 0x07, 0x6f, 0x30, 0xca, 0xe2, 0xbf, - 0xa0, 0x50, 0xa0, 0x30, 0xfa, 0xbf, 0x07, 0x43, 0xab, 0x49, 0x8f, 0x4a, 0xe6, 0x9b, 0xba, 0xff, - 0xb3, 0xb7, 0x97, 0xcc, 0x36, 0xed, 0x15, 0x4a, 0x14, 0xde, 0xd6, 0x67, 0x7b, 0x3d, 0x05, 0xd0, - 0xcd, 0x6e, 0x6d, 0xc5, 0xb5, 0x06, 0xbb, 0xb6, 0xe2, 0x7a, 0x6f, 0x1c, 0x6f, 0xf2, 0x2d, 0x86, - 0xa8, 0x2f, 0xb4, 0x2b, 0x68, 0x1d, 0x42, 0x57, 0xb6, 0x75, 0xb5, 0x7c, 0xec, 0xde, 0xb6, 0x96, - 0x4f, 0xa5, 0xff, 0x8b, 0x27, 0x9c, 0x20, 0xa0, 0x1e, 0x23, 0x18, 0x31, 0x12, 0xbf, 0x03, 0x7d, - 0xa3, 0xd3, 0x89, 0xcc, 0xd3, 0x54, 0xda, 0xa7, 0xfa, 0xa2, 0x34, 0xb4, 0x46, 0xf1, 0x16, 0xa7, - 0x3c, 0x42, 0x03, 0x46, 0x99, 0x49, 0x81, 0x53, 0x7f, 0x02, 0xa0, 0x9b, 0x72, 0x5a, 0x0a, 0xb5, - 0xee, 0xa2, 0x96, 0x42, 0xbd, 0x87, 0xa7, 0x6c, 0x1c, 0x01, 0x23, 0x2d, 0x4b, 0xd7, 0xcf, 0x61, - 0x64, 0xf7, 0x4c, 0xd1, 0xdb, 0x26, 0x85, 0x5a, 0x93, 0x75, 0xf6, 0xce, 0xb2, 0x69, 0xdb, 0x26, - 0xd1, 0x88, 0xdb, 0xa4, 0x26, 0x7b, 0x04, 0xeb, 0x65, 0x37, 0x0f, 0x4d, 0x4d, 0x22, 0x66, 0xd3, - 0x6f, 0x76, 0xb1, 0x61, 0x46, 0x52, 0xde, 0xe0, 0x94, 0xfb, 0x68, 0x9d, 0x51, 0x16, 0x45, 0x5d, - 0x45, 0x94, 0xff, 0x04, 0x60, 0x13, 0x35, 0x5a, 0x81, 0x15, 0xa2, 0x66, 0x43, 0xb0, 0x42, 0x94, - 0xd3, 0xf1, 0xa0, 0x6f, 0xf4, 0x8a, 0xb4, 0x26, 0xeb, 0x8d, 0x2e, 0xad, 0xc9, 0x86, 0xe6, 0x12, - 0xbe, 0xc0, 0x49, 0x6f, 0x08, 0x97, 0x97, 0x2c, 0x08, 0x55, 0x57, 0xfe, 0x77, 0x01, 0x74, 0x79, - 0x4f, 0x2b, 0xb3, 0x56, 0xf8, 0xd5, 0xe6, 0x57, 0xa9, 0x06, 0xe2, 0x8b, 0x9c, 0xf4, 0x26, 0xe6, - 0x42, 0xe6, 0x25, 0x57, 0xae, 0xce, 0x5b, 0xce, 0xb5, 0x9b, 0x0e, 0x7a, 0x06, 0x23, 0x8d, 0x7f, - 0x74, 0x46, 0x83, 0xf3, 0xb6, 0x98, 0x35, 0x4d, 0x49, 0x06, 0xde, 0xe6, 0xbb, 0x5c, 0xc0, 0xc8, - 0xde, 0x25, 0x3b, 0xa3, 0x01, 0xbb, 0x99, 0x3f, 0x85, 0xbe, 0xf1, 0xcb, 0x8d, 0x96, 0x53, 0xfd, - 0x3f, 0x9c, 0x59, 0x53, 0x01, 0xd2, 0x7e, 0x12, 0x64, 0x88, 0x9d, 0x9d, 0xfa, 0x0b, 0x46, 0x9b, - 0xc2, 0xc8, 0xae, 0xb3, 0x69, 0xb3, 0x6c, 0x2c, 0xda, 0x69, 0xb3, 0x5c, 0x52, 0x9e, 0xb3, 0x78, - 0xe1, 0xcd, 0x0d, 0x62, 0x3e, 0x41, 0x73, 0xf6, 0xea, 0x96, 0xf5, 0x36, 0xf3, 0xd5, 0xad, 0x96, - 0xf4, 0xcc, 0x57, 0xb7, 0x56, 0xa0, 0xb3, 0x79, 0x12, 0xdb, 0x28, 0xcd, 0xa0, 0xef, 0x01, 0x74, - 0xb5, 0x4d, 0xeb, 0xa4, 0x56, 0xb0, 0x9b, 0xcd, 0x9a, 0xa6, 0xe4, 0x06, 0x96, 0xe6, 0xc5, 0x06, - 0xea, 0xc9, 0xfb, 0x09, 0xf4, 0x54, 0xd9, 0x08, 0x95, 0x96, 0x53, 0xa9, 0x2d, 0xcd, 0xa6, 0xf5, - 0x89, 0x8a, 0xb9, 0x72, 0xc7, 0x93, 0xc9, 0x59, 0x46, 0x97, 0xc0, 0xb8, 0x52, 0x7a, 0x42, 0xa5, - 0xb4, 0x9b, 0x6b, 0x52, 0x33, 0xfb, 0x0f, 0x1b, 0xd1, 0xaf, 0xc2, 0x6f, 0xf1, 0x0d, 0xb6, 0xd1, - 0x26, 0xdf, 0x40, 0x2d, 0x14, 0x26, 0x75, 0xd3, 0x41, 0x8b, 0x4a, 0x29, 0x4a, 0xd6, 0x34, 0x0c, - 0x87, 0xd4, 0x58, 0xa9, 0x9a, 0x35, 0x95, 0x99, 0xf1, 0x8f, 0xf8, 0x5e, 0x6f, 0xa1, 0x8b, 0xd6, - 0x5e, 0xcc, 0xba, 0x54, 0x95, 0xfd, 0xa6, 0x83, 0xe6, 0x30, 0xb2, 0x49, 0xbe, 0xd1, 0x56, 0x15, - 0x33, 0x46, 0xa8, 0xb6, 0x15, 0xdb, 0xe3, 0x0f, 0x8c, 0xba, 0x9d, 0x55, 0x81, 0x43, 0x57, 0x9a, - 0xf7, 0xaa, 0x54, 0xe8, 0x66, 0x5b, 0xe6, 0x9e, 0x6a, 0x12, 0x63, 0xbe, 0xe9, 0x25, 0x34, 0xab, - 0x6f, 0xea, 0x4b, 0x1c, 0xee, 0x09, 0x06, 0x66, 0x6e, 0xa8, 0x03, 0x98, 0x86, 0xf4, 0x52, 0x07, - 0x30, 0x4d, 0xe9, 0xa4, 0x52, 0x9e, 0x08, 0x60, 0x78, 0xee, 0x78, 0x2c, 0x30, 0x98, 0x85, 0x3c, - 0xaf, 0x26, 0x91, 0x97, 0x96, 0xa4, 0x6c, 0x95, 0x78, 0xa0, 0x31, 0xa1, 0x53, 0x26, 0x8e, 0x36, - 0xd4, 0x56, 0x11, 0x7d, 0x2e, 0xf2, 0x3a, 0xf4, 0x35, 0x74, 0x78, 0xb6, 0x84, 0xb6, 0x74, 0xc8, - 0xaa, 0x93, 0xb2, 0xd9, 0x76, 0x05, 0x6a, 0x3f, 0xa9, 0x98, 0xfb, 0xf8, 0x82, 0xca, 0xe8, 0x6e, - 0x0e, 0x23, 0x11, 0x24, 0xa9, 0x9c, 0x42, 0x5f, 0x9a, 0x4a, 0xca, 0xa3, 0x2f, 0x4d, 0x35, 0xfd, - 0xb0, 0xdd, 0x8a, 0x88, 0x93, 0x4e, 0x25, 0xce, 0x2d, 0xe7, 0xda, 0x7c, 0x8d, 0xff, 0x0d, 0xff, - 0xc9, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x73, 0x92, 0x96, 0x52, 0x38, 0x2f, 0x00, 0x00, + // 3835 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3a, 0x4b, 0x8f, 0x1d, 0xc7, + 0x5a, 0xd3, 0xe7, 0xcc, 0x99, 0x73, 0xe6, 0x3b, 0xcf, 0xa9, 0x79, 0x78, 0x7c, 0xe2, 0x24, 0xbe, + 0x45, 0x1c, 0x39, 0x4e, 0x62, 0x9b, 0x09, 0x21, 0x37, 0x06, 0x47, 0xf1, 0x8c, 0x87, 0xd8, 0xc9, + 0xc4, 0xb6, 0x7a, 0x9c, 0x6b, 0x73, 0x05, 0x69, 0xf5, 0xe9, 0x2e, 0x7b, 0x1a, 0xf7, 0x54, 0x9f, + 0xf4, 0x63, 0x1e, 0xb0, 0x41, 0x57, 0xac, 0x60, 0x89, 0x58, 0xc3, 0x0a, 0x21, 0x81, 0xd8, 0xb3, + 0x40, 0x62, 0xcd, 0x96, 0x05, 0x12, 0xb0, 0x41, 0xf0, 0x0b, 0x10, 0x5b, 0x24, 0x54, 0xaf, 0xae, + 0xaa, 0xee, 0x3e, 0x73, 0xed, 0x2b, 0xb8, 0xbb, 0xae, 0xaf, 0xbe, 0xfa, 0xaa, 0xbe, 0x47, 0x7d, + 0xf5, 0x3d, 0x1a, 0x06, 0x67, 0x45, 0x98, 0xce, 0x83, 0x9b, 0xf3, 0x34, 0xc9, 0x13, 0xb4, 0x22, + 0x46, 0xd3, 0x35, 0x9f, 0xd2, 0x24, 0xf7, 0xf3, 0x28, 0xa1, 0x99, 0x98, 0xc2, 0x9b, 0xb0, 0x7e, + 0x2f, 0x0c, 0xf7, 0x8a, 0x34, 0x25, 0x34, 0x38, 0x77, 0x49, 0x36, 0x4f, 0x68, 0x46, 0xf0, 0xf7, + 0x30, 0xba, 0x17, 0x86, 0x4f, 0xfc, 0x28, 0x75, 0xc9, 0x0f, 0x05, 0xc9, 0x72, 0xf4, 0x1e, 0x0c, + 0x67, 0x7e, 0x46, 0xbc, 0x40, 0xa2, 0x6e, 0x3b, 0x57, 0x9d, 0xeb, 0xab, 0xae, 0x0d, 0x44, 0xef, + 0xc3, 0xe8, 0x87, 0x22, 0xc9, 0x0d, 0xb4, 0x16, 0x47, 0xab, 0x40, 0xf1, 0x1a, 0x8c, 0x4b, 0xfa, + 0x72, 0xcb, 0xff, 0x68, 0x41, 0x77, 0xd7, 0x8f, 0x7d, 0x1a, 0x10, 0xb6, 0x59, 0x9e, 0xe4, 0x7e, + 0xec, 0xcd, 0x04, 0x80, 0x6f, 0xb6, 0xec, 0xda, 0x40, 0x74, 0x1d, 0xc6, 0xc1, 0x91, 0x4f, 0x29, + 0xd1, 0x78, 0x2d, 0x8e, 0x57, 0x05, 0xa3, 0x1f, 0xc3, 0xa5, 0x39, 0xa1, 0x61, 0x44, 0x5f, 0x7a, + 0xd5, 0x15, 0x6d, 0xbe, 0x62, 0xd1, 0x34, 0xba, 0x03, 0xdb, 0x11, 0xf5, 0x83, 0x3c, 0x3a, 0x21, + 0xb5, 0xa5, 0xcb, 0x7c, 0xe9, 0xc2, 0x79, 0x26, 0x8c, 0x53, 0x3f, 0x8e, 0x49, 0x5e, 0xae, 0xe8, + 0xf0, 0x15, 0x15, 0x28, 0xfa, 0x02, 0xa6, 0x05, 0x0d, 0x12, 0xfa, 0x22, 0x4a, 0x8f, 0x49, 0xe8, + 0x55, 0xd6, 0xac, 0xf0, 0x35, 0x17, 0x60, 0xa0, 0x1b, 0x30, 0x49, 0x49, 0x46, 0xd2, 0x13, 0x12, + 0x96, 0xab, 0xba, 0x7c, 0x55, 0x0d, 0x8e, 0x7f, 0x1d, 0x60, 0xd7, 0xa7, 0x4a, 0xa9, 0xd7, 0x61, + 0x4c, 0x93, 0x90, 0x78, 0x51, 0x48, 0x68, 0x1e, 0xbd, 0x88, 0x48, 0x2a, 0xd5, 0x5a, 0x05, 0xe3, + 0x21, 0xf4, 0xf9, 0x3a, 0xa9, 0xac, 0xcf, 0xa0, 0xb3, 0x77, 0xe4, 0x47, 0x14, 0x6d, 0x40, 0x27, + 0x60, 0x1f, 0x72, 0x9d, 0x18, 0xa0, 0x6d, 0xe8, 0x52, 0x92, 0x9f, 0x26, 0xe9, 0x2b, 0xa9, 0x7f, + 0x35, 0xc4, 0x73, 0xe8, 0xed, 0x09, 0x31, 0x65, 0x68, 0x0b, 0x56, 0x84, 0xe4, 0xf8, 0xe2, 0xa1, + 0x2b, 0x47, 0x68, 0x0a, 0x3d, 0x25, 0x53, 0xbe, 0x7c, 0xe8, 0x96, 0x63, 0x46, 0x59, 0xaa, 0x8a, + 0x6b, 0x6e, 0xe8, 0xaa, 0x21, 0xa3, 0x16, 0xc4, 0x49, 0x46, 0x42, 0xae, 0x97, 0xa1, 0x2b, 0x47, + 0xf8, 0xef, 0x1d, 0x58, 0xdf, 0x63, 0x9f, 0x72, 0xdf, 0x37, 0xe6, 0x9d, 0x9d, 0xa7, 0x62, 0xce, + 0xe5, 0x98, 0xf1, 0xff, 0x22, 0x49, 0xa5, 0x1d, 0xf5, 0x5c, 0x31, 0x40, 0x57, 0xa1, 0x1f, 0x92, + 0x2c, 0x8f, 0x28, 0xbf, 0x6b, 0xfc, 0x40, 0xab, 0xae, 0x09, 0xe2, 0xbc, 0x1f, 0x27, 0x05, 0xcd, + 0xa5, 0x4d, 0xc8, 0x11, 0x9a, 0x40, 0xfb, 0x05, 0x51, 0x4a, 0x67, 0x9f, 0xf8, 0x4b, 0xd8, 0xb0, + 0x8f, 0x2f, 0x54, 0xc0, 0xce, 0x9f, 0xa7, 0x3e, 0xcd, 0x98, 0x60, 0x12, 0xea, 0x45, 0x61, 0xb6, + 0xed, 0x5c, 0x6d, 0xb3, 0xf3, 0x57, 0xc0, 0xf8, 0x23, 0x18, 0xed, 0x25, 0x94, 0x92, 0x20, 0x57, + 0xbc, 0x4f, 0xa1, 0xc7, 0x99, 0x2c, 0xd2, 0x48, 0x32, 0x5d, 0x8e, 0xd9, 0xd5, 0x2c, 0xb1, 0xa5, + 0xb6, 0x6f, 0xc1, 0xda, 0x5e, 0x4a, 0xfc, 0x9c, 0x3c, 0x4a, 0x42, 0x62, 0xd0, 0x98, 0xfb, 0x59, + 0x76, 0x9a, 0xa4, 0xa1, 0xa2, 0xa1, 0xc6, 0xf8, 0xcf, 0x1c, 0x40, 0xe6, 0x0a, 0x79, 0xe4, 0x5f, + 0x81, 0x61, 0x46, 0x48, 0xe8, 0x1d, 0x53, 0x72, 0x9c, 0xd0, 0x28, 0x90, 0x07, 0x1e, 0x30, 0xe0, + 0xb7, 0x12, 0x86, 0x3e, 0x80, 0x49, 0x44, 0xa3, 0x3c, 0xf2, 0xe3, 0xe8, 0xf7, 0x49, 0xe8, 0xc5, + 0x34, 0xcc, 0xb6, 0x5b, 0x82, 0x31, 0x03, 0x7e, 0x40, 0xc3, 0x0c, 0xdd, 0x82, 0x75, 0x13, 0x35, + 0x60, 0xc7, 0x3e, 0xcb, 0xa5, 0x2a, 0x90, 0x31, 0xb5, 0x27, 0x66, 0xf0, 0x3f, 0x3b, 0xd0, 0x53, + 0xbe, 0xce, 0x52, 0xab, 0x53, 0x51, 0xeb, 0x5d, 0xe8, 0x67, 0xa7, 0xfe, 0xdc, 0x0b, 0xe2, 0x88, + 0xd0, 0x9c, 0x6b, 0x7d, 0xb4, 0xf3, 0xd6, 0x4d, 0xe9, 0x55, 0x15, 0x89, 0x9b, 0x87, 0xa7, 0xfe, + 0x7c, 0x8f, 0xa3, 0xb8, 0x26, 0xbe, 0xf0, 0x5f, 0xaf, 0x08, 0xf5, 0xfc, 0x30, 0x4c, 0x49, 0x96, + 0xf1, 0x23, 0xad, 0xba, 0x36, 0x90, 0xf9, 0x87, 0x90, 0x04, 0xd1, 0xb1, 0x1f, 0x7b, 0xf3, 0xd8, + 0x0f, 0x48, 0x26, 0x2d, 0xb7, 0x02, 0xc5, 0x18, 0x40, 0x6f, 0x84, 0xba, 0xd0, 0x3e, 0x78, 0x74, + 0x7f, 0xb2, 0x84, 0xfa, 0xd0, 0xdd, 0x7b, 0xfc, 0xe8, 0xd1, 0xfe, 0xf3, 0xa7, 0x93, 0x16, 0xd3, + 0xf1, 0x7d, 0x32, 0x4f, 0xb2, 0xc8, 0xd4, 0xf1, 0x22, 0xf6, 0xf0, 0x87, 0x30, 0x2e, 0xb1, 0xa5, + 0x6e, 0xb6, 0xa1, 0xab, 0x0e, 0x2b, 0xb0, 0xd5, 0x90, 0x19, 0xe0, 0xfd, 0x28, 0x0b, 0x92, 0x13, + 0x92, 0x32, 0x6d, 0x66, 0x6f, 0xee, 0x3c, 0x3e, 0x85, 0xcd, 0x0a, 0x05, 0xb9, 0xe9, 0x15, 0x58, + 0xa5, 0xc5, 0xb1, 0xc7, 0xf0, 0x33, 0xe9, 0x04, 0x34, 0x00, 0xff, 0xb1, 0x03, 0x68, 0xff, 0x8c, + 0x04, 0x45, 0x4e, 0x18, 0xff, 0x06, 0x63, 0x49, 0x1a, 0x92, 0xd4, 0x8b, 0x4a, 0xc3, 0x53, 0x63, + 0xee, 0x1e, 0xfc, 0x88, 0x4f, 0x49, 0xc7, 0x23, 0x87, 0x08, 0xc3, 0x60, 0x4e, 0x48, 0xea, 0xcd, + 0x8b, 0x99, 0xf7, 0x8a, 0x9c, 0x4b, 0x8d, 0x58, 0x30, 0x46, 0xf9, 0x87, 0xc2, 0xa7, 0x79, 0x94, + 0x9f, 0x4b, 0xe7, 0x5e, 0x8e, 0xd9, 0x1d, 0xf8, 0x8a, 0xe4, 0xf2, 0x81, 0x7a, 0x1d, 0x19, 0xff, + 0x95, 0x03, 0xc8, 0x5c, 0x21, 0x59, 0xbe, 0x0f, 0x3d, 0xe9, 0x8b, 0xc5, 0x7d, 0xed, 0xef, 0x5c, + 0x57, 0x66, 0x55, 0xc7, 0xbe, 0x29, 0xc7, 0xd9, 0x3e, 0xcd, 0xd3, 0x73, 0xb7, 0x5c, 0x39, 0x3d, + 0x80, 0xa1, 0x35, 0xc5, 0xfc, 0x06, 0xe3, 0x4a, 0x1c, 0x82, 0x7d, 0xa2, 0x6b, 0xd0, 0x39, 0xf1, + 0xe3, 0x42, 0xb8, 0xd0, 0xfe, 0xce, 0x58, 0xed, 0xa2, 0xb6, 0x10, 0xb3, 0x77, 0x5a, 0x3f, 0x76, + 0xf0, 0x04, 0x46, 0x5f, 0x91, 0xfc, 0x21, 0x7d, 0x91, 0x48, 0xc6, 0xf0, 0xbf, 0xb4, 0x61, 0x5c, + 0x82, 0xb4, 0x85, 0x9c, 0x90, 0x34, 0x63, 0x0e, 0x4d, 0x5a, 0x88, 0x1c, 0x32, 0xd9, 0x72, 0x95, + 0x2b, 0xd9, 0x0a, 0xd1, 0x5b, 0x30, 0x84, 0x60, 0xb9, 0x48, 0x23, 0x76, 0x13, 0xd8, 0x55, 0xe6, + 0xdf, 0x4a, 0xfd, 0x4c, 0x07, 0xca, 0xf6, 0x35, 0xa0, 0x9c, 0xf5, 0xa3, 0x34, 0xe3, 0x5e, 0x52, + 0xcd, 0x32, 0x00, 0xfa, 0x10, 0x56, 0xb8, 0xd6, 0x33, 0xee, 0x2b, 0xfb, 0x3b, 0xeb, 0x8a, 0xbf, + 0xc7, 0x1c, 0xba, 0xc7, 0xbc, 0xa9, 0x2b, 0x51, 0xd0, 0x0e, 0xb4, 0x63, 0x1a, 0x6e, 0x77, 0xb9, + 0xbc, 0xaf, 0x1a, 0xf2, 0x36, 0x19, 0xbc, 0x79, 0x40, 0x43, 0x21, 0x67, 0x86, 0xcc, 0x3c, 0xbb, + 0x1f, 0x47, 0x7e, 0xb6, 0xbd, 0x2a, 0x5e, 0x36, 0x3e, 0x30, 0x5f, 0x36, 0xb0, 0x5e, 0x36, 0x74, + 0x1b, 0xd6, 0x55, 0x10, 0xc1, 0x5d, 0xc1, 0x91, 0x9f, 0x1d, 0x91, 0x6c, 0xbb, 0xcf, 0xf9, 0x6d, + 0x9a, 0x42, 0x1f, 0x43, 0x57, 0xb9, 0xac, 0x81, 0xcd, 0x83, 0xf4, 0x57, 0xfc, 0x74, 0x0a, 0x67, + 0xfa, 0x15, 0xf4, 0xd4, 0x09, 0xdf, 0x40, 0xdd, 0x07, 0x34, 0xe4, 0x64, 0x0c, 0x75, 0x7f, 0xc1, + 0x0d, 0x93, 0xdd, 0x44, 0x43, 0xe5, 0x6f, 0x70, 0x9d, 0x5d, 0x58, 0xb7, 0xd6, 0x97, 0xde, 0x7d, + 0x9c, 0x92, 0x79, 0x21, 0xe2, 0xcb, 0xc3, 0x20, 0x49, 0xc5, 0xbb, 0xbe, 0xe6, 0x82, 0x06, 0xb3, + 0x77, 0x6f, 0xc6, 0xde, 0x31, 0x71, 0x3f, 0x7b, 0xae, 0x1c, 0xe1, 0x4b, 0xb0, 0x79, 0x10, 0x65, + 0xb9, 0xf4, 0xac, 0x51, 0xe9, 0x65, 0xf0, 0xd7, 0xb0, 0x55, 0x9d, 0x90, 0xfb, 0xdd, 0x06, 0x08, + 0x4a, 0xa8, 0xbc, 0x4b, 0x93, 0xaa, 0x8b, 0x76, 0x0d, 0x1c, 0xfc, 0x8f, 0x0e, 0xac, 0x31, 0x62, + 0xc2, 0x44, 0x14, 0xe3, 0x86, 0xcf, 0x70, 0x6c, 0x9f, 0xf1, 0x29, 0x74, 0x92, 0x53, 0x4a, 0x52, + 0xe9, 0xff, 0xdf, 0x2d, 0x65, 0x5a, 0xa5, 0x71, 0xf3, 0x31, 0x43, 0x73, 0x05, 0x36, 0xb3, 0x9c, + 0x38, 0x3a, 0x8e, 0x72, 0x19, 0xa1, 0x88, 0x01, 0x93, 0x6f, 0x44, 0x83, 0xb8, 0x08, 0x89, 0xc7, + 0x4d, 0x49, 0xba, 0xfb, 0x9e, 0x5b, 0x05, 0xe3, 0xf7, 0xa0, 0xc3, 0xe9, 0xa1, 0x1e, 0x2c, 0xef, + 0x3e, 0x7e, 0xfa, 0x60, 0xb2, 0xc4, 0x9c, 0xfe, 0xe3, 0x67, 0x8f, 0x26, 0x0e, 0x03, 0x3d, 0xd9, + 0xdf, 0x77, 0x27, 0x2d, 0xfc, 0xe7, 0x0e, 0x20, 0xf3, 0x20, 0x52, 0x2a, 0x5f, 0x94, 0xf7, 0x42, + 0x48, 0xe4, 0xfd, 0xa6, 0x43, 0x4b, 0x83, 0x17, 0x43, 0x61, 0xf3, 0x72, 0xd5, 0xf4, 0x21, 0xf4, + 0x0d, 0x70, 0x83, 0xa1, 0xbd, 0x67, 0x1b, 0xda, 0xc8, 0xbe, 0x77, 0xa6, 0x9d, 0x21, 0x98, 0xb0, + 0x4d, 0x59, 0x94, 0x5f, 0xaa, 0xf3, 0x03, 0xa1, 0x01, 0x09, 0x93, 0x67, 0xde, 0x80, 0x8e, 0xb8, + 0xe5, 0x22, 0x1e, 0x10, 0x83, 0x72, 0x39, 0xd1, 0x72, 0xc6, 0x9f, 0xc9, 0xe5, 0xc4, 0x64, 0x19, + 0x43, 0x47, 0xb8, 0x10, 0xc1, 0xf1, 0x40, 0x9d, 0x88, 0x61, 0xb9, 0x62, 0x0a, 0xff, 0x9b, 0x03, + 0x5d, 0x79, 0x15, 0x98, 0x0d, 0x66, 0xb9, 0x9f, 0x17, 0xea, 0xa5, 0x93, 0x23, 0xf4, 0x11, 0xf4, + 0x64, 0x08, 0x9f, 0x49, 0xe6, 0xb4, 0x39, 0x49, 0xb8, 0x5b, 0x62, 0xa0, 0x6b, 0xb0, 0xc2, 0x83, + 0x5d, 0xe1, 0xd2, 0xfa, 0x3b, 0x43, 0x03, 0x37, 0xa2, 0xae, 0x9c, 0x64, 0xa1, 0xe0, 0x2c, 0x4e, + 0x82, 0x57, 0x47, 0x24, 0x7a, 0x79, 0x94, 0x4b, 0x2f, 0x67, 0x82, 0x4a, 0xcf, 0xd8, 0x31, 0x3c, + 0xa3, 0xe1, 0x6b, 0x57, 0x6c, 0x5f, 0x5b, 0xba, 0xa5, 0xae, 0xe1, 0x96, 0xf0, 0xd7, 0x30, 0xe2, + 0xf7, 0x51, 0x07, 0xad, 0x55, 0x9f, 0xec, 0x34, 0xf8, 0xe4, 0x92, 0x56, 0xcb, 0xa4, 0xf5, 0x97, + 0x0e, 0xa0, 0xc7, 0x73, 0x42, 0xff, 0x5f, 0xe2, 0x65, 0x1d, 0xf7, 0xb6, 0xad, 0xb8, 0xf7, 0x2a, + 0xf4, 0xe7, 0x45, 0x76, 0xe4, 0xc9, 0x49, 0xf1, 0xfa, 0x9a, 0x20, 0x15, 0x19, 0x77, 0x74, 0x64, + 0x7c, 0x17, 0xd6, 0xad, 0x73, 0x4a, 0x73, 0x78, 0x1f, 0x46, 0x76, 0x04, 0x2c, 0xcf, 0x59, 0x81, + 0xe2, 0x7f, 0x68, 0x41, 0x87, 0x1b, 0x2d, 0xb7, 0xbf, 0x34, 0x92, 0x69, 0xa6, 0xe3, 0x8a, 0x81, + 0x15, 0x0d, 0xb4, 0xec, 0x68, 0xc0, 0xf4, 0x19, 0x6d, 0xdb, 0x67, 0x8c, 0xa0, 0x15, 0x85, 0x32, + 0xe2, 0x6f, 0x45, 0x21, 0xfa, 0xb2, 0x2e, 0xb6, 0x0e, 0xb7, 0xad, 0x2d, 0x65, 0x2f, 0xb6, 0xe2, + 0x1a, 0xc5, 0x19, 0x27, 0x81, 0x1f, 0xb3, 0xcd, 0x84, 0x31, 0x94, 0x63, 0xf4, 0x0e, 0x40, 0xc0, + 0xe3, 0xec, 0xd0, 0xf3, 0x73, 0x99, 0xf4, 0x19, 0x10, 0x74, 0x0d, 0x96, 0xb3, 0x28, 0x24, 0xdb, + 0x3d, 0xee, 0xc0, 0xd6, 0xac, 0xbb, 0x7a, 0x18, 0x85, 0xc4, 0xe5, 0xd3, 0xcc, 0x58, 0xa2, 0xcc, + 0x4b, 0x4e, 0xa9, 0xc7, 0xbd, 0x00, 0x7f, 0xf2, 0x7a, 0xae, 0x05, 0x63, 0x66, 0x7a, 0x94, 0xc4, + 0x21, 0x7f, 0xf6, 0x96, 0x5d, 0xfe, 0x8d, 0xff, 0xc2, 0x81, 0x01, 0xa7, 0xe5, 0x92, 0xe3, 0xe4, + 0xc4, 0x8f, 0x2d, 0x99, 0x39, 0x8b, 0x65, 0x56, 0x89, 0xcd, 0xcc, 0x88, 0xae, 0x5d, 0x89, 0xe8, + 0x4c, 0xee, 0x97, 0x2b, 0xdc, 0x57, 0x8f, 0xdd, 0xa9, 0x1f, 0x1b, 0x1f, 0xc1, 0x8a, 0xf0, 0x4c, + 0xe8, 0x63, 0x80, 0x59, 0x71, 0xee, 0x59, 0xde, 0x71, 0x68, 0x49, 0xc4, 0x35, 0x10, 0xd0, 0x2d, + 0xe8, 0x67, 0x24, 0x8e, 0x15, 0x7e, 0xab, 0x09, 0xdf, 0xc4, 0xc0, 0x9f, 0x28, 0xcf, 0xc9, 0x63, + 0x0f, 0x26, 0x2f, 0xe6, 0x7a, 0x64, 0x58, 0xcb, 0xbf, 0x99, 0x0d, 0x27, 0xa7, 0x54, 0x26, 0xb5, + 0xec, 0x13, 0xff, 0xcc, 0x91, 0xab, 0xbe, 0x9b, 0x87, 0x7e, 0x4e, 0xd8, 0x33, 0x2e, 0x78, 0x71, + 0xb8, 0x91, 0xd8, 0xfb, 0x3d, 0x58, 0x72, 0xc5, 0x2c, 0xfa, 0x4d, 0x18, 0x0a, 0x09, 0xa5, 0x42, + 0xf0, 0xd2, 0x5f, 0x6d, 0xd8, 0xc7, 0x13, 0x73, 0x0f, 0x96, 0x5c, 0x1b, 0x79, 0x77, 0x04, 0x03, + 0x01, 0x28, 0xf8, 0xa6, 0xf8, 0x5f, 0x5b, 0xb0, 0xcc, 0x9c, 0xe5, 0xe2, 0x24, 0xe0, 0xb5, 0x42, + 0xbc, 0x2f, 0x61, 0x10, 0xd3, 0x50, 0x0d, 0x95, 0x5f, 0xbc, 0x62, 0xba, 0x63, 0x16, 0x8e, 0x3c, + 0x29, 0x66, 0xdf, 0x90, 0x73, 0xf9, 0xec, 0x58, 0x2b, 0xd8, 0xfe, 0x11, 0x9d, 0x25, 0x05, 0x0d, + 0xe5, 0xdb, 0xa8, 0x86, 0xfa, 0x89, 0xe8, 0x18, 0x4f, 0x04, 0xf3, 0x1a, 0x67, 0x45, 0xe8, 0xd9, + 0xae, 0xd2, 0x04, 0xa1, 0x8f, 0x60, 0x2d, 0x23, 0x41, 0x42, 0xc3, 0x4c, 0xa4, 0x87, 0x41, 0x4e, + 0x42, 0x7e, 0x4f, 0x86, 0x6e, 0x7d, 0xa2, 0x39, 0xe6, 0x9b, 0xde, 0x85, 0x71, 0xe5, 0xd8, 0x0d, + 0xcf, 0xe2, 0x86, 0xf9, 0x2c, 0xae, 0x9a, 0xcf, 0xe0, 0x1f, 0xb6, 0x60, 0xed, 0x09, 0xcb, 0xe4, + 0xa4, 0x52, 0x84, 0x3b, 0xfd, 0xbf, 0xf4, 0x39, 0xe6, 0xfd, 0x59, 0xae, 0xdc, 0x1f, 0xe5, 0x01, + 0x3a, 0x17, 0x7b, 0x00, 0x5e, 0x43, 0xe2, 0xf9, 0xa6, 0x57, 0x92, 0x12, 0xe2, 0xac, 0xc1, 0x59, + 0xa4, 0x1b, 0x1d, 0x1f, 0x93, 0x30, 0xf2, 0x73, 0x06, 0xf5, 0x02, 0x96, 0x4f, 0xc4, 0x5c, 0xaa, + 0x3d, 0xb7, 0x69, 0x8a, 0x89, 0x00, 0x99, 0x22, 0x90, 0x9e, 0xfa, 0x73, 0x96, 0xea, 0xe7, 0x24, + 0xa5, 0x7e, 0xec, 0x1d, 0xfb, 0x79, 0x70, 0x44, 0x16, 0xdc, 0xcb, 0x1a, 0x1a, 0xfa, 0x0d, 0x18, + 0xf1, 0x50, 0x3a, 0x2b, 0x82, 0x80, 0x64, 0x2c, 0x98, 0x12, 0x17, 0xb4, 0x0c, 0xa1, 0x59, 0xc6, + 0x78, 0x28, 0x26, 0xdd, 0x0a, 0x2a, 0xfa, 0x8c, 0x45, 0xaa, 0xc7, 0x7e, 0x44, 0x59, 0x44, 0x2e, + 0xae, 0x5b, 0xbb, 0xe1, 0xba, 0xb9, 0x55, 0x2c, 0xf4, 0x39, 0x0c, 0x39, 0xa9, 0x17, 0x7e, 0x14, + 0x17, 0x29, 0x8f, 0xe0, 0x6a, 0x9b, 0xfe, 0x96, 0x98, 0x73, 0x6d, 0x4c, 0xfc, 0x5f, 0x0e, 0x8c, + 0xb5, 0x08, 0xf6, 0x4f, 0x58, 0x2a, 0x7f, 0x0d, 0x3a, 0x9c, 0x9f, 0x85, 0x97, 0x9d, 0xcf, 0xa2, + 0xcf, 0x61, 0x60, 0x32, 0x20, 0xef, 0x7a, 0x13, 0xa7, 0x0f, 0x96, 0x5c, 0x0b, 0x15, 0x7d, 0xfe, + 0x7a, 0x9c, 0x3e, 0x58, 0x6a, 0xe2, 0x75, 0x60, 0x72, 0xc0, 0x0d, 0xab, 0x99, 0xd5, 0x72, 0x57, + 0x89, 0xba, 0xdb, 0x85, 0x0e, 0x61, 0x0c, 0xe2, 0x04, 0xfa, 0x46, 0x2a, 0xb3, 0x30, 0xf0, 0x32, + 0xdc, 0x4e, 0xcb, 0x76, 0x3b, 0x46, 0x1c, 0xb4, 0x5c, 0x8b, 0x83, 0x44, 0xe1, 0xb1, 0x63, 0x14, + 0x1e, 0xf1, 0x27, 0xb0, 0xc9, 0xbd, 0x1e, 0xd1, 0x15, 0xed, 0x9f, 0x9f, 0xa9, 0x6f, 0xc3, 0x56, + 0x75, 0x91, 0x2c, 0x7c, 0x1d, 0x00, 0x12, 0x33, 0xd6, 0xd5, 0xbd, 0xa8, 0x00, 0x71, 0xc1, 0x05, + 0xc6, 0x9f, 0xc2, 0xba, 0x45, 0x4d, 0xde, 0x82, 0x77, 0x60, 0xa2, 0x50, 0xbc, 0x84, 0x7a, 0xfc, + 0x91, 0x75, 0x8c, 0x47, 0xf6, 0x63, 0x58, 0x13, 0xcb, 0xcc, 0x72, 0xfc, 0xc2, 0xa4, 0x05, 0x6f, + 0xa8, 0x33, 0x5b, 0xd5, 0xf5, 0x3f, 0x6a, 0x31, 0x70, 0x96, 0x27, 0xa9, 0x55, 0xc4, 0x7b, 0xad, + 0x8a, 0x9c, 0x59, 0xe9, 0x6b, 0xd9, 0x95, 0x3e, 0xf4, 0x0d, 0xf4, 0x99, 0x07, 0x9f, 0xf9, 0xc1, + 0xab, 0x62, 0xae, 0x5c, 0xfe, 0x0d, 0x65, 0x24, 0xf5, 0x1d, 0xd9, 0x03, 0xb0, 0x2b, 0x90, 0xc5, + 0x03, 0x00, 0x71, 0x09, 0x40, 0x3f, 0xe2, 0x7d, 0x0b, 0x2f, 0xf4, 0x73, 0x7f, 0xe6, 0x67, 0xa2, + 0x0a, 0x3a, 0xe0, 0xfe, 0xfc, 0xbe, 0x04, 0x49, 0x5f, 0x6c, 0x52, 0xf8, 0x79, 0xbe, 0x78, 0x60, + 0xfa, 0x62, 0xc2, 0x54, 0x60, 0x9c, 0x49, 0x17, 0x26, 0x53, 0x01, 0x96, 0x05, 0x47, 0x29, 0x06, + 0x05, 0xe4, 0xd5, 0xc6, 0x0f, 0x78, 0x99, 0x5d, 0x20, 0xa9, 0xbc, 0x5d, 0x24, 0xb1, 0x63, 0x05, + 0x57, 0x75, 0xc6, 0x35, 0x18, 0x1f, 0x1e, 0x15, 0x79, 0x98, 0x9c, 0xaa, 0x52, 0x3b, 0xcb, 0x66, + 0x34, 0x48, 0x2a, 0xe5, 0xd7, 0x60, 0xeb, 0xb0, 0x98, 0x65, 0x41, 0x1a, 0xcd, 0x88, 0x9d, 0x93, + 0x4e, 0xa1, 0x47, 0xce, 0xa2, 0x2c, 0x8f, 0xe8, 0x4b, 0xce, 0x58, 0xcf, 0x2d, 0xc7, 0xf8, 0x5d, + 0x78, 0xbb, 0x5c, 0xc5, 0x6e, 0x61, 0x76, 0x2f, 0x08, 0xc8, 0x3c, 0x27, 0xa1, 0xda, 0xea, 0x2e, + 0x6c, 0xda, 0x08, 0x46, 0x0f, 0x47, 0xe5, 0x9a, 0xb9, 0xff, 0x4a, 0x06, 0x19, 0x3d, 0xd7, 0x06, + 0xe2, 0xff, 0x69, 0xc1, 0x80, 0x2d, 0x53, 0x64, 0xd1, 0xe5, 0x9a, 0xbd, 0x77, 0xf9, 0xf8, 0xa1, + 0x1d, 0x9d, 0xb5, 0x2a, 0xd1, 0xd9, 0x85, 0xef, 0xd5, 0xa2, 0x3a, 0x9b, 0x7e, 0x17, 0x3b, 0xe6, + 0xbb, 0x58, 0xad, 0xde, 0xad, 0x34, 0x54, 0xef, 0xb6, 0x60, 0x25, 0xe5, 0xa5, 0x15, 0x99, 0x1a, + 0xc9, 0x11, 0x7b, 0xda, 0x44, 0x0a, 0xe1, 0xa5, 0x24, 0x20, 0xd1, 0x09, 0x93, 0x69, 0x4f, 0xb4, + 0x47, 0xaa, 0x70, 0x96, 0x3b, 0x48, 0x58, 0x26, 0xbb, 0x0c, 0xab, 0xa2, 0x65, 0x63, 0x43, 0xd1, + 0x4d, 0x40, 0xca, 0x7d, 0x18, 0x54, 0x45, 0x45, 0xa8, 0x61, 0x86, 0x9d, 0xa1, 0x84, 0x2a, 0xca, + 0x7d, 0xf1, 0xbc, 0x56, 0xe1, 0xf8, 0xaf, 0x1d, 0xe8, 0x1b, 0xde, 0xf5, 0x17, 0xac, 0x77, 0x9a, + 0x32, 0x6e, 0x57, 0x64, 0x5c, 0x95, 0xe6, 0x72, 0x83, 0x34, 0xdf, 0x87, 0x91, 0x74, 0xe7, 0x5e, + 0x4a, 0xfc, 0x2c, 0x51, 0x8e, 0xb6, 0x02, 0xc5, 0x7f, 0xdb, 0x16, 0xa7, 0x95, 0x2f, 0xd0, 0x2f, + 0xd7, 0x58, 0xb4, 0xca, 0x3b, 0x96, 0xca, 0xaf, 0xc3, 0xd8, 0x52, 0x2d, 0x09, 0xa5, 0xc6, 0xab, + 0x60, 0x16, 0x41, 0x6a, 0xd5, 0xe6, 0x52, 0xdb, 0x26, 0xa8, 0x26, 0x2c, 0x68, 0x10, 0xd6, 0x55, + 0x58, 0x4e, 0x93, 0x98, 0x70, 0x95, 0x8e, 0x74, 0x01, 0xc2, 0x4d, 0x62, 0xe2, 0xf2, 0x19, 0x16, + 0x87, 0x56, 0xcc, 0x82, 0x84, 0xbc, 0xea, 0xb7, 0xea, 0xd6, 0x27, 0xd8, 0x45, 0x35, 0xcd, 0x22, + 0xdf, 0x1e, 0x8a, 0xfe, 0x81, 0x05, 0x64, 0xc9, 0x5f, 0xea, 0xcd, 0x53, 0x12, 0x1d, 0xfb, 0x2f, + 0xc9, 0xf6, 0x88, 0xa3, 0x18, 0x10, 0x7d, 0x95, 0xc6, 0xc6, 0x55, 0xc2, 0xff, 0xdd, 0x82, 0xce, + 0xd3, 0xd4, 0x0f, 0x09, 0xcb, 0x70, 0x8e, 0xd9, 0x8d, 0xf7, 0x16, 0x67, 0x1c, 0xae, 0x89, 0xc1, + 0x16, 0xe4, 0xc6, 0x82, 0x56, 0xe3, 0x02, 0x03, 0xc3, 0xd0, 0x4f, 0xdb, 0xd2, 0xcf, 0x45, 0x3a, + 0x35, 0x2c, 0xa1, 0x63, 0x5b, 0x42, 0xc9, 0xcf, 0x8a, 0xe9, 0x1a, 0x94, 0xec, 0xbb, 0x0b, 0x65, + 0x7f, 0x15, 0xfa, 0x44, 0xb4, 0x11, 0x78, 0x96, 0x2c, 0x2c, 0xc1, 0x04, 0x95, 0x41, 0xf2, 0xea, + 0xc5, 0x41, 0xf2, 0x1d, 0x18, 0x04, 0xcc, 0x30, 0x48, 0x3a, 0xf7, 0xd3, 0x5c, 0x98, 0xc2, 0xe2, + 0x44, 0xde, 0xc2, 0xc5, 0x1f, 0xc2, 0x3a, 0x97, 0xfa, 0x83, 0x88, 0x3d, 0x15, 0xe7, 0x46, 0x1a, + 0x20, 0x6a, 0x85, 0x8e, 0x51, 0x2b, 0xc4, 0x77, 0x61, 0xc3, 0x46, 0x96, 0xef, 0xd4, 0x35, 0x58, + 0xc9, 0x19, 0xbc, 0x16, 0x26, 0x73, 0x6c, 0x57, 0x4e, 0xe2, 0x3d, 0x18, 0x32, 0x40, 0x44, 0x5f, + 0x1e, 0x30, 0x72, 0xec, 0x52, 0x76, 0xbf, 0xf5, 0xcf, 0x0e, 0x49, 0x1c, 0xab, 0xac, 0xfc, 0xd8, + 0x3f, 0xf3, 0x58, 0xf2, 0x8a, 0x2e, 0xc1, 0xca, 0xb7, 0xfe, 0xd9, 0x6e, 0xa1, 0xc2, 0x95, 0x2e, + 0x9b, 0x99, 0x15, 0xe7, 0x78, 0x47, 0x9c, 0xa1, 0x24, 0xf2, 0x3a, 0x91, 0xd4, 0xdf, 0x38, 0xb0, + 0x59, 0x59, 0x24, 0x4f, 0x7e, 0x0f, 0x56, 0x38, 0x6b, 0xea, 0xe4, 0x1f, 0x98, 0x27, 0xaf, 0xa1, + 0xdf, 0x14, 0x43, 0x59, 0x99, 0x14, 0x0b, 0xa7, 0x4f, 0xa0, 0x6f, 0x80, 0x1b, 0x9e, 0xfd, 0x0f, + 0xed, 0xca, 0xe4, 0x66, 0xf3, 0x16, 0x46, 0x34, 0xf0, 0x13, 0x18, 0x7c, 0x47, 0x67, 0xbf, 0x40, + 0x3b, 0x1c, 0x5d, 0x81, 0xd5, 0x94, 0xc8, 0xbc, 0x51, 0x06, 0x01, 0x1a, 0x80, 0xc7, 0x30, 0x94, + 0x74, 0x75, 0x03, 0xf5, 0x3b, 0x1a, 0x27, 0xc1, 0xab, 0xd7, 0x6d, 0xa0, 0xfe, 0x14, 0x90, 0xb9, + 0x40, 0x87, 0x29, 0x05, 0x87, 0x56, 0xc2, 0x14, 0x05, 0xe4, 0x61, 0xca, 0xbb, 0xd0, 0x37, 0x51, + 0x44, 0xbf, 0x05, 0x34, 0x02, 0xfe, 0x13, 0x07, 0xc6, 0xcf, 0xa2, 0xfc, 0x28, 0x4c, 0xfd, 0xd3, + 0xd7, 0x50, 0x6a, 0xb5, 0x99, 0xdd, 0xba, 0xa8, 0x99, 0xdd, 0xae, 0x36, 0xb3, 0xfd, 0x38, 0x96, + 0xa9, 0x3c, 0xfb, 0x34, 0x8b, 0x78, 0x43, 0x51, 0xc4, 0xbb, 0x03, 0x13, 0x7d, 0x98, 0x37, 0xab, + 0xe0, 0xdd, 0xb8, 0x0e, 0xab, 0xe5, 0x15, 0x45, 0x5d, 0x68, 0xef, 0x7e, 0xf7, 0xdb, 0x93, 0x25, + 0xd4, 0x83, 0xe5, 0xc3, 0xfd, 0x83, 0x03, 0x51, 0x2c, 0xe7, 0xf5, 0xf3, 0xd6, 0x8d, 0x1b, 0xb0, + 0xcc, 0x1c, 0x02, 0x5a, 0x85, 0xce, 0xd3, 0x7b, 0xdf, 0xec, 0xbb, 0x93, 0x25, 0xf6, 0xf9, 0x2d, + 0xff, 0x74, 0xd0, 0x00, 0x7a, 0x0f, 0x1f, 0x3d, 0xdd, 0x77, 0x1f, 0xdd, 0x3b, 0x98, 0xb4, 0x76, + 0xfe, 0xdd, 0x81, 0xee, 0xf3, 0x22, 0x7c, 0x48, 0xa3, 0x1c, 0xed, 0x03, 0xe8, 0x3e, 0x36, 0xba, + 0x5c, 0x96, 0x78, 0xab, 0xdd, 0xf0, 0xe9, 0xb4, 0x69, 0x4a, 0x6a, 0x7f, 0x09, 0x3d, 0x80, 0xbe, + 0x11, 0x76, 0xa2, 0xe9, 0xe2, 0xf8, 0x78, 0xfa, 0x56, 0xe3, 0x5c, 0x49, 0x69, 0x1f, 0x40, 0x1b, + 0x86, 0x3e, 0x50, 0xcd, 0xba, 0xf4, 0x81, 0xea, 0x76, 0x84, 0x97, 0x76, 0xfe, 0x6e, 0x0b, 0xda, + 0xcf, 0x8b, 0x10, 0x3d, 0x87, 0xbe, 0xf1, 0xfb, 0x0f, 0xaa, 0xb5, 0x4f, 0xf4, 0x71, 0x9a, 0xfe, + 0x12, 0x9a, 0xfe, 0xec, 0x9f, 0xfe, 0xf3, 0x4f, 0x5b, 0x1b, 0x78, 0x7c, 0xeb, 0xe4, 0x57, 0x6f, + 0xf9, 0x61, 0xa8, 0x4c, 0xe6, 0x8e, 0x73, 0x03, 0xb9, 0xd0, 0x95, 0x7f, 0xf8, 0xa0, 0x2d, 0x83, + 0x86, 0x91, 0xc3, 0x4c, 0x2f, 0xd5, 0xe0, 0x92, 0xee, 0x16, 0xa7, 0x3b, 0xc1, 0x7d, 0x49, 0x97, + 0x3d, 0x00, 0x8c, 0xe6, 0x2e, 0xb4, 0x77, 0x7d, 0x8a, 0x90, 0x6e, 0x65, 0xaa, 0xab, 0x3b, 0x5d, + 0xb7, 0x60, 0x92, 0x0e, 0xe2, 0x74, 0x06, 0xb8, 0xcb, 0xe8, 0xcc, 0x7c, 0xca, 0x68, 0x04, 0x30, + 0x30, 0x7f, 0xa7, 0x40, 0xba, 0xa9, 0x5f, 0xff, 0x47, 0x64, 0x7a, 0xa5, 0x79, 0x52, 0x92, 0xdf, + 0xe6, 0xe4, 0x11, 0x9e, 0x30, 0xf2, 0xfc, 0x6f, 0x13, 0xd9, 0x1c, 0x60, 0xcc, 0xcb, 0x7f, 0x28, + 0x34, 0xf3, 0xf6, 0x2f, 0x18, 0x9a, 0xf9, 0xea, 0xcf, 0x16, 0x16, 0xf3, 0xd2, 0xa3, 0xb0, 0x83, + 0x7f, 0x0f, 0xc3, 0x67, 0xfc, 0xbf, 0x1f, 0xd9, 0xb9, 0xd7, 0x94, 0xed, 0xc6, 0xbf, 0xa6, 0x5c, + 0x69, 0xf1, 0xe3, 0x2b, 0x9c, 0xf2, 0x16, 0x5e, 0x63, 0x94, 0xc5, 0x3f, 0x44, 0xa1, 0x40, 0x61, + 0xf4, 0x7f, 0x0f, 0x86, 0x56, 0x93, 0x1e, 0x95, 0xcc, 0x37, 0x75, 0xff, 0xa7, 0x6f, 0x2f, 0x98, + 0x6d, 0xda, 0x2b, 0x94, 0x28, 0xbc, 0xad, 0xcf, 0xf6, 0x7a, 0x0e, 0xa0, 0x9b, 0xdd, 0xda, 0x8a, + 0x6b, 0x0d, 0x76, 0x6d, 0xc5, 0xf5, 0xde, 0x38, 0x5e, 0xe7, 0x5b, 0x0c, 0x51, 0x5f, 0x68, 0x57, + 0xd0, 0x3a, 0x80, 0xae, 0x6c, 0xeb, 0x6a, 0xf9, 0xd8, 0xbd, 0x6d, 0x2d, 0x9f, 0x4a, 0xff, 0x17, + 0x4f, 0x38, 0x41, 0x40, 0x3d, 0x46, 0x30, 0x62, 0x24, 0x7e, 0x07, 0xfa, 0x46, 0xa7, 0x13, 0x99, + 0xa7, 0xa9, 0xb4, 0x4f, 0xf5, 0x45, 0x69, 0x68, 0x8d, 0xe2, 0x0d, 0x4e, 0x79, 0x84, 0x06, 0x8c, + 0x32, 0x93, 0x02, 0xa7, 0xfe, 0x0c, 0x40, 0x37, 0xe5, 0xb4, 0x14, 0x6a, 0xdd, 0x45, 0x2d, 0x85, + 0x7a, 0x0f, 0x4f, 0xd9, 0x38, 0x02, 0x46, 0x5a, 0x96, 0xae, 0x5f, 0xc2, 0xc8, 0xee, 0x99, 0xa2, + 0xb7, 0x4d, 0x0a, 0xb5, 0x26, 0xeb, 0xf4, 0x9d, 0x45, 0xd3, 0xb6, 0x4d, 0xa2, 0x11, 0xb7, 0x49, + 0x4d, 0xf6, 0x10, 0x56, 0xcb, 0x6e, 0x1e, 0xda, 0x36, 0x89, 0x98, 0x4d, 0xbf, 0xe9, 0xe5, 0x86, + 0x19, 0x49, 0x79, 0x8d, 0x53, 0xee, 0xa3, 0x55, 0x46, 0x59, 0x14, 0x75, 0x15, 0x51, 0xfe, 0x13, + 0x80, 0x4d, 0xd4, 0x68, 0x05, 0x56, 0x88, 0x9a, 0x0d, 0xc1, 0x0a, 0x51, 0x4e, 0xc7, 0x83, 0xbe, + 0xd1, 0x2b, 0xd2, 0x9a, 0xac, 0x37, 0xba, 0xb4, 0x26, 0x1b, 0x9a, 0x4b, 0xf8, 0x12, 0x27, 0xbd, + 0x26, 0x5c, 0x5e, 0x32, 0x27, 0x54, 0x5d, 0xf9, 0xdf, 0x05, 0xd0, 0xe5, 0x3d, 0xad, 0xcc, 0x5a, + 0xe1, 0x57, 0x9b, 0x5f, 0xa5, 0x1a, 0x88, 0x2f, 0x73, 0xd2, 0xeb, 0x98, 0x0b, 0x99, 0x97, 0x5c, + 0xb9, 0x3a, 0xef, 0x38, 0x37, 0x6e, 0x3b, 0xe8, 0x05, 0x8c, 0x34, 0xfe, 0xe1, 0x39, 0x0d, 0x2e, + 0xda, 0x62, 0xda, 0x34, 0x25, 0x19, 0x78, 0x9b, 0xef, 0x72, 0x09, 0x23, 0x7b, 0x97, 0xec, 0x9c, + 0x06, 0xec, 0x66, 0xfe, 0x14, 0xfa, 0xc6, 0x2f, 0x37, 0x5a, 0x4e, 0xf5, 0xff, 0x70, 0xa6, 0x4d, + 0x05, 0x48, 0xfb, 0x49, 0x90, 0x21, 0x76, 0x76, 0xea, 0xcf, 0x19, 0x6d, 0x0a, 0x23, 0xbb, 0xce, + 0xa6, 0xcd, 0xb2, 0xb1, 0x68, 0xa7, 0xcd, 0x72, 0x41, 0x79, 0xce, 0xe2, 0x85, 0x37, 0x37, 0x88, + 0xf9, 0x04, 0xcd, 0xd8, 0xab, 0x5b, 0xd6, 0xdb, 0xcc, 0x57, 0xb7, 0x5a, 0xd2, 0x33, 0x5f, 0xdd, + 0x5a, 0x81, 0xce, 0xe6, 0x49, 0x6c, 0xa3, 0x34, 0x83, 0xbe, 0x07, 0xd0, 0xd5, 0x36, 0xad, 0x93, + 0x5a, 0xc1, 0x6e, 0x3a, 0x6d, 0x9a, 0x92, 0x1b, 0x58, 0x9a, 0x17, 0x1b, 0xa8, 0x27, 0xef, 0x27, + 0xd0, 0x53, 0x65, 0x23, 0x54, 0x5a, 0x4e, 0xa5, 0xb6, 0x34, 0xdd, 0xae, 0x4f, 0x54, 0xcc, 0x95, + 0x3b, 0x9e, 0x4c, 0xce, 0x32, 0xba, 0x04, 0xc6, 0x95, 0xd2, 0x13, 0x2a, 0xa5, 0xdd, 0x5c, 0x93, + 0x9a, 0xda, 0x7f, 0xd8, 0x88, 0x7e, 0x15, 0x7e, 0x8b, 0x6f, 0xb0, 0x89, 0xd6, 0xf9, 0x06, 0x6a, + 0xa1, 0x30, 0xa9, 0xdb, 0x0e, 0x9a, 0x57, 0x4a, 0x51, 0xb2, 0xa6, 0x61, 0x38, 0xa4, 0xc6, 0x4a, + 0xd5, 0xb4, 0xa9, 0xcc, 0x8c, 0x7f, 0xc4, 0xf7, 0x7a, 0x0b, 0x5d, 0xb6, 0xf6, 0x62, 0xd6, 0xa5, + 0xaa, 0xec, 0xb7, 0x1d, 0x34, 0x83, 0x91, 0x4d, 0xf2, 0x8d, 0xb6, 0xaa, 0x98, 0x31, 0x42, 0xb5, + 0xad, 0xd8, 0x1e, 0x7f, 0x60, 0xd4, 0xed, 0xac, 0x0a, 0x1c, 0xba, 0xd6, 0xbc, 0x57, 0xa5, 0x42, + 0x37, 0xdd, 0x30, 0xf7, 0x54, 0x93, 0x18, 0xf3, 0x4d, 0xaf, 0xa0, 0x69, 0x7d, 0x53, 0x5f, 0xe2, + 0x70, 0x4f, 0x30, 0x30, 0x73, 0x43, 0x1d, 0xc0, 0x34, 0xa4, 0x97, 0x3a, 0x80, 0x69, 0x4a, 0x27, + 0x95, 0xf2, 0x44, 0x00, 0xc3, 0x73, 0xc7, 0x23, 0x81, 0xc1, 0x2c, 0xe4, 0x65, 0x35, 0x89, 0xbc, + 0xb2, 0x20, 0x65, 0xab, 0xc4, 0x03, 0x8d, 0x09, 0x9d, 0x32, 0x71, 0xb4, 0xa6, 0xb6, 0x8a, 0xe8, + 0x4b, 0x91, 0xd7, 0xa1, 0xaf, 0xa1, 0xc3, 0xb3, 0x25, 0xb4, 0xa1, 0x43, 0x56, 0x9d, 0x94, 0x4d, + 0x37, 0x2b, 0x50, 0xfb, 0x49, 0xc5, 0xdc, 0xc7, 0x17, 0x54, 0x46, 0x77, 0x33, 0x18, 0x89, 0x20, + 0x49, 0xe5, 0x14, 0xfa, 0xd2, 0x54, 0x52, 0x1e, 0x7d, 0x69, 0xaa, 0xe9, 0x87, 0xed, 0x56, 0x44, + 0x9c, 0x74, 0x2a, 0x71, 0xee, 0x38, 0x37, 0x66, 0x2b, 0xfc, 0xcf, 0xf9, 0x4f, 0xfe, 0x37, 0x00, + 0x00, 0xff, 0xff, 0xd8, 0xb0, 0x15, 0x00, 0x64, 0x2f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. From 49c8c18cf9d00ede7f84ce617921ffc3aa9b18de Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Wed, 14 Oct 2020 11:20:31 -0400 Subject: [PATCH 04/11] fix(cli): switch getbalance table columns (#1931) This fixes a bug where the values for wallet balance and channel balance were switched in the `getbalance` formatted table output. Closes #1930 --- lib/cli/commands/getbalance.ts | 2 +- .../cli/__snapshots__/getbalance.spec.ts.snap | 26 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/cli/commands/getbalance.ts b/lib/cli/commands/getbalance.ts index c058a2b53..63deb664b 100644 --- a/lib/cli/commands/getbalance.ts +++ b/lib/cli/commands/getbalance.ts @@ -22,8 +22,8 @@ const formatBalances = (balances: GetBalanceResponse.AsObject) => { element.push( currency, satsToCoinsStr(balance.totalBalance), - formatBalance(balance.channelBalance, balance.pendingChannelBalance, balance.inactiveChannelBalance), formatBalance(balance.walletBalance, balance.unconfirmedWalletBalance), + formatBalance(balance.channelBalance, balance.pendingChannelBalance, balance.inactiveChannelBalance), satsToCoinsStr(balance.reservedBalance), ); formatted.push(element); diff --git a/test/jest/cli/__snapshots__/getbalance.spec.ts.snap b/test/jest/cli/__snapshots__/getbalance.spec.ts.snap index 707c6bd5a..6174ea995 100644 --- a/test/jest/cli/__snapshots__/getbalance.spec.ts.snap +++ b/test/jest/cli/__snapshots__/getbalance.spec.ts.snap @@ -10,7 +10,7 @@ Balance:", "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┬───────────┐ │ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ ├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.004 │ 0.001 │ 0 │ +│ BTC │ 0.005 │ 0.001 │ 0.004 │ 0 │ └──────────┴───────────────┴───────────────────────────────┴────────────────────────────┴───────────┘", ], ] @@ -26,7 +26,7 @@ Balance:", "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┬───────────┐ │ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ ├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.004 │ 0.001 │ 0.0008 │ +│ BTC │ 0.005 │ 0.001 │ 0.004 │ 0.0008 │ └──────────┴───────────────┴───────────────────────────────┴────────────────────────────┴───────────┘", ], ] @@ -39,11 +39,11 @@ Array [ Balance:", ], Array [ - "┌──────────┬───────────────┬──────────────────────────────────────────┬────────────────────────────┬───────────┐ -│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ -├──────────┼───────────────┼──────────────────────────────────────────┼────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.004 (0.00075 pending | 0.001 inactive) │ 0.001 (0.00025 pending) │ 0 │ -└──────────┴───────────────┴──────────────────────────────────────────┴────────────────────────────┴───────────┘", + "┌──────────┬───────────────┬───────────────────────────────┬──────────────────────────────────────────┬───────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ +├──────────┼───────────────┼───────────────────────────────┼──────────────────────────────────────────┼───────────┤ +│ BTC │ 0.005 │ 0.001 (0.00025 pending) │ 0.004 (0.00075 pending | 0.001 inactive) │ 0 │ +└──────────┴───────────────┴───────────────────────────────┴──────────────────────────────────────────┴───────────┘", ], ] `; @@ -58,7 +58,7 @@ Balance:", "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┬───────────┐ │ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ ├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.004 (0.00075 pending) │ 0.001 (0.00025 pending) │ 0 │ +│ BTC │ 0.005 │ 0.001 (0.00025 pending) │ 0.004 (0.00075 pending) │ 0 │ └──────────┴───────────────┴───────────────────────────────┴────────────────────────────┴───────────┘", ], ] @@ -71,11 +71,11 @@ Array [ Balance:", ], Array [ - "┌──────────┬───────────────┬──────────────────────────────────────────┬────────────────────────────┬───────────┐ -│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ -├──────────┼───────────────┼──────────────────────────────────────────┼────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.004 (0.00075 pending | 0.001 inactive) │ 0.001 (0.00025 pending) │ 0.0008 │ -└──────────┴───────────────┴──────────────────────────────────────────┴────────────────────────────┴───────────┘", + "┌──────────┬───────────────┬───────────────────────────────┬──────────────────────────────────────────┬───────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ +├──────────┼───────────────┼───────────────────────────────┼──────────────────────────────────────────┼───────────┤ +│ BTC │ 0.005 │ 0.001 (0.00025 pending) │ 0.004 (0.00075 pending | 0.001 inactive) │ 0.0008 │ +└──────────┴───────────────┴───────────────────────────────┴──────────────────────────────────────────┴───────────┘", ], ] `; From 98d6ca9c2fa8fa9953aa70896d7a8bd3f525e417 Mon Sep 17 00:00:00 2001 From: Karl Ranna Date: Thu, 15 Oct 2020 16:30:34 +0100 Subject: [PATCH 05/11] chore(simnet): upgrade simnet contracts (#1935) --- lib/db/seeds/simnet.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/db/seeds/simnet.ts b/lib/db/seeds/simnet.ts index 6c3503b59..83dad61e6 100644 --- a/lib/db/seeds/simnet.ts +++ b/lib/db/seeds/simnet.ts @@ -31,13 +31,13 @@ const currencies = [ id: 'USDT', swapClient: SwapClientType.Connext, decimalPlaces: 6, - tokenAddress: '0x292Ba2F10dbFB8925A209d3AdF09C2D2b1f491d4', + tokenAddress: '0x6149AA6798a75450EFb0151204513ce197f626Ce', }, { id: 'DAI', swapClient: SwapClientType.Connext, decimalPlaces: 18, - tokenAddress: '0x5CF98f1782117a20D8613Bf42701026c86061857', + tokenAddress: '0x69C3d485623bA3f382Fc0FB6756c4574d43C1618', }, /* { From 7f7cd683272e738a77480028c16095e8fb34c175 Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Thu, 15 Oct 2020 04:15:53 -0400 Subject: [PATCH 06/11] feat(rpc): reserved order amount for TradingLimits This exposes the amounts reserved for open orders on the `TradingLimits` call and subtracts reserved amounts from the `maxSell` and `maxBuy` values returned by the call. It also removes reserved order amounts from GetBalance - reversing #1584. The logic to calculate max sell and buys is as follows: 1. Sum up all outbound and inbound balances across all channels, as well as the maximum balances for a single channel, as we still aren't expecting to use multi-path payments. For Connext there is a single channel so we only have a single inbound & outbound value per currency. 2. Subtract reserved order amounts from the total inbound and outbound balances calculated above. E.g. if we have outbound capacity of 1.2 ETH, but we have an order to sell 0.7 ETH, our max sell would be 0.5 ETH. 3. Return the smaller of the amount calculated in step 2 or the maximum single channel balance calculated in step 1. Resolves #1678. --- docs/api.md | 7 +- lib/cli/commands/getbalance.ts | 8 +- lib/cli/commands/tradinglimits.ts | 22 +- lib/connextclient/ConnextClient.ts | 35 +- lib/grpc/GrpcService.ts | 9 +- lib/lndclient/LndClient.ts | 42 +- lib/proto/annotations_grpc_pb.js | 2 +- lib/proto/xudp2p_grpc_pb.js | 2 +- lib/proto/xudrpc.swagger.json | 23 +- lib/proto/xudrpc_pb.d.ts | 24 +- lib/proto/xudrpc_pb.js | 107 ++-- lib/service/Service.ts | 21 +- lib/swaps/SwapClient.ts | 18 +- lib/swaps/SwapClientManager.ts | 21 + lib/swaps/types.ts | 22 + proto/xudrpc.proto | 14 +- test/jest/Connext.spec.ts | 12 +- test/jest/LndClient.spec.ts | 14 +- test/jest/Service.spec.ts | 86 +-- test/jest/SwapClientManager.spec.ts | 49 ++ test/jest/__snapshots__/Service.spec.ts.snap | 7 - .../SwapClientManager.spec.ts.snap | 7 + .../cli/__snapshots__/getbalance.spec.ts.snap | 62 +-- .../__snapshots__/tradinglimits.spec.ts.snap | 17 + test/jest/cli/getbalance.spec.ts | 34 -- test/jest/cli/tradinglimits.spec.ts | 31 ++ test/simulation/tests-integration.go | 6 +- test/simulation/xudrpc/xudrpc.pb.go | 526 +++++++++--------- 28 files changed, 643 insertions(+), 585 deletions(-) create mode 100644 test/jest/cli/__snapshots__/tradinglimits.spec.ts.snap create mode 100644 test/jest/cli/tradinglimits.spec.ts diff --git a/docs/api.md b/docs/api.md index 9a3224af7..b866623ad 100644 --- a/docs/api.md +++ b/docs/api.md @@ -156,7 +156,6 @@ | inactive_channel_balance | [uint64](#uint64) | | Sum of inactive channel balances denominated in satoshis. | | wallet_balance | [uint64](#uint64) | | Confirmed wallet balance in satoshis. | | unconfirmed_wallet_balance | [uint64](#uint64) | | Unconfirmed wallet balance in satoshis. | -| reserved_balance | [uint64](#uint64) | | The balance that's reserved for open orders. | @@ -1261,8 +1260,10 @@ | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| MaxSell | [uint64](#uint64) | | Max outbound capacity for a distinct channel denominated in satoshis. | -| MaxBuy | [uint64](#uint64) | | Max inbound capacity for a distinct channel denominated in satoshis. | +| max_sell | [uint64](#uint64) | | Maximum outbound limit for an order denominated in satoshis. | +| max_buy | [uint64](#uint64) | | Maximum inbound limit for an order denominated in satoshis. | +| reserved_outbound | [uint64](#uint64) | | The outbound amount reserved for open orders. | +| reserved_inbound | [uint64](#uint64) | | The inbound amount reserved for open orders. | diff --git a/lib/cli/commands/getbalance.ts b/lib/cli/commands/getbalance.ts index 63deb664b..8dc35e155 100644 --- a/lib/cli/commands/getbalance.ts +++ b/lib/cli/commands/getbalance.ts @@ -10,7 +10,6 @@ const HEADERS = [ colors.blue('Total Balance'), colors.blue('Wallet Balance (Not Tradable)'), colors.blue('Channel Balance (Tradable)'), - colors.blue('In Orders'), ]; const formatBalances = (balances: GetBalanceResponse.AsObject) => { @@ -18,15 +17,14 @@ const formatBalances = (balances: GetBalanceResponse.AsObject) => { balances.balancesMap.forEach((balanceElement) => { const currency = balanceElement[0]; const balance = balanceElement[1]; - const element = []; - element.push( + const row = []; + row.push( currency, satsToCoinsStr(balance.totalBalance), formatBalance(balance.walletBalance, balance.unconfirmedWalletBalance), formatBalance(balance.channelBalance, balance.pendingChannelBalance, balance.inactiveChannelBalance), - satsToCoinsStr(balance.reservedBalance), ); - formatted.push(element); + formatted.push(row); }); return formatted; }; diff --git a/lib/cli/commands/tradinglimits.ts b/lib/cli/commands/tradinglimits.ts index 2266f24d0..28b6a5415 100644 --- a/lib/cli/commands/tradinglimits.ts +++ b/lib/cli/commands/tradinglimits.ts @@ -9,18 +9,24 @@ const HEADERS = [ colors.blue('Currency'), colors.blue('Max Buy'), colors.blue('Max Sell'), + colors.blue('Reserved Outbound'), + colors.blue('Reserved Inbound'), ]; const formatTradingLimits = (tradingLimits: TradingLimitsResponse.AsObject) => { const formatted: any[] = []; - tradingLimits.limitsMap.forEach((limits) => { - const element = []; - element.push( - limits[0], - `${satsToCoinsStr(limits[1].maxbuy)}`, - `${satsToCoinsStr(limits[1].maxsell)}`, + tradingLimits.limitsMap.forEach((tradingLimitElement) => { + const currency = tradingLimitElement[0]; + const tradingLimit = tradingLimitElement[1]; + const row = []; + row.push( + currency, + `${satsToCoinsStr(tradingLimit.maxBuy)}`, + `${satsToCoinsStr(tradingLimit.maxSell)}`, + `${satsToCoinsStr(tradingLimit.reservedOutbound)}`, + `${satsToCoinsStr(tradingLimit.reservedInbound)}`, ); - formatted.push(element); + formatted.push(row); }); return formatted; }; @@ -32,7 +38,7 @@ const createTable = () => { return table; }; -const displayLimits = (limits: TradingLimitsResponse.AsObject) => { +export const displayLimits = (limits: TradingLimitsResponse.AsObject) => { const table = createTable(); const formatted = formatTradingLimits(limits); formatted.forEach(limits => table.push(limits)); diff --git a/lib/connextclient/ConnextClient.ts b/lib/connextclient/ConnextClient.ts index 15950e1ba..b92a1533a 100644 --- a/lib/connextclient/ConnextClient.ts +++ b/lib/connextclient/ConnextClient.ts @@ -10,12 +10,11 @@ import SwapClient, { ClientStatus, PaymentState, WalletBalance, - TradingLimits, SwapClientInfo, PaymentStatus, WithdrawArguments, } from '../swaps/SwapClient'; -import { SwapDeal, CloseChannelParams, OpenChannelParams } from '../swaps/types'; +import { SwapDeal, CloseChannelParams, OpenChannelParams, SwapCapacities } from '../swaps/types'; import { UnitConverter } from '../utils/UnitConverter'; import errors, { errorCodes } from './errors'; import { @@ -115,8 +114,8 @@ class ConnextClient extends SwapClient { private getBalancePromises = new Map>(); /** A map of currencies to promises representing collateral requests. */ private requestCollateralPromises = new Map>(); - private _totalOutboundAmount = new Map(); - private _maxChannelInboundAmount = new Map(); + private outboundAmounts = new Map(); + private inboundAmounts = new Map(); /** The minimum incremental quantity that we may use for collateral requests. */ private static MIN_COLLATERAL_REQUEST_SIZES: { [key: string]: number | undefined } = { @@ -261,11 +260,7 @@ class ConnextClient extends SwapClient { } public totalOutboundAmount = (currency: string): number => { - return this._totalOutboundAmount.get(currency) || 0; - } - - public maxChannelOutboundAmount = (currency: string): number => { - return this._totalOutboundAmount.get(currency) || 0; + return this.outboundAmounts.get(currency) || 0; } /** @@ -291,7 +286,7 @@ class ConnextClient extends SwapClient { } public checkInboundCapacity = (inboundAmount: number, currency: string) => { - const inboundCapacity = this._maxChannelInboundAmount.get(currency) || 0; + const inboundCapacity = this.inboundAmounts.get(currency) || 0; if (inboundCapacity < inboundAmount) { // we do not have enough inbound capacity to receive the specified inbound amount so we must request collateral this.logger.debug(`collateral of ${inboundCapacity} for ${currency} is insufficient for order amount ${inboundAmount}`); @@ -310,7 +305,7 @@ class ConnextClient extends SwapClient { } public setReservedInboundAmount = (reservedInboundAmount: number, currency: string) => { - const inboundCapacity = this._maxChannelInboundAmount.get(currency) || 0; + const inboundCapacity = this.inboundAmounts.get(currency) || 0; if (inboundCapacity < reservedInboundAmount) { // we do not have enough inbound capacity to fill all open orders, so we will request more this.logger.debug(`collateral of ${inboundCapacity} for ${currency} is insufficient for reserved order amount of ${reservedInboundAmount}`); @@ -663,9 +658,9 @@ class ConnextClient extends SwapClient { units: Number(nodeFreeBalanceOffChain), }); - this._totalOutboundAmount.set(currency, freeBalanceAmount); - if (nodeFreeBalanceAmount !== this._maxChannelInboundAmount.get(currency)) { - this._maxChannelInboundAmount.set(currency, nodeFreeBalanceAmount); + this.outboundAmounts.set(currency, freeBalanceAmount); + if (nodeFreeBalanceAmount !== this.inboundAmounts.get(currency)) { + this.inboundAmounts.set(currency, nodeFreeBalanceAmount); this.logger.debug(`new inbound capacity (collateral) for ${currency} of ${nodeFreeBalanceAmount}`); } @@ -676,11 +671,15 @@ class ConnextClient extends SwapClient { }; } - public tradingLimits = async (currency: string): Promise => { - await this.channelBalance(currency); // refreshes the max outbound balance + public swapCapacities = async (currency: string): Promise => { + await this.channelBalance(currency); // refreshes the balances + const outboundAmount = this.outboundAmounts.get(currency) ?? 0; + const inboundAmount = this.inboundAmounts.get(currency) ?? 0; return { - maxSell: this.maxChannelOutboundAmount(currency), - maxBuy: this._maxChannelInboundAmount.get(currency) ?? 0, + maxOutboundChannelCapacity: outboundAmount, + maxInboundChannelCapacity: inboundAmount, + totalOutboundCapacity: outboundAmount, + totalInboundCapacity: inboundAmount, }; } diff --git a/lib/grpc/GrpcService.ts b/lib/grpc/GrpcService.ts index 45a8ca430..bea355554 100644 --- a/lib/grpc/GrpcService.ts +++ b/lib/grpc/GrpcService.ts @@ -307,9 +307,6 @@ class GrpcService { balance.setInactiveChannelBalance(balanceObj.inactiveChannelBalance); balance.setWalletBalance(balanceObj.walletBalance); balance.setUnconfirmedWalletBalance(balanceObj.unconfirmedWalletBalance); - if (balanceObj.reservedBalance) { - balance.setReservedBalance(balanceObj.reservedBalance); - } balancesMap.set(currency, balance); }); callback(null, response); @@ -331,8 +328,10 @@ class GrpcService { const limitsMap = response.getLimitsMap(); tradingLimitsResponse.forEach((tradingLimitsObj, currency) => { const tradingLimits = new xudrpc.TradingLimits(); - tradingLimits.setMaxsell(tradingLimitsObj.maxSell); - tradingLimits.setMaxbuy(tradingLimitsObj.maxBuy); + tradingLimits.setMaxSell(tradingLimitsObj.maxSell); + tradingLimits.setMaxBuy(tradingLimitsObj.maxBuy); + tradingLimits.setReservedInbound(tradingLimitsObj.reservedInbound); + tradingLimits.setReservedOutbound(tradingLimitsObj.reservedOutbound); limitsMap.set(currency, tradingLimits); }); callback(null, response); diff --git a/lib/lndclient/LndClient.ts b/lib/lndclient/LndClient.ts index 1ba7164f0..9c55d7bd2 100644 --- a/lib/lndclient/LndClient.ts +++ b/lib/lndclient/LndClient.ts @@ -10,8 +10,8 @@ import * as lndinvoices from '../proto/lndinvoices_pb'; import { LightningClient, WalletUnlockerClient } from '../proto/lndrpc_grpc_pb'; import * as lndrpc from '../proto/lndrpc_pb'; import swapErrors from '../swaps/errors'; -import SwapClient, { ChannelBalance, ClientStatus, PaymentState, SwapClientInfo, TradingLimits, WithdrawArguments } from '../swaps/SwapClient'; -import { CloseChannelParams, OpenChannelParams, SwapDeal } from '../swaps/types'; +import SwapClient, { ChannelBalance, ClientStatus, PaymentState, SwapClientInfo, WithdrawArguments } from '../swaps/SwapClient'; +import { CloseChannelParams, OpenChannelParams, SwapCapacities, SwapDeal } from '../swaps/types'; import { deriveChild } from '../utils/seedutil'; import { base64ToHex, hexToUint8Array } from '../utils/utils'; import errors from './errors'; @@ -63,8 +63,9 @@ class LndClient extends SwapClient { private invoiceSubscriptions = new Map>(); private initRetryTimeout?: NodeJS.Timeout; private _totalOutboundAmount = 0; - private _maxChannelOutboundAmount = 0; - private _maxChannelInboundAmount = 0; + private totalInboundAmount = 0; + private maxChannelOutboundAmount = 0; + private maxChannelInboundAmount = 0; private initWalletResolve?: (value: boolean) => void; private watchMacaroonResolve?: (value: boolean) => void; @@ -195,10 +196,6 @@ class LndClient extends SwapClient { return this._totalOutboundAmount; } - public maxChannelOutboundAmount = () => { - return this._maxChannelOutboundAmount; - } - public checkInboundCapacity = (_inboundAmount: number) => { return; // we do not currently check inbound capacities for lnd } @@ -715,6 +712,7 @@ class LndClient extends SwapClient { let balance = 0; let inactiveBalance = 0; let totalOutboundAmount = 0; + let totalInboundAmount = 0; channels.toObject().channelsList.forEach((channel) => { if (channel.active) { balance += channel.localBalance; @@ -725,6 +723,7 @@ class LndClient extends SwapClient { } const inbound = channel.remoteBalance - channel.remoteChanReserveSat; + totalInboundAmount += inbound; if (maxInbound < inbound) { maxInbound = inbound; } @@ -733,19 +732,24 @@ class LndClient extends SwapClient { } }); - if (this._maxChannelOutboundAmount !== maxOutbound) { - this._maxChannelOutboundAmount = maxOutbound; + if (this.maxChannelOutboundAmount !== maxOutbound) { + this.maxChannelOutboundAmount = maxOutbound; this.logger.debug(`new channel maximum outbound capacity: ${maxOutbound}`); } - if (this._maxChannelInboundAmount !== maxInbound) { - this._maxChannelInboundAmount = maxInbound; + if (this.maxChannelInboundAmount !== maxInbound) { + this.maxChannelInboundAmount = maxInbound; this.logger.debug(`new channel inbound capacity: ${maxInbound}`); } if (this._totalOutboundAmount !== totalOutboundAmount) { this._totalOutboundAmount = totalOutboundAmount; - this.logger.debug(`new channel total outbound capacity: ${maxOutbound}`); + this.logger.debug(`new channel total outbound capacity: ${totalOutboundAmount}`); + } + + if (this.totalInboundAmount !== totalInboundAmount) { + this.totalInboundAmount = totalInboundAmount; + this.logger.debug(`new channel total inbound capacity: ${totalInboundAmount}`); } const pendingOpenBalance = pendingChannels.toObject().pendingOpenChannelsList. @@ -754,6 +758,8 @@ class LndClient extends SwapClient { return { maxOutbound, maxInbound, + totalOutboundAmount, + totalInboundAmount, balance, inactiveBalance, pendingOpenBalance, @@ -765,11 +771,13 @@ class LndClient extends SwapClient { return { balance, inactiveBalance, pendingOpenBalance }; } - public tradingLimits = async (): Promise => { - const { maxOutbound, maxInbound } = await this.updateChannelBalances(); + public swapCapacities = async (): Promise => { + const { maxOutbound, maxInbound, totalInboundAmount, totalOutboundAmount } = await this.updateChannelBalances(); // get fresh balances return { - maxSell: maxOutbound, - maxBuy: maxInbound, + maxOutboundChannelCapacity: maxOutbound, + maxInboundChannelCapacity: maxInbound, + totalOutboundCapacity: totalOutboundAmount, + totalInboundCapacity: totalInboundAmount, }; } diff --git a/lib/proto/annotations_grpc_pb.js b/lib/proto/annotations_grpc_pb.js index 51b4d6959..97b3a2461 100644 --- a/lib/proto/annotations_grpc_pb.js +++ b/lib/proto/annotations_grpc_pb.js @@ -1 +1 @@ -// GENERATED CODE -- NO SERVICES IN PROTO +// GENERATED CODE -- NO SERVICES IN PROTO \ No newline at end of file diff --git a/lib/proto/xudp2p_grpc_pb.js b/lib/proto/xudp2p_grpc_pb.js index 51b4d6959..97b3a2461 100644 --- a/lib/proto/xudp2p_grpc_pb.js +++ b/lib/proto/xudp2p_grpc_pb.js @@ -1 +1 @@ -// GENERATED CODE -- NO SERVICES IN PROTO +// GENERATED CODE -- NO SERVICES IN PROTO \ No newline at end of file diff --git a/lib/proto/xudrpc.swagger.json b/lib/proto/xudrpc.swagger.json index 0a1c485ae..29db24fb1 100644 --- a/lib/proto/xudrpc.swagger.json +++ b/lib/proto/xudrpc.swagger.json @@ -887,11 +887,6 @@ "type": "string", "format": "uint64", "description": "Unconfirmed wallet balance in satoshis." - }, - "reserved_balance": { - "type": "string", - "format": "uint64", - "description": "The balance that's reserved for open orders." } } }, @@ -1834,15 +1829,25 @@ "xudrpcTradingLimits": { "type": "object", "properties": { - "MaxSell": { + "max_sell": { + "type": "string", + "format": "uint64", + "description": "Maximum outbound limit for an order denominated in satoshis." + }, + "max_buy": { + "type": "string", + "format": "uint64", + "description": "Maximum inbound limit for an order denominated in satoshis." + }, + "reserved_outbound": { "type": "string", "format": "uint64", - "description": "Max outbound capacity for a distinct channel denominated in satoshis." + "description": "The outbound amount reserved for open orders." }, - "MaxBuy": { + "reserved_inbound": { "type": "string", "format": "uint64", - "description": "Max inbound capacity for a distinct channel denominated in satoshis." + "description": "The inbound amount reserved for open orders." } } }, diff --git a/lib/proto/xudrpc_pb.d.ts b/lib/proto/xudrpc_pb.d.ts index 93e2eb745..65148b769 100644 --- a/lib/proto/xudrpc_pb.d.ts +++ b/lib/proto/xudrpc_pb.d.ts @@ -84,9 +84,6 @@ export class Balance extends jspb.Message { getUnconfirmedWalletBalance(): number; setUnconfirmedWalletBalance(value: number): void; - getReservedBalance(): number; - setReservedBalance(value: number): void; - serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): Balance.AsObject; @@ -106,7 +103,6 @@ export namespace Balance { inactiveChannelBalance: number, walletBalance: number, unconfirmedWalletBalance: number, - reservedBalance: number, } } @@ -2003,11 +1999,17 @@ export namespace TradeHistoryResponse { } export class TradingLimits extends jspb.Message { - getMaxsell(): number; - setMaxsell(value: number): void; + getMaxSell(): number; + setMaxSell(value: number): void; + + getMaxBuy(): number; + setMaxBuy(value: number): void; + + getReservedOutbound(): number; + setReservedOutbound(value: number): void; - getMaxbuy(): number; - setMaxbuy(value: number): void; + getReservedInbound(): number; + setReservedInbound(value: number): void; serializeBinary(): Uint8Array; @@ -2022,8 +2024,10 @@ export class TradingLimits extends jspb.Message { export namespace TradingLimits { export type AsObject = { - maxsell: number, - maxbuy: number, + maxSell: number, + maxBuy: number, + reservedOutbound: number, + reservedInbound: number, } } diff --git a/lib/proto/xudrpc_pb.js b/lib/proto/xudrpc_pb.js index 08518fe93..7f26f0e55 100644 --- a/lib/proto/xudrpc_pb.js +++ b/lib/proto/xudrpc_pb.js @@ -546,8 +546,7 @@ proto.xudrpc.Balance.toObject = function(includeInstance, msg) { pendingChannelBalance: jspb.Message.getFieldWithDefault(msg, 3, 0), inactiveChannelBalance: jspb.Message.getFieldWithDefault(msg, 4, 0), walletBalance: jspb.Message.getFieldWithDefault(msg, 5, 0), - unconfirmedWalletBalance: jspb.Message.getFieldWithDefault(msg, 6, 0), - reservedBalance: jspb.Message.getFieldWithDefault(msg, 7, 0) + unconfirmedWalletBalance: jspb.Message.getFieldWithDefault(msg, 6, 0) }; if (includeInstance) { @@ -608,10 +607,6 @@ proto.xudrpc.Balance.deserializeBinaryFromReader = function(msg, reader) { var value = /** @type {number} */ (reader.readUint64()); msg.setUnconfirmedWalletBalance(value); break; - case 7: - var value = /** @type {number} */ (reader.readUint64()); - msg.setReservedBalance(value); - break; default: reader.skipField(); break; @@ -683,13 +678,6 @@ proto.xudrpc.Balance.serializeBinaryToWriter = function(message, writer) { f ); } - f = message.getReservedBalance(); - if (f !== 0) { - writer.writeUint64( - 7, - f - ); - } }; @@ -783,21 +771,6 @@ proto.xudrpc.Balance.prototype.setUnconfirmedWalletBalance = function(value) { }; -/** - * optional uint64 reserved_balance = 7; - * @return {number} - */ -proto.xudrpc.Balance.prototype.getReservedBalance = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 7, 0)); -}; - - -/** @param {number} value */ -proto.xudrpc.Balance.prototype.setReservedBalance = function(value) { - jspb.Message.setProto3IntField(this, 7, value); -}; - - /** * Generated by JsPbCodeGenerator. @@ -13512,8 +13485,10 @@ proto.xudrpc.TradingLimits.prototype.toObject = function(opt_includeInstance) { */ proto.xudrpc.TradingLimits.toObject = function(includeInstance, msg) { var f, obj = { - maxsell: jspb.Message.getFieldWithDefault(msg, 1, 0), - maxbuy: jspb.Message.getFieldWithDefault(msg, 2, 0) + maxSell: jspb.Message.getFieldWithDefault(msg, 1, 0), + maxBuy: jspb.Message.getFieldWithDefault(msg, 2, 0), + reservedOutbound: jspb.Message.getFieldWithDefault(msg, 3, 0), + reservedInbound: jspb.Message.getFieldWithDefault(msg, 4, 0) }; if (includeInstance) { @@ -13552,11 +13527,19 @@ proto.xudrpc.TradingLimits.deserializeBinaryFromReader = function(msg, reader) { switch (field) { case 1: var value = /** @type {number} */ (reader.readUint64()); - msg.setMaxsell(value); + msg.setMaxSell(value); break; case 2: var value = /** @type {number} */ (reader.readUint64()); - msg.setMaxbuy(value); + msg.setMaxBuy(value); + break; + case 3: + var value = /** @type {number} */ (reader.readUint64()); + msg.setReservedOutbound(value); + break; + case 4: + var value = /** @type {number} */ (reader.readUint64()); + msg.setReservedInbound(value); break; default: reader.skipField(); @@ -13587,53 +13570,97 @@ proto.xudrpc.TradingLimits.prototype.serializeBinary = function() { */ proto.xudrpc.TradingLimits.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getMaxsell(); + f = message.getMaxSell(); if (f !== 0) { writer.writeUint64( 1, f ); } - f = message.getMaxbuy(); + f = message.getMaxBuy(); if (f !== 0) { writer.writeUint64( 2, f ); } + f = message.getReservedOutbound(); + if (f !== 0) { + writer.writeUint64( + 3, + f + ); + } + f = message.getReservedInbound(); + if (f !== 0) { + writer.writeUint64( + 4, + f + ); + } }; /** - * optional uint64 MaxSell = 1; + * optional uint64 max_sell = 1; * @return {number} */ -proto.xudrpc.TradingLimits.prototype.getMaxsell = function() { +proto.xudrpc.TradingLimits.prototype.getMaxSell = function() { return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); }; /** @param {number} value */ -proto.xudrpc.TradingLimits.prototype.setMaxsell = function(value) { +proto.xudrpc.TradingLimits.prototype.setMaxSell = function(value) { jspb.Message.setProto3IntField(this, 1, value); }; /** - * optional uint64 MaxBuy = 2; + * optional uint64 max_buy = 2; * @return {number} */ -proto.xudrpc.TradingLimits.prototype.getMaxbuy = function() { +proto.xudrpc.TradingLimits.prototype.getMaxBuy = function() { return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); }; /** @param {number} value */ -proto.xudrpc.TradingLimits.prototype.setMaxbuy = function(value) { +proto.xudrpc.TradingLimits.prototype.setMaxBuy = function(value) { jspb.Message.setProto3IntField(this, 2, value); }; +/** + * optional uint64 reserved_outbound = 3; + * @return {number} + */ +proto.xudrpc.TradingLimits.prototype.getReservedOutbound = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0)); +}; + + +/** @param {number} value */ +proto.xudrpc.TradingLimits.prototype.setReservedOutbound = function(value) { + jspb.Message.setProto3IntField(this, 3, value); +}; + + +/** + * optional uint64 reserved_inbound = 4; + * @return {number} + */ +proto.xudrpc.TradingLimits.prototype.getReservedInbound = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0)); +}; + + +/** @param {number} value */ +proto.xudrpc.TradingLimits.prototype.setReservedInbound = function(value) { + jspb.Message.setProto3IntField(this, 4, value); +}; + + /** * Generated by JsPbCodeGenerator. diff --git a/lib/service/Service.ts b/lib/service/Service.ts index 2c49b2207..cddead02f 100644 --- a/lib/service/Service.ts +++ b/lib/service/Service.ts @@ -8,10 +8,10 @@ import OrderBook from '../orderbook/OrderBook'; import { Currency, isOwnOrder, Order, OrderPortion, OwnLimitOrder, OwnMarketOrder, OwnOrder, PeerOrder, PlaceOrderEvent } from '../orderbook/types'; import Pool from '../p2p/Pool'; import swapsErrors from '../swaps/errors'; -import { ChannelBalance, TradingLimits } from '../swaps/SwapClient'; +import { ChannelBalance } from '../swaps/SwapClient'; import SwapClientManager from '../swaps/SwapClientManager'; import Swaps from '../swaps/Swaps'; -import { ResolveRequest, SwapAccepted, SwapDeal, SwapFailure, SwapSuccess } from '../swaps/types'; +import { ResolveRequest, SwapAccepted, SwapDeal, SwapFailure, SwapSuccess, TradingLimits } from '../swaps/types'; import { isNodePubKey } from '../utils/aliasUtils'; import { parseUri, toUri, UriParts } from '../utils/uriUtils'; import { checkDecimalPlaces, sortOrders, toEip55Address } from '../utils/utils'; @@ -125,7 +125,6 @@ class Service { await swapClient.channelBalance(currency), await swapClient.walletBalance(currency), ]); - channelBalance.reservedBalance = this.swapClientManager.getOutboundReservedAmount(currency); channelBalances.set(currency, channelBalance); walletBalances.set(currency, walletBalance); } else { @@ -136,7 +135,6 @@ class Service { this.swapClientManager.swapClients.forEach((swapClient, currency) => { if (swapClient.isConnected()) { balancePromises.push(swapClient.channelBalance(currency).then((channelBalance) => { - channelBalance.reservedBalance = this.swapClientManager.getOutboundReservedAmount(currency); channelBalances.set(currency, channelBalance); }).catch(this.logger.error)); balancePromises.push(swapClient.walletBalance(currency).then((walletBalance) => { @@ -148,8 +146,7 @@ class Service { } const balances = new Map(); channelBalances.forEach((channelBalance, currency) => { const walletBalance = walletBalances.get(currency); @@ -164,7 +161,6 @@ class Service { channelBalance: channelBalance.balance, pendingChannelBalance: channelBalance.pendingOpenBalance, inactiveChannelBalance: channelBalance.inactiveBalance, - reservedBalance: channelBalance.reservedBalance, walletBalance: walletBalance.confirmedBalance, unconfirmedWalletBalance: walletBalance.unconfirmedBalance, }); @@ -181,18 +177,13 @@ class Service { if (currency) { argChecks.VALID_CURRENCY(args); - const swapClient = this.swapClientManager.get(currency.toUpperCase()); - if (swapClient) { - const tradingLimits = await swapClient.tradingLimits(currency); - tradingLimitsMap.set(currency, tradingLimits); - } else { - throw swapsErrors.SWAP_CLIENT_NOT_FOUND(currency); - } + const tradingLimits = await this.swapClientManager.tradingLimits(currency.toUpperCase()); + tradingLimitsMap.set(currency, tradingLimits); } else { const promises: Promise[] = []; this.swapClientManager.swapClients.forEach((swapClient, currency) => { if (swapClient.isConnected()) { - promises.push(swapClient.tradingLimits(currency).then((tradingLimits) => { + promises.push(this.swapClientManager.tradingLimits(currency).then((tradingLimits) => { tradingLimitsMap.set(currency, tradingLimits); }).catch(this.logger.error)); } diff --git a/lib/swaps/SwapClient.ts b/lib/swaps/SwapClient.ts index bf158052a..30cd29795 100644 --- a/lib/swaps/SwapClient.ts +++ b/lib/swaps/SwapClient.ts @@ -1,8 +1,8 @@ -import Logger from '../Logger'; import { EventEmitter } from 'events'; -import { SwapDeal, Route, CloseChannelParams, OpenChannelParams } from './types'; import { SwapClientType } from '../constants/enums'; +import Logger from '../Logger'; import { setTimeoutPromise } from '../utils/utils'; +import { CloseChannelParams, OpenChannelParams, Route, SwapCapacities, SwapDeal } from './types'; enum ClientStatus { /** The starting status before a client has initialized. */ @@ -34,8 +34,6 @@ type ChannelBalance = { pendingOpenBalance: number, /** The cumulative balance of inactive channels denominated in satoshis. */ inactiveBalance: number, - /** The balance that is reserved for open orders denominated in satoshis. */ - reservedBalance?: number, }; type WalletBalance = { @@ -47,13 +45,6 @@ type WalletBalance = { unconfirmedBalance: number, }; -type TradingLimits = { - /** Max outbound capacity for a distinct channel denominated in satoshis. */ - maxSell: number, - /** Max inbound capacity for a distinct channel denominated in satoshis. */ - maxBuy: number, -}; - export type SwapClientInfo = { newIdentifier?: string; newUris?: string[]; @@ -133,10 +124,9 @@ abstract class SwapClient extends EventEmitter { * @param currency the currency whose trading limits to query for, otherwise all/any * currencies supported by this client are included in the trading limits. */ - public abstract tradingLimits(currency?: string): Promise; + public abstract swapCapacities(currency?: string): Promise; public abstract totalOutboundAmount(currency?: string): number; - public abstract maxChannelOutboundAmount(currency?: string): number; /** * Checks whether there is sufficient inbound capacity to receive the specified amount * and throws an error if there isn't, otherwise does nothing. @@ -400,4 +390,4 @@ abstract class SwapClient extends EventEmitter { } export default SwapClient; -export { ClientStatus, ChannelBalance, WalletBalance, TradingLimits }; +export { ClientStatus, ChannelBalance, WalletBalance }; diff --git a/lib/swaps/SwapClientManager.ts b/lib/swaps/SwapClientManager.ts index 2d76a4bae..4e0877287 100644 --- a/lib/swaps/SwapClientManager.ts +++ b/lib/swaps/SwapClientManager.ts @@ -13,6 +13,7 @@ import { UnitConverter } from '../utils/UnitConverter'; import errors from './errors'; import SwapClient, { ClientStatus } from './SwapClient'; import assert from 'assert'; +import { TradingLimits } from './types'; export function isConnextClient(swapClient: SwapClient): swapClient is ConnextClient { return (swapClient.type === SwapClientType.Connext); @@ -163,6 +164,26 @@ class SwapClientManager extends EventEmitter { } } + public tradingLimits = async (currency: string): Promise => { + const swapClient = this.get(currency); + if (swapClient) { + const swapCapacities = await swapClient.swapCapacities(currency); + const reservedOutbound = this.outboundReservedAmounts.get(currency) ?? 0; + const reservedInbound = this.inboundReservedAmounts.get(currency) ?? 0; + const availableOutboundCapacity = Math.max(0, swapCapacities.totalOutboundCapacity - reservedOutbound); + const availableInboundCapacity = Math.max(0, swapCapacities.totalInboundCapacity - reservedInbound); + + return { + reservedOutbound, + reservedInbound, + maxSell: Math.min(swapCapacities.maxOutboundChannelCapacity, availableOutboundCapacity), + maxBuy: Math.min(swapCapacities.maxInboundChannelCapacity, availableInboundCapacity), + }; + } else { + throw errors.SWAP_CLIENT_NOT_FOUND(currency); + } + } + public getOutboundReservedAmount = (currency: string) => { return this.outboundReservedAmounts.get(currency); } diff --git a/lib/swaps/types.ts b/lib/swaps/types.ts index 978ac54cf..1f6d8f7ae 100644 --- a/lib/swaps/types.ts +++ b/lib/swaps/types.ts @@ -108,6 +108,28 @@ export type SanitySwap = Pick & currency: string; }; +export type SwapCapacities = { + /** Max outbound capacity for a distinct channel denominated in satoshis. */ + maxOutboundChannelCapacity: number, + /** Max inbound capacity for a distinct channel denominated in satoshis. */ + maxInboundChannelCapacity: number, + /** The total outbound capacity. */ + totalOutboundCapacity: number, + /** The total inbound capacity. */ + totalInboundCapacity: number, +}; + +export type TradingLimits = { + /** Maximum outbound limit for an order denominated in satoshis. */ + maxSell: number, + /** Maximum inbound limit for an order denominated in satoshis. */ + maxBuy: number, + /** The outbound amount reserved for open orders. */ + reservedOutbound: number, + /** The inbound amount reserved for open orders. */ + reservedInbound: number, +}; + export type ResolveRequest = { /** The amount of the incoming payment pending resolution, in the smallest units supported by the token. */ amount: number, diff --git a/proto/xudrpc.proto b/proto/xudrpc.proto index fce3113a7..8fe161852 100644 --- a/proto/xudrpc.proto +++ b/proto/xudrpc.proto @@ -359,8 +359,6 @@ message Balance { uint64 wallet_balance = 5 [json_name = "wallet_balance"]; // Unconfirmed wallet balance in satoshis. uint64 unconfirmed_wallet_balance = 6 [json_name = "unconfirmed_wallet_balance"]; - // The balance that's reserved for open orders. - uint64 reserved_balance = 7 [json_name = "reserved_balance"]; } message BanRequest { @@ -886,10 +884,14 @@ message TradeHistoryResponse { } message TradingLimits { - // Max outbound capacity for a distinct channel denominated in satoshis. - uint64 MaxSell = 1 [json_name = "max_sell"]; - // Max inbound capacity for a distinct channel denominated in satoshis. - uint64 MaxBuy = 2 [json_name = "max_buy"]; + // Maximum outbound limit for an order denominated in satoshis. + uint64 max_sell = 1 [json_name = "max_sell"]; + // Maximum inbound limit for an order denominated in satoshis. + uint64 max_buy = 2 [json_name = "max_buy"]; + // The outbound amount reserved for open orders. + uint64 reserved_outbound = 3 [json_name = "reserved_outbound"]; + // The inbound amount reserved for open orders. + uint64 reserved_inbound = 4 [json_name = "reserved_outbound"]; } message TradingLimitsRequest { diff --git a/test/jest/Connext.spec.ts b/test/jest/Connext.spec.ts index f431421a0..bb7a1a182 100644 --- a/test/jest/Connext.spec.ts +++ b/test/jest/Connext.spec.ts @@ -330,7 +330,7 @@ describe('ConnextClient', () => { }); it('requests collateral plus 3% buffer when we have none', async () => { - connext['_maxChannelInboundAmount'].set('ETH', 0); + connext['inboundAmounts'].set('ETH', 0); connext.setReservedInboundAmount(amount, currency); expect(connext['sendRequest']).toHaveBeenCalledWith( '/request-collateral', @@ -340,7 +340,7 @@ describe('ConnextClient', () => { }); it('requests collateral plus 3% buffer when we have some collateral already', async () => { - connext['_maxChannelInboundAmount'].set('ETH', amount * 0.5); + connext['inboundAmounts'].set('ETH', amount * 0.5); connext.setReservedInboundAmount(amount, currency); expect(connext['sendRequest']).toHaveBeenCalledWith( '/request-collateral', @@ -350,7 +350,7 @@ describe('ConnextClient', () => { }); it('does not request collateral when we have more than enough to cover the reserved inbound amount', async () => { - connext['_maxChannelInboundAmount'].set('ETH', amount * 2); + connext['inboundAmounts'].set('ETH', amount * 2); connext.setReservedInboundAmount(amount, currency); expect(connext['sendRequest']).toHaveBeenCalledTimes(0); }); @@ -361,7 +361,7 @@ describe('ConnextClient', () => { const smallQuantity = 100; beforeEach(() => { connext['sendRequest'] = jest.fn().mockResolvedValue(undefined); - connext['_maxChannelInboundAmount'].set('ETH', 0); + connext['inboundAmounts'].set('ETH', 0); }); it('requests collateral plus 5% buffer when there is none', async () => { @@ -384,7 +384,7 @@ describe('ConnextClient', () => { it('requests the full collateral amount even when there is some existing collateral', async () => { const partialCollateral = 5000; - connext['_maxChannelInboundAmount'].set('ETH', partialCollateral); + connext['inboundAmounts'].set('ETH', partialCollateral); expect(() => connext.checkInboundCapacity(quantity, 'ETH')).toThrowError('channel collateralization in progress, please try again in ~1 minute'); @@ -421,7 +421,7 @@ describe('ConnextClient', () => { }); it('does not request collateral or throw when there is sufficient collateral', async () => { - connext['_maxChannelInboundAmount'].set('ETH', quantity); + connext['inboundAmounts'].set('ETH', quantity); connext.checkInboundCapacity(quantity, 'ETH'); expect(connext['sendRequest']).toHaveBeenCalledTimes(0); diff --git a/test/jest/LndClient.spec.ts b/test/jest/LndClient.spec.ts index 4f5270abf..8a39ff6f8 100644 --- a/test/jest/LndClient.spec.ts +++ b/test/jest/LndClient.spec.ts @@ -255,9 +255,9 @@ describe('LndClient', () => { }); }); - describe('tradingLimits', () => { + describe('swapCapacities', () => { - test('fetch and persist trading limits', async () => { + test('fetch and persist swap capacities', async () => { expect.assertions(5); lnd['pendingChannels'] = jest.fn().mockImplementation(() => { @@ -285,13 +285,13 @@ describe('LndClient', () => { }); }); - const tradingLimits = await lnd.tradingLimits(); - expect(tradingLimits.maxSell).toEqual(98); - expect(tradingLimits.maxBuy).toEqual(295); + const swapCapacities = await lnd.swapCapacities(); + expect(swapCapacities.maxOutboundChannelCapacity).toEqual(98); + expect(swapCapacities.maxInboundChannelCapacity).toEqual(295); expect(lnd['listChannels']).toHaveBeenCalledTimes(1); - expect(lnd.maxChannelOutboundAmount()).toEqual(98); - expect(lnd['_maxChannelInboundAmount']).toEqual(295); + expect(lnd['maxChannelOutboundAmount']).toEqual(98); + expect(lnd['maxChannelInboundAmount']).toEqual(295); }); }); }); diff --git a/test/jest/Service.spec.ts b/test/jest/Service.spec.ts index d50e6a1bb..d4f5e80b0 100644 --- a/test/jest/Service.spec.ts +++ b/test/jest/Service.spec.ts @@ -190,61 +190,6 @@ describe('Service', () => { expect(btcBalance.totalBalance).toEqual(289008); }); - test('returns balance with reserved amounts', async () => { - setup(); - const reservedBalance = 10000; - service['swapClientManager'].getOutboundReservedAmount = jest.fn().mockReturnValue(reservedBalance); - const result = await service.getBalance({ currency: 'BTC' }); - expect(result.size).toEqual(1); - - const btcBalance = result.get('BTC')!; - expect(btcBalance).toBeTruthy(); - expect(btcBalance.channelBalance).toEqual(70000); - expect(btcBalance.pendingChannelBalance).toEqual(190191); - expect(btcBalance.inactiveChannelBalance).toEqual(18817); - expect(btcBalance.walletBalance).toEqual(10000); - expect(btcBalance.unconfirmedWalletBalance).toEqual(0); - expect(btcBalance.totalBalance).toEqual(289008); - expect(btcBalance.reservedBalance).toEqual(reservedBalance); - }); - - test('returns balance with reserved amounts for multiple currencies', async () => { - setup(); - const btcReservedBalance = 10000; - const ltcReservedBalance = 2345; - service['swapClientManager'].getOutboundReservedAmount = jest.fn().mockImplementation((currency) => { - if (currency === 'BTC') { - return btcReservedBalance; - } - if (currency === 'LTC') { - return ltcReservedBalance; - } - return undefined; - }); - const result = await service.getBalance({ currency: '' }); - expect(result.size).toEqual(2); - - const btcBalance = result.get('BTC')!; - expect(btcBalance).toBeTruthy(); - expect(btcBalance.channelBalance).toEqual(70000); - expect(btcBalance.pendingChannelBalance).toEqual(190191); - expect(btcBalance.inactiveChannelBalance).toEqual(18817); - expect(btcBalance.walletBalance).toEqual(10000); - expect(btcBalance.unconfirmedWalletBalance).toEqual(0); - expect(btcBalance.totalBalance).toEqual(289008); - expect(btcBalance.reservedBalance).toEqual(btcReservedBalance); - - const ltcBalance = result.get('LTC')!; - expect(ltcBalance).toBeTruthy(); - expect(ltcBalance.channelBalance).toEqual(0); - expect(ltcBalance.pendingChannelBalance).toEqual(0); - expect(ltcBalance.inactiveChannelBalance).toEqual(12345); - expect(ltcBalance.walletBalance).toEqual(1500); - expect(ltcBalance.unconfirmedWalletBalance).toEqual(500); - expect(ltcBalance.totalBalance).toEqual(14345); - expect(ltcBalance.reservedBalance).toEqual(ltcReservedBalance); - }); - test('throws in case of invalid currency', async () => { setup(); await expect(service.getBalance({ currency: 'A' })).rejects.toMatchSnapshot(); @@ -260,22 +205,28 @@ describe('Service', () => { const setup = () => { service = new Service(components); components.swapClientManager.swapClients = new Map(); - components.swapClientManager.get = jest.fn().mockImplementation((arg) => { - return components.swapClientManager.swapClients.get(arg); + components.swapClientManager.tradingLimits = jest.fn().mockImplementation((currency) => { + if (currency === 'BTC') { + return Promise.resolve({ + maxSell: 2000, + maxBuy: 1500, + }); + } else if (currency === 'LTC') { + return Promise.resolve({ + maxSell: 7000, + maxBuy: 5500, + }); + } else { + return Promise.resolve(); + } }); const btcClient = new mockedSwapClient(); - btcClient.isConnected = jest.fn().mockImplementation(() => true); - btcClient.tradingLimits = jest.fn().mockImplementation(() => { - return Promise.resolve({ maxSell: 2000, maxBuy: 1500 }); - }); + btcClient.isConnected = jest.fn().mockReturnValue(true); components.swapClientManager.swapClients.set('BTC', btcClient); const ltcClient = new mockedSwapClient(); - ltcClient.isConnected = jest.fn().mockImplementation(() => true); - ltcClient.tradingLimits = jest.fn().mockImplementation(() => { - return Promise.resolve({ maxSell: 7000, maxBuy: 5500 }); - }); + ltcClient.isConnected = jest.fn().mockReturnValue(true); components.swapClientManager.swapClients.set('LTC', ltcClient); const bchClient = new mockedSwapClient(); @@ -314,11 +265,6 @@ describe('Service', () => { setup(); await expect(service.tradingLimits({ currency: 'A' })).rejects.toMatchSnapshot(); }); - - test('throws when swap client is not found', async () => { - setup(); - await expect(service.tradingLimits({ currency: 'BBB' })).rejects.toMatchSnapshot(); - }); }); describe('listOrders', () => { diff --git a/test/jest/SwapClientManager.spec.ts b/test/jest/SwapClientManager.spec.ts index d2fe9be39..d1c33d9c1 100644 --- a/test/jest/SwapClientManager.spec.ts +++ b/test/jest/SwapClientManager.spec.ts @@ -2,6 +2,7 @@ import Config from '../../lib/Config'; import { SwapClientType } from '../../lib/constants/enums'; import DB from '../../lib/db/DB'; import Logger from '../../lib/Logger'; +import SwapClient from '../../lib/swaps/SwapClient'; import SwapClientManager from '../../lib/swaps/SwapClientManager'; import { UnitConverter } from '../../lib/utils/UnitConverter'; @@ -48,6 +49,8 @@ jest.mock('../../lib/lndclient/LndClient', () => { }); }); const tokenAddresses = new Map(); +jest.mock('../../lib/swaps/SwapClient'); +const mockedSwapClient = >SwapClient; const logger = new Logger({}); logger.error = jest.fn(); @@ -275,4 +278,50 @@ describe('Swaps.SwapClientManager', () => { ); }); }); + + describe('tradingLimits', () => { + const setup = () => { + const btcClient = new mockedSwapClient(); + btcClient.isConnected = jest.fn().mockImplementation(() => true); + btcClient.swapCapacities = jest.fn().mockImplementation(() => { + return Promise.resolve({ + maxOutboundChannelCapacity: 2000, + maxInboundChannelCapacity: 1500, + totalOutboundCapacity: 2000, + totalInboundCapacity: 1500, + }); + }); + swapClientManager.swapClients.set('BTC', btcClient); + + const ltcClient = new mockedSwapClient(); + ltcClient.isConnected = jest.fn().mockImplementation(() => true); + ltcClient.swapCapacities = jest.fn().mockImplementation(() => { + return Promise.resolve({ + maxOutboundChannelCapacity: 7000, + maxInboundChannelCapacity: 5500, + totalOutboundCapacity: 7000, + totalInboundCapacity: 5500, + }); + }); + swapClientManager.swapClients.set('LTC', ltcClient); + + const bchClient = new mockedSwapClient(); + bchClient.isConnected = jest.fn().mockImplementation(() => false); + swapClientManager.swapClients.set('BCH', bchClient); + }; + + test('returns trading limits', async () => { + setup(); + const btcTradingLimits = await swapClientManager.tradingLimits('BTC'); + + expect(btcTradingLimits).toBeTruthy(); + expect(btcTradingLimits.maxSell).toEqual(2000); + expect(btcTradingLimits.maxBuy).toEqual(1500); + }); + + test('throws when swap client is not found', async () => { + setup(); + await expect(swapClientManager.tradingLimits('BBB')).rejects.toMatchSnapshot(); + }); + }); }); diff --git a/test/jest/__snapshots__/Service.spec.ts.snap b/test/jest/__snapshots__/Service.spec.ts.snap index a6bf5f49c..2d0f4cc79 100644 --- a/test/jest/__snapshots__/Service.spec.ts.snap +++ b/test/jest/__snapshots__/Service.spec.ts.snap @@ -27,10 +27,3 @@ Object { "message": "currency must consist of 2 to 5 upper case English letters or numbers", } `; - -exports[`Service tradingLimits throws when swap client is not found 1`] = ` -Object { - "code": "7.1", - "message": "swapClient for currency BBB not found", -} -`; diff --git a/test/jest/__snapshots__/SwapClientManager.spec.ts.snap b/test/jest/__snapshots__/SwapClientManager.spec.ts.snap index 4ec2a09a6..3b0f8aa61 100644 --- a/test/jest/__snapshots__/SwapClientManager.spec.ts.snap +++ b/test/jest/__snapshots__/SwapClientManager.spec.ts.snap @@ -6,3 +6,10 @@ Object { "message": "swapClient for currency BTC not found", } `; + +exports[`Swaps.SwapClientManager tradingLimits throws when swap client is not found 1`] = ` +Object { + "code": "7.1", + "message": "swapClient for currency BBB not found", +} +`; diff --git a/test/jest/cli/__snapshots__/getbalance.spec.ts.snap b/test/jest/cli/__snapshots__/getbalance.spec.ts.snap index 6174ea995..3aa085827 100644 --- a/test/jest/cli/__snapshots__/getbalance.spec.ts.snap +++ b/test/jest/cli/__snapshots__/getbalance.spec.ts.snap @@ -7,27 +7,11 @@ Array [ Balance:", ], Array [ - "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┬───────────┐ -│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ -├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.001 │ 0.004 │ 0 │ -└──────────┴───────────────┴───────────────────────────────┴────────────────────────────┴───────────┘", - ], -] -`; - -exports[`displayBalances should print a table with balance reserved for orders 1`] = ` -Array [ - Array [ - " -Balance:", - ], - Array [ - "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┬───────────┐ -│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ -├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.001 │ 0.004 │ 0.0008 │ -└──────────┴───────────────┴───────────────────────────────┴────────────────────────────┴───────────┘", + "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ +├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┤ +│ BTC │ 0.005 │ 0.001 │ 0.004 │ +└──────────┴───────────────┴───────────────────────────────┴────────────────────────────┘", ], ] `; @@ -39,11 +23,11 @@ Array [ Balance:", ], Array [ - "┌──────────┬───────────────┬───────────────────────────────┬──────────────────────────────────────────┬───────────┐ -│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ -├──────────┼───────────────┼───────────────────────────────┼──────────────────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.001 (0.00025 pending) │ 0.004 (0.00075 pending | 0.001 inactive) │ 0 │ -└──────────┴───────────────┴───────────────────────────────┴──────────────────────────────────────────┴───────────┘", + "┌──────────┬───────────────┬───────────────────────────────┬──────────────────────────────────────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ +├──────────┼───────────────┼───────────────────────────────┼──────────────────────────────────────────┤ +│ BTC │ 0.005 │ 0.001 (0.00025 pending) │ 0.004 (0.00075 pending | 0.001 inactive) │ +└──────────┴───────────────┴───────────────────────────────┴──────────────────────────────────────────┘", ], ] `; @@ -55,27 +39,11 @@ Array [ Balance:", ], Array [ - "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┬───────────┐ -│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ -├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.001 (0.00025 pending) │ 0.004 (0.00075 pending) │ 0 │ -└──────────┴───────────────┴───────────────────────────────┴────────────────────────────┴───────────┘", - ], -] -`; - -exports[`displayBalances should print a table with pending, inactive, and reserved balances 1`] = ` -Array [ - Array [ - " -Balance:", - ], - Array [ - "┌──────────┬───────────────┬───────────────────────────────┬──────────────────────────────────────────┬───────────┐ -│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ In Orders │ -├──────────┼───────────────┼───────────────────────────────┼──────────────────────────────────────────┼───────────┤ -│ BTC │ 0.005 │ 0.001 (0.00025 pending) │ 0.004 (0.00075 pending | 0.001 inactive) │ 0.0008 │ -└──────────┴───────────────┴───────────────────────────────┴──────────────────────────────────────────┴───────────┘", + "┌──────────┬───────────────┬───────────────────────────────┬────────────────────────────┐ +│ Currency │ Total Balance │ Wallet Balance (Not Tradable) │ Channel Balance (Tradable) │ +├──────────┼───────────────┼───────────────────────────────┼────────────────────────────┤ +│ BTC │ 0.005 │ 0.001 (0.00025 pending) │ 0.004 (0.00075 pending) │ +└──────────┴───────────────┴───────────────────────────────┴────────────────────────────┘", ], ] `; diff --git a/test/jest/cli/__snapshots__/tradinglimits.spec.ts.snap b/test/jest/cli/__snapshots__/tradinglimits.spec.ts.snap new file mode 100644 index 000000000..2fd40cfe4 --- /dev/null +++ b/test/jest/cli/__snapshots__/tradinglimits.spec.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`displayLimits should print a table 1`] = ` +Array [ + Array [ + " +Trading Limits:", + ], + Array [ + "┌──────────┬────────────┬───────────┬───────────────────┬──────────────────┐ +│ Currency │ Max Buy │ Max Sell │ Reserved Outbound │ Reserved Inbound │ +├──────────┼────────────┼───────────┼───────────────────┼──────────────────┤ +│ BTC │ 0.00012345 │ 0.0006789 │ 0.00075 │ 0.00025 │ +└──────────┴────────────┴───────────┴───────────────────┴──────────────────┘", + ], +] +`; diff --git a/test/jest/cli/getbalance.spec.ts b/test/jest/cli/getbalance.spec.ts index 647f7509c..24e5838b9 100644 --- a/test/jest/cli/getbalance.spec.ts +++ b/test/jest/cli/getbalance.spec.ts @@ -25,7 +25,6 @@ describe('displayBalances', () => { inactiveChannelBalance: 0, walletBalance: 100000, unconfirmedWalletBalance: 0, - reservedBalance: 0, }]], }); @@ -41,7 +40,6 @@ describe('displayBalances', () => { inactiveChannelBalance: 0, walletBalance: 100000, unconfirmedWalletBalance: 25000, - reservedBalance: 0, }]], }); expect(mockLog.mock.calls).toMatchSnapshot(); @@ -56,41 +54,9 @@ describe('displayBalances', () => { inactiveChannelBalance: 100000, walletBalance: 100000, unconfirmedWalletBalance: 25000, - reservedBalance: 0, }]], }); expect(mockLog.mock.calls).toMatchSnapshot(); }); - - it('should print a table with balance reserved for orders', () => { - displayBalances({ - balancesMap: [['BTC', { - totalBalance: 500000, - channelBalance: 400000, - pendingChannelBalance: 0, - inactiveChannelBalance: 0, - walletBalance: 100000, - unconfirmedWalletBalance: 0, - reservedBalance: 80000, - }]], - }); - expect(mockLog.mock.calls).toMatchSnapshot(); - }); - - it('should print a table with pending, inactive, and reserved balances', () => { - displayBalances({ - balancesMap: [['BTC', { - totalBalance: 500000, - channelBalance: 400000, - pendingChannelBalance: 75000, - inactiveChannelBalance: 100000, - walletBalance: 100000, - unconfirmedWalletBalance: 25000, - reservedBalance: 80000, - }]], - }); - expect(mockLog.mock.calls).toMatchSnapshot(); - }); - }); diff --git a/test/jest/cli/tradinglimits.spec.ts b/test/jest/cli/tradinglimits.spec.ts new file mode 100644 index 000000000..daf66d823 --- /dev/null +++ b/test/jest/cli/tradinglimits.spec.ts @@ -0,0 +1,31 @@ +import { displayLimits } from '../../../lib/cli/commands/tradinglimits'; + +jest.mock('colors/safe', () => { + return { + blue: (str: string) => str, + underline: (str: string) => str, + bold: (str: string) => str, + }; +}); + +describe('displayLimits', () => { + const mockLog = jest.fn(); + console.log = mockLog; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should print a table', () => { + displayLimits({ + limitsMap: [['BTC', { + maxBuy: 12345, + maxSell: 67890, + reservedInbound: 25000, + reservedOutbound: 75000, + }]], + }); + + expect(mockLog.mock.calls).toMatchSnapshot(); + }); +}); diff --git a/test/simulation/tests-integration.go b/test/simulation/tests-integration.go index 1414ef6eb..1f1a97b51 100644 --- a/test/simulation/tests-integration.go +++ b/test/simulation/tests-integration.go @@ -203,14 +203,12 @@ func testOrderBroadcastAndInvalidation(net *xudtest.NetworkHarness, ht *harnessT } order := ht.act.placeOrderAndBroadcast(net.Alice, net.Bob, req) - resBal, err := net.Alice.Client.GetBalance(ht.ctx, &xudrpc.GetBalanceRequest{Currency: "BTC"}) + _, err := net.Alice.Client.GetBalance(ht.ctx, &xudrpc.GetBalanceRequest{Currency: "BTC"}) ht.assert.NoError(err) - ht.assert.Equal(20000, int(resBal.Balances["BTC"].ReservedBalance)) ht.act.removeOrderAndInvalidate(net.Alice, net.Bob, order) - resBal, err = net.Alice.Client.GetBalance(ht.ctx, &xudrpc.GetBalanceRequest{Currency: "BTC"}) + _, err = net.Alice.Client.GetBalance(ht.ctx, &xudrpc.GetBalanceRequest{Currency: "BTC"}) ht.assert.NoError(err) - ht.assert.Equal(0, int(resBal.Balances["BTC"].ReservedBalance)) // Cleanup. ht.act.disconnect(net.Alice, net.Bob) diff --git a/test/simulation/xudrpc/xudrpc.pb.go b/test/simulation/xudrpc/xudrpc.pb.go index 3f484b720..4fe981742 100644 --- a/test/simulation/xudrpc/xudrpc.pb.go +++ b/test/simulation/xudrpc/xudrpc.pb.go @@ -255,12 +255,10 @@ type Balance struct { // Confirmed wallet balance in satoshis. WalletBalance uint64 `protobuf:"varint,5,opt,name=wallet_balance,proto3" json:"wallet_balance,omitempty"` // Unconfirmed wallet balance in satoshis. - UnconfirmedWalletBalance uint64 `protobuf:"varint,6,opt,name=unconfirmed_wallet_balance,proto3" json:"unconfirmed_wallet_balance,omitempty"` - // The balance that's reserved for open orders. - ReservedBalance uint64 `protobuf:"varint,7,opt,name=reserved_balance,proto3" json:"reserved_balance,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + UnconfirmedWalletBalance uint64 `protobuf:"varint,6,opt,name=unconfirmed_wallet_balance,proto3" json:"unconfirmed_wallet_balance,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Balance) Reset() { *m = Balance{} } @@ -330,13 +328,6 @@ func (m *Balance) GetUnconfirmedWalletBalance() uint64 { return 0 } -func (m *Balance) GetReservedBalance() uint64 { - if m != nil { - return m.ReservedBalance - } - return 0 -} - type BanRequest struct { // The node pub key or alias of the node to ban. NodeIdentifier string `protobuf:"bytes,1,opt,name=node_identifier,proto3" json:"node_identifier,omitempty"` @@ -3914,10 +3905,14 @@ func (m *TradeHistoryResponse) GetTrades() []*Trade { } type TradingLimits struct { - // Max outbound capacity for a distinct channel denominated in satoshis. - MaxSell uint64 `protobuf:"varint,1,opt,name=MaxSell,json=max_sell,proto3" json:"MaxSell,omitempty"` - // Max inbound capacity for a distinct channel denominated in satoshis. - MaxBuy uint64 `protobuf:"varint,2,opt,name=MaxBuy,json=max_buy,proto3" json:"MaxBuy,omitempty"` + // Maximum outbound limit for an order denominated in satoshis. + MaxSell uint64 `protobuf:"varint,1,opt,name=max_sell,proto3" json:"max_sell,omitempty"` + // Maximum inbound limit for an order denominated in satoshis. + MaxBuy uint64 `protobuf:"varint,2,opt,name=max_buy,proto3" json:"max_buy,omitempty"` + // The outbound amount reserved for open orders. + ReservedOutbound uint64 `protobuf:"varint,3,opt,name=reserved_outbound,proto3" json:"reserved_outbound,omitempty"` + // The inbound amount reserved for open orders. + ReservedInbound uint64 `protobuf:"varint,4,opt,name=reserved_inbound,json=reserved_outbound,proto3" json:"reserved_inbound,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -3962,6 +3957,20 @@ func (m *TradingLimits) GetMaxBuy() uint64 { return 0 } +func (m *TradingLimits) GetReservedOutbound() uint64 { + if m != nil { + return m.ReservedOutbound + } + return 0 +} + +func (m *TradingLimits) GetReservedInbound() uint64 { + if m != nil { + return m.ReservedInbound + } + return 0 +} + type TradingLimitsRequest struct { // The ticker symbol of the currency to query for, if unspecified then trading limits for all supported // currencies are queried. @@ -4422,247 +4431,248 @@ func init() { func init() { proto.RegisterFile("xudrpc.proto", fileDescriptor_6960a02cc0a63cf6) } var fileDescriptor_6960a02cc0a63cf6 = []byte{ - // 3835 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3a, 0x4b, 0x8f, 0x1d, 0xc7, - 0x5a, 0xd3, 0xe7, 0xcc, 0x99, 0x73, 0xe6, 0x3b, 0xcf, 0xa9, 0x79, 0x78, 0x7c, 0xe2, 0x24, 0xbe, - 0x45, 0x1c, 0x39, 0x4e, 0x62, 0x9b, 0x09, 0x21, 0x37, 0x06, 0x47, 0xf1, 0x8c, 0x87, 0xd8, 0xc9, - 0xc4, 0xb6, 0x7a, 0x9c, 0x6b, 0x73, 0x05, 0x69, 0xf5, 0xe9, 0x2e, 0x7b, 0x1a, 0xf7, 0x54, 0x9f, - 0xf4, 0x63, 0x1e, 0xb0, 0x41, 0x57, 0xac, 0x60, 0x89, 0x58, 0xc3, 0x0a, 0x21, 0x81, 0xd8, 0xb3, - 0x40, 0x62, 0xcd, 0x96, 0x05, 0x12, 0xb0, 0x41, 0xf0, 0x0b, 0x10, 0x5b, 0x24, 0x54, 0xaf, 0xae, - 0xaa, 0xee, 0x3e, 0x73, 0xed, 0x2b, 0xb8, 0xbb, 0xae, 0xaf, 0xbe, 0xfa, 0xaa, 0xbe, 0x47, 0x7d, - 0xf5, 0x3d, 0x1a, 0x06, 0x67, 0x45, 0x98, 0xce, 0x83, 0x9b, 0xf3, 0x34, 0xc9, 0x13, 0xb4, 0x22, - 0x46, 0xd3, 0x35, 0x9f, 0xd2, 0x24, 0xf7, 0xf3, 0x28, 0xa1, 0x99, 0x98, 0xc2, 0x9b, 0xb0, 0x7e, - 0x2f, 0x0c, 0xf7, 0x8a, 0x34, 0x25, 0x34, 0x38, 0x77, 0x49, 0x36, 0x4f, 0x68, 0x46, 0xf0, 0xf7, - 0x30, 0xba, 0x17, 0x86, 0x4f, 0xfc, 0x28, 0x75, 0xc9, 0x0f, 0x05, 0xc9, 0x72, 0xf4, 0x1e, 0x0c, - 0x67, 0x7e, 0x46, 0xbc, 0x40, 0xa2, 0x6e, 0x3b, 0x57, 0x9d, 0xeb, 0xab, 0xae, 0x0d, 0x44, 0xef, - 0xc3, 0xe8, 0x87, 0x22, 0xc9, 0x0d, 0xb4, 0x16, 0x47, 0xab, 0x40, 0xf1, 0x1a, 0x8c, 0x4b, 0xfa, - 0x72, 0xcb, 0xff, 0x68, 0x41, 0x77, 0xd7, 0x8f, 0x7d, 0x1a, 0x10, 0xb6, 0x59, 0x9e, 0xe4, 0x7e, - 0xec, 0xcd, 0x04, 0x80, 0x6f, 0xb6, 0xec, 0xda, 0x40, 0x74, 0x1d, 0xc6, 0xc1, 0x91, 0x4f, 0x29, - 0xd1, 0x78, 0x2d, 0x8e, 0x57, 0x05, 0xa3, 0x1f, 0xc3, 0xa5, 0x39, 0xa1, 0x61, 0x44, 0x5f, 0x7a, - 0xd5, 0x15, 0x6d, 0xbe, 0x62, 0xd1, 0x34, 0xba, 0x03, 0xdb, 0x11, 0xf5, 0x83, 0x3c, 0x3a, 0x21, - 0xb5, 0xa5, 0xcb, 0x7c, 0xe9, 0xc2, 0x79, 0x26, 0x8c, 0x53, 0x3f, 0x8e, 0x49, 0x5e, 0xae, 0xe8, - 0xf0, 0x15, 0x15, 0x28, 0xfa, 0x02, 0xa6, 0x05, 0x0d, 0x12, 0xfa, 0x22, 0x4a, 0x8f, 0x49, 0xe8, - 0x55, 0xd6, 0xac, 0xf0, 0x35, 0x17, 0x60, 0xa0, 0x1b, 0x30, 0x49, 0x49, 0x46, 0xd2, 0x13, 0x12, - 0x96, 0xab, 0xba, 0x7c, 0x55, 0x0d, 0x8e, 0x7f, 0x1d, 0x60, 0xd7, 0xa7, 0x4a, 0xa9, 0xd7, 0x61, - 0x4c, 0x93, 0x90, 0x78, 0x51, 0x48, 0x68, 0x1e, 0xbd, 0x88, 0x48, 0x2a, 0xd5, 0x5a, 0x05, 0xe3, - 0x21, 0xf4, 0xf9, 0x3a, 0xa9, 0xac, 0xcf, 0xa0, 0xb3, 0x77, 0xe4, 0x47, 0x14, 0x6d, 0x40, 0x27, - 0x60, 0x1f, 0x72, 0x9d, 0x18, 0xa0, 0x6d, 0xe8, 0x52, 0x92, 0x9f, 0x26, 0xe9, 0x2b, 0xa9, 0x7f, - 0x35, 0xc4, 0x73, 0xe8, 0xed, 0x09, 0x31, 0x65, 0x68, 0x0b, 0x56, 0x84, 0xe4, 0xf8, 0xe2, 0xa1, - 0x2b, 0x47, 0x68, 0x0a, 0x3d, 0x25, 0x53, 0xbe, 0x7c, 0xe8, 0x96, 0x63, 0x46, 0x59, 0xaa, 0x8a, - 0x6b, 0x6e, 0xe8, 0xaa, 0x21, 0xa3, 0x16, 0xc4, 0x49, 0x46, 0x42, 0xae, 0x97, 0xa1, 0x2b, 0x47, - 0xf8, 0xef, 0x1d, 0x58, 0xdf, 0x63, 0x9f, 0x72, 0xdf, 0x37, 0xe6, 0x9d, 0x9d, 0xa7, 0x62, 0xce, - 0xe5, 0x98, 0xf1, 0xff, 0x22, 0x49, 0xa5, 0x1d, 0xf5, 0x5c, 0x31, 0x40, 0x57, 0xa1, 0x1f, 0x92, - 0x2c, 0x8f, 0x28, 0xbf, 0x6b, 0xfc, 0x40, 0xab, 0xae, 0x09, 0xe2, 0xbc, 0x1f, 0x27, 0x05, 0xcd, - 0xa5, 0x4d, 0xc8, 0x11, 0x9a, 0x40, 0xfb, 0x05, 0x51, 0x4a, 0x67, 0x9f, 0xf8, 0x4b, 0xd8, 0xb0, - 0x8f, 0x2f, 0x54, 0xc0, 0xce, 0x9f, 0xa7, 0x3e, 0xcd, 0x98, 0x60, 0x12, 0xea, 0x45, 0x61, 0xb6, - 0xed, 0x5c, 0x6d, 0xb3, 0xf3, 0x57, 0xc0, 0xf8, 0x23, 0x18, 0xed, 0x25, 0x94, 0x92, 0x20, 0x57, - 0xbc, 0x4f, 0xa1, 0xc7, 0x99, 0x2c, 0xd2, 0x48, 0x32, 0x5d, 0x8e, 0xd9, 0xd5, 0x2c, 0xb1, 0xa5, - 0xb6, 0x6f, 0xc1, 0xda, 0x5e, 0x4a, 0xfc, 0x9c, 0x3c, 0x4a, 0x42, 0x62, 0xd0, 0x98, 0xfb, 0x59, - 0x76, 0x9a, 0xa4, 0xa1, 0xa2, 0xa1, 0xc6, 0xf8, 0xcf, 0x1c, 0x40, 0xe6, 0x0a, 0x79, 0xe4, 0x5f, - 0x81, 0x61, 0x46, 0x48, 0xe8, 0x1d, 0x53, 0x72, 0x9c, 0xd0, 0x28, 0x90, 0x07, 0x1e, 0x30, 0xe0, - 0xb7, 0x12, 0x86, 0x3e, 0x80, 0x49, 0x44, 0xa3, 0x3c, 0xf2, 0xe3, 0xe8, 0xf7, 0x49, 0xe8, 0xc5, - 0x34, 0xcc, 0xb6, 0x5b, 0x82, 0x31, 0x03, 0x7e, 0x40, 0xc3, 0x0c, 0xdd, 0x82, 0x75, 0x13, 0x35, - 0x60, 0xc7, 0x3e, 0xcb, 0xa5, 0x2a, 0x90, 0x31, 0xb5, 0x27, 0x66, 0xf0, 0x3f, 0x3b, 0xd0, 0x53, - 0xbe, 0xce, 0x52, 0xab, 0x53, 0x51, 0xeb, 0x5d, 0xe8, 0x67, 0xa7, 0xfe, 0xdc, 0x0b, 0xe2, 0x88, - 0xd0, 0x9c, 0x6b, 0x7d, 0xb4, 0xf3, 0xd6, 0x4d, 0xe9, 0x55, 0x15, 0x89, 0x9b, 0x87, 0xa7, 0xfe, - 0x7c, 0x8f, 0xa3, 0xb8, 0x26, 0xbe, 0xf0, 0x5f, 0xaf, 0x08, 0xf5, 0xfc, 0x30, 0x4c, 0x49, 0x96, - 0xf1, 0x23, 0xad, 0xba, 0x36, 0x90, 0xf9, 0x87, 0x90, 0x04, 0xd1, 0xb1, 0x1f, 0x7b, 0xf3, 0xd8, - 0x0f, 0x48, 0x26, 0x2d, 0xb7, 0x02, 0xc5, 0x18, 0x40, 0x6f, 0x84, 0xba, 0xd0, 0x3e, 0x78, 0x74, - 0x7f, 0xb2, 0x84, 0xfa, 0xd0, 0xdd, 0x7b, 0xfc, 0xe8, 0xd1, 0xfe, 0xf3, 0xa7, 0x93, 0x16, 0xd3, - 0xf1, 0x7d, 0x32, 0x4f, 0xb2, 0xc8, 0xd4, 0xf1, 0x22, 0xf6, 0xf0, 0x87, 0x30, 0x2e, 0xb1, 0xa5, - 0x6e, 0xb6, 0xa1, 0xab, 0x0e, 0x2b, 0xb0, 0xd5, 0x90, 0x19, 0xe0, 0xfd, 0x28, 0x0b, 0x92, 0x13, - 0x92, 0x32, 0x6d, 0x66, 0x6f, 0xee, 0x3c, 0x3e, 0x85, 0xcd, 0x0a, 0x05, 0xb9, 0xe9, 0x15, 0x58, - 0xa5, 0xc5, 0xb1, 0xc7, 0xf0, 0x33, 0xe9, 0x04, 0x34, 0x00, 0xff, 0xb1, 0x03, 0x68, 0xff, 0x8c, - 0x04, 0x45, 0x4e, 0x18, 0xff, 0x06, 0x63, 0x49, 0x1a, 0x92, 0xd4, 0x8b, 0x4a, 0xc3, 0x53, 0x63, - 0xee, 0x1e, 0xfc, 0x88, 0x4f, 0x49, 0xc7, 0x23, 0x87, 0x08, 0xc3, 0x60, 0x4e, 0x48, 0xea, 0xcd, - 0x8b, 0x99, 0xf7, 0x8a, 0x9c, 0x4b, 0x8d, 0x58, 0x30, 0x46, 0xf9, 0x87, 0xc2, 0xa7, 0x79, 0x94, - 0x9f, 0x4b, 0xe7, 0x5e, 0x8e, 0xd9, 0x1d, 0xf8, 0x8a, 0xe4, 0xf2, 0x81, 0x7a, 0x1d, 0x19, 0xff, - 0x95, 0x03, 0xc8, 0x5c, 0x21, 0x59, 0xbe, 0x0f, 0x3d, 0xe9, 0x8b, 0xc5, 0x7d, 0xed, 0xef, 0x5c, - 0x57, 0x66, 0x55, 0xc7, 0xbe, 0x29, 0xc7, 0xd9, 0x3e, 0xcd, 0xd3, 0x73, 0xb7, 0x5c, 0x39, 0x3d, - 0x80, 0xa1, 0x35, 0xc5, 0xfc, 0x06, 0xe3, 0x4a, 0x1c, 0x82, 0x7d, 0xa2, 0x6b, 0xd0, 0x39, 0xf1, - 0xe3, 0x42, 0xb8, 0xd0, 0xfe, 0xce, 0x58, 0xed, 0xa2, 0xb6, 0x10, 0xb3, 0x77, 0x5a, 0x3f, 0x76, - 0xf0, 0x04, 0x46, 0x5f, 0x91, 0xfc, 0x21, 0x7d, 0x91, 0x48, 0xc6, 0xf0, 0xbf, 0xb4, 0x61, 0x5c, - 0x82, 0xb4, 0x85, 0x9c, 0x90, 0x34, 0x63, 0x0e, 0x4d, 0x5a, 0x88, 0x1c, 0x32, 0xd9, 0x72, 0x95, - 0x2b, 0xd9, 0x0a, 0xd1, 0x5b, 0x30, 0x84, 0x60, 0xb9, 0x48, 0x23, 0x76, 0x13, 0xd8, 0x55, 0xe6, - 0xdf, 0x4a, 0xfd, 0x4c, 0x07, 0xca, 0xf6, 0x35, 0xa0, 0x9c, 0xf5, 0xa3, 0x34, 0xe3, 0x5e, 0x52, - 0xcd, 0x32, 0x00, 0xfa, 0x10, 0x56, 0xb8, 0xd6, 0x33, 0xee, 0x2b, 0xfb, 0x3b, 0xeb, 0x8a, 0xbf, - 0xc7, 0x1c, 0xba, 0xc7, 0xbc, 0xa9, 0x2b, 0x51, 0xd0, 0x0e, 0xb4, 0x63, 0x1a, 0x6e, 0x77, 0xb9, - 0xbc, 0xaf, 0x1a, 0xf2, 0x36, 0x19, 0xbc, 0x79, 0x40, 0x43, 0x21, 0x67, 0x86, 0xcc, 0x3c, 0xbb, - 0x1f, 0x47, 0x7e, 0xb6, 0xbd, 0x2a, 0x5e, 0x36, 0x3e, 0x30, 0x5f, 0x36, 0xb0, 0x5e, 0x36, 0x74, - 0x1b, 0xd6, 0x55, 0x10, 0xc1, 0x5d, 0xc1, 0x91, 0x9f, 0x1d, 0x91, 0x6c, 0xbb, 0xcf, 0xf9, 0x6d, - 0x9a, 0x42, 0x1f, 0x43, 0x57, 0xb9, 0xac, 0x81, 0xcd, 0x83, 0xf4, 0x57, 0xfc, 0x74, 0x0a, 0x67, - 0xfa, 0x15, 0xf4, 0xd4, 0x09, 0xdf, 0x40, 0xdd, 0x07, 0x34, 0xe4, 0x64, 0x0c, 0x75, 0x7f, 0xc1, - 0x0d, 0x93, 0xdd, 0x44, 0x43, 0xe5, 0x6f, 0x70, 0x9d, 0x5d, 0x58, 0xb7, 0xd6, 0x97, 0xde, 0x7d, - 0x9c, 0x92, 0x79, 0x21, 0xe2, 0xcb, 0xc3, 0x20, 0x49, 0xc5, 0xbb, 0xbe, 0xe6, 0x82, 0x06, 0xb3, - 0x77, 0x6f, 0xc6, 0xde, 0x31, 0x71, 0x3f, 0x7b, 0xae, 0x1c, 0xe1, 0x4b, 0xb0, 0x79, 0x10, 0x65, - 0xb9, 0xf4, 0xac, 0x51, 0xe9, 0x65, 0xf0, 0xd7, 0xb0, 0x55, 0x9d, 0x90, 0xfb, 0xdd, 0x06, 0x08, - 0x4a, 0xa8, 0xbc, 0x4b, 0x93, 0xaa, 0x8b, 0x76, 0x0d, 0x1c, 0xfc, 0x8f, 0x0e, 0xac, 0x31, 0x62, - 0xc2, 0x44, 0x14, 0xe3, 0x86, 0xcf, 0x70, 0x6c, 0x9f, 0xf1, 0x29, 0x74, 0x92, 0x53, 0x4a, 0x52, - 0xe9, 0xff, 0xdf, 0x2d, 0x65, 0x5a, 0xa5, 0x71, 0xf3, 0x31, 0x43, 0x73, 0x05, 0x36, 0xb3, 0x9c, - 0x38, 0x3a, 0x8e, 0x72, 0x19, 0xa1, 0x88, 0x01, 0x93, 0x6f, 0x44, 0x83, 0xb8, 0x08, 0x89, 0xc7, - 0x4d, 0x49, 0xba, 0xfb, 0x9e, 0x5b, 0x05, 0xe3, 0xf7, 0xa0, 0xc3, 0xe9, 0xa1, 0x1e, 0x2c, 0xef, - 0x3e, 0x7e, 0xfa, 0x60, 0xb2, 0xc4, 0x9c, 0xfe, 0xe3, 0x67, 0x8f, 0x26, 0x0e, 0x03, 0x3d, 0xd9, - 0xdf, 0x77, 0x27, 0x2d, 0xfc, 0xe7, 0x0e, 0x20, 0xf3, 0x20, 0x52, 0x2a, 0x5f, 0x94, 0xf7, 0x42, - 0x48, 0xe4, 0xfd, 0xa6, 0x43, 0x4b, 0x83, 0x17, 0x43, 0x61, 0xf3, 0x72, 0xd5, 0xf4, 0x21, 0xf4, - 0x0d, 0x70, 0x83, 0xa1, 0xbd, 0x67, 0x1b, 0xda, 0xc8, 0xbe, 0x77, 0xa6, 0x9d, 0x21, 0x98, 0xb0, - 0x4d, 0x59, 0x94, 0x5f, 0xaa, 0xf3, 0x03, 0xa1, 0x01, 0x09, 0x93, 0x67, 0xde, 0x80, 0x8e, 0xb8, - 0xe5, 0x22, 0x1e, 0x10, 0x83, 0x72, 0x39, 0xd1, 0x72, 0xc6, 0x9f, 0xc9, 0xe5, 0xc4, 0x64, 0x19, - 0x43, 0x47, 0xb8, 0x10, 0xc1, 0xf1, 0x40, 0x9d, 0x88, 0x61, 0xb9, 0x62, 0x0a, 0xff, 0x9b, 0x03, - 0x5d, 0x79, 0x15, 0x98, 0x0d, 0x66, 0xb9, 0x9f, 0x17, 0xea, 0xa5, 0x93, 0x23, 0xf4, 0x11, 0xf4, - 0x64, 0x08, 0x9f, 0x49, 0xe6, 0xb4, 0x39, 0x49, 0xb8, 0x5b, 0x62, 0xa0, 0x6b, 0xb0, 0xc2, 0x83, - 0x5d, 0xe1, 0xd2, 0xfa, 0x3b, 0x43, 0x03, 0x37, 0xa2, 0xae, 0x9c, 0x64, 0xa1, 0xe0, 0x2c, 0x4e, - 0x82, 0x57, 0x47, 0x24, 0x7a, 0x79, 0x94, 0x4b, 0x2f, 0x67, 0x82, 0x4a, 0xcf, 0xd8, 0x31, 0x3c, - 0xa3, 0xe1, 0x6b, 0x57, 0x6c, 0x5f, 0x5b, 0xba, 0xa5, 0xae, 0xe1, 0x96, 0xf0, 0xd7, 0x30, 0xe2, - 0xf7, 0x51, 0x07, 0xad, 0x55, 0x9f, 0xec, 0x34, 0xf8, 0xe4, 0x92, 0x56, 0xcb, 0xa4, 0xf5, 0x97, - 0x0e, 0xa0, 0xc7, 0x73, 0x42, 0xff, 0x5f, 0xe2, 0x65, 0x1d, 0xf7, 0xb6, 0xad, 0xb8, 0xf7, 0x2a, - 0xf4, 0xe7, 0x45, 0x76, 0xe4, 0xc9, 0x49, 0xf1, 0xfa, 0x9a, 0x20, 0x15, 0x19, 0x77, 0x74, 0x64, - 0x7c, 0x17, 0xd6, 0xad, 0x73, 0x4a, 0x73, 0x78, 0x1f, 0x46, 0x76, 0x04, 0x2c, 0xcf, 0x59, 0x81, - 0xe2, 0x7f, 0x68, 0x41, 0x87, 0x1b, 0x2d, 0xb7, 0xbf, 0x34, 0x92, 0x69, 0xa6, 0xe3, 0x8a, 0x81, - 0x15, 0x0d, 0xb4, 0xec, 0x68, 0xc0, 0xf4, 0x19, 0x6d, 0xdb, 0x67, 0x8c, 0xa0, 0x15, 0x85, 0x32, - 0xe2, 0x6f, 0x45, 0x21, 0xfa, 0xb2, 0x2e, 0xb6, 0x0e, 0xb7, 0xad, 0x2d, 0x65, 0x2f, 0xb6, 0xe2, - 0x1a, 0xc5, 0x19, 0x27, 0x81, 0x1f, 0xb3, 0xcd, 0x84, 0x31, 0x94, 0x63, 0xf4, 0x0e, 0x40, 0xc0, - 0xe3, 0xec, 0xd0, 0xf3, 0x73, 0x99, 0xf4, 0x19, 0x10, 0x74, 0x0d, 0x96, 0xb3, 0x28, 0x24, 0xdb, - 0x3d, 0xee, 0xc0, 0xd6, 0xac, 0xbb, 0x7a, 0x18, 0x85, 0xc4, 0xe5, 0xd3, 0xcc, 0x58, 0xa2, 0xcc, - 0x4b, 0x4e, 0xa9, 0xc7, 0xbd, 0x00, 0x7f, 0xf2, 0x7a, 0xae, 0x05, 0x63, 0x66, 0x7a, 0x94, 0xc4, - 0x21, 0x7f, 0xf6, 0x96, 0x5d, 0xfe, 0x8d, 0xff, 0xc2, 0x81, 0x01, 0xa7, 0xe5, 0x92, 0xe3, 0xe4, - 0xc4, 0x8f, 0x2d, 0x99, 0x39, 0x8b, 0x65, 0x56, 0x89, 0xcd, 0xcc, 0x88, 0xae, 0x5d, 0x89, 0xe8, - 0x4c, 0xee, 0x97, 0x2b, 0xdc, 0x57, 0x8f, 0xdd, 0xa9, 0x1f, 0x1b, 0x1f, 0xc1, 0x8a, 0xf0, 0x4c, - 0xe8, 0x63, 0x80, 0x59, 0x71, 0xee, 0x59, 0xde, 0x71, 0x68, 0x49, 0xc4, 0x35, 0x10, 0xd0, 0x2d, - 0xe8, 0x67, 0x24, 0x8e, 0x15, 0x7e, 0xab, 0x09, 0xdf, 0xc4, 0xc0, 0x9f, 0x28, 0xcf, 0xc9, 0x63, - 0x0f, 0x26, 0x2f, 0xe6, 0x7a, 0x64, 0x58, 0xcb, 0xbf, 0x99, 0x0d, 0x27, 0xa7, 0x54, 0x26, 0xb5, - 0xec, 0x13, 0xff, 0xcc, 0x91, 0xab, 0xbe, 0x9b, 0x87, 0x7e, 0x4e, 0xd8, 0x33, 0x2e, 0x78, 0x71, - 0xb8, 0x91, 0xd8, 0xfb, 0x3d, 0x58, 0x72, 0xc5, 0x2c, 0xfa, 0x4d, 0x18, 0x0a, 0x09, 0xa5, 0x42, - 0xf0, 0xd2, 0x5f, 0x6d, 0xd8, 0xc7, 0x13, 0x73, 0x0f, 0x96, 0x5c, 0x1b, 0x79, 0x77, 0x04, 0x03, - 0x01, 0x28, 0xf8, 0xa6, 0xf8, 0x5f, 0x5b, 0xb0, 0xcc, 0x9c, 0xe5, 0xe2, 0x24, 0xe0, 0xb5, 0x42, - 0xbc, 0x2f, 0x61, 0x10, 0xd3, 0x50, 0x0d, 0x95, 0x5f, 0xbc, 0x62, 0xba, 0x63, 0x16, 0x8e, 0x3c, - 0x29, 0x66, 0xdf, 0x90, 0x73, 0xf9, 0xec, 0x58, 0x2b, 0xd8, 0xfe, 0x11, 0x9d, 0x25, 0x05, 0x0d, - 0xe5, 0xdb, 0xa8, 0x86, 0xfa, 0x89, 0xe8, 0x18, 0x4f, 0x04, 0xf3, 0x1a, 0x67, 0x45, 0xe8, 0xd9, - 0xae, 0xd2, 0x04, 0xa1, 0x8f, 0x60, 0x2d, 0x23, 0x41, 0x42, 0xc3, 0x4c, 0xa4, 0x87, 0x41, 0x4e, - 0x42, 0x7e, 0x4f, 0x86, 0x6e, 0x7d, 0xa2, 0x39, 0xe6, 0x9b, 0xde, 0x85, 0x71, 0xe5, 0xd8, 0x0d, - 0xcf, 0xe2, 0x86, 0xf9, 0x2c, 0xae, 0x9a, 0xcf, 0xe0, 0x1f, 0xb6, 0x60, 0xed, 0x09, 0xcb, 0xe4, - 0xa4, 0x52, 0x84, 0x3b, 0xfd, 0xbf, 0xf4, 0x39, 0xe6, 0xfd, 0x59, 0xae, 0xdc, 0x1f, 0xe5, 0x01, - 0x3a, 0x17, 0x7b, 0x00, 0x5e, 0x43, 0xe2, 0xf9, 0xa6, 0x57, 0x92, 0x12, 0xe2, 0xac, 0xc1, 0x59, - 0xa4, 0x1b, 0x1d, 0x1f, 0x93, 0x30, 0xf2, 0x73, 0x06, 0xf5, 0x02, 0x96, 0x4f, 0xc4, 0x5c, 0xaa, - 0x3d, 0xb7, 0x69, 0x8a, 0x89, 0x00, 0x99, 0x22, 0x90, 0x9e, 0xfa, 0x73, 0x96, 0xea, 0xe7, 0x24, - 0xa5, 0x7e, 0xec, 0x1d, 0xfb, 0x79, 0x70, 0x44, 0x16, 0xdc, 0xcb, 0x1a, 0x1a, 0xfa, 0x0d, 0x18, - 0xf1, 0x50, 0x3a, 0x2b, 0x82, 0x80, 0x64, 0x2c, 0x98, 0x12, 0x17, 0xb4, 0x0c, 0xa1, 0x59, 0xc6, - 0x78, 0x28, 0x26, 0xdd, 0x0a, 0x2a, 0xfa, 0x8c, 0x45, 0xaa, 0xc7, 0x7e, 0x44, 0x59, 0x44, 0x2e, - 0xae, 0x5b, 0xbb, 0xe1, 0xba, 0xb9, 0x55, 0x2c, 0xf4, 0x39, 0x0c, 0x39, 0xa9, 0x17, 0x7e, 0x14, - 0x17, 0x29, 0x8f, 0xe0, 0x6a, 0x9b, 0xfe, 0x96, 0x98, 0x73, 0x6d, 0x4c, 0xfc, 0x5f, 0x0e, 0x8c, - 0xb5, 0x08, 0xf6, 0x4f, 0x58, 0x2a, 0x7f, 0x0d, 0x3a, 0x9c, 0x9f, 0x85, 0x97, 0x9d, 0xcf, 0xa2, - 0xcf, 0x61, 0x60, 0x32, 0x20, 0xef, 0x7a, 0x13, 0xa7, 0x0f, 0x96, 0x5c, 0x0b, 0x15, 0x7d, 0xfe, - 0x7a, 0x9c, 0x3e, 0x58, 0x6a, 0xe2, 0x75, 0x60, 0x72, 0xc0, 0x0d, 0xab, 0x99, 0xd5, 0x72, 0x57, - 0x89, 0xba, 0xdb, 0x85, 0x0e, 0x61, 0x0c, 0xe2, 0x04, 0xfa, 0x46, 0x2a, 0xb3, 0x30, 0xf0, 0x32, - 0xdc, 0x4e, 0xcb, 0x76, 0x3b, 0x46, 0x1c, 0xb4, 0x5c, 0x8b, 0x83, 0x44, 0xe1, 0xb1, 0x63, 0x14, - 0x1e, 0xf1, 0x27, 0xb0, 0xc9, 0xbd, 0x1e, 0xd1, 0x15, 0xed, 0x9f, 0x9f, 0xa9, 0x6f, 0xc3, 0x56, - 0x75, 0x91, 0x2c, 0x7c, 0x1d, 0x00, 0x12, 0x33, 0xd6, 0xd5, 0xbd, 0xa8, 0x00, 0x71, 0xc1, 0x05, - 0xc6, 0x9f, 0xc2, 0xba, 0x45, 0x4d, 0xde, 0x82, 0x77, 0x60, 0xa2, 0x50, 0xbc, 0x84, 0x7a, 0xfc, - 0x91, 0x75, 0x8c, 0x47, 0xf6, 0x63, 0x58, 0x13, 0xcb, 0xcc, 0x72, 0xfc, 0xc2, 0xa4, 0x05, 0x6f, - 0xa8, 0x33, 0x5b, 0xd5, 0xf5, 0x3f, 0x6a, 0x31, 0x70, 0x96, 0x27, 0xa9, 0x55, 0xc4, 0x7b, 0xad, - 0x8a, 0x9c, 0x59, 0xe9, 0x6b, 0xd9, 0x95, 0x3e, 0xf4, 0x0d, 0xf4, 0x99, 0x07, 0x9f, 0xf9, 0xc1, - 0xab, 0x62, 0xae, 0x5c, 0xfe, 0x0d, 0x65, 0x24, 0xf5, 0x1d, 0xd9, 0x03, 0xb0, 0x2b, 0x90, 0xc5, - 0x03, 0x00, 0x71, 0x09, 0x40, 0x3f, 0xe2, 0x7d, 0x0b, 0x2f, 0xf4, 0x73, 0x7f, 0xe6, 0x67, 0xa2, - 0x0a, 0x3a, 0xe0, 0xfe, 0xfc, 0xbe, 0x04, 0x49, 0x5f, 0x6c, 0x52, 0xf8, 0x79, 0xbe, 0x78, 0x60, - 0xfa, 0x62, 0xc2, 0x54, 0x60, 0x9c, 0x49, 0x17, 0x26, 0x53, 0x01, 0x96, 0x05, 0x47, 0x29, 0x06, - 0x05, 0xe4, 0xd5, 0xc6, 0x0f, 0x78, 0x99, 0x5d, 0x20, 0xa9, 0xbc, 0x5d, 0x24, 0xb1, 0x63, 0x05, - 0x57, 0x75, 0xc6, 0x35, 0x18, 0x1f, 0x1e, 0x15, 0x79, 0x98, 0x9c, 0xaa, 0x52, 0x3b, 0xcb, 0x66, - 0x34, 0x48, 0x2a, 0xe5, 0xd7, 0x60, 0xeb, 0xb0, 0x98, 0x65, 0x41, 0x1a, 0xcd, 0x88, 0x9d, 0x93, - 0x4e, 0xa1, 0x47, 0xce, 0xa2, 0x2c, 0x8f, 0xe8, 0x4b, 0xce, 0x58, 0xcf, 0x2d, 0xc7, 0xf8, 0x5d, - 0x78, 0xbb, 0x5c, 0xc5, 0x6e, 0x61, 0x76, 0x2f, 0x08, 0xc8, 0x3c, 0x27, 0xa1, 0xda, 0xea, 0x2e, - 0x6c, 0xda, 0x08, 0x46, 0x0f, 0x47, 0xe5, 0x9a, 0xb9, 0xff, 0x4a, 0x06, 0x19, 0x3d, 0xd7, 0x06, - 0xe2, 0xff, 0x69, 0xc1, 0x80, 0x2d, 0x53, 0x64, 0xd1, 0xe5, 0x9a, 0xbd, 0x77, 0xf9, 0xf8, 0xa1, - 0x1d, 0x9d, 0xb5, 0x2a, 0xd1, 0xd9, 0x85, 0xef, 0xd5, 0xa2, 0x3a, 0x9b, 0x7e, 0x17, 0x3b, 0xe6, - 0xbb, 0x58, 0xad, 0xde, 0xad, 0x34, 0x54, 0xef, 0xb6, 0x60, 0x25, 0xe5, 0xa5, 0x15, 0x99, 0x1a, - 0xc9, 0x11, 0x7b, 0xda, 0x44, 0x0a, 0xe1, 0xa5, 0x24, 0x20, 0xd1, 0x09, 0x93, 0x69, 0x4f, 0xb4, - 0x47, 0xaa, 0x70, 0x96, 0x3b, 0x48, 0x58, 0x26, 0xbb, 0x0c, 0xab, 0xa2, 0x65, 0x63, 0x43, 0xd1, - 0x4d, 0x40, 0xca, 0x7d, 0x18, 0x54, 0x45, 0x45, 0xa8, 0x61, 0x86, 0x9d, 0xa1, 0x84, 0x2a, 0xca, - 0x7d, 0xf1, 0xbc, 0x56, 0xe1, 0xf8, 0xaf, 0x1d, 0xe8, 0x1b, 0xde, 0xf5, 0x17, 0xac, 0x77, 0x9a, - 0x32, 0x6e, 0x57, 0x64, 0x5c, 0x95, 0xe6, 0x72, 0x83, 0x34, 0xdf, 0x87, 0x91, 0x74, 0xe7, 0x5e, - 0x4a, 0xfc, 0x2c, 0x51, 0x8e, 0xb6, 0x02, 0xc5, 0x7f, 0xdb, 0x16, 0xa7, 0x95, 0x2f, 0xd0, 0x2f, - 0xd7, 0x58, 0xb4, 0xca, 0x3b, 0x96, 0xca, 0xaf, 0xc3, 0xd8, 0x52, 0x2d, 0x09, 0xa5, 0xc6, 0xab, - 0x60, 0x16, 0x41, 0x6a, 0xd5, 0xe6, 0x52, 0xdb, 0x26, 0xa8, 0x26, 0x2c, 0x68, 0x10, 0xd6, 0x55, - 0x58, 0x4e, 0x93, 0x98, 0x70, 0x95, 0x8e, 0x74, 0x01, 0xc2, 0x4d, 0x62, 0xe2, 0xf2, 0x19, 0x16, - 0x87, 0x56, 0xcc, 0x82, 0x84, 0xbc, 0xea, 0xb7, 0xea, 0xd6, 0x27, 0xd8, 0x45, 0x35, 0xcd, 0x22, - 0xdf, 0x1e, 0x8a, 0xfe, 0x81, 0x05, 0x64, 0xc9, 0x5f, 0xea, 0xcd, 0x53, 0x12, 0x1d, 0xfb, 0x2f, - 0xc9, 0xf6, 0x88, 0xa3, 0x18, 0x10, 0x7d, 0x95, 0xc6, 0xc6, 0x55, 0xc2, 0xff, 0xdd, 0x82, 0xce, - 0xd3, 0xd4, 0x0f, 0x09, 0xcb, 0x70, 0x8e, 0xd9, 0x8d, 0xf7, 0x16, 0x67, 0x1c, 0xae, 0x89, 0xc1, - 0x16, 0xe4, 0xc6, 0x82, 0x56, 0xe3, 0x02, 0x03, 0xc3, 0xd0, 0x4f, 0xdb, 0xd2, 0xcf, 0x45, 0x3a, - 0x35, 0x2c, 0xa1, 0x63, 0x5b, 0x42, 0xc9, 0xcf, 0x8a, 0xe9, 0x1a, 0x94, 0xec, 0xbb, 0x0b, 0x65, - 0x7f, 0x15, 0xfa, 0x44, 0xb4, 0x11, 0x78, 0x96, 0x2c, 0x2c, 0xc1, 0x04, 0x95, 0x41, 0xf2, 0xea, - 0xc5, 0x41, 0xf2, 0x1d, 0x18, 0x04, 0xcc, 0x30, 0x48, 0x3a, 0xf7, 0xd3, 0x5c, 0x98, 0xc2, 0xe2, - 0x44, 0xde, 0xc2, 0xc5, 0x1f, 0xc2, 0x3a, 0x97, 0xfa, 0x83, 0x88, 0x3d, 0x15, 0xe7, 0x46, 0x1a, - 0x20, 0x6a, 0x85, 0x8e, 0x51, 0x2b, 0xc4, 0x77, 0x61, 0xc3, 0x46, 0x96, 0xef, 0xd4, 0x35, 0x58, - 0xc9, 0x19, 0xbc, 0x16, 0x26, 0x73, 0x6c, 0x57, 0x4e, 0xe2, 0x3d, 0x18, 0x32, 0x40, 0x44, 0x5f, - 0x1e, 0x30, 0x72, 0xec, 0x52, 0x76, 0xbf, 0xf5, 0xcf, 0x0e, 0x49, 0x1c, 0xab, 0xac, 0xfc, 0xd8, - 0x3f, 0xf3, 0x58, 0xf2, 0x8a, 0x2e, 0xc1, 0xca, 0xb7, 0xfe, 0xd9, 0x6e, 0xa1, 0xc2, 0x95, 0x2e, - 0x9b, 0x99, 0x15, 0xe7, 0x78, 0x47, 0x9c, 0xa1, 0x24, 0xf2, 0x3a, 0x91, 0xd4, 0xdf, 0x38, 0xb0, - 0x59, 0x59, 0x24, 0x4f, 0x7e, 0x0f, 0x56, 0x38, 0x6b, 0xea, 0xe4, 0x1f, 0x98, 0x27, 0xaf, 0xa1, - 0xdf, 0x14, 0x43, 0x59, 0x99, 0x14, 0x0b, 0xa7, 0x4f, 0xa0, 0x6f, 0x80, 0x1b, 0x9e, 0xfd, 0x0f, - 0xed, 0xca, 0xe4, 0x66, 0xf3, 0x16, 0x46, 0x34, 0xf0, 0x13, 0x18, 0x7c, 0x47, 0x67, 0xbf, 0x40, - 0x3b, 0x1c, 0x5d, 0x81, 0xd5, 0x94, 0xc8, 0xbc, 0x51, 0x06, 0x01, 0x1a, 0x80, 0xc7, 0x30, 0x94, - 0x74, 0x75, 0x03, 0xf5, 0x3b, 0x1a, 0x27, 0xc1, 0xab, 0xd7, 0x6d, 0xa0, 0xfe, 0x14, 0x90, 0xb9, - 0x40, 0x87, 0x29, 0x05, 0x87, 0x56, 0xc2, 0x14, 0x05, 0xe4, 0x61, 0xca, 0xbb, 0xd0, 0x37, 0x51, - 0x44, 0xbf, 0x05, 0x34, 0x02, 0xfe, 0x13, 0x07, 0xc6, 0xcf, 0xa2, 0xfc, 0x28, 0x4c, 0xfd, 0xd3, - 0xd7, 0x50, 0x6a, 0xb5, 0x99, 0xdd, 0xba, 0xa8, 0x99, 0xdd, 0xae, 0x36, 0xb3, 0xfd, 0x38, 0x96, - 0xa9, 0x3c, 0xfb, 0x34, 0x8b, 0x78, 0x43, 0x51, 0xc4, 0xbb, 0x03, 0x13, 0x7d, 0x98, 0x37, 0xab, - 0xe0, 0xdd, 0xb8, 0x0e, 0xab, 0xe5, 0x15, 0x45, 0x5d, 0x68, 0xef, 0x7e, 0xf7, 0xdb, 0x93, 0x25, - 0xd4, 0x83, 0xe5, 0xc3, 0xfd, 0x83, 0x03, 0x51, 0x2c, 0xe7, 0xf5, 0xf3, 0xd6, 0x8d, 0x1b, 0xb0, - 0xcc, 0x1c, 0x02, 0x5a, 0x85, 0xce, 0xd3, 0x7b, 0xdf, 0xec, 0xbb, 0x93, 0x25, 0xf6, 0xf9, 0x2d, - 0xff, 0x74, 0xd0, 0x00, 0x7a, 0x0f, 0x1f, 0x3d, 0xdd, 0x77, 0x1f, 0xdd, 0x3b, 0x98, 0xb4, 0x76, - 0xfe, 0xdd, 0x81, 0xee, 0xf3, 0x22, 0x7c, 0x48, 0xa3, 0x1c, 0xed, 0x03, 0xe8, 0x3e, 0x36, 0xba, - 0x5c, 0x96, 0x78, 0xab, 0xdd, 0xf0, 0xe9, 0xb4, 0x69, 0x4a, 0x6a, 0x7f, 0x09, 0x3d, 0x80, 0xbe, - 0x11, 0x76, 0xa2, 0xe9, 0xe2, 0xf8, 0x78, 0xfa, 0x56, 0xe3, 0x5c, 0x49, 0x69, 0x1f, 0x40, 0x1b, - 0x86, 0x3e, 0x50, 0xcd, 0xba, 0xf4, 0x81, 0xea, 0x76, 0x84, 0x97, 0x76, 0xfe, 0x6e, 0x0b, 0xda, - 0xcf, 0x8b, 0x10, 0x3d, 0x87, 0xbe, 0xf1, 0xfb, 0x0f, 0xaa, 0xb5, 0x4f, 0xf4, 0x71, 0x9a, 0xfe, - 0x12, 0x9a, 0xfe, 0xec, 0x9f, 0xfe, 0xf3, 0x4f, 0x5b, 0x1b, 0x78, 0x7c, 0xeb, 0xe4, 0x57, 0x6f, - 0xf9, 0x61, 0xa8, 0x4c, 0xe6, 0x8e, 0x73, 0x03, 0xb9, 0xd0, 0x95, 0x7f, 0xf8, 0xa0, 0x2d, 0x83, - 0x86, 0x91, 0xc3, 0x4c, 0x2f, 0xd5, 0xe0, 0x92, 0xee, 0x16, 0xa7, 0x3b, 0xc1, 0x7d, 0x49, 0x97, - 0x3d, 0x00, 0x8c, 0xe6, 0x2e, 0xb4, 0x77, 0x7d, 0x8a, 0x90, 0x6e, 0x65, 0xaa, 0xab, 0x3b, 0x5d, - 0xb7, 0x60, 0x92, 0x0e, 0xe2, 0x74, 0x06, 0xb8, 0xcb, 0xe8, 0xcc, 0x7c, 0xca, 0x68, 0x04, 0x30, - 0x30, 0x7f, 0xa7, 0x40, 0xba, 0xa9, 0x5f, 0xff, 0x47, 0x64, 0x7a, 0xa5, 0x79, 0x52, 0x92, 0xdf, - 0xe6, 0xe4, 0x11, 0x9e, 0x30, 0xf2, 0xfc, 0x6f, 0x13, 0xd9, 0x1c, 0x60, 0xcc, 0xcb, 0x7f, 0x28, - 0x34, 0xf3, 0xf6, 0x2f, 0x18, 0x9a, 0xf9, 0xea, 0xcf, 0x16, 0x16, 0xf3, 0xd2, 0xa3, 0xb0, 0x83, - 0x7f, 0x0f, 0xc3, 0x67, 0xfc, 0xbf, 0x1f, 0xd9, 0xb9, 0xd7, 0x94, 0xed, 0xc6, 0xbf, 0xa6, 0x5c, - 0x69, 0xf1, 0xe3, 0x2b, 0x9c, 0xf2, 0x16, 0x5e, 0x63, 0x94, 0xc5, 0x3f, 0x44, 0xa1, 0x40, 0x61, - 0xf4, 0x7f, 0x0f, 0x86, 0x56, 0x93, 0x1e, 0x95, 0xcc, 0x37, 0x75, 0xff, 0xa7, 0x6f, 0x2f, 0x98, - 0x6d, 0xda, 0x2b, 0x94, 0x28, 0xbc, 0xad, 0xcf, 0xf6, 0x7a, 0x0e, 0xa0, 0x9b, 0xdd, 0xda, 0x8a, - 0x6b, 0x0d, 0x76, 0x6d, 0xc5, 0xf5, 0xde, 0x38, 0x5e, 0xe7, 0x5b, 0x0c, 0x51, 0x5f, 0x68, 0x57, - 0xd0, 0x3a, 0x80, 0xae, 0x6c, 0xeb, 0x6a, 0xf9, 0xd8, 0xbd, 0x6d, 0x2d, 0x9f, 0x4a, 0xff, 0x17, - 0x4f, 0x38, 0x41, 0x40, 0x3d, 0x46, 0x30, 0x62, 0x24, 0x7e, 0x07, 0xfa, 0x46, 0xa7, 0x13, 0x99, - 0xa7, 0xa9, 0xb4, 0x4f, 0xf5, 0x45, 0x69, 0x68, 0x8d, 0xe2, 0x0d, 0x4e, 0x79, 0x84, 0x06, 0x8c, - 0x32, 0x93, 0x02, 0xa7, 0xfe, 0x0c, 0x40, 0x37, 0xe5, 0xb4, 0x14, 0x6a, 0xdd, 0x45, 0x2d, 0x85, - 0x7a, 0x0f, 0x4f, 0xd9, 0x38, 0x02, 0x46, 0x5a, 0x96, 0xae, 0x5f, 0xc2, 0xc8, 0xee, 0x99, 0xa2, - 0xb7, 0x4d, 0x0a, 0xb5, 0x26, 0xeb, 0xf4, 0x9d, 0x45, 0xd3, 0xb6, 0x4d, 0xa2, 0x11, 0xb7, 0x49, - 0x4d, 0xf6, 0x10, 0x56, 0xcb, 0x6e, 0x1e, 0xda, 0x36, 0x89, 0x98, 0x4d, 0xbf, 0xe9, 0xe5, 0x86, - 0x19, 0x49, 0x79, 0x8d, 0x53, 0xee, 0xa3, 0x55, 0x46, 0x59, 0x14, 0x75, 0x15, 0x51, 0xfe, 0x13, - 0x80, 0x4d, 0xd4, 0x68, 0x05, 0x56, 0x88, 0x9a, 0x0d, 0xc1, 0x0a, 0x51, 0x4e, 0xc7, 0x83, 0xbe, - 0xd1, 0x2b, 0xd2, 0x9a, 0xac, 0x37, 0xba, 0xb4, 0x26, 0x1b, 0x9a, 0x4b, 0xf8, 0x12, 0x27, 0xbd, - 0x26, 0x5c, 0x5e, 0x32, 0x27, 0x54, 0x5d, 0xf9, 0xdf, 0x05, 0xd0, 0xe5, 0x3d, 0xad, 0xcc, 0x5a, - 0xe1, 0x57, 0x9b, 0x5f, 0xa5, 0x1a, 0x88, 0x2f, 0x73, 0xd2, 0xeb, 0x98, 0x0b, 0x99, 0x97, 0x5c, - 0xb9, 0x3a, 0xef, 0x38, 0x37, 0x6e, 0x3b, 0xe8, 0x05, 0x8c, 0x34, 0xfe, 0xe1, 0x39, 0x0d, 0x2e, - 0xda, 0x62, 0xda, 0x34, 0x25, 0x19, 0x78, 0x9b, 0xef, 0x72, 0x09, 0x23, 0x7b, 0x97, 0xec, 0x9c, - 0x06, 0xec, 0x66, 0xfe, 0x14, 0xfa, 0xc6, 0x2f, 0x37, 0x5a, 0x4e, 0xf5, 0xff, 0x70, 0xa6, 0x4d, - 0x05, 0x48, 0xfb, 0x49, 0x90, 0x21, 0x76, 0x76, 0xea, 0xcf, 0x19, 0x6d, 0x0a, 0x23, 0xbb, 0xce, - 0xa6, 0xcd, 0xb2, 0xb1, 0x68, 0xa7, 0xcd, 0x72, 0x41, 0x79, 0xce, 0xe2, 0x85, 0x37, 0x37, 0x88, - 0xf9, 0x04, 0xcd, 0xd8, 0xab, 0x5b, 0xd6, 0xdb, 0xcc, 0x57, 0xb7, 0x5a, 0xd2, 0x33, 0x5f, 0xdd, - 0x5a, 0x81, 0xce, 0xe6, 0x49, 0x6c, 0xa3, 0x34, 0x83, 0xbe, 0x07, 0xd0, 0xd5, 0x36, 0xad, 0x93, - 0x5a, 0xc1, 0x6e, 0x3a, 0x6d, 0x9a, 0x92, 0x1b, 0x58, 0x9a, 0x17, 0x1b, 0xa8, 0x27, 0xef, 0x27, - 0xd0, 0x53, 0x65, 0x23, 0x54, 0x5a, 0x4e, 0xa5, 0xb6, 0x34, 0xdd, 0xae, 0x4f, 0x54, 0xcc, 0x95, - 0x3b, 0x9e, 0x4c, 0xce, 0x32, 0xba, 0x04, 0xc6, 0x95, 0xd2, 0x13, 0x2a, 0xa5, 0xdd, 0x5c, 0x93, - 0x9a, 0xda, 0x7f, 0xd8, 0x88, 0x7e, 0x15, 0x7e, 0x8b, 0x6f, 0xb0, 0x89, 0xd6, 0xf9, 0x06, 0x6a, - 0xa1, 0x30, 0xa9, 0xdb, 0x0e, 0x9a, 0x57, 0x4a, 0x51, 0xb2, 0xa6, 0x61, 0x38, 0xa4, 0xc6, 0x4a, - 0xd5, 0xb4, 0xa9, 0xcc, 0x8c, 0x7f, 0xc4, 0xf7, 0x7a, 0x0b, 0x5d, 0xb6, 0xf6, 0x62, 0xd6, 0xa5, - 0xaa, 0xec, 0xb7, 0x1d, 0x34, 0x83, 0x91, 0x4d, 0xf2, 0x8d, 0xb6, 0xaa, 0x98, 0x31, 0x42, 0xb5, - 0xad, 0xd8, 0x1e, 0x7f, 0x60, 0xd4, 0xed, 0xac, 0x0a, 0x1c, 0xba, 0xd6, 0xbc, 0x57, 0xa5, 0x42, - 0x37, 0xdd, 0x30, 0xf7, 0x54, 0x93, 0x18, 0xf3, 0x4d, 0xaf, 0xa0, 0x69, 0x7d, 0x53, 0x5f, 0xe2, - 0x70, 0x4f, 0x30, 0x30, 0x73, 0x43, 0x1d, 0xc0, 0x34, 0xa4, 0x97, 0x3a, 0x80, 0x69, 0x4a, 0x27, - 0x95, 0xf2, 0x44, 0x00, 0xc3, 0x73, 0xc7, 0x23, 0x81, 0xc1, 0x2c, 0xe4, 0x65, 0x35, 0x89, 0xbc, - 0xb2, 0x20, 0x65, 0xab, 0xc4, 0x03, 0x8d, 0x09, 0x9d, 0x32, 0x71, 0xb4, 0xa6, 0xb6, 0x8a, 0xe8, - 0x4b, 0x91, 0xd7, 0xa1, 0xaf, 0xa1, 0xc3, 0xb3, 0x25, 0xb4, 0xa1, 0x43, 0x56, 0x9d, 0x94, 0x4d, - 0x37, 0x2b, 0x50, 0xfb, 0x49, 0xc5, 0xdc, 0xc7, 0x17, 0x54, 0x46, 0x77, 0x33, 0x18, 0x89, 0x20, - 0x49, 0xe5, 0x14, 0xfa, 0xd2, 0x54, 0x52, 0x1e, 0x7d, 0x69, 0xaa, 0xe9, 0x87, 0xed, 0x56, 0x44, - 0x9c, 0x74, 0x2a, 0x71, 0xee, 0x38, 0x37, 0x66, 0x2b, 0xfc, 0xcf, 0xf9, 0x4f, 0xfe, 0x37, 0x00, - 0x00, 0xff, 0xff, 0xd8, 0xb0, 0x15, 0x00, 0x64, 0x2f, 0x00, 0x00, + // 3843 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3a, 0x4d, 0x8f, 0x1d, 0xc7, + 0x56, 0xd3, 0xf7, 0xce, 0x9d, 0x7b, 0xe7, 0xdc, 0xcf, 0xa9, 0xf9, 0xf0, 0xf8, 0xc6, 0x49, 0xfc, + 0x8a, 0x38, 0x72, 0xec, 0xc4, 0x36, 0x13, 0x42, 0x5e, 0x0c, 0x8e, 0xe2, 0x19, 0x0f, 0xb1, 0x93, + 0x79, 0xb6, 0xd5, 0xe3, 0xbc, 0x98, 0x27, 0x48, 0xab, 0x6f, 0x77, 0x79, 0xa6, 0x71, 0x4f, 0xf7, + 0x4d, 0x7f, 0xcc, 0x78, 0x60, 0x83, 0x9e, 0x58, 0xc1, 0x12, 0xb1, 0x86, 0x15, 0x42, 0x02, 0xb1, + 0x45, 0x2c, 0x90, 0x58, 0xb3, 0x65, 0x81, 0x04, 0x6c, 0x90, 0xf8, 0x05, 0x88, 0x2d, 0x12, 0x3a, + 0xf5, 0xd1, 0x5d, 0xd5, 0xdd, 0x77, 0x9e, 0x1d, 0xc1, 0xdb, 0x75, 0x9d, 0x3a, 0x75, 0xaa, 0xce, + 0x47, 0x9d, 0x3a, 0x1f, 0x0d, 0x83, 0x57, 0xb9, 0x9f, 0xcc, 0xbd, 0x5b, 0xf3, 0x24, 0xce, 0x62, + 0xb2, 0x22, 0x46, 0xd3, 0x35, 0x37, 0x8a, 0xe2, 0xcc, 0xcd, 0x82, 0x38, 0x4a, 0xc5, 0x14, 0xdd, + 0x84, 0xf5, 0xfb, 0xbe, 0xbf, 0x97, 0x27, 0x09, 0x8b, 0xbc, 0x73, 0x9b, 0xa5, 0xf3, 0x38, 0x4a, + 0x19, 0xfd, 0x0e, 0x46, 0xf7, 0x7d, 0xff, 0xa9, 0x1b, 0x24, 0x36, 0xfb, 0x3e, 0x67, 0x69, 0x46, + 0xde, 0x83, 0xe1, 0xcc, 0x4d, 0x99, 0xe3, 0x49, 0xd4, 0x6d, 0xeb, 0xaa, 0x75, 0x7d, 0xd5, 0x36, + 0x81, 0xe4, 0x7d, 0x18, 0x7d, 0x9f, 0xc7, 0x99, 0x86, 0xd6, 0xe2, 0x68, 0x15, 0x28, 0x5d, 0x83, + 0x71, 0x41, 0x5f, 0x6e, 0xf9, 0x77, 0x2d, 0xe8, 0xee, 0xba, 0xa1, 0x1b, 0x79, 0x0c, 0x37, 0xcb, + 0xe2, 0xcc, 0x0d, 0x9d, 0x99, 0x00, 0xf0, 0xcd, 0x96, 0x6d, 0x13, 0x48, 0xae, 0xc3, 0xd8, 0x3b, + 0x76, 0xa3, 0x88, 0x95, 0x78, 0x2d, 0x8e, 0x57, 0x05, 0x93, 0x1f, 0xc3, 0xa5, 0x39, 0x8b, 0xfc, + 0x20, 0x3a, 0x72, 0xaa, 0x2b, 0xda, 0x7c, 0xc5, 0xa2, 0x69, 0x72, 0x17, 0xb6, 0x83, 0xc8, 0xf5, + 0xb2, 0xe0, 0x94, 0xd5, 0x96, 0x2e, 0xf3, 0xa5, 0x0b, 0xe7, 0x51, 0x18, 0x67, 0x6e, 0x18, 0xb2, + 0xac, 0x58, 0xd1, 0xe1, 0x2b, 0x2a, 0x50, 0xf2, 0x39, 0x4c, 0xf3, 0xc8, 0x8b, 0xa3, 0x17, 0x41, + 0x72, 0xc2, 0x7c, 0xa7, 0xb2, 0x66, 0x85, 0xaf, 0xb9, 0x00, 0x83, 0xfe, 0x3a, 0xc0, 0xae, 0x1b, + 0x29, 0x45, 0x5d, 0x87, 0x71, 0x14, 0xfb, 0xcc, 0x09, 0x7c, 0x16, 0x65, 0xc1, 0x8b, 0x80, 0x25, + 0x52, 0x55, 0x55, 0x30, 0x1d, 0x42, 0x9f, 0xaf, 0x93, 0x0a, 0xf8, 0x14, 0x3a, 0x7b, 0xc7, 0x6e, + 0x10, 0x91, 0x0d, 0xe8, 0x78, 0xf8, 0x21, 0xd7, 0x89, 0x01, 0xd9, 0x86, 0x6e, 0xc4, 0xb2, 0xb3, + 0x38, 0x79, 0x29, 0x75, 0xaa, 0x86, 0x74, 0x0e, 0xbd, 0x3d, 0xc1, 0x7a, 0x4a, 0xb6, 0x60, 0x45, + 0x48, 0x83, 0x2f, 0x1e, 0xda, 0x72, 0x44, 0xa6, 0xd0, 0x53, 0x72, 0xe2, 0xcb, 0x87, 0x76, 0x31, + 0x46, 0xca, 0x52, 0xfc, 0x5c, 0x1b, 0x43, 0x5b, 0x0d, 0x91, 0x9a, 0x17, 0xc6, 0x29, 0xf3, 0xb9, + 0xac, 0x87, 0xb6, 0x1c, 0xd1, 0x7f, 0xb0, 0x60, 0x7d, 0x0f, 0x3f, 0xe5, 0xbe, 0x6f, 0xcc, 0x3b, + 0x9e, 0xa7, 0x62, 0xa2, 0xc5, 0x18, 0xf9, 0x7f, 0x11, 0x27, 0xd2, 0x36, 0x7a, 0xb6, 0x18, 0x90, + 0xab, 0xd0, 0xf7, 0x59, 0x9a, 0x05, 0x11, 0xbf, 0x3f, 0xfc, 0x40, 0xab, 0xb6, 0x0e, 0xe2, 0xbc, + 0x9f, 0xc4, 0x79, 0x94, 0x49, 0x3d, 0xcb, 0x11, 0x99, 0x40, 0xfb, 0x05, 0x53, 0x8a, 0xc4, 0x4f, + 0xfa, 0x05, 0x6c, 0x98, 0xc7, 0x17, 0x2a, 0xc0, 0xf3, 0x67, 0x89, 0x1b, 0xa5, 0x28, 0x98, 0x38, + 0x72, 0x02, 0x3f, 0xdd, 0xb6, 0xae, 0xb6, 0xf1, 0xfc, 0x15, 0x30, 0xfd, 0x10, 0x46, 0x7b, 0x71, + 0x14, 0x31, 0x2f, 0x53, 0xbc, 0x4f, 0xa1, 0xc7, 0x99, 0xcc, 0x93, 0x40, 0x32, 0x5d, 0x8c, 0xf1, + 0xba, 0x15, 0xd8, 0x52, 0xdb, 0xb7, 0x61, 0x6d, 0x2f, 0x61, 0x6e, 0xc6, 0x1e, 0xc7, 0x3e, 0xd3, + 0x68, 0xcc, 0xdd, 0x34, 0x3d, 0x8b, 0x13, 0x5f, 0xd1, 0x50, 0x63, 0xfa, 0x67, 0x16, 0x10, 0x7d, + 0x85, 0x3c, 0xf2, 0xaf, 0xc0, 0x30, 0x65, 0xcc, 0x77, 0x4e, 0x22, 0x76, 0x12, 0x47, 0x81, 0x27, + 0x0f, 0x3c, 0x40, 0xe0, 0x4f, 0x24, 0x8c, 0x7c, 0x00, 0x93, 0x20, 0x0a, 0xb2, 0xc0, 0x0d, 0x83, + 0xdf, 0x67, 0xbe, 0x13, 0x46, 0x7e, 0xba, 0xdd, 0x12, 0x8c, 0x69, 0xf0, 0x83, 0xc8, 0x4f, 0xc9, + 0x6d, 0x58, 0xd7, 0x51, 0x3d, 0x3c, 0xf6, 0xab, 0x4c, 0xaa, 0x82, 0x68, 0x53, 0x7b, 0x62, 0x86, + 0xfe, 0x8b, 0x05, 0x3d, 0xe5, 0xbf, 0x0c, 0xb5, 0x5a, 0x15, 0xb5, 0xde, 0x83, 0x7e, 0x7a, 0xe6, + 0xce, 0x1d, 0x2f, 0x0c, 0x58, 0x94, 0x71, 0xad, 0x8f, 0x76, 0xde, 0xba, 0x25, 0x3d, 0xa5, 0x22, + 0x71, 0xeb, 0xf0, 0xcc, 0x9d, 0xef, 0x71, 0x14, 0x5b, 0xc7, 0x17, 0x3e, 0xe9, 0x25, 0x8b, 0x1c, + 0xd7, 0xf7, 0x13, 0x96, 0xa6, 0xfc, 0x48, 0xab, 0xb6, 0x09, 0xc4, 0x3b, 0xef, 0x33, 0x2f, 0x38, + 0x71, 0x43, 0x67, 0x1e, 0xba, 0x1e, 0x4b, 0xa5, 0xe5, 0x56, 0xa0, 0x94, 0x02, 0x94, 0x1b, 0x91, + 0x2e, 0xb4, 0x0f, 0x1e, 0x3f, 0x98, 0x2c, 0x91, 0x3e, 0x74, 0xf7, 0x9e, 0x3c, 0x7e, 0xbc, 0xff, + 0xfc, 0xd9, 0xa4, 0x85, 0x3a, 0x7e, 0xc0, 0xe6, 0x71, 0x1a, 0xe8, 0x3a, 0x5e, 0xc4, 0x1e, 0xbd, + 0x09, 0xe3, 0x02, 0x5b, 0xea, 0x66, 0x1b, 0xba, 0xea, 0xb0, 0x02, 0x5b, 0x0d, 0xd1, 0x00, 0x1f, + 0x04, 0xa9, 0x17, 0x9f, 0xb2, 0x04, 0xb5, 0x99, 0xbe, 0xb9, 0xf3, 0xf8, 0x04, 0x36, 0x2b, 0x14, + 0xe4, 0xa6, 0x57, 0x60, 0x35, 0xca, 0x4f, 0x1c, 0xc4, 0x4f, 0xa5, 0x13, 0x28, 0x01, 0xf4, 0x8f, + 0x2d, 0x20, 0xfb, 0xaf, 0x98, 0x97, 0x67, 0x0c, 0xf9, 0xd7, 0x18, 0x8b, 0x13, 0x9f, 0x25, 0x4e, + 0x50, 0x18, 0x9e, 0x1a, 0x73, 0xf7, 0xe0, 0x06, 0x7c, 0x4a, 0x3a, 0x1e, 0x39, 0x24, 0x14, 0x06, + 0x73, 0xc6, 0x12, 0x67, 0x9e, 0xcf, 0x9c, 0x97, 0xec, 0x5c, 0x6a, 0xc4, 0x80, 0x21, 0xe5, 0xef, + 0x73, 0x37, 0xca, 0x82, 0xec, 0x5c, 0x3a, 0xec, 0x62, 0x8c, 0x77, 0xe0, 0x4b, 0x96, 0xc9, 0x47, + 0xe7, 0x75, 0x64, 0xfc, 0x57, 0x16, 0x10, 0x7d, 0x85, 0x64, 0xf9, 0x01, 0xf4, 0xa4, 0x2f, 0x16, + 0xf7, 0xb5, 0xbf, 0x73, 0x5d, 0x99, 0x55, 0x1d, 0xfb, 0x96, 0x1c, 0xa7, 0xfb, 0x51, 0x96, 0x9c, + 0xdb, 0xc5, 0xca, 0xe9, 0x01, 0x0c, 0x8d, 0x29, 0xf4, 0x1b, 0xc8, 0x95, 0x38, 0x04, 0x7e, 0x92, + 0x6b, 0xd0, 0x39, 0x75, 0xc3, 0x5c, 0xb8, 0xd0, 0xfe, 0xce, 0x58, 0xed, 0xa2, 0xb6, 0x10, 0xb3, + 0x77, 0x5b, 0x3f, 0xb6, 0xe8, 0x04, 0x46, 0x5f, 0xb2, 0xec, 0x51, 0xf4, 0x22, 0x96, 0x8c, 0xd1, + 0x7f, 0x6d, 0xc3, 0xb8, 0x00, 0x95, 0x16, 0x72, 0xca, 0x92, 0x14, 0x1d, 0x9a, 0xb4, 0x10, 0x39, + 0x44, 0xd9, 0x72, 0x95, 0x2b, 0xd9, 0x0a, 0xd1, 0x1b, 0x30, 0x42, 0x60, 0x39, 0x4f, 0x02, 0xbc, + 0x09, 0x78, 0x95, 0xf9, 0xb7, 0x52, 0x3f, 0xea, 0x40, 0xd9, 0x7e, 0x09, 0x28, 0x66, 0xdd, 0x20, + 0x49, 0xb9, 0x97, 0x54, 0xb3, 0x08, 0x20, 0x37, 0x61, 0x85, 0x6b, 0x3d, 0xe5, 0xbe, 0xb2, 0xbf, + 0xb3, 0xae, 0xf8, 0x7b, 0xc2, 0xa1, 0x7b, 0xe8, 0x4d, 0x6d, 0x89, 0x42, 0x76, 0xa0, 0x1d, 0x46, + 0xfe, 0x76, 0x97, 0xcb, 0xfb, 0xaa, 0x26, 0x6f, 0x9d, 0xc1, 0x5b, 0x07, 0x91, 0x2f, 0xe4, 0x8c, + 0xc8, 0xe8, 0xd9, 0xdd, 0x30, 0x70, 0xd3, 0xed, 0x55, 0xf1, 0xb2, 0xf1, 0x81, 0xfe, 0xb2, 0x81, + 0xf1, 0xb2, 0x91, 0x3b, 0xb0, 0xae, 0x02, 0x03, 0xee, 0x0a, 0x8e, 0xdd, 0xf4, 0x98, 0xa5, 0xdb, + 0x7d, 0xce, 0x6f, 0xd3, 0x14, 0xf9, 0x08, 0xba, 0xca, 0x65, 0x0d, 0x4c, 0x1e, 0xa4, 0xbf, 0xe2, + 0xa7, 0x53, 0x38, 0xd3, 0x2f, 0xa1, 0xa7, 0x4e, 0xf8, 0x06, 0xea, 0x3e, 0x88, 0x7c, 0x4e, 0x46, + 0x53, 0xf7, 0xe7, 0xdc, 0x30, 0xf1, 0x26, 0x6a, 0x2a, 0x7f, 0x83, 0xeb, 0x6c, 0xc3, 0xba, 0xb1, + 0xbe, 0xf0, 0xee, 0xe3, 0x84, 0xcd, 0x73, 0x11, 0x33, 0x1e, 0x7a, 0x71, 0x22, 0xde, 0xf5, 0x35, + 0x1b, 0x4a, 0x30, 0xbe, 0x7b, 0x33, 0x7c, 0xc7, 0xc4, 0xfd, 0xec, 0xd9, 0x72, 0x44, 0x2f, 0xc1, + 0xe6, 0x41, 0x90, 0x66, 0xd2, 0xb3, 0x06, 0x85, 0x97, 0xa1, 0x5f, 0xc1, 0x56, 0x75, 0x42, 0xee, + 0x77, 0x07, 0xc0, 0x2b, 0xa0, 0xf2, 0x2e, 0x4d, 0xaa, 0x2e, 0xda, 0xd6, 0x70, 0xe8, 0x3f, 0x59, + 0xb0, 0x86, 0xc4, 0x84, 0x89, 0x28, 0xc6, 0x35, 0x9f, 0x61, 0x99, 0x3e, 0xe3, 0x13, 0xe8, 0xc4, + 0x67, 0x11, 0x4b, 0xa4, 0xff, 0x7f, 0xb7, 0x90, 0x69, 0x95, 0xc6, 0xad, 0x27, 0x88, 0x66, 0x0b, + 0x6c, 0xb4, 0x9c, 0x30, 0x38, 0x09, 0x32, 0x19, 0xa1, 0x88, 0x01, 0xca, 0x37, 0x88, 0xbc, 0x30, + 0xf7, 0x99, 0xc3, 0x4d, 0x49, 0xba, 0xfb, 0x9e, 0x5d, 0x05, 0xd3, 0xf7, 0xa0, 0xc3, 0xe9, 0x91, + 0x1e, 0x2c, 0xef, 0x3e, 0x79, 0xf6, 0x70, 0xb2, 0x84, 0x4e, 0xff, 0xc9, 0xb7, 0x8f, 0x27, 0x16, + 0x82, 0x9e, 0xee, 0xef, 0xdb, 0x93, 0x16, 0xfd, 0x73, 0x0b, 0x88, 0x7e, 0x10, 0x29, 0x95, 0xcf, + 0x8b, 0x7b, 0x21, 0x24, 0xf2, 0x7e, 0xd3, 0xa1, 0xa5, 0xc1, 0x8b, 0xa1, 0xb0, 0x79, 0xb9, 0x6a, + 0xfa, 0x08, 0xfa, 0x1a, 0xb8, 0xc1, 0xd0, 0xde, 0x33, 0x0d, 0x6d, 0x64, 0xde, 0x3b, 0xdd, 0xce, + 0x08, 0x4c, 0x70, 0x53, 0x8c, 0xdc, 0x0b, 0x75, 0x7e, 0x20, 0x34, 0x20, 0x61, 0xf2, 0xcc, 0x1b, + 0xd0, 0x11, 0xb7, 0x5c, 0xc4, 0x03, 0x62, 0x50, 0x2c, 0x67, 0xa5, 0x9c, 0xe9, 0xa7, 0x72, 0x39, + 0xd3, 0x59, 0xa6, 0xd0, 0x11, 0x2e, 0x44, 0x70, 0x3c, 0x50, 0x27, 0x42, 0x2c, 0x5b, 0x4c, 0xd1, + 0x7f, 0xb7, 0xa0, 0x2b, 0xaf, 0x02, 0xda, 0x60, 0x9a, 0xb9, 0x59, 0xae, 0x5e, 0x3a, 0x39, 0x22, + 0x1f, 0x42, 0x4f, 0x86, 0xe5, 0xa9, 0x64, 0xae, 0x34, 0x27, 0x09, 0xb7, 0x0b, 0x0c, 0x72, 0x0d, + 0x56, 0x78, 0xb0, 0x2b, 0x5c, 0x5a, 0x7f, 0x67, 0xa8, 0xe1, 0x06, 0x91, 0x2d, 0x27, 0x31, 0x14, + 0x9c, 0x85, 0xb1, 0xf7, 0xf2, 0x98, 0x05, 0x47, 0xc7, 0x99, 0xf4, 0x72, 0x3a, 0xa8, 0xf0, 0x8c, + 0x1d, 0xcd, 0x33, 0x6a, 0xbe, 0x76, 0xc5, 0xf4, 0xb5, 0x85, 0x5b, 0xea, 0x6a, 0x6e, 0x89, 0x7e, + 0x05, 0x23, 0x7e, 0x1f, 0xcb, 0xa0, 0xb5, 0xea, 0x93, 0xad, 0x06, 0x9f, 0x5c, 0xd0, 0x6a, 0xe9, + 0xb4, 0xfe, 0xd2, 0x02, 0xf2, 0x64, 0xce, 0xa2, 0xff, 0x97, 0x78, 0xb9, 0x8c, 0x7b, 0xdb, 0x46, + 0xdc, 0x7b, 0x15, 0xfa, 0xf3, 0x3c, 0x3d, 0x76, 0xe4, 0xa4, 0x78, 0x7d, 0x75, 0x90, 0x8a, 0x8c, + 0x3b, 0x65, 0x64, 0x7c, 0x0f, 0xd6, 0x8d, 0x73, 0x4a, 0x73, 0x78, 0x1f, 0x46, 0x66, 0x04, 0x2c, + 0xcf, 0x59, 0x81, 0xd2, 0x7f, 0x6c, 0x41, 0x87, 0x1b, 0x2d, 0xb7, 0xbf, 0x24, 0x90, 0xa9, 0xa3, + 0x65, 0x8b, 0x81, 0x11, 0x0d, 0xb4, 0xcc, 0x68, 0x40, 0xf7, 0x19, 0x6d, 0xd3, 0x67, 0x8c, 0xa0, + 0x15, 0xf8, 0x32, 0xe2, 0x6f, 0x05, 0x3e, 0xf9, 0xa2, 0x2e, 0xb6, 0x0e, 0xb7, 0xad, 0x2d, 0x65, + 0x2f, 0xa6, 0xe2, 0x1a, 0xc5, 0x19, 0xc6, 0x9e, 0x1b, 0xe2, 0x66, 0xc2, 0x18, 0x8a, 0x31, 0x79, + 0x07, 0xc0, 0xe3, 0x71, 0xb6, 0xef, 0xb8, 0x19, 0x37, 0x89, 0x65, 0x5b, 0x83, 0x90, 0x6b, 0xb0, + 0x9c, 0x06, 0x3e, 0xdb, 0xee, 0x71, 0x07, 0xb6, 0x66, 0xdc, 0xd5, 0xc3, 0xc0, 0x67, 0x36, 0x9f, + 0x46, 0x63, 0x09, 0x52, 0x27, 0x3e, 0x8b, 0x1c, 0xee, 0x05, 0xf8, 0x93, 0xd7, 0xb3, 0x0d, 0x18, + 0x9a, 0xe9, 0x71, 0x1c, 0xfa, 0xfc, 0xd9, 0x5b, 0xb6, 0xf9, 0x37, 0xfd, 0x0b, 0x0b, 0x06, 0x9c, + 0x96, 0xcd, 0x4e, 0xe2, 0x53, 0x37, 0x34, 0x64, 0x66, 0x2d, 0x96, 0x59, 0x25, 0x36, 0xd3, 0x23, + 0xba, 0x76, 0x25, 0xa2, 0xd3, 0xb9, 0x5f, 0xae, 0x70, 0x5f, 0x3d, 0x76, 0xa7, 0x7e, 0x6c, 0x7a, + 0x0c, 0x2b, 0xc2, 0x33, 0x91, 0x8f, 0x00, 0x66, 0xf9, 0xb9, 0x63, 0x78, 0xc7, 0xa1, 0x21, 0x11, + 0x5b, 0x43, 0x20, 0xb7, 0xa1, 0x9f, 0xb2, 0x30, 0x54, 0xf8, 0xad, 0x26, 0x7c, 0x1d, 0x83, 0x7e, + 0xac, 0x3c, 0x27, 0x8f, 0x3d, 0x50, 0x5e, 0xe8, 0x7a, 0x64, 0x58, 0xcb, 0xbf, 0xd1, 0x86, 0xe3, + 0xb3, 0x48, 0x26, 0xb5, 0xf8, 0x49, 0x7f, 0x6e, 0xc9, 0x55, 0xdf, 0xcc, 0x7d, 0x37, 0x63, 0xf8, + 0x8c, 0x0b, 0x5e, 0x2c, 0x6e, 0x24, 0xe6, 0x7e, 0x0f, 0x97, 0x6c, 0x31, 0x4b, 0x7e, 0x13, 0x86, + 0x42, 0x42, 0x89, 0x10, 0xbc, 0xf4, 0x57, 0x1b, 0xe6, 0xf1, 0xc4, 0xdc, 0xc3, 0x25, 0xdb, 0x44, + 0xde, 0x1d, 0xc1, 0x40, 0x00, 0x72, 0xbe, 0x29, 0xfd, 0xb7, 0x16, 0x2c, 0xa3, 0xb3, 0x5c, 0x9c, + 0x04, 0xbc, 0x56, 0x88, 0xf7, 0x05, 0x0c, 0xc2, 0xc8, 0x57, 0x43, 0xe5, 0x17, 0xaf, 0xe8, 0xee, + 0x18, 0xc3, 0x91, 0xa7, 0xf9, 0xec, 0x6b, 0x76, 0x2e, 0x9f, 0x1d, 0x63, 0x05, 0xee, 0x1f, 0x44, + 0xb3, 0x38, 0x8f, 0x7c, 0xf9, 0x36, 0xaa, 0x61, 0xf9, 0x44, 0x74, 0xb4, 0x27, 0x02, 0xbd, 0xc6, + 0xab, 0xdc, 0x77, 0x4c, 0x57, 0xa9, 0x83, 0xc8, 0x87, 0xb0, 0x96, 0x32, 0x2f, 0x8e, 0xfc, 0x54, + 0xa4, 0x87, 0x5e, 0xc6, 0x7c, 0x7e, 0x4f, 0x86, 0x76, 0x7d, 0xa2, 0x39, 0xe6, 0x9b, 0xde, 0x83, + 0x71, 0xe5, 0xd8, 0x0d, 0xcf, 0xe2, 0x86, 0xfe, 0x2c, 0xae, 0xea, 0xcf, 0xe0, 0x1f, 0xb6, 0x60, + 0xed, 0x29, 0x66, 0x72, 0x52, 0x29, 0xc2, 0x9d, 0xfe, 0x5f, 0xfa, 0x1c, 0xfd, 0xfe, 0x2c, 0x57, + 0xee, 0x8f, 0xf2, 0x00, 0x9d, 0x8b, 0x3d, 0xc0, 0x0d, 0x98, 0x24, 0x8c, 0xe7, 0x9b, 0x4e, 0x41, + 0x4a, 0x88, 0xb3, 0x06, 0xc7, 0x48, 0x37, 0x38, 0x39, 0x61, 0x7e, 0xe0, 0x66, 0x08, 0x75, 0x3c, + 0xcc, 0x27, 0x42, 0x2e, 0xd5, 0x9e, 0xdd, 0x34, 0x85, 0x22, 0x20, 0xba, 0x08, 0xa4, 0xa7, 0xfe, + 0x0c, 0x53, 0xfd, 0x8c, 0x25, 0x91, 0x1b, 0x3a, 0x27, 0x6e, 0xe6, 0x1d, 0xb3, 0x05, 0xf7, 0xb2, + 0x86, 0x46, 0x7e, 0x03, 0x46, 0x3c, 0x94, 0x4e, 0x73, 0xcf, 0x63, 0x29, 0x06, 0x53, 0xe2, 0x82, + 0x16, 0x21, 0x34, 0x66, 0x8c, 0x87, 0x62, 0xd2, 0xae, 0xa0, 0x92, 0x4f, 0x31, 0x52, 0x3d, 0x71, + 0x83, 0x08, 0x23, 0x72, 0x71, 0xdd, 0xda, 0x0d, 0xd7, 0xcd, 0xae, 0x62, 0x91, 0xcf, 0x60, 0xc8, + 0x49, 0xbd, 0x70, 0x83, 0x30, 0x4f, 0x78, 0x04, 0x57, 0xdb, 0xf4, 0xb7, 0xc4, 0x9c, 0x6d, 0x62, + 0xd2, 0xff, 0xb2, 0x60, 0x5c, 0x8a, 0x60, 0xff, 0x14, 0x53, 0xf9, 0x6b, 0xd0, 0xe1, 0xfc, 0x2c, + 0xbc, 0xec, 0x7c, 0x96, 0x7c, 0x06, 0x03, 0x9d, 0x01, 0x79, 0xd7, 0x9b, 0x38, 0x7d, 0xb8, 0x64, + 0x1b, 0xa8, 0xe4, 0xb3, 0xd7, 0xe3, 0xf4, 0xe1, 0x52, 0x13, 0xaf, 0x03, 0x9d, 0x03, 0x6e, 0x58, + 0xcd, 0xac, 0x16, 0xbb, 0x4a, 0xd4, 0xdd, 0x2e, 0x74, 0x18, 0x32, 0x48, 0x63, 0xe8, 0x6b, 0xa9, + 0xcc, 0xc2, 0xc0, 0x4b, 0x73, 0x3b, 0x2d, 0xd3, 0xed, 0x68, 0x71, 0xd0, 0x72, 0x2d, 0x0e, 0x12, + 0x85, 0xc7, 0x8e, 0x56, 0x78, 0xa4, 0x1f, 0xc3, 0x26, 0xf7, 0x7a, 0xac, 0xac, 0x52, 0xff, 0xe2, + 0x4c, 0x7d, 0x1b, 0xb6, 0xaa, 0x8b, 0x64, 0xe1, 0xeb, 0x00, 0x88, 0x98, 0x31, 0xae, 0xee, 0x45, + 0x05, 0x88, 0x0b, 0x2e, 0x30, 0xfd, 0x04, 0xd6, 0x0d, 0x6a, 0xf2, 0x16, 0xbc, 0x03, 0x13, 0x85, + 0xe2, 0xc4, 0x91, 0xc3, 0x1f, 0x59, 0x4b, 0x7b, 0x64, 0x3f, 0x82, 0x35, 0xb1, 0x4c, 0x2f, 0xb1, + 0x2f, 0x4c, 0x5a, 0xe8, 0x86, 0x3a, 0xb3, 0x51, 0x31, 0xff, 0xa3, 0x16, 0x82, 0xd3, 0x2c, 0x4e, + 0x8c, 0x22, 0xde, 0x6b, 0x55, 0xe4, 0xf4, 0x4a, 0x5f, 0xcb, 0xac, 0xf4, 0x91, 0xaf, 0xa1, 0x8f, + 0x1e, 0x7c, 0xe6, 0x7a, 0x2f, 0xf3, 0xb9, 0x72, 0xf9, 0x37, 0x94, 0x91, 0xd4, 0x77, 0xc4, 0x07, + 0x60, 0x57, 0x20, 0x8b, 0x07, 0x00, 0xc2, 0x02, 0x40, 0x7e, 0xc4, 0x7b, 0x11, 0x8e, 0xef, 0x66, + 0xee, 0xcc, 0x4d, 0x45, 0x15, 0x74, 0xc0, 0xfd, 0xf9, 0x03, 0x09, 0x92, 0xbe, 0x58, 0xa7, 0xf0, + 0x8b, 0x7c, 0xf1, 0x40, 0xf7, 0xc5, 0x0c, 0x55, 0xa0, 0x9d, 0xa9, 0x2c, 0x4c, 0x26, 0x02, 0x2c, + 0x0b, 0x8e, 0x52, 0x0c, 0x0a, 0xc8, 0xab, 0x8d, 0x1f, 0xa0, 0x8b, 0x94, 0x48, 0x2a, 0x6f, 0x17, + 0x49, 0xec, 0x58, 0xc1, 0x55, 0x9d, 0x71, 0x0d, 0xc6, 0x87, 0xc7, 0x79, 0xe6, 0xc7, 0x67, 0xaa, + 0xd4, 0x8e, 0xd9, 0x4c, 0x09, 0x92, 0x4a, 0xf9, 0x35, 0xd8, 0x3a, 0xcc, 0x67, 0xa9, 0x97, 0x04, + 0x33, 0x66, 0xe6, 0xa4, 0x53, 0xe8, 0xb1, 0x57, 0x41, 0x9a, 0x05, 0xd1, 0x11, 0x67, 0xac, 0x67, + 0x17, 0x63, 0xfa, 0x2e, 0xbc, 0x5d, 0xac, 0xc2, 0x5b, 0x98, 0xde, 0xf7, 0x3c, 0x36, 0xcf, 0x98, + 0xaf, 0xb6, 0xba, 0x07, 0x9b, 0x26, 0x82, 0xd6, 0x97, 0x51, 0xb9, 0x66, 0xe6, 0xbe, 0x94, 0x41, + 0x46, 0xcf, 0x36, 0x81, 0xf4, 0x7f, 0x5a, 0x30, 0xc0, 0x65, 0x8a, 0x2c, 0xb9, 0x5c, 0xb3, 0xf7, + 0x2e, 0x1f, 0x3f, 0x32, 0xa3, 0xb3, 0x56, 0x25, 0x3a, 0xbb, 0xf0, 0xbd, 0x5a, 0x54, 0x67, 0x2b, + 0xdf, 0xc5, 0x8e, 0xfe, 0x2e, 0x56, 0xab, 0x77, 0x2b, 0x0d, 0xd5, 0xbb, 0x2d, 0x58, 0x49, 0x78, + 0x69, 0x45, 0xa6, 0x46, 0x72, 0x84, 0x4f, 0x9b, 0x48, 0x21, 0x9c, 0x84, 0x79, 0x2c, 0x38, 0x45, + 0x99, 0xf6, 0xf8, 0xae, 0x35, 0x38, 0xe6, 0x0e, 0x12, 0x96, 0xca, 0x2e, 0xc3, 0xaa, 0x68, 0xc3, + 0x98, 0x50, 0x72, 0x0b, 0x88, 0x72, 0x1f, 0x1a, 0x55, 0x51, 0x11, 0x6a, 0x98, 0xc1, 0x33, 0x14, + 0x50, 0x45, 0xb9, 0x2f, 0x9e, 0xd7, 0x2a, 0x9c, 0xfe, 0xb5, 0x05, 0x7d, 0xcd, 0xbb, 0xfe, 0xc0, + 0x7a, 0xa7, 0x2e, 0xe3, 0x76, 0x45, 0xc6, 0x55, 0x69, 0x2e, 0x37, 0x48, 0xf3, 0x7d, 0x18, 0x49, + 0x77, 0xee, 0x24, 0xcc, 0x4d, 0x63, 0xe5, 0x68, 0x2b, 0x50, 0xfa, 0xb7, 0x6d, 0x71, 0x5a, 0xf9, + 0x02, 0xfd, 0x72, 0x8d, 0xa5, 0x54, 0x79, 0xc7, 0x50, 0xf9, 0x75, 0x18, 0x1b, 0xaa, 0x65, 0xbe, + 0xd4, 0x78, 0x15, 0x8c, 0x11, 0x64, 0xa9, 0xda, 0x4c, 0x6a, 0x5b, 0x07, 0xd5, 0x84, 0x05, 0x0d, + 0xc2, 0xba, 0x0a, 0xcb, 0x49, 0x1c, 0x32, 0xae, 0xd2, 0x51, 0x59, 0x80, 0xb0, 0xe3, 0x90, 0xd9, + 0x7c, 0x06, 0xe3, 0xd0, 0x8a, 0x59, 0x30, 0x9f, 0x57, 0xfd, 0x56, 0xed, 0xfa, 0x04, 0x5e, 0x54, + 0xdd, 0x2c, 0xb2, 0xed, 0xa1, 0xe8, 0x1f, 0x18, 0x40, 0x4c, 0xfe, 0x12, 0x67, 0x9e, 0xb0, 0xe0, + 0xc4, 0x3d, 0x62, 0xdb, 0x23, 0x8e, 0xa2, 0x41, 0xca, 0xab, 0x34, 0xd6, 0xae, 0x12, 0xfd, 0xef, + 0x16, 0x74, 0x9e, 0x25, 0xae, 0xcf, 0x30, 0xc3, 0x39, 0xc1, 0x1b, 0xef, 0x2c, 0xce, 0x38, 0x6c, + 0x1d, 0x03, 0x17, 0x64, 0xda, 0x82, 0x56, 0xe3, 0x02, 0x0d, 0x43, 0xd3, 0x4f, 0xdb, 0xd0, 0xcf, + 0x45, 0x3a, 0xd5, 0x2c, 0xa1, 0x63, 0x5a, 0x42, 0xc1, 0xcf, 0x8a, 0xee, 0x1a, 0x94, 0xec, 0xbb, + 0x0b, 0x65, 0x7f, 0x15, 0xfa, 0x4c, 0xb4, 0x11, 0x78, 0x96, 0x2c, 0x2c, 0x41, 0x07, 0x15, 0x41, + 0xf2, 0xea, 0xc5, 0x41, 0xf2, 0x5d, 0x18, 0x78, 0x68, 0x18, 0x2c, 0x99, 0xbb, 0x49, 0x26, 0x4c, + 0x61, 0x71, 0x22, 0x6f, 0xe0, 0xd2, 0x9b, 0xb0, 0xce, 0xa5, 0xfe, 0x30, 0xc0, 0xa7, 0xe2, 0x5c, + 0x4b, 0x03, 0x44, 0xad, 0xd0, 0xd2, 0x6a, 0x85, 0xf4, 0x1e, 0x6c, 0x98, 0xc8, 0xf2, 0x9d, 0xba, + 0x06, 0x2b, 0x19, 0xc2, 0x6b, 0x61, 0x32, 0xc7, 0xb6, 0xe5, 0x24, 0xa6, 0xe5, 0x43, 0x84, 0x04, + 0xd1, 0xd1, 0x01, 0xd2, 0x4b, 0x51, 0xe0, 0x27, 0xee, 0x2b, 0x07, 0xd3, 0x55, 0x95, 0x97, 0xab, + 0x31, 0x0a, 0x1c, 0xbf, 0x67, 0xb9, 0x8a, 0x58, 0xd4, 0x10, 0x8d, 0x36, 0x61, 0x29, 0x4b, 0x4e, + 0x99, 0xef, 0xc4, 0x79, 0x26, 0x12, 0x33, 0xe1, 0x4c, 0xea, 0x13, 0xe4, 0x26, 0x7f, 0x1f, 0x05, + 0x50, 0xcf, 0xe2, 0x9a, 0x90, 0xe9, 0x8e, 0xe0, 0xb0, 0x38, 0xe1, 0xeb, 0xc4, 0x69, 0x7f, 0x63, + 0xc1, 0x66, 0x65, 0x91, 0x94, 0xcb, 0x7d, 0x58, 0xe1, 0x82, 0x53, 0x72, 0xf9, 0x40, 0x97, 0x4b, + 0x0d, 0xfd, 0x96, 0x18, 0xca, 0xba, 0xa7, 0x58, 0x38, 0x7d, 0x0a, 0x7d, 0x0d, 0xdc, 0x10, 0x54, + 0xdc, 0x34, 0xeb, 0x9e, 0x9b, 0xcd, 0x5b, 0x68, 0xb1, 0xc6, 0x4f, 0x61, 0xf0, 0x4d, 0x34, 0xfb, + 0x01, 0xcd, 0x76, 0x72, 0x05, 0x56, 0x13, 0x26, 0xb3, 0x52, 0x19, 0x62, 0x94, 0x00, 0x3a, 0x86, + 0xa1, 0xa4, 0x5b, 0xb6, 0x67, 0xbf, 0x89, 0xc2, 0xd8, 0x7b, 0xf9, 0xba, 0xed, 0xd9, 0x9f, 0x01, + 0xd1, 0x17, 0x94, 0x41, 0x50, 0xce, 0xa1, 0x95, 0x20, 0x48, 0x01, 0x79, 0x10, 0xf4, 0x2e, 0xf4, + 0x75, 0x14, 0xd1, 0xcd, 0x81, 0x12, 0x81, 0xfe, 0x89, 0x05, 0xe3, 0x6f, 0x83, 0xec, 0xd8, 0x4f, + 0xdc, 0xb3, 0xd7, 0x50, 0x6a, 0xb5, 0x55, 0xde, 0xba, 0xa8, 0x55, 0xde, 0xae, 0xb6, 0xca, 0xdd, + 0x30, 0x94, 0x85, 0x02, 0xfc, 0xd4, 0x4b, 0x84, 0x43, 0x51, 0x22, 0xbc, 0x0b, 0x93, 0xf2, 0x30, + 0x6f, 0x56, 0x1f, 0xbc, 0x71, 0x1d, 0x56, 0x0b, 0x07, 0x40, 0xba, 0xd0, 0xde, 0xfd, 0xe6, 0xb7, + 0x27, 0x4b, 0xa4, 0x07, 0xcb, 0x87, 0xfb, 0x07, 0x07, 0xa2, 0x14, 0xcf, 0xab, 0xf3, 0xad, 0x1b, + 0x37, 0x60, 0x19, 0xdd, 0x0d, 0x59, 0x85, 0xce, 0xb3, 0xfb, 0x5f, 0xef, 0xdb, 0x93, 0x25, 0xfc, + 0xfc, 0x09, 0xff, 0xb4, 0xc8, 0x00, 0x7a, 0x8f, 0x1e, 0x3f, 0xdb, 0xb7, 0x1f, 0xdf, 0x3f, 0x98, + 0xb4, 0x76, 0xfe, 0xc3, 0x82, 0xee, 0xf3, 0xdc, 0x7f, 0x14, 0x05, 0x19, 0xd9, 0x07, 0x28, 0xbb, + 0xe4, 0xe4, 0x72, 0x51, 0x40, 0xae, 0xf6, 0xda, 0xa7, 0xd3, 0xa6, 0x29, 0xa9, 0xfd, 0x25, 0xf2, + 0x10, 0xfa, 0x5a, 0x50, 0x4b, 0xa6, 0x8b, 0xa3, 0xef, 0xe9, 0x5b, 0x8d, 0x73, 0x05, 0xa5, 0x7d, + 0x80, 0xd2, 0x30, 0xca, 0x03, 0xd5, 0xac, 0xab, 0x3c, 0x50, 0xdd, 0x8e, 0xe8, 0xd2, 0xce, 0xdf, + 0x6f, 0x41, 0xfb, 0x79, 0xee, 0x93, 0xe7, 0xd0, 0xd7, 0x7e, 0x18, 0x22, 0xb5, 0xe6, 0x4c, 0x79, + 0x9c, 0xa6, 0xff, 0x8a, 0xa6, 0x3f, 0xff, 0xe7, 0xff, 0xfc, 0xd3, 0xd6, 0x06, 0x1d, 0xdf, 0x3e, + 0xfd, 0xd5, 0xdb, 0xae, 0xef, 0x2b, 0x93, 0xb9, 0x6b, 0xdd, 0x20, 0x36, 0x74, 0xe5, 0x3f, 0x41, + 0x64, 0x4b, 0xa3, 0xa1, 0x65, 0x48, 0xd3, 0x4b, 0x35, 0xb8, 0xa4, 0xbb, 0xc5, 0xe9, 0x4e, 0x68, + 0x5f, 0xd2, 0xc5, 0xe7, 0x05, 0x69, 0xee, 0x42, 0x7b, 0xd7, 0x8d, 0x08, 0x29, 0x1b, 0xa5, 0xea, + 0xea, 0x4e, 0xd7, 0x0d, 0x98, 0xa4, 0x43, 0x38, 0x9d, 0x01, 0xed, 0x22, 0x9d, 0x99, 0x1b, 0x21, + 0x0d, 0x0f, 0x06, 0xfa, 0xcf, 0x1a, 0xa4, 0xfc, 0x65, 0xa0, 0xfe, 0x07, 0xca, 0xf4, 0x4a, 0xf3, + 0xa4, 0x24, 0xbf, 0xcd, 0xc9, 0x13, 0x3a, 0x41, 0xf2, 0xfc, 0x5f, 0x16, 0xd9, 0x7a, 0x40, 0xe6, + 0xe5, 0x1f, 0x1a, 0x25, 0xf3, 0xe6, 0x0f, 0x1e, 0x25, 0xf3, 0xd5, 0x5f, 0x39, 0x0c, 0xe6, 0xa5, + 0x47, 0xc1, 0x83, 0x7f, 0x07, 0xc3, 0x6f, 0xf9, 0x9f, 0x42, 0xf2, 0xbf, 0x80, 0x92, 0xb2, 0xf9, + 0x5b, 0x41, 0x49, 0xb9, 0xf2, 0x03, 0x01, 0xbd, 0xc2, 0x29, 0x6f, 0xd1, 0x35, 0xa4, 0x2c, 0xfe, + 0x3a, 0xf2, 0x05, 0x0a, 0xd2, 0xff, 0x3d, 0x18, 0x1a, 0xbf, 0x00, 0x90, 0x82, 0xf9, 0xa6, 0x7f, + 0x0b, 0xa6, 0x6f, 0x2f, 0x98, 0x6d, 0xda, 0xcb, 0x97, 0x28, 0xfc, 0xa7, 0x01, 0xdc, 0xeb, 0x39, + 0x40, 0xd9, 0x4a, 0x2f, 0xad, 0xb8, 0xd6, 0xbe, 0x2f, 0xad, 0xb8, 0xde, 0x79, 0xa7, 0xeb, 0x7c, + 0x8b, 0x21, 0xe9, 0x0b, 0xed, 0x0a, 0x5a, 0x07, 0xd0, 0x95, 0x4d, 0xe3, 0x52, 0x3e, 0x66, 0xe7, + 0xbc, 0x94, 0x4f, 0xa5, 0xbb, 0x4c, 0x27, 0x9c, 0x20, 0x90, 0x1e, 0x12, 0x0c, 0x90, 0xc4, 0xef, + 0x40, 0x5f, 0xeb, 0xa3, 0x12, 0xfd, 0x34, 0x95, 0xe6, 0x6c, 0x79, 0x51, 0x1a, 0x1a, 0xaf, 0x74, + 0x83, 0x53, 0x1e, 0x91, 0x01, 0x52, 0x46, 0x29, 0x70, 0xea, 0xdf, 0x02, 0x94, 0x2d, 0xbf, 0x52, + 0x0a, 0xb5, 0xde, 0x65, 0x29, 0x85, 0x7a, 0x87, 0x50, 0xd9, 0x38, 0x01, 0x24, 0x2d, 0x0b, 0xe3, + 0x47, 0x30, 0x32, 0x3b, 0xb2, 0xe4, 0x6d, 0x9d, 0x42, 0xad, 0x85, 0x3b, 0x7d, 0x67, 0xd1, 0xb4, + 0x69, 0x93, 0x64, 0xc4, 0x6d, 0xb2, 0x24, 0x7b, 0x08, 0xab, 0x45, 0xaf, 0x90, 0x6c, 0xeb, 0x44, + 0xf4, 0x96, 0xe2, 0xf4, 0x72, 0xc3, 0x8c, 0xa4, 0xbc, 0xc6, 0x29, 0xf7, 0xc9, 0x2a, 0x52, 0x16, + 0x25, 0x63, 0x45, 0x94, 0xff, 0x62, 0x60, 0x12, 0xd5, 0x1a, 0x8d, 0x15, 0xa2, 0x7a, 0xbb, 0xb1, + 0x42, 0x94, 0xd3, 0x71, 0xa0, 0xaf, 0x75, 0xa2, 0x4a, 0x4d, 0xd6, 0xdb, 0x68, 0xa5, 0x26, 0x1b, + 0x5a, 0x57, 0xf4, 0x12, 0x27, 0xbd, 0x26, 0x5c, 0x5e, 0x3c, 0x67, 0x91, 0xba, 0xf2, 0xbf, 0x0b, + 0x50, 0x16, 0x0f, 0x4b, 0x65, 0xd6, 0xca, 0xca, 0xa5, 0xf9, 0x55, 0x6a, 0x8d, 0xf4, 0x32, 0x27, + 0xbd, 0x4e, 0xb9, 0x90, 0x79, 0x41, 0x97, 0xab, 0xf3, 0xae, 0x75, 0xe3, 0x8e, 0x45, 0x5e, 0xc0, + 0xa8, 0xc4, 0x3f, 0x3c, 0x8f, 0xbc, 0x8b, 0xb6, 0x98, 0x36, 0x4d, 0x49, 0x06, 0xde, 0xe6, 0xbb, + 0x5c, 0xa2, 0xc4, 0xdc, 0x25, 0x3d, 0x8f, 0x3c, 0xbc, 0x99, 0x3f, 0x83, 0xbe, 0xf6, 0x43, 0x4f, + 0x29, 0xa7, 0xfa, 0x5f, 0x3e, 0xd3, 0xa6, 0xf2, 0xa6, 0xf9, 0x24, 0xc8, 0x00, 0x3e, 0x3d, 0x73, + 0xe7, 0x48, 0x3b, 0x82, 0x91, 0x59, 0xc5, 0x2b, 0xcd, 0xb2, 0xb1, 0x24, 0x58, 0x9a, 0xe5, 0x82, + 0xe2, 0x9f, 0xc1, 0x0b, 0x6f, 0x9d, 0x30, 0xfd, 0x09, 0x9a, 0xe1, 0xab, 0x5b, 0x54, 0xf3, 0xf4, + 0x57, 0xb7, 0x5a, 0x30, 0xd4, 0x5f, 0xdd, 0x5a, 0xf9, 0xcf, 0xe4, 0x49, 0x6c, 0xa3, 0x34, 0x43, + 0xbe, 0x03, 0x28, 0x6b, 0x79, 0xa5, 0x4e, 0x6a, 0xe5, 0xc0, 0xe9, 0xb4, 0x69, 0x4a, 0x6e, 0x60, + 0x68, 0x5e, 0x6c, 0xa0, 0x9e, 0xbc, 0x9f, 0x42, 0x4f, 0x15, 0xa5, 0x48, 0x61, 0x39, 0x95, 0xca, + 0xd5, 0x74, 0xbb, 0x3e, 0x51, 0x31, 0x57, 0xee, 0x78, 0x52, 0x39, 0x8b, 0x74, 0x19, 0x8c, 0x2b, + 0x85, 0x2d, 0x52, 0x48, 0xbb, 0xb9, 0xe2, 0x35, 0x35, 0xff, 0xdf, 0x11, 0xdd, 0x30, 0xfa, 0x16, + 0xdf, 0x60, 0x93, 0xac, 0xf3, 0x0d, 0xd4, 0x42, 0x61, 0x52, 0x77, 0x2c, 0x32, 0xaf, 0x14, 0xba, + 0x64, 0xc5, 0x44, 0x73, 0x48, 0x8d, 0x75, 0xb0, 0x69, 0x53, 0x11, 0x9b, 0xfe, 0x88, 0xef, 0xf5, + 0x16, 0xb9, 0x6c, 0xec, 0x85, 0xd6, 0xa5, 0x6a, 0xf8, 0x77, 0x2c, 0x32, 0x83, 0x91, 0x49, 0xf2, + 0x8d, 0xb6, 0xaa, 0x98, 0x31, 0x21, 0xb5, 0xad, 0x70, 0x8f, 0x3f, 0xd0, 0xaa, 0x82, 0x46, 0x7d, + 0x8f, 0x5c, 0x6b, 0xde, 0xab, 0x52, 0xff, 0x9b, 0x6e, 0xe8, 0x7b, 0xaa, 0x49, 0x4a, 0xf9, 0xa6, + 0x57, 0xc8, 0xb4, 0xbe, 0xa9, 0x2b, 0x71, 0xb8, 0x27, 0x18, 0xe8, 0x99, 0x67, 0x19, 0xc0, 0x34, + 0x24, 0xaf, 0x65, 0x00, 0xd3, 0x94, 0xac, 0x2a, 0xe5, 0x89, 0x00, 0x86, 0x67, 0xa6, 0xc7, 0x02, + 0x03, 0x2d, 0xe4, 0xa8, 0x9a, 0xa1, 0x5e, 0x59, 0x90, 0xb2, 0x55, 0xe2, 0x81, 0xc6, 0x84, 0x4e, + 0x99, 0x38, 0x59, 0x53, 0x5b, 0x05, 0xd1, 0x91, 0xc8, 0xeb, 0xc8, 0x57, 0xd0, 0xe1, 0xd9, 0x12, + 0xd9, 0x28, 0x43, 0xd6, 0x32, 0x29, 0x9b, 0x6e, 0x56, 0xa0, 0xe6, 0x93, 0x4a, 0xb9, 0x8f, 0xcf, + 0x23, 0x19, 0xdd, 0xcd, 0x60, 0x24, 0x82, 0x24, 0x95, 0x53, 0x94, 0x97, 0xa6, 0x92, 0xf2, 0x94, + 0x97, 0xa6, 0x9a, 0x7e, 0x98, 0x6e, 0x45, 0xc4, 0x49, 0x67, 0x12, 0xe7, 0xae, 0x75, 0x63, 0xb6, + 0xc2, 0xff, 0xb5, 0xff, 0xf8, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x82, 0x20, 0x21, 0xba, 0x96, + 0x2f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. From 4c01b0e5fe5da75bcb3b4de063e0132929b358bb Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Thu, 15 Oct 2020 12:45:59 -0400 Subject: [PATCH 07/11] feat(cli): case insensitive choices This makes commands that have enumerated choices - such as `swap_client` which accepts either `Lnd` or `Connext` - case insensitive in regards to those choices. Previously a value of `lnd` in the example above would throw an error due to an invalid value. --- lib/cli/commands/addcurrency.ts | 5 +++++ lib/cli/commands/listorders.ts | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/lib/cli/commands/addcurrency.ts b/lib/cli/commands/addcurrency.ts index bc27732ea..951b01f8d 100644 --- a/lib/cli/commands/addcurrency.ts +++ b/lib/cli/commands/addcurrency.ts @@ -16,6 +16,10 @@ export const builder = (argv: Argv) => argv description: 'the payment channel network client for swaps', type: 'string', choices: ['Lnd', 'Connext'], + coerce: (swapClientStr: string) => { + const swapClientLower = swapClientStr.toLowerCase(); + return swapClientLower.charAt(0).toUpperCase() + swapClientLower.slice(1); + }, }) .option('decimal_places', { description: 'the places to the right of the decimal point of the smallest subunit (e.g. satoshi)', @@ -33,6 +37,7 @@ export const handler = async (argv: Arguments) => { if (isNaN(argv.decimal_places) || argv.decimal_places >= 100 || argv.decimal_places < 0) { throw 'decimal_places must be a number between 0 and 100'; } + const request = new Currency(); request.setCurrency(argv.currency.toUpperCase()); request.setSwapClient(Number(SwapClientType[argv.swap_client])); diff --git a/lib/cli/commands/listorders.ts b/lib/cli/commands/listorders.ts index 1688487df..df5f0aa7e 100644 --- a/lib/cli/commands/listorders.ts +++ b/lib/cli/commands/listorders.ts @@ -91,6 +91,10 @@ export const builder = (argv: Argv) => argv describe: 'whether to include own, peer or both orders', type: 'string', choices: ['Both', 'Own', 'Peer'], + coerce: (ownerStr: string) => { + const ownerLower = ownerStr.toLowerCase(); + return ownerLower.charAt(0).toUpperCase() + ownerLower.slice(1); + }, default: 'Both', }) .option('limit', { From 785ad9ce477ab7009d43ddf76e238084f07f884c Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Fri, 16 Oct 2020 00:35:43 -0400 Subject: [PATCH 08/11] docs: add 1.0.0 release description --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c39b03be6..b5561722a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,29 @@ Most notable features of this release: # [1.0.0](https://github.com/ExchangeUnion/xud/compare/v1.0.0-beta.8...v1.0.0) (2020-09-01) +This is the first major release of xud. This release contains several key fixes and features designed to improve stability and the likelihood of successful swaps when trading with peers. + +## Connext + +This version continues expanding support for Connext. Tokens can now be withdrawn from one's Connext balance to an on-chain address. Collateral is automatically requested from the Connext node upon depositing tokens to allow for incoming payments to succeed on the first try. + +It also handles and prevents an edge case that could have caused xud to crash if Connext receives an expected incoming transfer twice. + +## Order Book + +The decentralized order book has had some improvements to make it more robust. "Dust" orders - where at least one side of a trade may be for an amount so small that it doesn't meet minimum HTLC sizes - are automatically removed from the order book. Previously, fragments of partially filled or removed orders may have been left over and remained in the order book despite being effectively untradeable. + +This version also improves the logic for adding back orders that failed to swap. Orders - or portions thereof - are removed from the order book as they are matched. However, if they are not swapped successfully then xud (unless being run in "strict" mode) will add them back to the order book so that they may be traded again by a future order, perhaps after correcting temporary network or channel management issues that may have caused the first swap attempt to fail. We've fixed this logic to ensure we always add back peer orders that fail a swap. On the other hand, we've also added checks to ensure we don't add back an order that is *no longer valid* - as may be the case when an order is canceled by a peer while we were attempting to swap it. + +## Order Replacement + +Order replacement has been supported since early pre-release versions of xud and is a handy way to update existing orders in response to changing market conditions. However, on the network layer, order replacements were communicated to peers via two separate packets - one to remove the old order and one to add the new one replacing it. This allowed for the possibility of delays or inconsistency as the two packets may arrive or be processed at different times. This version supports replacing orders in a single packet, with the aim of making order replacement as atomic as possible both locally and on the xud network. + +## Failed Swap Monitoring + +Xud has a Swap Recovery module that was originally designed to recover swaps that were in progress during an unexpected crash, with the goal of ensuring that we claim any payments we are expecting from swaps. Over time this same module was used to monitor swaps that xud would deem as "failed" but where HTLCs were still pending. If an outgoing HTLC was eventually claimed by an unscrupulous peer, xud would claim its corresponding incoming payment. + +This version goes back to Swap Recovery handling only swaps that were aborted due to an unexpected crash. Similar logic has been added to monitor pending HTLCs for active swaps separately. Swaps now remain "active" as long as any HTLCs exist, and the corresponding orders held in limbo until these HTLCs reach a final resolution. This ensures that orders cannot be double filled. Peers that we detect to have settled an old HTLC are immediately banned, as this is recognized as intentional malicious behavior that may exploit the [free option problem](https://lists.linuxfoundation.org/pipermail/lightning-dev/2018-December/001752.html). ### Bug Fixes From ed0ac6e0bf67df0ced918e50611abed714dc86cc Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Fri, 16 Oct 2020 01:04:49 -0400 Subject: [PATCH 09/11] chore(release): v1.2.0 --- CHANGELOG.md | 51 +++++++++++++++++++++++++++++++++++++++++++++ npm-shrinkwrap.json | 2 +- package.json | 2 +- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5561722a..6b9c58279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,54 @@ +# [1.2.0](https://github.com/ExchangeUnion/xud/compare/v1.0.0...v1.2.0) (2020-10-16) + +This release includes a number of fixes and features, most significantly related to Connext integration. + +- Inbound collateral from the Connext node is now dynamically requested upon orders being placed that receive a Connext currency. +- Keep track of inbound and outbound amounts reserved by standing orders in the orderbook, and expose these amounts on the `TradingLimits` call. + +### Bug Fixes + +* **cli:** switch getbalance table columns ([#1931](https://github.com/ExchangeUnion/xud/issues/1931)) ([49c8c18](https://github.com/ExchangeUnion/xud/commit/49c8c18cf9d00ede7f84ce617921ffc3aa9b18de)), closes [#1930](https://github.com/ExchangeUnion/xud/issues/1930) +* **orderbook:** don't remove 0 quantity w/ hold ([#1921](https://github.com/ExchangeUnion/xud/issues/1921)) ([5f3793a](https://github.com/ExchangeUnion/xud/commit/5f3793a0dc5d4c1cd042a2b5260d3db1942de750)) +* bold link, mm link ([#1873](https://github.com/ExchangeUnion/xud/issues/1873)) ([54bd9ce](https://github.com/ExchangeUnion/xud/commit/54bd9ce11fc6297319b4c48c7fe9537b3031817b)) +* checking for invoice support on lnd clients while verifying connection ([4c26aff](https://github.com/ExchangeUnion/xud/commit/4c26aff0bafc52053aaf928a4d1936bab4293950)) +* don't activate unsupported pairs with peers ([0fe2d66](https://github.com/ExchangeUnion/xud/commit/0fe2d66d85c2fcc2d559740662977750ddae21e1)) +* grpc throws error for addpair/withdraw for wrong argument ([#1844](https://github.com/ExchangeUnion/xud/issues/1844)) ([48a0a33](https://github.com/ExchangeUnion/xud/commit/48a0a33811c2ba52f3791b73f1eef8b8933e09cc)) +* handling insufficient balance errors for swap clients ([246889b](https://github.com/ExchangeUnion/xud/commit/246889b89f7f9fa27ba47a31d1a2408d7a4a58a7)) +* implemented showing all pairs instead of active ones for listpeers ([206dad0](https://github.com/ExchangeUnion/xud/commit/206dad04b0151e3514f7883e066c361c034defca)) +* listorders limit displays first orders instead of last ([#1883](https://github.com/ExchangeUnion/xud/issues/1883)) ([e101e6f](https://github.com/ExchangeUnion/xud/commit/e101e6fb3d0ede2cf6439d10dafa410b533035da)) +* propagating currencies and pairs on database if initDB true even DB is filled ([17c7cb5](https://github.com/ExchangeUnion/xud/commit/17c7cb54c3a55189ca459a9a842a7e2aa4886a6b)) +* propagating nodes on database if initDB true even DB is filled ([#1907](https://github.com/ExchangeUnion/xud/issues/1907)) ([246136e](https://github.com/ExchangeUnion/xud/commit/246136e3d2992711ce5e09d132cf79348bf99e6e)) +* xudrpc GetBalanceResponse json_name ([#1909](https://github.com/ExchangeUnion/xud/issues/1909)) ([26f89e6](https://github.com/ExchangeUnion/xud/commit/26f89e6d01cce2ec9d66dc39c0538d142a5af18c)) +* **connext:** avoid scientific notation for amount ([#1905](https://github.com/ExchangeUnion/xud/issues/1905)) ([cc1e689](https://github.com/ExchangeUnion/xud/commit/cc1e689181bfe4bafa19112d634a6eb12178cbe9)) +* **connext:** display error message for 400 status code ([#1911](https://github.com/ExchangeUnion/xud/issues/1911)) ([b4e1858](https://github.com/ExchangeUnion/xud/commit/b4e1858fd78005b43dcedf4ec5b5425c727639c5)) +* **connext:** remove BigInt to avoid precision loss ([#1893](https://github.com/ExchangeUnion/xud/issues/1893)) ([d9ddd1c](https://github.com/ExchangeUnion/xud/commit/d9ddd1cfa16614fc914c61ded2c5e84fd7bd743c)) +* order invalidation only be sent to peers with active pair ([#1530](https://github.com/ExchangeUnion/xud/issues/1530)) ([#1890](https://github.com/ExchangeUnion/xud/issues/1890)) ([0dc85bd](https://github.com/ExchangeUnion/xud/commit/0dc85bd83ad0514241e85ae3a958bb01d31594b0)) + + +### Features + +* **cli:** case insensitive choices ([4c01b0e](https://github.com/ExchangeUnion/xud/commit/4c01b0e5fe5da75bcb3b4de063e0132929b358bb)) +* **connext:** lazy collateralization ([#1916](https://github.com/ExchangeUnion/xud/issues/1916)) ([0f2b841](https://github.com/ExchangeUnion/xud/commit/0f2b841d3bc353cebca01f0bcdfec52c6c13e9d0)), closes [#1896](https://github.com/ExchangeUnion/xud/issues/1896) +* **connext:** request collateral for order amount ([75078c0](https://github.com/ExchangeUnion/xud/commit/75078c059bfd752ae47c4530a671bd7a95568975)), closes [#1845](https://github.com/ExchangeUnion/xud/issues/1845) +* **logging:** order holds on trace level ([#1865](https://github.com/ExchangeUnion/xud/issues/1865)) ([5e3ad04](https://github.com/ExchangeUnion/xud/commit/5e3ad04ed8f2e35cb06479d2172d25bffa002768)) +* **rpc:** add txid to open/close channel response ([0669a3f](https://github.com/ExchangeUnion/xud/commit/0669a3f41f6a8de9cc6afcf4d8d58c91d18d5b58)), closes [#1860](https://github.com/ExchangeUnion/xud/issues/1860) +* **rpc:** expose reserved balance for GetBalance ([#1925](https://github.com/ExchangeUnion/xud/issues/1925)) ([8b18dd7](https://github.com/ExchangeUnion/xud/commit/8b18dd7426f01a760e571a0a5bb2310759229b64)) +* **rpc:** reserved order amount for TradingLimits ([7f7cd68](https://github.com/ExchangeUnion/xud/commit/7f7cd683272e738a77480028c16095e8fb34c175)), closes [#1584](https://github.com/ExchangeUnion/xud/issues/1584) [#1678](https://github.com/ExchangeUnion/xud/issues/1678) +* derive child seed for swap clients ([be4121f](https://github.com/ExchangeUnion/xud/commit/be4121fd04156318c68dba28ee5f1a2483fd0c07)), closes [#1576](https://github.com/ExchangeUnion/xud/issues/1576) +* **connext:** reject app install for transfers without status field ([#1863](https://github.com/ExchangeUnion/xud/issues/1863)) ([519aa54](https://github.com/ExchangeUnion/xud/commit/519aa54fa9bfd138d6086f0de0406462a62a57bc)) +* **connext:** unlock expired transfer apps ([#1857](https://github.com/ExchangeUnion/xud/issues/1857)) ([023434d](https://github.com/ExchangeUnion/xud/commit/023434de1eabe4811986b9156beef7a5a670c047)) +* **rpc:** show connext status on create/restore node ([#1902](https://github.com/ExchangeUnion/xud/issues/1902)) ([82e16a5](https://github.com/ExchangeUnion/xud/commit/82e16a5e4ed4fa91e481eac638b16eb10e5bb7de)) +* **simnet:** add DAI ([#1915](https://github.com/ExchangeUnion/xud/issues/1915)) ([35e85b3](https://github.com/ExchangeUnion/xud/commit/35e85b31bfbfa72430f5db982b7f64f19b346f2a)) +* sat_per_byte custom fee for openchannel ([#1832](https://github.com/ExchangeUnion/xud/issues/1832)) ([b56ad98](https://github.com/ExchangeUnion/xud/commit/b56ad98ecb31f94d304a31d3c060693506ae829a)), closes [#1829](https://github.com/ExchangeUnion/xud/issues/1829) +* **orderbook:** better replace order hold message ([b7fa00a](https://github.com/ExchangeUnion/xud/commit/b7fa00a7afc8ab0fe4e4f495395434e49e00f357)) +* **orderbook:** log error message on remove order ([#1901](https://github.com/ExchangeUnion/xud/issues/1901)) ([788490f](https://github.com/ExchangeUnion/xud/commit/788490f430691e2e93a28e4aab39aa260213e5b3)) +* **p2p:** don't log empty order packets ([#1871](https://github.com/ExchangeUnion/xud/issues/1871)) ([1b6d6d6](https://github.com/ExchangeUnion/xud/commit/1b6d6d6cf522517dbe138b8c7dda908b36f2d1a4)) +* **p2p:** increase reconnection delay backoff ([#1870](https://github.com/ExchangeUnion/xud/issues/1870)) ([44af197](https://github.com/ExchangeUnion/xud/commit/44af19722ced03fa2fd89702fea88d07ef51ae08)) +* **simnet:** change USDT contract address ([#1912](https://github.com/ExchangeUnion/xud/issues/1912)) ([0a2bdfd](https://github.com/ExchangeUnion/xud/commit/0a2bdfdba3507cbd0bba1a0af6d6f8b8b92c3272)) +* **simnet:** upgrade simnet USDT contract address ([#1906](https://github.com/ExchangeUnion/xud/issues/1906)) ([7e5f8ef](https://github.com/ExchangeUnion/xud/commit/7e5f8ef30a1d01a4405757d4359b827ef86cf750)) + + + # [1.1.0](https://github.com/ExchangeUnion/xud/compare/v1.0.0...v1.1.0) (2020-09-28) Most notable features of this release: diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d2baf1fbb..b01104a82 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "xud", - "version": "1.1.0", + "version": "1.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6062b472a..637c326f9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "xud", "minCompatibleVersion": "1.0.0-rc.1", - "version": "1.1.0", + "version": "1.2.0", "description": "Exchange Union Daemon", "main": "lib/Xud.js", "bin": { From c958e862542fb52fdeb6532cbe2d92dd4b52cedf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sercan=20=C3=96zdemir?= Date: Mon, 19 Oct 2020 12:47:26 +0300 Subject: [PATCH 10/11] feat: added new grpc method to easily cancel all orders (#1910) Signed-off-by: rsercano --- docs/api.md | 29 ++ lib/cli/commands/removeallorders.ts | 29 ++ lib/grpc/GrpcService.ts | 20 + lib/orderbook/OrderBook.ts | 16 + lib/proto/annotations_grpc_pb.js | 2 +- lib/proto/xudp2p_grpc_pb.js | 2 +- lib/proto/xudrpc.swagger.json | 49 +++ lib/proto/xudrpc_grpc_pb.d.ts | 17 + lib/proto/xudrpc_grpc_pb.js | 37 ++ lib/proto/xudrpc_pb.d.ts | 46 ++ lib/proto/xudrpc_pb.js | 322 ++++++++++++++ lib/service/Service.ts | 7 + proto/xudrpc.proto | 20 + test/simulation/xudrpc/xudrpc.pb.go | 659 +++++++++++++++++----------- 14 files changed, 987 insertions(+), 268 deletions(-) create mode 100644 lib/cli/commands/removeallorders.ts diff --git a/docs/api.md b/docs/api.md index b866623ad..0a1ef2e5f 100644 --- a/docs/api.md +++ b/docs/api.md @@ -56,6 +56,8 @@ - [PlaceOrderEvent](#xudrpc.PlaceOrderEvent) - [PlaceOrderRequest](#xudrpc.PlaceOrderRequest) - [PlaceOrderResponse](#xudrpc.PlaceOrderResponse) + - [RemoveAllOrdersRequest](#xudrpc.RemoveAllOrdersRequest) + - [RemoveAllOrdersResponse](#xudrpc.RemoveAllOrdersResponse) - [RemoveCurrencyRequest](#xudrpc.RemoveCurrencyRequest) - [RemoveCurrencyResponse](#xudrpc.RemoveCurrencyResponse) - [RemoveOrderRequest](#xudrpc.RemoveOrderRequest) @@ -936,6 +938,32 @@ + + +### RemoveAllOrdersRequest + + + + + + + + + +### RemoveAllOrdersResponse + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| removed_order_ids | [string](#string) | repeated | The local order ids that were successfully removed. | +| on_hold_order_ids | [string](#string) | repeated | The local order ids that were on hold and failed to be removed. | + + + + + + ### RemoveCurrencyRequest @@ -1491,6 +1519,7 @@ The primary service for interacting with a running xud node. | ExecuteSwap | [ExecuteSwapRequest](#xudrpc.ExecuteSwapRequest) | [SwapSuccess](#xudrpc.SwapSuccess) | Executes a swap on a maker peer order. | | RemoveCurrency | [RemoveCurrencyRequest](#xudrpc.RemoveCurrencyRequest) | [RemoveCurrencyResponse](#xudrpc.RemoveCurrencyResponse) | Removes a currency from the list of supported currencies. Only currencies that are not in use for any currently supported trading pairs may be removed. Once removed, the currency can no longer be used for any supported trading pairs. shell: xucli removecurrency <currency> | | RemoveOrder | [RemoveOrderRequest](#xudrpc.RemoveOrderRequest) | [RemoveOrderResponse](#xudrpc.RemoveOrderResponse) | Removes an order from the order book by its local id. This should be called when an order is canceled or filled outside of xud. Removed orders become immediately unavailable for swaps, and peers are notified that the order is no longer valid. Any portion of the order that is on hold due to ongoing swaps will not be removed until after the swap attempts complete. shell: xucli removeorder <order_id> [quantity] | +| RemoveAllOrders | [RemoveAllOrdersRequest](#xudrpc.RemoveAllOrdersRequest) | [RemoveAllOrdersResponse](#xudrpc.RemoveAllOrdersResponse) | Removes all orders from the order book. Removed orders become immediately unavailable for swaps, and peers are notified that the orders are no longer valid. Any portion of the orders that is on hold due to ongoing swaps will not be removed until after the swap attempts complete. shell: xucli removeallorders | | RemovePair | [RemovePairRequest](#xudrpc.RemovePairRequest) | [RemovePairResponse](#xudrpc.RemovePairResponse) | Removes a trading pair from the list of currently supported trading pair. This call will effectively cancel any standing orders for that trading pair. Peers are informed when a pair is no longer supported so that they will know to stop sending orders for it. shell: xucli removepair <pair_id> | | Shutdown | [ShutdownRequest](#xudrpc.ShutdownRequest) | [ShutdownResponse](#xudrpc.ShutdownResponse) | Begin gracefully shutting down xud. shell: xucli shutdown | | SubscribeOrders | [SubscribeOrdersRequest](#xudrpc.SubscribeOrdersRequest) | [OrderUpdate](#xudrpc.OrderUpdate) stream | Subscribes to orders being added to and removed from the order book. This call allows the client to maintain an up-to-date view of the order book. For example, an exchange that wants to show its users a real time view of the orders available to them would subscribe to this streaming call to be alerted as new orders are added and expired orders are removed. | diff --git a/lib/cli/commands/removeallorders.ts b/lib/cli/commands/removeallorders.ts new file mode 100644 index 000000000..8d2c42fe2 --- /dev/null +++ b/lib/cli/commands/removeallorders.ts @@ -0,0 +1,29 @@ +import { Arguments, Argv } from 'yargs'; +import { RemoveAllOrdersRequest, RemoveAllOrdersResponse } from '../../proto/xudrpc_pb'; +import { callback, loadXudClient } from '../command'; + +export const command = 'removeallorders'; + +export const describe = 'removes all orders'; + +export const builder = (argv: Argv) => argv + .example('$0 removeallorders', describe); + +const formatOutput = (response: RemoveAllOrdersResponse.AsObject) => { + if (response.removedOrderIdsList.length <= 0 && response.onHoldOrderIdsList.length <= 0) { + console.log('No orders found'); + return; + } + + if (response.removedOrderIdsList.length) { + response.removedOrderIdsList.forEach((removedOrder => console.log(`Removed order with id ${removedOrder}`))); + } + if (response.onHoldOrderIdsList.length) { + response.onHoldOrderIdsList.forEach((id => console.log(`Order with id ${id} has a hold for a pending swap and will be removed afterwards`))); + } + +}; + +export const handler = async (argv: Arguments) => { + (await loadXudClient(argv)).removeAllOrders(new RemoveAllOrdersRequest(), callback(argv, formatOutput)); +}; diff --git a/lib/grpc/GrpcService.ts b/lib/grpc/GrpcService.ts index bea355554..715f00dd5 100644 --- a/lib/grpc/GrpcService.ts +++ b/lib/grpc/GrpcService.ts @@ -288,6 +288,26 @@ class GrpcService { } } + /** + * See [[Service.removeAllOrders]] + */ + public removeAllOrders: grpc.handleUnaryCall = async (_, callback) => { + if (!this.isReady(this.service, callback)) { + return; + } + try { + const { removedOrderLocalIds, onHoldOrderLocalIds } = await this.service.removeAllOrders(); + + const response = new xudrpc.RemoveAllOrdersResponse(); + response.setRemovedOrderIdsList(removedOrderLocalIds); + response.setOnHoldOrderIdsList(onHoldOrderLocalIds); + + callback(null, response); + } catch (err) { + callback(getGrpcError(err), null); + } + } + /** * See [[Service.getBalance]] */ diff --git a/lib/orderbook/OrderBook.ts b/lib/orderbook/OrderBook.ts index 6645e7b4f..ed8b42de7 100644 --- a/lib/orderbook/OrderBook.ts +++ b/lib/orderbook/OrderBook.ts @@ -841,6 +841,22 @@ class OrderBook extends EventEmitter { return order; } + public removeOwnOrders = () => { + const removedOrderLocalIds = []; + const onHoldOrderLocalIds = []; + + for (const localId of this.localIdMap.keys()) { + const onHoldIndicator = this.removeOwnOrderByLocalId(localId, true); + if (onHoldIndicator === 0) { + removedOrderLocalIds.push(localId); + } else { + onHoldOrderLocalIds.push(localId); + } + } + + return { removedOrderLocalIds, onHoldOrderLocalIds }; + } + /** * Removes all or part of an order from the order book by its local id. Throws an error if the * specified pairId is not supported or if the order to cancel could not be found. diff --git a/lib/proto/annotations_grpc_pb.js b/lib/proto/annotations_grpc_pb.js index 97b3a2461..51b4d6959 100644 --- a/lib/proto/annotations_grpc_pb.js +++ b/lib/proto/annotations_grpc_pb.js @@ -1 +1 @@ -// GENERATED CODE -- NO SERVICES IN PROTO \ No newline at end of file +// GENERATED CODE -- NO SERVICES IN PROTO diff --git a/lib/proto/xudp2p_grpc_pb.js b/lib/proto/xudp2p_grpc_pb.js index 97b3a2461..51b4d6959 100644 --- a/lib/proto/xudp2p_grpc_pb.js +++ b/lib/proto/xudp2p_grpc_pb.js @@ -1 +1 @@ -// GENERATED CODE -- NO SERVICES IN PROTO \ No newline at end of file +// GENERATED CODE -- NO SERVICES IN PROTO diff --git a/lib/proto/xudrpc.swagger.json b/lib/proto/xudrpc.swagger.json index 29db24fb1..4cf741bff 100644 --- a/lib/proto/xudrpc.swagger.json +++ b/lib/proto/xudrpc.swagger.json @@ -440,6 +440,33 @@ ] } }, + "/v1/removeallorders": { + "post": { + "summary": "Removes all orders from the order book. Removed orders become immediately unavailable for swaps,\nand peers are notified that the orders are no longer valid. Any portion of the orders that is\non hold due to ongoing swaps will not be removed until after the swap attempts complete.\nshell: xucli removeallorders", + "operationId": "RemoveAllOrders", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/xudrpcRemoveAllOrdersResponse" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/xudrpcRemoveAllOrdersRequest" + } + } + ], + "tags": [ + "Xud" + ] + } + }, "/v1/removecurrency": { "post": { "summary": "Removes a currency from the list of supported currencies. Only currencies that are not in use\nfor any currently supported trading pairs may be removed. Once removed, the currency can no\nlonger be used for any supported trading pairs.\nshell: xucli removecurrency \u003ccurrency\u003e", @@ -1537,6 +1564,28 @@ } } }, + "xudrpcRemoveAllOrdersRequest": { + "type": "object" + }, + "xudrpcRemoveAllOrdersResponse": { + "type": "object", + "properties": { + "removed_order_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The local order ids that were successfully removed." + }, + "on_hold_order_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The local order ids that were on hold and failed to be removed." + } + } + }, "xudrpcRemoveCurrencyRequest": { "type": "object", "properties": { diff --git a/lib/proto/xudrpc_grpc_pb.d.ts b/lib/proto/xudrpc_grpc_pb.d.ts index e0433e79c..bc6c63d9b 100644 --- a/lib/proto/xudrpc_grpc_pb.d.ts +++ b/lib/proto/xudrpc_grpc_pb.d.ts @@ -95,6 +95,7 @@ interface IXudService extends grpc.ServiceDefinition; responseDeserialize: grpc.deserialize; } +interface IXudService_IRemoveAllOrders extends grpc.MethodDefinition { + path: string; // "/xudrpc.Xud/RemoveAllOrders" + requestStream: boolean; // false + responseStream: boolean; // false + requestSerialize: grpc.serialize; + requestDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; +} interface IXudService_IRemovePair extends grpc.MethodDefinition { path: string; // "/xudrpc.Xud/RemovePair" requestStream: boolean; // false @@ -401,6 +411,7 @@ export interface IXudServer { executeSwap: grpc.handleUnaryCall; removeCurrency: grpc.handleUnaryCall; removeOrder: grpc.handleUnaryCall; + removeAllOrders: grpc.handleUnaryCall; removePair: grpc.handleUnaryCall; shutdown: grpc.handleUnaryCall; subscribeOrders: grpc.handleServerStreamingCall; @@ -473,6 +484,9 @@ export interface IXudClient { removeOrder(request: xudrpc_pb.RemoveOrderRequest, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveOrderResponse) => void): grpc.ClientUnaryCall; removeOrder(request: xudrpc_pb.RemoveOrderRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveOrderResponse) => void): grpc.ClientUnaryCall; removeOrder(request: xudrpc_pb.RemoveOrderRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveOrderResponse) => void): grpc.ClientUnaryCall; + removeAllOrders(request: xudrpc_pb.RemoveAllOrdersRequest, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveAllOrdersResponse) => void): grpc.ClientUnaryCall; + removeAllOrders(request: xudrpc_pb.RemoveAllOrdersRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveAllOrdersResponse) => void): grpc.ClientUnaryCall; + removeAllOrders(request: xudrpc_pb.RemoveAllOrdersRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveAllOrdersResponse) => void): grpc.ClientUnaryCall; removePair(request: xudrpc_pb.RemovePairRequest, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemovePairResponse) => void): grpc.ClientUnaryCall; removePair(request: xudrpc_pb.RemovePairRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemovePairResponse) => void): grpc.ClientUnaryCall; removePair(request: xudrpc_pb.RemovePairRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemovePairResponse) => void): grpc.ClientUnaryCall; @@ -562,6 +576,9 @@ export class XudClient extends grpc.Client implements IXudClient { public removeOrder(request: xudrpc_pb.RemoveOrderRequest, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveOrderResponse) => void): grpc.ClientUnaryCall; public removeOrder(request: xudrpc_pb.RemoveOrderRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveOrderResponse) => void): grpc.ClientUnaryCall; public removeOrder(request: xudrpc_pb.RemoveOrderRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveOrderResponse) => void): grpc.ClientUnaryCall; + public removeAllOrders(request: xudrpc_pb.RemoveAllOrdersRequest, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveAllOrdersResponse) => void): grpc.ClientUnaryCall; + public removeAllOrders(request: xudrpc_pb.RemoveAllOrdersRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveAllOrdersResponse) => void): grpc.ClientUnaryCall; + public removeAllOrders(request: xudrpc_pb.RemoveAllOrdersRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemoveAllOrdersResponse) => void): grpc.ClientUnaryCall; public removePair(request: xudrpc_pb.RemovePairRequest, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemovePairResponse) => void): grpc.ClientUnaryCall; public removePair(request: xudrpc_pb.RemovePairRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemovePairResponse) => void): grpc.ClientUnaryCall; public removePair(request: xudrpc_pb.RemovePairRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: xudrpc_pb.RemovePairResponse) => void): grpc.ClientUnaryCall; diff --git a/lib/proto/xudrpc_grpc_pb.js b/lib/proto/xudrpc_grpc_pb.js index 203f92f44..df6d1f975 100644 --- a/lib/proto/xudrpc_grpc_pb.js +++ b/lib/proto/xudrpc_grpc_pb.js @@ -433,6 +433,28 @@ function deserialize_xudrpc_PlaceOrderResponse(buffer_arg) { return xudrpc_pb.PlaceOrderResponse.deserializeBinary(new Uint8Array(buffer_arg)); } +function serialize_xudrpc_RemoveAllOrdersRequest(arg) { + if (!(arg instanceof xudrpc_pb.RemoveAllOrdersRequest)) { + throw new Error('Expected argument of type xudrpc.RemoveAllOrdersRequest'); + } + return Buffer.from(arg.serializeBinary()); +} + +function deserialize_xudrpc_RemoveAllOrdersRequest(buffer_arg) { + return xudrpc_pb.RemoveAllOrdersRequest.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_xudrpc_RemoveAllOrdersResponse(arg) { + if (!(arg instanceof xudrpc_pb.RemoveAllOrdersResponse)) { + throw new Error('Expected argument of type xudrpc.RemoveAllOrdersResponse'); + } + return Buffer.from(arg.serializeBinary()); +} + +function deserialize_xudrpc_RemoveAllOrdersResponse(buffer_arg) { + return xudrpc_pb.RemoveAllOrdersResponse.deserializeBinary(new Uint8Array(buffer_arg)); +} + function serialize_xudrpc_RemoveCurrencyRequest(arg) { if (!(arg instanceof xudrpc_pb.RemoveCurrencyRequest)) { throw new Error('Expected argument of type xudrpc.RemoveCurrencyRequest'); @@ -1042,6 +1064,21 @@ var XudService = exports.XudService = { responseSerialize: serialize_xudrpc_RemoveOrderResponse, responseDeserialize: deserialize_xudrpc_RemoveOrderResponse, }, + // Removes all orders from the order book. Removed orders become immediately unavailable for swaps, + // and peers are notified that the orders are no longer valid. Any portion of the orders that is + // on hold due to ongoing swaps will not be removed until after the swap attempts complete. + // shell: xucli removeallorders + removeAllOrders: { + path: '/xudrpc.Xud/RemoveAllOrders', + requestStream: false, + responseStream: false, + requestType: xudrpc_pb.RemoveAllOrdersRequest, + responseType: xudrpc_pb.RemoveAllOrdersResponse, + requestSerialize: serialize_xudrpc_RemoveAllOrdersRequest, + requestDeserialize: deserialize_xudrpc_RemoveAllOrdersRequest, + responseSerialize: serialize_xudrpc_RemoveAllOrdersResponse, + responseDeserialize: deserialize_xudrpc_RemoveAllOrdersResponse, + }, // Removes a trading pair from the list of currently supported trading pair. This call will // effectively cancel any standing orders for that trading pair. Peers are informed when a pair // is no longer supported so that they will know to stop sending orders for it. diff --git a/lib/proto/xudrpc_pb.d.ts b/lib/proto/xudrpc_pb.d.ts index 65148b769..6f04fe0d4 100644 --- a/lib/proto/xudrpc_pb.d.ts +++ b/lib/proto/xudrpc_pb.d.ts @@ -1524,6 +1524,52 @@ export namespace RemoveOrderResponse { } } +export class RemoveAllOrdersRequest extends jspb.Message { + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RemoveAllOrdersRequest.AsObject; + static toObject(includeInstance: boolean, msg: RemoveAllOrdersRequest): RemoveAllOrdersRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: RemoveAllOrdersRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RemoveAllOrdersRequest; + static deserializeBinaryFromReader(message: RemoveAllOrdersRequest, reader: jspb.BinaryReader): RemoveAllOrdersRequest; +} + +export namespace RemoveAllOrdersRequest { + export type AsObject = { + } +} + +export class RemoveAllOrdersResponse extends jspb.Message { + clearRemovedOrderIdsList(): void; + getRemovedOrderIdsList(): Array; + setRemovedOrderIdsList(value: Array): void; + addRemovedOrderIds(value: string, index?: number): string; + + clearOnHoldOrderIdsList(): void; + getOnHoldOrderIdsList(): Array; + setOnHoldOrderIdsList(value: Array): void; + addOnHoldOrderIds(value: string, index?: number): string; + + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RemoveAllOrdersResponse.AsObject; + static toObject(includeInstance: boolean, msg: RemoveAllOrdersResponse): RemoveAllOrdersResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: RemoveAllOrdersResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RemoveAllOrdersResponse; + static deserializeBinaryFromReader(message: RemoveAllOrdersResponse, reader: jspb.BinaryReader): RemoveAllOrdersResponse; +} + +export namespace RemoveAllOrdersResponse { + export type AsObject = { + removedOrderIdsList: Array, + onHoldOrderIdsList: Array, + } +} + export class RemovePairRequest extends jspb.Message { getPairId(): string; setPairId(value: string): void; diff --git a/lib/proto/xudrpc_pb.js b/lib/proto/xudrpc_pb.js index 7f26f0e55..1284bc8e7 100644 --- a/lib/proto/xudrpc_pb.js +++ b/lib/proto/xudrpc_pb.js @@ -64,6 +64,8 @@ goog.exportSymbol('proto.xudrpc.Peer', null, global); goog.exportSymbol('proto.xudrpc.PlaceOrderEvent', null, global); goog.exportSymbol('proto.xudrpc.PlaceOrderRequest', null, global); goog.exportSymbol('proto.xudrpc.PlaceOrderResponse', null, global); +goog.exportSymbol('proto.xudrpc.RemoveAllOrdersRequest', null, global); +goog.exportSymbol('proto.xudrpc.RemoveAllOrdersResponse', null, global); goog.exportSymbol('proto.xudrpc.RemoveCurrencyRequest', null, global); goog.exportSymbol('proto.xudrpc.RemoveCurrencyResponse', null, global); goog.exportSymbol('proto.xudrpc.RemoveOrderRequest', null, global); @@ -10209,6 +10211,326 @@ proto.xudrpc.RemoveOrderResponse.prototype.setQuantityOnHold = function(value) { +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.xudrpc.RemoveAllOrdersRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.xudrpc.RemoveAllOrdersRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.xudrpc.RemoveAllOrdersRequest.displayName = 'proto.xudrpc.RemoveAllOrdersRequest'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.xudrpc.RemoveAllOrdersRequest.prototype.toObject = function(opt_includeInstance) { + return proto.xudrpc.RemoveAllOrdersRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.xudrpc.RemoveAllOrdersRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.xudrpc.RemoveAllOrdersRequest.toObject = function(includeInstance, msg) { + var f, obj = { + + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.xudrpc.RemoveAllOrdersRequest} + */ +proto.xudrpc.RemoveAllOrdersRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.xudrpc.RemoveAllOrdersRequest; + return proto.xudrpc.RemoveAllOrdersRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.xudrpc.RemoveAllOrdersRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.xudrpc.RemoveAllOrdersRequest} + */ +proto.xudrpc.RemoveAllOrdersRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.xudrpc.RemoveAllOrdersRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.xudrpc.RemoveAllOrdersRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.xudrpc.RemoveAllOrdersRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.xudrpc.RemoveAllOrdersRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.xudrpc.RemoveAllOrdersResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.xudrpc.RemoveAllOrdersResponse.repeatedFields_, null); +}; +goog.inherits(proto.xudrpc.RemoveAllOrdersResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.xudrpc.RemoveAllOrdersResponse.displayName = 'proto.xudrpc.RemoveAllOrdersResponse'; +} +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.xudrpc.RemoveAllOrdersResponse.repeatedFields_ = [1,2]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.xudrpc.RemoveAllOrdersResponse.prototype.toObject = function(opt_includeInstance) { + return proto.xudrpc.RemoveAllOrdersResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.xudrpc.RemoveAllOrdersResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.xudrpc.RemoveAllOrdersResponse.toObject = function(includeInstance, msg) { + var f, obj = { + removedOrderIdsList: jspb.Message.getRepeatedField(msg, 1), + onHoldOrderIdsList: jspb.Message.getRepeatedField(msg, 2) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.xudrpc.RemoveAllOrdersResponse} + */ +proto.xudrpc.RemoveAllOrdersResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.xudrpc.RemoveAllOrdersResponse; + return proto.xudrpc.RemoveAllOrdersResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.xudrpc.RemoveAllOrdersResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.xudrpc.RemoveAllOrdersResponse} + */ +proto.xudrpc.RemoveAllOrdersResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.addRemovedOrderIds(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.addOnHoldOrderIds(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.xudrpc.RemoveAllOrdersResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.xudrpc.RemoveAllOrdersResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.xudrpc.RemoveAllOrdersResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.xudrpc.RemoveAllOrdersResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getRemovedOrderIdsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 1, + f + ); + } + f = message.getOnHoldOrderIdsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 2, + f + ); + } +}; + + +/** + * repeated string removed_order_ids = 1; + * @return {!Array} + */ +proto.xudrpc.RemoveAllOrdersResponse.prototype.getRemovedOrderIdsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** @param {!Array} value */ +proto.xudrpc.RemoveAllOrdersResponse.prototype.setRemovedOrderIdsList = function(value) { + jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + */ +proto.xudrpc.RemoveAllOrdersResponse.prototype.addRemovedOrderIds = function(value, opt_index) { + jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +proto.xudrpc.RemoveAllOrdersResponse.prototype.clearRemovedOrderIdsList = function() { + this.setRemovedOrderIdsList([]); +}; + + +/** + * repeated string on_hold_order_ids = 2; + * @return {!Array} + */ +proto.xudrpc.RemoveAllOrdersResponse.prototype.getOnHoldOrderIdsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 2)); +}; + + +/** @param {!Array} value */ +proto.xudrpc.RemoveAllOrdersResponse.prototype.setOnHoldOrderIdsList = function(value) { + jspb.Message.setField(this, 2, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + */ +proto.xudrpc.RemoveAllOrdersResponse.prototype.addOnHoldOrderIds = function(value, opt_index) { + jspb.Message.addToRepeatedField(this, 2, value, opt_index); +}; + + +proto.xudrpc.RemoveAllOrdersResponse.prototype.clearOnHoldOrderIdsList = function() { + this.setOnHoldOrderIdsList([]); +}; + + + /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a diff --git a/lib/service/Service.ts b/lib/service/Service.ts index cddead02f..258097491 100644 --- a/lib/service/Service.ts +++ b/lib/service/Service.ts @@ -110,6 +110,13 @@ class Service { return this.orderBook.removeOwnOrderByLocalId(orderId, true, quantity); } + /* + * Removes all placed orders from the orderbook. + */ + public removeAllOrders = async () => { + return this.orderBook.removeOwnOrders(); + } + /** Gets the total balance for one or all currencies. */ public getBalance = async (args: { currency: string }) => { const { currency } = args; diff --git a/proto/xudrpc.proto b/proto/xudrpc.proto index 8fe161852..e9b533618 100644 --- a/proto/xudrpc.proto +++ b/proto/xudrpc.proto @@ -229,6 +229,17 @@ service Xud { }; } + /* Removes all orders from the order book. Removed orders become immediately unavailable for swaps, + * and peers are notified that the orders are no longer valid. Any portion of the orders that is + * on hold due to ongoing swaps will not be removed until after the swap attempts complete. + * shell: xucli removeallorders */ + rpc RemoveAllOrders(RemoveAllOrdersRequest) returns (RemoveAllOrdersResponse) { + option (google.api.http) = { + post: "/v1/removeallorders" + body: "*" + }; + } + /* Removes a trading pair from the list of currently supported trading pair. This call will * effectively cancel any standing orders for that trading pair. Peers are informed when a pair * is no longer supported so that they will know to stop sending orders for it. @@ -739,6 +750,15 @@ message RemoveOrderResponse { uint64 quantity_on_hold = 1 [json_name = "hold"]; } +message RemoveAllOrdersRequest {} + +message RemoveAllOrdersResponse { + // The local order ids that were successfully removed. + repeated string removed_order_ids = 1 [json_name = "removed_order_ids"]; + // The local order ids that were on hold and failed to be removed. + repeated string on_hold_order_ids = 2 [json_name = "on_hold_order_ids"]; +} + message RemovePairRequest { // The trading pair ticker to remove in a format such as "LTC/BTC". string pair_id = 1 [json_name = "pair_id"]; diff --git a/test/simulation/xudrpc/xudrpc.pb.go b/test/simulation/xudrpc/xudrpc.pb.go index 4fe981742..676335f08 100644 --- a/test/simulation/xudrpc/xudrpc.pb.go +++ b/test/simulation/xudrpc/xudrpc.pb.go @@ -2986,6 +2986,86 @@ func (m *RemoveOrderResponse) GetQuantityOnHold() uint64 { return 0 } +type RemoveAllOrdersRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveAllOrdersRequest) Reset() { *m = RemoveAllOrdersRequest{} } +func (m *RemoveAllOrdersRequest) String() string { return proto.CompactTextString(m) } +func (*RemoveAllOrdersRequest) ProtoMessage() {} +func (*RemoveAllOrdersRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6960a02cc0a63cf6, []int{52} +} + +func (m *RemoveAllOrdersRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveAllOrdersRequest.Unmarshal(m, b) +} +func (m *RemoveAllOrdersRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveAllOrdersRequest.Marshal(b, m, deterministic) +} +func (m *RemoveAllOrdersRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveAllOrdersRequest.Merge(m, src) +} +func (m *RemoveAllOrdersRequest) XXX_Size() int { + return xxx_messageInfo_RemoveAllOrdersRequest.Size(m) +} +func (m *RemoveAllOrdersRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveAllOrdersRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveAllOrdersRequest proto.InternalMessageInfo + +type RemoveAllOrdersResponse struct { + // The local order ids that were successfully removed. + RemovedOrderIds []string `protobuf:"bytes,1,rep,name=removed_order_ids,proto3" json:"removed_order_ids,omitempty"` + // The local order ids that were on hold and failed to be removed. + OnHoldOrderIds []string `protobuf:"bytes,2,rep,name=on_hold_order_ids,proto3" json:"on_hold_order_ids,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveAllOrdersResponse) Reset() { *m = RemoveAllOrdersResponse{} } +func (m *RemoveAllOrdersResponse) String() string { return proto.CompactTextString(m) } +func (*RemoveAllOrdersResponse) ProtoMessage() {} +func (*RemoveAllOrdersResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6960a02cc0a63cf6, []int{53} +} + +func (m *RemoveAllOrdersResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveAllOrdersResponse.Unmarshal(m, b) +} +func (m *RemoveAllOrdersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveAllOrdersResponse.Marshal(b, m, deterministic) +} +func (m *RemoveAllOrdersResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveAllOrdersResponse.Merge(m, src) +} +func (m *RemoveAllOrdersResponse) XXX_Size() int { + return xxx_messageInfo_RemoveAllOrdersResponse.Size(m) +} +func (m *RemoveAllOrdersResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveAllOrdersResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveAllOrdersResponse proto.InternalMessageInfo + +func (m *RemoveAllOrdersResponse) GetRemovedOrderIds() []string { + if m != nil { + return m.RemovedOrderIds + } + return nil +} + +func (m *RemoveAllOrdersResponse) GetOnHoldOrderIds() []string { + if m != nil { + return m.OnHoldOrderIds + } + return nil +} + type RemovePairRequest struct { // The trading pair ticker to remove in a format such as "LTC/BTC". PairId string `protobuf:"bytes,1,opt,name=pair_id,proto3" json:"pair_id,omitempty"` @@ -2998,7 +3078,7 @@ func (m *RemovePairRequest) Reset() { *m = RemovePairRequest{} } func (m *RemovePairRequest) String() string { return proto.CompactTextString(m) } func (*RemovePairRequest) ProtoMessage() {} func (*RemovePairRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{52} + return fileDescriptor_6960a02cc0a63cf6, []int{54} } func (m *RemovePairRequest) XXX_Unmarshal(b []byte) error { @@ -3036,7 +3116,7 @@ func (m *RemovePairResponse) Reset() { *m = RemovePairResponse{} } func (m *RemovePairResponse) String() string { return proto.CompactTextString(m) } func (*RemovePairResponse) ProtoMessage() {} func (*RemovePairResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{53} + return fileDescriptor_6960a02cc0a63cf6, []int{55} } func (m *RemovePairResponse) XXX_Unmarshal(b []byte) error { @@ -3076,7 +3156,7 @@ func (m *RestoreNodeRequest) Reset() { *m = RestoreNodeRequest{} } func (m *RestoreNodeRequest) String() string { return proto.CompactTextString(m) } func (*RestoreNodeRequest) ProtoMessage() {} func (*RestoreNodeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{54} + return fileDescriptor_6960a02cc0a63cf6, []int{56} } func (m *RestoreNodeRequest) XXX_Unmarshal(b []byte) error { @@ -3139,7 +3219,7 @@ func (m *RestoreNodeResponse) Reset() { *m = RestoreNodeResponse{} } func (m *RestoreNodeResponse) String() string { return proto.CompactTextString(m) } func (*RestoreNodeResponse) ProtoMessage() {} func (*RestoreNodeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{55} + return fileDescriptor_6960a02cc0a63cf6, []int{57} } func (m *RestoreNodeResponse) XXX_Unmarshal(b []byte) error { @@ -3184,7 +3264,7 @@ func (m *ShutdownRequest) Reset() { *m = ShutdownRequest{} } func (m *ShutdownRequest) String() string { return proto.CompactTextString(m) } func (*ShutdownRequest) ProtoMessage() {} func (*ShutdownRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{56} + return fileDescriptor_6960a02cc0a63cf6, []int{58} } func (m *ShutdownRequest) XXX_Unmarshal(b []byte) error { @@ -3215,7 +3295,7 @@ func (m *ShutdownResponse) Reset() { *m = ShutdownResponse{} } func (m *ShutdownResponse) String() string { return proto.CompactTextString(m) } func (*ShutdownResponse) ProtoMessage() {} func (*ShutdownResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{57} + return fileDescriptor_6960a02cc0a63cf6, []int{59} } func (m *ShutdownResponse) XXX_Unmarshal(b []byte) error { @@ -3248,7 +3328,7 @@ func (m *SubscribeOrdersRequest) Reset() { *m = SubscribeOrdersRequest{} func (m *SubscribeOrdersRequest) String() string { return proto.CompactTextString(m) } func (*SubscribeOrdersRequest) ProtoMessage() {} func (*SubscribeOrdersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{58} + return fileDescriptor_6960a02cc0a63cf6, []int{60} } func (m *SubscribeOrdersRequest) XXX_Unmarshal(b []byte) error { @@ -3286,7 +3366,7 @@ func (m *SubscribeSwapsAcceptedRequest) Reset() { *m = SubscribeSwapsAcc func (m *SubscribeSwapsAcceptedRequest) String() string { return proto.CompactTextString(m) } func (*SubscribeSwapsAcceptedRequest) ProtoMessage() {} func (*SubscribeSwapsAcceptedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{59} + return fileDescriptor_6960a02cc0a63cf6, []int{61} } func (m *SubscribeSwapsAcceptedRequest) XXX_Unmarshal(b []byte) error { @@ -3320,7 +3400,7 @@ func (m *SubscribeSwapsRequest) Reset() { *m = SubscribeSwapsRequest{} } func (m *SubscribeSwapsRequest) String() string { return proto.CompactTextString(m) } func (*SubscribeSwapsRequest) ProtoMessage() {} func (*SubscribeSwapsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{60} + return fileDescriptor_6960a02cc0a63cf6, []int{62} } func (m *SubscribeSwapsRequest) XXX_Unmarshal(b []byte) error { @@ -3380,7 +3460,7 @@ func (m *SwapAccepted) Reset() { *m = SwapAccepted{} } func (m *SwapAccepted) String() string { return proto.CompactTextString(m) } func (*SwapAccepted) ProtoMessage() {} func (*SwapAccepted) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{61} + return fileDescriptor_6960a02cc0a63cf6, []int{63} } func (m *SwapAccepted) XXX_Unmarshal(b []byte) error { @@ -3498,7 +3578,7 @@ func (m *SwapFailure) Reset() { *m = SwapFailure{} } func (m *SwapFailure) String() string { return proto.CompactTextString(m) } func (*SwapFailure) ProtoMessage() {} func (*SwapFailure) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{62} + return fileDescriptor_6960a02cc0a63cf6, []int{64} } func (m *SwapFailure) XXX_Unmarshal(b []byte) error { @@ -3590,7 +3670,7 @@ func (m *SwapSuccess) Reset() { *m = SwapSuccess{} } func (m *SwapSuccess) String() string { return proto.CompactTextString(m) } func (*SwapSuccess) ProtoMessage() {} func (*SwapSuccess) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{63} + return fileDescriptor_6960a02cc0a63cf6, []int{65} } func (m *SwapSuccess) XXX_Unmarshal(b []byte) error { @@ -3734,7 +3814,7 @@ func (m *Trade) Reset() { *m = Trade{} } func (m *Trade) String() string { return proto.CompactTextString(m) } func (*Trade) ProtoMessage() {} func (*Trade) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{64} + return fileDescriptor_6960a02cc0a63cf6, []int{66} } func (m *Trade) XXX_Unmarshal(b []byte) error { @@ -3837,7 +3917,7 @@ func (m *TradeHistoryRequest) Reset() { *m = TradeHistoryRequest{} } func (m *TradeHistoryRequest) String() string { return proto.CompactTextString(m) } func (*TradeHistoryRequest) ProtoMessage() {} func (*TradeHistoryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{65} + return fileDescriptor_6960a02cc0a63cf6, []int{67} } func (m *TradeHistoryRequest) XXX_Unmarshal(b []byte) error { @@ -3876,7 +3956,7 @@ func (m *TradeHistoryResponse) Reset() { *m = TradeHistoryResponse{} } func (m *TradeHistoryResponse) String() string { return proto.CompactTextString(m) } func (*TradeHistoryResponse) ProtoMessage() {} func (*TradeHistoryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{66} + return fileDescriptor_6960a02cc0a63cf6, []int{68} } func (m *TradeHistoryResponse) XXX_Unmarshal(b []byte) error { @@ -3922,7 +4002,7 @@ func (m *TradingLimits) Reset() { *m = TradingLimits{} } func (m *TradingLimits) String() string { return proto.CompactTextString(m) } func (*TradingLimits) ProtoMessage() {} func (*TradingLimits) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{67} + return fileDescriptor_6960a02cc0a63cf6, []int{69} } func (m *TradingLimits) XXX_Unmarshal(b []byte) error { @@ -3984,7 +4064,7 @@ func (m *TradingLimitsRequest) Reset() { *m = TradingLimitsRequest{} } func (m *TradingLimitsRequest) String() string { return proto.CompactTextString(m) } func (*TradingLimitsRequest) ProtoMessage() {} func (*TradingLimitsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{68} + return fileDescriptor_6960a02cc0a63cf6, []int{70} } func (m *TradingLimitsRequest) XXX_Unmarshal(b []byte) error { @@ -4024,7 +4104,7 @@ func (m *TradingLimitsResponse) Reset() { *m = TradingLimitsResponse{} } func (m *TradingLimitsResponse) String() string { return proto.CompactTextString(m) } func (*TradingLimitsResponse) ProtoMessage() {} func (*TradingLimitsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{69} + return fileDescriptor_6960a02cc0a63cf6, []int{71} } func (m *TradingLimitsResponse) XXX_Unmarshal(b []byte) error { @@ -4066,7 +4146,7 @@ func (m *UnbanRequest) Reset() { *m = UnbanRequest{} } func (m *UnbanRequest) String() string { return proto.CompactTextString(m) } func (*UnbanRequest) ProtoMessage() {} func (*UnbanRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{70} + return fileDescriptor_6960a02cc0a63cf6, []int{72} } func (m *UnbanRequest) XXX_Unmarshal(b []byte) error { @@ -4111,7 +4191,7 @@ func (m *UnbanResponse) Reset() { *m = UnbanResponse{} } func (m *UnbanResponse) String() string { return proto.CompactTextString(m) } func (*UnbanResponse) ProtoMessage() {} func (*UnbanResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{71} + return fileDescriptor_6960a02cc0a63cf6, []int{73} } func (m *UnbanResponse) XXX_Unmarshal(b []byte) error { @@ -4145,7 +4225,7 @@ func (m *UnlockNodeRequest) Reset() { *m = UnlockNodeRequest{} } func (m *UnlockNodeRequest) String() string { return proto.CompactTextString(m) } func (*UnlockNodeRequest) ProtoMessage() {} func (*UnlockNodeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{72} + return fileDescriptor_6960a02cc0a63cf6, []int{74} } func (m *UnlockNodeRequest) XXX_Unmarshal(b []byte) error { @@ -4187,7 +4267,7 @@ func (m *UnlockNodeResponse) Reset() { *m = UnlockNodeResponse{} } func (m *UnlockNodeResponse) String() string { return proto.CompactTextString(m) } func (*UnlockNodeResponse) ProtoMessage() {} func (*UnlockNodeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{73} + return fileDescriptor_6960a02cc0a63cf6, []int{75} } func (m *UnlockNodeResponse) XXX_Unmarshal(b []byte) error { @@ -4243,7 +4323,7 @@ func (m *WithdrawRequest) Reset() { *m = WithdrawRequest{} } func (m *WithdrawRequest) String() string { return proto.CompactTextString(m) } func (*WithdrawRequest) ProtoMessage() {} func (*WithdrawRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{74} + return fileDescriptor_6960a02cc0a63cf6, []int{76} } func (m *WithdrawRequest) XXX_Unmarshal(b []byte) error { @@ -4311,7 +4391,7 @@ func (m *WithdrawResponse) Reset() { *m = WithdrawResponse{} } func (m *WithdrawResponse) String() string { return proto.CompactTextString(m) } func (*WithdrawResponse) ProtoMessage() {} func (*WithdrawResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6960a02cc0a63cf6, []int{75} + return fileDescriptor_6960a02cc0a63cf6, []int{77} } func (m *WithdrawResponse) XXX_Unmarshal(b []byte) error { @@ -4400,6 +4480,8 @@ func init() { proto.RegisterType((*RemoveCurrencyResponse)(nil), "xudrpc.RemoveCurrencyResponse") proto.RegisterType((*RemoveOrderRequest)(nil), "xudrpc.RemoveOrderRequest") proto.RegisterType((*RemoveOrderResponse)(nil), "xudrpc.RemoveOrderResponse") + proto.RegisterType((*RemoveAllOrdersRequest)(nil), "xudrpc.RemoveAllOrdersRequest") + proto.RegisterType((*RemoveAllOrdersResponse)(nil), "xudrpc.RemoveAllOrdersResponse") proto.RegisterType((*RemovePairRequest)(nil), "xudrpc.RemovePairRequest") proto.RegisterType((*RemovePairResponse)(nil), "xudrpc.RemovePairResponse") proto.RegisterType((*RestoreNodeRequest)(nil), "xudrpc.RestoreNodeRequest") @@ -4431,248 +4513,252 @@ func init() { func init() { proto.RegisterFile("xudrpc.proto", fileDescriptor_6960a02cc0a63cf6) } var fileDescriptor_6960a02cc0a63cf6 = []byte{ - // 3843 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3a, 0x4d, 0x8f, 0x1d, 0xc7, - 0x56, 0xd3, 0xf7, 0xce, 0x9d, 0x7b, 0xe7, 0xdc, 0xcf, 0xa9, 0xf9, 0xf0, 0xf8, 0xc6, 0x49, 0xfc, - 0x8a, 0x38, 0x72, 0xec, 0xc4, 0x36, 0x13, 0x42, 0x5e, 0x0c, 0x8e, 0xe2, 0x19, 0x0f, 0xb1, 0x93, - 0x79, 0xb6, 0xd5, 0xe3, 0xbc, 0x98, 0x27, 0x48, 0xab, 0x6f, 0x77, 0x79, 0xa6, 0x71, 0x4f, 0xf7, - 0x4d, 0x7f, 0xcc, 0x78, 0x60, 0x83, 0x9e, 0x58, 0xc1, 0x12, 0xb1, 0x86, 0x15, 0x42, 0x02, 0xb1, - 0x45, 0x2c, 0x90, 0x58, 0xb3, 0x65, 0x81, 0x04, 0x6c, 0x90, 0xf8, 0x05, 0x88, 0x2d, 0x12, 0x3a, - 0xf5, 0xd1, 0x5d, 0xd5, 0xdd, 0x77, 0x9e, 0x1d, 0xc1, 0xdb, 0x75, 0x9d, 0x3a, 0x75, 0xaa, 0xce, - 0x47, 0x9d, 0x3a, 0x1f, 0x0d, 0x83, 0x57, 0xb9, 0x9f, 0xcc, 0xbd, 0x5b, 0xf3, 0x24, 0xce, 0x62, - 0xb2, 0x22, 0x46, 0xd3, 0x35, 0x37, 0x8a, 0xe2, 0xcc, 0xcd, 0x82, 0x38, 0x4a, 0xc5, 0x14, 0xdd, - 0x84, 0xf5, 0xfb, 0xbe, 0xbf, 0x97, 0x27, 0x09, 0x8b, 0xbc, 0x73, 0x9b, 0xa5, 0xf3, 0x38, 0x4a, - 0x19, 0xfd, 0x0e, 0x46, 0xf7, 0x7d, 0xff, 0xa9, 0x1b, 0x24, 0x36, 0xfb, 0x3e, 0x67, 0x69, 0x46, - 0xde, 0x83, 0xe1, 0xcc, 0x4d, 0x99, 0xe3, 0x49, 0xd4, 0x6d, 0xeb, 0xaa, 0x75, 0x7d, 0xd5, 0x36, - 0x81, 0xe4, 0x7d, 0x18, 0x7d, 0x9f, 0xc7, 0x99, 0x86, 0xd6, 0xe2, 0x68, 0x15, 0x28, 0x5d, 0x83, - 0x71, 0x41, 0x5f, 0x6e, 0xf9, 0x77, 0x2d, 0xe8, 0xee, 0xba, 0xa1, 0x1b, 0x79, 0x0c, 0x37, 0xcb, - 0xe2, 0xcc, 0x0d, 0x9d, 0x99, 0x00, 0xf0, 0xcd, 0x96, 0x6d, 0x13, 0x48, 0xae, 0xc3, 0xd8, 0x3b, - 0x76, 0xa3, 0x88, 0x95, 0x78, 0x2d, 0x8e, 0x57, 0x05, 0x93, 0x1f, 0xc3, 0xa5, 0x39, 0x8b, 0xfc, - 0x20, 0x3a, 0x72, 0xaa, 0x2b, 0xda, 0x7c, 0xc5, 0xa2, 0x69, 0x72, 0x17, 0xb6, 0x83, 0xc8, 0xf5, - 0xb2, 0xe0, 0x94, 0xd5, 0x96, 0x2e, 0xf3, 0xa5, 0x0b, 0xe7, 0x51, 0x18, 0x67, 0x6e, 0x18, 0xb2, - 0xac, 0x58, 0xd1, 0xe1, 0x2b, 0x2a, 0x50, 0xf2, 0x39, 0x4c, 0xf3, 0xc8, 0x8b, 0xa3, 0x17, 0x41, - 0x72, 0xc2, 0x7c, 0xa7, 0xb2, 0x66, 0x85, 0xaf, 0xb9, 0x00, 0x83, 0xfe, 0x3a, 0xc0, 0xae, 0x1b, - 0x29, 0x45, 0x5d, 0x87, 0x71, 0x14, 0xfb, 0xcc, 0x09, 0x7c, 0x16, 0x65, 0xc1, 0x8b, 0x80, 0x25, - 0x52, 0x55, 0x55, 0x30, 0x1d, 0x42, 0x9f, 0xaf, 0x93, 0x0a, 0xf8, 0x14, 0x3a, 0x7b, 0xc7, 0x6e, - 0x10, 0x91, 0x0d, 0xe8, 0x78, 0xf8, 0x21, 0xd7, 0x89, 0x01, 0xd9, 0x86, 0x6e, 0xc4, 0xb2, 0xb3, - 0x38, 0x79, 0x29, 0x75, 0xaa, 0x86, 0x74, 0x0e, 0xbd, 0x3d, 0xc1, 0x7a, 0x4a, 0xb6, 0x60, 0x45, - 0x48, 0x83, 0x2f, 0x1e, 0xda, 0x72, 0x44, 0xa6, 0xd0, 0x53, 0x72, 0xe2, 0xcb, 0x87, 0x76, 0x31, - 0x46, 0xca, 0x52, 0xfc, 0x5c, 0x1b, 0x43, 0x5b, 0x0d, 0x91, 0x9a, 0x17, 0xc6, 0x29, 0xf3, 0xb9, - 0xac, 0x87, 0xb6, 0x1c, 0xd1, 0x7f, 0xb0, 0x60, 0x7d, 0x0f, 0x3f, 0xe5, 0xbe, 0x6f, 0xcc, 0x3b, - 0x9e, 0xa7, 0x62, 0xa2, 0xc5, 0x18, 0xf9, 0x7f, 0x11, 0x27, 0xd2, 0x36, 0x7a, 0xb6, 0x18, 0x90, - 0xab, 0xd0, 0xf7, 0x59, 0x9a, 0x05, 0x11, 0xbf, 0x3f, 0xfc, 0x40, 0xab, 0xb6, 0x0e, 0xe2, 0xbc, - 0x9f, 0xc4, 0x79, 0x94, 0x49, 0x3d, 0xcb, 0x11, 0x99, 0x40, 0xfb, 0x05, 0x53, 0x8a, 0xc4, 0x4f, - 0xfa, 0x05, 0x6c, 0x98, 0xc7, 0x17, 0x2a, 0xc0, 0xf3, 0x67, 0x89, 0x1b, 0xa5, 0x28, 0x98, 0x38, - 0x72, 0x02, 0x3f, 0xdd, 0xb6, 0xae, 0xb6, 0xf1, 0xfc, 0x15, 0x30, 0xfd, 0x10, 0x46, 0x7b, 0x71, - 0x14, 0x31, 0x2f, 0x53, 0xbc, 0x4f, 0xa1, 0xc7, 0x99, 0xcc, 0x93, 0x40, 0x32, 0x5d, 0x8c, 0xf1, - 0xba, 0x15, 0xd8, 0x52, 0xdb, 0xb7, 0x61, 0x6d, 0x2f, 0x61, 0x6e, 0xc6, 0x1e, 0xc7, 0x3e, 0xd3, - 0x68, 0xcc, 0xdd, 0x34, 0x3d, 0x8b, 0x13, 0x5f, 0xd1, 0x50, 0x63, 0xfa, 0x67, 0x16, 0x10, 0x7d, - 0x85, 0x3c, 0xf2, 0xaf, 0xc0, 0x30, 0x65, 0xcc, 0x77, 0x4e, 0x22, 0x76, 0x12, 0x47, 0x81, 0x27, - 0x0f, 0x3c, 0x40, 0xe0, 0x4f, 0x24, 0x8c, 0x7c, 0x00, 0x93, 0x20, 0x0a, 0xb2, 0xc0, 0x0d, 0x83, - 0xdf, 0x67, 0xbe, 0x13, 0x46, 0x7e, 0xba, 0xdd, 0x12, 0x8c, 0x69, 0xf0, 0x83, 0xc8, 0x4f, 0xc9, - 0x6d, 0x58, 0xd7, 0x51, 0x3d, 0x3c, 0xf6, 0xab, 0x4c, 0xaa, 0x82, 0x68, 0x53, 0x7b, 0x62, 0x86, - 0xfe, 0x8b, 0x05, 0x3d, 0xe5, 0xbf, 0x0c, 0xb5, 0x5a, 0x15, 0xb5, 0xde, 0x83, 0x7e, 0x7a, 0xe6, - 0xce, 0x1d, 0x2f, 0x0c, 0x58, 0x94, 0x71, 0xad, 0x8f, 0x76, 0xde, 0xba, 0x25, 0x3d, 0xa5, 0x22, - 0x71, 0xeb, 0xf0, 0xcc, 0x9d, 0xef, 0x71, 0x14, 0x5b, 0xc7, 0x17, 0x3e, 0xe9, 0x25, 0x8b, 0x1c, - 0xd7, 0xf7, 0x13, 0x96, 0xa6, 0xfc, 0x48, 0xab, 0xb6, 0x09, 0xc4, 0x3b, 0xef, 0x33, 0x2f, 0x38, - 0x71, 0x43, 0x67, 0x1e, 0xba, 0x1e, 0x4b, 0xa5, 0xe5, 0x56, 0xa0, 0x94, 0x02, 0x94, 0x1b, 0x91, - 0x2e, 0xb4, 0x0f, 0x1e, 0x3f, 0x98, 0x2c, 0x91, 0x3e, 0x74, 0xf7, 0x9e, 0x3c, 0x7e, 0xbc, 0xff, - 0xfc, 0xd9, 0xa4, 0x85, 0x3a, 0x7e, 0xc0, 0xe6, 0x71, 0x1a, 0xe8, 0x3a, 0x5e, 0xc4, 0x1e, 0xbd, - 0x09, 0xe3, 0x02, 0x5b, 0xea, 0x66, 0x1b, 0xba, 0xea, 0xb0, 0x02, 0x5b, 0x0d, 0xd1, 0x00, 0x1f, - 0x04, 0xa9, 0x17, 0x9f, 0xb2, 0x04, 0xb5, 0x99, 0xbe, 0xb9, 0xf3, 0xf8, 0x04, 0x36, 0x2b, 0x14, - 0xe4, 0xa6, 0x57, 0x60, 0x35, 0xca, 0x4f, 0x1c, 0xc4, 0x4f, 0xa5, 0x13, 0x28, 0x01, 0xf4, 0x8f, - 0x2d, 0x20, 0xfb, 0xaf, 0x98, 0x97, 0x67, 0x0c, 0xf9, 0xd7, 0x18, 0x8b, 0x13, 0x9f, 0x25, 0x4e, - 0x50, 0x18, 0x9e, 0x1a, 0x73, 0xf7, 0xe0, 0x06, 0x7c, 0x4a, 0x3a, 0x1e, 0x39, 0x24, 0x14, 0x06, - 0x73, 0xc6, 0x12, 0x67, 0x9e, 0xcf, 0x9c, 0x97, 0xec, 0x5c, 0x6a, 0xc4, 0x80, 0x21, 0xe5, 0xef, - 0x73, 0x37, 0xca, 0x82, 0xec, 0x5c, 0x3a, 0xec, 0x62, 0x8c, 0x77, 0xe0, 0x4b, 0x96, 0xc9, 0x47, - 0xe7, 0x75, 0x64, 0xfc, 0x57, 0x16, 0x10, 0x7d, 0x85, 0x64, 0xf9, 0x01, 0xf4, 0xa4, 0x2f, 0x16, - 0xf7, 0xb5, 0xbf, 0x73, 0x5d, 0x99, 0x55, 0x1d, 0xfb, 0x96, 0x1c, 0xa7, 0xfb, 0x51, 0x96, 0x9c, - 0xdb, 0xc5, 0xca, 0xe9, 0x01, 0x0c, 0x8d, 0x29, 0xf4, 0x1b, 0xc8, 0x95, 0x38, 0x04, 0x7e, 0x92, - 0x6b, 0xd0, 0x39, 0x75, 0xc3, 0x5c, 0xb8, 0xd0, 0xfe, 0xce, 0x58, 0xed, 0xa2, 0xb6, 0x10, 0xb3, - 0x77, 0x5b, 0x3f, 0xb6, 0xe8, 0x04, 0x46, 0x5f, 0xb2, 0xec, 0x51, 0xf4, 0x22, 0x96, 0x8c, 0xd1, - 0x7f, 0x6d, 0xc3, 0xb8, 0x00, 0x95, 0x16, 0x72, 0xca, 0x92, 0x14, 0x1d, 0x9a, 0xb4, 0x10, 0x39, - 0x44, 0xd9, 0x72, 0x95, 0x2b, 0xd9, 0x0a, 0xd1, 0x1b, 0x30, 0x42, 0x60, 0x39, 0x4f, 0x02, 0xbc, - 0x09, 0x78, 0x95, 0xf9, 0xb7, 0x52, 0x3f, 0xea, 0x40, 0xd9, 0x7e, 0x09, 0x28, 0x66, 0xdd, 0x20, - 0x49, 0xb9, 0x97, 0x54, 0xb3, 0x08, 0x20, 0x37, 0x61, 0x85, 0x6b, 0x3d, 0xe5, 0xbe, 0xb2, 0xbf, - 0xb3, 0xae, 0xf8, 0x7b, 0xc2, 0xa1, 0x7b, 0xe8, 0x4d, 0x6d, 0x89, 0x42, 0x76, 0xa0, 0x1d, 0x46, - 0xfe, 0x76, 0x97, 0xcb, 0xfb, 0xaa, 0x26, 0x6f, 0x9d, 0xc1, 0x5b, 0x07, 0x91, 0x2f, 0xe4, 0x8c, - 0xc8, 0xe8, 0xd9, 0xdd, 0x30, 0x70, 0xd3, 0xed, 0x55, 0xf1, 0xb2, 0xf1, 0x81, 0xfe, 0xb2, 0x81, - 0xf1, 0xb2, 0x91, 0x3b, 0xb0, 0xae, 0x02, 0x03, 0xee, 0x0a, 0x8e, 0xdd, 0xf4, 0x98, 0xa5, 0xdb, - 0x7d, 0xce, 0x6f, 0xd3, 0x14, 0xf9, 0x08, 0xba, 0xca, 0x65, 0x0d, 0x4c, 0x1e, 0xa4, 0xbf, 0xe2, - 0xa7, 0x53, 0x38, 0xd3, 0x2f, 0xa1, 0xa7, 0x4e, 0xf8, 0x06, 0xea, 0x3e, 0x88, 0x7c, 0x4e, 0x46, - 0x53, 0xf7, 0xe7, 0xdc, 0x30, 0xf1, 0x26, 0x6a, 0x2a, 0x7f, 0x83, 0xeb, 0x6c, 0xc3, 0xba, 0xb1, - 0xbe, 0xf0, 0xee, 0xe3, 0x84, 0xcd, 0x73, 0x11, 0x33, 0x1e, 0x7a, 0x71, 0x22, 0xde, 0xf5, 0x35, - 0x1b, 0x4a, 0x30, 0xbe, 0x7b, 0x33, 0x7c, 0xc7, 0xc4, 0xfd, 0xec, 0xd9, 0x72, 0x44, 0x2f, 0xc1, - 0xe6, 0x41, 0x90, 0x66, 0xd2, 0xb3, 0x06, 0x85, 0x97, 0xa1, 0x5f, 0xc1, 0x56, 0x75, 0x42, 0xee, - 0x77, 0x07, 0xc0, 0x2b, 0xa0, 0xf2, 0x2e, 0x4d, 0xaa, 0x2e, 0xda, 0xd6, 0x70, 0xe8, 0x3f, 0x59, - 0xb0, 0x86, 0xc4, 0x84, 0x89, 0x28, 0xc6, 0x35, 0x9f, 0x61, 0x99, 0x3e, 0xe3, 0x13, 0xe8, 0xc4, - 0x67, 0x11, 0x4b, 0xa4, 0xff, 0x7f, 0xb7, 0x90, 0x69, 0x95, 0xc6, 0xad, 0x27, 0x88, 0x66, 0x0b, - 0x6c, 0xb4, 0x9c, 0x30, 0x38, 0x09, 0x32, 0x19, 0xa1, 0x88, 0x01, 0xca, 0x37, 0x88, 0xbc, 0x30, - 0xf7, 0x99, 0xc3, 0x4d, 0x49, 0xba, 0xfb, 0x9e, 0x5d, 0x05, 0xd3, 0xf7, 0xa0, 0xc3, 0xe9, 0x91, - 0x1e, 0x2c, 0xef, 0x3e, 0x79, 0xf6, 0x70, 0xb2, 0x84, 0x4e, 0xff, 0xc9, 0xb7, 0x8f, 0x27, 0x16, - 0x82, 0x9e, 0xee, 0xef, 0xdb, 0x93, 0x16, 0xfd, 0x73, 0x0b, 0x88, 0x7e, 0x10, 0x29, 0x95, 0xcf, - 0x8b, 0x7b, 0x21, 0x24, 0xf2, 0x7e, 0xd3, 0xa1, 0xa5, 0xc1, 0x8b, 0xa1, 0xb0, 0x79, 0xb9, 0x6a, - 0xfa, 0x08, 0xfa, 0x1a, 0xb8, 0xc1, 0xd0, 0xde, 0x33, 0x0d, 0x6d, 0x64, 0xde, 0x3b, 0xdd, 0xce, - 0x08, 0x4c, 0x70, 0x53, 0x8c, 0xdc, 0x0b, 0x75, 0x7e, 0x20, 0x34, 0x20, 0x61, 0xf2, 0xcc, 0x1b, - 0xd0, 0x11, 0xb7, 0x5c, 0xc4, 0x03, 0x62, 0x50, 0x2c, 0x67, 0xa5, 0x9c, 0xe9, 0xa7, 0x72, 0x39, - 0xd3, 0x59, 0xa6, 0xd0, 0x11, 0x2e, 0x44, 0x70, 0x3c, 0x50, 0x27, 0x42, 0x2c, 0x5b, 0x4c, 0xd1, - 0x7f, 0xb7, 0xa0, 0x2b, 0xaf, 0x02, 0xda, 0x60, 0x9a, 0xb9, 0x59, 0xae, 0x5e, 0x3a, 0x39, 0x22, - 0x1f, 0x42, 0x4f, 0x86, 0xe5, 0xa9, 0x64, 0xae, 0x34, 0x27, 0x09, 0xb7, 0x0b, 0x0c, 0x72, 0x0d, - 0x56, 0x78, 0xb0, 0x2b, 0x5c, 0x5a, 0x7f, 0x67, 0xa8, 0xe1, 0x06, 0x91, 0x2d, 0x27, 0x31, 0x14, - 0x9c, 0x85, 0xb1, 0xf7, 0xf2, 0x98, 0x05, 0x47, 0xc7, 0x99, 0xf4, 0x72, 0x3a, 0xa8, 0xf0, 0x8c, - 0x1d, 0xcd, 0x33, 0x6a, 0xbe, 0x76, 0xc5, 0xf4, 0xb5, 0x85, 0x5b, 0xea, 0x6a, 0x6e, 0x89, 0x7e, - 0x05, 0x23, 0x7e, 0x1f, 0xcb, 0xa0, 0xb5, 0xea, 0x93, 0xad, 0x06, 0x9f, 0x5c, 0xd0, 0x6a, 0xe9, - 0xb4, 0xfe, 0xd2, 0x02, 0xf2, 0x64, 0xce, 0xa2, 0xff, 0x97, 0x78, 0xb9, 0x8c, 0x7b, 0xdb, 0x46, - 0xdc, 0x7b, 0x15, 0xfa, 0xf3, 0x3c, 0x3d, 0x76, 0xe4, 0xa4, 0x78, 0x7d, 0x75, 0x90, 0x8a, 0x8c, - 0x3b, 0x65, 0x64, 0x7c, 0x0f, 0xd6, 0x8d, 0x73, 0x4a, 0x73, 0x78, 0x1f, 0x46, 0x66, 0x04, 0x2c, - 0xcf, 0x59, 0x81, 0xd2, 0x7f, 0x6c, 0x41, 0x87, 0x1b, 0x2d, 0xb7, 0xbf, 0x24, 0x90, 0xa9, 0xa3, - 0x65, 0x8b, 0x81, 0x11, 0x0d, 0xb4, 0xcc, 0x68, 0x40, 0xf7, 0x19, 0x6d, 0xd3, 0x67, 0x8c, 0xa0, - 0x15, 0xf8, 0x32, 0xe2, 0x6f, 0x05, 0x3e, 0xf9, 0xa2, 0x2e, 0xb6, 0x0e, 0xb7, 0xad, 0x2d, 0x65, - 0x2f, 0xa6, 0xe2, 0x1a, 0xc5, 0x19, 0xc6, 0x9e, 0x1b, 0xe2, 0x66, 0xc2, 0x18, 0x8a, 0x31, 0x79, - 0x07, 0xc0, 0xe3, 0x71, 0xb6, 0xef, 0xb8, 0x19, 0x37, 0x89, 0x65, 0x5b, 0x83, 0x90, 0x6b, 0xb0, - 0x9c, 0x06, 0x3e, 0xdb, 0xee, 0x71, 0x07, 0xb6, 0x66, 0xdc, 0xd5, 0xc3, 0xc0, 0x67, 0x36, 0x9f, - 0x46, 0x63, 0x09, 0x52, 0x27, 0x3e, 0x8b, 0x1c, 0xee, 0x05, 0xf8, 0x93, 0xd7, 0xb3, 0x0d, 0x18, - 0x9a, 0xe9, 0x71, 0x1c, 0xfa, 0xfc, 0xd9, 0x5b, 0xb6, 0xf9, 0x37, 0xfd, 0x0b, 0x0b, 0x06, 0x9c, - 0x96, 0xcd, 0x4e, 0xe2, 0x53, 0x37, 0x34, 0x64, 0x66, 0x2d, 0x96, 0x59, 0x25, 0x36, 0xd3, 0x23, - 0xba, 0x76, 0x25, 0xa2, 0xd3, 0xb9, 0x5f, 0xae, 0x70, 0x5f, 0x3d, 0x76, 0xa7, 0x7e, 0x6c, 0x7a, - 0x0c, 0x2b, 0xc2, 0x33, 0x91, 0x8f, 0x00, 0x66, 0xf9, 0xb9, 0x63, 0x78, 0xc7, 0xa1, 0x21, 0x11, - 0x5b, 0x43, 0x20, 0xb7, 0xa1, 0x9f, 0xb2, 0x30, 0x54, 0xf8, 0xad, 0x26, 0x7c, 0x1d, 0x83, 0x7e, - 0xac, 0x3c, 0x27, 0x8f, 0x3d, 0x50, 0x5e, 0xe8, 0x7a, 0x64, 0x58, 0xcb, 0xbf, 0xd1, 0x86, 0xe3, - 0xb3, 0x48, 0x26, 0xb5, 0xf8, 0x49, 0x7f, 0x6e, 0xc9, 0x55, 0xdf, 0xcc, 0x7d, 0x37, 0x63, 0xf8, - 0x8c, 0x0b, 0x5e, 0x2c, 0x6e, 0x24, 0xe6, 0x7e, 0x0f, 0x97, 0x6c, 0x31, 0x4b, 0x7e, 0x13, 0x86, - 0x42, 0x42, 0x89, 0x10, 0xbc, 0xf4, 0x57, 0x1b, 0xe6, 0xf1, 0xc4, 0xdc, 0xc3, 0x25, 0xdb, 0x44, - 0xde, 0x1d, 0xc1, 0x40, 0x00, 0x72, 0xbe, 0x29, 0xfd, 0xb7, 0x16, 0x2c, 0xa3, 0xb3, 0x5c, 0x9c, - 0x04, 0xbc, 0x56, 0x88, 0xf7, 0x05, 0x0c, 0xc2, 0xc8, 0x57, 0x43, 0xe5, 0x17, 0xaf, 0xe8, 0xee, - 0x18, 0xc3, 0x91, 0xa7, 0xf9, 0xec, 0x6b, 0x76, 0x2e, 0x9f, 0x1d, 0x63, 0x05, 0xee, 0x1f, 0x44, - 0xb3, 0x38, 0x8f, 0x7c, 0xf9, 0x36, 0xaa, 0x61, 0xf9, 0x44, 0x74, 0xb4, 0x27, 0x02, 0xbd, 0xc6, - 0xab, 0xdc, 0x77, 0x4c, 0x57, 0xa9, 0x83, 0xc8, 0x87, 0xb0, 0x96, 0x32, 0x2f, 0x8e, 0xfc, 0x54, - 0xa4, 0x87, 0x5e, 0xc6, 0x7c, 0x7e, 0x4f, 0x86, 0x76, 0x7d, 0xa2, 0x39, 0xe6, 0x9b, 0xde, 0x83, - 0x71, 0xe5, 0xd8, 0x0d, 0xcf, 0xe2, 0x86, 0xfe, 0x2c, 0xae, 0xea, 0xcf, 0xe0, 0x1f, 0xb6, 0x60, - 0xed, 0x29, 0x66, 0x72, 0x52, 0x29, 0xc2, 0x9d, 0xfe, 0x5f, 0xfa, 0x1c, 0xfd, 0xfe, 0x2c, 0x57, - 0xee, 0x8f, 0xf2, 0x00, 0x9d, 0x8b, 0x3d, 0xc0, 0x0d, 0x98, 0x24, 0x8c, 0xe7, 0x9b, 0x4e, 0x41, - 0x4a, 0x88, 0xb3, 0x06, 0xc7, 0x48, 0x37, 0x38, 0x39, 0x61, 0x7e, 0xe0, 0x66, 0x08, 0x75, 0x3c, - 0xcc, 0x27, 0x42, 0x2e, 0xd5, 0x9e, 0xdd, 0x34, 0x85, 0x22, 0x20, 0xba, 0x08, 0xa4, 0xa7, 0xfe, - 0x0c, 0x53, 0xfd, 0x8c, 0x25, 0x91, 0x1b, 0x3a, 0x27, 0x6e, 0xe6, 0x1d, 0xb3, 0x05, 0xf7, 0xb2, - 0x86, 0x46, 0x7e, 0x03, 0x46, 0x3c, 0x94, 0x4e, 0x73, 0xcf, 0x63, 0x29, 0x06, 0x53, 0xe2, 0x82, - 0x16, 0x21, 0x34, 0x66, 0x8c, 0x87, 0x62, 0xd2, 0xae, 0xa0, 0x92, 0x4f, 0x31, 0x52, 0x3d, 0x71, - 0x83, 0x08, 0x23, 0x72, 0x71, 0xdd, 0xda, 0x0d, 0xd7, 0xcd, 0xae, 0x62, 0x91, 0xcf, 0x60, 0xc8, - 0x49, 0xbd, 0x70, 0x83, 0x30, 0x4f, 0x78, 0x04, 0x57, 0xdb, 0xf4, 0xb7, 0xc4, 0x9c, 0x6d, 0x62, - 0xd2, 0xff, 0xb2, 0x60, 0x5c, 0x8a, 0x60, 0xff, 0x14, 0x53, 0xf9, 0x6b, 0xd0, 0xe1, 0xfc, 0x2c, - 0xbc, 0xec, 0x7c, 0x96, 0x7c, 0x06, 0x03, 0x9d, 0x01, 0x79, 0xd7, 0x9b, 0x38, 0x7d, 0xb8, 0x64, - 0x1b, 0xa8, 0xe4, 0xb3, 0xd7, 0xe3, 0xf4, 0xe1, 0x52, 0x13, 0xaf, 0x03, 0x9d, 0x03, 0x6e, 0x58, - 0xcd, 0xac, 0x16, 0xbb, 0x4a, 0xd4, 0xdd, 0x2e, 0x74, 0x18, 0x32, 0x48, 0x63, 0xe8, 0x6b, 0xa9, - 0xcc, 0xc2, 0xc0, 0x4b, 0x73, 0x3b, 0x2d, 0xd3, 0xed, 0x68, 0x71, 0xd0, 0x72, 0x2d, 0x0e, 0x12, - 0x85, 0xc7, 0x8e, 0x56, 0x78, 0xa4, 0x1f, 0xc3, 0x26, 0xf7, 0x7a, 0xac, 0xac, 0x52, 0xff, 0xe2, - 0x4c, 0x7d, 0x1b, 0xb6, 0xaa, 0x8b, 0x64, 0xe1, 0xeb, 0x00, 0x88, 0x98, 0x31, 0xae, 0xee, 0x45, - 0x05, 0x88, 0x0b, 0x2e, 0x30, 0xfd, 0x04, 0xd6, 0x0d, 0x6a, 0xf2, 0x16, 0xbc, 0x03, 0x13, 0x85, - 0xe2, 0xc4, 0x91, 0xc3, 0x1f, 0x59, 0x4b, 0x7b, 0x64, 0x3f, 0x82, 0x35, 0xb1, 0x4c, 0x2f, 0xb1, - 0x2f, 0x4c, 0x5a, 0xe8, 0x86, 0x3a, 0xb3, 0x51, 0x31, 0xff, 0xa3, 0x16, 0x82, 0xd3, 0x2c, 0x4e, - 0x8c, 0x22, 0xde, 0x6b, 0x55, 0xe4, 0xf4, 0x4a, 0x5f, 0xcb, 0xac, 0xf4, 0x91, 0xaf, 0xa1, 0x8f, - 0x1e, 0x7c, 0xe6, 0x7a, 0x2f, 0xf3, 0xb9, 0x72, 0xf9, 0x37, 0x94, 0x91, 0xd4, 0x77, 0xc4, 0x07, - 0x60, 0x57, 0x20, 0x8b, 0x07, 0x00, 0xc2, 0x02, 0x40, 0x7e, 0xc4, 0x7b, 0x11, 0x8e, 0xef, 0x66, - 0xee, 0xcc, 0x4d, 0x45, 0x15, 0x74, 0xc0, 0xfd, 0xf9, 0x03, 0x09, 0x92, 0xbe, 0x58, 0xa7, 0xf0, - 0x8b, 0x7c, 0xf1, 0x40, 0xf7, 0xc5, 0x0c, 0x55, 0xa0, 0x9d, 0xa9, 0x2c, 0x4c, 0x26, 0x02, 0x2c, - 0x0b, 0x8e, 0x52, 0x0c, 0x0a, 0xc8, 0xab, 0x8d, 0x1f, 0xa0, 0x8b, 0x94, 0x48, 0x2a, 0x6f, 0x17, - 0x49, 0xec, 0x58, 0xc1, 0x55, 0x9d, 0x71, 0x0d, 0xc6, 0x87, 0xc7, 0x79, 0xe6, 0xc7, 0x67, 0xaa, - 0xd4, 0x8e, 0xd9, 0x4c, 0x09, 0x92, 0x4a, 0xf9, 0x35, 0xd8, 0x3a, 0xcc, 0x67, 0xa9, 0x97, 0x04, - 0x33, 0x66, 0xe6, 0xa4, 0x53, 0xe8, 0xb1, 0x57, 0x41, 0x9a, 0x05, 0xd1, 0x11, 0x67, 0xac, 0x67, - 0x17, 0x63, 0xfa, 0x2e, 0xbc, 0x5d, 0xac, 0xc2, 0x5b, 0x98, 0xde, 0xf7, 0x3c, 0x36, 0xcf, 0x98, - 0xaf, 0xb6, 0xba, 0x07, 0x9b, 0x26, 0x82, 0xd6, 0x97, 0x51, 0xb9, 0x66, 0xe6, 0xbe, 0x94, 0x41, - 0x46, 0xcf, 0x36, 0x81, 0xf4, 0x7f, 0x5a, 0x30, 0xc0, 0x65, 0x8a, 0x2c, 0xb9, 0x5c, 0xb3, 0xf7, - 0x2e, 0x1f, 0x3f, 0x32, 0xa3, 0xb3, 0x56, 0x25, 0x3a, 0xbb, 0xf0, 0xbd, 0x5a, 0x54, 0x67, 0x2b, - 0xdf, 0xc5, 0x8e, 0xfe, 0x2e, 0x56, 0xab, 0x77, 0x2b, 0x0d, 0xd5, 0xbb, 0x2d, 0x58, 0x49, 0x78, - 0x69, 0x45, 0xa6, 0x46, 0x72, 0x84, 0x4f, 0x9b, 0x48, 0x21, 0x9c, 0x84, 0x79, 0x2c, 0x38, 0x45, - 0x99, 0xf6, 0xf8, 0xae, 0x35, 0x38, 0xe6, 0x0e, 0x12, 0x96, 0xca, 0x2e, 0xc3, 0xaa, 0x68, 0xc3, - 0x98, 0x50, 0x72, 0x0b, 0x88, 0x72, 0x1f, 0x1a, 0x55, 0x51, 0x11, 0x6a, 0x98, 0xc1, 0x33, 0x14, - 0x50, 0x45, 0xb9, 0x2f, 0x9e, 0xd7, 0x2a, 0x9c, 0xfe, 0xb5, 0x05, 0x7d, 0xcd, 0xbb, 0xfe, 0xc0, - 0x7a, 0xa7, 0x2e, 0xe3, 0x76, 0x45, 0xc6, 0x55, 0x69, 0x2e, 0x37, 0x48, 0xf3, 0x7d, 0x18, 0x49, - 0x77, 0xee, 0x24, 0xcc, 0x4d, 0x63, 0xe5, 0x68, 0x2b, 0x50, 0xfa, 0xb7, 0x6d, 0x71, 0x5a, 0xf9, - 0x02, 0xfd, 0x72, 0x8d, 0xa5, 0x54, 0x79, 0xc7, 0x50, 0xf9, 0x75, 0x18, 0x1b, 0xaa, 0x65, 0xbe, - 0xd4, 0x78, 0x15, 0x8c, 0x11, 0x64, 0xa9, 0xda, 0x4c, 0x6a, 0x5b, 0x07, 0xd5, 0x84, 0x05, 0x0d, - 0xc2, 0xba, 0x0a, 0xcb, 0x49, 0x1c, 0x32, 0xae, 0xd2, 0x51, 0x59, 0x80, 0xb0, 0xe3, 0x90, 0xd9, - 0x7c, 0x06, 0xe3, 0xd0, 0x8a, 0x59, 0x30, 0x9f, 0x57, 0xfd, 0x56, 0xed, 0xfa, 0x04, 0x5e, 0x54, - 0xdd, 0x2c, 0xb2, 0xed, 0xa1, 0xe8, 0x1f, 0x18, 0x40, 0x4c, 0xfe, 0x12, 0x67, 0x9e, 0xb0, 0xe0, - 0xc4, 0x3d, 0x62, 0xdb, 0x23, 0x8e, 0xa2, 0x41, 0xca, 0xab, 0x34, 0xd6, 0xae, 0x12, 0xfd, 0xef, - 0x16, 0x74, 0x9e, 0x25, 0xae, 0xcf, 0x30, 0xc3, 0x39, 0xc1, 0x1b, 0xef, 0x2c, 0xce, 0x38, 0x6c, - 0x1d, 0x03, 0x17, 0x64, 0xda, 0x82, 0x56, 0xe3, 0x02, 0x0d, 0x43, 0xd3, 0x4f, 0xdb, 0xd0, 0xcf, - 0x45, 0x3a, 0xd5, 0x2c, 0xa1, 0x63, 0x5a, 0x42, 0xc1, 0xcf, 0x8a, 0xee, 0x1a, 0x94, 0xec, 0xbb, - 0x0b, 0x65, 0x7f, 0x15, 0xfa, 0x4c, 0xb4, 0x11, 0x78, 0x96, 0x2c, 0x2c, 0x41, 0x07, 0x15, 0x41, - 0xf2, 0xea, 0xc5, 0x41, 0xf2, 0x5d, 0x18, 0x78, 0x68, 0x18, 0x2c, 0x99, 0xbb, 0x49, 0x26, 0x4c, - 0x61, 0x71, 0x22, 0x6f, 0xe0, 0xd2, 0x9b, 0xb0, 0xce, 0xa5, 0xfe, 0x30, 0xc0, 0xa7, 0xe2, 0x5c, - 0x4b, 0x03, 0x44, 0xad, 0xd0, 0xd2, 0x6a, 0x85, 0xf4, 0x1e, 0x6c, 0x98, 0xc8, 0xf2, 0x9d, 0xba, - 0x06, 0x2b, 0x19, 0xc2, 0x6b, 0x61, 0x32, 0xc7, 0xb6, 0xe5, 0x24, 0xa6, 0xe5, 0x43, 0x84, 0x04, - 0xd1, 0xd1, 0x01, 0xd2, 0x4b, 0x51, 0xe0, 0x27, 0xee, 0x2b, 0x07, 0xd3, 0x55, 0x95, 0x97, 0xab, - 0x31, 0x0a, 0x1c, 0xbf, 0x67, 0xb9, 0x8a, 0x58, 0xd4, 0x10, 0x8d, 0x36, 0x61, 0x29, 0x4b, 0x4e, - 0x99, 0xef, 0xc4, 0x79, 0x26, 0x12, 0x33, 0xe1, 0x4c, 0xea, 0x13, 0xe4, 0x26, 0x7f, 0x1f, 0x05, - 0x50, 0xcf, 0xe2, 0x9a, 0x90, 0xe9, 0x8e, 0xe0, 0xb0, 0x38, 0xe1, 0xeb, 0xc4, 0x69, 0x7f, 0x63, - 0xc1, 0x66, 0x65, 0x91, 0x94, 0xcb, 0x7d, 0x58, 0xe1, 0x82, 0x53, 0x72, 0xf9, 0x40, 0x97, 0x4b, - 0x0d, 0xfd, 0x96, 0x18, 0xca, 0xba, 0xa7, 0x58, 0x38, 0x7d, 0x0a, 0x7d, 0x0d, 0xdc, 0x10, 0x54, - 0xdc, 0x34, 0xeb, 0x9e, 0x9b, 0xcd, 0x5b, 0x68, 0xb1, 0xc6, 0x4f, 0x61, 0xf0, 0x4d, 0x34, 0xfb, - 0x01, 0xcd, 0x76, 0x72, 0x05, 0x56, 0x13, 0x26, 0xb3, 0x52, 0x19, 0x62, 0x94, 0x00, 0x3a, 0x86, - 0xa1, 0xa4, 0x5b, 0xb6, 0x67, 0xbf, 0x89, 0xc2, 0xd8, 0x7b, 0xf9, 0xba, 0xed, 0xd9, 0x9f, 0x01, - 0xd1, 0x17, 0x94, 0x41, 0x50, 0xce, 0xa1, 0x95, 0x20, 0x48, 0x01, 0x79, 0x10, 0xf4, 0x2e, 0xf4, - 0x75, 0x14, 0xd1, 0xcd, 0x81, 0x12, 0x81, 0xfe, 0x89, 0x05, 0xe3, 0x6f, 0x83, 0xec, 0xd8, 0x4f, - 0xdc, 0xb3, 0xd7, 0x50, 0x6a, 0xb5, 0x55, 0xde, 0xba, 0xa8, 0x55, 0xde, 0xae, 0xb6, 0xca, 0xdd, - 0x30, 0x94, 0x85, 0x02, 0xfc, 0xd4, 0x4b, 0x84, 0x43, 0x51, 0x22, 0xbc, 0x0b, 0x93, 0xf2, 0x30, - 0x6f, 0x56, 0x1f, 0xbc, 0x71, 0x1d, 0x56, 0x0b, 0x07, 0x40, 0xba, 0xd0, 0xde, 0xfd, 0xe6, 0xb7, - 0x27, 0x4b, 0xa4, 0x07, 0xcb, 0x87, 0xfb, 0x07, 0x07, 0xa2, 0x14, 0xcf, 0xab, 0xf3, 0xad, 0x1b, - 0x37, 0x60, 0x19, 0xdd, 0x0d, 0x59, 0x85, 0xce, 0xb3, 0xfb, 0x5f, 0xef, 0xdb, 0x93, 0x25, 0xfc, - 0xfc, 0x09, 0xff, 0xb4, 0xc8, 0x00, 0x7a, 0x8f, 0x1e, 0x3f, 0xdb, 0xb7, 0x1f, 0xdf, 0x3f, 0x98, - 0xb4, 0x76, 0xfe, 0xc3, 0x82, 0xee, 0xf3, 0xdc, 0x7f, 0x14, 0x05, 0x19, 0xd9, 0x07, 0x28, 0xbb, - 0xe4, 0xe4, 0x72, 0x51, 0x40, 0xae, 0xf6, 0xda, 0xa7, 0xd3, 0xa6, 0x29, 0xa9, 0xfd, 0x25, 0xf2, - 0x10, 0xfa, 0x5a, 0x50, 0x4b, 0xa6, 0x8b, 0xa3, 0xef, 0xe9, 0x5b, 0x8d, 0x73, 0x05, 0xa5, 0x7d, - 0x80, 0xd2, 0x30, 0xca, 0x03, 0xd5, 0xac, 0xab, 0x3c, 0x50, 0xdd, 0x8e, 0xe8, 0xd2, 0xce, 0xdf, - 0x6f, 0x41, 0xfb, 0x79, 0xee, 0x93, 0xe7, 0xd0, 0xd7, 0x7e, 0x18, 0x22, 0xb5, 0xe6, 0x4c, 0x79, - 0x9c, 0xa6, 0xff, 0x8a, 0xa6, 0x3f, 0xff, 0xe7, 0xff, 0xfc, 0xd3, 0xd6, 0x06, 0x1d, 0xdf, 0x3e, - 0xfd, 0xd5, 0xdb, 0xae, 0xef, 0x2b, 0x93, 0xb9, 0x6b, 0xdd, 0x20, 0x36, 0x74, 0xe5, 0x3f, 0x41, - 0x64, 0x4b, 0xa3, 0xa1, 0x65, 0x48, 0xd3, 0x4b, 0x35, 0xb8, 0xa4, 0xbb, 0xc5, 0xe9, 0x4e, 0x68, - 0x5f, 0xd2, 0xc5, 0xe7, 0x05, 0x69, 0xee, 0x42, 0x7b, 0xd7, 0x8d, 0x08, 0x29, 0x1b, 0xa5, 0xea, - 0xea, 0x4e, 0xd7, 0x0d, 0x98, 0xa4, 0x43, 0x38, 0x9d, 0x01, 0xed, 0x22, 0x9d, 0x99, 0x1b, 0x21, - 0x0d, 0x0f, 0x06, 0xfa, 0xcf, 0x1a, 0xa4, 0xfc, 0x65, 0xa0, 0xfe, 0x07, 0xca, 0xf4, 0x4a, 0xf3, - 0xa4, 0x24, 0xbf, 0xcd, 0xc9, 0x13, 0x3a, 0x41, 0xf2, 0xfc, 0x5f, 0x16, 0xd9, 0x7a, 0x40, 0xe6, - 0xe5, 0x1f, 0x1a, 0x25, 0xf3, 0xe6, 0x0f, 0x1e, 0x25, 0xf3, 0xd5, 0x5f, 0x39, 0x0c, 0xe6, 0xa5, - 0x47, 0xc1, 0x83, 0x7f, 0x07, 0xc3, 0x6f, 0xf9, 0x9f, 0x42, 0xf2, 0xbf, 0x80, 0x92, 0xb2, 0xf9, - 0x5b, 0x41, 0x49, 0xb9, 0xf2, 0x03, 0x01, 0xbd, 0xc2, 0x29, 0x6f, 0xd1, 0x35, 0xa4, 0x2c, 0xfe, - 0x3a, 0xf2, 0x05, 0x0a, 0xd2, 0xff, 0x3d, 0x18, 0x1a, 0xbf, 0x00, 0x90, 0x82, 0xf9, 0xa6, 0x7f, - 0x0b, 0xa6, 0x6f, 0x2f, 0x98, 0x6d, 0xda, 0xcb, 0x97, 0x28, 0xfc, 0xa7, 0x01, 0xdc, 0xeb, 0x39, - 0x40, 0xd9, 0x4a, 0x2f, 0xad, 0xb8, 0xd6, 0xbe, 0x2f, 0xad, 0xb8, 0xde, 0x79, 0xa7, 0xeb, 0x7c, - 0x8b, 0x21, 0xe9, 0x0b, 0xed, 0x0a, 0x5a, 0x07, 0xd0, 0x95, 0x4d, 0xe3, 0x52, 0x3e, 0x66, 0xe7, - 0xbc, 0x94, 0x4f, 0xa5, 0xbb, 0x4c, 0x27, 0x9c, 0x20, 0x90, 0x1e, 0x12, 0x0c, 0x90, 0xc4, 0xef, - 0x40, 0x5f, 0xeb, 0xa3, 0x12, 0xfd, 0x34, 0x95, 0xe6, 0x6c, 0x79, 0x51, 0x1a, 0x1a, 0xaf, 0x74, - 0x83, 0x53, 0x1e, 0x91, 0x01, 0x52, 0x46, 0x29, 0x70, 0xea, 0xdf, 0x02, 0x94, 0x2d, 0xbf, 0x52, - 0x0a, 0xb5, 0xde, 0x65, 0x29, 0x85, 0x7a, 0x87, 0x50, 0xd9, 0x38, 0x01, 0x24, 0x2d, 0x0b, 0xe3, - 0x47, 0x30, 0x32, 0x3b, 0xb2, 0xe4, 0x6d, 0x9d, 0x42, 0xad, 0x85, 0x3b, 0x7d, 0x67, 0xd1, 0xb4, - 0x69, 0x93, 0x64, 0xc4, 0x6d, 0xb2, 0x24, 0x7b, 0x08, 0xab, 0x45, 0xaf, 0x90, 0x6c, 0xeb, 0x44, - 0xf4, 0x96, 0xe2, 0xf4, 0x72, 0xc3, 0x8c, 0xa4, 0xbc, 0xc6, 0x29, 0xf7, 0xc9, 0x2a, 0x52, 0x16, - 0x25, 0x63, 0x45, 0x94, 0xff, 0x62, 0x60, 0x12, 0xd5, 0x1a, 0x8d, 0x15, 0xa2, 0x7a, 0xbb, 0xb1, - 0x42, 0x94, 0xd3, 0x71, 0xa0, 0xaf, 0x75, 0xa2, 0x4a, 0x4d, 0xd6, 0xdb, 0x68, 0xa5, 0x26, 0x1b, - 0x5a, 0x57, 0xf4, 0x12, 0x27, 0xbd, 0x26, 0x5c, 0x5e, 0x3c, 0x67, 0x91, 0xba, 0xf2, 0xbf, 0x0b, - 0x50, 0x16, 0x0f, 0x4b, 0x65, 0xd6, 0xca, 0xca, 0xa5, 0xf9, 0x55, 0x6a, 0x8d, 0xf4, 0x32, 0x27, - 0xbd, 0x4e, 0xb9, 0x90, 0x79, 0x41, 0x97, 0xab, 0xf3, 0xae, 0x75, 0xe3, 0x8e, 0x45, 0x5e, 0xc0, - 0xa8, 0xc4, 0x3f, 0x3c, 0x8f, 0xbc, 0x8b, 0xb6, 0x98, 0x36, 0x4d, 0x49, 0x06, 0xde, 0xe6, 0xbb, - 0x5c, 0xa2, 0xc4, 0xdc, 0x25, 0x3d, 0x8f, 0x3c, 0xbc, 0x99, 0x3f, 0x83, 0xbe, 0xf6, 0x43, 0x4f, - 0x29, 0xa7, 0xfa, 0x5f, 0x3e, 0xd3, 0xa6, 0xf2, 0xa6, 0xf9, 0x24, 0xc8, 0x00, 0x3e, 0x3d, 0x73, - 0xe7, 0x48, 0x3b, 0x82, 0x91, 0x59, 0xc5, 0x2b, 0xcd, 0xb2, 0xb1, 0x24, 0x58, 0x9a, 0xe5, 0x82, - 0xe2, 0x9f, 0xc1, 0x0b, 0x6f, 0x9d, 0x30, 0xfd, 0x09, 0x9a, 0xe1, 0xab, 0x5b, 0x54, 0xf3, 0xf4, - 0x57, 0xb7, 0x5a, 0x30, 0xd4, 0x5f, 0xdd, 0x5a, 0xf9, 0xcf, 0xe4, 0x49, 0x6c, 0xa3, 0x34, 0x43, - 0xbe, 0x03, 0x28, 0x6b, 0x79, 0xa5, 0x4e, 0x6a, 0xe5, 0xc0, 0xe9, 0xb4, 0x69, 0x4a, 0x6e, 0x60, - 0x68, 0x5e, 0x6c, 0xa0, 0x9e, 0xbc, 0x9f, 0x42, 0x4f, 0x15, 0xa5, 0x48, 0x61, 0x39, 0x95, 0xca, - 0xd5, 0x74, 0xbb, 0x3e, 0x51, 0x31, 0x57, 0xee, 0x78, 0x52, 0x39, 0x8b, 0x74, 0x19, 0x8c, 0x2b, - 0x85, 0x2d, 0x52, 0x48, 0xbb, 0xb9, 0xe2, 0x35, 0x35, 0xff, 0xdf, 0x11, 0xdd, 0x30, 0xfa, 0x16, - 0xdf, 0x60, 0x93, 0xac, 0xf3, 0x0d, 0xd4, 0x42, 0x61, 0x52, 0x77, 0x2c, 0x32, 0xaf, 0x14, 0xba, - 0x64, 0xc5, 0x44, 0x73, 0x48, 0x8d, 0x75, 0xb0, 0x69, 0x53, 0x11, 0x9b, 0xfe, 0x88, 0xef, 0xf5, - 0x16, 0xb9, 0x6c, 0xec, 0x85, 0xd6, 0xa5, 0x6a, 0xf8, 0x77, 0x2c, 0x32, 0x83, 0x91, 0x49, 0xf2, - 0x8d, 0xb6, 0xaa, 0x98, 0x31, 0x21, 0xb5, 0xad, 0x70, 0x8f, 0x3f, 0xd0, 0xaa, 0x82, 0x46, 0x7d, - 0x8f, 0x5c, 0x6b, 0xde, 0xab, 0x52, 0xff, 0x9b, 0x6e, 0xe8, 0x7b, 0xaa, 0x49, 0x4a, 0xf9, 0xa6, - 0x57, 0xc8, 0xb4, 0xbe, 0xa9, 0x2b, 0x71, 0xb8, 0x27, 0x18, 0xe8, 0x99, 0x67, 0x19, 0xc0, 0x34, - 0x24, 0xaf, 0x65, 0x00, 0xd3, 0x94, 0xac, 0x2a, 0xe5, 0x89, 0x00, 0x86, 0x67, 0xa6, 0xc7, 0x02, - 0x03, 0x2d, 0xe4, 0xa8, 0x9a, 0xa1, 0x5e, 0x59, 0x90, 0xb2, 0x55, 0xe2, 0x81, 0xc6, 0x84, 0x4e, - 0x99, 0x38, 0x59, 0x53, 0x5b, 0x05, 0xd1, 0x91, 0xc8, 0xeb, 0xc8, 0x57, 0xd0, 0xe1, 0xd9, 0x12, - 0xd9, 0x28, 0x43, 0xd6, 0x32, 0x29, 0x9b, 0x6e, 0x56, 0xa0, 0xe6, 0x93, 0x4a, 0xb9, 0x8f, 0xcf, - 0x23, 0x19, 0xdd, 0xcd, 0x60, 0x24, 0x82, 0x24, 0x95, 0x53, 0x94, 0x97, 0xa6, 0x92, 0xf2, 0x94, - 0x97, 0xa6, 0x9a, 0x7e, 0x98, 0x6e, 0x45, 0xc4, 0x49, 0x67, 0x12, 0xe7, 0xae, 0x75, 0x63, 0xb6, - 0xc2, 0xff, 0xb5, 0xff, 0xf8, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x82, 0x20, 0x21, 0xba, 0x96, - 0x2f, 0x00, 0x00, + // 3909 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3b, 0x4d, 0x8f, 0x1c, 0x49, + 0x56, 0x9d, 0x55, 0x5d, 0x5d, 0xd5, 0xaf, 0x3e, 0x3b, 0xfa, 0xc3, 0xe5, 0x1a, 0xcf, 0x8c, 0x37, + 0x18, 0x8f, 0x3c, 0xf6, 0x8c, 0x6d, 0x7a, 0x18, 0x66, 0xc7, 0xe0, 0xd1, 0xb8, 0xdb, 0xcd, 0xd8, + 0x33, 0xbd, 0xb6, 0x95, 0xed, 0x59, 0x9b, 0x15, 0x6c, 0x2a, 0x2b, 0x33, 0xec, 0x4e, 0x9c, 0x1d, + 0x59, 0x93, 0x1f, 0x6e, 0x37, 0x5c, 0xd0, 0x8a, 0x13, 0x1c, 0x11, 0x67, 0xf6, 0x84, 0x90, 0xf8, + 0xb8, 0x72, 0x42, 0xe2, 0xcc, 0x95, 0x03, 0x12, 0x70, 0x41, 0xe2, 0x17, 0x20, 0xae, 0x48, 0x28, + 0xbe, 0x32, 0x22, 0x32, 0xb3, 0x7a, 0xed, 0x15, 0x70, 0xab, 0x78, 0xf1, 0xe2, 0xbd, 0x88, 0xf7, + 0x5e, 0xbc, 0xaf, 0xc8, 0x82, 0xc1, 0xeb, 0x22, 0x4c, 0x17, 0xc1, 0x8d, 0x45, 0x9a, 0xe4, 0x09, + 0x5a, 0x13, 0xa3, 0xd9, 0x86, 0x4f, 0x69, 0x92, 0xfb, 0x79, 0x94, 0xd0, 0x4c, 0x4c, 0xe1, 0x6d, + 0xd8, 0xbc, 0x1b, 0x86, 0xfb, 0x45, 0x9a, 0x12, 0x1a, 0x9c, 0xb9, 0x24, 0x5b, 0x24, 0x34, 0x23, + 0xf8, 0xa7, 0x30, 0xba, 0x1b, 0x86, 0x8f, 0xfd, 0x28, 0x75, 0xc9, 0xf7, 0x05, 0xc9, 0x72, 0xf4, + 0x01, 0x0c, 0xe7, 0x7e, 0x46, 0xbc, 0x40, 0xa2, 0x4e, 0x9d, 0xcb, 0xce, 0xd5, 0x75, 0xd7, 0x06, + 0xa2, 0x0f, 0x61, 0xf4, 0x7d, 0x91, 0xe4, 0x06, 0x5a, 0x8b, 0xa3, 0x55, 0xa0, 0x78, 0x03, 0xc6, + 0x25, 0x7d, 0xc9, 0xf2, 0xef, 0x5a, 0xd0, 0xdd, 0xf3, 0x63, 0x9f, 0x06, 0x84, 0x31, 0xcb, 0x93, + 0xdc, 0x8f, 0xbd, 0xb9, 0x00, 0x70, 0x66, 0xab, 0xae, 0x0d, 0x44, 0x57, 0x61, 0x1c, 0x1c, 0xfb, + 0x94, 0x12, 0x8d, 0xd7, 0xe2, 0x78, 0x55, 0x30, 0xfa, 0x21, 0x5c, 0x58, 0x10, 0x1a, 0x46, 0xf4, + 0x85, 0x57, 0x5d, 0xd1, 0xe6, 0x2b, 0x96, 0x4d, 0xa3, 0xdb, 0x30, 0x8d, 0xa8, 0x1f, 0xe4, 0xd1, + 0x2b, 0x52, 0x5b, 0xba, 0xca, 0x97, 0x2e, 0x9d, 0x67, 0xc2, 0x38, 0xf5, 0xe3, 0x98, 0xe4, 0xe5, + 0x8a, 0x0e, 0x5f, 0x51, 0x81, 0xa2, 0x2f, 0x61, 0x56, 0xd0, 0x20, 0xa1, 0xcf, 0xa3, 0xf4, 0x84, + 0x84, 0x5e, 0x65, 0xcd, 0x1a, 0x5f, 0x73, 0x0e, 0x06, 0xfe, 0x75, 0x80, 0x3d, 0x9f, 0x2a, 0x45, + 0x5d, 0x85, 0x31, 0x4d, 0x42, 0xe2, 0x45, 0x21, 0xa1, 0x79, 0xf4, 0x3c, 0x22, 0xa9, 0x54, 0x55, + 0x15, 0x8c, 0x87, 0xd0, 0xe7, 0xeb, 0xa4, 0x02, 0x3e, 0x87, 0xce, 0xfe, 0xb1, 0x1f, 0x51, 0xb4, + 0x05, 0x9d, 0x80, 0xfd, 0x90, 0xeb, 0xc4, 0x00, 0x4d, 0xa1, 0x4b, 0x49, 0x7e, 0x9a, 0xa4, 0x2f, + 0xa5, 0x4e, 0xd5, 0x10, 0x2f, 0xa0, 0xb7, 0x2f, 0x8e, 0x9e, 0xa1, 0x1d, 0x58, 0x13, 0xd2, 0xe0, + 0x8b, 0x87, 0xae, 0x1c, 0xa1, 0x19, 0xf4, 0x94, 0x9c, 0xf8, 0xf2, 0xa1, 0x5b, 0x8e, 0x19, 0x65, + 0x29, 0x7e, 0xae, 0x8d, 0xa1, 0xab, 0x86, 0x8c, 0x5a, 0x10, 0x27, 0x19, 0x09, 0xb9, 0xac, 0x87, + 0xae, 0x1c, 0xe1, 0xbf, 0x77, 0x60, 0x73, 0x9f, 0xfd, 0x94, 0x7c, 0xdf, 0xfa, 0xec, 0x6c, 0x3f, + 0x15, 0x13, 0x2d, 0xc7, 0xec, 0xfc, 0xcf, 0x93, 0x54, 0xda, 0x46, 0xcf, 0x15, 0x03, 0x74, 0x19, + 0xfa, 0x21, 0xc9, 0xf2, 0x88, 0xf2, 0xfb, 0xc3, 0x37, 0xb4, 0xee, 0x9a, 0x20, 0x7e, 0xf6, 0x93, + 0xa4, 0xa0, 0xb9, 0xd4, 0xb3, 0x1c, 0xa1, 0x09, 0xb4, 0x9f, 0x13, 0xa5, 0x48, 0xf6, 0x13, 0x7f, + 0x05, 0x5b, 0xf6, 0xf6, 0x85, 0x0a, 0xd8, 0xfe, 0xf3, 0xd4, 0xa7, 0x19, 0x13, 0x4c, 0x42, 0xbd, + 0x28, 0xcc, 0xa6, 0xce, 0xe5, 0x36, 0xdb, 0x7f, 0x05, 0x8c, 0x3f, 0x86, 0xd1, 0x7e, 0x42, 0x29, + 0x09, 0x72, 0x75, 0xf6, 0x19, 0xf4, 0xf8, 0x21, 0x8b, 0x34, 0x92, 0x87, 0x2e, 0xc7, 0xec, 0xba, + 0x95, 0xd8, 0x52, 0xdb, 0x37, 0x61, 0x63, 0x3f, 0x25, 0x7e, 0x4e, 0x1e, 0x26, 0x21, 0x31, 0x68, + 0x2c, 0xfc, 0x2c, 0x3b, 0x4d, 0xd2, 0x50, 0xd1, 0x50, 0x63, 0xfc, 0x67, 0x0e, 0x20, 0x73, 0x85, + 0xdc, 0xf2, 0xaf, 0xc0, 0x30, 0x23, 0x24, 0xf4, 0x4e, 0x28, 0x39, 0x49, 0x68, 0x14, 0xc8, 0x0d, + 0x0f, 0x18, 0xf0, 0x47, 0x12, 0x86, 0x3e, 0x82, 0x49, 0x44, 0xa3, 0x3c, 0xf2, 0xe3, 0xe8, 0xf7, + 0x49, 0xe8, 0xc5, 0x34, 0xcc, 0xa6, 0x2d, 0x71, 0x30, 0x03, 0x7e, 0x48, 0xc3, 0x0c, 0xdd, 0x84, + 0x4d, 0x13, 0x35, 0x60, 0xdb, 0x7e, 0x9d, 0x4b, 0x55, 0x20, 0x63, 0x6a, 0x5f, 0xcc, 0xe0, 0x7f, + 0x76, 0xa0, 0xa7, 0xfc, 0x97, 0xa5, 0x56, 0xa7, 0xa2, 0xd6, 0x3b, 0xd0, 0xcf, 0x4e, 0xfd, 0x85, + 0x17, 0xc4, 0x11, 0xa1, 0x39, 0xd7, 0xfa, 0x68, 0xf7, 0x9d, 0x1b, 0xd2, 0x53, 0x2a, 0x12, 0x37, + 0x8e, 0x4e, 0xfd, 0xc5, 0x3e, 0x47, 0x71, 0x4d, 0x7c, 0xe1, 0x93, 0x5e, 0x12, 0xea, 0xf9, 0x61, + 0x98, 0x92, 0x2c, 0xe3, 0x5b, 0x5a, 0x77, 0x6d, 0x20, 0xbb, 0xf3, 0x21, 0x09, 0xa2, 0x13, 0x3f, + 0xf6, 0x16, 0xb1, 0x1f, 0x90, 0x4c, 0x5a, 0x6e, 0x05, 0x8a, 0x31, 0x80, 0x66, 0x84, 0xba, 0xd0, + 0x3e, 0x7c, 0x78, 0x6f, 0xb2, 0x82, 0xfa, 0xd0, 0xdd, 0x7f, 0xf4, 0xf0, 0xe1, 0xc1, 0xb3, 0x27, + 0x93, 0x16, 0xd3, 0xf1, 0x3d, 0xb2, 0x48, 0xb2, 0xc8, 0xd4, 0xf1, 0xb2, 0xe3, 0xe1, 0xeb, 0x30, + 0x2e, 0xb1, 0xa5, 0x6e, 0xa6, 0xd0, 0x55, 0x9b, 0x15, 0xd8, 0x6a, 0xc8, 0x0c, 0xf0, 0x5e, 0x94, + 0x05, 0xc9, 0x2b, 0x92, 0x32, 0x6d, 0x66, 0x6f, 0xef, 0x3c, 0x3e, 0x83, 0xed, 0x0a, 0x05, 0xc9, + 0xf4, 0x12, 0xac, 0xd3, 0xe2, 0xc4, 0x63, 0xf8, 0x99, 0x74, 0x02, 0x1a, 0x80, 0xff, 0xd8, 0x01, + 0x74, 0xf0, 0x9a, 0x04, 0x45, 0x4e, 0xd8, 0xf9, 0x8d, 0x83, 0x25, 0x69, 0x48, 0x52, 0x2f, 0x2a, + 0x0d, 0x4f, 0x8d, 0xb9, 0x7b, 0xf0, 0x23, 0x3e, 0x25, 0x1d, 0x8f, 0x1c, 0x22, 0x0c, 0x83, 0x05, + 0x21, 0xa9, 0xb7, 0x28, 0xe6, 0xde, 0x4b, 0x72, 0x26, 0x35, 0x62, 0xc1, 0x18, 0xe5, 0xef, 0x0b, + 0x9f, 0xe6, 0x51, 0x7e, 0x26, 0x1d, 0x76, 0x39, 0x66, 0x77, 0xe0, 0x6b, 0x92, 0xcb, 0xa0, 0xf3, + 0x26, 0x32, 0xfe, 0x4b, 0x07, 0x90, 0xb9, 0x42, 0x1e, 0xf9, 0x1e, 0xf4, 0xa4, 0x2f, 0x16, 0xf7, + 0xb5, 0xbf, 0x7b, 0x55, 0x99, 0x55, 0x1d, 0xfb, 0x86, 0x1c, 0x67, 0x07, 0x34, 0x4f, 0xcf, 0xdc, + 0x72, 0xe5, 0xec, 0x10, 0x86, 0xd6, 0x14, 0xf3, 0x1b, 0xec, 0x54, 0x62, 0x13, 0xec, 0x27, 0xba, + 0x02, 0x9d, 0x57, 0x7e, 0x5c, 0x08, 0x17, 0xda, 0xdf, 0x1d, 0x2b, 0x2e, 0x8a, 0x85, 0x98, 0xbd, + 0xdd, 0xfa, 0xa1, 0x83, 0x27, 0x30, 0xfa, 0x9a, 0xe4, 0x0f, 0xe8, 0xf3, 0x44, 0x1e, 0x0c, 0xff, + 0x4b, 0x1b, 0xc6, 0x25, 0x48, 0x5b, 0xc8, 0x2b, 0x92, 0x66, 0xcc, 0xa1, 0x49, 0x0b, 0x91, 0x43, + 0x26, 0x5b, 0xae, 0x72, 0x25, 0x5b, 0x21, 0x7a, 0x0b, 0x86, 0x10, 0xac, 0x16, 0x69, 0xc4, 0x6e, + 0x02, 0xbb, 0xca, 0xfc, 0xb7, 0x52, 0x3f, 0xd3, 0x81, 0xb2, 0x7d, 0x0d, 0x28, 0x67, 0xfd, 0x28, + 0xcd, 0xb8, 0x97, 0x54, 0xb3, 0x0c, 0x80, 0xae, 0xc3, 0x1a, 0xd7, 0x7a, 0xc6, 0x7d, 0x65, 0x7f, + 0x77, 0x53, 0x9d, 0xef, 0x11, 0x87, 0xee, 0x33, 0x6f, 0xea, 0x4a, 0x14, 0xb4, 0x0b, 0xed, 0x98, + 0x86, 0xd3, 0x2e, 0x97, 0xf7, 0x65, 0x43, 0xde, 0xe6, 0x01, 0x6f, 0x1c, 0xd2, 0x50, 0xc8, 0x99, + 0x21, 0x33, 0xcf, 0xee, 0xc7, 0x91, 0x9f, 0x4d, 0xd7, 0x45, 0x64, 0xe3, 0x03, 0x33, 0xb2, 0x81, + 0x15, 0xd9, 0xd0, 0x2d, 0xd8, 0x54, 0x89, 0x01, 0x77, 0x05, 0xc7, 0x7e, 0x76, 0x4c, 0xb2, 0x69, + 0x9f, 0x9f, 0xb7, 0x69, 0x0a, 0x7d, 0x02, 0x5d, 0xe5, 0xb2, 0x06, 0xf6, 0x19, 0xa4, 0xbf, 0xe2, + 0xbb, 0x53, 0x38, 0xb3, 0xaf, 0xa1, 0xa7, 0x76, 0xf8, 0x16, 0xea, 0x3e, 0xa4, 0x21, 0x27, 0x63, + 0xa8, 0xfb, 0x4b, 0x6e, 0x98, 0xec, 0x26, 0x1a, 0x2a, 0x7f, 0x8b, 0xeb, 0xec, 0xc2, 0xa6, 0xb5, + 0xbe, 0xf4, 0xee, 0xe3, 0x94, 0x2c, 0x0a, 0x91, 0x33, 0x1e, 0x05, 0x49, 0x2a, 0xe2, 0xfa, 0x86, + 0x0b, 0x1a, 0xcc, 0xe2, 0xde, 0x9c, 0xc5, 0x31, 0x71, 0x3f, 0x7b, 0xae, 0x1c, 0xe1, 0x0b, 0xb0, + 0x7d, 0x18, 0x65, 0xb9, 0xf4, 0xac, 0x51, 0xe9, 0x65, 0xf0, 0x37, 0xb0, 0x53, 0x9d, 0x90, 0xfc, + 0x6e, 0x01, 0x04, 0x25, 0x54, 0xde, 0xa5, 0x49, 0xd5, 0x45, 0xbb, 0x06, 0x0e, 0xfe, 0x47, 0x07, + 0x36, 0x18, 0x31, 0x61, 0x22, 0xea, 0xe0, 0x86, 0xcf, 0x70, 0x6c, 0x9f, 0xf1, 0x19, 0x74, 0x92, + 0x53, 0x4a, 0x52, 0xe9, 0xff, 0xdf, 0x2f, 0x65, 0x5a, 0xa5, 0x71, 0xe3, 0x11, 0x43, 0x73, 0x05, + 0x36, 0xb3, 0x9c, 0x38, 0x3a, 0x89, 0x72, 0x99, 0xa1, 0x88, 0x01, 0x93, 0x6f, 0x44, 0x83, 0xb8, + 0x08, 0x89, 0xc7, 0x4d, 0x49, 0xba, 0xfb, 0x9e, 0x5b, 0x05, 0xe3, 0x0f, 0xa0, 0xc3, 0xe9, 0xa1, + 0x1e, 0xac, 0xee, 0x3d, 0x7a, 0x72, 0x7f, 0xb2, 0xc2, 0x9c, 0xfe, 0xa3, 0xa7, 0x0f, 0x27, 0x0e, + 0x03, 0x3d, 0x3e, 0x38, 0x70, 0x27, 0x2d, 0xfc, 0xe7, 0x0e, 0x20, 0x73, 0x23, 0x52, 0x2a, 0x5f, + 0x96, 0xf7, 0x42, 0x48, 0xe4, 0xc3, 0xa6, 0x4d, 0x4b, 0x83, 0x17, 0x43, 0x61, 0xf3, 0x72, 0xd5, + 0xec, 0x01, 0xf4, 0x0d, 0x70, 0x83, 0xa1, 0x7d, 0x60, 0x1b, 0xda, 0xc8, 0xbe, 0x77, 0xa6, 0x9d, + 0x21, 0x98, 0x30, 0xa6, 0x2c, 0x73, 0x2f, 0xd5, 0xf9, 0x91, 0xd0, 0x80, 0x84, 0xc9, 0x3d, 0x6f, + 0x41, 0x47, 0xdc, 0x72, 0x91, 0x0f, 0x88, 0x41, 0xb9, 0x9c, 0x68, 0x39, 0xe3, 0xcf, 0xe5, 0x72, + 0x62, 0x1e, 0x19, 0x43, 0x47, 0xb8, 0x10, 0x71, 0xe2, 0x81, 0xda, 0x11, 0xc3, 0x72, 0xc5, 0x14, + 0xfe, 0x37, 0x07, 0xba, 0xf2, 0x2a, 0x30, 0x1b, 0xcc, 0x72, 0x3f, 0x2f, 0x54, 0xa4, 0x93, 0x23, + 0xf4, 0x31, 0xf4, 0x64, 0x5a, 0x9e, 0xc9, 0xc3, 0x69, 0x73, 0x92, 0x70, 0xb7, 0xc4, 0x40, 0x57, + 0x60, 0x8d, 0x27, 0xbb, 0xc2, 0xa5, 0xf5, 0x77, 0x87, 0x06, 0x6e, 0x44, 0x5d, 0x39, 0xc9, 0x52, + 0xc1, 0x79, 0x9c, 0x04, 0x2f, 0x8f, 0x49, 0xf4, 0xe2, 0x38, 0x97, 0x5e, 0xce, 0x04, 0x95, 0x9e, + 0xb1, 0x63, 0x78, 0x46, 0xc3, 0xd7, 0xae, 0xd9, 0xbe, 0xb6, 0x74, 0x4b, 0x5d, 0xc3, 0x2d, 0xe1, + 0x6f, 0x60, 0xc4, 0xef, 0xa3, 0x4e, 0x5a, 0xab, 0x3e, 0xd9, 0x69, 0xf0, 0xc9, 0x25, 0xad, 0x96, + 0x49, 0xeb, 0x2f, 0x1c, 0x40, 0x8f, 0x16, 0x84, 0xfe, 0x9f, 0xe4, 0xcb, 0x3a, 0xef, 0x6d, 0x5b, + 0x79, 0xef, 0x65, 0xe8, 0x2f, 0x8a, 0xec, 0xd8, 0x93, 0x93, 0x22, 0xfa, 0x9a, 0x20, 0x95, 0x19, + 0x77, 0x74, 0x66, 0x7c, 0x07, 0x36, 0xad, 0x7d, 0x4a, 0x73, 0xf8, 0x10, 0x46, 0x76, 0x06, 0x2c, + 0xf7, 0x59, 0x81, 0xe2, 0x7f, 0x68, 0x41, 0x87, 0x1b, 0x2d, 0xb7, 0xbf, 0x34, 0x92, 0xa5, 0xa3, + 0xe3, 0x8a, 0x81, 0x95, 0x0d, 0xb4, 0xec, 0x6c, 0xc0, 0xf4, 0x19, 0x6d, 0xdb, 0x67, 0x8c, 0xa0, + 0x15, 0x85, 0x32, 0xe3, 0x6f, 0x45, 0x21, 0xfa, 0xaa, 0x2e, 0xb6, 0x0e, 0xb7, 0xad, 0x1d, 0x65, + 0x2f, 0xb6, 0xe2, 0x1a, 0xc5, 0x19, 0x27, 0x81, 0x1f, 0x33, 0x66, 0xc2, 0x18, 0xca, 0x31, 0x7a, + 0x0f, 0x20, 0xe0, 0x79, 0x76, 0xe8, 0xf9, 0x39, 0x37, 0x89, 0x55, 0xd7, 0x80, 0xa0, 0x2b, 0xb0, + 0x9a, 0x45, 0x21, 0x99, 0xf6, 0xb8, 0x03, 0xdb, 0xb0, 0xee, 0xea, 0x51, 0x14, 0x12, 0x97, 0x4f, + 0x33, 0x63, 0x89, 0x32, 0x2f, 0x39, 0xa5, 0x1e, 0xf7, 0x02, 0x3c, 0xe4, 0xf5, 0x5c, 0x0b, 0xc6, + 0xcc, 0xf4, 0x38, 0x89, 0x43, 0x1e, 0xf6, 0x56, 0x5d, 0xfe, 0x1b, 0xff, 0xdc, 0x81, 0x01, 0xa7, + 0xe5, 0x92, 0x93, 0xe4, 0x95, 0x1f, 0x5b, 0x32, 0x73, 0x96, 0xcb, 0xac, 0x92, 0x9b, 0x99, 0x19, + 0x5d, 0xbb, 0x92, 0xd1, 0x99, 0xa7, 0x5f, 0xad, 0x9c, 0xbe, 0xba, 0xed, 0x4e, 0x7d, 0xdb, 0xf8, + 0x18, 0xd6, 0x84, 0x67, 0x42, 0x9f, 0x00, 0xcc, 0x8b, 0x33, 0xcf, 0xf2, 0x8e, 0x43, 0x4b, 0x22, + 0xae, 0x81, 0x80, 0x6e, 0x42, 0x3f, 0x23, 0x71, 0xac, 0xf0, 0x5b, 0x4d, 0xf8, 0x26, 0x06, 0xfe, + 0x54, 0x79, 0x4e, 0x9e, 0x7b, 0x30, 0x79, 0x31, 0xd7, 0x23, 0xd3, 0x5a, 0xfe, 0x9b, 0xd9, 0x70, + 0x72, 0x4a, 0x65, 0x51, 0xcb, 0x7e, 0xe2, 0x9f, 0x39, 0x72, 0xd5, 0x77, 0x8b, 0xd0, 0xcf, 0x09, + 0x0b, 0xe3, 0xe2, 0x2c, 0x0e, 0x37, 0x12, 0x9b, 0xdf, 0xfd, 0x15, 0x57, 0xcc, 0xa2, 0xdf, 0x84, + 0xa1, 0x90, 0x50, 0x2a, 0x04, 0x2f, 0xfd, 0xd5, 0x96, 0xbd, 0x3d, 0x31, 0x77, 0x7f, 0xc5, 0xb5, + 0x91, 0xf7, 0x46, 0x30, 0x10, 0x80, 0x82, 0x33, 0xc5, 0xff, 0xda, 0x82, 0x55, 0xe6, 0x2c, 0x97, + 0x17, 0x01, 0x6f, 0x94, 0xe2, 0x7d, 0x05, 0x83, 0x98, 0x86, 0x6a, 0xa8, 0xfc, 0xe2, 0x25, 0xd3, + 0x1d, 0xb3, 0x74, 0xe4, 0x71, 0x31, 0xff, 0x96, 0x9c, 0xc9, 0xb0, 0x63, 0xad, 0x60, 0xfc, 0x23, + 0x3a, 0x4f, 0x0a, 0x1a, 0xca, 0xd8, 0xa8, 0x86, 0x3a, 0x44, 0x74, 0x8c, 0x10, 0xc1, 0xbc, 0xc6, + 0xeb, 0x22, 0xf4, 0x6c, 0x57, 0x69, 0x82, 0xd0, 0xc7, 0xb0, 0x91, 0x91, 0x20, 0xa1, 0x61, 0x26, + 0xca, 0xc3, 0x20, 0x27, 0x21, 0xbf, 0x27, 0x43, 0xb7, 0x3e, 0xd1, 0x9c, 0xf3, 0xcd, 0xee, 0xc0, + 0xb8, 0xb2, 0xed, 0x86, 0xb0, 0xb8, 0x65, 0x86, 0xc5, 0x75, 0x33, 0x0c, 0xfe, 0x61, 0x0b, 0x36, + 0x1e, 0xb3, 0x4a, 0x4e, 0x2a, 0x45, 0xb8, 0xd3, 0xff, 0x4d, 0x9f, 0x63, 0xde, 0x9f, 0xd5, 0xca, + 0xfd, 0x51, 0x1e, 0xa0, 0x73, 0xbe, 0x07, 0xb8, 0x06, 0x93, 0x94, 0xf0, 0x7a, 0xd3, 0x2b, 0x49, + 0x09, 0x71, 0xd6, 0xe0, 0x2c, 0xd3, 0x8d, 0x4e, 0x4e, 0x48, 0x18, 0xf9, 0x39, 0x83, 0x7a, 0x01, + 0xab, 0x27, 0x62, 0x2e, 0xd5, 0x9e, 0xdb, 0x34, 0xc5, 0x44, 0x80, 0x4c, 0x11, 0x48, 0x4f, 0xfd, + 0x05, 0x2b, 0xf5, 0x73, 0x92, 0x52, 0x3f, 0xf6, 0x4e, 0xfc, 0x3c, 0x38, 0x26, 0x4b, 0xee, 0x65, + 0x0d, 0x0d, 0xfd, 0x06, 0x8c, 0x78, 0x2a, 0x9d, 0x15, 0x41, 0x40, 0x32, 0x96, 0x4c, 0x89, 0x0b, + 0x5a, 0xa6, 0xd0, 0xac, 0x62, 0x3c, 0x12, 0x93, 0x6e, 0x05, 0x15, 0x7d, 0xce, 0x32, 0xd5, 0x13, + 0x3f, 0xa2, 0x2c, 0x23, 0x17, 0xd7, 0xad, 0xdd, 0x70, 0xdd, 0xdc, 0x2a, 0x16, 0xfa, 0x02, 0x86, + 0x9c, 0xd4, 0x73, 0x3f, 0x8a, 0x8b, 0x94, 0x67, 0x70, 0x35, 0xa6, 0xbf, 0x25, 0xe6, 0x5c, 0x1b, + 0x13, 0xff, 0xa7, 0x03, 0x63, 0x2d, 0x82, 0x83, 0x57, 0xac, 0x94, 0xbf, 0x02, 0x1d, 0x7e, 0x9e, + 0xa5, 0x97, 0x9d, 0xcf, 0xa2, 0x2f, 0x60, 0x60, 0x1e, 0x40, 0xde, 0xf5, 0xa6, 0x93, 0xde, 0x5f, + 0x71, 0x2d, 0x54, 0xf4, 0xc5, 0x9b, 0x9d, 0xf4, 0xfe, 0x4a, 0xd3, 0x59, 0x07, 0xe6, 0x09, 0xb8, + 0x61, 0x35, 0x1f, 0xb5, 0xe4, 0x2a, 0x51, 0xf7, 0xba, 0xd0, 0x21, 0xec, 0x80, 0x38, 0x81, 0xbe, + 0x51, 0xca, 0x2c, 0x4d, 0xbc, 0x0c, 0xb7, 0xd3, 0xb2, 0xdd, 0x8e, 0x91, 0x07, 0xad, 0xd6, 0xf2, + 0x20, 0xd1, 0x78, 0xec, 0x18, 0x8d, 0x47, 0xfc, 0x29, 0x6c, 0x73, 0xaf, 0x47, 0x74, 0x97, 0xfa, + 0x17, 0x57, 0xea, 0x53, 0xd8, 0xa9, 0x2e, 0x92, 0x8d, 0xaf, 0x43, 0x40, 0x62, 0xc6, 0xba, 0xba, + 0xe7, 0x35, 0x20, 0xce, 0xb9, 0xc0, 0xf8, 0x33, 0xd8, 0xb4, 0xa8, 0xc9, 0x5b, 0xf0, 0x1e, 0x4c, + 0x14, 0x8a, 0x97, 0x50, 0x8f, 0x07, 0x59, 0xc7, 0x08, 0xb2, 0xe5, 0xf6, 0xee, 0xc6, 0xb1, 0x55, + 0x75, 0xe0, 0x02, 0x2e, 0xd4, 0x66, 0x24, 0xd1, 0x8f, 0x61, 0x83, 0x7b, 0x7b, 0x12, 0x96, 0xf7, + 0x56, 0xa5, 0xd7, 0xf5, 0x09, 0x86, 0x2d, 0x39, 0x1b, 0xd8, 0xa2, 0xe9, 0x56, 0x9f, 0xc0, 0x9f, + 0xc0, 0x86, 0x60, 0x6b, 0xf6, 0xfc, 0x97, 0x56, 0x51, 0x78, 0x4b, 0x09, 0xd1, 0x6a, 0xe1, 0xff, + 0x51, 0x8b, 0x81, 0xb3, 0x3c, 0x49, 0xad, 0xae, 0xe2, 0x1b, 0xb5, 0x08, 0xcd, 0xd6, 0x63, 0xcb, + 0x6e, 0x3d, 0xa2, 0x6f, 0xa1, 0xcf, 0x42, 0xca, 0xdc, 0x0f, 0x5e, 0x16, 0x0b, 0x15, 0x83, 0xae, + 0x29, 0xab, 0xad, 0x73, 0x64, 0x11, 0x69, 0x4f, 0x20, 0x8b, 0x88, 0x04, 0x71, 0x09, 0x40, 0x3f, + 0xe0, 0x8f, 0x23, 0x5e, 0xe8, 0xe7, 0xfe, 0xdc, 0xcf, 0x44, 0x5b, 0x76, 0xc0, 0x03, 0xcc, 0x3d, + 0x09, 0x92, 0xc1, 0xc1, 0xa4, 0xf0, 0x8b, 0x82, 0xc3, 0xc0, 0x0c, 0x0e, 0x84, 0xd9, 0x84, 0xb1, + 0x27, 0xdd, 0x29, 0x4d, 0x05, 0x58, 0x76, 0x40, 0xa5, 0x18, 0x14, 0x90, 0xb7, 0x3f, 0x3f, 0x62, + 0x3e, 0x5b, 0x22, 0xa9, 0x46, 0x82, 0xa8, 0xaa, 0xc7, 0x0a, 0xae, 0x1a, 0x9f, 0x1b, 0x30, 0x3e, + 0x3a, 0x2e, 0xf2, 0x30, 0x39, 0x55, 0xbd, 0x7f, 0x56, 0x5e, 0x69, 0x90, 0x54, 0xca, 0xaf, 0xc1, + 0xce, 0x51, 0x31, 0xcf, 0x82, 0x34, 0x9a, 0x13, 0xbb, 0x48, 0x9e, 0x41, 0x8f, 0xbc, 0x8e, 0xb2, + 0x3c, 0xa2, 0x2f, 0xf8, 0xc1, 0x7a, 0x6e, 0x39, 0xc6, 0xef, 0xc3, 0xbb, 0xe5, 0x2a, 0xe6, 0x16, + 0xb2, 0xbb, 0x41, 0x40, 0x16, 0x39, 0x09, 0x15, 0xab, 0x3b, 0xb0, 0x6d, 0x23, 0x18, 0x0f, 0x45, + 0xaa, 0xf8, 0xcd, 0xfd, 0x97, 0x32, 0xeb, 0xe9, 0xb9, 0x36, 0x10, 0xff, 0x77, 0x0b, 0x06, 0x6c, + 0x99, 0x22, 0x8b, 0x2e, 0xd6, 0x2e, 0x60, 0x97, 0x8f, 0x1f, 0xd8, 0xe9, 0x62, 0xab, 0x92, 0x2e, + 0x9e, 0x1b, 0x40, 0x97, 0x35, 0xfe, 0x74, 0xa0, 0xee, 0x98, 0x81, 0xba, 0xda, 0x4e, 0x5c, 0x6b, + 0x68, 0x27, 0xee, 0xc0, 0x5a, 0xca, 0x7b, 0x3d, 0xb2, 0x56, 0x93, 0x23, 0x16, 0x6b, 0x45, 0x4d, + 0xe3, 0xa5, 0x24, 0x20, 0xd1, 0x2b, 0x26, 0xd3, 0x1e, 0xe7, 0x5a, 0x83, 0xb3, 0x62, 0x46, 0xc2, + 0x32, 0xf9, 0xec, 0xb1, 0x2e, 0xde, 0x85, 0x6c, 0x28, 0xba, 0x01, 0x48, 0xf9, 0x33, 0x83, 0xaa, + 0x68, 0x51, 0x35, 0xcc, 0xb0, 0x3d, 0x94, 0x50, 0x45, 0xb9, 0x2f, 0xe2, 0x7d, 0x15, 0x8e, 0xff, + 0xca, 0x81, 0xbe, 0xe1, 0xee, 0x7f, 0xc9, 0x06, 0xac, 0x29, 0xe3, 0x76, 0x45, 0xc6, 0x55, 0x69, + 0xae, 0x36, 0x48, 0xf3, 0x43, 0x18, 0xc9, 0xf8, 0xe2, 0xa5, 0xc4, 0xcf, 0x12, 0xe5, 0xf9, 0x2b, + 0x50, 0xfc, 0xb7, 0x6d, 0xb1, 0x5b, 0x19, 0x12, 0xff, 0x7f, 0x8d, 0x45, 0xab, 0xbc, 0x63, 0xa9, + 0xfc, 0x2a, 0x8c, 0x2d, 0xd5, 0x92, 0x50, 0x6a, 0xbc, 0x0a, 0x66, 0x29, 0xad, 0x56, 0x6d, 0x2e, + 0xb5, 0x6d, 0x82, 0x6a, 0xc2, 0x82, 0x06, 0x61, 0x5d, 0x86, 0xd5, 0x34, 0x89, 0x09, 0x57, 0xe9, + 0x48, 0x77, 0x44, 0xdc, 0x24, 0x26, 0x2e, 0x9f, 0x61, 0x2e, 0xbf, 0x62, 0x16, 0x24, 0xe4, 0x6d, + 0xc8, 0x75, 0xb7, 0x3e, 0xc1, 0x2e, 0xaa, 0x69, 0x16, 0xf9, 0x74, 0x28, 0x1e, 0x34, 0x2c, 0x20, + 0xab, 0x46, 0x53, 0x6f, 0x91, 0x92, 0xe8, 0xc4, 0x7f, 0x41, 0xa6, 0x23, 0x8e, 0x62, 0x40, 0xf4, + 0x55, 0x1a, 0x1b, 0x57, 0x09, 0xff, 0x57, 0x0b, 0x3a, 0x4f, 0x52, 0x3f, 0x24, 0xac, 0xe4, 0x3a, + 0x61, 0x37, 0xde, 0x5b, 0x5e, 0x02, 0xb9, 0x26, 0x06, 0x5b, 0x90, 0x1b, 0x0b, 0x5a, 0x8d, 0x0b, + 0x0c, 0x0c, 0x43, 0x3f, 0x6d, 0x4b, 0x3f, 0xe7, 0xe9, 0xd4, 0xb0, 0x84, 0x8e, 0x6d, 0x09, 0xe5, + 0x79, 0xd6, 0x4c, 0xd7, 0xa0, 0x64, 0xdf, 0x5d, 0x2a, 0xfb, 0xcb, 0xd0, 0x27, 0xe2, 0x5d, 0x83, + 0x97, 0xed, 0xc2, 0x12, 0x4c, 0x50, 0x99, 0xb5, 0xaf, 0x9f, 0x9f, 0xb5, 0xdf, 0x86, 0x41, 0xc0, + 0x0c, 0x83, 0xa4, 0x0b, 0x3f, 0xcd, 0x85, 0x29, 0x2c, 0xef, 0x2c, 0x58, 0xb8, 0xf8, 0x3a, 0x6c, + 0x72, 0xa9, 0xdf, 0x8f, 0x58, 0xa8, 0x38, 0x33, 0xea, 0x12, 0xd1, 0xbc, 0x74, 0x8c, 0xe6, 0x25, + 0xbe, 0x03, 0x5b, 0x36, 0xb2, 0x8c, 0x53, 0x57, 0x60, 0x2d, 0x67, 0xf0, 0x5a, 0xde, 0xce, 0xb1, + 0x5d, 0x39, 0x89, 0x7f, 0xee, 0xc0, 0x90, 0x41, 0x22, 0xfa, 0xe2, 0x90, 0xd1, 0xcb, 0x98, 0xc0, + 0x4f, 0xfc, 0xd7, 0x1e, 0xab, 0x9f, 0x55, 0xa3, 0x40, 0x8d, 0x99, 0xc0, 0xd9, 0xef, 0x79, 0xa1, + 0x52, 0x28, 0x35, 0x14, 0x59, 0x4d, 0x46, 0x52, 0x9e, 0xbd, 0x14, 0xb9, 0xa8, 0x14, 0x85, 0x33, + 0xa9, 0x4f, 0xa0, 0xeb, 0x3c, 0x3e, 0x0a, 0xa0, 0x59, 0x56, 0x36, 0x21, 0xe3, 0x5d, 0x71, 0xc2, + 0x72, 0x87, 0x6f, 0x92, 0x38, 0xfe, 0xb5, 0x03, 0xdb, 0x95, 0x45, 0x52, 0x2e, 0x77, 0x61, 0x8d, + 0x0b, 0x4e, 0xc9, 0xe5, 0x23, 0x53, 0x2e, 0x35, 0xf4, 0x1b, 0x62, 0x28, 0x1b, 0xb1, 0x62, 0xe1, + 0xec, 0x31, 0xf4, 0x0d, 0x70, 0x43, 0x52, 0x71, 0xdd, 0x6e, 0xc4, 0x6e, 0x37, 0xb3, 0x30, 0x72, + 0x8d, 0x1f, 0xc3, 0xe0, 0x3b, 0x3a, 0xff, 0x25, 0x5e, 0xff, 0xd1, 0x25, 0x58, 0x4f, 0x89, 0x2c, + 0x93, 0x65, 0x8a, 0xa1, 0x01, 0x78, 0x0c, 0x43, 0x49, 0x57, 0xbf, 0x17, 0x7f, 0x47, 0xe3, 0x24, + 0x78, 0xf9, 0xa6, 0xef, 0xc5, 0x3f, 0x01, 0x64, 0x2e, 0xd0, 0x49, 0x50, 0xc1, 0xa1, 0x95, 0x24, + 0x48, 0x01, 0x79, 0x12, 0xf4, 0x3e, 0xf4, 0x4d, 0x14, 0xf1, 0xbc, 0x04, 0x1a, 0x01, 0xff, 0x89, + 0x03, 0xe3, 0xa7, 0x51, 0x7e, 0x1c, 0xa6, 0xfe, 0xe9, 0x1b, 0x28, 0xb5, 0xfa, 0x76, 0xdf, 0x3a, + 0xef, 0xed, 0xbe, 0x5d, 0x7d, 0xbb, 0xf7, 0xe3, 0x58, 0x76, 0x2e, 0xd8, 0x4f, 0xb3, 0x67, 0x39, + 0x14, 0x3d, 0xcb, 0xdb, 0x30, 0xd1, 0x9b, 0x79, 0xbb, 0x86, 0xe5, 0xb5, 0xab, 0xb0, 0x5e, 0x3a, + 0x00, 0xd4, 0x85, 0xf6, 0xde, 0x77, 0xbf, 0x3d, 0x59, 0x41, 0x3d, 0x58, 0x3d, 0x3a, 0x38, 0x3c, + 0x14, 0x6f, 0x03, 0xfc, 0xb9, 0xa0, 0x75, 0xed, 0x1a, 0xac, 0x32, 0x77, 0x83, 0xd6, 0xa1, 0xf3, + 0xe4, 0xee, 0xb7, 0x07, 0xee, 0x64, 0x85, 0xfd, 0xfc, 0x11, 0xff, 0xe9, 0xa0, 0x01, 0xf4, 0x1e, + 0x3c, 0x7c, 0x72, 0xe0, 0x3e, 0xbc, 0x7b, 0x38, 0x69, 0xed, 0xfe, 0xbb, 0x03, 0xdd, 0x67, 0x45, + 0xf8, 0x80, 0x46, 0x39, 0x3a, 0x00, 0xd0, 0xcf, 0xf6, 0xe8, 0x62, 0xd9, 0xd1, 0xae, 0x3e, 0xfe, + 0xcf, 0x66, 0x4d, 0x53, 0x52, 0xfb, 0x2b, 0xe8, 0x3e, 0xf4, 0x8d, 0xa4, 0x16, 0xcd, 0x96, 0x67, + 0xdf, 0xb3, 0x77, 0x1a, 0xe7, 0x4a, 0x4a, 0x07, 0x00, 0xda, 0x30, 0xf4, 0x86, 0x6a, 0xd6, 0xa5, + 0x37, 0x54, 0xb7, 0x23, 0xbc, 0xb2, 0xfb, 0x37, 0x17, 0xa0, 0xfd, 0xac, 0x08, 0xd1, 0x33, 0xe8, + 0x1b, 0x5f, 0x30, 0xa1, 0xda, 0x6b, 0x91, 0xde, 0x4e, 0xd3, 0x87, 0x4e, 0xb3, 0x9f, 0xfd, 0xd3, + 0x7f, 0xfc, 0x69, 0x6b, 0x0b, 0x8f, 0x6f, 0xbe, 0xfa, 0xd5, 0x9b, 0x7e, 0x18, 0x2a, 0x93, 0xb9, + 0xed, 0x5c, 0x43, 0x2e, 0x74, 0xe5, 0x47, 0x4a, 0x68, 0xc7, 0xa0, 0x61, 0x54, 0x48, 0xb3, 0x0b, + 0x35, 0xb8, 0xa4, 0xbb, 0xc3, 0xe9, 0x4e, 0x70, 0x5f, 0xd2, 0x65, 0xe1, 0x85, 0xd1, 0xdc, 0x83, + 0xf6, 0x9e, 0x4f, 0x11, 0xd2, 0x2f, 0xb7, 0xea, 0xea, 0xce, 0x36, 0x2d, 0x98, 0xa4, 0x83, 0x38, + 0x9d, 0x01, 0xee, 0x32, 0x3a, 0x73, 0x9f, 0x32, 0x1a, 0x01, 0x0c, 0xcc, 0xaf, 0x47, 0x90, 0xfe, + 0x86, 0xa1, 0xfe, 0x49, 0xcc, 0xec, 0x52, 0xf3, 0xa4, 0x24, 0x3f, 0xe5, 0xe4, 0x11, 0x9e, 0x30, + 0xf2, 0xfc, 0xe3, 0x1a, 0xf9, 0x16, 0xc2, 0x0e, 0x2f, 0x3f, 0x19, 0xd1, 0x87, 0xb7, 0xbf, 0x38, + 0xd1, 0x87, 0xaf, 0x7e, 0x5b, 0x62, 0x1d, 0x5e, 0x7a, 0x14, 0xb6, 0xf1, 0x9f, 0xc2, 0xf0, 0x29, + 0xff, 0x74, 0x49, 0x7e, 0xa8, 0xa0, 0x29, 0xdb, 0xdf, 0x39, 0x68, 0xca, 0x95, 0x2f, 0x1a, 0xf0, + 0x25, 0x4e, 0x79, 0x07, 0x6f, 0x30, 0xca, 0xe2, 0x33, 0xa8, 0x50, 0xa0, 0x30, 0xfa, 0xbf, 0x07, + 0x43, 0xeb, 0x9b, 0x04, 0x54, 0x1e, 0xbe, 0xe9, 0x63, 0x87, 0xd9, 0xbb, 0x4b, 0x66, 0x9b, 0x78, + 0x85, 0x12, 0x85, 0x7f, 0xc5, 0xc0, 0x78, 0x3d, 0x03, 0xd0, 0x6f, 0xfb, 0xda, 0x8a, 0x6b, 0xdf, + 0x13, 0x68, 0x2b, 0xae, 0x7f, 0x0a, 0x80, 0x37, 0x39, 0x8b, 0x21, 0xea, 0x0b, 0xed, 0x0a, 0x5a, + 0x87, 0xd0, 0x95, 0xaf, 0xd8, 0x5a, 0x3e, 0xf6, 0x53, 0xbe, 0x96, 0x4f, 0xe5, 0xb9, 0x1b, 0x4f, + 0x38, 0x41, 0x40, 0x3d, 0x46, 0x30, 0x62, 0x24, 0x7e, 0x07, 0xfa, 0xc6, 0xc3, 0x2e, 0x32, 0x77, + 0x53, 0x79, 0x2d, 0xd6, 0x17, 0xa5, 0xe1, 0x25, 0x18, 0x6f, 0x71, 0xca, 0x23, 0x34, 0x60, 0x94, + 0x99, 0x14, 0x38, 0xf5, 0xa7, 0x00, 0xfa, 0x0d, 0x52, 0x4b, 0xa1, 0xf6, 0x98, 0xaa, 0xa5, 0x50, + 0x7f, 0xb2, 0x54, 0x36, 0x8e, 0x80, 0x91, 0x96, 0x9d, 0xfa, 0x17, 0x30, 0xb2, 0x9f, 0x88, 0xd1, + 0xbb, 0x26, 0x85, 0xda, 0x9b, 0xf2, 0xec, 0xbd, 0x65, 0xd3, 0xb6, 0x4d, 0xa2, 0x11, 0xb7, 0x49, + 0x4d, 0xf6, 0x08, 0xd6, 0xcb, 0xc7, 0x4b, 0x34, 0x35, 0x89, 0x98, 0x6f, 0x9c, 0xb3, 0x8b, 0x0d, + 0x33, 0x92, 0xf2, 0x06, 0xa7, 0xdc, 0x47, 0xeb, 0x8c, 0xb2, 0xe8, 0x61, 0x2b, 0xa2, 0xfc, 0x9b, + 0x07, 0x9b, 0xa8, 0xf1, 0xf2, 0x59, 0x21, 0x6a, 0xbe, 0x7f, 0x56, 0x88, 0x72, 0x3a, 0x1e, 0xf4, + 0x8d, 0xa7, 0x31, 0xad, 0xc9, 0xfa, 0xbb, 0x9e, 0xd6, 0x64, 0xc3, 0x5b, 0x1a, 0xbe, 0xc0, 0x49, + 0x6f, 0x08, 0x97, 0x97, 0x2c, 0x08, 0x55, 0x57, 0xfe, 0x77, 0x01, 0x74, 0x37, 0x53, 0x2b, 0xb3, + 0xd6, 0xe7, 0xd6, 0xe6, 0x57, 0x69, 0x7e, 0xe2, 0x8b, 0x9c, 0xf4, 0x26, 0xe6, 0x42, 0xe6, 0x1d, + 0x66, 0xae, 0xce, 0xdb, 0xce, 0xb5, 0x5b, 0x0e, 0x7a, 0x0e, 0x23, 0x8d, 0x7f, 0x74, 0x46, 0x83, + 0xf3, 0x58, 0xcc, 0x9a, 0xa6, 0xe4, 0x01, 0xde, 0xe5, 0x5c, 0x2e, 0x60, 0x64, 0x73, 0xc9, 0xce, + 0x68, 0xc0, 0x6e, 0xe6, 0x4f, 0xa0, 0x6f, 0x7c, 0x61, 0xa4, 0xe5, 0x54, 0xff, 0xec, 0x68, 0xd6, + 0xd4, 0x6f, 0xb5, 0x43, 0x82, 0x4c, 0xe0, 0xb3, 0x53, 0x7f, 0xc1, 0x68, 0x53, 0x18, 0xd9, 0x6d, + 0x45, 0x6d, 0x96, 0x8d, 0x3d, 0x4a, 0x6d, 0x96, 0x4b, 0xba, 0x91, 0xd6, 0x59, 0x44, 0x13, 0xcf, + 0x0c, 0x41, 0x73, 0x16, 0x75, 0xcb, 0xf6, 0xa2, 0x19, 0x75, 0xab, 0x1d, 0x4c, 0x33, 0xea, 0xd6, + 0xfa, 0x91, 0xf6, 0x99, 0x04, 0x1b, 0xa5, 0x19, 0x94, 0xc2, 0xb8, 0xd2, 0x71, 0x44, 0x95, 0x5d, + 0x57, 0x9b, 0x94, 0xb3, 0xf7, 0x97, 0xce, 0x4b, 0x7e, 0xef, 0x71, 0x7e, 0x53, 0xbc, 0xa9, 0xf9, + 0xf9, 0x71, 0x2c, 0xd4, 0x24, 0x22, 0x01, 0xe8, 0xfe, 0xa1, 0xb6, 0x83, 0x5a, 0x0b, 0x72, 0x36, + 0x6b, 0x9a, 0x92, 0x4c, 0x2c, 0x6b, 0x13, 0x4c, 0x54, 0x98, 0xfd, 0x31, 0xf4, 0x54, 0x23, 0x0c, + 0x95, 0xd6, 0x5a, 0xe9, 0x96, 0xcd, 0xa6, 0xf5, 0x89, 0xca, 0x15, 0xe1, 0xce, 0x2e, 0x93, 0xb3, + 0x8c, 0x2e, 0x81, 0x71, 0xa5, 0x99, 0xa6, 0x65, 0xd5, 0xdc, 0x65, 0x9b, 0xd9, 0x1f, 0x31, 0x89, + 0x27, 0x41, 0xfc, 0x0e, 0x67, 0xb0, 0x8d, 0xb8, 0x7c, 0x32, 0xb5, 0x50, 0xc8, 0xe7, 0x96, 0x83, + 0x16, 0x95, 0xe6, 0x9a, 0xec, 0xd2, 0x18, 0x4e, 0xb0, 0xb1, 0xf7, 0x36, 0x6b, 0xea, 0xe4, 0xe3, + 0x1f, 0x70, 0x5e, 0xef, 0xa0, 0x8b, 0x16, 0x2f, 0x66, 0xd1, 0xea, 0x21, 0xe3, 0x96, 0x83, 0xe6, + 0x30, 0xb2, 0x49, 0xbe, 0x15, 0xab, 0xca, 0xd5, 0x41, 0xa8, 0xc6, 0x8a, 0xf1, 0xf8, 0x03, 0xa3, + 0x13, 0x69, 0xf5, 0x14, 0xd1, 0x95, 0x66, 0x5e, 0x95, 0x9e, 0xe3, 0x6c, 0xcb, 0xe4, 0xa9, 0x26, + 0x31, 0xe6, 0x4c, 0x2f, 0xa1, 0x59, 0x9d, 0xa9, 0x2f, 0x71, 0xb8, 0xf7, 0x19, 0x98, 0xd5, 0xae, + 0x4e, 0x9a, 0x1a, 0x0a, 0x66, 0x9d, 0x34, 0x35, 0x15, 0xc8, 0x4a, 0x79, 0x22, 0x69, 0xe2, 0xd5, + 0xf0, 0xb1, 0xc0, 0x60, 0x16, 0xf2, 0xa2, 0x5a, 0x15, 0x5f, 0x5a, 0x52, 0x26, 0x56, 0x72, 0x90, + 0xc6, 0x22, 0x52, 0x99, 0x38, 0xda, 0x50, 0xac, 0x22, 0xfa, 0x42, 0xd4, 0x92, 0xe8, 0x1b, 0xe8, + 0xf0, 0x0a, 0x0d, 0x6d, 0xe9, 0x34, 0x59, 0x17, 0x82, 0xb3, 0xed, 0x0a, 0xd4, 0x0e, 0xe3, 0x98, + 0xc7, 0x95, 0x82, 0xca, 0x8c, 0x72, 0x0e, 0x23, 0x91, 0x98, 0xa9, 0x3a, 0x46, 0x5f, 0x9a, 0x4a, + 0x99, 0xa5, 0x2f, 0x4d, 0xb5, 0xe4, 0xb1, 0x5d, 0x99, 0xc8, 0xcd, 0x4e, 0x25, 0xce, 0x6d, 0xe7, + 0xda, 0x7c, 0x8d, 0xff, 0xe1, 0xe0, 0xd3, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x73, 0xf8, 0x32, + 0x65, 0x9b, 0x30, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4907,6 +4993,11 @@ type XudClient interface { // on hold due to ongoing swaps will not be removed until after the swap attempts complete. // shell: xucli removeorder [quantity] RemoveOrder(ctx context.Context, in *RemoveOrderRequest, opts ...grpc.CallOption) (*RemoveOrderResponse, error) + // Removes all orders from the order book. Removed orders become immediately unavailable for swaps, + // and peers are notified that the orders are no longer valid. Any portion of the orders that is + // on hold due to ongoing swaps will not be removed until after the swap attempts complete. + // shell: xucli removeallorders + RemoveAllOrders(ctx context.Context, in *RemoveAllOrdersRequest, opts ...grpc.CallOption) (*RemoveAllOrdersResponse, error) // Removes a trading pair from the list of currently supported trading pair. This call will // effectively cancel any standing orders for that trading pair. Peers are informed when a pair // is no longer supported so that they will know to stop sending orders for it. @@ -5159,6 +5250,15 @@ func (c *xudClient) RemoveOrder(ctx context.Context, in *RemoveOrderRequest, opt return out, nil } +func (c *xudClient) RemoveAllOrders(ctx context.Context, in *RemoveAllOrdersRequest, opts ...grpc.CallOption) (*RemoveAllOrdersResponse, error) { + out := new(RemoveAllOrdersResponse) + err := c.cc.Invoke(ctx, "/xudrpc.Xud/RemoveAllOrders", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *xudClient) RemovePair(ctx context.Context, in *RemovePairRequest, opts ...grpc.CallOption) (*RemovePairResponse, error) { out := new(RemovePairResponse) err := c.cc.Invoke(ctx, "/xudrpc.Xud/RemovePair", in, out, opts...) @@ -5417,6 +5517,11 @@ type XudServer interface { // on hold due to ongoing swaps will not be removed until after the swap attempts complete. // shell: xucli removeorder [quantity] RemoveOrder(context.Context, *RemoveOrderRequest) (*RemoveOrderResponse, error) + // Removes all orders from the order book. Removed orders become immediately unavailable for swaps, + // and peers are notified that the orders are no longer valid. Any portion of the orders that is + // on hold due to ongoing swaps will not be removed until after the swap attempts complete. + // shell: xucli removeallorders + RemoveAllOrders(context.Context, *RemoveAllOrdersRequest) (*RemoveAllOrdersResponse, error) // Removes a trading pair from the list of currently supported trading pair. This call will // effectively cancel any standing orders for that trading pair. Peers are informed when a pair // is no longer supported so that they will know to stop sending orders for it. @@ -5825,6 +5930,24 @@ func _Xud_RemoveOrder_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } +func _Xud_RemoveAllOrders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveAllOrdersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(XudServer).RemoveAllOrders(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/xudrpc.Xud/RemoveAllOrders", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(XudServer).RemoveAllOrders(ctx, req.(*RemoveAllOrdersRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Xud_RemovePair_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(RemovePairRequest) if err := dec(in); err != nil { @@ -6097,6 +6220,10 @@ var _Xud_serviceDesc = grpc.ServiceDesc{ MethodName: "RemoveOrder", Handler: _Xud_RemoveOrder_Handler, }, + { + MethodName: "RemoveAllOrders", + Handler: _Xud_RemoveAllOrders_Handler, + }, { MethodName: "RemovePair", Handler: _Xud_RemovePair_Handler, From 767f3d68a1b0f0fca1f0e9b8bd8f42c11e43f9e8 Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Mon, 19 Oct 2020 11:46:23 -0400 Subject: [PATCH 11/11] feat(rpc): runtime addcurrency for lnd & connext This PR allows for adding Connext and Lnd currencies via the `AddCurrency` rpc call and have them available for trading immediately without requiring a restart of xud. In the case of Connext it merely registers the tokenaddress and currency symbol for the new currency with the existing ConnextClient, as we had previously done with Raiden. In the case of Lnd, we read from the configuration and use that to instantiate and initialize a new `LndClient` for the specified currency. Closes #1111. Co-authored-by: Le Premier Homme --- lib/orderbook/OrderBook.ts | 13 +++++++++++-- lib/p2p/Pool.ts | 8 +++++++- lib/swaps/SwapClientManager.ts | 24 +++++++++++++----------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/lib/orderbook/OrderBook.ts b/lib/orderbook/OrderBook.ts index ed8b42de7..98c29505c 100644 --- a/lib/orderbook/OrderBook.ts +++ b/lib/orderbook/OrderBook.ts @@ -304,6 +304,11 @@ class OrderBook extends EventEmitter { this.pairInstances.set(pairInstance.id, pairInstance); this.addTradingPair(pairInstance.id); + this.pool.rawPeers().forEach(async (peer) => { + this.checkPeerCurrencies(peer); + await this.verifyPeerPairs(peer); + }); + this.pool.updatePairs(this.pairIds); return pairInstance; } @@ -332,7 +337,7 @@ class OrderBook extends EventEmitter { } const currencyInstance = await this.repository.addCurrency({ ...currency, decimalPlaces: currency.decimalPlaces || 8 }); this.currencyInstances.set(currencyInstance.id, currencyInstance); - this.swaps.swapClientManager.add(currencyInstance); + await this.swaps.swapClientManager.add(currencyInstance); } public removeCurrency = async (currencyId: string) => { @@ -344,7 +349,6 @@ class OrderBook extends EventEmitter { } } this.currencyInstances.delete(currencyId); - this.swaps.swapClientManager.remove(currencyId); await currency.destroy(); } else { throw errors.CURRENCY_DOES_NOT_EXIST(currencyId); @@ -360,6 +364,11 @@ class OrderBook extends EventEmitter { this.pairInstances.delete(pairId); this.tradingPairs.delete(pairId); + this.pool.rawPeers().forEach(async (peer) => { + this.checkPeerCurrencies(peer); + await this.verifyPeerPairs(peer); + }); + this.pool.updatePairs(this.pairIds); return pair.destroy(); } diff --git a/lib/p2p/Pool.ts b/lib/p2p/Pool.ts index d4cc7c0c2..dc41b5867 100644 --- a/lib/p2p/Pool.ts +++ b/lib/p2p/Pool.ts @@ -238,7 +238,9 @@ class Pool extends EventEmitter { * packet to currently connected peers to notify them of the change. */ public updateConnextState = (tokenAddresses: Map, pubKey?: string) => { - this.nodeState.connextIdentifier = pubKey || ''; + if (pubKey) { + this.nodeState.connextIdentifier = pubKey; + } tokenAddresses.forEach((tokenAddress, currency) => { this.nodeState.tokenIdentifiers[currency] = tokenAddress; }); @@ -476,6 +478,10 @@ class Pool extends EventEmitter { return peerInfos; } + public rawPeers = (): Map => { + return this.peers; + } + private addressIsSelf = (address: Address): boolean => { if (address.port === this.listenPort) { switch (address.host) { diff --git a/lib/swaps/SwapClientManager.ts b/lib/swaps/SwapClientManager.ts index 4e0877287..b2bba6d37 100644 --- a/lib/swaps/SwapClientManager.ts +++ b/lib/swaps/SwapClientManager.ts @@ -338,19 +338,21 @@ class SwapClientManager extends EventEmitter { * @param currency a currency that should be linked with a swap client. * @returns Nothing upon success, throws otherwise. */ - public add = (currency: Currency): void => { - if (currency.swapClient === SwapClientType.Lnd) { - // in case of lnd we check if the configuration includes swap client - // for the specified currency - let isCurrencyConfigured = false; - for (const lndCurrency in this.config.lnd) { - if (lndCurrency === currency.id) { - isCurrencyConfigured = true; - break; + public add = async (currency: Currency) => { + if (currency.tokenAddress) { + if (currency.swapClient === SwapClientType.Connext) { + if (!this.connextClient) { + throw errors.SWAP_CLIENT_NOT_CONFIGURED(currency.id); } + this.swapClients.set(currency.id, this.connextClient); + this.connextClient.tokenAddresses.set(currency.id, currency.tokenAddress); + this.emit('connextUpdate', this.connextClient.tokenAddresses); } - // adding a new lnd client at runtime is currently not supported - if (!isCurrencyConfigured) { + } else if (currency.swapClient === SwapClientType.Lnd) { + // in case of lnd we check if the configuration includes swap client + // for the specified currency + const config = this.config.lnd[currency.id]; + if (!config) { throw errors.SWAP_CLIENT_NOT_CONFIGURED(currency.id); } }