From b8f6202b9fa14480e8b63781f235f48e61cd4e45 Mon Sep 17 00:00:00 2001 From: Thomas Nguy Date: Mon, 5 Sep 2022 15:38:49 +0900 Subject: [PATCH] implement adr-007 --- app/app.go | 2 + contracts/src/ModuleCRC21.sol | 18 +- docs/architecture/README.md | 2 +- docs/architecture/adr-007.md | 5 +- .../evmhandlers/cancel_send_to_evm_chain.go | 126 +++++++++++++ .../keeper/evmhandlers/send_to_evm_chain.go | 170 ++++++++++++++++++ x/cronos/keeper/evmhandlers/send_to_ibc.go | 45 ++++- x/cronos/types/contracts/ModuleCRC21.json | 63 +++++-- 8 files changed, 400 insertions(+), 31 deletions(-) create mode 100644 x/cronos/keeper/evmhandlers/cancel_send_to_evm_chain.go create mode 100644 x/cronos/keeper/evmhandlers/send_to_evm_chain.go diff --git a/app/app.go b/app/app.go index e568c36d98..ec3fcc30c8 100644 --- a/app/app.go +++ b/app/app.go @@ -515,6 +515,8 @@ func New( evmhandlers.NewCancelSendToChainHandler(gravitySrv, app.CronosKeeper, app.GravityKeeper), evmhandlers.NewSendToIbcHandler(app.BankKeeper, app.CronosKeeper), evmhandlers.NewSendCroToIbcHandler(app.BankKeeper, app.CronosKeeper), + evmhandlers.NewSendToEvmChainHandler(gravitySrv, app.BankKeeper, app.CronosKeeper), + evmhandlers.NewCancelSendToEvmChainHandler(gravitySrv, app.CronosKeeper, app.GravityKeeper), )) // register the staking hooks diff --git a/contracts/src/ModuleCRC21.sol b/contracts/src/ModuleCRC21.sol index d3f6d8930e..31e3201dbc 100644 --- a/contracts/src/ModuleCRC21.sol +++ b/contracts/src/ModuleCRC21.sol @@ -8,9 +8,9 @@ contract ModuleCRC21 is DSToken { string denom; bool isSource; - event __CronosSendToIbc(address sender, string recipient, uint256 amount); - event __CronosSendToChain(address sender, address recipient, uint256 amount, uint256 bridge_fee, uint256 chain_id); - event __CronosCancelSendToChain(address sender, uint256 id); + event __CronosSendToIbc(address indexed sender, string indexed recipient, uint256 amount, string indexed channel_id, bytes extraData); + event __CronosSendToEvmChain(address indexed sender, address indexed recipient, uint256 indexed chain_id, uint256 amount, uint256 bridge_fee, bytes extraData); + event __CronosCancelSendToEvmChain(address indexed sender, uint256 id); constructor(string memory denom_, uint8 decimals_, bool isSource_) DSToken(denom_) public { decimals = decimals_; @@ -57,28 +57,28 @@ contract ModuleCRC21 is DSToken { **/ // send an "amount" of the contract token to recipient through IBC - function send_to_ibc(string memory recipient, uint amount) public { + function send_to_ibc(string memory recipient, uint amount, string memory channel_id, bytes memory extraData) public { if (isSource) { transferFrom(msg.sender, module_address, amount); } else { unsafe_burn(msg.sender, amount); } - emit __CronosSendToIbc(msg.sender, recipient, amount); + emit __CronosSendToIbc(msg.sender, recipient, amount, channel_id, extraData); } // send to another chain through gravity bridge - function send_to_chain(address recipient, uint amount, uint bridge_fee, uint chain_id) external { + function send_to_evm_chain(address recipient, uint amount, uint chain_id, uint bridge_fee, bytes calldata extraData) external { if (isSource) { transferFrom(msg.sender, module_address, add(amount, bridge_fee)); } else { unsafe_burn(msg.sender, add(amount, bridge_fee)); } - emit __CronosSendToChain(msg.sender, recipient, amount, bridge_fee, chain_id); + emit __CronosSendToEvmChain(msg.sender, recipient, chain_id, amount, bridge_fee, extraData); } // cancel a send to chain transaction considering if it hasnt been batched yet. - function cancel_send_to_chain(uint256 id) external { - emit __CronosCancelSendToChain(msg.sender, id); + function cancel_send_to_evm_chain(uint256 id) external { + emit __CronosCancelSendToEvmChain(msg.sender, id); } /** diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 1be2fe6a2a..4c29b60196 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -33,5 +33,5 @@ To suggest an ADR, please make use of the [ADR template](./adr-template.md) prov | [004](./adr-004.md) | Tokens conversion in Cronos | Accepted | | [005](./adr-005.md) | Cross-chain Validation for Gravity Bridge | Rejected | | [006](./adr-006.md) | Migrating CRC20 contract to CRC21 standard | Rejected | -| [007](./adr-007.md) | Generic event format for evm-hook actions | Proposed | +| [007](./adr-007.md) | Generic event format for evm-hook actions | Accepted | | [008](./adr-008.md) | Denom and Contract Mapping Enhancement for Bi-Directional Token Conversion | Accepted | diff --git a/docs/architecture/adr-007.md b/docs/architecture/adr-007.md index 941b8171ad..cb787ceb3f 100644 --- a/docs/architecture/adr-007.md +++ b/docs/architecture/adr-007.md @@ -4,6 +4,7 @@ * 2022-06-09: Initial Draft * 2022-08-03: Update proposal to generic argument option +* 2022-09-05: Move to accepted ## Context @@ -31,7 +32,7 @@ In this ADR, we define generic event argument that can be extended to accept new event __CronosSendToIbc(address sender, string recipient, uint256 amount); // Proposal -event __CronosSendToIbc(address sender, string recipient, uint256 amount, string channelId, bytes extraData); +event __CronosSendToIbc(address indexed sender, string indexed recipient, uint256 amount, string indexed channelId, bytes extraData); ``` #### Description @@ -58,7 +59,7 @@ event __CronosSendToIbc(address sender, string recipient, uint256 amount, string event __CronosSendToChain(address sender, address recipient, uint256 amount, uint256 bridge_fee, uint256 chain_id); // Proposal -event __CronosSendToEVMChain(address sender, address recipient, uint256 amount, string chain_id, bytes extraData); +event __CronosSendToEvmChain(address indexed sender, address indexed recipient, uint256 indexed chain_id, uint256 amount, uint256 bridge_fee, bytes extraData); ``` #### Description diff --git a/x/cronos/keeper/evmhandlers/cancel_send_to_evm_chain.go b/x/cronos/keeper/evmhandlers/cancel_send_to_evm_chain.go new file mode 100644 index 0000000000..7f8971ff28 --- /dev/null +++ b/x/cronos/keeper/evmhandlers/cancel_send_to_evm_chain.go @@ -0,0 +1,126 @@ +package evmhandler + +import ( + "fmt" + "math/big" + + gravitytypes "github.com/peggyjv/gravity-bridge/module/v2/x/gravity/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + cronoskeeper "github.com/crypto-org-chain/cronos/x/cronos/keeper" + "github.com/crypto-org-chain/cronos/x/cronos/types" +) + +var _ types.EvmLogHandler = CancelSendToChainHandler{} + +const CancelSendToEvmChainEventName = "__CronosCancelSendToEvmChain" + +// CancelSendToEvmChainEvent represent the signature of +// `event __CronosCancelSendToEvmChain(uint256 id)` +var CancelSendToEvmChainEvent abi.Event + +func init() { + addressType, _ := abi.NewType("address", "", nil) + uint256Type, _ := abi.NewType("uint256", "", nil) + + CancelSendToEvmChainEvent = abi.NewEvent( + CancelSendToEvmChainEventName, + CancelSendToEvmChainEventName, + false, + abi.Arguments{abi.Argument{ + Name: "sender", + Type: addressType, + Indexed: false, + }, abi.Argument{ + Name: "id", + Type: uint256Type, + Indexed: false, + }}, + ) +} + +// CancelSendToEvmChainHandler handles `__CronosCancelSendToEvmChain` log +type CancelSendToEvmChainHandler struct { + gravitySrv gravitytypes.MsgServer + cronosKeeper cronoskeeper.Keeper + gravityKeeper types.GravityKeeper +} + +func NewCancelSendToEvmChainHandler( + gravitySrv gravitytypes.MsgServer, + cronosKeeper cronoskeeper.Keeper, + gravityKeeper types.GravityKeeper, +) *CancelSendToEvmChainHandler { + return &CancelSendToEvmChainHandler{ + gravitySrv: gravitySrv, + cronosKeeper: cronosKeeper, + gravityKeeper: gravityKeeper, + } +} + +func (h CancelSendToEvmChainHandler) EventID() common.Hash { + return CancelSendToChainEvent.ID +} + +// Handle `__CronosCancelSendToChain` log only if gravity is activated. +func (h CancelSendToEvmChainHandler) Handle( + ctx sdk.Context, + _ common.Address, + data []byte, + _ func(contractAddress common.Address, logSig common.Hash, logData []byte), +) error { + if h.gravitySrv == nil { + return fmt.Errorf("native action %s is not implemented", CancelSendToChainEventName) + } + + unpacked, err := CancelSendToChainEvent.Inputs.Unpack(data) + if err != nil { + // log and ignore + h.cronosKeeper.Logger(ctx).Info("log signature matches but failed to decode") + return nil + } + + senderCosmosAddr := sdk.AccAddress(unpacked[0].(common.Address).Bytes()) + id := sdk.NewIntFromBigInt(unpacked[1].(*big.Int)) + + // Need to retrieve the batch to get the amount to refund + var unbatched []*gravitytypes.SendToEthereum + h.gravityKeeper.IterateUnbatchedSendToEthereums(ctx, func(ste *gravitytypes.SendToEthereum) bool { + unbatched = append(unbatched, ste) + return false + }) + + var send *gravitytypes.SendToEthereum + for _, ste := range unbatched { + if ste.Id == id.Uint64() { + send = ste + } + } + if send == nil { + return fmt.Errorf("id not found or the transaction is already included in a batch") + } + + _, denom := h.gravityKeeper.ERC20ToDenomLookup(ctx, common.HexToAddress(send.Erc20Token.Contract)) + if !types.IsValidGravityDenom(denom) { + return fmt.Errorf("the native token associated with the contract %s is not a gravity voucher", send.Erc20Token.Contract) + } + + msg := gravitytypes.MsgCancelSendToEthereum{ + Sender: senderCosmosAddr.String(), + Id: id.Uint64(), + } + _, err = h.gravitySrv.CancelSendToEthereum(sdk.WrapSDKContext(ctx), &msg) + if err != nil { + return err + } + refundAmount := sdk.NewCoins(sdk.NewCoin(denom, send.Erc20Token.Amount.Add(send.Erc20Fee.Amount))) + // If cancel has no error, we need to convert back the native token to evm tokens + err = h.cronosKeeper.ConvertVouchersToEvmCoins(ctx, senderCosmosAddr.String(), refundAmount) + if err != nil { + return err + } + return nil +} diff --git a/x/cronos/keeper/evmhandlers/send_to_evm_chain.go b/x/cronos/keeper/evmhandlers/send_to_evm_chain.go new file mode 100644 index 0000000000..b7e29ea19d --- /dev/null +++ b/x/cronos/keeper/evmhandlers/send_to_evm_chain.go @@ -0,0 +1,170 @@ +package evmhandler + +import ( + "fmt" + "math/big" + + gravitytypes "github.com/peggyjv/gravity-bridge/module/v2/x/gravity/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + cronoskeeper "github.com/crypto-org-chain/cronos/x/cronos/keeper" + "github.com/crypto-org-chain/cronos/x/cronos/types" +) + +var _ types.EvmLogHandler = SendToEvmChainHandler{} + +const ( + SendToEvmChainEventName = "__CronosSendToEvmChain" + SendToEvmChainResponseEventName = "__CronosSendToEvmChainResponse" +) + +var ( + // SendToEvmChainEvent represent the signature of + // `event __CronosSendToEvmChain(address indexed sender, address indexed recipient, uint256 indexed chain_id, uint256 amount, uint256 bridge_fee, bytes extraData)` + SendToEvmChainEvent abi.Event + + // SendToEvmChainResponseEvent represent the signature of + // `event __CronosSendToChainResponse(uint256 id)` + SendToEvmChainResponseEvent abi.Event +) + +func init() { + addressType, _ := abi.NewType("address", "", nil) + uint256Type, _ := abi.NewType("uint256", "", nil) + bytesType, _ := abi.NewType("bytes", "", nil) + + SendToEvmChainEvent = abi.NewEvent( + SendToEvmChainEventName, + SendToEvmChainEventName, + false, + abi.Arguments{abi.Argument{ + Name: "sender", + Type: addressType, + Indexed: true, + }, abi.Argument{ + Name: "recipient", + Type: addressType, + Indexed: true, + }, abi.Argument{ + Name: "chain_id", + Type: uint256Type, + Indexed: true, + }, abi.Argument{ + Name: "amount", + Type: uint256Type, + Indexed: false, + }, abi.Argument{ + Name: "bridge_fee", + Type: uint256Type, + Indexed: false, + }, abi.Argument{ + Name: "extraData", + Type: bytesType, + Indexed: false, + }}, + ) + SendToEvmChainResponseEvent = abi.NewEvent( + SendToEvmChainResponseEventName, + SendToEvmChainResponseEventName, + false, + abi.Arguments{abi.Argument{ + Name: "id", + Type: uint256Type, + Indexed: false, + }}, + ) +} + +// SendToEvmChainHandler handles `__CronosSendToEvmChain` log +type SendToEvmChainHandler struct { + gravitySrv gravitytypes.MsgServer + bankKeeper types.BankKeeper + cronosKeeper cronoskeeper.Keeper +} + +func NewSendToEvmChainHandler(gravitySrv gravitytypes.MsgServer, bankKeeper types.BankKeeper, cronosKeeper cronoskeeper.Keeper) *SendToEvmChainHandler { + return &SendToEvmChainHandler{ + gravitySrv: gravitySrv, + bankKeeper: bankKeeper, + cronosKeeper: cronosKeeper, + } +} + +func (h SendToEvmChainHandler) EventID() common.Hash { + return SendToChainEvent.ID +} + +// Handle `__CronosSendToChain` log only if gravity is activated. +func (h SendToEvmChainHandler) Handle( + ctx sdk.Context, + contract common.Address, + data []byte, + addLogToReceipt func(contractAddress common.Address, logSig common.Hash, logData []byte), +) error { + if h.gravitySrv == nil { + return fmt.Errorf("native action %s is not implemented", SendToChainEventName) + } + + unpacked, err := SendToEvmChainEvent.Inputs.Unpack(data) + if err != nil { + // log and ignore + h.cronosKeeper.Logger(ctx).Info("log signature matches but failed to decode") + return nil + } + + denom, found := h.cronosKeeper.GetDenomByContract(ctx, contract) + if !found { + return fmt.Errorf("contract %s is not connected to native token", contract) + } + + if !types.IsValidGravityDenom(denom) && !types.IsValidCronosDenom(denom) { + return fmt.Errorf("the native token associated with the contract %s is neither a gravity voucher or a cronos token", contract) + } + + contractCosmosAddr := sdk.AccAddress(contract.Bytes()) + senderCosmosAddr := sdk.AccAddress(unpacked[0].(common.Address).Bytes()) + ethRecipient := unpacked[1].(common.Address) + amount := sdk.NewIntFromBigInt(unpacked[2].(*big.Int)) + bridgeFee := sdk.NewIntFromBigInt(unpacked[3].(*big.Int)) + chainID := sdk.NewIntFromBigInt(unpacked[4].(*big.Int)) + + if !chainID.Equal(sdk.NewInt(1)) && !chainID.Equal(sdk.NewInt(3)) && + !chainID.Equal(sdk.NewInt(4)) && !chainID.Equal(sdk.NewInt(5)) { + return fmt.Errorf("only ethereum network is not supported") + } + + coins := sdk.NewCoins(sdk.NewCoin(denom, amount.Add(bridgeFee))) + if types.IsSourceCoin(denom) { + // it is a source token, we need to mint coins + if err = h.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { + return err + } + // send the coin to the user + if err = h.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, senderCosmosAddr.Bytes(), coins); err != nil { + return err + } + } else { + // send coins from contract address to user address so that he will be able to cancel later on + if err = h.bankKeeper.SendCoins(ctx, contractCosmosAddr, senderCosmosAddr.Bytes(), coins); err != nil { + return err + } + } + // Initialize a gravity transfer + msg := gravitytypes.MsgSendToEthereum{ + Sender: senderCosmosAddr.String(), + EthereumRecipient: ethRecipient.Hex(), + Amount: sdk.NewCoin(denom, amount), + BridgeFee: sdk.NewCoin(denom, bridgeFee), + } + resp, err := h.gravitySrv.SendToEthereum(sdk.WrapSDKContext(ctx), &msg) + if err != nil { + return err + } + + logData, _ := SendToEvmChainResponseEvent.Inputs.Pack(big.NewInt(int64(resp.Id))) + addLogToReceipt(contract, SendToEvmChainResponseEvent.ID, logData) + return nil +} diff --git a/x/cronos/keeper/evmhandlers/send_to_ibc.go b/x/cronos/keeper/evmhandlers/send_to_ibc.go index e156eddd32..60a6c5a756 100644 --- a/x/cronos/keeper/evmhandlers/send_to_ibc.go +++ b/x/cronos/keeper/evmhandlers/send_to_ibc.go @@ -17,13 +17,18 @@ var _ types.EvmLogHandler = SendToIbcHandler{} const SendToIbcEventName = "__CronosSendToIbc" // SendToIbcEvent represent the signature of -// `event __CronosSendToIbc(string recipient, uint256 amount)` +// `event __CronosSendToIbc(address sender, string recipient, uint256 amount)` var SendToIbcEvent abi.Event +// SendToIbcEventV2 represent the signature of +// `event __CronosSendToIbc(address indexed sender, string indexed recipient, string indexed channel_id, uint256 amount, bytes extraData)` +var SendToIbcEventV2 abi.Event + func init() { addressType, _ := abi.NewType("address", "", nil) uint256Type, _ := abi.NewType("uint256", "", nil) stringType, _ := abi.NewType("string", "", nil) + bytesType, _ := abi.NewType("bytes", "", nil) SendToIbcEvent = abi.NewEvent( SendToIbcEventName, @@ -43,6 +48,33 @@ func init() { Indexed: false, }}, ) + + SendToIbcEventV2 = abi.NewEvent( + SendToIbcEventName, + SendToIbcEventName, + false, + abi.Arguments{abi.Argument{ + Name: "sender", + Type: addressType, + Indexed: true, + }, abi.Argument{ + Name: "recipient", + Type: stringType, + Indexed: true, + }, abi.Argument{ + Name: "amount", + Type: uint256Type, + Indexed: false, + }, abi.Argument{ + Name: "channel_id", + Type: stringType, + Indexed: true, + }, abi.Argument{ + Name: "extraData", + Type: bytesType, + Indexed: false, + }}, + ) } // SendToIbcHandler handles `__CronosSendToIbc` log @@ -68,11 +100,16 @@ func (h SendToIbcHandler) Handle( data []byte, _ func(contractAddress common.Address, logSig common.Hash, logData []byte), ) error { + var unpacked []interface{} unpacked, err := SendToIbcEvent.Inputs.Unpack(data) if err != nil { - // log and ignore - h.cronosKeeper.Logger(ctx).Info("log signature matches but failed to decode") - return nil + // try v2 + unpacked, err = SendToIbcEventV2.Inputs.Unpack(data) + if err != nil { + // log and ignore + h.cronosKeeper.Logger(ctx).Info("log signature matches but failed to decode") + return nil + } } denom, found := h.cronosKeeper.GetDenomByContract(ctx, contract) diff --git a/x/cronos/types/contracts/ModuleCRC21.json b/x/cronos/types/contracts/ModuleCRC21.json index 72ef77d14d..8a5d4dc38c 100644 --- a/x/cronos/types/contracts/ModuleCRC21.json +++ b/x/cronos/types/contracts/ModuleCRC21.json @@ -151,7 +151,7 @@ "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "address", "name": "sender", "type": "address" @@ -163,24 +163,30 @@ "type": "uint256" } ], - "name": "__CronosCancelSendToChain", + "name": "__CronosCancelSendToEvmChain", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "address", "name": "sender", "type": "address" }, { - "indexed": false, + "indexed": true, "internalType": "address", "name": "recipient", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "chain_id", + "type": "uint256" + }, { "indexed": false, "internalType": "uint256", @@ -195,25 +201,25 @@ }, { "indexed": false, - "internalType": "uint256", - "name": "chain_id", - "type": "uint256" + "internalType": "bytes", + "name": "extraData", + "type": "bytes" } ], - "name": "__CronosSendToChain", + "name": "__CronosSendToEvmChain", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "address", "name": "sender", "type": "address" }, { - "indexed": false, + "indexed": true, "internalType": "string", "name": "recipient", "type": "string" @@ -223,6 +229,18 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": true, + "internalType": "string", + "name": "channel_id", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "extraData", + "type": "bytes" } ], "name": "__CronosSendToIbc", @@ -384,7 +402,7 @@ "type": "uint256" } ], - "name": "cancel_send_to_chain", + "name": "cancel_send_to_evm_chain", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -576,16 +594,21 @@ }, { "internalType": "uint256", - "name": "bridge_fee", + "name": "chain_id", "type": "uint256" }, { "internalType": "uint256", - "name": "chain_id", + "name": "bridge_fee", "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraData", + "type": "bytes" } ], - "name": "send_to_chain", + "name": "send_to_evm_chain", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -601,6 +624,16 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "internalType": "string", + "name": "channel_id", + "type": "string" + }, + { + "internalType": "bytes", + "name": "extraData", + "type": "bytes" } ], "name": "send_to_ibc", @@ -790,5 +823,5 @@ "type": "function" } ], - "bin": "60806040526012600660006101000a81548160ff021916908360ff16021790555060405180602001604052806000815250600790805190602001906200004792919062000249565b503480156200005557600080fd5b506040516200332738038062003327833981810160405260608110156200007b57600080fd5b81019080805160405193929190846401000000008211156200009c57600080fd5b83820191506020820185811115620000b357600080fd5b8251866001820283011164010000000082111715620000d157600080fd5b8083526020830192505050908051906020019080838360005b8381101562000107578082015181840152602081019050620000ea565b50505050905090810190601f168015620001355780820380516001836020036101000a031916815260200191505b5060405260200180519060200190929190805190602001909291905050508233600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9460405160405180910390a28060059080519060200190620001f092919062000249565b505081600660006101000a81548160ff021916908360ff16021790555082600890805190602001906200022592919062000249565b5080600960006101000a81548160ff021916908315150217905550505050620002f8565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200028c57805160ff1916838001178555620002bd565b82800160010185558215620002bd579182015b82811115620002bc5782518255916020019190600101906200029f565b5b509050620002cc9190620002d0565b5090565b620002f591905b80821115620002f1576000816000905550600101620002d7565b5090565b90565b61301f80620003086000396000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c806395d89b411161011a578063be9a6555116100ad578063dd62ed3e1161007c578063dd62ed3e14610b4d578063e978206414610bc5578063eb0d7c4714610c13578063ee36665414610c41578063f2d5d56b14610cc457610206565b8063be9a6555146109e2578063bf7e214f146109ec578063c47f002714610a36578063daea85c514610af157610206565b8063a515cb40116100e9578063a515cb40146107fb578063a9059cbb146108c0578063b753a98c14610926578063bb35783b1461097457610206565b806395d89b41146106da5780639dc29fac1461075d578063a0712d68146107ab578063a30780a7146107d957610206565b806340c10f191161019d57806375620d6f1161016c57806375620d6f1461057a57806375f12b21146105c85780637a9e5e4b146105ea5780637c31396e1461062e5780638da5cb5b1461069057610206565b806340c10f191461045857806342966c68146104a6578063480551bf146104d457806370a082311461052257610206565b806318160ddd116101d957806318160ddd1461034257806323b872dd1461036057806328b7d342146103e6578063313ce5671461043457610206565b806306fdde031461020b57806307da68f51461028e578063095ea7b31461029857806313af4035146102fe575b600080fd5b610213610d12565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610253578082015181840152602081019050610238565b50505050905090810190601f1680156102805780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610296610db0565b005b6102e4600480360360408110156102ae57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e98565b604051808215151515815260200191505060405180910390f35b6103406004803603602081101561031457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061100d565b005b61034a611156565b6040518082815260200191505060405180910390f35b6103cc6004803603606081101561037657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061115c565b604051808215151515815260200191505060405180910390f35b610432600480360360408110156103fc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506116f4565b005b61043c611763565b604051808260ff1660ff16815260200191505060405180910390f35b6104a46004803603604081101561046e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611776565b005b6104d2600480360360208110156104bc57600080fd5b8101908080359060200190929190505050611989565b005b610520600480360360408110156104ea57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611996565b005b6105646004803603602081101561053857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506119ba565b6040518082815260200191505060405180910390f35b6105c66004803603604081101561059057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506119d2565b005b6105d0611a2c565b604051808215151515815260200191505060405180910390f35b61062c6004803603602081101561060057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611a3f565b005b61068e6004803603608081101561064457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050611b86565b005b610698611c92565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6106e2611cb8565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610722578082015181840152602081019050610707565b50505050905090810190601f16801561074f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6107a96004803603604081101561077357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611d56565b005b6107d7600480360360208110156107c157600080fd5b81019080803590602001909291905050506122f4565b005b6107e1612301565b604051808215151515815260200191505060405180910390f35b6108be6004803603604081101561081157600080fd5b810190808035906020019064010000000081111561082e57600080fd5b82018360208201111561084057600080fd5b8035906020019184600183028401116401000000008311171561086257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190929190505050612318565b005b61090c600480360360408110156108d657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612439565b604051808215151515815260200191505060405180910390f35b6109726004803603604081101561093c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061244e565b005b6109e06004803603606081101561098a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061245e565b005b6109ea61246f565b005b6109f4612558565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610aef60048036036020811015610a4c57600080fd5b8101908080359060200190640100000000811115610a6957600080fd5b820183602082011115610a7b57600080fd5b80359060200191846001830284011164010000000083111715610a9d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061257d565b005b610b3360048036036020811015610b0757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612637565b604051808215151515815260200191505060405180910390f35b610baf60048036036040811015610b6357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061266a565b6040518082815260200191505060405180910390f35b610c1160048036036040811015610bdb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061268f565b005b610c3f60048036036020811015610c2957600080fd5b81019080803590602001909291905050506126e9565b005b610c49612757565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610c89578082015181840152602081019050610c6e565b50505050905090810190601f168015610cb65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610d1060048036036040811015610cda57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506127f9565b005b60078054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610da85780601f10610d7d57610100808354040283529160200191610da8565b820191906000526020600020905b815481529060010190602001808311610d8b57829003601f168201915b505050505081565b610dde336000357fffffffff0000000000000000000000000000000000000000000000000000000016612809565b610e50576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b60018060146101000a81548160ff0219169083151502179055507fbedf0f4abfe86d4ffad593d9607fe70e83ea706033d44d24b3b6283cf3fc4f6b60405160405180910390a1565b6000600160149054906101000a900460ff1615610f1d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f64732d73746f702d69732d73746f70706564000000000000000000000000000081525060200191505060405180910390fd5b81600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b61103b336000357fffffffff0000000000000000000000000000000000000000000000000000000016612809565b6110ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9460405160405180910390a250565b60025481565b6000600160149054906101000a900460ff16156111e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f64732d73746f702d69732d73746f70706564000000000000000000000000000081525060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141580156112b957507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b156114b75781600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156113b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f64732d746f6b656e2d696e73756666696369656e742d617070726f76616c000081525060200191505060405180910390fd5b611436600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483612a62565b600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b81600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561156c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f64732d746f6b656e2d696e73756666696369656e742d62616c616e636500000081525060200191505060405180910390fd5b6115b5600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483612a62565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611641600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483612ae5565b600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b7389a7ef2f08b1c018d5cc88836249b84dd539290573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461174057600080fd5b61175f827389a7ef2f08b1c018d5cc88836249b84dd539290583612b68565b5050565b600660009054906101000a900460ff1681565b6117a4336000357fffffffff0000000000000000000000000000000000000000000000000000000016612809565b611816576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b600160149054906101000a900460ff1615611899576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f64732d73746f702d69732d73746f70706564000000000000000000000000000081525060200191505060405180910390fd5b6118e2600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612ae5565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061193160025482612ae5565b6002819055508173ffffffffffffffffffffffffffffffffffffffff167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885826040518082815260200191505060405180910390a25050565b6119933382611d56565b50565b6119b57389a7ef2f08b1c018d5cc88836249b84dd5392905838361115c565b505050565b60036020528060005260406000206000915090505481565b7389a7ef2f08b1c018d5cc88836249b84dd539290573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611a1e57600080fd5b611a288282612d9f565b5050565b600160149054906101000a900460ff1681565b611a6d336000357fffffffff0000000000000000000000000000000000000000000000000000000016612809565b611adf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada460405160405180910390a250565b600960009054906101000a900460ff1615611bc957611bc3337389a7ef2f08b1c018d5cc88836249b84dd5392905611bbe8686612ae5565b61115c565b50611bdd565b611bdc33611bd78585612ae5565b612d9f565b5b7f3b97abfbfe92dfeeaf1cf38ad0229ea2da0441f814ebdbe46e6644bbc54337743385858585604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018381526020018281526020019550505050505060405180910390a150505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015611d4e5780601f10611d2357610100808354040283529160200191611d4e565b820191906000526020600020905b815481529060010190602001808311611d3157829003601f168201915b505050505081565b611d84336000357fffffffff0000000000000000000000000000000000000000000000000000000016612809565b611df6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b600160149054906101000a900460ff1615611e79576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f64732d73746f702d69732d73746f70706564000000000000000000000000000081525060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611f5157507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b1561214f5780600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015612048576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f64732d746f6b656e2d696e73756666696369656e742d617070726f76616c000081525060200191505060405180910390fd5b6120ce600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612a62565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015612204576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f64732d746f6b656e2d696e73756666696369656e742d62616c616e636500000081525060200191505060405180910390fd5b61224d600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612a62565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061229c60025482612a62565b6002819055508173ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5826040518082815260200191505060405180910390a25050565b6122fe3382611776565b50565b6000600960009054906101000a900460ff16905090565b600960009054906101000a900460ff16156123525761234c337389a7ef2f08b1c018d5cc88836249b84dd53929058361115c565b5061235d565b61235c3382612d9f565b5b7f7835232045347ac086653cbd9c0e6303f23502bb796f671a56755142063df2b2338383604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156123f95780820151818401526020810190506123de565b50505050905090810190601f1680156124265780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a15050565b600061244633848461115c565b905092915050565b61245933838361115c565b505050565b61246983838361115c565b50505050565b61249d336000357fffffffff0000000000000000000000000000000000000000000000000000000016612809565b61250f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b6000600160146101000a81548160ff0219169083151502179055507f1b55ba3aa851a46be3b365aee5b5c140edd620d578922f3e8466d2cbd96f954b60405160405180910390a1565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6125ab336000357fffffffff0000000000000000000000000000000000000000000000000000000016612809565b61261d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b8060079080519060200190612633929190612f44565b5050565b6000612663827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610e98565b9050919050565b6004602052816000526040600020602052806000526040600020600091509150505481565b7389a7ef2f08b1c018d5cc88836249b84dd539290573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146126db57600080fd5b6126e58282611776565b5050565b7f45717461201e72093a31a7b93c80db3e7a4cfc8f09a45c2d075483743319cffe3382604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a150565b606060088054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156127ef5780601f106127c4576101008083540402835291602001916127ef565b820191906000526020600020905b8154815290600101906020018083116127d257829003601f168201915b5050505050905090565b61280482338361115c565b505050565b60003073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156128485760019050612a5c565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156128a75760019050612a5c565b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156129065760009050612a5c565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b70096138430856040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001935050505060206040518083038186803b158015612a1e57600080fd5b505afa158015612a32573d6000803e3d6000fd5b505050506040513d6020811015612a4857600080fd5b810190808051906020019092919050505090505b92915050565b6000828284039150811115612adf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f64732d6d6174682d7375622d756e646572666c6f77000000000000000000000081525060200191505060405180910390fd5b92915050565b6000828284019150811015612b62576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d6d6174682d6164642d6f766572666c6f7700000000000000000000000081525060200191505060405180910390fd5b92915050565b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015612c1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f64732d746f6b656e2d696e73756666696369656e742d62616c616e636500000081525060200191505060405180910390fd5b612c66600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612a62565b600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550612cf2600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612ae5565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015612e54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f64732d746f6b656e2d696e73756666696369656e742d62616c616e636500000081525060200191505060405180910390fd5b612e9d600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612a62565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550612eec60025482612a62565b6002819055508173ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5826040518082815260200191505060405180910390a25050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612f8557805160ff1916838001178555612fb3565b82800160010185558215612fb3579182015b82811115612fb2578251825591602001919060010190612f97565b5b509050612fc09190612fc4565b5090565b612fe691905b80821115612fe2576000816000905550600101612fca565b5090565b9056fea2646970667358221220b09ee42fa79c3ab2a0f2816717f8e1e0b8568f6e318ba1d1490bcadf6610926f64736f6c63430006080033" + "bin": "60806040526012600660006101000a81548160ff021916908360ff16021790555060405180602001604052806000815250600790805190602001906200004792919062000249565b503480156200005557600080fd5b506040516200352938038062003529833981810160405260608110156200007b57600080fd5b81019080805160405193929190846401000000008211156200009c57600080fd5b83820191506020820185811115620000b357600080fd5b8251866001820283011164010000000082111715620000d157600080fd5b8083526020830192505050908051906020019080838360005b8381101562000107578082015181840152602081019050620000ea565b50505050905090810190601f168015620001355780820380516001836020036101000a031916815260200191505b5060405260200180519060200190929190805190602001909291905050508233600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9460405160405180910390a28060059080519060200190620001f092919062000249565b505081600660006101000a81548160ff021916908360ff16021790555082600890805190602001906200022592919062000249565b5080600960006101000a81548160ff021916908315150217905550505050620002f8565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200028c57805160ff1916838001178555620002bd565b82800160010185558215620002bd579182015b82811115620002bc5782518255916020019190600101906200029f565b5b509050620002cc9190620002d0565b5090565b620002f591905b80821115620002f1576000816000905550600101620002d7565b5090565b90565b61322180620003086000396000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c806395d89b411161011a578063bf7e214f116100ad578063e2d871a51161007c578063e2d871a514610acc578063e978206414610b83578063ee36665414610bd1578063f2d5d56b14610c54578063f473b57914610ca257610206565b8063bf7e214f146108f3578063c47f00271461093d578063daea85c5146109f8578063dd62ed3e14610a5457610206565b8063a9059cbb116100e9578063a9059cbb146107c7578063b753a98c1461082d578063bb35783b1461087b578063be9a6555146108e957610206565b806395d89b41146106a65780639dc29fac14610729578063a0712d6814610777578063a30780a7146107a557610206565b8063313ce5671161019d57806370a082311161016c57806370a082311461055057806375620d6f146105a857806375f12b21146105f65780637a9e5e4b146106185780638da5cb5b1461065c57610206565b8063313ce5671461046257806340c10f191461048657806342966c68146104d4578063480551bf1461050257610206565b806313af4035116101d957806313af40351461032c57806318160ddd1461037057806323b872dd1461038e57806328b7d3421461041457610206565b806306fdde031461020b57806307da68f51461028e578063095ea7b3146102985780630cacbca8146102fe575b600080fd5b610213610e95565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610253578082015181840152602081019050610238565b50505050905090810190601f1680156102805780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610296610f33565b005b6102e4600480360360408110156102ae57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061101b565b604051808215151515815260200191505060405180910390f35b61032a6004803603602081101561031457600080fd5b8101908080359060200190929190505050611190565b005b61036e6004803603602081101561034257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506111e1565b005b61037861132a565b6040518082815260200191505060405180910390f35b6103fa600480360360608110156103a457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611330565b604051808215151515815260200191505060405180910390f35b6104606004803603604081101561042a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506118c8565b005b61046a611937565b604051808260ff1660ff16815260200191505060405180910390f35b6104d26004803603604081101561049c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061194a565b005b610500600480360360208110156104ea57600080fd5b8101908080359060200190929190505050611b5d565b005b61054e6004803603604081101561051857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611b6a565b005b6105926004803603602081101561056657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611b8e565b6040518082815260200191505060405180910390f35b6105f4600480360360408110156105be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611ba6565b005b6105fe611c00565b604051808215151515815260200191505060405180910390f35b61065a6004803603602081101561062e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611c13565b005b610664611d5a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6106ae611d80565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156106ee5780820151818401526020810190506106d3565b50505050905090810190601f16801561071b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6107756004803603604081101561073f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611e1e565b005b6107a36004803603602081101561078d57600080fd5b81019080803590602001909291905050506123bc565b005b6107ad6123c9565b604051808215151515815260200191505060405180910390f35b610813600480360360408110156107dd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506123e0565b604051808215151515815260200191505060405180910390f35b6108796004803603604081101561084357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506123f5565b005b6108e76004803603606081101561089157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612405565b005b6108f1612416565b005b6108fb6124ff565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6109f66004803603602081101561095357600080fd5b810190808035906020019064010000000081111561097057600080fd5b82018360208201111561098257600080fd5b803590602001918460018302840111640100000000831117156109a457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612524565b005b610a3a60048036036020811015610a0e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506125de565b604051808215151515815260200191505060405180910390f35b610ab660048036036040811015610a6a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612611565b6040518082815260200191505060405180910390f35b610b81600480360360a0811015610ae257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610b3d57600080fd5b820183602082011115610b4f57600080fd5b80359060200191846001830284011164010000000083111715610b7157600080fd5b9091929391929390505050612636565b005b610bcf60048036036040811015610b9957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612737565b005b610bd9612791565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610c19578082015181840152602081019050610bfe565b50505050905090810190601f168015610c465780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610ca060048036036040811015610c6a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612833565b005b610e9360048036036080811015610cb857600080fd5b8101908080359060200190640100000000811115610cd557600080fd5b820183602082011115610ce757600080fd5b80359060200191846001830284011164010000000083111715610d0957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019092919080359060200190640100000000811115610d7657600080fd5b820183602082011115610d8857600080fd5b80359060200191846001830284011164010000000083111715610daa57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610e0d57600080fd5b820183602082011115610e1f57600080fd5b80359060200191846001830284011164010000000083111715610e4157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612843565b005b60078054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610f2b5780601f10610f0057610100808354040283529160200191610f2b565b820191906000526020600020905b815481529060010190602001808311610f0e57829003601f168201915b505050505081565b610f61336000357fffffffff0000000000000000000000000000000000000000000000000000000016612a0b565b610fd3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b60018060146101000a81548160ff0219169083151502179055507fbedf0f4abfe86d4ffad593d9607fe70e83ea706033d44d24b3b6283cf3fc4f6b60405160405180910390a1565b6000600160149054906101000a900460ff16156110a0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f64732d73746f702d69732d73746f70706564000000000000000000000000000081525060200191505060405180910390fd5b81600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b3373ffffffffffffffffffffffffffffffffffffffff167ff4fe77725fcbdec3d1f9eca9f080493ca64022cbfecc51cde2b2edb3cee82686826040518082815260200191505060405180910390a250565b61120f336000357fffffffff0000000000000000000000000000000000000000000000000000000016612a0b565b611281576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9460405160405180910390a250565b60025481565b6000600160149054906101000a900460ff16156113b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f64732d73746f702d69732d73746f70706564000000000000000000000000000081525060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415801561148d57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b1561168b5781600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015611584576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f64732d746f6b656e2d696e73756666696369656e742d617070726f76616c000081525060200191505060405180910390fd5b61160a600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483612c64565b600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b81600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015611740576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f64732d746f6b656e2d696e73756666696369656e742d62616c616e636500000081525060200191505060405180910390fd5b611789600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483612c64565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611815600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483612ce7565b600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b7389a7ef2f08b1c018d5cc88836249b84dd539290573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461191457600080fd5b611933827389a7ef2f08b1c018d5cc88836249b84dd539290583612d6a565b5050565b600660009054906101000a900460ff1681565b611978336000357fffffffff0000000000000000000000000000000000000000000000000000000016612a0b565b6119ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b600160149054906101000a900460ff1615611a6d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f64732d73746f702d69732d73746f70706564000000000000000000000000000081525060200191505060405180910390fd5b611ab6600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612ce7565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611b0560025482612ce7565b6002819055508173ffffffffffffffffffffffffffffffffffffffff167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885826040518082815260200191505060405180910390a25050565b611b673382611e1e565b50565b611b897389a7ef2f08b1c018d5cc88836249b84dd53929058383611330565b505050565b60036020528060005260406000206000915090505481565b7389a7ef2f08b1c018d5cc88836249b84dd539290573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611bf257600080fd5b611bfc8282612fa1565b5050565b600160149054906101000a900460ff1681565b611c41336000357fffffffff0000000000000000000000000000000000000000000000000000000016612a0b565b611cb3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada460405160405180910390a250565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015611e165780601f10611deb57610100808354040283529160200191611e16565b820191906000526020600020905b815481529060010190602001808311611df957829003601f168201915b505050505081565b611e4c336000357fffffffff0000000000000000000000000000000000000000000000000000000016612a0b565b611ebe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b600160149054906101000a900460ff1615611f41576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f64732d73746f702d69732d73746f70706564000000000000000000000000000081525060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561201957507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b156122175780600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015612110576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f64732d746f6b656e2d696e73756666696369656e742d617070726f76616c000081525060200191505060405180910390fd5b612196600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612c64565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156122cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f64732d746f6b656e2d696e73756666696369656e742d62616c616e636500000081525060200191505060405180910390fd5b612315600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612c64565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061236460025482612c64565b6002819055508173ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5826040518082815260200191505060405180910390a25050565b6123c6338261194a565b50565b6000600960009054906101000a900460ff16905090565b60006123ed338484611330565b905092915050565b612400338383611330565b505050565b612410838383611330565b50505050565b612444336000357fffffffff0000000000000000000000000000000000000000000000000000000016612a0b565b6124b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b6000600160146101000a81548160ff0219169083151502179055507f1b55ba3aa851a46be3b365aee5b5c140edd620d578922f3e8466d2cbd96f954b60405160405180910390a1565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b612552336000357fffffffff0000000000000000000000000000000000000000000000000000000016612a0b565b6125c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d617574682d756e617574686f72697a656400000000000000000000000081525060200191505060405180910390fd5b80600790805190602001906125da929190613146565b5050565b600061260a827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61101b565b9050919050565b6004602052816000526040600020602052806000526040600020600091509150505481565b600960009054906101000a900460ff161561267957612673337389a7ef2f08b1c018d5cc88836249b84dd539290561266e8887612ce7565b611330565b5061268d565b61268c336126878786612ce7565b612fa1565b5b838673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f1368737b9ca85302ba31831891159b06474bf82f7b208806cdcec8662c7055518887878760405180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509550505050505060405180910390a4505050505050565b7389a7ef2f08b1c018d5cc88836249b84dd539290573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461278357600080fd5b61278d828261194a565b5050565b606060088054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156128295780601f106127fe57610100808354040283529160200191612829565b820191906000526020600020905b81548152906001019060200180831161280c57829003601f168201915b5050505050905090565b61283e823383611330565b505050565b600960009054906101000a900460ff161561287d57612877337389a7ef2f08b1c018d5cc88836249b84dd539290585611330565b50612888565b6128873384612fa1565b5b816040518082805190602001908083835b602083106128bc5780518252602082019150602081019050602083039250612899565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020846040518082805190602001908083835b6020831061291d57805182526020820191506020810190506020830392506128fa565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390203373ffffffffffffffffffffffffffffffffffffffff167f603d21eede70b2efa21363351479b8b72d0fa0e32d899de2a41c2c51776a29f286856040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156129ca5780820151818401526020810190506129af565b50505050905090810190601f1680156129f75780820380516001836020036101000a031916815260200191505b50935050505060405180910390a450505050565b60003073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612a4a5760019050612c5e565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612aa95760019050612c5e565b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415612b085760009050612c5e565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b70096138430856040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001935050505060206040518083038186803b158015612c2057600080fd5b505afa158015612c34573d6000803e3d6000fd5b505050506040513d6020811015612c4a57600080fd5b810190808051906020019092919050505090505b92915050565b6000828284039150811115612ce1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f64732d6d6174682d7375622d756e646572666c6f77000000000000000000000081525060200191505060405180910390fd5b92915050565b6000828284019150811015612d64576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f64732d6d6174682d6164642d6f766572666c6f7700000000000000000000000081525060200191505060405180910390fd5b92915050565b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015612e1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f64732d746f6b656e2d696e73756666696369656e742d62616c616e636500000081525060200191505060405180910390fd5b612e68600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612c64565b600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550612ef4600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612ce7565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b80600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015613056576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f64732d746f6b656e2d696e73756666696369656e742d62616c616e636500000081525060200191505060405180910390fd5b61309f600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482612c64565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506130ee60025482612c64565b6002819055508173ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5826040518082815260200191505060405180910390a25050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061318757805160ff19168380011785556131b5565b828001600101855582156131b5579182015b828111156131b4578251825591602001919060010190613199565b5b5090506131c291906131c6565b5090565b6131e891905b808211156131e45760008160009055506001016131cc565b5090565b9056fea2646970667358221220dd1298ee1b6631f28b6f3890d3e46fd01f3aaf5636bd1c99130022610da37c0f64736f6c63430006080033" }