Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- GnosisSafe
- Optimization enabled
- false
- Compiler version
- v0.5.17+commit.d19bba13
- EVM Version
- default
- Verified at
- 2024-07-10T16:14:42.785134Z
.sol
pragma solidity >=0.5.0 <0.7.0;
/// @title SelfAuthorized - authorizes current contract to perform actions
/// @author Richard Meissner - <[email protected]>
contract SelfAuthorized {
modifier authorized() {
require(msg.sender == address(this), "Method can only be called from this contract");
_;
}
}
/// @title Enum - Collection of enums
/// @author Richard Meissner - <[email protected]>
contract Enum {
enum Operation {
Call,
DelegateCall
}
}
contract ISignatureValidatorConstants {
// bytes4(keccak256("isValidSignature(bytes,bytes)")
bytes4 constant internal EIP1271_MAGIC_VALUE = 0x20c13b0b;
}
contract ISignatureValidator is ISignatureValidatorConstants {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param _data Arbitrary length data signed on the behalf of address(this)
* @param _signature Signature byte array associated with _data
*
* MUST return the bytes4 magic value 0x20c13b0b when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(
bytes memory _data,
bytes memory _signature)
public
view
returns (bytes4);
}
/**
* @title GnosisSafeMath
* @dev Math operations with safety checks that revert on error
* Renamed from SafeMath to GnosisSafeMath to avoid conflicts
* TODO: remove once open zeppelin update to solc 0.5.0
*/
library GnosisSafeMath {
/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0); // Solidity only automatically asserts when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
/**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
}
/// @title SignatureDecoder - Decodes signatures that a encoded as bytes
/// @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
/// @author Richard Meissner - <[email protected]>
contract SignatureDecoder {
/// @dev Recovers address who signed the message
/// @param messageHash operation ethereum signed message hash
/// @param messageSignature message `txHash` signature
/// @param pos which signature to read
function recoverKey (
bytes32 messageHash,
bytes memory messageSignature,
uint256 pos
)
internal
pure
returns (address)
{
uint8 v;
bytes32 r;
bytes32 s;
(v, r, s) = signatureSplit(messageSignature, pos);
return ecrecover(messageHash, v, r, s);
}
/// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.
/// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures
/// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access
/// @param signatures concatenated rsv signatures
function signatureSplit(bytes memory signatures, uint256 pos)
internal
pure
returns (uint8 v, bytes32 r, bytes32 s)
{
// The signature format is a compact form of:
// {bytes32 r}{bytes32 s}{uint8 v}
// Compact means, uint8 is not padded to 32 bytes.
// solium-disable-next-line security/no-inline-assembly
assembly {
let signaturePos := mul(0x41, pos)
r := mload(add(signatures, add(signaturePos, 0x20)))
s := mload(add(signatures, add(signaturePos, 0x40)))
// Here we are loading the last 32 bytes, including 31 bytes
// of 's'. There is no 'mload8' to do this.
//
// 'byte' is not working due to the Solidity parser, so lets
// use the second best option, 'and'
v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
}
}
}
/// @title SecuredTokenTransfer - Secure token transfer
/// @author Richard Meissner - <[email protected]>
contract SecuredTokenTransfer {
/// @dev Transfers a token and returns if it was a success
/// @param token Token that should be transferred
/// @param receiver Receiver to whom the token should be transferred
/// @param amount The amount of tokens that should be transferred
function transferToken (
address token,
address receiver,
uint256 amount
)
internal
returns (bool transferred)
{
bytes memory data = abi.encodeWithSignature("transfer(address,uint256)", receiver, amount);
// solium-disable-next-line security/no-inline-assembly
assembly {
let success := call(sub(gas, 10000), token, 0, add(data, 0x20), mload(data), 0, 0)
let ptr := mload(0x40)
mstore(0x40, add(ptr, returndatasize()))
returndatacopy(ptr, 0, returndatasize())
switch returndatasize()
case 0 { transferred := success }
case 0x20 { transferred := iszero(or(iszero(success), iszero(mload(ptr)))) }
default { transferred := 0 }
}
}
}
/// @title MasterCopy - Base for master copy contracts (should always be first super contract)
/// This contract is tightly coupled to our proxy contract (see `proxies/GnosisSafeProxy.sol`)
/// @author Richard Meissner - <[email protected]>
contract MasterCopy is SelfAuthorized {
event ChangedMasterCopy(address masterCopy);
// masterCopy always needs to be first declared variable, to ensure that it is at the same location as in the Proxy contract.
// It should also always be ensured that the address is stored alone (uses a full word)
address private masterCopy;
/// @dev Allows to upgrade the contract. This can only be done via a Safe transaction.
/// @param _masterCopy New contract address.
function changeMasterCopy(address _masterCopy)
public
authorized
{
// Master copy address cannot be null.
require(_masterCopy != address(0), "Invalid master copy address provided");
masterCopy = _masterCopy;
emit ChangedMasterCopy(_masterCopy);
}
}
/// @title OwnerManager - Manages a set of owners and a threshold to perform actions.
/// @author Stefan George - <[email protected]>
/// @author Richard Meissner - <[email protected]>
contract OwnerManager is SelfAuthorized {
event AddedOwner(address owner);
event RemovedOwner(address owner);
event ChangedThreshold(uint256 threshold);
address internal constant SENTINEL_OWNERS = address(0x1);
mapping(address => address) internal owners;
uint256 ownerCount;
uint256 internal threshold;
/// @dev Setup function sets initial storage of contract.
/// @param _owners List of Safe owners.
/// @param _threshold Number of required confirmations for a Safe transaction.
function setupOwners(address[] memory _owners, uint256 _threshold)
internal
{
// Threshold can only be 0 at initialization.
// Check ensures that setup function can only be called once.
require(threshold == 0, "Owners have already been setup");
// Validate that threshold is smaller than number of added owners.
require(_threshold <= _owners.length, "Threshold cannot exceed owner count");
// There has to be at least one Safe owner.
require(_threshold >= 1, "Threshold needs to be greater than 0");
// Initializing Safe owners.
address currentOwner = SENTINEL_OWNERS;
for (uint256 i = 0; i < _owners.length; i++) {
// Owner address cannot be null.
address owner = _owners[i];
require(owner != address(0) && owner != SENTINEL_OWNERS, "Invalid owner address provided");
// No duplicate owners allowed.
require(owners[owner] == address(0), "Duplicate owner address provided");
owners[currentOwner] = owner;
currentOwner = owner;
}
owners[currentOwner] = SENTINEL_OWNERS;
ownerCount = _owners.length;
threshold = _threshold;
}
/// @dev Allows to add a new owner to the Safe and update the threshold at the same time.
/// This can only be done via a Safe transaction.
/// @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
/// @param owner New owner address.
/// @param _threshold New threshold.
function addOwnerWithThreshold(address owner, uint256 _threshold)
public
authorized
{
// Owner address cannot be null.
require(owner != address(0) && owner != SENTINEL_OWNERS, "Invalid owner address provided");
// No duplicate owners allowed.
require(owners[owner] == address(0), "Address is already an owner");
owners[owner] = owners[SENTINEL_OWNERS];
owners[SENTINEL_OWNERS] = owner;
ownerCount++;
emit AddedOwner(owner);
// Change threshold if threshold was changed.
if (threshold != _threshold)
changeThreshold(_threshold);
}
/// @dev Allows to remove an owner from the Safe and update the threshold at the same time.
/// This can only be done via a Safe transaction.
/// @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
/// @param prevOwner Owner that pointed to the owner to be removed in the linked list
/// @param owner Owner address to be removed.
/// @param _threshold New threshold.
function removeOwner(address prevOwner, address owner, uint256 _threshold)
public
authorized
{
// Only allow to remove an owner, if threshold can still be reached.
require(ownerCount - 1 >= _threshold, "New owner count needs to be larger than new threshold");
// Validate owner address and check that it corresponds to owner index.
require(owner != address(0) && owner != SENTINEL_OWNERS, "Invalid owner address provided");
require(owners[prevOwner] == owner, "Invalid prevOwner, owner pair provided");
owners[prevOwner] = owners[owner];
owners[owner] = address(0);
ownerCount--;
emit RemovedOwner(owner);
// Change threshold if threshold was changed.
if (threshold != _threshold)
changeThreshold(_threshold);
}
/// @dev Allows to swap/replace an owner from the Safe with another address.
/// This can only be done via a Safe transaction.
/// @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
/// @param prevOwner Owner that pointed to the owner to be replaced in the linked list
/// @param oldOwner Owner address to be replaced.
/// @param newOwner New owner address.
function swapOwner(address prevOwner, address oldOwner, address newOwner)
public
authorized
{
// Owner address cannot be null.
require(newOwner != address(0) && newOwner != SENTINEL_OWNERS, "Invalid owner address provided");
// No duplicate owners allowed.
require(owners[newOwner] == address(0), "Address is already an owner");
// Validate oldOwner address and check that it corresponds to owner index.
require(oldOwner != address(0) && oldOwner != SENTINEL_OWNERS, "Invalid owner address provided");
require(owners[prevOwner] == oldOwner, "Invalid prevOwner, owner pair provided");
owners[newOwner] = owners[oldOwner];
owners[prevOwner] = newOwner;
owners[oldOwner] = address(0);
emit RemovedOwner(oldOwner);
emit AddedOwner(newOwner);
}
/// @dev Allows to update the number of required confirmations by Safe owners.
/// This can only be done via a Safe transaction.
/// @notice Changes the threshold of the Safe to `_threshold`.
/// @param _threshold New threshold.
function changeThreshold(uint256 _threshold)
public
authorized
{
// Validate that threshold is smaller than number of owners.
require(_threshold <= ownerCount, "Threshold cannot exceed owner count");
// There has to be at least one Safe owner.
require(_threshold >= 1, "Threshold needs to be greater than 0");
threshold = _threshold;
emit ChangedThreshold(threshold);
}
function getThreshold()
public
view
returns (uint256)
{
return threshold;
}
function isOwner(address owner)
public
view
returns (bool)
{
return owner != SENTINEL_OWNERS && owners[owner] != address(0);
}
/// @dev Returns array of owners.
/// @return Array of Safe owners.
function getOwners()
public
view
returns (address[] memory)
{
address[] memory array = new address[](ownerCount);
// populate return array
uint256 index = 0;
address currentOwner = owners[SENTINEL_OWNERS];
while(currentOwner != SENTINEL_OWNERS) {
array[index] = currentOwner;
currentOwner = owners[currentOwner];
index ++;
}
return array;
}
}
/// @title Executor - A contract that can execute transactions
/// @author Richard Meissner - <[email protected]>
contract Executor {
function execute(address to, uint256 value, bytes memory data, Enum.Operation operation, uint256 txGas)
internal
returns (bool success)
{
if (operation == Enum.Operation.Call)
success = executeCall(to, value, data, txGas);
else if (operation == Enum.Operation.DelegateCall)
success = executeDelegateCall(to, data, txGas);
else
success = false;
}
function executeCall(address to, uint256 value, bytes memory data, uint256 txGas)
internal
returns (bool success)
{
// solium-disable-next-line security/no-inline-assembly
assembly {
success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)
}
}
function executeDelegateCall(address to, bytes memory data, uint256 txGas)
internal
returns (bool success)
{
// solium-disable-next-line security/no-inline-assembly
assembly {
success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)
}
}
}
/// @title Module Manager - A contract that manages modules that can execute transactions via this contract
/// @author Stefan George - <[email protected]>
/// @author Richard Meissner - <[email protected]>
contract ModuleManager is SelfAuthorized, Executor {
event EnabledModule(Module module);
event DisabledModule(Module module);
event ExecutionFromModuleSuccess(address indexed module);
event ExecutionFromModuleFailure(address indexed module);
address internal constant SENTINEL_MODULES = address(0x1);
mapping (address => address) internal modules;
function setupModules(address to, bytes memory data)
internal
{
require(modules[SENTINEL_MODULES] == address(0), "Modules have already been initialized");
modules[SENTINEL_MODULES] = SENTINEL_MODULES;
if (to != address(0))
// Setup has to complete successfully or transaction fails.
require(executeDelegateCall(to, data, gasleft()), "Could not finish initialization");
}
/// @dev Allows to add a module to the whitelist.
/// This can only be done via a Safe transaction.
/// @notice Enables the module `module` for the Safe.
/// @param module Module to be whitelisted.
function enableModule(Module module)
public
authorized
{
// Module address cannot be null or sentinel.
require(address(module) != address(0) && address(module) != SENTINEL_MODULES, "Invalid module address provided");
// Module cannot be added twice.
require(modules[address(module)] == address(0), "Module has already been added");
modules[address(module)] = modules[SENTINEL_MODULES];
modules[SENTINEL_MODULES] = address(module);
emit EnabledModule(module);
}
/// @dev Allows to remove a module from the whitelist.
/// This can only be done via a Safe transaction.
/// @notice Disables the module `module` for the Safe.
/// @param prevModule Module that pointed to the module to be removed in the linked list
/// @param module Module to be removed.
function disableModule(Module prevModule, Module module)
public
authorized
{
// Validate module address and check that it corresponds to module index.
require(address(module) != address(0) && address(module) != SENTINEL_MODULES, "Invalid module address provided");
require(modules[address(prevModule)] == address(module), "Invalid prevModule, module pair provided");
modules[address(prevModule)] = modules[address(module)];
modules[address(module)] = address(0);
emit DisabledModule(module);
}
/// @dev Allows a Module to execute a Safe transaction without any further confirmations.
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction.
function execTransactionFromModule(address to, uint256 value, bytes memory data, Enum.Operation operation)
public
returns (bool success)
{
// Only whitelisted modules are allowed.
require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "Method can only be called from an enabled module");
// Execute transaction without further confirmations.
success = execute(to, value, data, operation, gasleft());
if (success) emit ExecutionFromModuleSuccess(msg.sender);
else emit ExecutionFromModuleFailure(msg.sender);
}
/// @dev Allows a Module to execute a Safe transaction without any further confirmations and return data
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction.
function execTransactionFromModuleReturnData(address to, uint256 value, bytes memory data, Enum.Operation operation)
public
returns (bool success, bytes memory returnData)
{
success = execTransactionFromModule(to, value, data, operation);
// solium-disable-next-line security/no-inline-assembly
assembly {
// Load free memory location
let ptr := mload(0x40)
// We allocate memory for the return data by setting the free memory location to
// current free memory location + data size + 32 bytes for data size value
mstore(0x40, add(ptr, add(returndatasize(), 0x20)))
// Store the size
mstore(ptr, returndatasize())
// Store the data
returndatacopy(add(ptr, 0x20), 0, returndatasize())
// Point the return data to the correct memory location
returnData := ptr
}
}
/// @dev Returns if an module is enabled
/// @return True if the module is enabled
function isModuleEnabled(Module module)
public
view
returns (bool)
{
return SENTINEL_MODULES != address(module) && modules[address(module)] != address(0);
}
/// @dev Returns array of first 10 modules.
/// @return Array of modules.
function getModules()
public
view
returns (address[] memory)
{
(address[] memory array,) = getModulesPaginated(SENTINEL_MODULES, 10);
return array;
}
/// @dev Returns array of modules.
/// @param start Start of the page.
/// @param pageSize Maximum number of modules that should be returned.
/// @return Array of modules.
function getModulesPaginated(address start, uint256 pageSize)
public
view
returns (address[] memory array, address next)
{
// Init array with max page size
array = new address[](pageSize);
// Populate return array
uint256 moduleCount = 0;
address currentModule = modules[start];
while(currentModule != address(0x0) && currentModule != SENTINEL_MODULES && moduleCount < pageSize) {
array[moduleCount] = currentModule;
currentModule = modules[currentModule];
moduleCount++;
}
next = currentModule;
// Set correct size of returned array
// solium-disable-next-line security/no-inline-assembly
assembly {
mstore(array, moduleCount)
}
}
}
/// @title Module - Base class for modules.
/// @author Stefan George - <[email protected]>
/// @author Richard Meissner - <[email protected]>
contract Module is MasterCopy {
ModuleManager public manager;
modifier authorized() {
require(msg.sender == address(manager), "Method can only be called from manager");
_;
}
function setManager()
internal
{
// manager can only be 0 at initalization of contract.
// Check ensures that setup function can only be called once.
require(address(manager) == address(0), "Manager has already been set");
manager = ModuleManager(msg.sender);
}
}
/// @title Fallback Manager - A contract that manages fallback calls made to this contract
/// @author Richard Meissner - <[email protected]>
contract FallbackManager is SelfAuthorized {
// keccak256("fallback_manager.handler.address")
bytes32 internal constant FALLBACK_HANDLER_STORAGE_SLOT = 0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5;
function internalSetFallbackHandler(address handler) internal {
bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
// solium-disable-next-line security/no-inline-assembly
assembly {
sstore(slot, handler)
}
}
/// @dev Allows to add a contract to handle fallback calls.
/// Only fallback calls without value and with data will be forwarded.
/// This can only be done via a Safe transaction.
/// @param handler contract to handle fallbacks calls.
function setFallbackHandler(address handler)
public
authorized
{
internalSetFallbackHandler(handler);
}
function ()
external
payable
{
// Only calls without value and with data will be forwarded
if (msg.value > 0 || msg.data.length == 0) {
return;
}
bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
address handler;
// solium-disable-next-line security/no-inline-assembly
assembly {
handler := sload(slot)
}
if (handler != address(0)) {
// solium-disable-next-line security/no-inline-assembly
assembly {
calldatacopy(0, 0, calldatasize())
let success := call(gas, handler, 0, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
if eq(success, 0) { revert(0, returndatasize()) }
return(0, returndatasize())
}
}
}
}
/// @title Gnosis Safe - A multisignature wallet with support for confirmations using signed messages based on ERC191.
/// @author Stefan George - <[email protected]>
/// @author Richard Meissner - <[email protected]>
/// @author Ricardo Guilherme Schmidt - (Status Research & Development GmbH) - Gas Token Payment
contract GnosisSafe
is MasterCopy, ModuleManager, OwnerManager, SignatureDecoder, SecuredTokenTransfer, ISignatureValidatorConstants, FallbackManager {
using GnosisSafeMath for uint256;
string public constant NAME = "Gnosis Safe";
string public constant VERSION = "1.2.0";
//keccak256(
// "EIP712Domain(address verifyingContract)"
//);
bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;
//keccak256(
// "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce)"
//);
bytes32 private constant SAFE_TX_TYPEHASH = 0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8;
//keccak256(
// "SafeMessage(bytes message)"
//);
bytes32 private constant SAFE_MSG_TYPEHASH = 0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca;
event ApproveHash(
bytes32 indexed approvedHash,
address indexed owner
);
event SignMsg(
bytes32 indexed msgHash
);
event ExecutionFailure(
bytes32 txHash, uint256 payment
);
event ExecutionSuccess(
bytes32 txHash, uint256 payment
);
uint256 public nonce;
bytes32 public domainSeparator;
// Mapping to keep track of all message hashes that have been approve by ALL REQUIRED owners
mapping(bytes32 => uint256) public signedMessages;
// Mapping to keep track of all hashes (message or transaction) that have been approve by ANY owners
mapping(address => mapping(bytes32 => uint256)) public approvedHashes;
// This constructor ensures that this contract can only be used as a master copy for Proxy contracts
constructor() public {
// By setting the threshold it is not possible to call setup anymore,
// so we create a Safe with 0 owners and threshold 1.
// This is an unusable Safe, perfect for the mastercopy
threshold = 1;
}
/// @dev Setup function sets initial storage of contract.
/// @param _owners List of Safe owners.
/// @param _threshold Number of required confirmations for a Safe transaction.
/// @param to Contract address for optional delegate call.
/// @param data Data payload for optional delegate call.
/// @param fallbackHandler Handler for fallback calls to this contract
/// @param paymentToken Token that should be used for the payment (0 is ETH)
/// @param payment Value that should be paid
/// @param paymentReceiver Adddress that should receive the payment (or 0 if tx.origin)
function setup(
address[] calldata _owners,
uint256 _threshold,
address to,
bytes calldata data,
address fallbackHandler,
address paymentToken,
uint256 payment,
address payable paymentReceiver
)
external
{
require(domainSeparator == 0, "Domain Separator already set!");
domainSeparator = keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, this));
setupOwners(_owners, _threshold);
if (fallbackHandler != address(0)) internalSetFallbackHandler(fallbackHandler);
// As setupOwners can only be called if the contract has not been initialized we don't need a check for setupModules
setupModules(to, data);
if (payment > 0) {
// To avoid running into issues with EIP-170 we reuse the handlePayment function (to avoid adjusting code of that has been verified we do not adjust the method itself)
// baseGas = 0, gasPrice = 1 and gas = payment => amount = (payment + 0) * 1 = payment
handlePayment(payment, 0, 1, paymentToken, paymentReceiver);
}
}
/// @dev Allows to execute a Safe transaction confirmed by required number of owners and then pays the account that submitted the transaction.
/// Note: The fees are always transfered, even if the user transaction fails.
/// @param to Destination address of Safe transaction.
/// @param value Ether value of Safe transaction.
/// @param data Data payload of Safe transaction.
/// @param operation Operation type of Safe transaction.
/// @param safeTxGas Gas that should be used for the Safe transaction.
/// @param baseGas Gas costs for that are indipendent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
/// @param gasPrice Gas price that should be used for the payment calculation.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @param signatures Packed signature data ({bytes32 r}{bytes32 s}{uint8 v})
function execTransaction(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver,
bytes calldata signatures
)
external
payable
returns (bool success)
{
bytes32 txHash;
// Use scope here to limit variable lifetime and prevent `stack too deep` errors
{
bytes memory txHashData = encodeTransactionData(
to, value, data, operation, // Transaction info
safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, // Payment info
nonce
);
// Increase nonce and execute transaction.
nonce++;
txHash = keccak256(txHashData);
checkSignatures(txHash, txHashData, signatures, true);
}
// We require some gas to emit the events (at least 2500) after the execution and some to perform code until the execution (500)
// We also include the 1/64 in the check that is not send along with a call to counteract potential shortings because of EIP-150
require(gasleft() >= (safeTxGas * 64 / 63).max(safeTxGas + 2500) + 500, "Not enough gas to execute safe transaction");
// Use scope here to limit variable lifetime and prevent `stack too deep` errors
{
uint256 gasUsed = gasleft();
// If the gasPrice is 0 we assume that nearly all available gas can be used (it is always more than safeTxGas)
// We only substract 2500 (compared to the 3000 before) to ensure that the amount passed is still higher than safeTxGas
success = execute(to, value, data, operation, gasPrice == 0 ? (gasleft() - 2500) : safeTxGas);
gasUsed = gasUsed.sub(gasleft());
// We transfer the calculated tx costs to the tx.origin to avoid sending it to intermediate contracts that have made calls
uint256 payment = 0;
if (gasPrice > 0) {
payment = handlePayment(gasUsed, baseGas, gasPrice, gasToken, refundReceiver);
}
if (success) emit ExecutionSuccess(txHash, payment);
else emit ExecutionFailure(txHash, payment);
}
}
function handlePayment(
uint256 gasUsed,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver
)
private
returns (uint256 payment)
{
// solium-disable-next-line security/no-tx-origin
address payable receiver = refundReceiver == address(0) ? tx.origin : refundReceiver;
if (gasToken == address(0)) {
// For ETH we will only adjust the gas price to not be higher than the actual used gas price
payment = gasUsed.add(baseGas).mul(gasPrice < tx.gasprice ? gasPrice : tx.gasprice);
// solium-disable-next-line security/no-send
require(receiver.send(payment), "Could not pay gas costs with ether");
} else {
payment = gasUsed.add(baseGas).mul(gasPrice);
require(transferToken(gasToken, receiver, payment), "Could not pay gas costs with token");
}
}
/**
* @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
* @param dataHash Hash of the data (could be either a message hash or transaction hash)
* @param data That should be signed (this is passed to an external validator contract)
* @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
* @param consumeHash Indicates that in case of an approved hash the storage can be freed to save gas
*/
function checkSignatures(bytes32 dataHash, bytes memory data, bytes memory signatures, bool consumeHash)
internal
{
// Load threshold to avoid multiple storage loads
uint256 _threshold = threshold;
// Check that a threshold is set
require(_threshold > 0, "Threshold needs to be defined!");
// Check that the provided signature data is not too short
require(signatures.length >= _threshold.mul(65), "Signatures data too short");
// There cannot be an owner with address 0.
address lastOwner = address(0);
address currentOwner;
uint8 v;
bytes32 r;
bytes32 s;
uint256 i;
for (i = 0; i < _threshold; i++) {
(v, r, s) = signatureSplit(signatures, i);
// If v is 0 then it is a contract signature
if (v == 0) {
// When handling contract signatures the address of the contract is encoded into r
currentOwner = address(uint256(r));
// Check that signature data pointer (s) is not pointing inside the static part of the signatures bytes
// This check is not completely accurate, since it is possible that more signatures than the threshold are send.
// Here we only check that the pointer is not pointing inside the part that is being processed
require(uint256(s) >= _threshold.mul(65), "Invalid contract signature location: inside static part");
// Check that signature data pointer (s) is in bounds (points to the length of data -> 32 bytes)
require(uint256(s).add(32) <= signatures.length, "Invalid contract signature location: length not present");
// Check if the contract signature is in bounds: start of data is s + 32 and end is start + signature length
uint256 contractSignatureLen;
// solium-disable-next-line security/no-inline-assembly
assembly {
contractSignatureLen := mload(add(add(signatures, s), 0x20))
}
require(uint256(s).add(32).add(contractSignatureLen) <= signatures.length, "Invalid contract signature location: data not complete");
// Check signature
bytes memory contractSignature;
// solium-disable-next-line security/no-inline-assembly
assembly {
// The signature data for contract signatures is appended to the concatenated signatures and the offset is stored in s
contractSignature := add(add(signatures, s), 0x20)
}
require(ISignatureValidator(currentOwner).isValidSignature(data, contractSignature) == EIP1271_MAGIC_VALUE, "Invalid contract signature provided");
// If v is 1 then it is an approved hash
} else if (v == 1) {
// When handling approved hashes the address of the approver is encoded into r
currentOwner = address(uint256(r));
// Hashes are automatically approved by the sender of the message or when they have been pre-approved via a separate transaction
require(msg.sender == currentOwner || approvedHashes[currentOwner][dataHash] != 0, "Hash has not been approved");
// Hash has been marked for consumption. If this hash was pre-approved free storage
if (consumeHash && msg.sender != currentOwner) {
approvedHashes[currentOwner][dataHash] = 0;
}
} else if (v > 30) {
// To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix before applying ecrecover
currentOwner = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)), v - 4, r, s);
} else {
// Use ecrecover with the messageHash for EOA signatures
currentOwner = ecrecover(dataHash, v, r, s);
}
require (
currentOwner > lastOwner && owners[currentOwner] != address(0) && currentOwner != SENTINEL_OWNERS,
"Invalid owner provided"
);
lastOwner = currentOwner;
}
}
/// @dev Allows to estimate a Safe transaction.
/// This method is only meant for estimation purpose, therefore two different protection mechanism against execution in a transaction have been made:
/// 1.) The method can only be called from the safe itself
/// 2.) The response is returned with a revert
/// When estimating set `from` to the address of the safe.
/// Since the `estimateGas` function includes refunds, call this method to get an estimated of the costs that are deducted from the safe with `execTransaction`
/// @param to Destination address of Safe transaction.
/// @param value Ether value of Safe transaction.
/// @param data Data payload of Safe transaction.
/// @param operation Operation type of Safe transaction.
/// @return Estimate without refunds and overhead fees (base transaction and payload data gas costs).
function requiredTxGas(address to, uint256 value, bytes calldata data, Enum.Operation operation)
external
authorized
returns (uint256)
{
uint256 startGas = gasleft();
// We don't provide an error message here, as we use it to return the estimate
// solium-disable-next-line error-reason
require(execute(to, value, data, operation, gasleft()));
uint256 requiredGas = startGas - gasleft();
// Convert response to string and return via error message
revert(string(abi.encodePacked(requiredGas)));
}
/**
* @dev Marks a hash as approved. This can be used to validate a hash that is used by a signature.
* @param hashToApprove The hash that should be marked as approved for signatures that are verified by this contract.
*/
function approveHash(bytes32 hashToApprove)
external
{
require(owners[msg.sender] != address(0), "Only owners can approve a hash");
approvedHashes[msg.sender][hashToApprove] = 1;
emit ApproveHash(hashToApprove, msg.sender);
}
/**
* @dev Marks a message as signed, so that it can be used with EIP-1271
* @notice Marks a message (`_data`) as signed.
* @param _data Arbitrary length data that should be marked as signed on the behalf of address(this)
*/
function signMessage(bytes calldata _data)
external
authorized
{
bytes32 msgHash = getMessageHash(_data);
signedMessages[msgHash] = 1;
emit SignMsg(msgHash);
}
/**
* Implementation of ISignatureValidator (see `interfaces/ISignatureValidator.sol`)
* @dev Should return whether the signature provided is valid for the provided data.
* The save does not implement the interface since `checkSignatures` is not a view method.
* The method will not perform any state changes (see parameters of `checkSignatures`)
* @param _data Arbitrary length data signed on the behalf of address(this)
* @param _signature Signature byte array associated with _data
* @return a bool upon valid or invalid signature with corresponding _data
*/
function isValidSignature(bytes calldata _data, bytes calldata _signature)
external
returns (bytes4)
{
bytes32 messageHash = getMessageHash(_data);
if (_signature.length == 0) {
require(signedMessages[messageHash] != 0, "Hash not approved");
} else {
// consumeHash needs to be false, as the state should not be changed
checkSignatures(messageHash, _data, _signature, false);
}
return EIP1271_MAGIC_VALUE;
}
/// @dev Returns hash of a message that can be signed by owners.
/// @param message Message that should be hashed
/// @return Message hash.
function getMessageHash(
bytes memory message
)
public
view
returns (bytes32)
{
bytes32 safeMessageHash = keccak256(
abi.encode(SAFE_MSG_TYPEHASH, keccak256(message))
);
return keccak256(
abi.encodePacked(byte(0x19), byte(0x01), domainSeparator, safeMessageHash)
);
}
/// @dev Returns the bytes that are hashed to be signed by owners.
/// @param to Destination address.
/// @param value Ether value.
/// @param data Data payload.
/// @param operation Operation type.
/// @param safeTxGas Fas that should be used for the safe transaction.
/// @param baseGas Gas costs for data used to trigger the safe transaction.
/// @param gasPrice Maximum gas price that should be used for this transaction.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @param _nonce Transaction nonce.
/// @return Transaction hash bytes.
function encodeTransactionData(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
)
public
view
returns (bytes memory)
{
bytes32 safeTxHash = keccak256(
abi.encode(SAFE_TX_TYPEHASH, to, value, keccak256(data), operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce)
);
return abi.encodePacked(byte(0x19), byte(0x01), domainSeparator, safeTxHash);
}
/// @dev Returns hash to be signed by owners.
/// @param to Destination address.
/// @param value Ether value.
/// @param data Data payload.
/// @param operation Operation type.
/// @param safeTxGas Fas that should be used for the safe transaction.
/// @param baseGas Gas costs for data used to trigger the safe transaction.
/// @param gasPrice Maximum gas price that should be used for this transaction.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @param _nonce Transaction nonce.
/// @return Transaction hash.
function getTransactionHash(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
)
public
view
returns (bytes32)
{
return keccak256(encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce));
}
}
Compiler Settings
{"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":false},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[]},{"type":"event","name":"AddedOwner","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ApproveHash","inputs":[{"type":"bytes32","name":"approvedHash","internalType":"bytes32","indexed":true},{"type":"address","name":"owner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ChangedMasterCopy","inputs":[{"type":"address","name":"masterCopy","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ChangedThreshold","inputs":[{"type":"uint256","name":"threshold","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DisabledModule","inputs":[{"type":"address","name":"module","internalType":"contract Module","indexed":false}],"anonymous":false},{"type":"event","name":"EnabledModule","inputs":[{"type":"address","name":"module","internalType":"contract Module","indexed":false}],"anonymous":false},{"type":"event","name":"ExecutionFailure","inputs":[{"type":"bytes32","name":"txHash","internalType":"bytes32","indexed":false},{"type":"uint256","name":"payment","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExecutionFromModuleFailure","inputs":[{"type":"address","name":"module","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ExecutionFromModuleSuccess","inputs":[{"type":"address","name":"module","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ExecutionSuccess","inputs":[{"type":"bytes32","name":"txHash","internalType":"bytes32","indexed":false},{"type":"uint256","name":"payment","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RemovedOwner","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SignMsg","inputs":[{"type":"bytes32","name":"msgHash","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"fallback","stateMutability":"payable","payable":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"","internalType":"string"}],"name":"NAME","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"","internalType":"string"}],"name":"VERSION","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addOwnerWithThreshold","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"uint256","name":"_threshold","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"approveHash","inputs":[{"type":"bytes32","name":"hashToApprove","internalType":"bytes32"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"approvedHashes","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"bytes32","name":"","internalType":"bytes32"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"changeMasterCopy","inputs":[{"type":"address","name":"_masterCopy","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"changeThreshold","inputs":[{"type":"uint256","name":"_threshold","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"disableModule","inputs":[{"type":"address","name":"prevModule","internalType":"contract Module"},{"type":"address","name":"module","internalType":"contract Module"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"domainSeparator","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"enableModule","inputs":[{"type":"address","name":"module","internalType":"contract Module"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"encodeTransactionData","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"uint8","name":"operation","internalType":"enum Enum.Operation"},{"type":"uint256","name":"safeTxGas","internalType":"uint256"},{"type":"uint256","name":"baseGas","internalType":"uint256"},{"type":"uint256","name":"gasPrice","internalType":"uint256"},{"type":"address","name":"gasToken","internalType":"address"},{"type":"address","name":"refundReceiver","internalType":"address"},{"type":"uint256","name":"_nonce","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"payable","payable":true,"outputs":[{"type":"bool","name":"success","internalType":"bool"}],"name":"execTransaction","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"uint8","name":"operation","internalType":"enum Enum.Operation"},{"type":"uint256","name":"safeTxGas","internalType":"uint256"},{"type":"uint256","name":"baseGas","internalType":"uint256"},{"type":"uint256","name":"gasPrice","internalType":"uint256"},{"type":"address","name":"gasToken","internalType":"address"},{"type":"address","name":"refundReceiver","internalType":"address payable"},{"type":"bytes","name":"signatures","internalType":"bytes"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"success","internalType":"bool"}],"name":"execTransactionFromModule","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"uint8","name":"operation","internalType":"enum Enum.Operation"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"success","internalType":"bool"},{"type":"bytes","name":"returnData","internalType":"bytes"}],"name":"execTransactionFromModuleReturnData","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"uint8","name":"operation","internalType":"enum Enum.Operation"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getMessageHash","inputs":[{"type":"bytes","name":"message","internalType":"bytes"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getModules","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":"array","internalType":"address[]"},{"type":"address","name":"next","internalType":"address"}],"name":"getModulesPaginated","inputs":[{"type":"address","name":"start","internalType":"address"},{"type":"uint256","name":"pageSize","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getOwners","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getThreshold","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getTransactionHash","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"uint8","name":"operation","internalType":"enum Enum.Operation"},{"type":"uint256","name":"safeTxGas","internalType":"uint256"},{"type":"uint256","name":"baseGas","internalType":"uint256"},{"type":"uint256","name":"gasPrice","internalType":"uint256"},{"type":"address","name":"gasToken","internalType":"address"},{"type":"address","name":"refundReceiver","internalType":"address"},{"type":"uint256","name":"_nonce","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isModuleEnabled","inputs":[{"type":"address","name":"module","internalType":"contract Module"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"isValidSignature","inputs":[{"type":"bytes","name":"_data","internalType":"bytes"},{"type":"bytes","name":"_signature","internalType":"bytes"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nonce","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeOwner","inputs":[{"type":"address","name":"prevOwner","internalType":"address"},{"type":"address","name":"owner","internalType":"address"},{"type":"uint256","name":"_threshold","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"requiredTxGas","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"uint8","name":"operation","internalType":"enum Enum.Operation"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setFallbackHandler","inputs":[{"type":"address","name":"handler","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setup","inputs":[{"type":"address[]","name":"_owners","internalType":"address[]"},{"type":"uint256","name":"_threshold","internalType":"uint256"},{"type":"address","name":"to","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"address","name":"fallbackHandler","internalType":"address"},{"type":"address","name":"paymentToken","internalType":"address"},{"type":"uint256","name":"payment","internalType":"uint256"},{"type":"address","name":"paymentReceiver","internalType":"address payable"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"signMessage","inputs":[{"type":"bytes","name":"_data","internalType":"bytes"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"signedMessages","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"swapOwner","inputs":[{"type":"address","name":"prevOwner","internalType":"address"},{"type":"address","name":"oldOwner","internalType":"address"},{"type":"address","name":"newOwner","internalType":"address"}],"constant":false}]
Contract Creation Code
0x608060405234801561001057600080fd5b506001600481905550615f5a80620000296000396000f3fe6080604052600436106101d85760003560e01c8063a3f4df7e11610102578063e009cfde11610095578063f08a032311610064578063f08a03231461156b578063f698da25146115bc578063f8dc5dd9146115e7578063ffa1ad7414611662576101d8565b8063e009cfde1461125d578063e318b52b146112ce578063e75235b81461135f578063e86637db1461138a576101d8565b8063c4ca3a9c116100d1578063c4ca3a9c14610ef2578063cc2f845214610fc3578063d4d9bdcd146110a6578063d8d11f78146110e1576101d8565b8063a3f4df7e14610c5b578063affed0e014610ceb578063b2494df314610d16578063b63e800d14610d82576101d8565b80635ae6bd371161017a5780637d832974116101495780637d83297414610aa95780637de7edef14610b1857806385a5affe14610b69578063a0e67e2b14610bef576101d8565b80635ae6bd3714610852578063610b5925146108a1578063694e80c3146108f25780636a7612021461092d576101d8565b80632d9ad53d116101b65780632d9ad53d146104e65780632f54bf6e1461054f578063468721a7146105b85780635229073f146106cf576101d8565b80630a1028c4146102825780630d582f131461035e57806320c13b0b146103b9575b60003411806101ea5750600080369050145b156101f457610280565b60007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b9050600081549050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461027d57366000803760008036600080855af13d6000803e6000811415610278573d6000fd5b3d6000f35b50505b005b34801561028e57600080fd5b50610348600480360360208110156102a557600080fd5b81019080803590602001906401000000008111156102c257600080fd5b8201836020820111156102d457600080fd5b803590602001918460018302840111640100000000831117156102f657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506116f2565b6040518082815260200191505060405180910390f35b34801561036a57600080fd5b506103b76004803603604081101561038157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611829565b005b3480156103c557600080fd5b50610492600480360360408110156103dc57600080fd5b81019080803590602001906401000000008111156103f957600080fd5b82018360208201111561040b57600080fd5b8035906020019184600183028401116401000000008311171561042d57600080fd5b90919293919293908035906020019064010000000081111561044e57600080fd5b82018360208201111561046057600080fd5b8035906020019184600183028401116401000000008311171561048257600080fd5b9091929391929390505050611c73565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b3480156104f257600080fd5b506105356004803603602081101561050957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e09565b604051808215151515815260200191505060405180910390f35b34801561055b57600080fd5b5061059e6004803603602081101561057257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611edb565b604051808215151515815260200191505060405180910390f35b3480156105c457600080fd5b506106b5600480360360808110156105db57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561062257600080fd5b82018360208201111561063457600080fd5b8035906020019184600183028401116401000000008311171561065657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff169060200190929190505050611fad565b604051808215151515815260200191505060405180910390f35b3480156106db57600080fd5b506107cc600480360360808110156106f257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561073957600080fd5b82018360208201111561074b57600080fd5b8035906020019184600183028401116401000000008311171561076d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff169060200190929190505050612176565b604051808315151515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156108165780820151818401526020810190506107fb565b50505050905090810190601f1680156108435780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561085e57600080fd5b5061088b6004803603602081101561087557600080fd5b81019080803590602001909291905050506121ac565b6040518082815260200191505060405180910390f35b3480156108ad57600080fd5b506108f0600480360360208110156108c457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506121c4565b005b3480156108fe57600080fd5b5061092b6004803603602081101561091557600080fd5b81019080803590602001909291905050506125e8565b005b610a8f600480360361014081101561094457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561098b57600080fd5b82018360208201111561099d57600080fd5b803590602001918460018302840111640100000000831117156109bf57600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610a4b57600080fd5b820183602082011115610a5d57600080fd5b80359060200191846001830284011164010000000083111715610a7f57600080fd5b9091929391929390505050612764565b604051808215151515815260200191505060405180910390f35b348015610ab557600080fd5b50610b0260048036036040811015610acc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506129ec565b6040518082815260200191505060405180910390f35b348015610b2457600080fd5b50610b6760048036036020811015610b3b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612a11565b005b348015610b7557600080fd5b50610bed60048036036020811015610b8c57600080fd5b8101908080359060200190640100000000811115610ba957600080fd5b820183602082011115610bbb57600080fd5b80359060200191846001830284011164010000000083111715610bdd57600080fd5b9091929391929390505050612bc1565b005b348015610bfb57600080fd5b50610c04612ce1565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610c47578082015181840152602081019050610c2c565b505050509050019250505060405180910390f35b348015610c6757600080fd5b50610c70612e76565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610cb0578082015181840152602081019050610c95565b50505050905090810190601f168015610cdd5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610cf757600080fd5b50610d00612eaf565b6040518082815260200191505060405180910390f35b348015610d2257600080fd5b50610d2b612eb5565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610d6e578082015181840152602081019050610d53565b505050509050019250505060405180910390f35b348015610d8e57600080fd5b50610ef06004803603610100811015610da657600080fd5b8101908080359060200190640100000000811115610dc357600080fd5b820183602082011115610dd557600080fd5b80359060200191846020830284011164010000000083111715610df757600080fd5b909192939192939080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610e4257600080fd5b820183602082011115610e5457600080fd5b80359060200191846001830284011164010000000083111715610e7657600080fd5b9091929391929390803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612ece565b005b348015610efe57600080fd5b50610fad60048036036080811015610f1557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190640100000000811115610f5c57600080fd5b820183602082011115610f6e57600080fd5b80359060200191846001830284011164010000000083111715610f9057600080fd5b9091929391929390803560ff1690602001909291905050506130c9565b6040518082815260200191505060405180910390f35b348015610fcf57600080fd5b5061101c60048036036040811015610fe657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613276565b60405180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019060200280838360005b83811015611091578082015181840152602081019050611076565b50505050905001935050505060405180910390f35b3480156110b257600080fd5b506110df600480360360208110156110c957600080fd5b8101908080359060200190929190505050613455565b005b3480156110ed57600080fd5b50611247600480360361014081101561110557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561114c57600080fd5b82018360208201111561115e57600080fd5b8035906020019184600183028401116401000000008311171561118057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506135f4565b6040518082815260200191505060405180910390f35b34801561126957600080fd5b506112cc6004803603604081101561128057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061361f565b005b3480156112da57600080fd5b5061135d600480360360608110156112f157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613a25565b005b34801561136b57600080fd5b506113746140ea565b6040518082815260200191505060405180910390f35b34801561139657600080fd5b506114f060048036036101408110156113ae57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156113f557600080fd5b82018360208201111561140757600080fd5b8035906020019184600183028401116401000000008311171561142957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506140f4565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015611530578082015181840152602081019050611515565b50505050905090810190601f16801561155d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561157757600080fd5b506115ba6004803603602081101561158e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614308565b005b3480156115c857600080fd5b506115d1614398565b6040518082815260200191505060405180910390f35b3480156115f357600080fd5b506116606004803603606081101561160a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061439e565b005b34801561166e57600080fd5b50611677614829565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156116b757808201518184015260208101905061169c565b50505050905090810190601f1680156116e45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000807f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca60001b83805190602001206040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209050601960f81b600160f81b6006548360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260010183815260200182815260200194505050505060405160208183030381529060405280519060200120915050919050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146118ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156119175750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611989576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611a8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f4164647265737320697320616c726561647920616e206f776e6572000000000081525060200191505060405180910390fd5b60026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506003600081548092919060010191905055507f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2682604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18060045414611c6f57611c6e816125e8565b5b5050565b600080611cc386868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506116f2565b90506000848490501415611d6057600060076000838152602001908152602001600020541415611d5b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f48617368206e6f7420617070726f76656400000000000000000000000000000081525060200191505060405180910390fd5b611df6565b611df58187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505086868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000614862565b5b6320c13b0b60e01b915050949350505050565b60008173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff1614158015611ed45750600073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611fa65750600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156120785750600073ffffffffffffffffffffffffffffffffffffffff16600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b6120cd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180615e736030913960400191505060405180910390fd5b6120da858585855a615190565b9050801561212a573373ffffffffffffffffffffffffffffffffffffffff167f6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb860405160405180910390a261216e565b3373ffffffffffffffffffffffffffffffffffffffff167facd2c8702804128fdb0db2bb49f6d127dd0181c13fd45dbfe16de0930e2bd37560405160405180910390a25b949350505050565b6000606061218686868686611fad565b915060405160203d0181016040523d81523d6000602083013e8091505094509492505050565b60076020528060005260406000206000915090505481565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612248576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156122b25750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b612324576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f496e76616c6964206d6f64756c6520616464726573732070726f76696465640081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612425576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4d6f64756c652068617320616c7265616479206265656e20616464656400000081525060200191505060405180910390fd5b60016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f844081604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461266c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b6003548111156126c7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180615d166023913960400191505060405180910390fd5b6001811015612721576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180615dec6024913960400191505060405180910390fd5b806004819055507f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c936004546040518082815260200191505060405180910390a150565b60008060606127c18f8f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508e8e8e8e8e8e6005546140f4565b905060056000815480929190600101919050555080805190602001209150612830828287878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506001614862565b506101f46128586109c48b01603f60408d028161284957fe5b0461520290919063ffffffff16565b015a10156128b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180615efc602a913960400191505060405180910390fd5b60005a905061291a8f8f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508e60008d1461290f578e612915565b6109c45a035b615190565b925061292f5a8261521c90919063ffffffff16565b90506000809050600089111561294f5761294c828b8b8b8b61523c565b90505b8315612999577f442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e8382604051808381526020018281526020019250505060405180910390a16129d9565b7f23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d238382604051808381526020018281526020019250505060405180910390a15b5050509c9b505050505050505050505050565b6008602052816000526040600020602052806000526040600020600091509150505481565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612a95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612b1b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180615c826024913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f75e41bc35ff1bf14d81d1d2f649c0084a0f974f9289c803ec9898eeec4c8d0b881604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612c45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b6000612c9483838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506116f2565b905060016007600083815260200190815260200160002081905550807fe7f4675038f4f6034dfcbbb24c4dc08e4ebf10eb9d257d3d02c0f38d122ac6e460405160405180910390a2505050565b606080600354604051908082528060200260200182016040528015612d155781602001602082028038833980820191505090505b5090506000809050600060026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612e6d5780838381518110612dc457fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508180600101925050612d83565b82935050505090565b6040518060400160405280600b81526020017f476e6f736973205361666500000000000000000000000000000000000000000081525081565b60055481565b606080612ec46001600a613276565b5090508091505090565b6000801b60065414612f48576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f446f6d61696e20536570617261746f7220616c7265616479207365742100000081525060200191505060405180910390fd5b7f035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d474960001b30604051602001808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050604051602081830303815290604052805190602001206006819055506130178a8a80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505089615408565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146130555761305484615861565b5b6130a38787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050615890565b60008211156130bd576130bb8260006001868561523c565b505b50505050505050505050565b60003073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461314f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b60005a90506131a5878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050865a615190565b6131ae57600080fd5b60005a8203905080604051602001808281526020019150506040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561323b578082015181840152602081019050613220565b50505050905090810190601f1680156132685780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60606000826040519080825280602002602001820160405280156132a95781602001602082028038833980820191505090505b50915060008090506000600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156133805750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561338b57508482105b15613446578084838151811061339d57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508180600101925050613316565b80925081845250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff16600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415613557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f4f6e6c79206f776e6572732063616e20617070726f766520612068617368000081525060200191505060405180910390fd5b6001600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000838152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff16817ff2a0eb156472d1440255b0d7c1e19cc07115d1051fe605b0dce69acfec884d9c60405160405180910390a350565b60006136088b8b8b8b8b8b8b8b8b8b6140f4565b8051906020012090509a9950505050505050505050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146136a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561370d5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b61377f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f496e76616c6964206d6f64756c6520616464726573732070726f76696465640081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613862576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180615cee6028913960400191505060405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507faab4fa2b463f581b2b32cb3b7e3b704b9ce37cc209b5fb4d77e593ace405427681604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a15050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614613aa9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015613b135750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b613b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613c86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f4164647265737320697320616c726561647920616e206f776e6572000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015613cf05750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b613d62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613e45576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180615d906026913960400191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a17f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2681604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1505050565b6000600454905090565b606060007fbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d860001b8c8c8c805190602001208c8c8c8c8c8c8c604051602001808c81526020018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018a815260200189815260200188600181111561418457fe5b60ff1681526020018781526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019b505050505050505050505050604051602081830303815290604052805190602001209050601960f81b600160f81b6006548360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040529150509a9950505050505050505050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461438c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b61439581615861565b50565b60065481565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614614422576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b806001600354031015614480576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526035815260200180615d396035913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156144ea5750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b61455c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461463f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180615d906026913960400191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360008154809291906001900391905055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1806004541461482457614823816125e8565b5b505050565b6040518060400160405280600581526020017f312e322e3000000000000000000000000000000000000000000000000000000081525081565b60006004549050600081116148df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f5468726573686f6c64206e6565647320746f20626520646566696e656421000081525060200191505060405180910390fd5b6148f3604182615aaa90919063ffffffff16565b83511015614969576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f5369676e617475726573206461746120746f6f2073686f72740000000000000081525060200191505060405180910390fd5b600080905060008060008060008090505b868110156151835761498c8982615ae4565b80945081955082965050505060008460ff161415614d21578260001c94506149be604188615aaa90919063ffffffff16565b8260001c1015614a19576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526037815260200180615e106037913960400191505060405180910390fd5b8851614a3260208460001c615b1390919063ffffffff16565b1115614a89576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526037815260200180615ea36037913960400191505060405180910390fd5b60006020838b01015190508951614abf82614ab160208760001c615b1390919063ffffffff16565b615b1390919063ffffffff16565b1115614b16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180615db66036913960400191505060405180910390fd5b60606020848c010190506320c13b0b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168773ffffffffffffffffffffffffffffffffffffffff166320c13b0b8e846040518363ffffffff1660e01b8152600401808060200180602001838103835285818151815260200191508051906020019080838360005b83811015614bb8578082015181840152602081019050614b9d565b50505050905090810190601f168015614be55780820380516001836020036101000a031916815260200191505b50838103825284818151815260200191508051906020019080838360005b83811015614c1e578082015181840152602081019050614c03565b50505050905090810190601f168015614c4b5780820380516001836020036101000a031916815260200191505b5094505050505060206040518083038186803b158015614c6a57600080fd5b505afa158015614c7e573d6000803e3d6000fd5b505050506040513d6020811015614c9457600080fd5b81019080805190602001909291905050507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614614d1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180615ccb6023913960400191505060405180910390fd5b5050615001565b60018460ff161415614eca578260001c94508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480614dbe57506000600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008d81526020019081526020016000205414155b614e30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4861736820686173206e6f74206265656e20617070726f76656400000000000081525060200191505060405180910390fd5b878015614e6957508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15614ec5576000600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008d8152602001908152602001600020819055505b615000565b601e8460ff161115614f955760018b60405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012060048603858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015614f84573d6000803e3d6000fd5b505050602060405103519450614fff565b60018b85858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015614ff2573d6000803e3d6000fd5b5050506020604051035194505b5b5b8573ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161180156150c85750600073ffffffffffffffffffffffffffffffffffffffff16600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b80156151015750600173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b615173576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f496e76616c6964206f776e65722070726f76696465640000000000000000000081525060200191505060405180910390fd5b849550808060010191505061497a565b5050505050505050505050565b600080600181111561519e57fe5b8360018111156151aa57fe5b14156151c3576151bc86868685615b32565b90506151f9565b6001808111156151cf57fe5b8360018111156151db57fe5b14156151f3576151ec868584615b4b565b90506151f8565b600090505b5b95945050505050565b6000818310156152125781615214565b825b905092915050565b60008282111561522b57600080fd5b600082840390508091505092915050565b600080600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614615279578261527b565b325b9050600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415615376576152e53a86106152c2573a6152c4565b855b6152d7888a615b1390919063ffffffff16565b615aaa90919063ffffffff16565b91508073ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050615371576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180615eda6022913960400191505060405180910390fd5b6153fe565b61539b8561538d888a615b1390919063ffffffff16565b615aaa90919063ffffffff16565b91506153a8848284615b62565b6153fd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180615d6e6022913960400191505060405180910390fd5b5b5095945050505050565b600060045414615480576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f4f776e657273206861766520616c7265616479206265656e207365747570000081525060200191505060405180910390fd5b81518111156154da576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180615d166023913960400191505060405180910390fd5b6001811015615534576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180615dec6024913960400191505060405180910390fd5b60006001905060008090505b83518110156157cd57600084828151811061555757fe5b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156155cb5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b61563d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461573e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4475706c6963617465206f776e657220616464726573732070726f766964656481525060200191505060405180910390fd5b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550809250508080600101915050615540565b506001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550825160038190555081600481905550505050565b60007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b90508181555050565b600073ffffffffffffffffffffffffffffffffffffffff1660016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614615975576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180615ca66025913960400191505060405180910390fd5b6001806000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614615aa657615a3382825a615b4b565b615aa5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f436f756c64206e6f742066696e69736820696e697469616c697a6174696f6e0081525060200191505060405180910390fd5b5b5050565b600080831415615abd5760009050615ade565b6000828402905082848281615ace57fe5b0414615ad957600080fd5b809150505b92915050565b60008060008360410260208101860151925060408101860151915060ff60418201870151169350509250925092565b600080828401905083811015615b2857600080fd5b8091505092915050565b6000806000845160208601878987f19050949350505050565b60008060008451602086018786f490509392505050565b600060608383604051602401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808251602084016000896127105a03f16040513d81016040523d6000823e3d60008114615c645760208114615c6c5760009450615c76565b829450615c76565b8151158315171594505b50505050939250505056fe496e76616c6964206d617374657220636f707920616464726573732070726f76696465644d6f64756c6573206861766520616c7265616479206265656e20696e697469616c697a6564496e76616c696420636f6e7472616374207369676e61747572652070726f7669646564496e76616c696420707265764d6f64756c652c206d6f64756c6520706169722070726f76696465645468726573686f6c642063616e6e6f7420657863656564206f776e657220636f756e744e6577206f776e657220636f756e74206e6565647320746f206265206c6172676572207468616e206e6577207468726573686f6c64436f756c64206e6f74207061792067617320636f737473207769746820746f6b656e496e76616c696420707265764f776e65722c206f776e657220706169722070726f7669646564496e76616c696420636f6e7472616374207369676e6174757265206c6f636174696f6e3a2064617461206e6f7420636f6d706c6574655468726573686f6c64206e6565647320746f2062652067726561746572207468616e2030496e76616c696420636f6e7472616374207369676e6174757265206c6f636174696f6e3a20696e736964652073746174696320706172744d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d207468697320636f6e74726163744d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d20616e20656e61626c6564206d6f64756c65496e76616c696420636f6e7472616374207369676e6174757265206c6f636174696f6e3a206c656e677468206e6f742070726573656e74436f756c64206e6f74207061792067617320636f73747320776974682065746865724e6f7420656e6f7567682067617320746f20657865637574652073616665207472616e73616374696f6ea265627a7a72315820eba952a8e826ae22d1831da9d381d7b6c153687b8cb43c646ad31acd2ce8428864736f6c63430005110032
Deployed ByteCode
0x6080604052600436106101d85760003560e01c8063a3f4df7e11610102578063e009cfde11610095578063f08a032311610064578063f08a03231461156b578063f698da25146115bc578063f8dc5dd9146115e7578063ffa1ad7414611662576101d8565b8063e009cfde1461125d578063e318b52b146112ce578063e75235b81461135f578063e86637db1461138a576101d8565b8063c4ca3a9c116100d1578063c4ca3a9c14610ef2578063cc2f845214610fc3578063d4d9bdcd146110a6578063d8d11f78146110e1576101d8565b8063a3f4df7e14610c5b578063affed0e014610ceb578063b2494df314610d16578063b63e800d14610d82576101d8565b80635ae6bd371161017a5780637d832974116101495780637d83297414610aa95780637de7edef14610b1857806385a5affe14610b69578063a0e67e2b14610bef576101d8565b80635ae6bd3714610852578063610b5925146108a1578063694e80c3146108f25780636a7612021461092d576101d8565b80632d9ad53d116101b65780632d9ad53d146104e65780632f54bf6e1461054f578063468721a7146105b85780635229073f146106cf576101d8565b80630a1028c4146102825780630d582f131461035e57806320c13b0b146103b9575b60003411806101ea5750600080369050145b156101f457610280565b60007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b9050600081549050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461027d57366000803760008036600080855af13d6000803e6000811415610278573d6000fd5b3d6000f35b50505b005b34801561028e57600080fd5b50610348600480360360208110156102a557600080fd5b81019080803590602001906401000000008111156102c257600080fd5b8201836020820111156102d457600080fd5b803590602001918460018302840111640100000000831117156102f657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506116f2565b6040518082815260200191505060405180910390f35b34801561036a57600080fd5b506103b76004803603604081101561038157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611829565b005b3480156103c557600080fd5b50610492600480360360408110156103dc57600080fd5b81019080803590602001906401000000008111156103f957600080fd5b82018360208201111561040b57600080fd5b8035906020019184600183028401116401000000008311171561042d57600080fd5b90919293919293908035906020019064010000000081111561044e57600080fd5b82018360208201111561046057600080fd5b8035906020019184600183028401116401000000008311171561048257600080fd5b9091929391929390505050611c73565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b3480156104f257600080fd5b506105356004803603602081101561050957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e09565b604051808215151515815260200191505060405180910390f35b34801561055b57600080fd5b5061059e6004803603602081101561057257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611edb565b604051808215151515815260200191505060405180910390f35b3480156105c457600080fd5b506106b5600480360360808110156105db57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561062257600080fd5b82018360208201111561063457600080fd5b8035906020019184600183028401116401000000008311171561065657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff169060200190929190505050611fad565b604051808215151515815260200191505060405180910390f35b3480156106db57600080fd5b506107cc600480360360808110156106f257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561073957600080fd5b82018360208201111561074b57600080fd5b8035906020019184600183028401116401000000008311171561076d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff169060200190929190505050612176565b604051808315151515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156108165780820151818401526020810190506107fb565b50505050905090810190601f1680156108435780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561085e57600080fd5b5061088b6004803603602081101561087557600080fd5b81019080803590602001909291905050506121ac565b6040518082815260200191505060405180910390f35b3480156108ad57600080fd5b506108f0600480360360208110156108c457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506121c4565b005b3480156108fe57600080fd5b5061092b6004803603602081101561091557600080fd5b81019080803590602001909291905050506125e8565b005b610a8f600480360361014081101561094457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561098b57600080fd5b82018360208201111561099d57600080fd5b803590602001918460018302840111640100000000831117156109bf57600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610a4b57600080fd5b820183602082011115610a5d57600080fd5b80359060200191846001830284011164010000000083111715610a7f57600080fd5b9091929391929390505050612764565b604051808215151515815260200191505060405180910390f35b348015610ab557600080fd5b50610b0260048036036040811015610acc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506129ec565b6040518082815260200191505060405180910390f35b348015610b2457600080fd5b50610b6760048036036020811015610b3b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612a11565b005b348015610b7557600080fd5b50610bed60048036036020811015610b8c57600080fd5b8101908080359060200190640100000000811115610ba957600080fd5b820183602082011115610bbb57600080fd5b80359060200191846001830284011164010000000083111715610bdd57600080fd5b9091929391929390505050612bc1565b005b348015610bfb57600080fd5b50610c04612ce1565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610c47578082015181840152602081019050610c2c565b505050509050019250505060405180910390f35b348015610c6757600080fd5b50610c70612e76565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610cb0578082015181840152602081019050610c95565b50505050905090810190601f168015610cdd5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610cf757600080fd5b50610d00612eaf565b6040518082815260200191505060405180910390f35b348015610d2257600080fd5b50610d2b612eb5565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610d6e578082015181840152602081019050610d53565b505050509050019250505060405180910390f35b348015610d8e57600080fd5b50610ef06004803603610100811015610da657600080fd5b8101908080359060200190640100000000811115610dc357600080fd5b820183602082011115610dd557600080fd5b80359060200191846020830284011164010000000083111715610df757600080fd5b909192939192939080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610e4257600080fd5b820183602082011115610e5457600080fd5b80359060200191846001830284011164010000000083111715610e7657600080fd5b9091929391929390803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612ece565b005b348015610efe57600080fd5b50610fad60048036036080811015610f1557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190640100000000811115610f5c57600080fd5b820183602082011115610f6e57600080fd5b80359060200191846001830284011164010000000083111715610f9057600080fd5b9091929391929390803560ff1690602001909291905050506130c9565b6040518082815260200191505060405180910390f35b348015610fcf57600080fd5b5061101c60048036036040811015610fe657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613276565b60405180806020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019060200280838360005b83811015611091578082015181840152602081019050611076565b50505050905001935050505060405180910390f35b3480156110b257600080fd5b506110df600480360360208110156110c957600080fd5b8101908080359060200190929190505050613455565b005b3480156110ed57600080fd5b50611247600480360361014081101561110557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561114c57600080fd5b82018360208201111561115e57600080fd5b8035906020019184600183028401116401000000008311171561118057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506135f4565b6040518082815260200191505060405180910390f35b34801561126957600080fd5b506112cc6004803603604081101561128057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061361f565b005b3480156112da57600080fd5b5061135d600480360360608110156112f157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613a25565b005b34801561136b57600080fd5b506113746140ea565b6040518082815260200191505060405180910390f35b34801561139657600080fd5b506114f060048036036101408110156113ae57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156113f557600080fd5b82018360208201111561140757600080fd5b8035906020019184600183028401116401000000008311171561142957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506140f4565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015611530578082015181840152602081019050611515565b50505050905090810190601f16801561155d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561157757600080fd5b506115ba6004803603602081101561158e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614308565b005b3480156115c857600080fd5b506115d1614398565b6040518082815260200191505060405180910390f35b3480156115f357600080fd5b506116606004803603606081101561160a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061439e565b005b34801561166e57600080fd5b50611677614829565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156116b757808201518184015260208101905061169c565b50505050905090810190601f1680156116e45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000807f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca60001b83805190602001206040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209050601960f81b600160f81b6006548360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260010183815260200182815260200194505050505060405160208183030381529060405280519060200120915050919050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146118ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156119175750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611989576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611a8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f4164647265737320697320616c726561647920616e206f776e6572000000000081525060200191505060405180910390fd5b60026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506003600081548092919060010191905055507f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2682604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18060045414611c6f57611c6e816125e8565b5b5050565b600080611cc386868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506116f2565b90506000848490501415611d6057600060076000838152602001908152602001600020541415611d5b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f48617368206e6f7420617070726f76656400000000000000000000000000000081525060200191505060405180910390fd5b611df6565b611df58187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505086868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000614862565b5b6320c13b0b60e01b915050949350505050565b60008173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff1614158015611ed45750600073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611fa65750600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156120785750600073ffffffffffffffffffffffffffffffffffffffff16600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b6120cd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180615e736030913960400191505060405180910390fd5b6120da858585855a615190565b9050801561212a573373ffffffffffffffffffffffffffffffffffffffff167f6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb860405160405180910390a261216e565b3373ffffffffffffffffffffffffffffffffffffffff167facd2c8702804128fdb0db2bb49f6d127dd0181c13fd45dbfe16de0930e2bd37560405160405180910390a25b949350505050565b6000606061218686868686611fad565b915060405160203d0181016040523d81523d6000602083013e8091505094509492505050565b60076020528060005260406000206000915090505481565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612248576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156122b25750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b612324576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f496e76616c6964206d6f64756c6520616464726573732070726f76696465640081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612425576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4d6f64756c652068617320616c7265616479206265656e20616464656400000081525060200191505060405180910390fd5b60016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f844081604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461266c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b6003548111156126c7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180615d166023913960400191505060405180910390fd5b6001811015612721576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180615dec6024913960400191505060405180910390fd5b806004819055507f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c936004546040518082815260200191505060405180910390a150565b60008060606127c18f8f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508e8e8e8e8e8e6005546140f4565b905060056000815480929190600101919050555080805190602001209150612830828287878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506001614862565b506101f46128586109c48b01603f60408d028161284957fe5b0461520290919063ffffffff16565b015a10156128b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180615efc602a913960400191505060405180910390fd5b60005a905061291a8f8f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508e60008d1461290f578e612915565b6109c45a035b615190565b925061292f5a8261521c90919063ffffffff16565b90506000809050600089111561294f5761294c828b8b8b8b61523c565b90505b8315612999577f442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e8382604051808381526020018281526020019250505060405180910390a16129d9565b7f23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d238382604051808381526020018281526020019250505060405180910390a15b5050509c9b505050505050505050505050565b6008602052816000526040600020602052806000526040600020600091509150505481565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612a95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612b1b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180615c826024913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f75e41bc35ff1bf14d81d1d2f649c0084a0f974f9289c803ec9898eeec4c8d0b881604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612c45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b6000612c9483838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506116f2565b905060016007600083815260200190815260200160002081905550807fe7f4675038f4f6034dfcbbb24c4dc08e4ebf10eb9d257d3d02c0f38d122ac6e460405160405180910390a2505050565b606080600354604051908082528060200260200182016040528015612d155781602001602082028038833980820191505090505b5090506000809050600060026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612e6d5780838381518110612dc457fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508180600101925050612d83565b82935050505090565b6040518060400160405280600b81526020017f476e6f736973205361666500000000000000000000000000000000000000000081525081565b60055481565b606080612ec46001600a613276565b5090508091505090565b6000801b60065414612f48576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f446f6d61696e20536570617261746f7220616c7265616479207365742100000081525060200191505060405180910390fd5b7f035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d474960001b30604051602001808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050604051602081830303815290604052805190602001206006819055506130178a8a80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505089615408565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146130555761305484615861565b5b6130a38787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050615890565b60008211156130bd576130bb8260006001868561523c565b505b50505050505050505050565b60003073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461314f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b60005a90506131a5878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050865a615190565b6131ae57600080fd5b60005a8203905080604051602001808281526020019150506040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561323b578082015181840152602081019050613220565b50505050905090810190601f1680156132685780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60606000826040519080825280602002602001820160405280156132a95781602001602082028038833980820191505090505b50915060008090506000600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156133805750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561338b57508482105b15613446578084838151811061339d57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508180600101925050613316565b80925081845250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff16600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415613557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f4f6e6c79206f776e6572732063616e20617070726f766520612068617368000081525060200191505060405180910390fd5b6001600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000838152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff16817ff2a0eb156472d1440255b0d7c1e19cc07115d1051fe605b0dce69acfec884d9c60405160405180910390a350565b60006136088b8b8b8b8b8b8b8b8b8b6140f4565b8051906020012090509a9950505050505050505050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146136a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561370d5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b61377f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f496e76616c6964206d6f64756c6520616464726573732070726f76696465640081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613862576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180615cee6028913960400191505060405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507faab4fa2b463f581b2b32cb3b7e3b704b9ce37cc209b5fb4d77e593ace405427681604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a15050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614613aa9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015613b135750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b613b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613c86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f4164647265737320697320616c726561647920616e206f776e6572000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015613cf05750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b613d62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613e45576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180615d906026913960400191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a17f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2681604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1505050565b6000600454905090565b606060007fbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d860001b8c8c8c805190602001208c8c8c8c8c8c8c604051602001808c81526020018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018a815260200189815260200188600181111561418457fe5b60ff1681526020018781526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019b505050505050505050505050604051602081830303815290604052805190602001209050601960f81b600160f81b6006548360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040529150509a9950505050505050505050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461438c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b61439581615861565b50565b60065481565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614614422576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180615e47602c913960400191505060405180910390fd5b806001600354031015614480576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526035815260200180615d396035913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156144ea5750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b61455c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461463f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180615d906026913960400191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360008154809291906001900391905055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1806004541461482457614823816125e8565b5b505050565b6040518060400160405280600581526020017f312e322e3000000000000000000000000000000000000000000000000000000081525081565b60006004549050600081116148df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f5468726573686f6c64206e6565647320746f20626520646566696e656421000081525060200191505060405180910390fd5b6148f3604182615aaa90919063ffffffff16565b83511015614969576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f5369676e617475726573206461746120746f6f2073686f72740000000000000081525060200191505060405180910390fd5b600080905060008060008060008090505b868110156151835761498c8982615ae4565b80945081955082965050505060008460ff161415614d21578260001c94506149be604188615aaa90919063ffffffff16565b8260001c1015614a19576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526037815260200180615e106037913960400191505060405180910390fd5b8851614a3260208460001c615b1390919063ffffffff16565b1115614a89576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526037815260200180615ea36037913960400191505060405180910390fd5b60006020838b01015190508951614abf82614ab160208760001c615b1390919063ffffffff16565b615b1390919063ffffffff16565b1115614b16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526036815260200180615db66036913960400191505060405180910390fd5b60606020848c010190506320c13b0b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168773ffffffffffffffffffffffffffffffffffffffff166320c13b0b8e846040518363ffffffff1660e01b8152600401808060200180602001838103835285818151815260200191508051906020019080838360005b83811015614bb8578082015181840152602081019050614b9d565b50505050905090810190601f168015614be55780820380516001836020036101000a031916815260200191505b50838103825284818151815260200191508051906020019080838360005b83811015614c1e578082015181840152602081019050614c03565b50505050905090810190601f168015614c4b5780820380516001836020036101000a031916815260200191505b5094505050505060206040518083038186803b158015614c6a57600080fd5b505afa158015614c7e573d6000803e3d6000fd5b505050506040513d6020811015614c9457600080fd5b81019080805190602001909291905050507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614614d1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180615ccb6023913960400191505060405180910390fd5b5050615001565b60018460ff161415614eca578260001c94508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480614dbe57506000600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008d81526020019081526020016000205414155b614e30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4861736820686173206e6f74206265656e20617070726f76656400000000000081525060200191505060405180910390fd5b878015614e6957508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15614ec5576000600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008d8152602001908152602001600020819055505b615000565b601e8460ff161115614f955760018b60405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012060048603858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015614f84573d6000803e3d6000fd5b505050602060405103519450614fff565b60018b85858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015614ff2573d6000803e3d6000fd5b5050506020604051035194505b5b5b8573ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161180156150c85750600073ffffffffffffffffffffffffffffffffffffffff16600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b80156151015750600173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b615173576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f496e76616c6964206f776e65722070726f76696465640000000000000000000081525060200191505060405180910390fd5b849550808060010191505061497a565b5050505050505050505050565b600080600181111561519e57fe5b8360018111156151aa57fe5b14156151c3576151bc86868685615b32565b90506151f9565b6001808111156151cf57fe5b8360018111156151db57fe5b14156151f3576151ec868584615b4b565b90506151f8565b600090505b5b95945050505050565b6000818310156152125781615214565b825b905092915050565b60008282111561522b57600080fd5b600082840390508091505092915050565b600080600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614615279578261527b565b325b9050600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415615376576152e53a86106152c2573a6152c4565b855b6152d7888a615b1390919063ffffffff16565b615aaa90919063ffffffff16565b91508073ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050615371576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180615eda6022913960400191505060405180910390fd5b6153fe565b61539b8561538d888a615b1390919063ffffffff16565b615aaa90919063ffffffff16565b91506153a8848284615b62565b6153fd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180615d6e6022913960400191505060405180910390fd5b5b5095945050505050565b600060045414615480576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f4f776e657273206861766520616c7265616479206265656e207365747570000081525060200191505060405180910390fd5b81518111156154da576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180615d166023913960400191505060405180910390fd5b6001811015615534576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180615dec6024913960400191505060405180910390fd5b60006001905060008090505b83518110156157cd57600084828151811061555757fe5b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156155cb5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b61563d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f496e76616c6964206f776e657220616464726573732070726f7669646564000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461573e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4475706c6963617465206f776e657220616464726573732070726f766964656481525060200191505060405180910390fd5b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550809250508080600101915050615540565b506001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550825160038190555081600481905550505050565b60007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b90508181555050565b600073ffffffffffffffffffffffffffffffffffffffff1660016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614615975576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180615ca66025913960400191505060405180910390fd5b6001806000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614615aa657615a3382825a615b4b565b615aa5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f436f756c64206e6f742066696e69736820696e697469616c697a6174696f6e0081525060200191505060405180910390fd5b5b5050565b600080831415615abd5760009050615ade565b6000828402905082848281615ace57fe5b0414615ad957600080fd5b809150505b92915050565b60008060008360410260208101860151925060408101860151915060ff60418201870151169350509250925092565b600080828401905083811015615b2857600080fd5b8091505092915050565b6000806000845160208601878987f19050949350505050565b60008060008451602086018786f490509392505050565b600060608383604051602401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808251602084016000896127105a03f16040513d81016040523d6000823e3d60008114615c645760208114615c6c5760009450615c76565b829450615c76565b8151158315171594505b50505050939250505056fe496e76616c6964206d617374657220636f707920616464726573732070726f76696465644d6f64756c6573206861766520616c7265616479206265656e20696e697469616c697a6564496e76616c696420636f6e7472616374207369676e61747572652070726f7669646564496e76616c696420707265764d6f64756c652c206d6f64756c6520706169722070726f76696465645468726573686f6c642063616e6e6f7420657863656564206f776e657220636f756e744e6577206f776e657220636f756e74206e6565647320746f206265206c6172676572207468616e206e6577207468726573686f6c64436f756c64206e6f74207061792067617320636f737473207769746820746f6b656e496e76616c696420707265764f776e65722c206f776e657220706169722070726f7669646564496e76616c696420636f6e7472616374207369676e6174757265206c6f636174696f6e3a2064617461206e6f7420636f6d706c6574655468726573686f6c64206e6565647320746f2062652067726561746572207468616e2030496e76616c696420636f6e7472616374207369676e6174757265206c6f636174696f6e3a20696e736964652073746174696320706172744d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d207468697320636f6e74726163744d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d20616e20656e61626c6564206d6f64756c65496e76616c696420636f6e7472616374207369676e6174757265206c6f636174696f6e3a206c656e677468206e6f742070726573656e74436f756c64206e6f74207061792067617320636f73747320776974682065746865724e6f7420656e6f7567682067617320746f20657865637574652073616665207472616e73616374696f6ea265627a7a72315820eba952a8e826ae22d1831da9d381d7b6c153687b8cb43c646ad31acd2ce8428864736f6c63430005110032