ETH Price: $2,437.44 (-1.51%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60a06040122993862021-04-23 23:13:271291 days ago1619219607IN
 Create: DharmaTradeReserveV19Implementation
0 ETH0.3639342769.55764161

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DharmaTradeReserveV19Implementation

Compiler Version
v0.8.1+commit.df193b15

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-04-23
*/

// SPDX-License-Identifier: MIT

pragma solidity 0.8.1;


interface ITypes {
  struct Call {
    address to;
    uint96 value;
    bytes data;
  }

  struct CallReturn {
    bool ok;
    bytes returnData;
  }
}

interface IActionRegistry {

  // events
  event AddedSelector(address account, bytes4 selector);
  event RemovedSelector(address account, bytes4 selector);
  event AddedSpender(address account, address spender);
  event RemovedSpender(address account, address spender);

  struct AccountSelectors {
    address account;
    bytes4[] selectors;
  }

  struct AccountSpenders {
    address account;
    address[] spenders;
  }

  function isValidAction(ITypes.Call[] calldata calls) external view returns (bool valid);
  function addSelector(address account, bytes4 selector) external;
  function removeSelector(address account, bytes4 selector) external;
  function addSpender(address account, address spender) external;
  function removeSpender(address account, address spender) external;
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 *
 * In order to transfer ownership, a recipient must be specified, at which point
 * the specified recipient can call `acceptOwnership` and take ownership.
 */

contract TwoStepOwnable {
  address private _owner;

  address private _newPotentialOwner;

  event OwnershipTransferred(
    address indexed previousOwner,
    address indexed newOwner
  );

  /**
   * @dev Initialize contract by setting transaction submitter as initial owner.
   */
  constructor() public {
    _owner = tx.origin;
    emit OwnershipTransferred(address(0), _owner);
  }

  /**
   * @dev Returns the address of the current owner.
   */
  function owner() public view returns (address) {
    return _owner;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(isOwner(), "TwoStepOwnable: caller is not the owner.");
    _;
  }

  /**
   * @dev Returns true if the caller is the current owner.
   */
  function isOwner() public view returns (bool) {
    return msg.sender == _owner;
  }

  /**
   * @dev Allows a new account (`newOwner`) to accept ownership.
   * Can only be called by the current owner.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    require(
      newOwner != address(0),
      "TwoStepOwnable: new potential owner is the zero address."
    );

    _newPotentialOwner = newOwner;
  }

  /**
   * @dev Cancel a transfer of ownership to a new account.
   * Can only be called by the current owner.
   */
  function cancelOwnershipTransfer() public onlyOwner {
    delete _newPotentialOwner;
  }

  /**
   * @dev Transfers ownership of the contract to the caller.
   * Can only be called by a new potential owner set by the current owner.
   */
  function acceptOwnership() public {
    require(
      msg.sender == _newPotentialOwner,
      "TwoStepOwnable: current owner must set caller as new potential owner."
    );

    delete _newPotentialOwner;

    emit OwnershipTransferred(_owner, msg.sender);

    _owner = msg.sender;
  }
}

interface DharmaTradeReserveV19Interface {
  event Trade(
    address account,
    address suppliedAsset,
    address receivedAsset,
    address retainedAsset,
    uint256 suppliedAmount,
    uint256 recievedAmount, // note: typo
    uint256 retainedAmount
  );
  event RoleModified(Role indexed role, address account);
  event RolePaused(Role indexed role);
  event RoleUnpaused(Role indexed role);
  event EtherReceived(address sender, uint256 amount);
  event GasReserveRefilled(uint256 etherAmount);

  enum Role {            //
    DEPOSIT_MANAGER,     // 0
    ADJUSTER,            // 1
    WITHDRAWAL_MANAGER,  // 2
    RESERVE_TRADER,      // 3
    PAUSER,              // 4
    GAS_RESERVE_REFILLER, // 5
    ACTIONER // 6
  }

  enum FeeType {    // #
    SUPPLIED_ASSET, // 0
    RECEIVED_ASSET, // 1
    ETHER           // 2
  }

  enum TradeType {
    ETH_TO_TOKEN,
    TOKEN_TO_ETH,
    TOKEN_TO_TOKEN,
    ETH_TO_TOKEN_WITH_TRANSFER_FEE,
    TOKEN_TO_ETH_WITH_TRANSFER_FEE,
    TOKEN_TO_TOKEN_WITH_TRANSFER_FEE
  }

  struct RoleStatus {
    address account;
    bool paused;
  }

  function simulate(
    ITypes.Call[] calldata calls
  ) external returns (bool[] memory ok, bytes[] memory returnData, bool validCalls);

  function execute(
    ITypes.Call[] calldata calls
  ) external returns (bool[] memory ok, bytes[] memory returnData);

  event CallSuccess(
    bool rolledBack,
    address to,
    uint256 value,
    bytes data,
    bytes returnData
  );

  event CallFailure(
    address to,
    uint256 value,
    bytes data,
    string revertReason
  );

  function tradeTokenForTokenSpecifyingFee(
    ERC20Interface tokenProvided,
    address tokenReceived,
    uint256 tokenProvidedAmount,
    uint256 quotedTokenReceivedAmount,
    uint256 maximumFeeAmount, // WETH if routeThroughEther, else tokenReceived
    uint256 deadline,
    bool routeThroughEther,
    FeeType feeType
  ) external returns (uint256 totalTokensBought);

  function tradeTokenForTokenWithFeeOnTransfer(
    ERC20Interface tokenProvided,
    address tokenReceived,
    uint256 tokenProvidedAmount,
    uint256 quotedTokenReceivedAmount,
    uint256 quotedTokenReceivedAmountAfterTransferFee,
    uint256 deadline,
    bool routeThroughEther
  ) external returns (uint256 totalTokensBought);

  function tradeTokenForTokenWithFeeOnTransferSpecifyingFee(
    ERC20Interface tokenProvided,
    address tokenReceived,
    uint256 tokenProvidedAmount,
    uint256 quotedTokenReceivedAmount,
    uint256 quotedTokenReceivedAmountAfterTransferFee,
    uint256 maximumFeeAmount, // WETH if routeThroughEther, else tokenReceived
    uint256 deadline,
    bool routeThroughEther,
    FeeType feeType
  ) external returns (uint256 totalTokensBought);

  function tradeTokenForTokenUsingReservesWithFeeOnTransferSpecifyingFee(
    ERC20Interface tokenProvidedFromReserves,
    address tokenReceived,
    uint256 tokenProvidedAmountFromReserves,
    uint256 quotedTokenReceivedAmount,
    uint256 maximumFeeAmount, // WETH if routeThroughEther, else tokenReceived
    uint256 deadline,
    bool routeThroughEther,
    FeeType feeType
  ) external returns (uint256 totalTokensBought);

  function tradeTokenForEtherWithFeeOnTransfer(
    ERC20Interface token,
    uint256 tokenAmount,
    uint256 quotedEtherAmount,
    uint256 deadline
  ) external returns (uint256 totalEtherBought);

  function tradeTokenForEtherWithFeeOnTransferSpecifyingFee(
    ERC20Interface token,
    uint256 tokenAmount,
    uint256 quotedEtherAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external returns (uint256 totalEtherBought);

  function tradeTokenForEtherUsingReservesWithFeeOnTransferSpecifyingFee(
    ERC20Interface token,
    uint256 tokenAmountFromReserves,
    uint256 quotedEtherAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external returns (uint256 totalEtherBought);

  function tradeTokenForEtherSpecifyingFee(
    ERC20Interface token,
    uint256 tokenAmount,
    uint256 quotedEtherAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external returns (uint256 totalEtherBought);

  function tradeEtherForTokenWithFeeOnTransfer(
    address token,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 deadline
  ) external payable returns (uint256 totalTokensBought);

  function tradeEtherForTokenSpecifyingFee(
    address token,
    uint256 quotedTokenAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external payable returns (uint256 totalTokensBought);

  function tradeEtherForTokenWithFeeOnTransferSpecifyingFee(
    address token,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external payable returns (uint256 totalTokensBought);

  function tradeEtherForTokenWithFeeOnTransferUsingEtherizer(
    address token,
    uint256 etherAmount,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 deadline
  ) external returns (uint256 totalTokensBought);

  function tradeTokenForTokenUsingReservesSpecifyingFee(
    ERC20Interface tokenProvidedFromReserves,
    address tokenReceived,
    uint256 tokenProvidedAmountFromReserves,
    uint256 quotedTokenReceivedAmount,
    uint256 maximumFeeAmount, // WETH if routeThroughEther, else tokenReceived
    uint256 deadline,
    bool routeThroughEther,
    FeeType feeType
  ) external returns (uint256 totalTokensBought);

  function tradeEtherForTokenUsingReservesWithFeeOnTransferSpecifyingFee(
    address token,
    uint256 etherAmountFromReserves,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external returns (uint256 totalTokensBought);

  function tradeTokenForEtherUsingReservesSpecifyingFee(
    ERC20Interface token,
    uint256 tokenAmountFromReserves,
    uint256 quotedEtherAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external returns (uint256 totalEtherBought);

  function tradeEtherForTokenUsingReservesSpecifyingFee(
    address token,
    uint256 etherAmountFromReserves,
    uint256 quotedTokenAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external returns (uint256 totalTokensBought);

  function finalizeEtherDeposit(
    address payable smartWallet,
    address initialUserSigningKey,
    uint256 etherAmount
  ) external;

  function finalizeTokenDeposit(
    address smartWallet,
    address initialUserSigningKey,
    ERC20Interface token,
    uint256 amount
  ) external;

  function refillGasReserve(uint256 etherAmount) external;

  function withdrawUSDCToPrimaryRecipient(uint256 usdcAmount) external;

  function withdrawDaiToPrimaryRecipient(uint256 usdcAmount) external;

  function withdrawEther(
    address payable recipient, uint256 etherAmount
  ) external;

  function withdraw(
    ERC20Interface token, address recipient, uint256 amount
  ) external returns (bool success);

  function callAny(
    address payable target, uint256 amount, bytes calldata data
  ) external returns (bool ok, bytes memory returnData);

  function setPrimaryUSDCRecipient(address recipient) external;

  function setPrimaryDaiRecipient(address recipient) external;

  function setRole(Role role, address account) external;

  function removeRole(Role role) external;

  function pause(Role role) external;

  function unpause(Role role) external;

  function isPaused(Role role) external view returns (bool paused);

  function isRole(Role role) external view returns (bool hasRole);

  function isDharmaSmartWallet(
    address smartWallet, address initialUserSigningKey
  ) external view returns (bool dharmaSmartWallet);

  function getDepositManager() external view returns (address depositManager);

  function getReserveTrader() external view returns (address reserveTrader);

  function getWithdrawalManager() external view returns (
    address withdrawalManager
  );

  function getActioner() external view returns (
    address actioner
  );

  function getPauser() external view returns (address pauser);

  function getGasReserveRefiller() external view returns (
    address gasReserveRefiller
  );

  function getPrimaryUSDCRecipient() external view returns (
    address recipient
  );

  function getPrimaryDaiRecipient() external view returns (
    address recipient
  );

  function getImplementation() external view returns (address implementation);

  function getInstance() external pure returns (address instance);

  function getVersion() external view returns (uint256 version);
}

interface ERC20Interface {
  function balanceOf(address) external view returns (uint256);
  function approve(address, uint256) external returns (bool);
  function allowance(address, address) external view returns (uint256);
  function transfer(address, uint256) external returns (bool);
  function transferFrom(address, address, uint256) external returns (bool);
}


interface DTokenInterface {
  function balanceOf(address) external view returns (uint256);
  function balanceOfUnderlying(address) external view returns (uint256);
  function transfer(address, uint256) external returns (bool);
  function approve(address, uint256) external returns (bool);
  function exchangeRateCurrent() external view returns (uint256);
}


interface UniswapV2Interface {
  function swapTokensForExactTokens(
    uint256 amountOut,
    uint256 amountInMax,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external returns (uint256[] memory amounts);

  function swapExactTokensForTokens(
    uint256 amountIn,
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external returns (uint256[] memory amounts);

  function swapExactTokensForETH(
    uint256 amountIn,
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external returns (uint256[] memory amounts);

  function swapTokensForExactETH(
    uint256 amountOut,
    uint256 amountInMax,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external returns (uint256[] memory amounts);

  function swapETHForExactTokens(
    uint256 amountOut,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external payable returns (uint256[] memory amounts);

  function swapExactETHForTokens(
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external payable returns (uint256[] memory amounts);

  function swapExactTokensForTokensSupportingFeeOnTransferTokens(
    uint256 amountIn,
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external;

  function swapExactTokensForETHSupportingFeeOnTransferTokens(
    uint256 amountIn,
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external;

  function swapExactETHForTokensSupportingFeeOnTransferTokens(
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external payable;
}

library SafeMath {
  function max(uint256 a, uint256 b) internal pure returns (uint256) {
    return a >= b ? a : b;
  }

  function min(uint256 a, uint256 b) internal pure returns (uint256) {
    return a < b ? a : b;
  }
}


/**
 * @title DharmaTradeReserveV19Implementation
 * @author 0age + cf ;)
 * @notice This contract manages Dharma's reserves. It designates a collection of
 * "roles" - these are dedicated accounts that can be modified by the owner, and
 * that can trigger specific functionality on the reserve. These roles are:
 *  - depositManager (0): initiates Eth / token transfers to smart wallets
 *  - adjuster (1): mints / redeems Dai, and swaps USDC, for dDai
 *  - withdrawalManager (2): initiates token transfers to recipients set by owner
 *  - reserveTrader (3): initiates trades using funds held in reserve
 *  - pauser (4): pauses any role (only the owner is then able to unpause it)
 *  - gasReserveRefiller (5): transfers Ether to the Dharma Gas Reserve
 *
 * When finalizing deposits, the deposit manager must adhere to two constraints:
 *  - it must provide "proof" that the recipient is a smart wallet by including
 *    the initial user signing key used to derive the smart wallet address
 *
 * Note that "proofs" can be validated via `isSmartWallet`.
 */
contract DharmaTradeReserveV19Implementation is DharmaTradeReserveV19Interface, TwoStepOwnable {
  using SafeMath for uint256;

  // Maintain a role status mapping with assigned accounts and paused states.
  mapping(uint256 => RoleStatus) private _roles;

  // Maintain a "primary recipient" the withdrawal manager can transfer Dai to.
  address private _primaryDaiRecipient;

  // Maintain a "primary recipient" the withdrawal manager can transfer USDC to.
  address private _primaryUSDCRecipient;

  // Maintain a maximum allowable transfer size (in Dai) for the deposit manager.
  uint256 private _daiLimit; // unused

  // Maintain a maximum allowable transfer size (in Ether) for the deposit manager.
  uint256 private _etherLimit; // unused

  bool private _originatesFromReserveTrader; // unused, don't change storage layout

  bytes4 internal _selfCallContext;

  uint256 private constant _VERSION = 19;

  // This contract interacts with USDC, Dai, and Dharma Dai.
  ERC20Interface internal constant _USDC = ERC20Interface(
    0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 // mainnet
  );

  ERC20Interface internal constant _DAI = ERC20Interface(
    0x6B175474E89094C44Da98b954EedeAC495271d0F // mainnet
  );

  ERC20Interface internal constant _ETHERIZER = ERC20Interface(
    0x723B51b72Ae89A3d0c2a2760f0458307a1Baa191
  );

  DTokenInterface internal constant _DDAI = DTokenInterface(
    0x00000000001876eB1444c986fD502e618c587430
  );

  UniswapV2Interface internal constant _UNISWAP_ROUTER = UniswapV2Interface(
    0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
  );

  address internal constant _WETH = address(
    0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
  );

  address internal constant _GAS_RESERVE = address(
    0x55F2039347564d206Ccc6e6cE202853Fed386dBf
  );

  // The "Create2 Header" is used to compute smart wallet deployment addresses.
  bytes21 internal constant _CREATE2_HEADER = bytes21(
    0xfffc00c80b0000007f73004edb00094cad80626d8d // control character + factory
  );

  // The "Wallet creation code" header & footer are also used to derive wallets.
  bytes internal constant _WALLET_CREATION_CODE_HEADER = hex"60806040526040516104423803806104428339818101604052602081101561002657600080fd5b810190808051604051939291908464010000000082111561004657600080fd5b90830190602082018581111561005b57600080fd5b825164010000000081118282018810171561007557600080fd5b82525081516020918201929091019080838360005b838110156100a257818101518382015260200161008a565b50505050905090810190601f1680156100cf5780820380516001836020036101000a031916815260200191505b5060405250505060006100e661019e60201b60201c565b6001600160a01b0316826040518082805190602001908083835b6020831061011f5780518252601f199092019160209182019101610100565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461017f576040519150601f19603f3d011682016040523d82523d6000602084013e610184565b606091505b5050905080610197573d6000803e3d6000fd5b50506102be565b60405160009081906060906e26750c571ce882b17016557279adaa9083818181855afa9150503d80600081146101f0576040519150601f19603f3d011682016040523d82523d6000602084013e6101f5565b606091505b509150915081819061029f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561026457818101518382015260200161024c565b50505050905090810190601f1680156102915780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b508080602001905160208110156102b557600080fd5b50519392505050565b610175806102cd6000396000f3fe608060405261001461000f610016565b61011c565b005b60405160009081906060906e26750c571ce882b17016557279adaa9083818181855afa9150503d8060008114610068576040519150601f19603f3d011682016040523d82523d6000602084013e61006d565b606091505b50915091508181906100fd5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156100c25781810151838201526020016100aa565b50505050905090810190601f1680156100ef5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5080806020019051602081101561011357600080fd5b50519392505050565b3660008037600080366000845af43d6000803e80801561013b573d6000f35b3d6000fdfea265627a7a7231582020202020202055706772616465426561636f6e50726f7879563120202020202064736f6c634300050b003200000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024c4d66de8000000000000000000000000";
  bytes28 internal constant _WALLET_CREATION_CODE_FOOTER = bytes28(
    0x00000000000000000000000000000000000000000000000000000000
  );

  // Flag to trigger trade for USDC and retain full trade amount
  address internal constant _TRADE_FOR_USDC_AND_RETAIN_FLAG = address(type(uint160).max);

  // The "action registry" keeps track of function-selectors and approved spenders
  // allowed in the generic call execution flow.
  IActionRegistry public immutable _ACTION_REGISTRY;

  address private constant V17 = address(
    0xf1209998BD17eAe301a97e3cF7ec17dF580E7964
  );

  // Include a payable fallback so that the contract can receive Ether payments.
  receive() external payable {
    emit EtherReceived(msg.sender, msg.value);
  }

  constructor(address actionRegistryAddress) public {
    _ACTION_REGISTRY = IActionRegistry(actionRegistryAddress);
  }

  /**
  * @notice Simulate a series of generic calls to other contracts.
  * Calls will be rolled back (and calls will only be
  * simulated up until a failing call is encountered).
  * @param calls Call[] A struct containing the target, value, and calldata to
  * provide when making each call.
  * return An array of structs signifying the status of each call, as well as
  * any data returned from that call. Calls that are not executed will return
  * empty data.
  */
  function simulate(
    ITypes.Call[] calldata calls
  ) external override returns (bool[] memory ok, bytes[] memory returnData, bool validCalls) {
    // Ensure all calls are valid
    validCalls = _ACTION_REGISTRY.isValidAction(calls);

    // Specify length of returned values in order to work with them in memory.
    ok = new bool[](calls.length);
    returnData = new bytes[](calls.length);

    // Make the atomic self-call - if any call fails, calls that preceded it
    // will be rolled back and calls that follow it will not be made.
    (, bytes memory rawCallResults) = address(this).call(
      abi.encodeWithSelector(
        this._simulate.selector, calls
      )
    );

    // Parse data returned from self-call into each call result and store / log.
    ITypes.CallReturn[] memory callResults = abi.decode(rawCallResults, (ITypes.CallReturn[]));
    for (uint256 i = 0; i < callResults.length; i++) {
      // Set the status and the return data / revert reason from the call.
      ok[i] = callResults[i].ok;
      returnData[i] = callResults[i].returnData;

      if (!callResults[i].ok) {
        // exit early - any calls after the first failed call will not execute.
        break;
      }
    }
  }

  /**
  * @notice Protected function that can only be called from
  * `simulateActionWithAtomicBatchCalls` on this contract. It will attempt to
  * perform each specified call, populating the array of results as it goes,
  * unless a failure occurs, at which point it will revert and "return" the
  * array of results as revert data. Regardless, it will roll back all calls at
  * the end of execution — in other words, this call always reverts.
  * @param calls Call[] A struct containing the target, value, and calldata to
  * provide when making each call.
  * return An array of structs signifying the status of each call, as well as
  * any data returned from that call. Calls that are not executed will return
  * empty data. If any of the calls fail, the array will be returned as revert
  * data.
  */
  function _simulate(
    ITypes.Call[] memory calls
  ) public returns (ITypes.CallReturn[] memory callResults) {

    callResults = new ITypes.CallReturn[](calls.length);

    for (uint256 i = 0; i < calls.length; i++) {
      // Perform low-level call and set return values using result.
      (bool ok, bytes memory returnData) = calls[i].to.call{value:
        uint256(calls[i].value)
      }(calls[i].data);
      callResults[i] = ITypes.CallReturn({ok: ok, returnData: returnData});
      if (!ok) {
        // Exit early - any calls after the first failed call will not execute.
        break;
      }
    }
    // Wrap in length encoding and revert (provide bytes instead of a string).
    bytes memory callResultsBytes = abi.encode(callResults);
    assembly { revert(add(32, callResultsBytes), mload(callResultsBytes)) }
  }

  function execute(
    ITypes.Call[] memory calls
  ) public onlyOwnerOr(Role.ACTIONER) override returns (bool[] memory ok, bytes[] memory returnData) {
    // Ensure all calls are valid
    bool validCalls = _ACTION_REGISTRY.isValidAction(calls);

    require(validCalls, "Invalid call detected!");

    // Note: from this point on, there are no reverts (apart from out-of-gas or
    // call-depth-exceeded) originating from this contract. However, one of the
    // calls may revert, in which case the function will return `false`, along
    // with the revert reason encoded as bytes, and fire a CallFailure event.

    // Specify length of returned values in order to work with them in memory.
    ok = new bool[](calls.length);
    returnData = new bytes[](calls.length);

    // Set self-call context to call _execute.
    _selfCallContext = this.execute.selector;

    // Make the atomic self-call - if any call fails, calls that preceded it
    // will be rolled back and calls that follow it will not be made.
    (bool externalOk, bytes memory rawCallResults) = address(this).call(
      abi.encodeWithSelector(
        this._execute.selector, calls
      )
    );

    // Ensure that self-call context has been cleared.
    if (!externalOk) {
      delete _selfCallContext;
    }

    // Parse data returned from self-call into each call result and store / log.
    ITypes.CallReturn[] memory callResults = abi.decode(rawCallResults, (ITypes.CallReturn[]));
    for (uint256 i = 0; i < callResults.length; i++) {
      ITypes.Call memory currentCall = calls[i];

      // Set the status and the return data / revert reason from the call.
      ok[i] = callResults[i].ok;
      returnData[i] = callResults[i].returnData;

      // Emit CallSuccess or CallFailure event based on the outcome of the call.
      if (callResults[i].ok) {
        // Note: while the call succeeded, the action may still have "failed".
        emit CallSuccess(
          !externalOk, // If another call failed this will have been rolled back
          currentCall.to,
          uint256(currentCall.value),
          currentCall.data,
          callResults[i].returnData
        );
      } else {
        // Note: while the call failed, the nonce will still be incremented,
        // which will invalidate all supplied signatures.
        emit CallFailure(
          currentCall.to,
          uint256(currentCall.value),
          currentCall.data,
          _decodeRevertReason(callResults[i].returnData)
        );

        // exit early - any calls after the first failed call will not execute.
        break;
      }
    }
  }

  function _execute(
    ITypes.Call[] memory calls
  ) public returns (ITypes.CallReturn[] memory callResults) {
    // Ensure caller is this contract and self-call context is correctly set.
    _enforceSelfCallFrom(this.execute.selector);

    bool rollBack = false;
    callResults = new ITypes.CallReturn[](calls.length);

    for (uint256 i = 0; i < calls.length; i++) {
      // Perform low-level call and set return values using result.
      (bool ok, bytes memory returnData) = calls[i].to.call{value:
        uint256(calls[i].value)
      }(calls[i].data);
      callResults[i] = ITypes.CallReturn({ok: ok, returnData: returnData});
      if (!ok) {
        // Exit early - any calls after the first failed call will not execute.
        rollBack = true;
        break;
      }
    }

    if (rollBack) {
      // Wrap in length encoding and revert (provide bytes instead of a string).
      bytes memory callResultsBytes = abi.encode(callResults);
      assembly { revert(add(32, callResultsBytes), mload(callResultsBytes)) }
    }
  }

  /**
   * @notice Internal function to ensure that protected functions can only be
   * called from this contract and that they have the appropriate context set.
   * The self-call context is then cleared. It is used as an additional guard
   * against reentrancy, especially once generic actions are supported by the
   * smart wallet in future versions.
   * @param selfCallContext bytes4 The expected self-call context, equal to the
   * function selector of the approved calling function.
   */
  function _enforceSelfCallFrom(bytes4 selfCallContext) internal {
    // Ensure caller is this contract and self-call context is correctly set.
    require(
      msg.sender == address(this) && _selfCallContext == selfCallContext,
      "External accounts or unapproved internal functions cannot call this."
    );

    // Clear the self-call context.
    delete _selfCallContext;
  }


  function _decodeRevertReason(
    bytes memory revertData
  ) internal pure returns (string memory revertReason) {
    // Solidity prefixes revert reason with 0x08c379a0 -> Error(string) selector
    if (
      revertData.length > 68 && // prefix (4) + position (32) + length (32)
      revertData[0] == bytes1(0x08) &&
      revertData[1] == bytes1(0xc3) &&
      revertData[2] == bytes1(0x79) &&
      revertData[3] == bytes1(0xa0)
    ) {
      // Get the revert reason without the prefix from the revert data.
      bytes memory revertReasonBytes = new bytes(revertData.length - 4);
      for (uint256 i = 4; i < revertData.length; i++) {
        revertReasonBytes[i - 4] = revertData[i];
      }

      // Decode the resultant revert reason as a string.
      revertReason = abi.decode(revertReasonBytes, (string));
    } else {
      // Simply return the default, with no revert reason.
      revertReason = "(no revert reason)";
    }
  }

  function tradeTokenForTokenSpecifyingFee(
    ERC20Interface tokenProvided,
    address tokenReceived,
    uint256 tokenProvidedAmount,
    uint256 quotedTokenReceivedAmount,
    uint256 maximumFeeAmount, // WETH if routeThroughEther, else tokenReceived
    uint256 deadline,
    bool routeThroughEther,
    FeeType feeType
  ) external override returns (uint256 totalTokensBought) {
    _ensureNoEtherFeeTypeWhenNotRouted(routeThroughEther, feeType);

    // Transfer the token from the caller and revert on failure.
    _transferInToken(tokenProvided, msg.sender, tokenProvidedAmount);

    totalTokensBought = _tradeTokenForToken(
      msg.sender,
      tokenProvided,
      tokenReceived,
      tokenProvidedAmount,
      quotedTokenReceivedAmount,
      maximumFeeAmount,
      deadline,
      routeThroughEther,
      feeType
    );
  }

  function tradeTokenForTokenWithFeeOnTransfer(
    ERC20Interface tokenProvided,
    address tokenReceived,
    uint256 tokenProvidedAmount,
    uint256 quotedTokenReceivedAmount,
    uint256 quotedTokenReceivedAmountAfterTransferFee,
    uint256 deadline,
    bool routeThroughEther
  ) external override returns (uint256 totalTokensBought) {
    _delegate(V17);
  }

  function tradeTokenForTokenWithFeeOnTransferSpecifyingFee(
    ERC20Interface tokenProvided,
    address tokenReceived,
    uint256 tokenProvidedAmount,
    uint256 quotedTokenReceivedAmount,
    uint256 quotedTokenReceivedAmountAfterTransferFee,
    uint256 maximumFeeAmount, // WETH if routeThroughEther, else tokenReceived
    uint256 deadline,
    bool routeThroughEther,
    FeeType feeType
  ) external override returns (uint256 totalTokensBought) {
    _delegate(V17);
  }

  function tradeTokenForEtherSpecifyingFee(
    ERC20Interface token,
    uint256 tokenAmount,
    uint256 quotedEtherAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external override returns (uint256 totalEtherBought) {
    // Transfer the tokens from the caller and revert on failure.
    _transferInToken(token, msg.sender, tokenAmount);

    uint256 receivedEtherAmount;
    uint256 retainedAmount;
    (totalEtherBought, receivedEtherAmount, retainedAmount) = _tradeTokenForEther(
      token,
      tokenAmount,
      tokenAmount,
      quotedEtherAmount,
      deadline,
      feeType,
      maximumFeeAmount
    );

    _fireTradeEvent(
      false,
      false,
      feeType != FeeType.SUPPLIED_ASSET,
      address(token),
      tokenAmount,
      receivedEtherAmount,
      retainedAmount
    );

    // Transfer the Ether amount to receive to the caller.
    _transferEther(msg.sender, receivedEtherAmount);
  }

  function tradeTokenForEtherWithFeeOnTransfer(
    ERC20Interface token,
    uint256 tokenAmount,
    uint256 quotedEtherAmount,
    uint256 deadline
  ) external override returns (uint256 totalEtherBought) {
    _delegate(V17);
  }

  function tradeTokenForEtherWithFeeOnTransferSpecifyingFee(
    ERC20Interface token,
    uint256 tokenAmount,
    uint256 quotedEtherAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external override returns (uint256 totalEtherBought) {
    _delegate(V17);
  }

  function tradeEtherForTokenSpecifyingFee(
    address token,
    uint256 quotedTokenAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external override payable returns (uint256 totalTokensBought) {
    // Trade Ether for the specified token.
    uint256 receivedTokenAmount;
    uint256 retainedAmount;
    (totalTokensBought, receivedTokenAmount, retainedAmount) = _tradeExactEtherForToken(
      token,
      msg.value,
      quotedTokenAmount,
      deadline,
      false,
      feeType,
      maximumFeeAmount
    );

    _fireTradeEvent(
      false,
      true,
      feeType != FeeType.RECEIVED_ASSET,
      token,
      msg.value,
      receivedTokenAmount,
      retainedAmount
    );
  }

  function tradeEtherForTokenWithFeeOnTransfer(
    address token,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 deadline
  ) external override payable returns (uint256 totalTokensBought) {
    _delegate(V17);
  }

  function tradeEtherForTokenWithFeeOnTransferSpecifyingFee(
    address token,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external override payable returns (uint256 totalTokensBought) {
    _delegate(V17);
  }

  function tradeEtherForTokenUsingReservesWithFeeOnTransferSpecifyingFee(
    address token,
    uint256 etherAmountFromReserves,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external override onlyOwnerOr(Role.RESERVE_TRADER) returns (uint256 totalTokensBought) {
    totalTokensBought = _tradeEtherForTokenWithFeeOnTransfer(
      token,
      etherAmountFromReserves,
      quotedTokenAmount,
      quotedTokenAmountAfterTransferFee,
      maximumFeeAmount,
      deadline,
      true,
      feeType
    );
  }

  function tradeEtherForTokenWithFeeOnTransferUsingEtherizer(
    address token,
    uint256 etherAmount,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 deadline
  ) external override returns (uint256 totalTokensBought) {
    _delegate(V17);
  }

  function tradeTokenForTokenUsingReservesSpecifyingFee(
    ERC20Interface tokenProvidedFromReserves,
    address tokenReceived,
    uint256 tokenProvidedAmountFromReserves,
    uint256 quotedTokenReceivedAmount,
    uint256 maximumFeeAmount, // WETH if routeThroughEther, else tokenReceived
    uint256 deadline,
    bool routeThroughEther,
    FeeType feeType
  ) external onlyOwnerOr(Role.RESERVE_TRADER) override returns (uint256 totalTokensBought) {
    _ensureNoEtherFeeTypeWhenNotRouted(routeThroughEther, feeType);

    totalTokensBought = _tradeTokenForToken(
      address(this),
      tokenProvidedFromReserves,
      tokenReceived,
      tokenProvidedAmountFromReserves,
      quotedTokenReceivedAmount,
      maximumFeeAmount,
      deadline,
      routeThroughEther,
      feeType
    );
  }

  function tradeTokenForTokenUsingReservesWithFeeOnTransferSpecifyingFee(
    ERC20Interface tokenProvidedFromReserves,
    address tokenReceived,
    uint256 tokenProvidedAmountFromReserves,
    uint256 quotedTokenReceivedAmount,
    uint256 maximumFeeAmount, // WETH if routeThroughEther, else tokenReceived
    uint256 deadline,
    bool routeThroughEther,
    FeeType feeType
  ) external onlyOwnerOr(Role.RESERVE_TRADER) override returns (uint256 totalTokensBought) {
    _ensureNoEtherFee(feeType);

    totalTokensBought = _tradeTokenForTokenWithFeeOnTransfer(
      TradeTokenForTokenWithFeeOnTransferArgs({
      account: address(this),
      tokenProvided: tokenProvidedFromReserves,
      tokenReceivedOrUSDCFlag: tokenReceived,
      tokenProvidedAmount: tokenProvidedAmountFromReserves,
      tokenProvidedAmountAfterTransferFee: tokenProvidedAmountFromReserves,
      quotedTokenReceivedAmount: quotedTokenReceivedAmount,
      quotedTokenReceivedAmountAfterTransferFee: tokenProvidedAmountFromReserves,
      maximumFeeAmount: maximumFeeAmount,
      deadline: deadline,
      routeThroughEther: routeThroughEther,
      feeType: feeType
      })
    );
  }

  function tradeTokenForEtherUsingReservesSpecifyingFee(
    ERC20Interface token,
    uint256 tokenAmountFromReserves,
    uint256 quotedEtherAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external onlyOwnerOr(Role.RESERVE_TRADER) override returns (uint256 totalEtherBought) {
    uint256 receivedEtherAmount;
    uint256 retainedAmount;
    (totalEtherBought, receivedEtherAmount, retainedAmount) = _tradeTokenForEther(
      token,
      tokenAmountFromReserves,
      tokenAmountFromReserves,
      quotedEtherAmount,
      deadline,
      feeType,
      maximumFeeAmount
    );

    _fireTradeEvent(
      true,
      false,
      feeType != FeeType.SUPPLIED_ASSET,
      address(token),
      tokenAmountFromReserves,
      receivedEtherAmount,
      retainedAmount
    );
  }

  function tradeTokenForEtherUsingReservesWithFeeOnTransferSpecifyingFee(
    ERC20Interface token,
    uint256 tokenAmountFromReserves,
    uint256 quotedEtherAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external onlyOwnerOr(Role.RESERVE_TRADER) override returns (uint256 totalEtherBought) {
    uint256 receivedEtherAmount;
    uint256 retainedAmount;
    (totalEtherBought, receivedEtherAmount, retainedAmount) = _tradeTokenForEther(
      token,
      tokenAmountFromReserves + 1,
      tokenAmountFromReserves,
      quotedEtherAmount,
      deadline,
      feeType,
      maximumFeeAmount
    );

    _fireTradeEvent(
      true,
      false,
      feeType != FeeType.SUPPLIED_ASSET,
      address(token),
      tokenAmountFromReserves,
      receivedEtherAmount,
      retainedAmount
    );
  }

  function tradeEtherForTokenUsingReservesSpecifyingFee(
    address token,
    uint256 etherAmountFromReserves,
    uint256 quotedTokenAmount,
    uint256 maximumFeeAmount,
    uint256 deadline,
    FeeType feeType
  ) external onlyOwnerOr(Role.RESERVE_TRADER) override returns (
    uint256 totalTokensBought
  ) {
    // Trade Ether for the specified token.
    uint256 receivedTokenAmount;
    uint256 retainedAmount;
    (totalTokensBought, receivedTokenAmount, retainedAmount) = _tradeExactEtherForToken(
      token,
      etherAmountFromReserves,
      quotedTokenAmount,
      deadline,
      true,
      feeType,
      maximumFeeAmount
    );

    _fireTradeEvent(
      true,
      true,
      feeType != FeeType.RECEIVED_ASSET,
      token,
      etherAmountFromReserves,
      receivedTokenAmount,
      maximumFeeAmount
    );
  }

  /**
   * @notice Transfer `amount` of token `token` to `smartWallet`, providing the
   * initial user signing key `initialUserSigningKey` as proof that the
   * specified smart wallet is indeed a Dharma Smart Wallet - this assumes that
   * the address is derived and deployed using the Dharma Smart Wallet Factory
   * V1. Only the owner or the designated deposit manager role may call this
   * function.
   * @param smartWallet address The smart wallet to transfer tokens to.
   * @param initialUserSigningKey address The initial user signing key supplied
   * when deriving the smart wallet address - this could be an EOA or a Dharma
   * key ring address.
   * @param token ERC20Interface The token to transfer.
   * @param amount uint256 The amount of tokens to transfer.
   */
  function finalizeTokenDeposit(
    address smartWallet,
    address initialUserSigningKey,
    ERC20Interface token,
    uint256 amount
  ) external onlyOwnerOr(Role.DEPOSIT_MANAGER) override {
    // Ensure that the recipient is indeed a smart wallet.
    _ensureSmartWallet(smartWallet, initialUserSigningKey);

    // Transfer the token to the specified smart wallet.
    _transferToken(token, smartWallet, amount);
  }

  /**
   * @notice Transfer `etherAmount` Ether to `smartWallet`, providing the
   * initial user signing key `initialUserSigningKey` as proof that the
   * specified smart wallet is indeed a Dharma Smart Wallet - this assumes that
   * the address is derived and deployed using the Dharma Smart Wallet Factory
   * V1. In addition, the Ether amount must be less than the configured limit
   * amount. Only the owner or the designated deposit manager role may call this
   * function.
   * @param smartWallet address The smart wallet to transfer Ether to.
   * @param initialUserSigningKey address The initial user signing key supplied
   * when deriving the smart wallet address - this could be an EOA or a Dharma
   * key ring address.
   * @param etherAmount uint256 The amount of Ether to transfer - this amount
   * must be less than the current limit.
   */
  function finalizeEtherDeposit(
    address payable smartWallet,
    address initialUserSigningKey,
    uint256 etherAmount
  ) external onlyOwnerOr(Role.DEPOSIT_MANAGER) override {
    // Ensure that the recipient is indeed a smart wallet.
    _ensureSmartWallet(smartWallet, initialUserSigningKey);

    // Transfer the Ether to the specified smart wallet.
    _transferEther(smartWallet, etherAmount);
  }

  function refillGasReserve(
    uint256 etherAmount
  ) external onlyOwnerOr(Role.GAS_RESERVE_REFILLER) override {
    // Transfer the Ether to the gas reserve.
    _transferEther(_GAS_RESERVE, etherAmount);

    emit GasReserveRefilled(etherAmount);
  }

  /**
   * @notice Transfer `usdcAmount` USDC for to the current primary recipient set
   * by the owner. Only the owner or the designated withdrawal manager role may
   * call this function.
   * @param usdcAmount uint256 The amount of USDC to transfer to the primary
   * recipient.
   */
  function withdrawUSDCToPrimaryRecipient(
    uint256 usdcAmount
  ) external onlyOwnerOr(Role.WITHDRAWAL_MANAGER) override {
    // Get the current primary recipient.
    address primaryRecipient = _primaryUSDCRecipient;
    require(
      primaryRecipient != address(0), "No USDC primary recipient currently set."
    );

    // Transfer the supplied USDC amount to the primary recipient.
    _transferToken(_USDC, primaryRecipient, usdcAmount);
  }

  /**
   * @notice Transfer `daiAmount` Dai for to the current primary recipient set
   * by the owner. Only the owner or the designated withdrawal manager role may
   * call this function.
   * @param daiAmount uint256 The amount of Dai to transfer to the primary
   * recipient.
   */
  function withdrawDaiToPrimaryRecipient(
    uint256 daiAmount
  ) external onlyOwnerOr(Role.WITHDRAWAL_MANAGER) override {
    // Get the current primary recipient.
    address primaryRecipient = _primaryDaiRecipient;
    require(
      primaryRecipient != address(0), "No Dai primary recipient currently set."
    );

    // Transfer the supplied Dai amount to the primary recipient.
    _transferToken(_DAI, primaryRecipient, daiAmount);
  }

  /**
   * @notice Transfer `etherAmount` Ether to `recipient`. Only the owner may
   * call this function.
   * @param recipient address The account to transfer Ether to.
   * @param etherAmount uint256 The amount of Ether to transfer.
   */
  function withdrawEther(
    address payable recipient, uint256 etherAmount
  ) external override onlyOwner {
    // Transfer the Ether to the specified recipient.
    _transferEther(recipient, etherAmount);
  }

  /**
   * @notice Transfer `amount` of ERC20 token `token` to `recipient`. Only the
   * owner may call this function.
   * @param token ERC20Interface The ERC20 token to transfer.
   * @param recipient address The account to transfer the tokens to.
   * @param amount uint256 The amount of tokens to transfer.
   * @return success - a boolean to indicate if the transfer was successful - note that
   * unsuccessful ERC20 transfers will usually revert.
   */
  function withdraw(
    ERC20Interface token, address recipient, uint256 amount
  ) external onlyOwner override returns (bool success) {
    // Transfer the token to the specified recipient.
    success = token.transfer(recipient, amount);
  }

  /**
   * @notice Call account `target`, supplying value `amount` and data `data`.
   * Only the owner may call this function.
   * @param target address The account to call.
   * @param amount uint256 The amount of ether to include as an endowment.
   * @param data bytes The data to include along with the call.
   * @return ok and returnData - a boolean to indicate if the call was successful, as well as the
   * returned data or revert reason.
   */
  function callAny(
    address payable target, uint256 amount, bytes calldata data
  ) external onlyOwner override returns (bool ok, bytes memory returnData) {
    // Call the specified target and supply the specified data.
    (ok, returnData) = target.call{value:amount}(data);
  }

  /**
   * @notice Set `recipient` as the new primary recipient for USDC withdrawals.
   * Only the owner may call this function.
   * @param recipient address The new primary recipient.
   */
  function setPrimaryUSDCRecipient(address recipient) external override onlyOwner {
    // Set the new primary recipient.
    _primaryUSDCRecipient = recipient;
  }

  /**
   * @notice Set `recipient` as the new primary recipient for Dai withdrawals.
   * Only the owner may call this function.
   * @param recipient address The new primary recipient.
   */
  function setPrimaryDaiRecipient(address recipient) external override onlyOwner {
    // Set the new primary recipient.
    _primaryDaiRecipient = recipient;
  }

  /**
   * @notice Pause a currently unpaused role and emit a `RolePaused` event. Only
   * the owner or the designated pauser may call this function. Also, bear in
   * mind that only the owner may unpause a role once paused.
   * @param role The role to pause.
   */
  function pause(Role role) external override onlyOwnerOr(Role.PAUSER) {
    RoleStatus storage storedRoleStatus = _roles[uint256(role)];
    require(!storedRoleStatus.paused, "Role in question is already paused.");
    storedRoleStatus.paused = true;
    emit RolePaused(role);
  }

  /**
   * @notice Unpause a currently paused role and emit a `RoleUnpaused` event.
   * Only the owner may call this function.
   * @param role The role to pause.
   */
  function unpause(Role role) external override onlyOwner {
    RoleStatus storage storedRoleStatus = _roles[uint256(role)];
    require(storedRoleStatus.paused, "Role in question is already unpaused.");
    storedRoleStatus.paused = false;
    emit RoleUnpaused(role);
  }

  /**
   * @notice Set a new account on a given role and emit a `RoleModified` event
   * if the role holder has changed. Only the owner may call this function.
   * @param role The role that the account will be set for.
   * @param account The account to set as the designated role bearer.
   */
  function setRole(Role role, address account) external override onlyOwner {
    require(account != address(0), "Must supply an account.");
    _setRole(role, account);
  }

  /**
   * @notice Remove any current role bearer for a given role and emit a
   * `RoleModified` event if a role holder was previously set. Only the owner
   * may call this function.
   * @param role The role that the account will be removed from.
   */
  function removeRole(Role role) external override onlyOwner {
    _setRole(role, address(0));
  }

  /**
   * @notice External view function to check whether or not the functionality
   * associated with a given role is currently paused or not. The owner or the
   * pauser may pause any given role (including the pauser itself), but only the
   * owner may unpause functionality. Additionally, the owner may call paused
   * functions directly.
   * @param role The role to check the pause status on.
   * @return paused - a boolean to indicate if the functionality associated with the role
   * in question is currently paused.
   */
  function isPaused(Role role) external view override returns (bool paused) {
    paused = _isPaused(role);
  }

  /**
   * @notice External view function to check whether the caller is the current
   * role holder.
   * @param role The role to check for.
   * @return hasRole - a boolean indicating if the caller has the specified role.
   */
  function isRole(Role role) external view override returns (bool hasRole) {
    hasRole = _isRole(role);
  }

  /**
   * @notice External view function to check whether a "proof" that a given
   * smart wallet is actually a Dharma Smart Wallet, based on the initial user
   * signing key, is valid or not. This proof only works when the Dharma Smart
   * Wallet in question is derived using V1 of the Dharma Smart Wallet Factory.
   * @param smartWallet address The smart wallet to check.
   * @param initialUserSigningKey address The initial user signing key supplied
   * when deriving the smart wallet address - this could be an EOA or a Dharma
   * key ring address.
   * @return dharmaSmartWallet - a boolean indicating if the specified smart wallet account is
   * indeed a smart wallet based on the specified initial user signing key.
   */
  function isDharmaSmartWallet(
    address smartWallet, address initialUserSigningKey
  ) external pure override returns (bool dharmaSmartWallet) {
    dharmaSmartWallet = _isSmartWallet(smartWallet, initialUserSigningKey);
  }

  /**
   * @notice External view function to check the account currently holding the
   * deposit manager role. The deposit manager can process standard deposit
   * finalization via `finalizeDaiDeposit` and `finalizeDharmaDaiDeposit`, but
   * must prove that the recipient is a Dharma Smart Wallet and adhere to the
   * current deposit size limit.
   * @return depositManager - the address of the current deposit manager, or the null address if
   * none is set.
   */
  function getDepositManager() external view override returns (address depositManager) {
    depositManager = _roles[uint256(Role.DEPOSIT_MANAGER)].account;
  }

  /**
   * @notice External view function to check the account currently holding the
   * reserve trader role. The reserve trader can trigger trades that utilize
   * reserves in addition to supplied funds, if any.
   * @return reserveTrader - the address of the current reserve trader, or the null address if
   * none is set.
   */
  function getReserveTrader() external view override returns (address reserveTrader) {
    reserveTrader = _roles[uint256(Role.RESERVE_TRADER)].account;
  }

  /**
   * @notice External view function to check the account currently holding the
   * withdrawal manager role. The withdrawal manager can transfer USDC to the
   * "primary recipient" address set by the owner.
   * @return withdrawalManager - the address of the current withdrawal manager, or the null address
   * if none is set.
   */
  function getWithdrawalManager() external view override returns (
    address withdrawalManager
  ) {
    withdrawalManager = _roles[uint256(Role.WITHDRAWAL_MANAGER)].account;
  }


  /**
   * @notice External view function to check the account currently holding the
   * actioner role. The actioner can submit a generic calls transaction through `execute`
   * @return actioner - the address of the current actioner, or the null address
   * if none is set.
   */
  function getActioner() external view override returns (
    address actioner
    ) {
    actioner = _roles[uint256(Role.ACTIONER)].account;
  }


  /**
   * @notice External view function to check the account currently holding the
   * pauser role. The pauser can pause any role from taking its standard action,
   * though the owner will still be able to call the associated function in the
   * interim and is the only entity able to unpause the given role once paused.
   * @return pauser - the address of the current pauser, or the null address if none is
   * set.
   */
  function getPauser() external view override returns (address pauser) {
    pauser = _roles[uint256(Role.PAUSER)].account;
  }

  function getGasReserveRefiller() external view override returns (
    address gasReserveRefiller
  ) {
    gasReserveRefiller = _roles[uint256(Role.GAS_RESERVE_REFILLER)].account;
  }

  /**
   * @notice External view function to check the address of the current
   * primary recipient for USDC.
   * @return recipient - the primary recipient for USDC.
   */
  function getPrimaryUSDCRecipient() external view override returns (
    address recipient
  ) {
    recipient = _primaryUSDCRecipient;
  }

  /**
   * @notice External view function to check the address of the current
   * primary recipient for Dai.
   * @return recipient - the primary recipient for Dai.
   */
  function getPrimaryDaiRecipient() external view override returns (
    address recipient
  ) {
    recipient = _primaryDaiRecipient;
  }

  /**
   * @notice External view function to check the current implementation
   * of this contract (i.e. the "logic" for the contract).
   * @return implementation - the current implementation for this contract.
   */
  function getImplementation() external view override returns (
    address implementation
  ) {
    (bool ok, bytes memory returnData) = address(
      0x2Cf7C0333D9b7F94BbF55B9701227E359F92fD31
    ).staticcall("");
    require(ok && returnData.length == 32, "Invalid implementation.");
    implementation = abi.decode(returnData, (address));
  }

  /**
   * @notice External pure function to get the address of the actual
   * contract instance (i.e. the "storage" foor this contract).
   * @return instance - the address of this contract instance.
   */
  function getInstance() external pure override returns (address instance) {
    instance = address(0x0eFb068354c10c070ddD64a0E8EaF8f054DF7E26);
  }

  function getVersion() external pure override returns (uint256 version) {
    version = _VERSION;
  }

  function _grantUniswapRouterApprovalIfNecessary(
    ERC20Interface token, uint256 amount
  ) internal {
    if (token.allowance(address(this), address(_UNISWAP_ROUTER)) < amount) {
      // Try removing approval first as a workaround for unusual tokens.
      (bool success, bytes memory data) = address(token).call(
        abi.encodeWithSelector(
          token.approve.selector, address(_UNISWAP_ROUTER), uint256(0)
        )
      );

      // Grant transfer approval to Uniswap router on behalf of this contract.
      (success, data) = address(token).call(
        abi.encodeWithSelector(
          token.approve.selector, address(_UNISWAP_ROUTER), type(uint256).max
        )
      );

      if (!success) {
        // Some janky tokens only allow setting approval up to current balance.
        (success, data) = address(token).call(
          abi.encodeWithSelector(
            token.approve.selector, address(_UNISWAP_ROUTER), amount
          )
        );
      }

      require(
        success && (data.length == 0 || abi.decode(data, (bool))),
        "Token approval for Uniswap router failed."
      );
    }
  }

  function _tradeEtherForTokenWithFeeOnTransfer(
    address tokenReceivedOrUSDCFlag,
    uint256 etherAmount,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 maximumFeeAmount,
    uint256 deadline,
    bool fromReserves,
    FeeType feeType
  ) internal returns (uint256 totalTokensBought) {
    _delegate(V17);
  }

  function _tradeEtherForTokenWithFeeOnTransferLegacy(
    address tokenReceivedOrUSDCFlag,
    uint256 etherAmount,
    uint256 quotedTokenAmount,
    uint256 quotedTokenAmountAfterTransferFee,
    uint256 deadline,
    bool fromReserves
  ) internal returns (uint256 totalTokensBought) {
    _delegate(V17);
  }

  /**
  * @notice Internal trade function. If token is _TRADE_FOR_USDC_AND_RETAIN_FLAG,
  * trade for USDC and retain the full output amount by replacing the recipient
  * ("to" input) on the swapETHForExactTokens call.
  */
  function _tradeExactEtherForToken(
    address tokenReceivedOrUSDCFlag,
    uint256 etherAmount,
    uint256 quotedTokenAmount,
    uint256 deadline,
    bool fromReserves,
    FeeType feeType,
    uint256 maximumFeeAmount
  ) internal returns (
    uint256 totalTokensBought,
    uint256 receivedTokenAmount,
    uint256 retainedAmount
  ) {
    // Set swap target destination and token.
    address destination;
    address[] memory path = new address[](2);
    path[0] = _WETH;
    if (tokenReceivedOrUSDCFlag == _TRADE_FOR_USDC_AND_RETAIN_FLAG) {
      path[1] = address(_USDC);
      destination = address(this);
    } else {
      path[1] = tokenReceivedOrUSDCFlag;
      destination = fromReserves ? address(this) : msg.sender;
    }

    // Trade Ether for quoted token amount and send to appropriate recipient.
    uint256[] memory amounts = new uint256[](2);
    amounts = _UNISWAP_ROUTER.swapExactETHForTokens{value:
      feeType != FeeType.RECEIVED_ASSET
      ? etherAmount - maximumFeeAmount
      : etherAmount
    }(
      quotedTokenAmount,
      path,
      destination,
      deadline
    );
    totalTokensBought = amounts[1];

    if (feeType == FeeType.RECEIVED_ASSET) {
      // Retain the lesser of either max fee or bought amount less quoted amount.
      retainedAmount = maximumFeeAmount.min(
        totalTokensBought - quotedTokenAmount
      );
      receivedTokenAmount = totalTokensBought - retainedAmount;
    } else {
      retainedAmount = maximumFeeAmount;
      receivedTokenAmount = totalTokensBought;
    }
  }

  function _tradeTokenForEther(
    ERC20Interface token,
    uint256 tokenAmount,
    uint256 tokenAmountAfterTransferFee,
    uint256 quotedEtherAmount,
    uint256 deadline,
    FeeType feeType,
    uint256 maximumFeeAmount
  ) internal returns (
    uint256 totalEtherBought,
    uint256 receivedEtherAmount,
    uint256 retainedAmount
  ) {
    // Trade tokens for Ether.
    uint256 tradeAmount;
    if (feeType == FeeType.SUPPLIED_ASSET) {
      tradeAmount = (tokenAmount.min(tokenAmountAfterTransferFee) - maximumFeeAmount);
      retainedAmount = maximumFeeAmount;
    } else {
      tradeAmount = tokenAmount.min(tokenAmountAfterTransferFee);
    }

    // Approve Uniswap router to transfer tokens on behalf of this contract.
    _grantUniswapRouterApprovalIfNecessary(token, tokenAmount);

    // Establish path from target token to Ether.
    (address[] memory path, uint256[] memory amounts) = _createPathAndAmounts(
      address(token), _WETH, false
    );

    // Trade tokens for quoted Ether amount on Uniswap (send to this contract).
    if (tokenAmount == tokenAmountAfterTransferFee) {
      amounts = _UNISWAP_ROUTER.swapExactTokensForETH(
        tradeAmount, quotedEtherAmount, path, address(this), deadline
      );
      totalEtherBought = amounts[1];
    } else {
      uint256 ethBalanceBeforeTrade = address(this).balance;
      _UNISWAP_ROUTER.swapExactTokensForETHSupportingFeeOnTransferTokens(
        tradeAmount,
        quotedEtherAmount,
        path,
        address(this),
        deadline
      );
      totalEtherBought = address(this).balance - ethBalanceBeforeTrade;
    }

    if (feeType != FeeType.SUPPLIED_ASSET) {
      // Retain the lesser of either max fee or bought amount less quoted amount.
      retainedAmount = maximumFeeAmount.min(
        totalEtherBought - quotedEtherAmount
      );

      // Receive back the total bought Ether less total retained Ether.
      receivedEtherAmount = totalEtherBought - retainedAmount;
    } else {
      receivedEtherAmount = totalEtherBought;
    }
  }

  /**
  * @notice Internal trade function. If tokenReceived is _TRADE_FOR_USDC_AND_RETAIN_FLAG,
  * trade for USDC and retain the full output amount by replacing the recipient
  * ("to" input) on the swapTokensForExactTokens call.
  */
  function _tradeTokenForToken(
    address account,
    ERC20Interface tokenProvided,
    address tokenReceivedOrUSDCFlag,
    uint256 tokenProvidedAmount,
    uint256 quotedTokenReceivedAmount,
    uint256 maximumFeeAmount, // WETH if routeThroughEther, else tokenReceived
    uint256 deadline,
    bool routeThroughEther,
    FeeType feeType
  ) internal returns (uint256 totalTokensBought) {
    uint256 retainedAmount;
    uint256 receivedAmount;
    address tokenReceived;

    // Approve Uniswap router to transfer tokens on behalf of this contract.
    _grantUniswapRouterApprovalIfNecessary(tokenProvided, tokenProvidedAmount);

    // Set recipient, swap target token
    if (tokenReceivedOrUSDCFlag == _TRADE_FOR_USDC_AND_RETAIN_FLAG) {
      tokenReceived = address(_USDC);
    } else {
      tokenReceived = tokenReceivedOrUSDCFlag;
    }

    if (routeThroughEther == false) {
      // Establish direct path between tokens.
      (address[] memory path, uint256[] memory amounts) = _createPathAndAmounts(
        address(tokenProvided), tokenReceived, false
      );

      // Trade for the quoted token amount on Uniswap and send to this contract.
      amounts = _UNISWAP_ROUTER.swapExactTokensForTokens(
        feeType == FeeType.SUPPLIED_ASSET
        ? tokenProvidedAmount - maximumFeeAmount
        : tokenProvidedAmount,
        quotedTokenReceivedAmount,
        path,
        address(this),
        deadline
      );

      totalTokensBought = amounts[1];

      if (feeType == FeeType.RECEIVED_ASSET) {
        // Retain lesser of either max fee or bought amount less quoted amount.
        retainedAmount = maximumFeeAmount.min(
          totalTokensBought - quotedTokenReceivedAmount
        );
        receivedAmount = totalTokensBought - retainedAmount;
      } else {
        retainedAmount = maximumFeeAmount;
        receivedAmount = totalTokensBought;
      }
    } else {
      // Establish path between provided token and WETH.
      (address[] memory path, uint256[] memory amounts) = _createPathAndAmounts(
        address(tokenProvided), _WETH, false
      );

      // Trade all provided tokens for WETH on Uniswap and send to this contract.
      amounts = _UNISWAP_ROUTER.swapExactTokensForTokens(
        feeType == FeeType.SUPPLIED_ASSET
        ? tokenProvidedAmount - maximumFeeAmount
        : tokenProvidedAmount,
        feeType == FeeType.ETHER ? maximumFeeAmount : 1,
        path,
        address(this),
        deadline
      );
      retainedAmount = amounts[1];

      // Establish path between WETH and received token.
      (path, amounts) = _createPathAndAmounts(
        _WETH, tokenReceived, false
      );

      // Trade bought WETH (less fee) for received token, send to this contract.
      amounts = _UNISWAP_ROUTER.swapExactTokensForTokens(
        feeType == FeeType.ETHER
        ? retainedAmount - maximumFeeAmount
        : retainedAmount,
        quotedTokenReceivedAmount,
        path,
        address(this),
        deadline
      );

      totalTokensBought = amounts[1];

      if (feeType == FeeType.RECEIVED_ASSET) {
        // Retain lesser of either max fee or bought amount less quoted amount.
        retainedAmount = maximumFeeAmount.min(
          totalTokensBought - quotedTokenReceivedAmount
        );
        receivedAmount = totalTokensBought - retainedAmount;
      } else {
        retainedAmount = maximumFeeAmount;
        receivedAmount = totalTokensBought;
      }
    }

    _emitTrade(
      account,
      address(tokenProvided),
      tokenReceivedOrUSDCFlag,
      feeType == FeeType.ETHER
      ? _WETH
      : (feeType == FeeType.RECEIVED_ASSET
    ? tokenReceived
    : address(tokenProvided)
    ),
      tokenProvidedAmount,
      receivedAmount,
      retainedAmount
    );

    if (
      account != address(this) &&
      tokenReceivedOrUSDCFlag != _TRADE_FOR_USDC_AND_RETAIN_FLAG
    ) {
      _transferToken(ERC20Interface(tokenReceived), account, receivedAmount);
    }
  }

  /**
  * @notice Internal trade function. If tokenReceived is _TRADE_FOR_USDC_AND_RETAIN_FLAG,
  * trade for USDC and retain the full output amount by replacing the recipient
  * ("to" input) on the swapTokensForExactTokens call.
  */
  function _tradeTokenForTokenLegacy(
    address account,
    ERC20Interface tokenProvided,
    address tokenReceivedOrUSDCFlag,
    uint256 tokenProvidedAmount,
    uint256 quotedTokenReceivedAmount,
    uint256 deadline,
    bool routeThroughEther
  ) internal returns (uint256 totalTokensSold) {
    uint256 retainedAmount;
    address tokenReceived;
    address recipient;

    // Approve Uniswap router to transfer tokens on behalf of this contract.
    _grantUniswapRouterApprovalIfNecessary(tokenProvided, tokenProvidedAmount);

    // Set recipient, swap target token
    if (tokenReceivedOrUSDCFlag == _TRADE_FOR_USDC_AND_RETAIN_FLAG) {
      recipient = address(this);
      tokenReceived = address(_USDC);
    } else {
      recipient = account;
      tokenReceived = tokenReceivedOrUSDCFlag;
    }

    if (routeThroughEther == false) {
      // Establish direct path between tokens.
      (address[] memory path, uint256[] memory amounts) = _createPathAndAmounts(
        address(tokenProvided), tokenReceived, false
      );

      // Trade for the quoted token amount on Uniswap and send to recipient.
      amounts = _UNISWAP_ROUTER.swapTokensForExactTokens(
        quotedTokenReceivedAmount,
        tokenProvidedAmount,
        path,
        recipient,
        deadline
      );

      totalTokensSold = amounts[0];
      retainedAmount = tokenProvidedAmount - totalTokensSold;
    } else {
      // Establish path between provided token and WETH.
      (address[] memory path, uint256[] memory amounts) = _createPathAndAmounts(
        address(tokenProvided), _WETH, false
      );

      // Trade all provided tokens for WETH on Uniswap and send to this contract.
      amounts = _UNISWAP_ROUTER.swapExactTokensForTokens(
        tokenProvidedAmount, 0, path, address(this), deadline
      );
      retainedAmount = amounts[1];

      // Establish path between WETH and received token.
      (path, amounts) = _createPathAndAmounts(
        _WETH, tokenReceived, false
      );

      // Trade bought WETH for received token on Uniswap and send to recipient.
      amounts = _UNISWAP_ROUTER.swapTokensForExactTokens(
        quotedTokenReceivedAmount, retainedAmount, path, recipient, deadline
      );

      totalTokensSold = amounts[0];
      retainedAmount = retainedAmount - totalTokensSold;
    }

    _emitTrade(
      account,
      address(tokenProvided),
      tokenReceivedOrUSDCFlag,
      routeThroughEther ? _WETH : address(tokenProvided),
      tokenProvidedAmount,
      quotedTokenReceivedAmount,
      retainedAmount
    );
  }

  struct TradeTokenForTokenWithFeeOnTransferArgs {
    address account;
    ERC20Interface tokenProvided;
    address tokenReceivedOrUSDCFlag;
    uint256 tokenProvidedAmount;
    uint256 tokenProvidedAmountAfterTransferFee;
    uint256 quotedTokenReceivedAmount;
    uint256 quotedTokenReceivedAmountAfterTransferFee;
    uint256 maximumFeeAmount;
    uint256 deadline;
    bool routeThroughEther;
    FeeType feeType;
  }

  /**
  * @notice Internal trade function for cases where one of the tokens in
  * question levies a transfer fee. If tokenReceived is
  * _TRADE_FOR_USDC_AND_RETAIN_FLAG, trade for USDC and retain the full output
  * amount by replacing the recipient ("to" input) on the
  * swapTokensForExactTokens call.
  */
  function _tradeTokenForTokenWithFeeOnTransfer(
    TradeTokenForTokenWithFeeOnTransferArgs memory args
  ) internal returns (uint256 totalTokensBought) {
    ERC20Interface tokenReceived = (
    args.tokenReceivedOrUSDCFlag == _TRADE_FOR_USDC_AND_RETAIN_FLAG
    ? ERC20Interface(_USDC)
    : ERC20Interface(args.tokenReceivedOrUSDCFlag)
    );

    // Approve Uniswap router to transfer tokens on behalf of this contract.
    _grantUniswapRouterApprovalIfNecessary(
      args.tokenProvided, args.tokenProvidedAmountAfterTransferFee
    );

    { // Scope to avoid stack too deep error.
      // Establish path between tokens.
      (address[] memory path, ) = _createPathAndAmounts(
        address(args.tokenProvided), address(tokenReceived), args.routeThroughEther
      );

      // Get this contract's balance in the output token prior to the trade.
      uint256 priorReserveBalanceOfReceivedToken = tokenReceived.balanceOf(
        address(this)
      );

      // Trade for the quoted token amount on Uniswap and send to this contract.
      _UNISWAP_ROUTER.swapExactTokensForTokensSupportingFeeOnTransferTokens(
        args.feeType == FeeType.SUPPLIED_ASSET
        ? args.tokenProvidedAmountAfterTransferFee - args.maximumFeeAmount
        : args.tokenProvidedAmountAfterTransferFee,
        args.quotedTokenReceivedAmount,
        path,
        address(this),
        args.deadline
      );

      totalTokensBought = tokenReceived.balanceOf(address(this)) - priorReserveBalanceOfReceivedToken;
    }
    uint256 receivedAmountAfterTransferFee;
    if (
      args.account != address(this) &&
      args.tokenReceivedOrUSDCFlag != _TRADE_FOR_USDC_AND_RETAIN_FLAG
    ) {
      {
        // Get the receiver's balance prior to the transfer.
        uint256 priorRecipientBalanceOfReceivedToken = tokenReceived.balanceOf(
          args.account
        );

        // Transfer the received tokens (less the fee) to the recipient.
        _transferToken(
          tokenReceived,
          args.account,
          args.feeType == FeeType.RECEIVED_ASSET
          ? totalTokensBought - args.maximumFeeAmount
          : totalTokensBought
        );

        receivedAmountAfterTransferFee = tokenReceived.balanceOf(args.account) - priorRecipientBalanceOfReceivedToken;
      }

      // Ensure that sufficient tokens were returned to the user.
      require(
        receivedAmountAfterTransferFee >= args.quotedTokenReceivedAmountAfterTransferFee,
        "Received token amount after transfer fee is less than quoted amount."
      );
    } else {
      receivedAmountAfterTransferFee = args.feeType == FeeType.RECEIVED_ASSET
      ? totalTokensBought - args.maximumFeeAmount
      : totalTokensBought;
    }

    _emitTrade(
      args.account,
      address(args.tokenProvided),
      args.tokenReceivedOrUSDCFlag,
      args.feeType == FeeType.RECEIVED_ASSET
      ? address(tokenReceived)
      : address(args.tokenProvided),
      args.tokenProvidedAmount,
      receivedAmountAfterTransferFee,
      args.maximumFeeAmount
    );
  }

  /**
  * @notice Internal trade function for cases where one of the tokens in
  * question levies a transfer fee. If tokenReceived is
  * _TRADE_FOR_USDC_AND_RETAIN_FLAG, trade for USDC and retain the full output
  * amount by replacing the recipient ("to" input) on the
  * swapTokensForExactTokens call.
  */
  function _tradeTokenForTokenWithFeeOnTransferLegacy(
    address account,
    ERC20Interface tokenProvided,
    address tokenReceivedOrUSDCFlag,
    uint256 tokenProvidedAmount,
    uint256 tokenProvidedAmountAfterTransferFee,
    uint256 quotedTokenReceivedAmount,
    uint256 quotedTokenReceivedAmountAfterTransferFee,
    uint256 deadline,
    bool routeThroughEther
  ) internal returns (uint256 totalTokensBought) {
    uint256 retainedAmount;
    uint256 receivedAmountAfterTransferFee;
    ERC20Interface tokenReceived;

    // Approve Uniswap router to transfer tokens on behalf of this contract.
    _grantUniswapRouterApprovalIfNecessary(
      tokenProvided, tokenProvidedAmountAfterTransferFee
    );

    { // Scope to avoid stack too deep error.
      address recipient;
      // Set recipient, swap target token
      if (tokenReceivedOrUSDCFlag == _TRADE_FOR_USDC_AND_RETAIN_FLAG) {
        recipient = address(this);
        tokenReceived = ERC20Interface(_USDC);
      } else {
        recipient = account;
        tokenReceived = ERC20Interface(tokenReceivedOrUSDCFlag);
      }

      // Establish path between tokens.
      (address[] memory path, ) = _createPathAndAmounts(
        address(tokenProvided), address(tokenReceived), routeThroughEther
      );

      // Get this contract's balance in the output token prior to the trade.
      uint256 priorReserveBalanceOfReceivedToken = tokenReceived.balanceOf(
        address(this)
      );

      // Trade for the quoted token amount on Uniswap and send to this contract.
      _UNISWAP_ROUTER.swapExactTokensForTokensSupportingFeeOnTransferTokens(
        tokenProvidedAmountAfterTransferFee,
        quotedTokenReceivedAmount,
        path,
        address(this),
        deadline
      );

      totalTokensBought = tokenReceived.balanceOf(address(this)) - priorReserveBalanceOfReceivedToken;
      retainedAmount = totalTokensBought - quotedTokenReceivedAmount;

      // Get the receiver's balance prior to the transfer.
      uint256 priorRecipientBalanceOfReceivedToken = tokenReceived.balanceOf(
        recipient
      );

      // Transfer the received tokens to the recipient.
      _transferToken(tokenReceived, recipient, quotedTokenReceivedAmount);

      receivedAmountAfterTransferFee = tokenReceived.balanceOf(recipient) - priorRecipientBalanceOfReceivedToken;

      // Ensure that sufficient tokens were returned to the user.
      require(
        receivedAmountAfterTransferFee >= quotedTokenReceivedAmountAfterTransferFee,
        "Received token amount after transfer fee is less than quoted amount."
      );
    }

    _emitTrade(
      account,
      address(tokenProvided),
      tokenReceivedOrUSDCFlag,
      address(tokenReceived),
      tokenProvidedAmount,
      receivedAmountAfterTransferFee,
      retainedAmount
    );
  }

  /**
   * @notice Internal function to set a new account on a given role and emit a
   * `RoleModified` event if the role holder has changed.
   * @param role The role that the account will be set for. Permitted roles are
   * deposit manager (0), adjuster (1), and pauser (2).
   * @param account The account to set as the designated role bearer.
   */
  function _setRole(Role role, address account) internal {
    RoleStatus storage storedRoleStatus = _roles[uint256(role)];

    if (account != storedRoleStatus.account) {
      storedRoleStatus.account = account;
      emit RoleModified(role, account);
    }
  }

  function _emitTrade(
    address account,
    address suppliedAsset,
    address receivedAsset,
    address retainedAsset,
    uint256 suppliedAmount,
    uint256 receivedAmount,
    uint256 retainedAmount
  ) internal {
    emit Trade(
      account,
      suppliedAsset,
      receivedAsset,
      retainedAsset,
      suppliedAmount,
      receivedAmount,
      retainedAmount
    );
  }

  function _fireTradeEvent(
    bool fromReserves,
    bool supplyingEther,
    bool feeInEther,
    address token,
    uint256 suppliedAmount,
    uint256 receivedAmount,
    uint256 retainedAmount
  ) internal {
    emit Trade(
      fromReserves ? address(this) : msg.sender,
      supplyingEther ? address(0) : token,
      supplyingEther ? token : address(0),
      feeInEther
      ? address(0)
      : (token == _TRADE_FOR_USDC_AND_RETAIN_FLAG ? address(_USDC) : token),
      suppliedAmount,
      receivedAmount,
      retainedAmount
    );
  }

  /**
   * @notice Internal view function to check whether the caller is the current
   * role holder.
   * @param role The role to check for.
   * @return hasRole - a boolean indicating if the caller has the specified role.
   */
  function _isRole(Role role) internal view returns (bool hasRole) {
    hasRole = msg.sender == _roles[uint256(role)].account;
  }

  /**
   * @notice Internal view function to check whether the given role is paused or
   * not.
   * @param role The role to check for.
   * @return paused - a boolean indicating if the specified role is paused or not.
   */
  function _isPaused(Role role) internal view returns (bool paused) {
    paused = _roles[uint256(role)].paused;
  }

  /**
   * @notice Internal view function to enforce that the given initial user signing
   * key resolves to the given smart wallet when deployed through the Dharma Smart
   * Wallet Factory V1. (staging version)
   * @param smartWallet address The smart wallet.
   * @param initialUserSigningKey address The initial user signing key.
   */
  function _isSmartWallet(
    address smartWallet, address initialUserSigningKey
  ) internal pure returns (bool) {
    // Derive the keccak256 hash of the smart wallet initialization code.
    bytes32 initCodeHash = keccak256(
      abi.encodePacked(
        _WALLET_CREATION_CODE_HEADER,
        initialUserSigningKey,
        _WALLET_CREATION_CODE_FOOTER
      )
    );

    // Attempt to derive a smart wallet address that matches the one provided.
    address target;
    for (uint256 nonce = 0; nonce < 10; nonce++) {
      target = address(          // derive the target deployment address.
        uint160(                 // downcast to match the address type.
          uint256(               // cast to uint to truncate upper digits.
            keccak256(           // compute CREATE2 hash using all inputs.
              abi.encodePacked(  // pack all inputs to the hash together.
                _CREATE2_HEADER, // pass in control character + factory address.
                nonce,           // pass in current nonce as the salt.
                initCodeHash     // pass in hash of contract creation code.
              )
            )
          )
        )
      );

      // Exit early if the provided smart wallet matches derived target address.
      if (target == smartWallet) {
        return true;
      }

      // Otherwise, increment the nonce and derive a new salt.
      nonce++;
    }

    // Explicity recognize no target was found matching provided smart wallet.
    return false;
  }

  function _transferToken(ERC20Interface token, address to, uint256 amount) internal {
    (bool success, bytes memory data) = address(token).call(
      abi.encodeWithSelector(token.transfer.selector, to, amount)
    );
    require(
      success && (data.length == 0 || abi.decode(data, (bool))),
      "Transfer out failed."
    );
  }

  function _transferEther(address recipient, uint256 etherAmount) internal {
    // Send quoted Ether amount to recipient and revert with reason on failure.
    (bool ok, ) = recipient.call{value:etherAmount}("");
    if (!ok) {
      assembly {
        returndatacopy(0, 0, returndatasize())
        revert(0, returndatasize())
      }
    }
  }

  function _transferInToken(ERC20Interface token, address from, uint256 amount) internal {
    (bool success, bytes memory data) = address(token).call(
      abi.encodeWithSelector(token.transferFrom.selector, from, address(this), amount)
    );

    require(
      success && (data.length == 0 || abi.decode(data, (bool))),
      "Transfer in failed."
    );
  }

  function _ensureSmartWallet(
    address smartWallet, address initialUserSigningKey
  ) internal pure {
    require(
      _isSmartWallet(smartWallet, initialUserSigningKey),
      "Could not resolve smart wallet using provided signing key."
    );
  }

  function _createPathAndAmounts(
    address start, address end, bool routeThroughEther
  ) internal pure returns (address[] memory, uint256[] memory) {
    uint256 pathLength = routeThroughEther ? 3 : 2;
    address[] memory path = new address[](pathLength);
    path[0] = start;

    if (routeThroughEther) {
      path[1] = _WETH;
    }

    path[pathLength - 1] = end;

    return (path, new uint256[](pathLength));
  }

  function _ensureNoEtherFeeTypeWhenNotRouted(
    bool routeThroughEther, FeeType feeType
  ) internal pure {
    require(
      routeThroughEther || feeType != FeeType.ETHER,
      "Cannot take token-for-token fee in Ether unless routed through Ether."
    );
  }

  function _ensureNoEtherFee(FeeType feeType) internal pure {
    require(
      feeType != FeeType.ETHER,
      "Cannot take token-for-token fee in Ether with fee on transfer."
    );
  }

  function _delegate(address implementation) private {
    assembly {
      calldatacopy(0, 0, calldatasize())
      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
      returndatacopy(0, 0, returndatasize())
      switch result
      case 0 { revert(0, returndatasize()) }
      default { return(0, returndatasize()) }
    }
  }

  /**
   * @notice Modifier that throws if called by any account other than the owner
   * or the supplied role, or if the caller is not the owner and the role in
   * question is paused.
   * @param role The role to require unless the caller is the owner.
   */
  modifier onlyOwnerOr(Role role) {
    if (!isOwner()) {
      require(_isRole(role), "Caller does not have a required role.");
      require(!_isPaused(role), "Role in question is currently paused.");
    }
    _;
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"actionRegistryAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"string","name":"revertReason","type":"string"}],"name":"CallFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"rolledBack","type":"bool"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"CallSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EtherReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"etherAmount","type":"uint256"}],"name":"GasReserveRefilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum DharmaTradeReserveV19Interface.Role","name":"role","type":"uint8"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"RoleModified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum DharmaTradeReserveV19Interface.Role","name":"role","type":"uint8"}],"name":"RolePaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum DharmaTradeReserveV19Interface.Role","name":"role","type":"uint8"}],"name":"RoleUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"suppliedAsset","type":"address"},{"indexed":false,"internalType":"address","name":"receivedAsset","type":"address"},{"indexed":false,"internalType":"address","name":"retainedAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"suppliedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"recievedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"retainedAmount","type":"uint256"}],"name":"Trade","type":"event"},{"inputs":[],"name":"_ACTION_REGISTRY","outputs":[{"internalType":"contract IActionRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint96","name":"value","type":"uint96"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ITypes.Call[]","name":"calls","type":"tuple[]"}],"name":"_execute","outputs":[{"components":[{"internalType":"bool","name":"ok","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct ITypes.CallReturn[]","name":"callResults","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint96","name":"value","type":"uint96"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ITypes.Call[]","name":"calls","type":"tuple[]"}],"name":"_simulate","outputs":[{"components":[{"internalType":"bool","name":"ok","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct ITypes.CallReturn[]","name":"callResults","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callAny","outputs":[{"internalType":"bool","name":"ok","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint96","name":"value","type":"uint96"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ITypes.Call[]","name":"calls","type":"tuple[]"}],"name":"execute","outputs":[{"internalType":"bool[]","name":"ok","type":"bool[]"},{"internalType":"bytes[]","name":"returnData","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"smartWallet","type":"address"},{"internalType":"address","name":"initialUserSigningKey","type":"address"},{"internalType":"uint256","name":"etherAmount","type":"uint256"}],"name":"finalizeEtherDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"smartWallet","type":"address"},{"internalType":"address","name":"initialUserSigningKey","type":"address"},{"internalType":"contract ERC20Interface","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"finalizeTokenDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getActioner","outputs":[{"internalType":"address","name":"actioner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDepositManager","outputs":[{"internalType":"address","name":"depositManager","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGasReserveRefiller","outputs":[{"internalType":"address","name":"gasReserveRefiller","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getImplementation","outputs":[{"internalType":"address","name":"implementation","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInstance","outputs":[{"internalType":"address","name":"instance","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPauser","outputs":[{"internalType":"address","name":"pauser","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrimaryDaiRecipient","outputs":[{"internalType":"address","name":"recipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrimaryUSDCRecipient","outputs":[{"internalType":"address","name":"recipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserveTrader","outputs":[{"internalType":"address","name":"reserveTrader","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVersion","outputs":[{"internalType":"uint256","name":"version","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getWithdrawalManager","outputs":[{"internalType":"address","name":"withdrawalManager","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"smartWallet","type":"address"},{"internalType":"address","name":"initialUserSigningKey","type":"address"}],"name":"isDharmaSmartWallet","outputs":[{"internalType":"bool","name":"dharmaSmartWallet","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum DharmaTradeReserveV19Interface.Role","name":"role","type":"uint8"}],"name":"isPaused","outputs":[{"internalType":"bool","name":"paused","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum DharmaTradeReserveV19Interface.Role","name":"role","type":"uint8"}],"name":"isRole","outputs":[{"internalType":"bool","name":"hasRole","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum DharmaTradeReserveV19Interface.Role","name":"role","type":"uint8"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"etherAmount","type":"uint256"}],"name":"refillGasReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum DharmaTradeReserveV19Interface.Role","name":"role","type":"uint8"}],"name":"removeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"setPrimaryDaiRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"setPrimaryUSDCRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum DharmaTradeReserveV19Interface.Role","name":"role","type":"uint8"},{"internalType":"address","name":"account","type":"address"}],"name":"setRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint96","name":"value","type":"uint96"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ITypes.Call[]","name":"calls","type":"tuple[]"}],"name":"simulate","outputs":[{"internalType":"bool[]","name":"ok","type":"bool[]"},{"internalType":"bytes[]","name":"returnData","type":"bytes[]"},{"internalType":"bool","name":"validCalls","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"quotedTokenAmount","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeEtherForTokenSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"etherAmountFromReserves","type":"uint256"},{"internalType":"uint256","name":"quotedTokenAmount","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeEtherForTokenUsingReservesSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"etherAmountFromReserves","type":"uint256"},{"internalType":"uint256","name":"quotedTokenAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenAmountAfterTransferFee","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeEtherForTokenUsingReservesWithFeeOnTransferSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"quotedTokenAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenAmountAfterTransferFee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"tradeEtherForTokenWithFeeOnTransfer","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"quotedTokenAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenAmountAfterTransferFee","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeEtherForTokenWithFeeOnTransferSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"etherAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenAmountAfterTransferFee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"tradeEtherForTokenWithFeeOnTransferUsingEtherizer","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"token","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"quotedEtherAmount","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeTokenForEtherSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalEtherBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"token","type":"address"},{"internalType":"uint256","name":"tokenAmountFromReserves","type":"uint256"},{"internalType":"uint256","name":"quotedEtherAmount","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeTokenForEtherUsingReservesSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalEtherBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"token","type":"address"},{"internalType":"uint256","name":"tokenAmountFromReserves","type":"uint256"},{"internalType":"uint256","name":"quotedEtherAmount","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeTokenForEtherUsingReservesWithFeeOnTransferSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalEtherBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"token","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"quotedEtherAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"tradeTokenForEtherWithFeeOnTransfer","outputs":[{"internalType":"uint256","name":"totalEtherBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"token","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"quotedEtherAmount","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeTokenForEtherWithFeeOnTransferSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalEtherBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"tokenProvided","type":"address"},{"internalType":"address","name":"tokenReceived","type":"address"},{"internalType":"uint256","name":"tokenProvidedAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenReceivedAmount","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"routeThroughEther","type":"bool"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeTokenForTokenSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"tokenProvidedFromReserves","type":"address"},{"internalType":"address","name":"tokenReceived","type":"address"},{"internalType":"uint256","name":"tokenProvidedAmountFromReserves","type":"uint256"},{"internalType":"uint256","name":"quotedTokenReceivedAmount","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"routeThroughEther","type":"bool"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeTokenForTokenUsingReservesSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"tokenProvidedFromReserves","type":"address"},{"internalType":"address","name":"tokenReceived","type":"address"},{"internalType":"uint256","name":"tokenProvidedAmountFromReserves","type":"uint256"},{"internalType":"uint256","name":"quotedTokenReceivedAmount","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"routeThroughEther","type":"bool"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeTokenForTokenUsingReservesWithFeeOnTransferSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"tokenProvided","type":"address"},{"internalType":"address","name":"tokenReceived","type":"address"},{"internalType":"uint256","name":"tokenProvidedAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenReceivedAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenReceivedAmountAfterTransferFee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"routeThroughEther","type":"bool"}],"name":"tradeTokenForTokenWithFeeOnTransfer","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"tokenProvided","type":"address"},{"internalType":"address","name":"tokenReceived","type":"address"},{"internalType":"uint256","name":"tokenProvidedAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenReceivedAmount","type":"uint256"},{"internalType":"uint256","name":"quotedTokenReceivedAmountAfterTransferFee","type":"uint256"},{"internalType":"uint256","name":"maximumFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"routeThroughEther","type":"bool"},{"internalType":"enum DharmaTradeReserveV19Interface.FeeType","name":"feeType","type":"uint8"}],"name":"tradeTokenForTokenWithFeeOnTransferSpecifyingFee","outputs":[{"internalType":"uint256","name":"totalTokensBought","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum DharmaTradeReserveV19Interface.Role","name":"role","type":"uint8"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20Interface","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"daiAmount","type":"uint256"}],"name":"withdrawDaiToPrimaryRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"etherAmount","type":"uint256"}],"name":"withdrawEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdcAmount","type":"uint256"}],"name":"withdrawUSDCToPrimaryRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a06040523480156200001157600080fd5b5060405162005e2f38038062005e2f833981016040819052620000349162000093565b600080546001600160a01b03191632178082556040516001600160a01b039190911691907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a360601b6001600160601b031916608052620000c3565b600060208284031215620000a5578081fd5b81516001600160a01b0381168114620000bc578182fd5b9392505050565b60805160601c615d3f620000f060003960008181610b6d01528181610ff401526114830152615d3f6000f3fe6080604052600436106103385760003560e01c80638f32d59b116101ab578063c6102aa8116100f7578063eb68b08a11610095578063f2fde38b1161006f578063f2fde38b14610946578063f495018714610966578063f816c0fa14610986578063f97086f6146109a657610378565b8063eb68b08a146108f1578063edf07f1514610906578063f2e12a391461092657610378565b8063d9caed12116100d1578063d9caed1214610887578063dab41d0d146108a7578063de7b5d14146108c7578063e20ed9d2146108dc57610378565b8063c6102aa814610832578063c90418b414610847578063cef0a6041461086757610378565b8063afd6116b11610164578063bb6033201161013e578063bb603320146107b2578063bc61e733146107d2578063c21e4e42146107f2578063c54d559e1461081257610378565b8063afd6116b1461075c578063b1f2aa6714610789578063badafb37146107a457610378565b80638f32d59b146106b25780639b86f0ef146106c7578063a0a6d75f146106e7578063a735559614610707578063aaf10f4214610727578063aeed28611461073c57610378565b8063329504da116102855780637008b5481161022357806378a967aa116101fd57806378a967aa1461064857806379ba5097146106685780638218a8e91461067d5780638da5cb5b1461069d57610378565b80637008b548146105d657806372b272eb146105eb5780637787c5871461061957610378565b8063522f68151161025f578063522f6815146105545780635ce4a04914610574578063618fdbb0146105895780636b309696146105a957610378565b8063329504da1461050c5780633efa667e146105215780634d0757eb1461054157610378565b806321a012ec116102f2578063301c7e5d116102cc578063301c7e5d146104a25780633059d1d3146104c257806331ab6d2a146104d757806331ae1f02146104f757610378565b806321a012ec1461044d57806323452b9c1461046d5780632e5cd5f31461048257610378565b806263f2fb1461037d5780630d8e6e2c1461039f57806312e6bf6a146103ca57806312fd415a146103f8578063153f92eb1461041857806318b93e461461043a57610378565b36610378577f1e57e3bb474320be3d2c77138f75b7c3941292d647f5f9634e33a8e94e0e069b333460405161036e929190614df1565b60405180910390a1005b600080fd5b34801561038957600080fd5b5061039d610398366004614320565b6109c6565b005b3480156103ab57600080fd5b506103b4610a15565b6040516103c191906156be565b60405180910390f35b3480156103d657600080fd5b506103ea6103e53660046143c3565b610a1a565b6040516103c19291906150b7565b34801561040457600080fd5b506103b461041336600461459c565b610aad565b34801561042457600080fd5b5061042d610b6b565b6040516103c19190614d5b565b6103b461044836600461459c565b610b8f565b34801561045957600080fd5b506103b46104683660046149ef565b610bb8565b34801561047957600080fd5b5061039d610c3c565b34801561048e57600080fd5b5061039d61049d366004614358565b610c72565b3480156104ae57600080fd5b5061039d6104bd366004614af9565b610ce5565b3480156104ce57600080fd5b5061042d610dc2565b3480156104e357600080fd5b506103b46104f236600461459c565b610dd1565b34801561050357600080fd5b5061042d610e3f565b34801561051857600080fd5b5061042d610e65565b34801561052d57600080fd5b506103b461053c366004614a6f565b610e74565b6103b461054f366004614508565b610ea0565b34801561056057600080fd5b5061039d61056f366004614398565b610efa565b34801561058057600080fd5b5061042d610f2c565b34801561059557600080fd5b506103b46105a43660046144ce565b610f38565b3480156105b557600080fd5b506105c96105c4366004614446565b610f5f565b6040516103c1919061506b565b3480156105e257600080fd5b5061042d610f72565b3480156105f757600080fd5b5061060b6106063660046147af565b610f7e565b6040516103c1929190614e43565b34801561062557600080fd5b50610639610634366004614741565b61147c565b6040516103c193929190614e68565b34801561065457600080fd5b5061039d610663366004614320565b6117a4565b34801561067457600080fd5b5061039d6117ea565b34801561068957600080fd5b506103b4610698366004614559565b611870565b3480156106a957600080fd5b5061042d611898565b3480156106be57600080fd5b506105c96118a7565b3480156106d357600080fd5b506103b46106e236600461459c565b6118b8565b3480156106f357600080fd5b506103b46107023660046149ef565b61195f565b34801561071357600080fd5b506103b46107223660046145f5565b611a52565b34801561073357600080fd5b5061042d611abe565b34801561074857600080fd5b5061039d61075736600461447e565b611b77565b34801561076857600080fd5b5061077c6107773660046147af565b611bec565b6040516103c19190614ea0565b34801561079557600080fd5b506103b461044836600461459c565b6103b46105a43660046144ce565b3480156107be57600080fd5b506105c96107cd366004614af9565b611dda565b3480156107de57600080fd5b506105c96107ed366004614af9565b611deb565b3480156107fe57600080fd5b5061077c61080d3660046147af565b611df6565b34801561081e57600080fd5b5061039d61082d366004614b73565b611fed565b34801561083e57600080fd5b5061042d612093565b34801561085357600080fd5b506103b46108623660046149ef565b61209e565b34801561087357600080fd5b5061039d610882366004614b73565b6120c6565b34801561089357600080fd5b506105c96108a236600461496a565b612167565b3480156108b357600080fd5b5061039d6108c2366004614af9565b61220d565b3480156108d357600080fd5b5061042d61223f565b3480156108e857600080fd5b5061042d612257565b3480156108fd57600080fd5b5061042d612263565b34801561091257600080fd5b5061039d610921366004614af9565b61226f565b34801561093257600080fd5b5061039d610941366004614b13565b612389565b34801561095257600080fd5b5061039d610961366004614320565b6123dd565b34801561097257600080fd5b506103b461098136600461459c565b612449565b34801561099257600080fd5b5061039d6109a1366004614b73565b6124b6565b3480156109b257600080fd5b506103b46109c136600461497e565b612568565b6109ce6118a7565b6109f35760405162461bcd60e51b81526004016109ea906153a5565b60405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b601390565b60006060610a266118a7565b610a425760405162461bcd60e51b81526004016109ea906153a5565b856001600160a01b0316858585604051610a5d929190614ce6565b60006040518083038185875af1925050503d8060008114610a9a576040519150601f19603f3d011682016040523d82523d6000602084013e610a9f565b606091505b509097909650945050505050565b60006003610ab96118a7565b610b0857610ac681612592565b610ae25760405162461bcd60e51b81526004016109ea906152be565b610aeb816125da565b15610b085760405162461bcd60e51b81526004016109ea90615527565b600080610b248a610b1a8b60016157b2565b8b8b8a8a8d612621565b91955092509050610b5e6001600080886002811115610b5357634e487b7160e01b600052602160045260246000fd5b14158d8d8787612873565b5050509695505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610bae73f1209998bd17eae301a97e3cf7ec17df580e796461291d565b9695505050505050565b60006003610bc46118a7565b610c1357610bd181612592565b610bed5760405162461bcd60e51b81526004016109ea906152be565b610bf6816125da565b15610c135760405162461bcd60e51b81526004016109ea90615527565b610c1d8484612941565b610c2e308b8b8b8b8b8b8b8b612989565b9a9950505050505050505050565b610c446118a7565b610c605760405162461bcd60e51b81526004016109ea906153a5565b600180546001600160a01b0319169055565b6000610c7c6118a7565b610ccb57610c8981612592565b610ca55760405162461bcd60e51b81526004016109ea906152be565b610cae816125da565b15610ccb5760405162461bcd60e51b81526004016109ea90615527565b610cd58484612ef3565b610cdf8483612f19565b50505050565b610ced6118a7565b610d095760405162461bcd60e51b81526004016109ea906153a5565b600060026000836006811115610d2f57634e487b7160e01b600052602160045260246000fd5b815260208101919091526040016000208054909150600160a01b900460ff16610d6a5760405162461bcd60e51b81526004016109ea906154e2565b805460ff60a01b19168155816006811115610d9557634e487b7160e01b600052602160045260246000fd5b6040517fd9ff16dcccc040d408ddf47191ae2d5313510993b245b3a7ccfb0258a4401d7890600090a25050565b6004546001600160a01b031690565b6000610dde873388612f87565b600080610df089898a8a89898c612621565b91945092509050610e2960008080876002811115610e1e57634e487b7160e01b600052602160045260246000fd5b14158c8c8787612873565b610e333383612f19565b50509695505050505050565b6000600281805b81526020810191909152604001600020546001600160a01b0316919050565b6003546001600160a01b031690565b6000610e9373f1209998bd17eae301a97e3cf7ec17df580e796461291d565b9998505050505050505050565b6000806000610eb5883489886000898c613077565b91945092509050610eef6000600180876002811115610ee457634e487b7160e01b600052602160045260246000fd5b14158b348787612873565b505095945050505050565b610f026118a7565b610f1e5760405162461bcd60e51b81526004016109ea906153a5565b610f288282612f19565b5050565b60006002816005610e46565b6000610f5773f1209998bd17eae301a97e3cf7ec17df580e796461291d565b949350505050565b6000610f6b8383613329565b9392505050565b60006002816004610e46565b6060806006610f8b6118a7565b610fda57610f9881612592565b610fb45760405162461bcd60e51b81526004016109ea906152be565b610fbd816125da565b15610fda5760405162461bcd60e51b81526004016109ea90615527565b60405163c7cbc79960e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c7cbc79990611029908890600401614feb565b60206040518083038186803b15801561104157600080fd5b505afa158015611055573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611079919061494e565b9050806110985760405162461bcd60e51b81526004016109ea9061512f565b84516001600160401b038111156110bf57634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156110e8578160200160208202803683370190505b50935084516001600160401b0381111561111257634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561114557816020015b60608152602001906001900390816111305790505b506007805464ffffffff0019166472b272eb001790556040519093506000908190309063610f272160e11b9061117f908a90602401614feb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516111bd9190614cf6565b6000604051808303816000865af19150503d80600081146111fa576040519150601f19603f3d011682016040523d82523d6000602084013e6111ff565b606091505b509150915081611218576007805464ffffffff00191690555b60008180602001905181019061122e9190614659565b905060005b815181101561147157600089828151811061125e57634e487b7160e01b600052603260045260246000fd5b6020026020010151905082828151811061128857634e487b7160e01b600052603260045260246000fd5b6020026020010151600001518983815181106112b457634e487b7160e01b600052603260045260246000fd5b6020026020010190151590811515815250508282815181106112e657634e487b7160e01b600052603260045260246000fd5b60200260200101516020015188838151811061131257634e487b7160e01b600052603260045260246000fd5b602002602001018190525082828151811061133d57634e487b7160e01b600052603260045260246000fd5b602002602001015160000151156113d3577f26f13c2c104b2a1b3f0b1c6232d84f2bba70d231216636c3ceeebea631eb97dd8515826000015183602001516001600160601b031684604001518787815181106113a957634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516040516113c6959493929190615076565b60405180910390a161145e565b7f2007dedc5d6ba6b20b13bb9cbff9121300b36978bbac6fbbc5ccadaa1ff6c668816000015182602001516001600160601b0316836040015161144087878151811061142f57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151613426565b6040516114509493929190614e0a565b60405180910390a150611471565b50806114698161580d565b915050611233565b505050505050915091565b60608060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c7cbc79986866040518363ffffffff1660e01b81526004016114cf929190614f13565b60206040518083038186803b1580156114e757600080fd5b505afa1580156114fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151f919061494e565b9050836001600160401b0381111561154757634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611570578160200160208202803683370190505b509250836001600160401b0381111561159957634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156115cc57816020015b60608152602001906001900390816115b75790505b5091506000306001600160a01b031663afd6116b60e01b87876040516024016115f6929190614f13565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516116349190614cf6565b6000604051808303816000865af19150503d8060008114611671576040519150601f19603f3d011682016040523d82523d6000602084013e611676565b606091505b509150506000818060200190518101906116909190614659565b905060005b815181101561179a578181815181106116be57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001518682815181106116ea57634e487b7160e01b600052603260045260246000fd5b60200260200101901515908115158152505081818151811061171c57634e487b7160e01b600052603260045260246000fd5b60200260200101516020015185828151811061174857634e487b7160e01b600052603260045260246000fd5b602002602001018190525081818151811061177357634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516117885761179a565b806117928161580d565b915050611695565b5050509250925092565b6117ac6118a7565b6117c85760405162461bcd60e51b81526004016109ea906153a5565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031633146118145760405162461bcd60e51b81526004016109ea9061533a565b600180546001600160a01b03191690556000805460405133926001600160a01b03909216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03191633179055565b600061188f73f1209998bd17eae301a97e3cf7ec17df580e796461291d565b95945050505050565b6000546001600160a01b031690565b6000546001600160a01b0316331490565b600060036118c46118a7565b611913576118d181612592565b6118ed5760405162461bcd60e51b81526004016109ea906152be565b6118f6816125da565b156119135760405162461bcd60e51b81526004016109ea90615527565b6000806119268a8a8a8960018a8d613077565b91955092509050610b5e6001808088600281111561195457634e487b7160e01b600052602160045260246000fd5b14158d8d878d612873565b6000600361196b6118a7565b6119ba5761197881612592565b6119945760405162461bcd60e51b81526004016109ea906152be565b61199d816125da565b156119ba5760405162461bcd60e51b81526004016109ea90615527565b6119c383613671565b610c2e604051806101600160405280306001600160a01b031681526020018c6001600160a01b031681526020018b6001600160a01b031681526020018a81526020018a81526020018981526020018a81526020018881526020018781526020018615158152602001856002811115611a4b57634e487b7160e01b600052602160045260246000fd5b90526136b1565b60006003611a5e6118a7565b611aad57611a6b81612592565b611a875760405162461bcd60e51b81526004016109ea906152be565b611a90816125da565b15611aad5760405162461bcd60e51b81526004016109ea90615527565b610e9389898989898960018a613b47565b6000806000732cf7c0333d9b7f94bbf55b9701227e359f92fd316001600160a01b0316604051611aed90614d58565b600060405180830381855afa9150503d8060008114611b28576040519150601f19603f3d011682016040523d82523d6000602084013e611b2d565b606091505b5091509150818015611b40575080516020145b611b5c5760405162461bcd60e51b81526004016109ea906153ed565b80806020019051810190611b70919061433c565b9250505090565b6000611b816118a7565b611bd057611b8e81612592565b611baa5760405162461bcd60e51b81526004016109ea906152be565b611bb3816125da565b15611bd05760405162461bcd60e51b81526004016109ea90615527565b611bda8585612ef3565b611be5838684613b72565b5050505050565b606081516001600160401b03811115611c1557634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611c4e57816020015b611c3b61429e565b815260200190600190039081611c335790505b50905060005b8251811015611dad57600080848381518110611c8057634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b0316858481518110611cb557634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516001600160601b0316868581518110611cea57634e487b7160e01b600052603260045260246000fd5b602002602001015160400151604051611d039190614cf6565b60006040518083038185875af1925050503d8060008114611d40576040519150601f19603f3d011682016040523d82523d6000602084013e611d45565b606091505b50915091506040518060400160405280831515815260200182815250848481518110611d8157634e487b7160e01b600052603260045260246000fd5b602002602001018190525081611d98575050611dad565b50508080611da59061580d565b915050611c54565b50600081604051602001611dc19190614ea0565b6040516020818303038152906040529050805181602001fd5b6000611de582612592565b92915050565b6000611de5826125da565b6060611e086372b272eb60e01b613c60565b600082516001600160401b03811115611e3157634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611e6a57816020015b611e5761429e565b815260200190600190039081611e4f5790505b50915060005b8351811015611fcd57600080858381518110611e9c57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b0316868481518110611ed157634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516001600160601b0316878581518110611f0657634e487b7160e01b600052603260045260246000fd5b602002602001015160400151604051611f1f9190614cf6565b60006040518083038185875af1925050503d8060008114611f5c576040519150601f19603f3d011682016040523d82523d6000602084013e611f61565b606091505b50915091506040518060400160405280831515815260200182815250858481518110611f9d57634e487b7160e01b600052603260045260246000fd5b602002602001018190525081611fb857600193505050611fcd565b50508080611fc59061580d565b915050611e70565b508015611fe757600082604051602001611dc19190614ea0565b50919050565b6002611ff76118a7565b6120465761200481612592565b6120205760405162461bcd60e51b81526004016109ea906152be565b612029816125da565b156120465760405162461bcd60e51b81526004016109ea90615527565b6003546001600160a01b03168061206f5760405162461bcd60e51b81526004016109ea9061549b565b61208e736b175474e89094c44da98b954eedeac495271d0f8285613b72565b505050565b600060028181610e46565b60006120aa8383612941565b6120b5893389612f87565b610e93338a8a8a8a8a8a8a8a612989565b60026120d06118a7565b61211f576120dd81612592565b6120f95760405162461bcd60e51b81526004016109ea906152be565b612102816125da565b1561211f5760405162461bcd60e51b81526004016109ea90615527565b6004546001600160a01b0316806121485760405162461bcd60e51b81526004016109ea90615619565b61208e73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488285613b72565b60006121716118a7565b61218d5760405162461bcd60e51b81526004016109ea906153a5565b60405163a9059cbb60e01b81526001600160a01b0385169063a9059cbb906121bb9086908690600401614df1565b602060405180830381600087803b1580156121d557600080fd5b505af11580156121e9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f57919061494e565b6122156118a7565b6122315760405162461bcd60e51b81526004016109ea906153a5565b61223c816000613cb2565b50565b730efb068354c10c070ddd64a0e8eaf8f054df7e2690565b60006002816006610e46565b60006002816003610e46565b60046122796118a7565b6122c85761228681612592565b6122a25760405162461bcd60e51b81526004016109ea906152be565b6122ab816125da565b156122c85760405162461bcd60e51b81526004016109ea90615527565b6000600260008460068111156122ee57634e487b7160e01b600052602160045260246000fd5b815260208101919091526040016000208054909150600160a01b900460ff161561232a5760405162461bcd60e51b81526004016109ea9061556c565b805460ff60a01b1916600160a01b17815582600681111561235b57634e487b7160e01b600052602160045260246000fd5b6040517fad75709c5a2559beeed6c59693a5ea8701185d51947d3eef38713bb0fe5891e990600090a2505050565b6123916118a7565b6123ad5760405162461bcd60e51b81526004016109ea906153a5565b6001600160a01b0381166123d35760405162461bcd60e51b81526004016109ea90615303565b610f288282613cb2565b6123e56118a7565b6124015760405162461bcd60e51b81526004016109ea906153a5565b6001600160a01b0381166124275760405162461bcd60e51b81526004016109ea90615661565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b600060036124556118a7565b6124a45761246281612592565b61247e5760405162461bcd60e51b81526004016109ea906152be565b612487816125da565b156124a45760405162461bcd60e51b81526004016109ea90615527565b600080610b248a8a8b8b8a8a8d612621565b60056124c06118a7565b61250f576124cd81612592565b6124e95760405162461bcd60e51b81526004016109ea906152be565b6124f2816125da565b1561250f5760405162461bcd60e51b81526004016109ea90615527565b61252d7355f2039347564d206ccc6e6ce202853fed386dbf83612f19565b7f70c14fa013d428be746414c53915d6af2495865a3687262ce430049e977d50c58260405161255c91906156be565b60405180910390a15050565b600061258773f1209998bd17eae301a97e3cf7ec17df580e796461291d565b979650505050505050565b6000600260008360068111156125b857634e487b7160e01b600052602160045260246000fd5b81526020810191909152604001600020546001600160a01b0316331492915050565b60006002600083600681111561260057634e487b7160e01b600052602160045260246000fd5b8152602081019190915260400160002054600160a01b900460ff1692915050565b60008080808086600281111561264757634e487b7160e01b600052602160045260246000fd5b141561266c57846126588b8b613d74565b61266291906157ca565b9050849150612679565b6126768a8a613d74565b90505b6126838b8b613d8a565b6000806126a68d73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc260006140ad565b915091508a8c141561278257737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b03166318cbafe5848c85308e6040518663ffffffff1660e01b81526004016126fa9594939291906156fc565b600060405180830381600087803b15801561271457600080fd5b505af1158015612728573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261275091908101906148bf565b90508060018151811061277357634e487b7160e01b600052603260045260246000fd5b60200260200101519550612811565b6000479050737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663791ac947858d86308f6040518663ffffffff1660e01b81526004016127cf9594939291906156fc565b600060405180830381600087803b1580156127e957600080fd5b505af11580156127fd573d6000803e3d6000fd5b50505050804761280d91906157ca565b9650505b600088600281111561283357634e487b7160e01b600052602160045260246000fd5b1461285f5761284c6128458b886157ca565b8890613d74565b935061285884876157ca565b9450612863565b8594505b5050509750975097945050505050565b7f8d4e5e4cf68c4b7be730141ed4b1c725966c0e1df450c1a01b965afa060fa3e08761289f57336128a1565b305b876128ac57856128af565b60005b886128bb5760006128bd565b865b886128f3576001600160a01b03888116146128d857876128ee565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb485b6128f6565b60005b87878760405161290c9796959493929190614d89565b60405180910390a150505050505050565b3660008037600080366000845af43d6000803e80801561293c573d6000f35b3d6000fd5b818061296d5750600281600281111561296a57634e487b7160e01b600052602160045260246000fd5b14155b610f285760405162461bcd60e51b81526004016109ea90615253565b6000806000806129998c8b613d8a565b6001600160a01b038b811614156129c5575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486129c8565b50895b85612b55576000806129dc8e8460006140ad565b9092509050737a250d5630b4cf539739df2c5dacb4c659f2488d6338ed17396000896002811115612a1d57634e487b7160e01b600052602160045260246000fd5b14612a28578d612a32565b612a328c8f6157ca565b8d85308e6040518663ffffffff1660e01b8152600401612a569594939291906156fc565b600060405180830381600087803b158015612a7057600080fd5b505af1158015612a84573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612aac91908101906148bf565b905080600181518110612acf57634e487b7160e01b600052603260045260246000fd5b6020026020010151955060016002811115612afa57634e487b7160e01b600052602160045260246000fd5b876002811115612b1a57634e487b7160e01b600052602160045260246000fd5b1415612b4757612b34612b2d8c886157ca565b8b90613d74565b9450612b4085876157ca565b9350612b4e565b8994508593505b5050612e32565b600080612b788e73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc260006140ad565b9092509050737a250d5630b4cf539739df2c5dacb4c659f2488d6338ed17396000896002811115612bb957634e487b7160e01b600052602160045260246000fd5b14612bc4578d612bce565b612bce8c8f6157ca565b60028a6002811115612bf057634e487b7160e01b600052602160045260246000fd5b14612bfc576001612bfe565b8c5b85308e6040518663ffffffff1660e01b8152600401612c219594939291906156fc565b600060405180830381600087803b158015612c3b57600080fd5b505af1158015612c4f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612c7791908101906148bf565b905080600181518110612c9a57634e487b7160e01b600052603260045260246000fd5b60200260200101519450612cc473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28460006140ad565b9092509050737a250d5630b4cf539739df2c5dacb4c659f2488d6338ed17396002896002811115612d0557634e487b7160e01b600052602160045260246000fd5b14612d105786612d1a565b612d1a8c886157ca565b8d85308e6040518663ffffffff1660e01b8152600401612d3e9594939291906156fc565b600060405180830381600087803b158015612d5857600080fd5b505af1158015612d6c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d9491908101906148bf565b905080600181518110612db757634e487b7160e01b600052603260045260246000fd5b6020026020010151955060016002811115612de257634e487b7160e01b600052602160045260246000fd5b876002811115612e0257634e487b7160e01b600052602160045260246000fd5b1415612e2857612e15612b2d8c886157ca565b9450612e2185876157ca565b9350612e2f565b8994508593505b50505b612eb18d8d8d6002896002811115612e5a57634e487b7160e01b600052602160045260246000fd5b14612e93576001896002811115612e8157634e487b7160e01b600052602160045260246000fd5b14612e8c578f612e8e565b845b612ea9565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b8e8789614263565b6001600160a01b038d163014801590612ed357506001600160a01b038b811614155b15612ee357612ee3818e84613b72565b5050509998505050505050505050565b612efd8282613329565b610f285760405162461bcd60e51b81526004016109ea906150d2565b6000826001600160a01b031682604051612f3290614d58565b60006040518083038185875af1925050503d8060008114612f6f576040519150601f19603f3d011682016040523d82523d6000602084013e612f74565b606091505b505090508061208e573d6000803e3d6000fd5b600080846001600160a01b03166323b872dd60e01b853086604051602401612fb193929190614dcd565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612fef9190614cf6565b6000604051808303816000865af19150503d806000811461302c576040519150601f19603f3d011682016040523d82523d6000602084013e613031565b606091505b509150915081801561305b57508051158061305b57508080602001905181019061305b919061494e565b611be55760405162461bcd60e51b81526004016109ea9061515f565b6040805160028082526060820183526000928392839283928392919060208301908036833701905050905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2816000815181106130d857634e487b7160e01b600052603260045260246000fd5b6001600160a01b0392831660209182029290920101528c811614156131555773a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488160018151811061312d57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250503091506131a7565b8b8160018151811061317757634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b031681525050876131a257336131a4565b305b91505b604080516002808252606082018352600092602083019080368337019050509050737a250d5630b4cf539739df2c5dacb4c659f2488d637ff36ab560018a600281111561320457634e487b7160e01b600052602160045260246000fd5b1415613210578d61321a565b61321a898f6157ca565b8d85878f6040518663ffffffff1660e01b815260040161323d94939291906156c7565b6000604051808303818588803b15801561325657600080fd5b505af115801561326a573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405261329391908101906148bf565b9050806001815181106132b657634e487b7160e01b600052603260045260246000fd5b60200260200101519550600160028111156132e157634e487b7160e01b600052602160045260246000fd5b88600281111561330157634e487b7160e01b600052602160045260246000fd5b14156133145761284c6128458c886157ca565b50939b8c9b5094995093975050505050505050565b600080604051806104c001604052806104928152602001615878610492913960405161335d91908590600090602001614d12565b60408051601f19818403018152919052805160209091012090506000805b600a81101561341a576040516133b9907ffffc00c80b0000007f73004edb00094cad80626d8d00000000000000000000009083908690602001614cc0565b6040516020818303038152906040528051906020012060001c9150856001600160a01b0316826001600160a01b031614156133fa5760019350505050611de5565b806134048161580d565b91505080806134129061580d565b91505061337b565b50600095945050505050565b60606044825111801561346c57508151600160fb1b90839060009061345b57634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916145b80156134ad5750815160c360f81b908390600190811061349c57634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916145b80156134ee57508151607960f81b90839060029081106134dd57634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916145b801561352f57508151600560fd1b908390600390811061351e57634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916145b156136415760006004835161354491906157ca565b6001600160401b0381111561356957634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015613593576020820181803683370190505b50905060045b8351811015613624578381815181106135c257634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916826135dd6004846157ca565b815181106135fb57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053508061361c8161580d565b915050613599565b50808060200190518101906136399190614b2e565b91505061366c565b50604080518082019091526012815271286e6f2072657665727420726561736f6e2960701b60208201525b919050565b600281600281111561369357634e487b7160e01b600052602160045260246000fd5b141561223c5760405162461bcd60e51b81526004016109ea906151f6565b6000806001600160a01b03801683604001516001600160a01b0316146136db5782604001516136f1565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb485b905061370583602001518460800151613d8a565b600061371b8460200151838661012001516140ad565b5090506000826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161374c9190614d5b565b60206040518083038186803b15801561376457600080fd5b505afa158015613778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379c9190614b8b565b9050737a250d5630b4cf539739df2c5dacb4c659f2488d635c11d795600087610140015160028111156137df57634e487b7160e01b600052602160045260246000fd5b146137ee578660800151613802565b8660e00151876080015161380291906157ca565b8760a0015185308a61010001516040518663ffffffff1660e01b815260040161382f9594939291906156fc565b600060405180830381600087803b15801561384957600080fd5b505af115801561385d573d6000803e3d6000fd5b50506040516370a0823160e01b81528392506001600160a01b03861691506370a082319061388f903090600401614d5b565b60206040518083038186803b1580156138a757600080fd5b505afa1580156138bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138df9190614b8b565b6138e991906157ca565b8551909450600092506001600160a01b0316301480159150613919575060408401516001600160a01b0390811614155b15613aa25783516040516370a0823160e01b81526000916001600160a01b038516916370a082319161394d91600401614d5b565b60206040518083038186803b15801561396557600080fd5b505afa158015613979573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399d9190614b8b565b85519091506139ee908490600188610140015160028111156139cf57634e487b7160e01b600052602160045260246000fd5b146139da57866139e9565b60e08801516139e990886157ca565b613b72565b84516040516370a0823160e01b815282916001600160a01b038616916370a0823191613a1c91600401614d5b565b60206040518083038186803b158015613a3457600080fd5b505afa158015613a48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a6c9190614b8b565b613a7691906157ca565b9150508360c00151811015613a9d5760405162461bcd60e51b81526004016109ea906155af565b613ae6565b60018461014001516002811115613ac957634e487b7160e01b600052602160045260246000fd5b14613ad45782613ae3565b60e0840151613ae390846157ca565b90505b835160208501516040860151613b4092919060018861014001516002811115613b1f57634e487b7160e01b600052602160045260246000fd5b14613b2e578760200151613b30565b855b8860600151868a60e00151614263565b5050919050565b6000613b6673f1209998bd17eae301a97e3cf7ec17df580e796461291d565b98975050505050505050565b600080846001600160a01b031663a9059cbb60e01b8585604051602401613b9a929190614df1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613bd89190614cf6565b6000604051808303816000865af19150503d8060008114613c15576040519150601f19603f3d011682016040523d82523d6000602084013e613c1a565b606091505b5091509150818015613c44575080511580613c44575080806020019051810190613c44919061494e565b611be55760405162461bcd60e51b81526004016109ea90615424565b3330148015613c8557506007546001600160e01b031982811661010090920460e01b16145b613ca15760405162461bcd60e51b81526004016109ea9061518c565b506007805464ffffffff0019169055565b600060026000846006811115613cd857634e487b7160e01b600052602160045260246000fd5b8152602081019190915260400160002080549091506001600160a01b0383811691161461208e5780546001600160a01b0319166001600160a01b038316178155826006811115613d3857634e487b7160e01b600052602160045260246000fd5b7f40ab465936efb8324cf37e3a29170c60d9b81de43af89693ce9d92c761e42adc83604051613d679190614d5b565b60405180910390a2505050565b6000818310613d835781610f6b565b5090919050565b604051636eb1769f60e11b815281906001600160a01b0384169063dd62ed3e90613dce903090737a250d5630b4cf539739df2c5dacb4c659f2488d90600401614d6f565b60206040518083038186803b158015613de657600080fd5b505afa158015613dfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1e9190614b8b565b1015610f2857600080836001600160a01b031663095ea7b360e01b737a250d5630b4cf539739df2c5dacb4c659f2488d6000604051602401613e61929190614df1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613e9f9190614cf6565b6000604051808303816000865af19150503d8060008114613edc576040519150601f19603f3d011682016040523d82523d6000602084013e613ee1565b606091505b5091509150836001600160a01b031663095ea7b360e01b737a250d5630b4cf539739df2c5dacb4c659f2488d600019604051602401613f21929190614df1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613f5f9190614cf6565b6000604051808303816000865af19150503d8060008114613f9c576040519150601f19603f3d011682016040523d82523d6000602084013e613fa1565b606091505b5090925090508161406c57836001600160a01b031663095ea7b360e01b737a250d5630b4cf539739df2c5dacb4c659f2488d85604051602401613fe5929190614df1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516140239190614cf6565b6000604051808303816000865af19150503d8060008114614060576040519150601f19603f3d011682016040523d82523d6000602084013e614065565b606091505b5090925090505b818015614091575080511580614091575080806020019051810190614091919061494e565b610cdf5760405162461bcd60e51b81526004016109ea90615452565b6060806000836140be5760026140c1565b60035b60ff1690506000816001600160401b038111156140ee57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015614117578160200160208202803683370190505b509050868160008151811061413c57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b03168152505084156141b95773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28160018151811061419857634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250505b85816141c66001856157ca565b815181106141e457634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b03168152505080826001600160401b0381111561422b57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015614254578160200160208202803683370190505b50935093505050935093915050565b7f8d4e5e4cf68c4b7be730141ed4b1c725966c0e1df450c1a01b965afa060fa3e08787878787878760405161290c9796959493929190614d89565b60408051808201909152600081526060602082015290565b60006142c96142c48461578b565b615738565b90508281528383830111156142dd57600080fd5b610f6b8360208301846157e1565b80356003811061366c57600080fd5b80356007811061366c57600080fd5b80356001600160601b038116811461366c57600080fd5b600060208284031215614331578081fd5b8135610f6b81615854565b60006020828403121561434d578081fd5b8151610f6b81615854565b60008060006060848603121561436c578182fd5b833561437781615854565b9250602084013561438781615854565b929592945050506040919091013590565b600080604083850312156143aa578182fd5b82356143b581615854565b946020939093013593505050565b600080600080606085870312156143d8578182fd5b84356143e381615854565b93506020850135925060408501356001600160401b0380821115614405578384fd5b818701915087601f830112614418578384fd5b813581811115614426578485fd5b886020828501011115614437578485fd5b95989497505060200194505050565b60008060408385031215614458578182fd5b823561446381615854565b9150602083013561447381615854565b809150509250929050565b60008060008060808587031215614493578182fd5b843561449e81615854565b935060208501356144ae81615854565b925060408501356144be81615854565b9396929550929360600135925050565b600080600080608085870312156144e3578182fd5b84356144ee81615854565b966020860135965060408601359560600135945092505050565b600080600080600060a0868803121561451f578283fd5b853561452a81615854565b945060208601359350604086013592506060860135915061454d608087016142eb565b90509295509295909350565b600080600080600060a08688031215614570578283fd5b853561457b81615854565b97602087013597506040870135966060810135965060800135945092505050565b60008060008060008060c087890312156145b4578384fd5b86356145bf81615854565b9550602087013594506040870135935060608701359250608087013591506145e960a088016142eb565b90509295509295509295565b600080600080600080600060e0888a03121561460f578485fd5b873561461a81615854565b96506020880135955060408801359450606088013593506080880135925060a0880135915061464b60c089016142eb565b905092959891949750929550565b6000602080838503121561466b578182fd5b82516001600160401b0380821115614681578384fd5b818501915085601f830112614694578384fd5b81516146a26142c482615768565b81815284810190848601875b848110156147325781518701604080601f19838f030112156146ce578a8bfd5b6146d781615738565b8a8301516146e481615869565b815282820151898111156146f6578c8dfd5b8084019350508d603f84011261470a578b8cfd5b61471a8e8c8501518486016142b6565b818c01528652505092870192908701906001016146ae565b50909998505050505050505050565b60008060208385031215614753578182fd5b82356001600160401b0380821115614769578384fd5b818501915085601f83011261477c578384fd5b81358181111561478a578485fd5b866020808302850101111561479d578485fd5b60209290920196919550909350505050565b600060208083850312156147c1578182fd5b82356001600160401b03808211156147d7578384fd5b818501915085601f8301126147ea578384fd5b81356147f86142c482615768565b81815284810190848601875b848110156147325781358701606080601f19838f03011215614824578a8bfd5b61482d81615738565b8a83013561483a81615854565b81526040614849848201614309565b828d015291830135918983111561485e578c8dfd5b82840193508e603f850112614871578c8dfd5b8b84013592506148836142c48461578b565b8381528f82858701011115614896578d8efd5b838286018e8301379283018c018d90528101919091528552509287019290870190600101614804565b600060208083850312156148d1578182fd5b82516001600160401b038111156148e6578283fd5b8301601f810185136148f6578283fd5b80516149046142c482615768565b8181528381019083850185840285018601891015614920578687fd5b8694505b83851015614942578051835260019490940193918501918501614924565b50979650505050505050565b60006020828403121561495f578081fd5b8151610f6b81615869565b60008060006060848603121561436c578081fd5b600080600080600080600060e0888a031215614998578081fd5b87356149a381615854565b965060208801356149b381615854565b955060408801359450606088013593506080880135925060a0880135915060c08801356149df81615869565b8091505092959891949750929550565b600080600080600080600080610100898b031215614a0b578182fd5b8835614a1681615854565b97506020890135614a2681615854565b965060408901359550606089013594506080890135935060a0890135925060c0890135614a5281615869565b9150614a6060e08a016142eb565b90509295985092959890939650565b60008060008060008060008060006101208a8c031215614a8d578283fd5b8935614a9881615854565b985060208a0135614aa881615854565b975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a0135614adb81615869565b9150614aea6101008b016142eb565b90509295985092959850929598565b600060208284031215614b0a578081fd5b610f6b826142fa565b60008060408385031215614b25578182fd5b614463836142fa565b600060208284031215614b3f578081fd5b81516001600160401b03811115614b54578182fd5b8201601f81018413614b64578182fd5b610f57848251602084016142b6565b600060208284031215614b84578081fd5b5035919050565b600060208284031215614b9c578081fd5b5051919050565b6000815180845260208085019450808401835b83811015614bdb5781516001600160a01b031687529582019590820190600101614bb6565b509495945050505050565b6000815180845260208085019450808401835b83811015614bdb578151151587529582019590820190600101614bf9565b6000815180845260208085018081965082840281019150828601855b85811015614c5d578284038952614c4b848351614c94565b98850198935090840190600101614c33565b5091979650505050505050565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b60008151808452614cac8160208601602086016157e1565b601f01601f19169290920160200192915050565b6affffffffffffffffffffff199390931683526015830191909152603582015260550190565b6000828483379101908152919050565b60008251614d088184602087016157e1565b9190910192915050565b60008451614d248184602089016157e1565b60609490941b6bffffffffffffffffffffffff19169190930190815263ffffffff1991909116601482015260300192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03978816815295871660208701529386166040860152919094166060840152608083019390935260a082019290925260c081019190915260e00190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b600060018060a01b038616825284602083015260806040830152614e316080830185614c94565b82810360608401526125878185614c94565b600060408252614e566040830185614be6565b828103602084015261188f8185614c17565b600060608252614e7b6060830186614be6565b8281036020840152614e8d8186614c17565b9150508215156040830152949350505050565b60208082528251828201819052600091906040908185019080840286018301878501865b83811015614f0557888303603f190185528151805115158452870151878401879052614ef287850182614c94565b9588019593505090860190600101614ec4565b509098975050505050505050565b602080825281810183905260009060408084018583028501820187855b88811015614f0557878303603f190184528135368b9003605e19018112614f55578788fd5b8a0160608135614f6481615854565b6001600160a01b031685526001600160601b03614f82838a01614309565b168886015286820135601e19833603018112614f9c57898afd5b820180356001600160401b03811115614fb3578a8bfd5b803603841315614fc1578a8bfd5b8289880152614fd5838801828c8501614c6a565b978a019796505050928701925050600101614f30565b60208082528251828201819052600091906040908185019080840286018301878501865b83811015614f0557888303603f19018552815180516001600160a01b03168452878101516001600160601b031688850152860151606087850181905261505781860183614c94565b96890196945050509086019060010161500f565b901515815260200190565b6000861515825260018060a01b038616602083015284604083015260a060608301526150a560a0830185614c94565b8281036080840152613b668185614c94565b6000831515825260406020830152610f576040830184614c94565b6020808252603a908201527f436f756c64206e6f74207265736f6c766520736d6172742077616c6c6574207560408201527f73696e672070726f7669646564207369676e696e67206b65792e000000000000606082015260800190565b602080825260169082015275496e76616c69642063616c6c2064657465637465642160501b604082015260600190565b6020808252601390820152722a3930b739b332b91034b7103330b4b632b21760691b604082015260600190565b60208082526044908201527f45787465726e616c206163636f756e7473206f7220756e617070726f7665642060408201527f696e7465726e616c2066756e6374696f6e732063616e6e6f742063616c6c20746060820152633434b99760e11b608082015260a00190565b6020808252603e908201527f43616e6e6f742074616b6520746f6b656e2d666f722d746f6b656e206665652060408201527f696e204574686572207769746820666565206f6e207472616e736665722e0000606082015260800190565b60208082526045908201527f43616e6e6f742074616b6520746f6b656e2d666f722d746f6b656e206665652060408201527f696e20457468657220756e6c65737320726f75746564207468726f75676820456060820152643a3432b91760d91b608082015260a00190565b60208082526025908201527f43616c6c657220646f6573206e6f7420686176652061207265717569726564206040820152643937b6329760d91b606082015260800190565b60208082526017908201527f4d75737420737570706c7920616e206163636f756e742e000000000000000000604082015260600190565b60208082526045908201527f54776f537465704f776e61626c653a2063757272656e74206f776e6572206d7560408201527f7374207365742063616c6c6572206173206e657720706f74656e7469616c206f6060820152643bb732b91760d91b608082015260a00190565b60208082526028908201527f54776f537465704f776e61626c653a2063616c6c6572206973206e6f74207468604082015267329037bbb732b91760c11b606082015260800190565b60208082526017908201527f496e76616c696420696d706c656d656e746174696f6e2e000000000000000000604082015260600190565b6020808252601490820152732a3930b739b332b91037baba103330b4b632b21760611b604082015260600190565b60208082526029908201527f546f6b656e20617070726f76616c20666f7220556e697377617020726f75746560408201526839103330b4b632b21760b91b606082015260800190565b60208082526027908201527f4e6f20446169207072696d61727920726563697069656e742063757272656e74604082015266363c9039b2ba1760c91b606082015260800190565b60208082526025908201527f526f6c6520696e207175657374696f6e20697320616c726561647920756e70616040820152643ab9b2b21760d91b606082015260800190565b60208082526025908201527f526f6c6520696e207175657374696f6e2069732063757272656e746c792070616040820152643ab9b2b21760d91b606082015260800190565b60208082526023908201527f526f6c6520696e207175657374696f6e20697320616c7265616479207061757360408201526232b21760e91b606082015260800190565b60208082526044908201527f526563656976656420746f6b656e20616d6f756e74206166746572207472616e60408201527f7366657220666565206973206c657373207468616e2071756f74656420616d6f6060820152633ab73a1760e11b608082015260a00190565b60208082526028908201527f4e6f2055534443207072696d61727920726563697069656e742063757272656e6040820152673a363c9039b2ba1760c11b606082015260800190565b60208082526038908201527f54776f537465704f776e61626c653a206e657720706f74656e7469616c206f7760408201527f6e657220697320746865207a65726f20616464726573732e0000000000000000606082015260800190565b90815260200190565b6000858252608060208301526156e06080830186614ba3565b6001600160a01b03949094166040830152506060015292915050565b600086825285602083015260a0604083015261571b60a0830186614ba3565b6001600160a01b0394909416606083015250608001529392505050565b604051601f8201601f191681016001600160401b03811182821017156157605761576061583e565b604052919050565b60006001600160401b038211156157815761578161583e565b5060209081020190565b60006001600160401b038211156157a4576157a461583e565b50601f01601f191660200190565b600082198211156157c5576157c5615828565b500190565b6000828210156157dc576157dc615828565b500390565b60005b838110156157fc5781810151838201526020016157e4565b83811115610cdf5750506000910152565b600060001982141561582157615821615828565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461223c57600080fd5b801515811461223c57600080fdfe60806040526040516104423803806104428339818101604052602081101561002657600080fd5b810190808051604051939291908464010000000082111561004657600080fd5b90830190602082018581111561005b57600080fd5b825164010000000081118282018810171561007557600080fd5b82525081516020918201929091019080838360005b838110156100a257818101518382015260200161008a565b50505050905090810190601f1680156100cf5780820380516001836020036101000a031916815260200191505b5060405250505060006100e661019e60201b60201c565b6001600160a01b0316826040518082805190602001908083835b6020831061011f5780518252601f199092019160209182019101610100565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461017f576040519150601f19603f3d011682016040523d82523d6000602084013e610184565b606091505b5050905080610197573d6000803e3d6000fd5b50506102be565b60405160009081906060906e26750c571ce882b17016557279adaa9083818181855afa9150503d80600081146101f0576040519150601f19603f3d011682016040523d82523d6000602084013e6101f5565b606091505b509150915081819061029f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561026457818101518382015260200161024c565b50505050905090810190601f1680156102915780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b508080602001905160208110156102b557600080fd5b50519392505050565b610175806102cd6000396000f3fe608060405261001461000f610016565b61011c565b005b60405160009081906060906e26750c571ce882b17016557279adaa9083818181855afa9150503d8060008114610068576040519150601f19603f3d011682016040523d82523d6000602084013e61006d565b606091505b50915091508181906100fd5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156100c25781810151838201526020016100aa565b50505050905090810190601f1680156100ef5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5080806020019051602081101561011357600080fd5b50519392505050565b3660008037600080366000845af43d6000803e80801561013b573d6000f35b3d6000fdfea265627a7a7231582020202020202055706772616465426561636f6e50726f7879563120202020202064736f6c634300050b003200000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024c4d66de8000000000000000000000000a2646970667358221220784b1cc3f6622b5c7aae2f03aa8870aed35115d5feb5040157029b0dff2d8f2364736f6c63430008010033000000000000000000000000c982ee89bc9395c8bb470f9816bee3a257bb1e9b

Deployed Bytecode

0x6080604052600436106103385760003560e01c80638f32d59b116101ab578063c6102aa8116100f7578063eb68b08a11610095578063f2fde38b1161006f578063f2fde38b14610946578063f495018714610966578063f816c0fa14610986578063f97086f6146109a657610378565b8063eb68b08a146108f1578063edf07f1514610906578063f2e12a391461092657610378565b8063d9caed12116100d1578063d9caed1214610887578063dab41d0d146108a7578063de7b5d14146108c7578063e20ed9d2146108dc57610378565b8063c6102aa814610832578063c90418b414610847578063cef0a6041461086757610378565b8063afd6116b11610164578063bb6033201161013e578063bb603320146107b2578063bc61e733146107d2578063c21e4e42146107f2578063c54d559e1461081257610378565b8063afd6116b1461075c578063b1f2aa6714610789578063badafb37146107a457610378565b80638f32d59b146106b25780639b86f0ef146106c7578063a0a6d75f146106e7578063a735559614610707578063aaf10f4214610727578063aeed28611461073c57610378565b8063329504da116102855780637008b5481161022357806378a967aa116101fd57806378a967aa1461064857806379ba5097146106685780638218a8e91461067d5780638da5cb5b1461069d57610378565b80637008b548146105d657806372b272eb146105eb5780637787c5871461061957610378565b8063522f68151161025f578063522f6815146105545780635ce4a04914610574578063618fdbb0146105895780636b309696146105a957610378565b8063329504da1461050c5780633efa667e146105215780634d0757eb1461054157610378565b806321a012ec116102f2578063301c7e5d116102cc578063301c7e5d146104a25780633059d1d3146104c257806331ab6d2a146104d757806331ae1f02146104f757610378565b806321a012ec1461044d57806323452b9c1461046d5780632e5cd5f31461048257610378565b806263f2fb1461037d5780630d8e6e2c1461039f57806312e6bf6a146103ca57806312fd415a146103f8578063153f92eb1461041857806318b93e461461043a57610378565b36610378577f1e57e3bb474320be3d2c77138f75b7c3941292d647f5f9634e33a8e94e0e069b333460405161036e929190614df1565b60405180910390a1005b600080fd5b34801561038957600080fd5b5061039d610398366004614320565b6109c6565b005b3480156103ab57600080fd5b506103b4610a15565b6040516103c191906156be565b60405180910390f35b3480156103d657600080fd5b506103ea6103e53660046143c3565b610a1a565b6040516103c19291906150b7565b34801561040457600080fd5b506103b461041336600461459c565b610aad565b34801561042457600080fd5b5061042d610b6b565b6040516103c19190614d5b565b6103b461044836600461459c565b610b8f565b34801561045957600080fd5b506103b46104683660046149ef565b610bb8565b34801561047957600080fd5b5061039d610c3c565b34801561048e57600080fd5b5061039d61049d366004614358565b610c72565b3480156104ae57600080fd5b5061039d6104bd366004614af9565b610ce5565b3480156104ce57600080fd5b5061042d610dc2565b3480156104e357600080fd5b506103b46104f236600461459c565b610dd1565b34801561050357600080fd5b5061042d610e3f565b34801561051857600080fd5b5061042d610e65565b34801561052d57600080fd5b506103b461053c366004614a6f565b610e74565b6103b461054f366004614508565b610ea0565b34801561056057600080fd5b5061039d61056f366004614398565b610efa565b34801561058057600080fd5b5061042d610f2c565b34801561059557600080fd5b506103b46105a43660046144ce565b610f38565b3480156105b557600080fd5b506105c96105c4366004614446565b610f5f565b6040516103c1919061506b565b3480156105e257600080fd5b5061042d610f72565b3480156105f757600080fd5b5061060b6106063660046147af565b610f7e565b6040516103c1929190614e43565b34801561062557600080fd5b50610639610634366004614741565b61147c565b6040516103c193929190614e68565b34801561065457600080fd5b5061039d610663366004614320565b6117a4565b34801561067457600080fd5b5061039d6117ea565b34801561068957600080fd5b506103b4610698366004614559565b611870565b3480156106a957600080fd5b5061042d611898565b3480156106be57600080fd5b506105c96118a7565b3480156106d357600080fd5b506103b46106e236600461459c565b6118b8565b3480156106f357600080fd5b506103b46107023660046149ef565b61195f565b34801561071357600080fd5b506103b46107223660046145f5565b611a52565b34801561073357600080fd5b5061042d611abe565b34801561074857600080fd5b5061039d61075736600461447e565b611b77565b34801561076857600080fd5b5061077c6107773660046147af565b611bec565b6040516103c19190614ea0565b34801561079557600080fd5b506103b461044836600461459c565b6103b46105a43660046144ce565b3480156107be57600080fd5b506105c96107cd366004614af9565b611dda565b3480156107de57600080fd5b506105c96107ed366004614af9565b611deb565b3480156107fe57600080fd5b5061077c61080d3660046147af565b611df6565b34801561081e57600080fd5b5061039d61082d366004614b73565b611fed565b34801561083e57600080fd5b5061042d612093565b34801561085357600080fd5b506103b46108623660046149ef565b61209e565b34801561087357600080fd5b5061039d610882366004614b73565b6120c6565b34801561089357600080fd5b506105c96108a236600461496a565b612167565b3480156108b357600080fd5b5061039d6108c2366004614af9565b61220d565b3480156108d357600080fd5b5061042d61223f565b3480156108e857600080fd5b5061042d612257565b3480156108fd57600080fd5b5061042d612263565b34801561091257600080fd5b5061039d610921366004614af9565b61226f565b34801561093257600080fd5b5061039d610941366004614b13565b612389565b34801561095257600080fd5b5061039d610961366004614320565b6123dd565b34801561097257600080fd5b506103b461098136600461459c565b612449565b34801561099257600080fd5b5061039d6109a1366004614b73565b6124b6565b3480156109b257600080fd5b506103b46109c136600461497e565b612568565b6109ce6118a7565b6109f35760405162461bcd60e51b81526004016109ea906153a5565b60405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b601390565b60006060610a266118a7565b610a425760405162461bcd60e51b81526004016109ea906153a5565b856001600160a01b0316858585604051610a5d929190614ce6565b60006040518083038185875af1925050503d8060008114610a9a576040519150601f19603f3d011682016040523d82523d6000602084013e610a9f565b606091505b509097909650945050505050565b60006003610ab96118a7565b610b0857610ac681612592565b610ae25760405162461bcd60e51b81526004016109ea906152be565b610aeb816125da565b15610b085760405162461bcd60e51b81526004016109ea90615527565b600080610b248a610b1a8b60016157b2565b8b8b8a8a8d612621565b91955092509050610b5e6001600080886002811115610b5357634e487b7160e01b600052602160045260246000fd5b14158d8d8787612873565b5050509695505050505050565b7f000000000000000000000000c982ee89bc9395c8bb470f9816bee3a257bb1e9b81565b6000610bae73f1209998bd17eae301a97e3cf7ec17df580e796461291d565b9695505050505050565b60006003610bc46118a7565b610c1357610bd181612592565b610bed5760405162461bcd60e51b81526004016109ea906152be565b610bf6816125da565b15610c135760405162461bcd60e51b81526004016109ea90615527565b610c1d8484612941565b610c2e308b8b8b8b8b8b8b8b612989565b9a9950505050505050505050565b610c446118a7565b610c605760405162461bcd60e51b81526004016109ea906153a5565b600180546001600160a01b0319169055565b6000610c7c6118a7565b610ccb57610c8981612592565b610ca55760405162461bcd60e51b81526004016109ea906152be565b610cae816125da565b15610ccb5760405162461bcd60e51b81526004016109ea90615527565b610cd58484612ef3565b610cdf8483612f19565b50505050565b610ced6118a7565b610d095760405162461bcd60e51b81526004016109ea906153a5565b600060026000836006811115610d2f57634e487b7160e01b600052602160045260246000fd5b815260208101919091526040016000208054909150600160a01b900460ff16610d6a5760405162461bcd60e51b81526004016109ea906154e2565b805460ff60a01b19168155816006811115610d9557634e487b7160e01b600052602160045260246000fd5b6040517fd9ff16dcccc040d408ddf47191ae2d5313510993b245b3a7ccfb0258a4401d7890600090a25050565b6004546001600160a01b031690565b6000610dde873388612f87565b600080610df089898a8a89898c612621565b91945092509050610e2960008080876002811115610e1e57634e487b7160e01b600052602160045260246000fd5b14158c8c8787612873565b610e333383612f19565b50509695505050505050565b6000600281805b81526020810191909152604001600020546001600160a01b0316919050565b6003546001600160a01b031690565b6000610e9373f1209998bd17eae301a97e3cf7ec17df580e796461291d565b9998505050505050505050565b6000806000610eb5883489886000898c613077565b91945092509050610eef6000600180876002811115610ee457634e487b7160e01b600052602160045260246000fd5b14158b348787612873565b505095945050505050565b610f026118a7565b610f1e5760405162461bcd60e51b81526004016109ea906153a5565b610f288282612f19565b5050565b60006002816005610e46565b6000610f5773f1209998bd17eae301a97e3cf7ec17df580e796461291d565b949350505050565b6000610f6b8383613329565b9392505050565b60006002816004610e46565b6060806006610f8b6118a7565b610fda57610f9881612592565b610fb45760405162461bcd60e51b81526004016109ea906152be565b610fbd816125da565b15610fda5760405162461bcd60e51b81526004016109ea90615527565b60405163c7cbc79960e01b81526000906001600160a01b037f000000000000000000000000c982ee89bc9395c8bb470f9816bee3a257bb1e9b169063c7cbc79990611029908890600401614feb565b60206040518083038186803b15801561104157600080fd5b505afa158015611055573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611079919061494e565b9050806110985760405162461bcd60e51b81526004016109ea9061512f565b84516001600160401b038111156110bf57634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156110e8578160200160208202803683370190505b50935084516001600160401b0381111561111257634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561114557816020015b60608152602001906001900390816111305790505b506007805464ffffffff0019166472b272eb001790556040519093506000908190309063610f272160e11b9061117f908a90602401614feb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516111bd9190614cf6565b6000604051808303816000865af19150503d80600081146111fa576040519150601f19603f3d011682016040523d82523d6000602084013e6111ff565b606091505b509150915081611218576007805464ffffffff00191690555b60008180602001905181019061122e9190614659565b905060005b815181101561147157600089828151811061125e57634e487b7160e01b600052603260045260246000fd5b6020026020010151905082828151811061128857634e487b7160e01b600052603260045260246000fd5b6020026020010151600001518983815181106112b457634e487b7160e01b600052603260045260246000fd5b6020026020010190151590811515815250508282815181106112e657634e487b7160e01b600052603260045260246000fd5b60200260200101516020015188838151811061131257634e487b7160e01b600052603260045260246000fd5b602002602001018190525082828151811061133d57634e487b7160e01b600052603260045260246000fd5b602002602001015160000151156113d3577f26f13c2c104b2a1b3f0b1c6232d84f2bba70d231216636c3ceeebea631eb97dd8515826000015183602001516001600160601b031684604001518787815181106113a957634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516040516113c6959493929190615076565b60405180910390a161145e565b7f2007dedc5d6ba6b20b13bb9cbff9121300b36978bbac6fbbc5ccadaa1ff6c668816000015182602001516001600160601b0316836040015161144087878151811061142f57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151613426565b6040516114509493929190614e0a565b60405180910390a150611471565b50806114698161580d565b915050611233565b505050505050915091565b60608060007f000000000000000000000000c982ee89bc9395c8bb470f9816bee3a257bb1e9b6001600160a01b031663c7cbc79986866040518363ffffffff1660e01b81526004016114cf929190614f13565b60206040518083038186803b1580156114e757600080fd5b505afa1580156114fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151f919061494e565b9050836001600160401b0381111561154757634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611570578160200160208202803683370190505b509250836001600160401b0381111561159957634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156115cc57816020015b60608152602001906001900390816115b75790505b5091506000306001600160a01b031663afd6116b60e01b87876040516024016115f6929190614f13565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516116349190614cf6565b6000604051808303816000865af19150503d8060008114611671576040519150601f19603f3d011682016040523d82523d6000602084013e611676565b606091505b509150506000818060200190518101906116909190614659565b905060005b815181101561179a578181815181106116be57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001518682815181106116ea57634e487b7160e01b600052603260045260246000fd5b60200260200101901515908115158152505081818151811061171c57634e487b7160e01b600052603260045260246000fd5b60200260200101516020015185828151811061174857634e487b7160e01b600052603260045260246000fd5b602002602001018190525081818151811061177357634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516117885761179a565b806117928161580d565b915050611695565b5050509250925092565b6117ac6118a7565b6117c85760405162461bcd60e51b81526004016109ea906153a5565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031633146118145760405162461bcd60e51b81526004016109ea9061533a565b600180546001600160a01b03191690556000805460405133926001600160a01b03909216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03191633179055565b600061188f73f1209998bd17eae301a97e3cf7ec17df580e796461291d565b95945050505050565b6000546001600160a01b031690565b6000546001600160a01b0316331490565b600060036118c46118a7565b611913576118d181612592565b6118ed5760405162461bcd60e51b81526004016109ea906152be565b6118f6816125da565b156119135760405162461bcd60e51b81526004016109ea90615527565b6000806119268a8a8a8960018a8d613077565b91955092509050610b5e6001808088600281111561195457634e487b7160e01b600052602160045260246000fd5b14158d8d878d612873565b6000600361196b6118a7565b6119ba5761197881612592565b6119945760405162461bcd60e51b81526004016109ea906152be565b61199d816125da565b156119ba5760405162461bcd60e51b81526004016109ea90615527565b6119c383613671565b610c2e604051806101600160405280306001600160a01b031681526020018c6001600160a01b031681526020018b6001600160a01b031681526020018a81526020018a81526020018981526020018a81526020018881526020018781526020018615158152602001856002811115611a4b57634e487b7160e01b600052602160045260246000fd5b90526136b1565b60006003611a5e6118a7565b611aad57611a6b81612592565b611a875760405162461bcd60e51b81526004016109ea906152be565b611a90816125da565b15611aad5760405162461bcd60e51b81526004016109ea90615527565b610e9389898989898960018a613b47565b6000806000732cf7c0333d9b7f94bbf55b9701227e359f92fd316001600160a01b0316604051611aed90614d58565b600060405180830381855afa9150503d8060008114611b28576040519150601f19603f3d011682016040523d82523d6000602084013e611b2d565b606091505b5091509150818015611b40575080516020145b611b5c5760405162461bcd60e51b81526004016109ea906153ed565b80806020019051810190611b70919061433c565b9250505090565b6000611b816118a7565b611bd057611b8e81612592565b611baa5760405162461bcd60e51b81526004016109ea906152be565b611bb3816125da565b15611bd05760405162461bcd60e51b81526004016109ea90615527565b611bda8585612ef3565b611be5838684613b72565b5050505050565b606081516001600160401b03811115611c1557634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611c4e57816020015b611c3b61429e565b815260200190600190039081611c335790505b50905060005b8251811015611dad57600080848381518110611c8057634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b0316858481518110611cb557634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516001600160601b0316868581518110611cea57634e487b7160e01b600052603260045260246000fd5b602002602001015160400151604051611d039190614cf6565b60006040518083038185875af1925050503d8060008114611d40576040519150601f19603f3d011682016040523d82523d6000602084013e611d45565b606091505b50915091506040518060400160405280831515815260200182815250848481518110611d8157634e487b7160e01b600052603260045260246000fd5b602002602001018190525081611d98575050611dad565b50508080611da59061580d565b915050611c54565b50600081604051602001611dc19190614ea0565b6040516020818303038152906040529050805181602001fd5b6000611de582612592565b92915050565b6000611de5826125da565b6060611e086372b272eb60e01b613c60565b600082516001600160401b03811115611e3157634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611e6a57816020015b611e5761429e565b815260200190600190039081611e4f5790505b50915060005b8351811015611fcd57600080858381518110611e9c57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b0316868481518110611ed157634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516001600160601b0316878581518110611f0657634e487b7160e01b600052603260045260246000fd5b602002602001015160400151604051611f1f9190614cf6565b60006040518083038185875af1925050503d8060008114611f5c576040519150601f19603f3d011682016040523d82523d6000602084013e611f61565b606091505b50915091506040518060400160405280831515815260200182815250858481518110611f9d57634e487b7160e01b600052603260045260246000fd5b602002602001018190525081611fb857600193505050611fcd565b50508080611fc59061580d565b915050611e70565b508015611fe757600082604051602001611dc19190614ea0565b50919050565b6002611ff76118a7565b6120465761200481612592565b6120205760405162461bcd60e51b81526004016109ea906152be565b612029816125da565b156120465760405162461bcd60e51b81526004016109ea90615527565b6003546001600160a01b03168061206f5760405162461bcd60e51b81526004016109ea9061549b565b61208e736b175474e89094c44da98b954eedeac495271d0f8285613b72565b505050565b600060028181610e46565b60006120aa8383612941565b6120b5893389612f87565b610e93338a8a8a8a8a8a8a8a612989565b60026120d06118a7565b61211f576120dd81612592565b6120f95760405162461bcd60e51b81526004016109ea906152be565b612102816125da565b1561211f5760405162461bcd60e51b81526004016109ea90615527565b6004546001600160a01b0316806121485760405162461bcd60e51b81526004016109ea90615619565b61208e73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488285613b72565b60006121716118a7565b61218d5760405162461bcd60e51b81526004016109ea906153a5565b60405163a9059cbb60e01b81526001600160a01b0385169063a9059cbb906121bb9086908690600401614df1565b602060405180830381600087803b1580156121d557600080fd5b505af11580156121e9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f57919061494e565b6122156118a7565b6122315760405162461bcd60e51b81526004016109ea906153a5565b61223c816000613cb2565b50565b730efb068354c10c070ddd64a0e8eaf8f054df7e2690565b60006002816006610e46565b60006002816003610e46565b60046122796118a7565b6122c85761228681612592565b6122a25760405162461bcd60e51b81526004016109ea906152be565b6122ab816125da565b156122c85760405162461bcd60e51b81526004016109ea90615527565b6000600260008460068111156122ee57634e487b7160e01b600052602160045260246000fd5b815260208101919091526040016000208054909150600160a01b900460ff161561232a5760405162461bcd60e51b81526004016109ea9061556c565b805460ff60a01b1916600160a01b17815582600681111561235b57634e487b7160e01b600052602160045260246000fd5b6040517fad75709c5a2559beeed6c59693a5ea8701185d51947d3eef38713bb0fe5891e990600090a2505050565b6123916118a7565b6123ad5760405162461bcd60e51b81526004016109ea906153a5565b6001600160a01b0381166123d35760405162461bcd60e51b81526004016109ea90615303565b610f288282613cb2565b6123e56118a7565b6124015760405162461bcd60e51b81526004016109ea906153a5565b6001600160a01b0381166124275760405162461bcd60e51b81526004016109ea90615661565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b600060036124556118a7565b6124a45761246281612592565b61247e5760405162461bcd60e51b81526004016109ea906152be565b612487816125da565b156124a45760405162461bcd60e51b81526004016109ea90615527565b600080610b248a8a8b8b8a8a8d612621565b60056124c06118a7565b61250f576124cd81612592565b6124e95760405162461bcd60e51b81526004016109ea906152be565b6124f2816125da565b1561250f5760405162461bcd60e51b81526004016109ea90615527565b61252d7355f2039347564d206ccc6e6ce202853fed386dbf83612f19565b7f70c14fa013d428be746414c53915d6af2495865a3687262ce430049e977d50c58260405161255c91906156be565b60405180910390a15050565b600061258773f1209998bd17eae301a97e3cf7ec17df580e796461291d565b979650505050505050565b6000600260008360068111156125b857634e487b7160e01b600052602160045260246000fd5b81526020810191909152604001600020546001600160a01b0316331492915050565b60006002600083600681111561260057634e487b7160e01b600052602160045260246000fd5b8152602081019190915260400160002054600160a01b900460ff1692915050565b60008080808086600281111561264757634e487b7160e01b600052602160045260246000fd5b141561266c57846126588b8b613d74565b61266291906157ca565b9050849150612679565b6126768a8a613d74565b90505b6126838b8b613d8a565b6000806126a68d73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc260006140ad565b915091508a8c141561278257737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b03166318cbafe5848c85308e6040518663ffffffff1660e01b81526004016126fa9594939291906156fc565b600060405180830381600087803b15801561271457600080fd5b505af1158015612728573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261275091908101906148bf565b90508060018151811061277357634e487b7160e01b600052603260045260246000fd5b60200260200101519550612811565b6000479050737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663791ac947858d86308f6040518663ffffffff1660e01b81526004016127cf9594939291906156fc565b600060405180830381600087803b1580156127e957600080fd5b505af11580156127fd573d6000803e3d6000fd5b50505050804761280d91906157ca565b9650505b600088600281111561283357634e487b7160e01b600052602160045260246000fd5b1461285f5761284c6128458b886157ca565b8890613d74565b935061285884876157ca565b9450612863565b8594505b5050509750975097945050505050565b7f8d4e5e4cf68c4b7be730141ed4b1c725966c0e1df450c1a01b965afa060fa3e08761289f57336128a1565b305b876128ac57856128af565b60005b886128bb5760006128bd565b865b886128f3576001600160a01b03888116146128d857876128ee565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb485b6128f6565b60005b87878760405161290c9796959493929190614d89565b60405180910390a150505050505050565b3660008037600080366000845af43d6000803e80801561293c573d6000f35b3d6000fd5b818061296d5750600281600281111561296a57634e487b7160e01b600052602160045260246000fd5b14155b610f285760405162461bcd60e51b81526004016109ea90615253565b6000806000806129998c8b613d8a565b6001600160a01b038b811614156129c5575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486129c8565b50895b85612b55576000806129dc8e8460006140ad565b9092509050737a250d5630b4cf539739df2c5dacb4c659f2488d6338ed17396000896002811115612a1d57634e487b7160e01b600052602160045260246000fd5b14612a28578d612a32565b612a328c8f6157ca565b8d85308e6040518663ffffffff1660e01b8152600401612a569594939291906156fc565b600060405180830381600087803b158015612a7057600080fd5b505af1158015612a84573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612aac91908101906148bf565b905080600181518110612acf57634e487b7160e01b600052603260045260246000fd5b6020026020010151955060016002811115612afa57634e487b7160e01b600052602160045260246000fd5b876002811115612b1a57634e487b7160e01b600052602160045260246000fd5b1415612b4757612b34612b2d8c886157ca565b8b90613d74565b9450612b4085876157ca565b9350612b4e565b8994508593505b5050612e32565b600080612b788e73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc260006140ad565b9092509050737a250d5630b4cf539739df2c5dacb4c659f2488d6338ed17396000896002811115612bb957634e487b7160e01b600052602160045260246000fd5b14612bc4578d612bce565b612bce8c8f6157ca565b60028a6002811115612bf057634e487b7160e01b600052602160045260246000fd5b14612bfc576001612bfe565b8c5b85308e6040518663ffffffff1660e01b8152600401612c219594939291906156fc565b600060405180830381600087803b158015612c3b57600080fd5b505af1158015612c4f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612c7791908101906148bf565b905080600181518110612c9a57634e487b7160e01b600052603260045260246000fd5b60200260200101519450612cc473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28460006140ad565b9092509050737a250d5630b4cf539739df2c5dacb4c659f2488d6338ed17396002896002811115612d0557634e487b7160e01b600052602160045260246000fd5b14612d105786612d1a565b612d1a8c886157ca565b8d85308e6040518663ffffffff1660e01b8152600401612d3e9594939291906156fc565b600060405180830381600087803b158015612d5857600080fd5b505af1158015612d6c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d9491908101906148bf565b905080600181518110612db757634e487b7160e01b600052603260045260246000fd5b6020026020010151955060016002811115612de257634e487b7160e01b600052602160045260246000fd5b876002811115612e0257634e487b7160e01b600052602160045260246000fd5b1415612e2857612e15612b2d8c886157ca565b9450612e2185876157ca565b9350612e2f565b8994508593505b50505b612eb18d8d8d6002896002811115612e5a57634e487b7160e01b600052602160045260246000fd5b14612e93576001896002811115612e8157634e487b7160e01b600052602160045260246000fd5b14612e8c578f612e8e565b845b612ea9565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b8e8789614263565b6001600160a01b038d163014801590612ed357506001600160a01b038b811614155b15612ee357612ee3818e84613b72565b5050509998505050505050505050565b612efd8282613329565b610f285760405162461bcd60e51b81526004016109ea906150d2565b6000826001600160a01b031682604051612f3290614d58565b60006040518083038185875af1925050503d8060008114612f6f576040519150601f19603f3d011682016040523d82523d6000602084013e612f74565b606091505b505090508061208e573d6000803e3d6000fd5b600080846001600160a01b03166323b872dd60e01b853086604051602401612fb193929190614dcd565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612fef9190614cf6565b6000604051808303816000865af19150503d806000811461302c576040519150601f19603f3d011682016040523d82523d6000602084013e613031565b606091505b509150915081801561305b57508051158061305b57508080602001905181019061305b919061494e565b611be55760405162461bcd60e51b81526004016109ea9061515f565b6040805160028082526060820183526000928392839283928392919060208301908036833701905050905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2816000815181106130d857634e487b7160e01b600052603260045260246000fd5b6001600160a01b0392831660209182029290920101528c811614156131555773a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488160018151811061312d57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250503091506131a7565b8b8160018151811061317757634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b031681525050876131a257336131a4565b305b91505b604080516002808252606082018352600092602083019080368337019050509050737a250d5630b4cf539739df2c5dacb4c659f2488d637ff36ab560018a600281111561320457634e487b7160e01b600052602160045260246000fd5b1415613210578d61321a565b61321a898f6157ca565b8d85878f6040518663ffffffff1660e01b815260040161323d94939291906156c7565b6000604051808303818588803b15801561325657600080fd5b505af115801561326a573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405261329391908101906148bf565b9050806001815181106132b657634e487b7160e01b600052603260045260246000fd5b60200260200101519550600160028111156132e157634e487b7160e01b600052602160045260246000fd5b88600281111561330157634e487b7160e01b600052602160045260246000fd5b14156133145761284c6128458c886157ca565b50939b8c9b5094995093975050505050505050565b600080604051806104c001604052806104928152602001615878610492913960405161335d91908590600090602001614d12565b60408051601f19818403018152919052805160209091012090506000805b600a81101561341a576040516133b9907ffffc00c80b0000007f73004edb00094cad80626d8d00000000000000000000009083908690602001614cc0565b6040516020818303038152906040528051906020012060001c9150856001600160a01b0316826001600160a01b031614156133fa5760019350505050611de5565b806134048161580d565b91505080806134129061580d565b91505061337b565b50600095945050505050565b60606044825111801561346c57508151600160fb1b90839060009061345b57634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916145b80156134ad5750815160c360f81b908390600190811061349c57634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916145b80156134ee57508151607960f81b90839060029081106134dd57634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916145b801561352f57508151600560fd1b908390600390811061351e57634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916145b156136415760006004835161354491906157ca565b6001600160401b0381111561356957634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015613593576020820181803683370190505b50905060045b8351811015613624578381815181106135c257634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916826135dd6004846157ca565b815181106135fb57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053508061361c8161580d565b915050613599565b50808060200190518101906136399190614b2e565b91505061366c565b50604080518082019091526012815271286e6f2072657665727420726561736f6e2960701b60208201525b919050565b600281600281111561369357634e487b7160e01b600052602160045260246000fd5b141561223c5760405162461bcd60e51b81526004016109ea906151f6565b6000806001600160a01b03801683604001516001600160a01b0316146136db5782604001516136f1565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb485b905061370583602001518460800151613d8a565b600061371b8460200151838661012001516140ad565b5090506000826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161374c9190614d5b565b60206040518083038186803b15801561376457600080fd5b505afa158015613778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379c9190614b8b565b9050737a250d5630b4cf539739df2c5dacb4c659f2488d635c11d795600087610140015160028111156137df57634e487b7160e01b600052602160045260246000fd5b146137ee578660800151613802565b8660e00151876080015161380291906157ca565b8760a0015185308a61010001516040518663ffffffff1660e01b815260040161382f9594939291906156fc565b600060405180830381600087803b15801561384957600080fd5b505af115801561385d573d6000803e3d6000fd5b50506040516370a0823160e01b81528392506001600160a01b03861691506370a082319061388f903090600401614d5b565b60206040518083038186803b1580156138a757600080fd5b505afa1580156138bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138df9190614b8b565b6138e991906157ca565b8551909450600092506001600160a01b0316301480159150613919575060408401516001600160a01b0390811614155b15613aa25783516040516370a0823160e01b81526000916001600160a01b038516916370a082319161394d91600401614d5b565b60206040518083038186803b15801561396557600080fd5b505afa158015613979573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399d9190614b8b565b85519091506139ee908490600188610140015160028111156139cf57634e487b7160e01b600052602160045260246000fd5b146139da57866139e9565b60e08801516139e990886157ca565b613b72565b84516040516370a0823160e01b815282916001600160a01b038616916370a0823191613a1c91600401614d5b565b60206040518083038186803b158015613a3457600080fd5b505afa158015613a48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a6c9190614b8b565b613a7691906157ca565b9150508360c00151811015613a9d5760405162461bcd60e51b81526004016109ea906155af565b613ae6565b60018461014001516002811115613ac957634e487b7160e01b600052602160045260246000fd5b14613ad45782613ae3565b60e0840151613ae390846157ca565b90505b835160208501516040860151613b4092919060018861014001516002811115613b1f57634e487b7160e01b600052602160045260246000fd5b14613b2e578760200151613b30565b855b8860600151868a60e00151614263565b5050919050565b6000613b6673f1209998bd17eae301a97e3cf7ec17df580e796461291d565b98975050505050505050565b600080846001600160a01b031663a9059cbb60e01b8585604051602401613b9a929190614df1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613bd89190614cf6565b6000604051808303816000865af19150503d8060008114613c15576040519150601f19603f3d011682016040523d82523d6000602084013e613c1a565b606091505b5091509150818015613c44575080511580613c44575080806020019051810190613c44919061494e565b611be55760405162461bcd60e51b81526004016109ea90615424565b3330148015613c8557506007546001600160e01b031982811661010090920460e01b16145b613ca15760405162461bcd60e51b81526004016109ea9061518c565b506007805464ffffffff0019169055565b600060026000846006811115613cd857634e487b7160e01b600052602160045260246000fd5b8152602081019190915260400160002080549091506001600160a01b0383811691161461208e5780546001600160a01b0319166001600160a01b038316178155826006811115613d3857634e487b7160e01b600052602160045260246000fd5b7f40ab465936efb8324cf37e3a29170c60d9b81de43af89693ce9d92c761e42adc83604051613d679190614d5b565b60405180910390a2505050565b6000818310613d835781610f6b565b5090919050565b604051636eb1769f60e11b815281906001600160a01b0384169063dd62ed3e90613dce903090737a250d5630b4cf539739df2c5dacb4c659f2488d90600401614d6f565b60206040518083038186803b158015613de657600080fd5b505afa158015613dfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1e9190614b8b565b1015610f2857600080836001600160a01b031663095ea7b360e01b737a250d5630b4cf539739df2c5dacb4c659f2488d6000604051602401613e61929190614df1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613e9f9190614cf6565b6000604051808303816000865af19150503d8060008114613edc576040519150601f19603f3d011682016040523d82523d6000602084013e613ee1565b606091505b5091509150836001600160a01b031663095ea7b360e01b737a250d5630b4cf539739df2c5dacb4c659f2488d600019604051602401613f21929190614df1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613f5f9190614cf6565b6000604051808303816000865af19150503d8060008114613f9c576040519150601f19603f3d011682016040523d82523d6000602084013e613fa1565b606091505b5090925090508161406c57836001600160a01b031663095ea7b360e01b737a250d5630b4cf539739df2c5dacb4c659f2488d85604051602401613fe5929190614df1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516140239190614cf6565b6000604051808303816000865af19150503d8060008114614060576040519150601f19603f3d011682016040523d82523d6000602084013e614065565b606091505b5090925090505b818015614091575080511580614091575080806020019051810190614091919061494e565b610cdf5760405162461bcd60e51b81526004016109ea90615452565b6060806000836140be5760026140c1565b60035b60ff1690506000816001600160401b038111156140ee57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015614117578160200160208202803683370190505b509050868160008151811061413c57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b03168152505084156141b95773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28160018151811061419857634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250505b85816141c66001856157ca565b815181106141e457634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b03168152505080826001600160401b0381111561422b57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015614254578160200160208202803683370190505b50935093505050935093915050565b7f8d4e5e4cf68c4b7be730141ed4b1c725966c0e1df450c1a01b965afa060fa3e08787878787878760405161290c9796959493929190614d89565b60408051808201909152600081526060602082015290565b60006142c96142c48461578b565b615738565b90508281528383830111156142dd57600080fd5b610f6b8360208301846157e1565b80356003811061366c57600080fd5b80356007811061366c57600080fd5b80356001600160601b038116811461366c57600080fd5b600060208284031215614331578081fd5b8135610f6b81615854565b60006020828403121561434d578081fd5b8151610f6b81615854565b60008060006060848603121561436c578182fd5b833561437781615854565b9250602084013561438781615854565b929592945050506040919091013590565b600080604083850312156143aa578182fd5b82356143b581615854565b946020939093013593505050565b600080600080606085870312156143d8578182fd5b84356143e381615854565b93506020850135925060408501356001600160401b0380821115614405578384fd5b818701915087601f830112614418578384fd5b813581811115614426578485fd5b886020828501011115614437578485fd5b95989497505060200194505050565b60008060408385031215614458578182fd5b823561446381615854565b9150602083013561447381615854565b809150509250929050565b60008060008060808587031215614493578182fd5b843561449e81615854565b935060208501356144ae81615854565b925060408501356144be81615854565b9396929550929360600135925050565b600080600080608085870312156144e3578182fd5b84356144ee81615854565b966020860135965060408601359560600135945092505050565b600080600080600060a0868803121561451f578283fd5b853561452a81615854565b945060208601359350604086013592506060860135915061454d608087016142eb565b90509295509295909350565b600080600080600060a08688031215614570578283fd5b853561457b81615854565b97602087013597506040870135966060810135965060800135945092505050565b60008060008060008060c087890312156145b4578384fd5b86356145bf81615854565b9550602087013594506040870135935060608701359250608087013591506145e960a088016142eb565b90509295509295509295565b600080600080600080600060e0888a03121561460f578485fd5b873561461a81615854565b96506020880135955060408801359450606088013593506080880135925060a0880135915061464b60c089016142eb565b905092959891949750929550565b6000602080838503121561466b578182fd5b82516001600160401b0380821115614681578384fd5b818501915085601f830112614694578384fd5b81516146a26142c482615768565b81815284810190848601875b848110156147325781518701604080601f19838f030112156146ce578a8bfd5b6146d781615738565b8a8301516146e481615869565b815282820151898111156146f6578c8dfd5b8084019350508d603f84011261470a578b8cfd5b61471a8e8c8501518486016142b6565b818c01528652505092870192908701906001016146ae565b50909998505050505050505050565b60008060208385031215614753578182fd5b82356001600160401b0380821115614769578384fd5b818501915085601f83011261477c578384fd5b81358181111561478a578485fd5b866020808302850101111561479d578485fd5b60209290920196919550909350505050565b600060208083850312156147c1578182fd5b82356001600160401b03808211156147d7578384fd5b818501915085601f8301126147ea578384fd5b81356147f86142c482615768565b81815284810190848601875b848110156147325781358701606080601f19838f03011215614824578a8bfd5b61482d81615738565b8a83013561483a81615854565b81526040614849848201614309565b828d015291830135918983111561485e578c8dfd5b82840193508e603f850112614871578c8dfd5b8b84013592506148836142c48461578b565b8381528f82858701011115614896578d8efd5b838286018e8301379283018c018d90528101919091528552509287019290870190600101614804565b600060208083850312156148d1578182fd5b82516001600160401b038111156148e6578283fd5b8301601f810185136148f6578283fd5b80516149046142c482615768565b8181528381019083850185840285018601891015614920578687fd5b8694505b83851015614942578051835260019490940193918501918501614924565b50979650505050505050565b60006020828403121561495f578081fd5b8151610f6b81615869565b60008060006060848603121561436c578081fd5b600080600080600080600060e0888a031215614998578081fd5b87356149a381615854565b965060208801356149b381615854565b955060408801359450606088013593506080880135925060a0880135915060c08801356149df81615869565b8091505092959891949750929550565b600080600080600080600080610100898b031215614a0b578182fd5b8835614a1681615854565b97506020890135614a2681615854565b965060408901359550606089013594506080890135935060a0890135925060c0890135614a5281615869565b9150614a6060e08a016142eb565b90509295985092959890939650565b60008060008060008060008060006101208a8c031215614a8d578283fd5b8935614a9881615854565b985060208a0135614aa881615854565b975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a0135614adb81615869565b9150614aea6101008b016142eb565b90509295985092959850929598565b600060208284031215614b0a578081fd5b610f6b826142fa565b60008060408385031215614b25578182fd5b614463836142fa565b600060208284031215614b3f578081fd5b81516001600160401b03811115614b54578182fd5b8201601f81018413614b64578182fd5b610f57848251602084016142b6565b600060208284031215614b84578081fd5b5035919050565b600060208284031215614b9c578081fd5b5051919050565b6000815180845260208085019450808401835b83811015614bdb5781516001600160a01b031687529582019590820190600101614bb6565b509495945050505050565b6000815180845260208085019450808401835b83811015614bdb578151151587529582019590820190600101614bf9565b6000815180845260208085018081965082840281019150828601855b85811015614c5d578284038952614c4b848351614c94565b98850198935090840190600101614c33565b5091979650505050505050565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b60008151808452614cac8160208601602086016157e1565b601f01601f19169290920160200192915050565b6affffffffffffffffffffff199390931683526015830191909152603582015260550190565b6000828483379101908152919050565b60008251614d088184602087016157e1565b9190910192915050565b60008451614d248184602089016157e1565b60609490941b6bffffffffffffffffffffffff19169190930190815263ffffffff1991909116601482015260300192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03978816815295871660208701529386166040860152919094166060840152608083019390935260a082019290925260c081019190915260e00190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b600060018060a01b038616825284602083015260806040830152614e316080830185614c94565b82810360608401526125878185614c94565b600060408252614e566040830185614be6565b828103602084015261188f8185614c17565b600060608252614e7b6060830186614be6565b8281036020840152614e8d8186614c17565b9150508215156040830152949350505050565b60208082528251828201819052600091906040908185019080840286018301878501865b83811015614f0557888303603f190185528151805115158452870151878401879052614ef287850182614c94565b9588019593505090860190600101614ec4565b509098975050505050505050565b602080825281810183905260009060408084018583028501820187855b88811015614f0557878303603f190184528135368b9003605e19018112614f55578788fd5b8a0160608135614f6481615854565b6001600160a01b031685526001600160601b03614f82838a01614309565b168886015286820135601e19833603018112614f9c57898afd5b820180356001600160401b03811115614fb3578a8bfd5b803603841315614fc1578a8bfd5b8289880152614fd5838801828c8501614c6a565b978a019796505050928701925050600101614f30565b60208082528251828201819052600091906040908185019080840286018301878501865b83811015614f0557888303603f19018552815180516001600160a01b03168452878101516001600160601b031688850152860151606087850181905261505781860183614c94565b96890196945050509086019060010161500f565b901515815260200190565b6000861515825260018060a01b038616602083015284604083015260a060608301526150a560a0830185614c94565b8281036080840152613b668185614c94565b6000831515825260406020830152610f576040830184614c94565b6020808252603a908201527f436f756c64206e6f74207265736f6c766520736d6172742077616c6c6574207560408201527f73696e672070726f7669646564207369676e696e67206b65792e000000000000606082015260800190565b602080825260169082015275496e76616c69642063616c6c2064657465637465642160501b604082015260600190565b6020808252601390820152722a3930b739b332b91034b7103330b4b632b21760691b604082015260600190565b60208082526044908201527f45787465726e616c206163636f756e7473206f7220756e617070726f7665642060408201527f696e7465726e616c2066756e6374696f6e732063616e6e6f742063616c6c20746060820152633434b99760e11b608082015260a00190565b6020808252603e908201527f43616e6e6f742074616b6520746f6b656e2d666f722d746f6b656e206665652060408201527f696e204574686572207769746820666565206f6e207472616e736665722e0000606082015260800190565b60208082526045908201527f43616e6e6f742074616b6520746f6b656e2d666f722d746f6b656e206665652060408201527f696e20457468657220756e6c65737320726f75746564207468726f75676820456060820152643a3432b91760d91b608082015260a00190565b60208082526025908201527f43616c6c657220646f6573206e6f7420686176652061207265717569726564206040820152643937b6329760d91b606082015260800190565b60208082526017908201527f4d75737420737570706c7920616e206163636f756e742e000000000000000000604082015260600190565b60208082526045908201527f54776f537465704f776e61626c653a2063757272656e74206f776e6572206d7560408201527f7374207365742063616c6c6572206173206e657720706f74656e7469616c206f6060820152643bb732b91760d91b608082015260a00190565b60208082526028908201527f54776f537465704f776e61626c653a2063616c6c6572206973206e6f74207468604082015267329037bbb732b91760c11b606082015260800190565b60208082526017908201527f496e76616c696420696d706c656d656e746174696f6e2e000000000000000000604082015260600190565b6020808252601490820152732a3930b739b332b91037baba103330b4b632b21760611b604082015260600190565b60208082526029908201527f546f6b656e20617070726f76616c20666f7220556e697377617020726f75746560408201526839103330b4b632b21760b91b606082015260800190565b60208082526027908201527f4e6f20446169207072696d61727920726563697069656e742063757272656e74604082015266363c9039b2ba1760c91b606082015260800190565b60208082526025908201527f526f6c6520696e207175657374696f6e20697320616c726561647920756e70616040820152643ab9b2b21760d91b606082015260800190565b60208082526025908201527f526f6c6520696e207175657374696f6e2069732063757272656e746c792070616040820152643ab9b2b21760d91b606082015260800190565b60208082526023908201527f526f6c6520696e207175657374696f6e20697320616c7265616479207061757360408201526232b21760e91b606082015260800190565b60208082526044908201527f526563656976656420746f6b656e20616d6f756e74206166746572207472616e60408201527f7366657220666565206973206c657373207468616e2071756f74656420616d6f6060820152633ab73a1760e11b608082015260a00190565b60208082526028908201527f4e6f2055534443207072696d61727920726563697069656e742063757272656e6040820152673a363c9039b2ba1760c11b606082015260800190565b60208082526038908201527f54776f537465704f776e61626c653a206e657720706f74656e7469616c206f7760408201527f6e657220697320746865207a65726f20616464726573732e0000000000000000606082015260800190565b90815260200190565b6000858252608060208301526156e06080830186614ba3565b6001600160a01b03949094166040830152506060015292915050565b600086825285602083015260a0604083015261571b60a0830186614ba3565b6001600160a01b0394909416606083015250608001529392505050565b604051601f8201601f191681016001600160401b03811182821017156157605761576061583e565b604052919050565b60006001600160401b038211156157815761578161583e565b5060209081020190565b60006001600160401b038211156157a4576157a461583e565b50601f01601f191660200190565b600082198211156157c5576157c5615828565b500190565b6000828210156157dc576157dc615828565b500390565b60005b838110156157fc5781810151838201526020016157e4565b83811115610cdf5750506000910152565b600060001982141561582157615821615828565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461223c57600080fd5b801515811461223c57600080fdfe60806040526040516104423803806104428339818101604052602081101561002657600080fd5b810190808051604051939291908464010000000082111561004657600080fd5b90830190602082018581111561005b57600080fd5b825164010000000081118282018810171561007557600080fd5b82525081516020918201929091019080838360005b838110156100a257818101518382015260200161008a565b50505050905090810190601f1680156100cf5780820380516001836020036101000a031916815260200191505b5060405250505060006100e661019e60201b60201c565b6001600160a01b0316826040518082805190602001908083835b6020831061011f5780518252601f199092019160209182019101610100565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461017f576040519150601f19603f3d011682016040523d82523d6000602084013e610184565b606091505b5050905080610197573d6000803e3d6000fd5b50506102be565b60405160009081906060906e26750c571ce882b17016557279adaa9083818181855afa9150503d80600081146101f0576040519150601f19603f3d011682016040523d82523d6000602084013e6101f5565b606091505b509150915081819061029f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561026457818101518382015260200161024c565b50505050905090810190601f1680156102915780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b508080602001905160208110156102b557600080fd5b50519392505050565b610175806102cd6000396000f3fe608060405261001461000f610016565b61011c565b005b60405160009081906060906e26750c571ce882b17016557279adaa9083818181855afa9150503d8060008114610068576040519150601f19603f3d011682016040523d82523d6000602084013e61006d565b606091505b50915091508181906100fd5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156100c25781810151838201526020016100aa565b50505050905090810190601f1680156100ef5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5080806020019051602081101561011357600080fd5b50519392505050565b3660008037600080366000845af43d6000803e80801561013b573d6000f35b3d6000fdfea265627a7a7231582020202020202055706772616465426561636f6e50726f7879563120202020202064736f6c634300050b003200000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024c4d66de8000000000000000000000000a2646970667358221220784b1cc3f6622b5c7aae2f03aa8870aed35115d5feb5040157029b0dff2d8f2364736f6c63430008010033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000c982ee89bc9395c8bb470f9816bee3a257bb1e9b

-----Decoded View---------------
Arg [0] : actionRegistryAddress (address): 0xc982eE89BC9395c8bb470F9816bEe3a257bB1E9B

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c982ee89bc9395c8bb470f9816bee3a257bb1e9b


Deployed Bytecode Sourcemap

16498:67839:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21759:36;21773:10;21785:9;21759:36;;;;;;;:::i;:::-;;;;;;;;16498:67839;;;;;47742:165;;;;;;;;;;-1:-1:-1;47742:165:0;;;;;:::i;:::-;;:::i;:::-;;56649:102;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;47251:287;;;;;;;;;;-1:-1:-1;47251:287:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;39514:867::-;;;;;;;;;;-1:-1:-1;39514:867:0;;;;;:::i;:::-;;:::i;21483:49::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;35348:328::-;;;;;;:::i;:::-;;:::i;36626:827::-;;;;;;;;;;-1:-1:-1;36626:827:0;;;;;:::i;:::-;;:::i;2971:90::-;;;;;;;;;;;;;:::i;43385:417::-;;;;;;;;;;-1:-1:-1;43385:417:0;;;;;:::i;:::-;;:::i;49020:276::-;;;;;;;;;;-1:-1:-1;49020:276:0;;;;;:::i;:::-;;:::i;55227:142::-;;;;;;;;;;;;;:::i;32761:993::-;;;;;;;;;;-1:-1:-1;32761:993:0;;;;;:::i;:::-;;:::i;52633:160::-;;;;;;;;;;;;;:::i;55552:140::-;;;;;;;;;;;;;:::i;32264:491::-;;;;;;;;;;-1:-1:-1;32264:491:0;;;;;:::i;:::-;;:::i;34314:760::-;;;;;;:::i;:::-;;:::i;45842:215::-;;;;;;;;;;-1:-1:-1;45842:215:0;;;;;:::i;:::-;;:::i;54855:187::-;;;;;;;;;;;;;:::i;33760:238::-;;;;;;;;;;-1:-1:-1;33760:238:0;;;;;:::i;:::-;;:::i;51916:230::-;;;;;;;;;;-1:-1:-1;51916:230:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;54722:127::-;;;;;;;;;;;;;:::i;25358:2683::-;;;;;;;;;;-1:-1:-1;25358:2683:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;22416:1251::-;;;;;;;;;;-1:-1:-1;22416:1251:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;48110:163::-;;;;;;;;;;-1:-1:-1;48110:163:0;;;;;:::i;:::-;;:::i;3219:298::-;;;;;;;;;;;;;:::i;36326:294::-;;;;;;;;;;-1:-1:-1;36326:294:0;;;;;:::i;:::-;;:::i;2058:73::-;;;;;;;;;;;;;:::i;2400:86::-;;;;;;;;;;;;;:::i;40387:874::-;;;;;;;;;;-1:-1:-1;40387:874:0;;;;;:::i;:::-;;:::i;37459:1197::-;;;;;;;;;;-1:-1:-1;37459:1197:0;;;;;:::i;:::-;;:::i;35682:638::-;;;;;;;;;;-1:-1:-1;35682:638:0;;;;;:::i;:::-;;:::i;55922:354::-;;;;;;;;;;;;;:::i;42067:433::-;;;;;;;;;;-1:-1:-1;42067:433:0;;;;;:::i;:::-;;:::i;24499:853::-;;;;;;;;;;-1:-1:-1;24499:853:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;34004:304::-;;;;;;;;;;-1:-1:-1;34004:304:0;;;;;:::i;35080:262::-;;;;;;:::i;51051:109::-;;;;;;;;;;-1:-1:-1;51051:109:0;;;;;:::i;:::-;;:::i;50697:111::-;;;;;;;;;;-1:-1:-1;50697:111:0;;;;;:::i;:::-;;:::i;28047:1071::-;;;;;;;;;;-1:-1:-1;28047:1071:0;;;;;:::i;:::-;;:::i;45133:454::-;;;;;;;;;;-1:-1:-1;45133:454:0;;;;;:::i;:::-;;:::i;53650:182::-;;;;;;;;;;;;;:::i;31007:869::-;;;;;;;;;;-1:-1:-1;31007:869:0;;;;;:::i;:::-;;:::i;44372:461::-;;;;;;;;;;-1:-1:-1;44372:461:0;;;;;:::i;:::-;;:::i;46533:247::-;;;;;;;;;;-1:-1:-1;46533:247:0;;;;;:::i;:::-;;:::i;50046:98::-;;;;;;;;;;-1:-1:-1;50046:98:0;;;;;:::i;:::-;;:::i;56495:148::-;;;;;;;;;;;;;:::i;54129:147::-;;;;;;;;;;;;;:::i;53140:156::-;;;;;;;;;;;;;:::i;48554:285::-;;;;;;;;;;-1:-1:-1;48554:285:0;;;;;:::i;:::-;;:::i;49605:173::-;;;;;;;;;;-1:-1:-1;49605:173:0;;;;;:::i;:::-;;:::i;2619:225::-;;;;;;;;;;-1:-1:-1;2619:225:0;;;;;:::i;:::-;;:::i;38662:846::-;;;;;;;;;;-1:-1:-1;38662:846:0;;;;;:::i;:::-;;:::i;43808:260::-;;;;;;;;;;-1:-1:-1;43808:260:0;;;;;:::i;:::-;;:::i;31882:376::-;;;;;;;;;;-1:-1:-1;31882:376:0;;;;;:::i;:::-;;:::i;47742:165::-;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;;;;;;;;;47868:21:::1;:33:::0;;-1:-1:-1;;;;;;47868:33:0::1;-1:-1:-1::0;;;;;47868:33:0;;;::::1;::::0;;;::::1;::::0;;47742:165::o;56649:102::-;17428:2;;56649:102::o;47251:287::-;47376:7;47385:23;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;47501:6:::1;-1:-1:-1::0;;;;;47501:11:0::1;47519:6;47527:4;;47501:31;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;47482:50:0;;;;-1:-1:-1;47251:287:0;-1:-1:-1;;;;;47251:287:0:o;39514:867::-;39823:24;39784:19;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;39856:27:::1;::::0;39977:192:::1;40005:5:::0;40019:27:::1;:23:::0;40045:1:::1;40019:27;:::i;:::-;40055:23;40087:17;40113:8;40130:7;40146:16;39977:19;:192::i;:::-;39919:250:::0;;-1:-1:-1;39919:250:0;-1:-1:-1;39919:250:0;-1:-1:-1;40178:197:0::1;40202:4;40215:5;::::0;40229:7:::1;:33;;;;;;-1:-1:-1::0;;;40229:33:0::1;;;;;;;;;;;40279:5;40294:23;40326:19;40354:14;40178:15;:197::i;:::-;84327:1;;39514:867:::0;;;;;;;;;:::o;21483:49::-;;;:::o;35348:328::-;35622:25;35656:14;21584:42;35656:9;:14::i;:::-;35348:328;;;;;;;;:::o;36626:827::-;37060:25;37021:19;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;37094:62:::1;37129:17;37148:7;37094:34;:62::i;:::-;37185:262;37221:4;37235:25;37269:13;37291:31;37331:25;37365:16;37390:8;37407:17;37433:7;37185:19;:262::i;:::-;37165:282:::0;36626:827;-1:-1:-1;;;;;;;;;;36626:827:0:o;2971:90::-;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;3037:18:::1;3030:25:::0;;-1:-1:-1;;;;;;3030:25:0::1;::::0;;2971:90::o;43385:417::-;43537:20;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;43635:54:::1;43654:11;43667:21;43635:18;:54::i;:::-;43756:40;43771:11;43784;43756:14;:40::i;:::-;43385:417:::0;;;;:::o;49020:276::-;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;49083:35:::1;49121:6;:21;49136:4;49128:13;;;;;;-1:-1:-1::0;;;49128:13:0::1;;;;;;;;;49121:21:::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;49121:21:0;49157:23;;49121:21;;-1:-1:-1;;;;49157:23:0;::::1;;;49149:73;;;;-1:-1:-1::0;;;49149:73:0::1;;;;;;;:::i;:::-;49229:31:::0;;-1:-1:-1;;;;49229:31:0::1;::::0;;49285:4;49272:18:::1;::::0;::::1;;;;-1:-1:-1::0;;;49272:18:0::1;;;;;;;;;;::::0;::::1;::::0;;;::::1;2313:1;49020:276:::0;:::o;55227:142::-;55342:21;;-1:-1:-1;;;;;55342:21:0;;55227:142::o;32761:993::-;32995:24;33095:48;33112:5;33119:10;33131:11;33095:16;:48::i;:::-;33152:27;33186:22;33273:164;33301:5;33315:11;33335;33355:17;33381:8;33398:7;33414:16;33273:19;:164::i;:::-;33215:222;;-1:-1:-1;33215:222:0;-1:-1:-1;33215:222:0;-1:-1:-1;33446:186:0;33470:5;;;33498:7;:33;;;;;;-1:-1:-1;;;33498:33:0;;;;;;;;;;;33548:5;33563:11;33583:19;33611:14;33446:15;:186::i;:::-;33701:47;33716:10;33728:19;33701:14;:47::i;:::-;32761:993;;;;;;;;;;:::o;52633:160::-;52694:22;52742:6;52694:22;;52749:29;52742:37;;;;;;;;;;;-1:-1:-1;52742:37:0;:45;-1:-1:-1;;;;;52742:45:0;;52633:160;-1:-1:-1;52633:160:0:o;55552:140::-;55666:20;;-1:-1:-1;;;;;55666:20:0;;55552:140::o;32264:491::-;32701:25;32735:14;21584:42;32735:9;:14::i;:::-;32264:491;;;;;;;;;;;:::o;34314:760::-;34523:25;34602:27;34636:22;34724:161;34757:5;34771:9;34789:17;34815:8;34832:5;34846:7;34862:16;34724:24;:161::i;:::-;34665:220;;-1:-1:-1;34665:220:0;-1:-1:-1;34665:220:0;-1:-1:-1;34894:174:0;34918:5;34932:4;;34945:7;:33;;;;;;-1:-1:-1;;;34945:33:0;;;;;;;;;;;34987:5;35001:9;35019:19;35047:14;34894:15;:174::i;:::-;34314:760;;;;;;;;;:::o;45842:215::-;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;46013:38:::1;46028:9;46039:11;46013:14;:38::i;:::-;45842:215:::0;;:::o;54855:187::-;54926:26;54986:6;54926:26;55001:25;54993:34;;33760:238;33945:24;33978:14;21584:42;33978:9;:14::i;:::-;33760:238;;;;;;:::o;51916:230::-;52039:22;52090:50;52105:11;52118:21;52090:14;:50::i;:::-;52070:70;51916:230;-1:-1:-1;;;51916:230:0:o;54722:127::-;54775:14;54807:6;54775:14;54822:11;54814:20;;25358:2683;25465:16;25483:25;25432:13;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;25570:37:::1;::::0;-1:-1:-1;;;25570:37:0;;25552:15:::1;::::0;-1:-1:-1;;;;;25570:16:0::1;:30;::::0;::::1;::::0;:37:::1;::::0;25601:5;;25570:37:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;25552:55;;25624:10;25616:45;;;;-1:-1:-1::0;;;25616:45:0::1;;;;;;;:::i;:::-;26089:5;:12;-1:-1:-1::0;;;;;26078:24:0::1;;;;;-1:-1:-1::0;;;26078:24:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;26078:24:0::1;;26073:29;;26134:5;:12;-1:-1:-1::0;;;;;26122:25:0::1;;;;;-1:-1:-1::0;;;26122:25:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;26204:16:0::1;:40:::0;;-1:-1:-1;;26204:40:0::1;::::0;::::1;::::0;;26478:71:::1;::::0;26109:38;;-1:-1:-1;;;;;26459:4:0::1;::::0;-1:-1:-1;;;26511:22:0;26478:71:::1;::::0;26535:5;;26478:71:::1;;;:::i;:::-;;::::0;;-1:-1:-1;;26478:71:0;;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;;-1:-1:-1;;;;;26478:71:0::1;-1:-1:-1::0;;;;;;26478:71:0;;::::1;::::0;;;::::1;::::0;;;26451:105;;::::1;::::0;26478:71;26451:105:::1;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26402:154;;;;26626:10;26621:57;;26654:16;26647:23:::0;;-1:-1:-1;;26647:23:0::1;::::0;;26621:57:::1;26768:38;26820:14;26809:49;;;;;;;;;;;;:::i;:::-;26768:90;;26870:9;26865:1171;26889:11;:18;26885:1;:22;26865:1171;;;26923:30;26956:5;26962:1;26956:8;;;;;;-1:-1:-1::0;;;26956:8:0::1;;;;;;;;;;;;;;;26923:41;;27059:11;27071:1;27059:14;;;;;;-1:-1:-1::0;;;27059:14:0::1;;;;;;;;;;;;;;;:17;;;27051:2;27054:1;27051:5;;;;;;-1:-1:-1::0;;;27051:5:0::1;;;;;;;;;;;;;;:25;;;;;;;;;::::0;::::1;27101:11;27113:1;27101:14;;;;;;-1:-1:-1::0;;;27101:14:0::1;;;;;;;;;;;;;;;:25;;;27085:10;27096:1;27085:13;;;;;;-1:-1:-1::0;;;27085:13:0::1;;;;;;;;;;;;;;:41;;;;27223:11;27235:1;27223:14;;;;;;-1:-1:-1::0;;;27223:14:0::1;;;;;;;;;;;;;;;:17;;;27219:810;;;27338:237;27363:10;27362:11;27444;:14;;;27479:11;:17;;;-1:-1:-1::0;;;;;27471:26:0::1;27510:11;:16;;;27539:11;27551:1;27539:14;;;;;;-1:-1:-1::0;;;27539:14:0::1;;;;;;;;;;;;;;;:25;;;27338:237;;;;;;;;;;:::i;:::-;;;;;;;;27219:810;;;27744:176;27768:11;:14;;;27803:11;:17;;;-1:-1:-1::0;;;;;27795:26:0::1;27834:11;:16;;;27863:46;27883:11;27895:1;27883:14;;;;;;-1:-1:-1::0;;;27883:14:0::1;;;;;;;;;;;;;;;:25;;;27863:19;:46::i;:::-;27744:176;;;;;;;;;:::i;:::-;;;;;;;;28014:5;;;27219:810;-1:-1:-1::0;26909:3:0;::::1;::::0;::::1;:::i;:::-;;;;26865:1171;;;;84327:1;;;;25358:2683:::0;;;;:::o;22416:1251::-;22501:16;22519:25;22546:15;22618:16;-1:-1:-1;;;;;22618:30:0;;22649:5;;22618:37;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22605:50;-1:-1:-1;22760:5:0;-1:-1:-1;;;;;22749:24:0;;;;;-1:-1:-1;;;22749:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;22749:24:0;-1:-1:-1;22744:29:0;-1:-1:-1;22805:5:0;-1:-1:-1;;;;;22793:25:0;;;;;-1:-1:-1;;;22793:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22780:38;;22979:27;23018:4;-1:-1:-1;;;;;23010:18:0;23070:23;;;23095:5;;23037:72;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;23037:72:0;;;;;;;;;;;;;;-1:-1:-1;;;;;23037:72:0;-1:-1:-1;;;;;;23037:72:0;;;;;;;;;;23010:106;;;;23037:72;23010:106;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22976:140;;;23207:38;23259:14;23248:49;;;;;;;;;;;;:::i;:::-;23207:90;;23309:9;23304:358;23328:11;:18;23324:1;:22;23304:358;;;23446:11;23458:1;23446:14;;;;;;-1:-1:-1;;;23446:14:0;;;;;;;;;;;;;;;:17;;;23438:2;23441:1;23438:5;;;;;;-1:-1:-1;;;23438:5:0;;;;;;;;;;;;;;:25;;;;;;;;;;;23488:11;23500:1;23488:14;;;;;;-1:-1:-1;;;23488:14:0;;;;;;;;;;;;;;;:25;;;23472:10;23483:1;23472:13;;;;;;-1:-1:-1;;;23472:13:0;;;;;;;;;;;;;;:41;;;;23529:11;23541:1;23529:14;;;;;;-1:-1:-1;;;23529:14:0;;;;;;;;;;;;;;;:17;;;23524:131;;23640:5;;23524:131;23348:3;;;;:::i;:::-;;;;23304:358;;;;22416:1251;;;;;;;:::o;48110:163::-;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;48235:20:::1;:32:::0;;-1:-1:-1;;;;;;48235:32:0::1;-1:-1:-1::0;;;;;48235:32:0;;;::::1;::::0;;;::::1;::::0;;48110:163::o;3219:298::-;3290:18;;-1:-1:-1;;;;;3290:18:0;3276:10;:32;3260:135;;;;-1:-1:-1;;;3260:135:0;;;;;;;:::i;:::-;3411:18;3404:25;;-1:-1:-1;;;;;;3404:25:0;;;-1:-1:-1;3464:6:0;;3443:40;;3472:10;;-1:-1:-1;;;;;3464:6:0;;;;3443:40;;;3492:6;:19;;-1:-1:-1;;;;;;3492:19:0;3501:10;3492:19;;;3219:298::o;36326:294::-;36566:25;36600:14;21584:42;36600:9;:14::i;:::-;36326:294;;;;;;;:::o;2058:73::-;2096:7;2119:6;-1:-1:-1;;;;;2119:6:0;2058:73;:::o;2400:86::-;2440:4;2474:6;-1:-1:-1;;;;;2474:6:0;2460:10;:20;;2400:86::o;40387:874::-;40678:25;40633:19;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;40761:27:::1;40795:22:::0;40883:174:::1;40916:5;40930:23;40962:17;40988:8;41005:4;41018:7;41034:16;40883:24;:174::i;:::-;40824:233:::0;;-1:-1:-1;40824:233:0;-1:-1:-1;40824:233:0;-1:-1:-1;41066:189:0::1;41090:4;::::0;;41116:7:::1;:33;;;;;;-1:-1:-1::0;;;41116:33:0::1;;;;;;;;;;;41158:5;41172:23;41204:19;41232:16;41066:15;:189::i;37459:1197::-:0;37910:25;37871:19;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;37944:26:::1;37962:7;37944:17;:26::i;:::-;37999:651;38044:599;;;;;;;;38110:4;-1:-1:-1::0;;;;;38044:599:0::1;;;;;38139:25;-1:-1:-1::0;;;;;38044:599:0::1;;;;;38198:13;-1:-1:-1::0;;;;;38044:599:0::1;;;;;38241:31;38044:599;;;;38318:31;38044:599;;;;38385:25;38044:599;;;;38462:31;38044:599;;;;38520:16;38044:599;;;;38555:8;38044:599;;;;38591:17;38044:599;;;;;;38626:7;38044:599;;;;;;-1:-1:-1::0;;;38044:599:0::1;;;;;;;;;::::0;;37999:36:::1;:651::i;35682:638::-:0;36032:25;36002:19;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;36086:228:::1;36131:5;36145:23;36177:17;36203:33;36245:16;36270:8;36287:4;36300:7;36086:36;:228::i;55922:354::-:0;55989:22;56025:7;56034:23;56077:42;-1:-1:-1;;;;;56061:76:0;:80;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56024:117;;;;56156:2;:29;;;;;56162:10;:17;56183:2;56162:23;56156:29;56148:65;;;;-1:-1:-1;;;56148:65:0;;;;;;;:::i;:::-;56248:10;56237:33;;;;;;;;;;;;:::i;:::-;56220:50;;55922:354;;;:::o;42067:433::-;42233:20;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;42331:54:::1;42350:11;42363:21;42331:18;:54::i;:::-;42452:42;42467:5;42474:11;42487:6;42452:14;:42::i;:::-;42067:433:::0;;;;;:::o;24499:853::-;24572:38;24659:5;:12;-1:-1:-1;;;;;24635:37:0;;;;;-1:-1:-1;;;24635:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;24621:51;;24686:9;24681:447;24705:5;:12;24701:1;:16;24681:447;;;24803:7;24812:23;24839:5;24845:1;24839:8;;;;;;-1:-1:-1;;;24839:8:0;;;;;;;;;;;;;;;:11;;;-1:-1:-1;;;;;24839:16:0;24880:5;24886:1;24880:8;;;;;;-1:-1:-1;;;24880:8:0;;;;;;;;;;;;;;;:14;;;-1:-1:-1;;;;;24872:23:0;24905:5;24911:1;24905:8;;;;;;-1:-1:-1;;;24905:8:0;;;;;;;;;;;;;;;:13;;;24839:80;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24802:117;;;;24945:51;;;;;;;;24968:2;24945:51;;;;;;24984:10;24945:51;;;24928:11;24940:1;24928:14;;;;;;-1:-1:-1;;;24928:14:0;;;;;;;;;;;;;;:68;;;;25010:2;25005:116;;25106:5;;;;25005:116;24681:447;;24719:3;;;;;:::i;:::-;;;;24681:447;;;;25214:29;25257:11;25246:23;;;;;;;;:::i;:::-;;;;;;;;;;;;;25214:55;;25327:16;25321:23;25302:16;25298:2;25294:25;25287:58;51051:109;51110:12;51141:13;51149:4;51141:7;:13::i;:::-;51131:23;51051:109;-1:-1:-1;;51051:109:0:o;50697:111::-;50758:11;50787:15;50797:4;50787:9;:15::i;28047:1071::-;28119:38;28245:43;-1:-1:-1;;;28245:20:0;:43::i;:::-;28297:13;28363:5;:12;-1:-1:-1;;;;;28339:37:0;;;;;-1:-1:-1;;;28339:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;28325:51;;28390:9;28385:473;28409:5;:12;28405:1;:16;28385:473;;;28507:7;28516:23;28543:5;28549:1;28543:8;;;;;;-1:-1:-1;;;28543:8:0;;;;;;;;;;;;;;;:11;;;-1:-1:-1;;;;;28543:16:0;28584:5;28590:1;28584:8;;;;;;-1:-1:-1;;;28584:8:0;;;;;;;;;;;;;;;:14;;;-1:-1:-1;;;;;28576:23:0;28609:5;28615:1;28609:8;;;;;;-1:-1:-1;;;28609:8:0;;;;;;;;;;;;;;;:13;;;28543:80;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28506:117;;;;28649:51;;;;;;;;28672:2;28649:51;;;;;;28688:10;28649:51;;;28632:11;28644:1;28632:14;;;;;;-1:-1:-1;;;28632:14:0;;;;;;;;;;;;;;:68;;;;28714:2;28709:142;;28821:4;28810:15;;28836:5;;;;28709:142;28385:473;;28423:3;;;;;:::i;:::-;;;;28385:473;;;;28870:8;28866:247;;;28971:29;29014:11;29003:23;;;;;;;;:::i;29044:62::-;28047:1071;;;;:::o;45133:454::-;45222:23;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;45333:20:::1;::::0;-1:-1:-1;;;;;45333:20:0::1;45376:30:::0;45360:96:::1;;;;-1:-1:-1::0;;;45360:96:0::1;;;;;;;:::i;:::-;45532:49;17687:42;45553:16;45571:9;45532:14;:49::i;:::-;84327:1;45133:454:::0;;:::o;53650:182::-;53720:25;53778:6;53720:25;53778:6;53785:32;;31007:869;31371:25;31405:62;31440:17;31459:7;31405:34;:62::i;:::-;31542:64;31559:13;31574:10;31586:19;31542:16;:64::i;:::-;31635:235;31663:10;31682:13;31704;31726:19;31754:25;31788:16;31813:8;31830:17;31856:7;31635:19;:235::i;44372:461::-;44463:23;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;44574:21:::1;::::0;-1:-1:-1;;;;;44574:21:0::1;44618:30:::0;44602:97:::1;;;;-1:-1:-1::0;;;44602:97:0::1;;;;;;;:::i;:::-;44776:51;17561:42;44798:16;44816:10;44776:14;:51::i;46533:247::-:0;46655:12;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;46741:33:::1;::::0;-1:-1:-1;;;46741:33:0;;-1:-1:-1;;;;;46741:14:0;::::1;::::0;::::1;::::0;:33:::1;::::0;46756:9;;46767:6;;46741:33:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;50046:98::-:0;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;50112:26:::1;50121:4;50135:1;50112:8;:26::i;:::-;50046:98:::0;:::o;56495:148::-;56594:42;;56495:148::o;54129:147::-;54190:16;54232:6;54190:16;54247:13;54239:22;;53140:156;53200:21;53246:6;53200:21;53261:19;53253:28;;48554:285;48610:11;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;48630:35:::1;48668:6;:21;48683:4;48675:13;;;;;;-1:-1:-1::0;;;48675:13:0::1;;;;;;;;;48668:21:::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;48668:21:0;48705:23;;48668:21;;-1:-1:-1;;;;48705:23:0;::::1;;;48704:24;48696:72;;;;-1:-1:-1::0;;;48696:72:0::1;;;;;;;:::i;:::-;48775:30:::0;;-1:-1:-1;;;;48775:30:0::1;-1:-1:-1::0;;;48775:30:0::1;::::0;;48828:4;48817:16:::1;::::0;::::1;;;;-1:-1:-1::0;;;48817:16:0::1;;;;;;;;;;::::0;::::1;::::0;;;::::1;84327:1;48554:285:::0;;:::o;49605:173::-;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;49693:21:0;::::1;49685:57;;;;-1:-1:-1::0;;;49685:57:0::1;;;;;;;:::i;:::-;49749:23;49758:4;49764:7;49749:8;:23::i;2619:225::-:0;2252:9;:7;:9::i;:::-;2244:62;;;;-1:-1:-1;;;2244:62:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;2704:22:0;::::1;2688:112;;;;-1:-1:-1::0;;;2688:112:0::1;;;;;;;:::i;:::-;2809:18;:29:::0;;-1:-1:-1;;;;;;2809:29:0::1;-1:-1:-1::0;;;;;2809:29:0;;;::::1;::::0;;;::::1;::::0;;2619:225::o;38662:846::-;38954:24;38915:19;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;38987:27:::1;39021:22:::0;39108:188:::1;39136:5;39150:23;39182;39214:17;39240:8;39257:7;39273:16;39108:19;:188::i;43808:260::-:0;43886:25;84155:9;:7;:9::i;:::-;84150:171;;84183:13;84191:4;84183:7;:13::i;:::-;84175:63;;;;-1:-1:-1;;;84175:63:0;;;;;;;:::i;:::-;84256:15;84266:4;84256:9;:15::i;:::-;84255:16;84247:66;;;;-1:-1:-1;;;84247:66:0;;;;;;;:::i;:::-;43976:41:::1;18282:42;44005:11;43976:14;:41::i;:::-;44031:31;44050:11;44031:31;;;;;;:::i;:::-;;;;;;;;43808:260:::0;;:::o;31882:376::-;32204:25;32238:14;21584:42;32238:9;:14::i;:::-;31882:376;;;;;;;;;:::o;78807:131::-;78858:12;78903:6;:21;78918:4;78910:13;;;;;;-1:-1:-1;;;78910:13:0;;;;;;;;;78903:21;;;;;;;;;;;-1:-1:-1;78903:21:0;:29;-1:-1:-1;;;;;78903:29:0;78889:10;:43;;;-1:-1:-1;;78807:131:0:o;79176:116::-;79229:11;79258:6;:21;79273:4;79265:13;;;;;;-1:-1:-1;;;79265:13:0;;;;;;;;;79258:21;;;;;;;;;;;-1:-1:-1;79258:21:0;:28;-1:-1:-1;;;79258:28:0;;;;;;-1:-1:-1;;79176:116:0:o;60460:2105::-;60721:24;;;;;60883:7;:33;;;;;;-1:-1:-1;;;60883:33:0;;;;;;;;;;60879:258;;;60989:16;60942:44;:11;60958:27;60942:15;:44::i;:::-;:63;;;;:::i;:::-;60927:79;;61032:16;61015:33;;60879:258;;;61085:44;:11;61101:27;61085:15;:44::i;:::-;61071:58;;60879:258;61223:58;61262:5;61269:11;61223:38;:58::i;:::-;61342:21;61365:24;61393:65;61431:5;18173:42;61446:5;61393:21;:65::i;:::-;61341:117;;;;61567:27;61552:11;:42;61548:572;;;18071:42;-1:-1:-1;;;;;61615:37:0;;61663:11;61676:17;61695:4;61709;61716:8;61615:118;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;61615:118:0;;;;;;;;;;;;:::i;:::-;61605:128;;61761:7;61769:1;61761:10;;;;;;-1:-1:-1;;;61761:10:0;;;;;;;;;;;;;;;61742:29;;61548:572;;;61794:29;61826:21;61794:53;;18071:42;-1:-1:-1;;;;;61856:66:0;;61933:11;61955:17;61983:4;62006;62022:8;61856:183;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62091:21;62067;:45;;;;:::i;:::-;62048:64;;61548:572;;62143:22;62132:7;:33;;;;;;-1:-1:-1;;;62132:33:0;;;;;;;;;;62128:432;;62276:76;62307:36;62326:17;62307:16;:36;:::i;:::-;62276:16;;:20;:76::i;:::-;62259:93;-1:-1:-1;62458:33:0;62259:93;62458:16;:33;:::i;:::-;62436:55;;62128:432;;;62536:16;62514:38;;62128:432;60460:2105;;;;;;;;;;;;;;:::o;77993:571::-;78223:335;78237:12;:41;;78268:10;78237:41;;;78260:4;78237:41;78287:14;:35;;78317:5;78287:35;;;78312:1;78287:35;78331:14;:35;;78364:1;78331:35;;;78348:5;78331:35;78375:10;:107;;-1:-1:-1;;;;;78416:40:0;;;;:65;;78476:5;78416:65;;;17561:42;78416:65;78375:107;;;78403:1;78375:107;78491:14;78514;78537;78223:335;;;;;;;;;;;;:::i;:::-;;;;;;;;77993:571;;;;;;;:::o;83472:364::-;83567:14;83564:1;83561;83548:34;83662:1;83659;83643:14;83640:1;83624:14;83617:5;83604:60;83693:16;83690:1;83687;83672:38;83725:6;83739:38;;;;83805:16;83802:1;83795:27;83739:38;83758:16;83755:1;83748:27;82999:270;83131:17;:45;;;-1:-1:-1;83163:13:0;83152:7;:24;;;;;;-1:-1:-1;;;83152:24:0;;;;;;;;;;;83131:45;83115:148;;;;-1:-1:-1;;;83115:148:0;;;;;;;:::i;62812:4104::-;63187:25;63221:22;63250;63279:21;63387:74;63426:13;63441:19;63387:38;:74::i;:::-;-1:-1:-1;;;;;63515:58:0;;;;63511:173;;;-1:-1:-1;17561:42:0;63511:173;;;-1:-1:-1;63653:23:0;63511:173;63696:26;63692:2682;;63782:21;63805:24;63833:85;63873:13;63889;63904:5;63833:21;:85::i;:::-;63781:137;;-1:-1:-1;63781:137:0;-1:-1:-1;18071:42:0;64021:40;64083:22;64072:7;:33;;;;;;-1:-1:-1;;;64072:33:0;;;;;;;;;;:114;;64167:19;64072:114;;;64117:38;64139:16;64117:19;:38;:::i;:::-;64197:25;64233:4;64256;64272:8;64021:268;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;64021:268:0;;;;;;;;;;;;:::i;:::-;64011:278;;64320:7;64328:1;64320:10;;;;;;-1:-1:-1;;;64320:10:0;;;;;;;;;;;;;;;64300:30;;64356:22;64345:33;;;;;;-1:-1:-1;;;64345:33:0;;;;;;;;;:7;:33;;;;;;-1:-1:-1;;;64345:33:0;;;;;;;;;;64341:414;;;64489:89;64522:45;64542:25;64522:17;:45;:::i;:::-;64489:16;;:20;:89::i;:::-;64472:106;-1:-1:-1;64606:34:0;64472:106;64606:17;:34;:::i;:::-;64589:51;;64341:414;;;64684:16;64667:33;;64728:17;64711:34;;64341:414;63692:2682;;;;;64836:21;64859:24;64887:77;64927:13;18173:42;64950:5;64887:21;:77::i;:::-;64835:129;;-1:-1:-1;64835:129:0;-1:-1:-1;18071:42:0;65068:40;65130:22;65119:7;:33;;;;;;-1:-1:-1;;;65119:33:0;;;;;;;;;;:114;;65214:19;65119:114;;;65164:38;65186:16;65164:19;:38;:::i;:::-;65255:13;65244:7;:24;;;;;;-1:-1:-1;;;65244:24:0;;;;;;;;;;:47;;65290:1;65244:47;;;65271:16;65244:47;65302:4;65325;65341:8;65068:290;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;65068:290:0;;;;;;;;;;;;:::i;:::-;65058:300;;65384:7;65392:1;65384:10;;;;;;-1:-1:-1;;;65384:10:0;;;;;;;;;;;;;;;65367:27;;65481:68;18173:42;65520:13;65535:5;65481:21;:68::i;:::-;65463:86;;-1:-1:-1;65463:86:0;-1:-1:-1;18071:42:0;65652:40;65714:13;65703:7;:24;;;;;;-1:-1:-1;;;65703:24:0;;;;;;;;;;:95;;65784:14;65703:95;;;65739:33;65756:16;65739:14;:33;:::i;:::-;65809:25;65845:4;65868;65884:8;65652:249;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;65652:249:0;;;;;;;;;;;;:::i;:::-;65642:259;;65932:7;65940:1;65932:10;;;;;;-1:-1:-1;;;65932:10:0;;;;;;;;;;;;;;;65912:30;;65968:22;65957:33;;;;;;-1:-1:-1;;;65957:33:0;;;;;;;;;:7;:33;;;;;;-1:-1:-1;;;65957:33:0;;;;;;;;;;65953:414;;;66101:89;66134:45;66154:25;66134:17;:45;:::i;66101:89::-;66084:106;-1:-1:-1;66218:34:0;66084:106;66218:17;:34;:::i;:::-;66201:51;;65953:414;;;66296:16;66279:33;;66340:17;66323:34;;65953:414;63692:2682;;;66382:320;66401:7;66425:13;66448:23;66491:13;66480:7;:24;;;;;;-1:-1:-1;;;66480:24:0;;;;;;;;;;:141;;66541:22;66530:7;:33;;;;;;-1:-1:-1;;;66530:33:0;;;;;;;;;;:84;;66600:13;66530:84;;;66571:13;66530:84;66480:141;;;18173:42;66480:141;66630:19;66658:14;66681;66382:10;:320::i;:::-;-1:-1:-1;;;;;66723:24:0;;66742:4;66723:24;;;;:93;;-1:-1:-1;;;;;;66758:58:0;;;;;66723:93;66711:200;;;66833:70;66863:13;66879:7;66888:14;66833;:70::i;:::-;62812:4104;;;;;;;;;;;;;;:::o;82292:259::-;82419:50;82434:11;82447:21;82419:14;:50::i;:::-;82403:142;;;;-1:-1:-1;;;82403:142:0;;;;;;;:::i;81557:353::-;81719:7;81732:9;-1:-1:-1;;;;;81732:14:0;81753:11;81732:37;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81718:51;;;81781:2;81776:129;;81835:16;81832:1;;81814:38;81872:16;81832:1;81862:27;81916:370;82011:12;82025:17;82054:5;-1:-1:-1;;;;;82046:19:0;82097:27;;;82126:4;82140;82147:6;82074:80;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;82074:80:0;;;;;;;;;;;;;;-1:-1:-1;;;;;82074:80:0;-1:-1:-1;;;;;;82074:80:0;;;;;;;;;;82046:115;;;;82074:80;82046:115;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;82010:151;;;;82186:7;:57;;;;-1:-1:-1;82198:11:0;;:16;;:44;;;82229:4;82218:24;;;;;;;;;;;;:::i;:::-;82170:110;;;;-1:-1:-1;;;82170:110:0;;;;;;;:::i;58855:1599::-;59312:16;;;59326:1;59312:16;;;;;;;;59114:25;;;;;;;;;;59312:16;59326:1;59312:16;;;;;;;;;;-1:-1:-1;59312:16:0;59288:40;;18173:42;59335:4;59340:1;59335:7;;;;;;-1:-1:-1;;;59335:7:0;;;;;;;;;-1:-1:-1;;;;;59335:15:0;;;:7;;;;;;;;;:15;59361:58;;;;59357:261;;;17561:42;59430:4;59435:1;59430:7;;;;;;-1:-1:-1;;;59430:7:0;;;;;;;;;;;;;;:24;-1:-1:-1;;;;;59430:24:0;;;-1:-1:-1;;;;;59430:24:0;;;;;59485:4;59463:27;;59357:261;;;59523:23;59513:4;59518:1;59513:7;;;;;;-1:-1:-1;;;59513:7:0;;;;;;;;;;;;;;:33;-1:-1:-1;;;;;59513:33:0;;;-1:-1:-1;;;;;59513:33:0;;;;;59569:12;:41;;59600:10;59569:41;;;59592:4;59569:41;59555:55;;59357:261;59732:16;;;59746:1;59732:16;;;;;;;;59705:24;;59732:16;;;;;;;;;;-1:-1:-1;;59705:43:0;-1:-1:-1;18071:42:0;59765:37;59828:22;59817:7;:33;;;;;;-1:-1:-1;;;59817:33:0;;;;;;;;;;;:94;;59900:11;59817:94;;;59860:30;59874:16;59860:11;:30;:::i;:::-;59927:17;59953:4;59966:11;59986:8;59765:236;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;59765:236:0;;;;;;;;;;;;:::i;:::-;59755:246;;60028:7;60036:1;60028:10;;;;;;-1:-1:-1;;;60028:10:0;;;;;;;;;;;;;;;60008:30;;60062:22;60051:33;;;;;;-1:-1:-1;;;60051:33:0;;;;;;;;;:7;:33;;;;;;-1:-1:-1;;;60051:33:0;;;;;;;;;;60047:402;;;60195:77;60226:37;60246:17;60226;:37;:::i;60047:402::-;-1:-1:-1;60424:17:0;;;;-1:-1:-1;60377:16:0;;-1:-1:-1;58855:1599:0;;-1:-1:-1;;;;;;;;58855:1599:0:o;79647:1554::-;79756:4;79844:20;79912:28;;;;;;;;;;;;;;;;;79885:135;;;;;79951:21;;21120:58;;21106:77;79885:135;;:::i;:::-;;;;-1:-1:-1;;79885:135:0;;;;;;;;;79867:160;;79885:135;79867:160;;;;;-1:-1:-1;80116:14:0;;80137:958;80169:2;80161:5;:10;80137:958;;;80499:307;;;;18461:94;;80658:5;;80730:12;;80499:307;;;:::i;:::-;;;;;;;;;;;;;80421:400;;;;;;80343:491;;80191:663;;80961:11;-1:-1:-1;;;;;80951:21:0;:6;-1:-1:-1;;;;;80951:21:0;;80947:59;;;80992:4;80985:11;;;;;;;80947:59;81080:7;;;;:::i;:::-;;;;80173;;;;;:::i;:::-;;;;80137:958;;;-1:-1:-1;81190:5:0;;79647:1554;-1:-1:-1;;;;;79647:1554:0:o;30033:968::-;30120:26;30269:2;30249:10;:17;:22;:106;;;;-1:-1:-1;30326:13:0;;-1:-1:-1;;;30343:12:0;30326:10;;30337:1;;30326:13;;-1:-1:-1;;;30326:13:0;;;;;;;;;;;;;-1:-1:-1;;;;;;30326:13:0;:29;30249:106;:146;;;;-1:-1:-1;30366:13:0;;-1:-1:-1;;;30383:12:0;30366:10;;30377:1;;30366:13;;;;-1:-1:-1;;;30366:13:0;;;;;;;;;;;;;-1:-1:-1;;;;;;30366:13:0;:29;30249:146;:186;;;;-1:-1:-1;30406:13:0;;-1:-1:-1;;;30423:12:0;30406:10;;30417:1;;30406:13;;;;-1:-1:-1;;;30406:13:0;;;;;;;;;;;;;-1:-1:-1;;;;;;30406:13:0;:29;30249:186;:226;;;;-1:-1:-1;30446:13:0;;-1:-1:-1;;;30463:12:0;30446:10;;30457:1;;30446:13;;;;-1:-1:-1;;;30446:13:0;;;;;;;;;;;;;-1:-1:-1;;;;;;30446:13:0;:29;30249:226;30237:759;;;30565:30;30628:1;30608:10;:17;:21;;;;:::i;:::-;-1:-1:-1;;;;;30598:32:0;;;;;-1:-1:-1;;;30598:32:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;30598:32:0;-1:-1:-1;30565:65:0;-1:-1:-1;30656:1:0;30639:109;30663:10;:17;30659:1;:21;30639:109;;;30725:10;30736:1;30725:13;;;;;;-1:-1:-1;;;30725:13:0;;;;;;;;;;;;;-1:-1:-1;;;;;;30725:13:0;30698:17;30716:5;30720:1;30716;:5;:::i;:::-;30698:24;;;;;;-1:-1:-1;;;30698:24:0;;;;;;;;;;;;:40;-1:-1:-1;;;;;30698:40:0;;;;;;;;-1:-1:-1;30682:3:0;;;;:::i;:::-;;;;30639:109;;;;30842:17;30831:39;;;;;;;;;;;;:::i;:::-;30816:54;;30237:759;;;;-1:-1:-1;30953:35:0;;;;;;;;;;;;-1:-1:-1;;;30953:35:0;;;;30237:759;30033:968;;;:::o;83275:191::-;83367:13;83356:7;:24;;;;;;-1:-1:-1;;;83356:24:0;;;;;;;;;;;83340:120;;;;-1:-1:-1;;;83340:120:0;;;;;;;:::i;70569:3132::-;70696:25;70730:28;-1:-1:-1;;;;;70768:63:0;;:4;:28;;;-1:-1:-1;;;;;70768:63:0;;:144;;70883:4;:28;;;70768:144;;;17561:42;70768:144;70730:189;;71006:114;71053:4;:18;;;71073:4;:40;;;71006:38;:114::i;:::-;71220:21;71247:116;71287:4;:18;;;71316:13;71332:4;:22;;;71247:21;:116::i;:::-;71219:144;;;71452:42;71497:13;-1:-1:-1;;;;;71497:23:0;;71539:4;71497:56;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;71452:101;-1:-1:-1;18071:42:0;71646:69;71742:22;71726:4;:12;;;:38;;;;;;-1:-1:-1;;;71726:38:0;;;;;;;;;;:166;;71852:4;:40;;;71726:166;;;71819:4;:21;;;71776:4;:40;;;:64;;;;:::i;:::-;71903:4;:30;;;71944:4;71967;71983;:13;;;71646:359;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;72036:38:0;;-1:-1:-1;;;72036:38:0;;72077:34;;-1:-1:-1;;;;;;72036:23:0;;;-1:-1:-1;72036:23:0;;:38;;72068:4;;72036:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:75;;;;:::i;:::-;72182:12;;72016:95;;-1:-1:-1;72125:38:0;;-1:-1:-1;;;;;;72182:29:0;72206:4;72182:29;;;;-1:-1:-1;72182:103:0;;-1:-1:-1;72222:28:0;;;;-1:-1:-1;;;;;72222:63:0;;;;;72182:103;72170:1188;;;72458:12;;72422:59;;-1:-1:-1;;;72422:59:0;;72375:44;;-1:-1:-1;;;;;72422:23:0;;;;;:59;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;72621:12;;72375:106;;-1:-1:-1;72568:213:0;;72595:13;;72662:22;72646:4;:12;;;:38;;;;;;-1:-1:-1;;;72646:38:0;;;;;;;;;;:124;;72753:17;72646:124;;;72718:21;;;;72698:41;;:17;:41;:::i;:::-;72568:14;:213::i;:::-;72851:12;;72827:37;;-1:-1:-1;;;72827:37:0;;72867:36;;-1:-1:-1;;;;;72827:23:0;;;;;:37;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:76;;;;:::i;:::-;72794:109;;72170:1188;73042:4;:46;;;73008:30;:80;;72990:188;;;;-1:-1:-1;;;72990:188:0;;;;;;;:::i;:::-;72170:1188;;;73250:22;73234:4;:12;;;:38;;;;;;-1:-1:-1;;;73234:38:0;;;;;;;;;;:116;;73333:17;73234:116;;;73302:21;;;;73282:41;;:17;:41;:::i;:::-;73201:149;;72170:1188;73385:12;;73414:18;;;;73442:28;;;;73366:329;;73385:12;73414:18;73495:22;73479:4;:12;;;:38;;;;;;-1:-1:-1;;;73479:38:0;;;;;;;;;;:107;;73567:4;:18;;;73479:107;;;73535:13;73479:107;73595:4;:24;;;73628:30;73667:4;:21;;;73366:10;:329::i;:::-;70569:3132;;;;;:::o;57926:367::-;58239:25;58273:14;21584:42;58273:9;:14::i;:::-;57926:367;;;;;;;;;;:::o;81207:344::-;81298:12;81312:17;81341:5;-1:-1:-1;;;;;81333:19:0;81384:23;;;81409:2;81413:6;81361:59;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;81361:59:0;;;;;;;;;;;;;;-1:-1:-1;;;;;81361:59:0;-1:-1:-1;;;;;;81361:59:0;;;;;;;;;;81333:94;;;;81361:59;81333:94;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81297:130;;;;81450:7;:57;;;;-1:-1:-1;81462:11:0;;:16;;:44;;;81493:4;81482:24;;;;;;;;;;;;:::i;:::-;81434:111;;;;-1:-1:-1;;;81434:111:0;;;;;;;:::i;29633:392::-;29798:10;29820:4;29798:27;:66;;;;-1:-1:-1;29829:16:0;;-1:-1:-1;;;;;;29829:35:0;;;:16;;;;;;:35;;29798:66;29782:168;;;;-1:-1:-1;;;29782:168:0;;;;;;;:::i;:::-;-1:-1:-1;30003:16:0;29996:23;;-1:-1:-1;;29996:23:0;;;29633:392::o;77305:268::-;77367:35;77405:6;:21;77420:4;77412:13;;;;;;-1:-1:-1;;;77412:13:0;;;;;;;;;77405:21;;;;;;;;;;;-1:-1:-1;77405:21:0;77450:24;;77405:21;;-1:-1:-1;;;;;;77439:35:0;;;77450:24;;77439:35;77435:133;;77485:34;;-1:-1:-1;;;;;;77485:34:0;-1:-1:-1;;;;;77485:34:0;;;;;77546:4;77533:27;;;;;;-1:-1:-1;;;77533:27:0;;;;;;;;;;77552:7;77533:27;;;;;;:::i;:::-;;;;;;;;77305:268;;;:::o;15308:100::-;15366:7;15393:1;15389;:5;:13;;15401:1;15389:13;;;-1:-1:-1;15397:1:0;;15308:100;-1:-1:-1;15308:100:0:o;56757:1163::-;56873:56;;-1:-1:-1;;;56873:56:0;;56932:6;;-1:-1:-1;;;;;56873:15:0;;;;;:56;;56897:4;;18071:42;;56873:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:65;56869:1046;;;57024:12;57038:17;57067:5;-1:-1:-1;;;;;57059:19:0;57124:22;;;18071:42;57182:1;57089:106;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;57089:106:0;;;;;;;;;;;;;;-1:-1:-1;;;;;57089:106:0;-1:-1:-1;;;;;;57089:106:0;;;;;;;;;;57059:145;;;;57089:106;57059:145;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57023:181;;;;57321:5;-1:-1:-1;;;;;57313:19:0;57378:22;;;18071:42;-1:-1:-1;;57343:113:0;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;57343:113:0;;;;;;;;;;;;;;-1:-1:-1;;;;;57343:113:0;-1:-1:-1;;;;;;57343:113:0;;;;;;;;;;57313:152;;;;57343:113;57313:152;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;57295:170:0;;-1:-1:-1;57295:170:0;-1:-1:-1;57295:170:0;57476:283;;57608:5;-1:-1:-1;;;;;57600:19:0;57669:22;;;18071:42;57719:6;57632:106;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;57632:106:0;;;;;;;;;;;;;;-1:-1:-1;;;;;57632:106:0;-1:-1:-1;;;;;;57632:106:0;;;;;;;;;;57600:149;;;;57632:106;57600:149;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;57582:167:0;;-1:-1:-1;57582:167:0;-1:-1:-1;57476:283:0;57787:7;:57;;;;-1:-1:-1;57799:11:0;;:16;;:44;;;57830:4;57819:24;;;;;;;;;;;;:::i;:::-;57769:138;;;;-1:-1:-1;;;57769:138:0;;;;;;;:::i;82557:436::-;82673:16;82691;82716:18;82737:17;:25;;82761:1;82737:25;;;82757:1;82737:25;82716:46;;;;82769:21;82807:10;-1:-1:-1;;;;;82793:25:0;;;;;-1:-1:-1;;;82793:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;82793:25:0;;82769:49;;82835:5;82825:4;82830:1;82825:7;;;;;;-1:-1:-1;;;82825:7:0;;;;;;;;;;;;;;:15;-1:-1:-1;;;;;82825:15:0;;;-1:-1:-1;;;;;82825:15:0;;;;;82853:17;82849:55;;;18173:42;82881:4;82886:1;82881:7;;;;;;-1:-1:-1;;;82881:7:0;;;;;;;;;;;;;;:15;-1:-1:-1;;;;;82881:15:0;;;-1:-1:-1;;;;;82881:15:0;;;;;82849:55;82935:3;82912:4;82917:14;82930:1;82917:10;:14;:::i;:::-;82912:20;;;;;;-1:-1:-1;;;82912:20:0;;;;;;;;;;;;;;:26;-1:-1:-1;;;;;82912:26:0;;;-1:-1:-1;;;;;82912:26:0;;;;;82955:4;82975:10;-1:-1:-1;;;;;82961:25:0;;;;;-1:-1:-1;;;82961:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;82961:25:0;;82947:40;;;;;;82557:436;;;;;;:::o;77579:408::-;77818:163;77832:7;77848:13;77870;77892;77914:14;77937;77960;77818:163;;;;;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;:::o;14:311:1:-;;120:54;136:37;166:6;136:37;:::i;:::-;120:54;:::i;:::-;111:63;;197:6;190:5;183:21;237:3;228:6;223:3;219:16;216:25;213:2;;;254:1;251;244:12;213:2;267:52;312:6;305:4;298:5;294:16;289:3;267:52;:::i;330:151::-;406:20;;455:1;445:12;;435:2;;471:1;468;461:12;486:148;559:20;;608:1;598:12;;588:2;;624:1;621;614:12;639:181;708:20;;-1:-1:-1;;;;;757:38:1;;747:49;;737:2;;810:1;807;800:12;825:259;;937:2;925:9;916:7;912:23;908:32;905:2;;;958:6;950;943:22;905:2;1002:9;989:23;1021:33;1048:5;1021:33;:::i;1089:271::-;;1220:2;1208:9;1199:7;1195:23;1191:32;1188:2;;;1241:6;1233;1226:22;1188:2;1278:9;1272:16;1297:33;1324:5;1297:33;:::i;1365:478::-;;;;1519:2;1507:9;1498:7;1494:23;1490:32;1487:2;;;1540:6;1532;1525:22;1487:2;1584:9;1571:23;1603:33;1630:5;1603:33;:::i;:::-;1655:5;-1:-1:-1;1712:2:1;1697:18;;1684:32;1725:35;1684:32;1725:35;:::i;:::-;1477:366;;1779:7;;-1:-1:-1;;;1833:2:1;1818:18;;;;1805:32;;1477:366::o;1848:335::-;;;1985:2;1973:9;1964:7;1960:23;1956:32;1953:2;;;2006:6;1998;1991:22;1953:2;2050:9;2037:23;2069:33;2096:5;2069:33;:::i;:::-;2121:5;2173:2;2158:18;;;;2145:32;;-1:-1:-1;;;1943:240:1:o;2188:854::-;;;;;2361:2;2349:9;2340:7;2336:23;2332:32;2329:2;;;2382:6;2374;2367:22;2329:2;2426:9;2413:23;2445:33;2472:5;2445:33;:::i;:::-;2497:5;-1:-1:-1;2549:2:1;2534:18;;2521:32;;-1:-1:-1;2604:2:1;2589:18;;2576:32;-1:-1:-1;;;;;2657:14:1;;;2654:2;;;2689:6;2681;2674:22;2654:2;2732:6;2721:9;2717:22;2707:32;;2777:7;2770:4;2766:2;2762:13;2758:27;2748:2;;2804:6;2796;2789:22;2748:2;2849;2836:16;2875:2;2867:6;2864:14;2861:2;;;2896:6;2888;2881:22;2861:2;2946:7;2941:2;2932:6;2928:2;2924:15;2920:24;2917:37;2914:2;;;2972:6;2964;2957:22;2914:2;2319:723;;;;-1:-1:-1;;3008:2:1;3000:11;;-1:-1:-1;;;2319:723:1:o;3047:402::-;;;3176:2;3164:9;3155:7;3151:23;3147:32;3144:2;;;3197:6;3189;3182:22;3144:2;3241:9;3228:23;3260:33;3287:5;3260:33;:::i;:::-;3312:5;-1:-1:-1;3369:2:1;3354:18;;3341:32;3382:35;3341:32;3382:35;:::i;:::-;3436:7;3426:17;;;3134:315;;;;;:::o;3454:636::-;;;;;3639:3;3627:9;3618:7;3614:23;3610:33;3607:2;;;3661:6;3653;3646:22;3607:2;3705:9;3692:23;3724:33;3751:5;3724:33;:::i;:::-;3776:5;-1:-1:-1;3833:2:1;3818:18;;3805:32;3846:35;3805:32;3846:35;:::i;:::-;3900:7;-1:-1:-1;3959:2:1;3944:18;;3931:32;3972:35;3931:32;3972:35;:::i;:::-;3597:493;;;;-1:-1:-1;4026:7:1;;4080:2;4065:18;4052:32;;-1:-1:-1;;3597:493:1:o;4095:464::-;;;;;4258:3;4246:9;4237:7;4233:23;4229:33;4226:2;;;4280:6;4272;4265:22;4226:2;4324:9;4311:23;4343:33;4370:5;4343:33;:::i;:::-;4395:5;4447:2;4432:18;;4419:32;;-1:-1:-1;4498:2:1;4483:18;;4470:32;;4549:2;4534:18;4521:32;;-1:-1:-1;4216:343:1;-1:-1:-1;;;4216:343:1:o;4564:558::-;;;;;;4755:3;4743:9;4734:7;4730:23;4726:33;4723:2;;;4777:6;4769;4762:22;4723:2;4821:9;4808:23;4840:33;4867:5;4840:33;:::i;:::-;4892:5;-1:-1:-1;4944:2:1;4929:18;;4916:32;;-1:-1:-1;4995:2:1;4980:18;;4967:32;;-1:-1:-1;5046:2:1;5031:18;;5018:32;;-1:-1:-1;5069:47:1;5111:3;5096:19;;5069:47;:::i;:::-;5059:57;;4713:409;;;;;;;;:::o;5127:533::-;;;;;;5307:3;5295:9;5286:7;5282:23;5278:33;5275:2;;;5329:6;5321;5314:22;5275:2;5373:9;5360:23;5392:33;5419:5;5392:33;:::i;:::-;5444:5;5496:2;5481:18;;5468:32;;-1:-1:-1;5547:2:1;5532:18;;5519:32;;5598:2;5583:18;;5570:32;;-1:-1:-1;5649:3:1;5634:19;5621:33;;-1:-1:-1;5265:395:1;-1:-1:-1;;;5265:395:1:o;5665:627::-;;;;;;;5873:3;5861:9;5852:7;5848:23;5844:33;5841:2;;;5895:6;5887;5880:22;5841:2;5939:9;5926:23;5958:33;5985:5;5958:33;:::i;:::-;6010:5;-1:-1:-1;6062:2:1;6047:18;;6034:32;;-1:-1:-1;6113:2:1;6098:18;;6085:32;;-1:-1:-1;6164:2:1;6149:18;;6136:32;;-1:-1:-1;6215:3:1;6200:19;;6187:33;;-1:-1:-1;6239:47:1;6281:3;6266:19;;6239:47;:::i;:::-;6229:57;;5831:461;;;;;;;;:::o;6297:696::-;;;;;;;;6522:3;6510:9;6501:7;6497:23;6493:33;6490:2;;;6544:6;6536;6529:22;6490:2;6588:9;6575:23;6607:33;6634:5;6607:33;:::i;:::-;6659:5;-1:-1:-1;6711:2:1;6696:18;;6683:32;;-1:-1:-1;6762:2:1;6747:18;;6734:32;;-1:-1:-1;6813:2:1;6798:18;;6785:32;;-1:-1:-1;6864:3:1;6849:19;;6836:33;;-1:-1:-1;6916:3:1;6901:19;;6888:33;;-1:-1:-1;6940:47:1;6982:3;6967:19;;6940:47;:::i;:::-;6930:57;;6480:513;;;;;;;;;;:::o;6998:1585::-;;7150:2;7193;7181:9;7172:7;7168:23;7164:32;7161:2;;;7214:6;7206;7199:22;7161:2;7252:9;7246:16;-1:-1:-1;;;;;7322:2:1;7314:6;7311:14;7308:2;;;7343:6;7335;7328:22;7308:2;7386:6;7375:9;7371:22;7361:32;;7431:7;7424:4;7420:2;7416:13;7412:27;7402:2;;7458:6;7450;7443:22;7402:2;7492;7486:9;7515:77;7531:60;7588:2;7531:60;:::i;7515:77::-;7626:15;;;7657:12;;;;7689:11;;;7718:6;7733:820;7747:2;7744:1;7741:9;7733:820;;;7816:3;7810:10;7806:2;7802:19;7844:4;7900:2;7894;7890:7;7885:2;7876:7;7872:16;7868:30;7864:39;7861:2;;;7921:6;7913;7906:22;7861:2;7956:19;7972:2;7956:19;:::i;:::-;8017:2;8013;8009:11;8003:18;8034:32;8058:7;8034:32;:::i;:::-;8079:22;;8136:11;;;8130:18;8164:16;;;8161:2;;;8198:6;8190;8183:22;8161:2;8238:8;8234:2;8230:17;8220:27;;;8287:7;8282:2;8278;8274:11;8270:25;8260:2;;8314:6;8306;8299:22;8260:2;8359:88;8439:7;8433:2;8429;8425:11;8419:18;8414:2;8410;8406:11;8359:88;:::i;:::-;8343:14;;;8336:112;8461:18;;-1:-1:-1;;8499:12:1;;;;8531;;;;7765:1;7758:9;7733:820;;;-1:-1:-1;8572:5:1;;7130:1453;-1:-1:-1;;;;;;;;;7130:1453:1:o;8588:687::-;;;8756:2;8744:9;8735:7;8731:23;8727:32;8724:2;;;8777:6;8769;8762:22;8724:2;8822:9;8809:23;-1:-1:-1;;;;;8892:2:1;8884:6;8881:14;8878:2;;;8913:6;8905;8898:22;8878:2;8956:6;8945:9;8941:22;8931:32;;9001:7;8994:4;8990:2;8986:13;8982:27;8972:2;;9028:6;9020;9013:22;8972:2;9073;9060:16;9099:2;9091:6;9088:14;9085:2;;;9120:6;9112;9105:22;9085:2;9179:7;9174:2;9168;9160:6;9156:15;9152:2;9148:24;9144:33;9141:46;9138:2;;;9205:6;9197;9190:22;9138:2;9241;9233:11;;;;;9263:6;;-1:-1:-1;8714:561:1;;-1:-1:-1;;;;8714:561:1:o;9280:1956::-;;9414:2;9457;9445:9;9436:7;9432:23;9428:32;9425:2;;;9478:6;9470;9463:22;9425:2;9523:9;9510:23;-1:-1:-1;;;;;9593:2:1;9585:6;9582:14;9579:2;;;9614:6;9606;9599:22;9579:2;9657:6;9646:9;9642:22;9632:32;;9702:7;9695:4;9691:2;9687:13;9683:27;9673:2;;9729:6;9721;9714:22;9673:2;9770;9757:16;9793:77;9809:60;9866:2;9809:60;:::i;9793:77::-;9904:15;;;9935:12;;;;9967:11;;;9996:6;10011:1195;10025:2;10022:1;10019:9;10011:1195;;;10101:3;10088:17;10084:2;10080:26;10129:4;10185:2;10179;10175:7;10170:2;10161:7;10157:16;10153:30;10149:39;10146:2;;;10206:6;10198;10191:22;10146:2;10241:19;10257:2;10241:19;:::i;:::-;10309:2;10305;10301:11;10288:25;10326:35;10353:7;10326:35;:::i;:::-;10374:22;;10419:2;10457:32;10477:11;;;10457:32;:::i;:::-;10441:14;;;10434:56;10532:11;;;10519:25;;10560:16;;;10557:2;;;10594:6;10586;10579:22;10557:2;10634:8;10630:2;10626:17;10616:27;;10683:7;10678:2;10674;10670:11;10666:25;10656:2;;10710:6;10702;10695:22;10656:2;10763;10759;10755:11;10742:25;10732:35;;10793:50;10809:33;10839:2;10809:33;:::i;10793:50::-;10870:2;10863:5;10856:17;10914:7;10909:2;10904;10900;10896:11;10892:20;10889:33;10886:2;;;10940:6;10932;10925:22;10886:2;11004;10999;10995;10991:11;10986:2;10979:5;10975:14;10962:45;11031:14;;;11027:23;;11020:39;;;11079:14;;11072:29;;;;11114:18;;-1:-1:-1;11152:12:1;;;;11184;;;;10043:1;10036:9;10011:1195;;11241:955;;11367:2;11410;11398:9;11389:7;11385:23;11381:32;11378:2;;;11431:6;11423;11416:22;11378:2;11469:9;11463:16;-1:-1:-1;;;;;11494:6:1;11491:30;11488:2;;;11539:6;11531;11524:22;11488:2;11567:22;;11620:4;11612:13;;11608:27;-1:-1:-1;11598:2:1;;11654:6;11646;11639:22;11598:2;11688;11682:9;11711:77;11727:60;11784:2;11727:60;:::i;11711:77::-;11822:15;;;11853:12;;;;11885:11;;;11923;;;11915:20;;11911:29;;11908:42;-1:-1:-1;11905:2:1;;;11968:6;11960;11953:22;11905:2;11995:6;11986:15;;12010:156;12024:2;12021:1;12018:9;12010:156;;;12081:10;;12069:23;;12042:1;12035:9;;;;;12112:12;;;;12144;;12010:156;;;-1:-1:-1;12185:5:1;11347:849;-1:-1:-1;;;;;;;11347:849:1:o;12201:257::-;;12321:2;12309:9;12300:7;12296:23;12292:32;12289:2;;;12342:6;12334;12327:22;12289:2;12379:9;12373:16;12398:30;12422:5;12398:30;:::i;12463:492::-;;;;12631:2;12619:9;12610:7;12606:23;12602:32;12599:2;;;12652:6;12644;12637:22;12960:837;;;;;;;;13193:3;13181:9;13172:7;13168:23;13164:33;13161:2;;;13215:6;13207;13200:22;13161:2;13259:9;13246:23;13278:33;13305:5;13278:33;:::i;:::-;13330:5;-1:-1:-1;13387:2:1;13372:18;;13359:32;13400:35;13359:32;13400:35;:::i;:::-;13454:7;-1:-1:-1;13508:2:1;13493:18;;13480:32;;-1:-1:-1;13559:2:1;13544:18;;13531:32;;-1:-1:-1;13610:3:1;13595:19;;13582:33;;-1:-1:-1;13662:3:1;13647:19;;13634:33;;-1:-1:-1;13719:3:1;13704:19;;13691:33;13733:32;13691:33;13733:32;:::i;:::-;13784:7;13774:17;;;13151:646;;;;;;;;;;:::o;13802:931::-;;;;;;;;;14063:3;14051:9;14042:7;14038:23;14034:33;14031:2;;;14085:6;14077;14070:22;14031:2;14129:9;14116:23;14148:33;14175:5;14148:33;:::i;:::-;14200:5;-1:-1:-1;14257:2:1;14242:18;;14229:32;14270:35;14229:32;14270:35;:::i;:::-;14324:7;-1:-1:-1;14378:2:1;14363:18;;14350:32;;-1:-1:-1;14429:2:1;14414:18;;14401:32;;-1:-1:-1;14480:3:1;14465:19;;14452:33;;-1:-1:-1;14532:3:1;14517:19;;14504:33;;-1:-1:-1;14589:3:1;14574:19;;14561:33;14603:32;14561:33;14603:32;:::i;:::-;14654:7;-1:-1:-1;14680:47:1;14722:3;14707:19;;14680:47;:::i;:::-;14670:57;;14021:712;;;;;;;;;;;:::o;14738:1000::-;;;;;;;;;;15016:3;15004:9;14995:7;14991:23;14987:33;14984:2;;;15038:6;15030;15023:22;14984:2;15082:9;15069:23;15101:33;15128:5;15101:33;:::i;:::-;15153:5;-1:-1:-1;15210:2:1;15195:18;;15182:32;15223:35;15182:32;15223:35;:::i;:::-;15277:7;-1:-1:-1;15331:2:1;15316:18;;15303:32;;-1:-1:-1;15382:2:1;15367:18;;15354:32;;-1:-1:-1;15433:3:1;15418:19;;15405:33;;-1:-1:-1;15485:3:1;15470:19;;15457:33;;-1:-1:-1;15537:3:1;15522:19;;15509:33;;-1:-1:-1;15594:3:1;15579:19;;15566:33;15608:32;15566:33;15608:32;:::i;:::-;15659:7;-1:-1:-1;15685:47:1;15727:3;15712:19;;15685:47;:::i;:::-;15675:57;;14974:764;;;;;;;;;;;:::o;16888:209::-;;17008:2;16996:9;16987:7;16983:23;16979:32;16976:2;;;17029:6;17021;17014:22;16976:2;17057:34;17081:9;17057:34;:::i;17102:346::-;;;17239:2;17227:9;17218:7;17214:23;17210:32;17207:2;;;17260:6;17252;17245:22;17207:2;17288:34;17312:9;17288:34;:::i;17453:490::-;;17586:2;17574:9;17565:7;17561:23;17557:32;17554:2;;;17607:6;17599;17592:22;17554:2;17645:9;17639:16;-1:-1:-1;;;;;17670:6:1;17667:30;17664:2;;;17715:6;17707;17700:22;17664:2;17743:22;;17796:4;17788:13;;17784:27;-1:-1:-1;17774:2:1;;17830:6;17822;17815:22;17774:2;17858:79;17929:7;17924:2;17918:9;17913:2;17909;17905:11;17858:79;:::i;17948:190::-;;18060:2;18048:9;18039:7;18035:23;18031:32;18028:2;;;18081:6;18073;18066:22;18028:2;-1:-1:-1;18109:23:1;;18018:120;-1:-1:-1;18018:120:1:o;18143:194::-;;18266:2;18254:9;18245:7;18241:23;18237:32;18234:2;;;18287:6;18279;18272:22;18234:2;-1:-1:-1;18315:16:1;;18224:113;-1:-1:-1;18224:113:1:o;18342:469::-;;18439:5;18433:12;18466:6;18461:3;18454:19;18492:4;18521:2;18516:3;18512:12;18505:19;;18558:2;18551:5;18547:14;18579:3;18591:195;18605:6;18602:1;18599:13;18591:195;;;18670:13;;-1:-1:-1;;;;;18666:39:1;18654:52;;18726:12;;;;18761:15;;;;18702:1;18620:9;18591:195;;;-1:-1:-1;18802:3:1;;18409:402;-1:-1:-1;;;;;18409:402:1:o;18816:456::-;;18910:5;18904:12;18937:6;18932:3;18925:19;18963:4;18992:2;18987:3;18983:12;18976:19;;19029:2;19022:5;19018:14;19050:3;19062:185;19076:6;19073:1;19070:13;19062:185;;;19151:13;;19144:21;19137:29;19125:42;;19187:12;;;;19222:15;;;;19098:1;19091:9;19062:185;;19277:625;;19372:5;19366:12;19399:6;19394:3;19387:19;19425:4;19466:2;19461:3;19457:12;19491:11;19518;19511:18;;19573:2;19565:6;19561:15;19554:5;19550:27;19538:39;;19611:2;19604:5;19600:14;19632:3;19644:232;19658:6;19655:1;19652:13;19644:232;;;19729:5;19723:4;19719:16;19714:3;19707:29;19757:39;19791:4;19782:6;19776:13;19757:39;:::i;:::-;19854:12;;;;19749:47;-1:-1:-1;19819:15:1;;;;19680:1;19673:9;19644:232;;;-1:-1:-1;19892:4:1;;19342:560;-1:-1:-1;;;;;;;19342:560:1:o;19907:270::-;;19997:6;19992:3;19985:19;20049:6;20042:5;20035:4;20030:3;20026:14;20013:43;20101:3;20094:4;20085:6;20080:3;20076:16;20072:27;20065:40;20166:4;20159:2;20155:7;20150:2;20142:6;20138:15;20134:29;20129:3;20125:39;20121:50;20114:57;;19975:202;;;;;:::o;20182:259::-;;20263:5;20257:12;20290:6;20285:3;20278:19;20306:63;20362:6;20355:4;20350:3;20346:14;20339:4;20332:5;20328:16;20306:63;:::i;:::-;20423:2;20402:15;-1:-1:-1;;20398:29:1;20389:39;;;;20430:4;20385:50;;20233:208;-1:-1:-1;;20233:208:1:o;20446:348::-;-1:-1:-1;;20643:42:1;;;;20631:55;;20711:2;20702:12;;20695:28;;;;20748:2;20739:12;;20732:28;20785:2;20776:12;;20621:173::o;20799:273::-;;20982:6;20974;20969:3;20956:33;21008:16;;21033:15;;;21008:16;20946:126;-1:-1:-1;20946:126:1:o;21077:274::-;;21244:6;21238:13;21260:53;21306:6;21301:3;21294:4;21286:6;21282:17;21260:53;:::i;:::-;21329:16;;;;;21214:137;-1:-1:-1;;21214:137:1:o;21356:504::-;;21579:6;21573:13;21595:53;21641:6;21636:3;21629:4;21621:6;21617:17;21595:53;:::i;:::-;21717:2;21713:15;;;;-1:-1:-1;;21709:53:1;21670:16;;;;21695:68;;;-1:-1:-1;;21795:28:1;;;;21790:2;21779:14;;21772:52;21851:2;21840:14;;21549:311;-1:-1:-1;;21549:311:1:o;21865:205::-;22065:3;22056:14::o;22075:203::-;-1:-1:-1;;;;;22239:32:1;;;;22221:51;;22209:2;22194:18;;22176:102::o;22283:304::-;-1:-1:-1;;;;;22513:15:1;;;22495:34;;22565:15;;22560:2;22545:18;;22538:43;22445:2;22430:18;;22412:175::o;22592:681::-;-1:-1:-1;;;;;22963:15:1;;;22945:34;;23015:15;;;23010:2;22995:18;;22988:43;23067:15;;;23062:2;23047:18;;23040:43;23119:15;;;;23114:2;23099:18;;23092:43;23166:3;23151:19;;23144:35;;;;22925:3;23195:19;;23188:35;;;;23254:3;23239:19;;23232:35;;;;22894:3;22879:19;;22861:412::o;23278:375::-;-1:-1:-1;;;;;23536:15:1;;;23518:34;;23588:15;;;;23583:2;23568:18;;23561:43;23635:2;23620:18;;23613:34;;;;23468:2;23453:18;;23435:218::o;23658:274::-;-1:-1:-1;;;;;23850:32:1;;;;23832:51;;23914:2;23899:18;;23892:34;23820:2;23805:18;;23787:145::o;23937:553::-;;24217:1;24213;24208:3;24204:11;24200:19;24192:6;24188:32;24177:9;24170:51;24257:6;24252:2;24241:9;24237:18;24230:34;24300:3;24295:2;24284:9;24280:18;24273:31;24327:47;24369:3;24358:9;24354:19;24346:6;24327:47;:::i;:::-;24422:9;24414:6;24410:22;24405:2;24394:9;24390:18;24383:50;24450:34;24477:6;24469;24450:34;:::i;24495:484::-;;24764:2;24753:9;24746:21;24790:59;24845:2;24834:9;24830:18;24822:6;24790:59;:::i;:::-;24897:9;24889:6;24885:22;24880:2;24869:9;24865:18;24858:50;24925:48;24966:6;24958;24925:48;:::i;24984:565::-;;25275:2;25264:9;25257:21;25301:59;25356:2;25345:9;25341:18;25333:6;25301:59;:::i;:::-;25408:9;25400:6;25396:22;25391:2;25380:9;25376:18;25369:50;25436:48;25477:6;25469;25436:48;:::i;:::-;25428:56;;;25534:6;25527:14;25520:22;25515:2;25504:9;25500:18;25493:50;25247:302;;;;;;:::o;25554:1050::-;25777:2;25829:21;;;25899:13;;25802:18;;;25921:22;;;25554:1050;;25777:2;25962;;25980:18;;;;26040:15;;;26025:31;;26021:40;;26084:15;;;25554:1050;26130:445;26144:6;26141:1;26138:13;26130:445;;;26209:22;;;-1:-1:-1;;26205:36:1;26193:49;;26265:13;;26320:9;;26313:17;26306:25;26291:41;;26371:11;;26365:18;26403:15;;;26396:27;;;26446:49;26479:15;;;26365:18;26446:49;:::i;:::-;26553:12;;;;26436:59;-1:-1:-1;;26518:15:1;;;;26166:1;26159:9;26130:445;;;-1:-1:-1;26592:6:1;;25757:847;-1:-1:-1;;;;;;;;25757:847:1:o;26609:1840::-;26830:2;26882:21;;;26855:18;;;26938:22;;;26609:1840;;26979:2;26997:18;;;27057:15;;;27042:31;;27038:40;;27101:6;26609:1840;27138:1282;27152:6;27149:1;27146:13;27138:1282;;;27217:22;;;-1:-1:-1;;27213:36:1;27201:49;;27289:20;;27364:14;27360:27;;;-1:-1:-1;;27356:41:1;27332:66;;27322:2;;27415:4;27409;27402:18;27322:2;27448:31;;27502:4;27534:19;;27566:35;27534:19;27566:35;:::i;:::-;-1:-1:-1;;;;;27629:33:1;27614:49;;-1:-1:-1;;;;;27704:35:1;27724:14;;;27704:35;:::i;:::-;27700:68;27695:2;27687:6;27683:15;27676:93;27834:2;27827:5;27823:14;27810:28;27923:2;27919:7;27911:5;27895:14;27891:26;27887:40;27865:20;27861:67;27851:2;;27945:4;27939;27932:18;27851:2;27980:32;;28039:21;;-1:-1:-1;;;;;28076:30:1;;28073:2;;;28122:4;28116;28109:18;28073:2;28176:6;28160:14;28156:27;28149:5;28145:39;28142:2;;;28200:4;28194;28187:18;28142:2;28244;28239;28231:6;28227:15;28220:27;28270:70;28336:2;28328:6;28324:15;28316:6;28311:2;28302:7;28298:16;28270:70;:::i;:::-;28398:12;;;;28260:80;-1:-1:-1;;;28363:15:1;;;;-1:-1:-1;;27174:1:1;27167:9;27138:1282;;28454:1162;28663:2;28715:21;;;28785:13;;28688:18;;;28807:22;;;28454:1162;;28663:2;28848;;28866:18;;;;28926:15;;;28911:31;;28907:40;;28970:15;;;28454:1162;29016:571;29030:6;29027:1;29024:13;29016:571;;;29095:22;;;-1:-1:-1;;29091:36:1;29079:49;;29151:13;;29223:9;;-1:-1:-1;;;;;29219:35:1;29204:51;;29302:11;;;29296:18;-1:-1:-1;;;;;29292:51:1;29275:15;;;29268:76;29383:11;;29377:18;29187:4;29415:15;;;29408:27;;;29458:49;29491:15;;;29377:18;29458:49;:::i;:::-;29565:12;;;;29448:59;-1:-1:-1;;;29530:15:1;;;;29052:1;29045:9;29016:571;;29621:187;29786:14;;29779:22;29761:41;;29749:2;29734:18;;29716:92::o;29813:633::-;;30098:6;30091:14;30084:22;30073:9;30066:41;30172:1;30168;30163:3;30159:11;30155:19;30147:6;30143:32;30138:2;30127:9;30123:18;30116:60;30212:6;30207:2;30196:9;30192:18;30185:34;30255:3;30250:2;30239:9;30235:18;30228:31;30282:47;30324:3;30313:9;30309:19;30301:6;30282:47;:::i;:::-;30378:9;30370:6;30366:22;30360:3;30349:9;30345:19;30338:51;30406:34;30433:6;30425;30406:34;:::i;30451:300::-;;30634:6;30627:14;30620:22;30609:9;30602:41;30679:2;30674;30663:9;30659:18;30652:30;30699:46;30741:2;30730:9;30726:18;30718:6;30699:46;:::i;30986:422::-;31188:2;31170:21;;;31227:2;31207:18;;;31200:30;31266:34;31261:2;31246:18;;31239:62;31337:28;31332:2;31317:18;;31310:56;31398:3;31383:19;;31160:248::o;31413:346::-;31615:2;31597:21;;;31654:2;31634:18;;;31627:30;-1:-1:-1;;;31688:2:1;31673:18;;31666:52;31750:2;31735:18;;31587:172::o;31764:343::-;31966:2;31948:21;;;32005:2;31985:18;;;31978:30;-1:-1:-1;;;32039:2:1;32024:18;;32017:49;32098:2;32083:18;;31938:169::o;32112:472::-;32314:2;32296:21;;;32353:2;32333:18;;;32326:30;32392:34;32387:2;32372:18;;32365:62;32463:34;32458:2;32443:18;;32436:62;-1:-1:-1;;;32529:3:1;32514:19;;32507:35;32574:3;32559:19;;32286:298::o;32589:426::-;32791:2;32773:21;;;32830:2;32810:18;;;32803:30;32869:34;32864:2;32849:18;;32842:62;32940:32;32935:2;32920:18;;32913:60;33005:3;32990:19;;32763:252::o;33020:473::-;33222:2;33204:21;;;33261:2;33241:18;;;33234:30;33300:34;33295:2;33280:18;;33273:62;33371:34;33366:2;33351:18;;33344:62;-1:-1:-1;;;33437:3:1;33422:19;;33415:36;33483:3;33468:19;;33194:299::o;33498:401::-;33700:2;33682:21;;;33739:2;33719:18;;;33712:30;33778:34;33773:2;33758:18;;33751:62;-1:-1:-1;;;33844:2:1;33829:18;;33822:35;33889:3;33874:19;;33672:227::o;33904:347::-;34106:2;34088:21;;;34145:2;34125:18;;;34118:30;34184:25;34179:2;34164:18;;34157:53;34242:2;34227:18;;34078:173::o;34256:473::-;34458:2;34440:21;;;34497:2;34477:18;;;34470:30;34536:34;34531:2;34516:18;;34509:62;34607:34;34602:2;34587:18;;34580:62;-1:-1:-1;;;34673:3:1;34658:19;;34651:36;34719:3;34704:19;;34430:299::o;34734:404::-;34936:2;34918:21;;;34975:2;34955:18;;;34948:30;35014:34;35009:2;34994:18;;34987:62;-1:-1:-1;;;35080:2:1;35065:18;;35058:38;35128:3;35113:19;;34908:230::o;35143:347::-;35345:2;35327:21;;;35384:2;35364:18;;;35357:30;35423:25;35418:2;35403:18;;35396:53;35481:2;35466:18;;35317:173::o;35495:344::-;35697:2;35679:21;;;35736:2;35716:18;;;35709:30;-1:-1:-1;;;35770:2:1;35755:18;;35748:50;35830:2;35815:18;;35669:170::o;35844:405::-;36046:2;36028:21;;;36085:2;36065:18;;;36058:30;36124:34;36119:2;36104:18;;36097:62;-1:-1:-1;;;36190:2:1;36175:18;;36168:39;36239:3;36224:19;;36018:231::o;36254:403::-;36456:2;36438:21;;;36495:2;36475:18;;;36468:30;36534:34;36529:2;36514:18;;36507:62;-1:-1:-1;;;36600:2:1;36585:18;;36578:37;36647:3;36632:19;;36428:229::o;36662:401::-;36864:2;36846:21;;;36903:2;36883:18;;;36876:30;36942:34;36937:2;36922:18;;36915:62;-1:-1:-1;;;37008:2:1;36993:18;;36986:35;37053:3;37038:19;;36836:227::o;37068:401::-;37270:2;37252:21;;;37309:2;37289:18;;;37282:30;37348:34;37343:2;37328:18;;37321:62;-1:-1:-1;;;37414:2:1;37399:18;;37392:35;37459:3;37444:19;;37242:227::o;37474:399::-;37676:2;37658:21;;;37715:2;37695:18;;;37688:30;37754:34;37749:2;37734:18;;37727:62;-1:-1:-1;;;37820:2:1;37805:18;;37798:33;37863:3;37848:19;;37648:225::o;37878:472::-;38080:2;38062:21;;;38119:2;38099:18;;;38092:30;38158:34;38153:2;38138:18;;38131:62;38229:34;38224:2;38209:18;;38202:62;-1:-1:-1;;;38295:3:1;38280:19;;38273:35;38340:3;38325:19;;38052:298::o;38355:404::-;38557:2;38539:21;;;38596:2;38576:18;;;38569:30;38635:34;38630:2;38615:18;;38608:62;-1:-1:-1;;;38701:2:1;38686:18;;38679:38;38749:3;38734:19;;38529:230::o;38764:420::-;38966:2;38948:21;;;39005:2;38985:18;;;38978:30;39044:34;39039:2;39024:18;;39017:62;39115:26;39110:2;39095:18;;39088:54;39174:3;39159:19;;38938:246::o;39189:177::-;39335:25;;;39323:2;39308:18;;39290:76::o;39371:508::-;;39634:6;39623:9;39616:25;39677:3;39672:2;39661:9;39657:18;39650:31;39698:63;39756:3;39745:9;39741:19;39733:6;39698:63;:::i;:::-;-1:-1:-1;;;;;39797:32:1;;;;39792:2;39777:18;;39770:60;-1:-1:-1;39861:2:1;39846:18;39839:34;39690:71;39606:273;-1:-1:-1;;39606:273:1:o;39884:580::-;;40175:6;40164:9;40157:25;40218:6;40213:2;40202:9;40198:18;40191:34;40261:3;40256:2;40245:9;40241:18;40234:31;40282:63;40340:3;40329:9;40325:19;40317:6;40282:63;:::i;:::-;-1:-1:-1;;;;;40381:32:1;;;;40376:2;40361:18;;40354:60;-1:-1:-1;40445:3:1;40430:19;40423:35;40274:71;40147:317;-1:-1:-1;;;40147:317:1:o;40469:275::-;40540:2;40534:9;40605:2;40586:13;;-1:-1:-1;;40582:27:1;40570:40;;-1:-1:-1;;;;;40625:34:1;;40661:22;;;40622:62;40619:2;;;40687:18;;:::i;:::-;40723:2;40716:22;40514:230;;-1:-1:-1;40514:230:1:o;40749:203::-;;-1:-1:-1;;;;;40851:6:1;40848:30;40845:2;;;40881:18;;:::i;:::-;-1:-1:-1;40941:4:1;40922:17;;;40918:28;;40835:117::o;40957:188::-;;-1:-1:-1;;;;;41032:6:1;41029:30;41026:2;;;41062:18;;:::i;:::-;-1:-1:-1;41128:2:1;41107:15;-1:-1:-1;;41103:29:1;41134:4;41099:40;;41016:129::o;41150:128::-;;41221:1;41217:6;41214:1;41211:13;41208:2;;;41227:18;;:::i;:::-;-1:-1:-1;41263:9:1;;41198:80::o;41283:125::-;;41351:1;41348;41345:8;41342:2;;;41356:18;;:::i;:::-;-1:-1:-1;41393:9:1;;41332:76::o;41413:258::-;41485:1;41495:113;41509:6;41506:1;41503:13;41495:113;;;41585:11;;;41579:18;41566:11;;;41559:39;41531:2;41524:10;41495:113;;;41626:6;41623:1;41620:13;41617:2;;;-1:-1:-1;;41661:1:1;41643:16;;41636:27;41466:205::o;41676:135::-;;-1:-1:-1;;41736:17:1;;41733:2;;;41756:18;;:::i;:::-;-1:-1:-1;41803:1:1;41792:13;;41723:88::o;41816:127::-;41877:10;41872:3;41868:20;41865:1;41858:31;41908:4;41905:1;41898:15;41932:4;41929:1;41922:15;41948:127;42009:10;42004:3;42000:20;41997:1;41990:31;42040:4;42037:1;42030:15;42064:4;42061:1;42054:15;42080:133;-1:-1:-1;;;;;42157:31:1;;42147:42;;42137:2;;42203:1;42200;42193:12;42218:120;42306:5;42299:13;42292:21;42285:5;42282:32;42272:2;;42328:1;42325;42318:12

Swarm Source

ipfs://784b1cc3f6622b5c7aae2f03aa8870aed35115d5feb5040157029b0dff2d8f23

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.