Contract 0x0000000000C5FD1aeF1a9421626cf804086185E9

 
Ad
Ad
Txn Hash Method
Block
From
To
Value
0xda5ccdee3e0471b9fc1acaf2804e28ec1b9c6663f93424db8603a62c1038213eSet Attribute Ty...78198962019-05-24 3:13:21846 days 22 hrs agoENS Name 0age.eth IN  0x0000000000c5fd1aef1a9421626cf804086185e90 Ether0.0006584110
0x332095788d7ca4b6e228fb18a904addcad902016d47b404c335a4324ac806ee5Add Attribute Ty...78198912019-05-24 3:11:43846 days 22 hrs agoENS Name 0age.eth IN  0x0000000000c5fd1aef1a9421626cf804086185e90 Ether0.0015462710
[ Download CSV Export 
Latest 1 internal transaction
Parent Txn Hash Block From To Value
0x5fba37ce001dec150398759673cb365a1e513863472fabfd7b760dd1bcafd15978198692019-05-24 3:06:54846 days 22 hrs ago 0x000000000063b99b8036c31e91c64fc89bff9ca7  Contract Creation0 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ExtendedJurisdiction

Compiler Version
v0.4.26+commit.4563c3fc

Optimization Enabled:
Yes with 500 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2019-05-24
*/

pragma solidity 0.4.26; // optimization enabled, runs: 500


/************** TPL Extended Jurisdiction - YES token integration *************
 * This digital jurisdiction supports assigning YES token, or other contracts *
 * with a similar validation mechanism, as additional attribute validators.   *
 * https://github.com/TPL-protocol/tpl-contracts/tree/yes-token-integration   *
 * Implements an Attribute Registry https://github.com/0age/AttributeRegistry *
 *                                                                            *
 * Source layout:                                    Line #                   *
 *  - library ECDSA                                    41                     *
 *  - library SafeMath                                108                     *
 *  - library Roles                                   172                     *
 *  - contract PauserRole                             212                     *
 *    - using Roles for Roles.Role                                            *
 *  - contract Pausable                               257                     *
 *    - is PauserRole                                                         *
 *  - contract Ownable                                313                     *
 *  - interface AttributeRegistryInterface            386                     *
 *  - interface BasicJurisdictionInterface            440                     *
 *  - interface ExtendedJurisdictionInterface         658                     *
 *  - interface IERC20 (partial)                      926                     *
 *  - ExtendedJurisdiction                            934                     *
 *    - is Ownable                                                            *
 *    - is Pausable                                                           *
 *    - is AttributeRegistryInterface                                         *
 *    - is BasicJurisdictionInterface                                         *
 *    - is ExtendedJurisdictionInterface                                      *
 *    - using ECDSA for bytes32                                               *
 *    - using SafeMath for uint256                                            *
 *                                                                            *
 *  https://github.com/TPL-protocol/tpl-contracts/blob/master/LICENSE.md      *
 ******************************************************************************/


/**
 * @title Elliptic curve signature operations
 * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
 * TODO Remove this library once solidity supports passing a signature to ecrecover.
 * See https://github.com/ethereum/solidity/issues/864
 */
library ECDSA {
  /**
   * @dev Recover signer address from a message by using their signature
   * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
   * @param signature bytes signature, the signature is generated using web3.eth.sign()
   */
  function recover(bytes32 hash, bytes signature)
    internal
    pure
    returns (address)
  {
    bytes32 r;
    bytes32 s;
    uint8 v;

    // Check the signature length
    if (signature.length != 65) {
      return (address(0));
    }

    // Divide the signature in r, s and v variables
    // ecrecover takes the signature parameters, and the only way to get them
    // currently is to use assembly.
    // solium-disable-next-line security/no-inline-assembly
    assembly {
      r := mload(add(signature, 0x20))
      s := mload(add(signature, 0x40))
      v := byte(0, mload(add(signature, 0x60)))
    }

    // Version of signature should be 27 or 28, but 0 and 1 are also possible versions
    if (v < 27) {
      v += 27;
    }

    // If the version is correct return the signer address
    if (v != 27 && v != 28) {
      return (address(0));
    } else {
      // solium-disable-next-line arg-overflow
      return ecrecover(hash, v, r, s);
    }
  }

  /**
   * toEthSignedMessageHash
   * @dev prefix a bytes32 value with "\x19Ethereum Signed Message:"
   * and hash the result
   */
  function toEthSignedMessageHash(bytes32 hash)
    internal
    pure
    returns (bytes32)
  {
    // 32 is the length in bytes of hash,
    // enforced by the type signature above
    return keccak256(
      abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
    );
  }
}


/**
 * @title SafeMath
 * @dev Math operations with safety checks that revert on error
 */
library SafeMath {
  /**
  * @dev Multiplies two numbers, reverts on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (a == 0) {
      return 0;
    }

    uint256 c = a * b;
    require(c / a == b);

    return c;
  }

  /**
  * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b > 0); // Solidity only automatically asserts when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold

    return c;
  }

  /**
  * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b <= a);
    uint256 c = a - b;

    return c;
  }

  /**
  * @dev Adds two numbers, reverts on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c >= a);

    return c;
  }

  /**
  * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
  * reverts when dividing by zero.
  */
  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0);
    return a % b;
  }
}


/**
 * @title Roles
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
  struct Role {
    mapping (address => bool) bearer;
  }

  /**
   * @dev give an account access to this role
   */
  function add(Role storage role, address account) internal {
    require(account != address(0));
    require(!has(role, account));

    role.bearer[account] = true;
  }

  /**
   * @dev remove an account's access to this role
   */
  function remove(Role storage role, address account) internal {
    require(account != address(0));
    require(has(role, account));

    role.bearer[account] = false;
  }

  /**
   * @dev check if an account has this role
   * @return bool
   */
  function has(Role storage role, address account)
    internal
    view
    returns (bool)
  {
    require(account != address(0));
    return role.bearer[account];
  }
}


contract PauserRole {
  using Roles for Roles.Role;

  event PauserAdded(address indexed account);
  event PauserRemoved(address indexed account);

  Roles.Role private pausers;

  constructor() internal {
    _addPauser(msg.sender);
  }

  modifier onlyPauser() {
    require(isPauser(msg.sender));
    _;
  }

  function isPauser(address account) public view returns (bool) {
    return pausers.has(account);
  }

  function addPauser(address account) public onlyPauser {
    _addPauser(account);
  }

  function renouncePauser() public {
    _removePauser(msg.sender);
  }

  function _addPauser(address account) internal {
    pausers.add(account);
    emit PauserAdded(account);
  }

  function _removePauser(address account) internal {
    pausers.remove(account);
    emit PauserRemoved(account);
  }
}


/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is PauserRole {
  event Paused(address account);
  event Unpaused(address account);

  bool private _paused;

  constructor() internal {
    _paused = false;
  }

  /**
   * @return true if the contract is paused, false otherwise.
   */
  function paused() public view returns(bool) {
    return _paused;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is not paused.
   */
  modifier whenNotPaused() {
    require(!_paused);
    _;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is paused.
   */
  modifier whenPaused() {
    require(_paused);
    _;
  }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
  function pause() public onlyPauser whenNotPaused {
    _paused = true;
    emit Paused(msg.sender);
  }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
  function unpause() public onlyPauser whenPaused {
    _paused = false;
    emit Unpaused(msg.sender);
  }
}


/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address private _owner;

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

  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  constructor(address owner) internal {
    _owner = owner;
    emit OwnershipTransferred(address(0), _owner);
  }

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

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(isOwner());
    _;
  }

  /**
   * @return true if `msg.sender` is the owner of the contract.
   */
  function isOwner() public view returns(bool) {
    return msg.sender == _owner;
  }

  /**
   * @dev Allows the current owner to relinquish control of the contract.
   * @notice Renouncing to ownership will leave the contract without an owner.
   * It will not be possible to call the functions with the `onlyOwner`
   * modifier anymore.
   */
  function renounceOwnership() public onlyOwner {
    emit OwnershipTransferred(_owner, address(0));
    _owner = address(0);
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    _transferOwnership(newOwner);
  }

  /**
   * @dev Transfers control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function _transferOwnership(address newOwner) internal {
    require(newOwner != address(0));
    emit OwnershipTransferred(_owner, newOwner);
    _owner = newOwner;
  }
}


/**
 * @title Attribute Registry interface. EIP-165 ID: 0x5f46473f
 */
interface AttributeRegistryInterface {
  /**
   * @notice Check if an attribute of the type with ID `attributeTypeID` has
   * been assigned to the account at `account` and is currently valid.
   * @param account address The account to check for a valid attribute.
   * @param attributeTypeID uint256 The ID of the attribute type to check for.
   * @return True if the attribute is assigned and valid, false otherwise.
   * @dev This function MUST return either true or false - i.e. calling this
   * function MUST NOT cause the caller to revert.
   */
  function hasAttribute(
    address account,
    uint256 attributeTypeID
  ) external view returns (bool);

  /**
   * @notice Retrieve the value of the attribute of the type with ID
   * `attributeTypeID` on the account at `account`, assuming it is valid.
   * @param account address The account to check for the given attribute value.
   * @param attributeTypeID uint256 The ID of the attribute type to check for.
   * @return The attribute value if the attribute is valid, reverts otherwise.
   * @dev This function MUST revert if a directly preceding or subsequent
   * function call to `hasAttribute` with identical `account` and
   * `attributeTypeID` parameters would return false.
   */
  function getAttributeValue(
    address account,
    uint256 attributeTypeID
  ) external view returns (uint256);

  /**
   * @notice Count the number of attribute types defined by the registry.
   * @return The number of available attribute types.
   * @dev This function MUST return a positive integer value  - i.e. calling
   * this function MUST NOT cause the caller to revert.
   */
  function countAttributeTypes() external view returns (uint256);

  /**
   * @notice Get the ID of the attribute type at index `index`.
   * @param index uint256 The index of the attribute type in question.
   * @return The ID of the attribute type.
   * @dev This function MUST revert if the provided `index` value falls outside
   * of the range of the value returned from a directly preceding or subsequent
   * function call to `countAttributeTypes`. It MUST NOT revert if the provided
   * `index` value falls inside said range.
   */
  function getAttributeTypeID(uint256 index) external view returns (uint256);
}


/**
 * @title Basic TPL Jurisdiction Interface.
 */
interface BasicJurisdictionInterface {
  // declare events
  event AttributeTypeAdded(uint256 indexed attributeTypeID, string description);
  
  event AttributeTypeRemoved(uint256 indexed attributeTypeID);
  
  event ValidatorAdded(address indexed validator, string description);
  
  event ValidatorRemoved(address indexed validator);
  
  event ValidatorApprovalAdded(
    address validator,
    uint256 indexed attributeTypeID
  );

  event ValidatorApprovalRemoved(
    address validator,
    uint256 indexed attributeTypeID
  );

  event AttributeAdded(
    address validator,
    address indexed attributee,
    uint256 attributeTypeID,
    uint256 attributeValue
  );

  event AttributeRemoved(
    address validator,
    address indexed attributee,
    uint256 attributeTypeID
  );

  /**
  * @notice Add an attribute type with ID `ID` and description `description` to
  * the jurisdiction.
  * @param ID uint256 The ID of the attribute type to add.
  * @param description string A description of the attribute type.
  * @dev Once an attribute type is added with a given ID, the description of the
  * attribute type cannot be changed, even if the attribute type is removed and
  * added back later.
  */
  function addAttributeType(uint256 ID, string description) external;

  /**
  * @notice Remove the attribute type with ID `ID` from the jurisdiction.
  * @param ID uint256 The ID of the attribute type to remove.
  * @dev All issued attributes of the given type will become invalid upon
  * removal, but will become valid again if the attribute is reinstated.
  */
  function removeAttributeType(uint256 ID) external;

  /**
  * @notice Add account `validator` as a validator with a description
  * `description` who can be approved to set attributes of specific types.
  * @param validator address The account to assign as the validator.
  * @param description string A description of the validator.
  * @dev Note that the jurisdiction can add iteslf as a validator if desired.
  */
  function addValidator(address validator, string description) external;

  /**
  * @notice Remove the validator at address `validator` from the jurisdiction.
  * @param validator address The account of the validator to remove.
  * @dev Any attributes issued by the validator will become invalid upon their
  * removal. If the validator is reinstated, those attributes will become valid
  * again. Any approvals to issue attributes of a given type will need to be
  * set from scratch in the event a validator is reinstated.
  */
  function removeValidator(address validator) external;

  /**
  * @notice Approve the validator at address `validator` to issue attributes of
  * the type with ID `attributeTypeID`.
  * @param validator address The account of the validator to approve.
  * @param attributeTypeID uint256 The ID of the approved attribute type.
  */
  function addValidatorApproval(
    address validator,
    uint256 attributeTypeID
  ) external;

  /**
  * @notice Deny the validator at address `validator` the ability to continue to
  * issue attributes of the type with ID `attributeTypeID`.
  * @param validator address The account of the validator with removed approval.
  * @param attributeTypeID uint256 The ID of the attribute type to unapprove.
  * @dev Any attributes of the specified type issued by the validator in
  * question will become invalid once the approval is removed. If the approval
  * is reinstated, those attributes will become valid again. The approval will
  * also be removed if the approved validator is removed.
  */
  function removeValidatorApproval(
    address validator,
    uint256 attributeTypeID
  ) external;

  /**
  * @notice Issue an attribute of the type with ID `attributeTypeID` and a value
  * of `value` to `account` if `message.caller.address()` is approved validator.
  * @param account address The account to issue the attribute on.
  * @param attributeTypeID uint256 The ID of the attribute type to issue.
  * @param value uint256 An optional value for the issued attribute.
  * @dev Existing attributes of the given type on the address must be removed
  * in order to set a new attribute. Be aware that ownership of the account to
  * which the attribute is assigned may still be transferable - restricting
  * assignment to externally-owned accounts may partially alleviate this issue.
  */
  function issueAttribute(
    address account,
    uint256 attributeTypeID,
    uint256 value
  ) external payable;

  /**
  * @notice Revoke the attribute of the type with ID `attributeTypeID` from
  * `account` if `message.caller.address()` is the issuing validator.
  * @param account address The account to issue the attribute on.
  * @param attributeTypeID uint256 The ID of the attribute type to issue.
  * @dev Validators may still revoke issued attributes even after they have been
  * removed or had their approval to issue the attribute type removed - this
  * enables them to address any objectionable issuances before being reinstated.
  */
  function revokeAttribute(
    address account,
    uint256 attributeTypeID
  ) external;

  /**
   * @notice Determine if a validator at account `validator` is able to issue
   * attributes of the type with ID `attributeTypeID`.
   * @param validator address The account of the validator.
   * @param attributeTypeID uint256 The ID of the attribute type to check.
   * @return True if the validator can issue attributes of the given type, false
   * otherwise.
   */
  function canIssueAttributeType(
    address validator,
    uint256 attributeTypeID
  ) external view returns (bool);

  /**
   * @notice Get a description of the attribute type with ID `attributeTypeID`.
   * @param attributeTypeID uint256 The ID of the attribute type to check for.
   * @return A description of the attribute type.
   */
  function getAttributeTypeDescription(
    uint256 attributeTypeID
  ) external view returns (string description);
  
  /**
   * @notice Get a description of the validator at account `validator`.
   * @param validator address The account of the validator in question.
   * @return A description of the validator.
   */
  function getValidatorDescription(
    address validator
  ) external view returns (string description);

  /**
   * @notice Find the validator that issued the attribute of the type with ID
   * `attributeTypeID` on the account at `account` and determine if the
   * validator is still valid.
   * @param account address The account that contains the attribute be checked.
   * @param attributeTypeID uint256 The ID of the attribute type in question.
   * @return The validator and the current status of the validator as it
   * pertains to the attribute type in question.
   * @dev if no attribute of the given attribute type exists on the account, the
   * function will return (address(0), false).
   */
  function getAttributeValidator(
    address account,
    uint256 attributeTypeID
  ) external view returns (address validator, bool isStillValid);

  /**
   * @notice Count the number of attribute types defined by the jurisdiction.
   * @return The number of available attribute types.
   */
  function countAttributeTypes() external view returns (uint256);

  /**
   * @notice Get the ID of the attribute type at index `index`.
   * @param index uint256 The index of the attribute type in question.
   * @return The ID of the attribute type.
   */
  function getAttributeTypeID(uint256 index) external view returns (uint256);

  /**
   * @notice Get the IDs of all available attribute types on the jurisdiction.
   * @return A dynamic array containing all available attribute type IDs.
   */
  function getAttributeTypeIDs() external view returns (uint256[]);

  /**
   * @notice Count the number of validators defined by the jurisdiction.
   * @return The number of defined validators.
   */
  function countValidators() external view returns (uint256);

  /**
   * @notice Get the account of the validator at index `index`.
   * @param index uint256 The index of the validator in question.
   * @return The account of the validator.
   */
  function getValidator(uint256 index) external view returns (address);

  /**
   * @notice Get the accounts of all available validators on the jurisdiction.
   * @return A dynamic array containing all available validator accounts.
   */
  function getValidators() external view returns (address[]);
}

/**
 * @title Extended TPL Jurisdiction Interface.
 * @dev this extends BasicJurisdictionInterface for additional functionality.
 */
interface ExtendedJurisdictionInterface {
  // declare events (NOTE: consider which fields should be indexed)
  event ValidatorSigningKeyModified(
    address indexed validator,
    address newSigningKey
  );

  event StakeAllocated(
    address indexed staker,
    uint256 indexed attribute,
    uint256 amount
  );

  event StakeRefunded(
    address indexed staker,
    uint256 indexed attribute,
    uint256 amount
  );

  event FeePaid(
    address indexed recipient,
    address indexed payee,
    uint256 indexed attribute,
    uint256 amount
  );
  
  event TransactionRebatePaid(
    address indexed submitter,
    address indexed payee,
    uint256 indexed attribute,
    uint256 amount
  );

  /**
  * @notice Add a restricted attribute type with ID `ID` and description
  * `description` to the jurisdiction. Restricted attribute types can only be
  * removed by the issuing validator or the jurisdiction.
  * @param ID uint256 The ID of the restricted attribute type to add.
  * @param description string A description of the restricted attribute type.
  * @dev Once an attribute type is added with a given ID, the description or the
  * restricted status of the attribute type cannot be changed, even if the
  * attribute type is removed and added back later.
  */
  function addRestrictedAttributeType(uint256 ID, string description) external;

  /**
  * @notice Enable or disable a restriction for a given attribute type ID `ID`
  * that prevents attributes of the given type from being set by operators based
  * on the provided value for `onlyPersonal`.
  * @param ID uint256 The attribute type ID in question.
  * @param onlyPersonal bool Whether the address may only be set personally.
  */
  function setAttributeTypeOnlyPersonal(uint256 ID, bool onlyPersonal) external;

  /**
  * @notice Set a secondary source for a given attribute type ID `ID`, with an
  * address `registry` of the secondary source in question and a given
  * `sourceAttributeTypeID` for attribute type ID to check on the secondary
  * source. The secondary source will only be checked for the given attribute in
  * cases where no attribute of the given attribute type ID is assigned locally.
  * @param ID uint256 The attribute type ID to set the secondary source for.
  * @param attributeRegistry address The secondary attribute registry account.
  * @param sourceAttributeTypeID uint256 The attribute type ID on the secondary
  * source to check.
  * @dev To remove a secondary source on an attribute type, the registry address
  * should be set to the null address.
  */
  function setAttributeTypeSecondarySource(
    uint256 ID,
    address attributeRegistry,
    uint256 sourceAttributeTypeID
  ) external;

  /**
  * @notice Set a minimum required stake for a given attribute type ID `ID` and
  * an amount of `stake`, to be locked in the jurisdiction upon assignment of
  * attributes of the given type. The stake will be applied toward a transaction
  * rebate in the event the attribute is revoked, with the remainder returned to
  * the staker.
  * @param ID uint256 The attribute type ID to set a minimum required stake for.
  * @param minimumRequiredStake uint256 The minimum required funds to lock up.
  * @dev To remove a stake requirement from an attribute type, the stake amount
  * should be set to 0.
  */
  function setAttributeTypeMinimumRequiredStake(
    uint256 ID,
    uint256 minimumRequiredStake
  ) external;

  /**
  * @notice Set a required fee for a given attribute type ID `ID` and an amount
  * of `fee`, to be paid to the owner of the jurisdiction upon assignment of
  * attributes of the given type.
  * @param ID uint256 The attribute type ID to set the required fee for.
  * @param fee uint256 The required fee amount to be paid upon assignment.
  * @dev To remove a fee requirement from an attribute type, the fee amount
  * should be set to 0.
  */
  function setAttributeTypeJurisdictionFee(uint256 ID, uint256 fee) external;

  /**
  * @notice Set the public address associated with a validator signing key, used
  * to sign off-chain attribute approvals, as `newSigningKey`.
  * @param newSigningKey address The address associated with signing key to set.
  */
  function setValidatorSigningKey(address newSigningKey) external;

  /**
  * @notice Add an attribute of the type with ID `attributeTypeID`, an attribute
  * value of `value`, and an associated validator fee of `validatorFee` to
  * account of `msg.sender` by passing in a signed attribute approval with
  * signature `signature`.
  * @param attributeTypeID uint256 The ID of the attribute type to add.
  * @param value uint256 The value for the attribute to add.
  * @param validatorFee uint256 The fee to be paid to the issuing validator.
  * @param signature bytes The signature from the validator attribute approval.
  */
  function addAttribute(
    uint256 attributeTypeID,
    uint256 value,
    uint256 validatorFee,
    bytes signature
  ) external payable;

  /**
  * @notice Remove an attribute of the type with ID `attributeTypeID` from
  * account of `msg.sender`.
  * @param attributeTypeID uint256 The ID of the attribute type to remove.
  */
  function removeAttribute(uint256 attributeTypeID) external;

  /**
  * @notice Add an attribute of the type with ID `attributeTypeID`, an attribute
  * value of `value`, and an associated validator fee of `validatorFee` to
  * account `account` by passing in a signed attribute approval with signature
  * `signature`.
  * @param account address The account to add the attribute to.
  * @param attributeTypeID uint256 The ID of the attribute type to add.
  * @param value uint256 The value for the attribute to add.
  * @param validatorFee uint256 The fee to be paid to the issuing validator.
  * @param signature bytes The signature from the validator attribute approval.
  * @dev Restricted attribute types can only be removed by issuing validators or
  * the jurisdiction itself.
  */
  function addAttributeFor(
    address account,
    uint256 attributeTypeID,
    uint256 value,
    uint256 validatorFee,
    bytes signature
  ) external payable;

  /**
  * @notice Remove an attribute of the type with ID `attributeTypeID` from
  * account of `account`.
  * @param account address The account to remove the attribute from.
  * @param attributeTypeID uint256 The ID of the attribute type to remove.
  * @dev Restricted attribute types can only be removed by issuing validators or
  * the jurisdiction itself.
  */
  function removeAttributeFor(address account, uint256 attributeTypeID) external;

  /**
   * @notice Invalidate a signed attribute approval before it has been set by
   * supplying the hash of the approval `hash` and the signature `signature`.
   * @param hash bytes32 The hash of the attribute approval.
   * @param signature bytes The hash's signature, resolving to the signing key.
   * @dev Attribute approvals can only be removed by issuing validators or the
   * jurisdiction itself.
   */
  function invalidateAttributeApproval(
    bytes32 hash,
    bytes signature
  ) external;

  /**
   * @notice Get the hash of a given attribute approval.
   * @param account address The account specified by the attribute approval.
   * @param operator address An optional account permitted to submit approval.
   * @param attributeTypeID uint256 The ID of the attribute type in question.
   * @param value uint256 The value of the attribute in the approval.
   * @param fundsRequired uint256 The amount to be included with the approval.
   * @param validatorFee uint256 The required fee to be paid to the validator.
   * @return The hash of the attribute approval.
   */
  function getAttributeApprovalHash(
    address account,
    address operator,
    uint256 attributeTypeID,
    uint256 value,
    uint256 fundsRequired,
    uint256 validatorFee
  ) external view returns (bytes32 hash);

  /**
   * @notice Check if a given signed attribute approval is currently valid when
   * submitted directly by `msg.sender`.
   * @param attributeTypeID uint256 The ID of the attribute type in question.
   * @param value uint256 The value of the attribute in the approval.
   * @param fundsRequired uint256 The amount to be included with the approval.
   * @param validatorFee uint256 The required fee to be paid to the validator.
   * @param signature bytes The attribute approval signature, based on a hash of
   * the other parameters and the submitting account.
   * @return True if the approval is currently valid, false otherwise.
   */
  function canAddAttribute(
    uint256 attributeTypeID,
    uint256 value,
    uint256 fundsRequired,
    uint256 validatorFee,
    bytes signature
  ) external view returns (bool);

  /**
   * @notice Check if a given signed attribute approval is currently valid for a
   * given account when submitted by the operator at `msg.sender`.
   * @param account address The account specified by the attribute approval.
   * @param attributeTypeID uint256 The ID of the attribute type in question.
   * @param value uint256 The value of the attribute in the approval.
   * @param fundsRequired uint256 The amount to be included with the approval.
   * @param validatorFee uint256 The required fee to be paid to the validator.
   * @param signature bytes The attribute approval signature, based on a hash of
   * the other parameters and the submitting account.
   * @return True if the approval is currently valid, false otherwise.
   */
  function canAddAttributeFor(
    address account,
    uint256 attributeTypeID,
    uint256 value,
    uint256 fundsRequired,
    uint256 validatorFee,
    bytes signature
  ) external view returns (bool);

  /**
   * @notice Get comprehensive information on an attribute type with ID
   * `attributeTypeID`.
   * @param attributeTypeID uint256 The attribute type ID in question.
   * @return Information on the attribute type in question.
   */
  function getAttributeTypeInformation(
    uint256 attributeTypeID
  ) external view returns (
    string description,
    bool isRestricted,
    bool isOnlyPersonal,
    address secondarySource,
    uint256 secondaryId,
    uint256 minimumRequiredStake,
    uint256 jurisdictionFee
  );
  
  /**
   * @notice Get a validator's signing key.
   * @param validator address The account of the validator.
   * @return The account referencing the public component of the signing key.
   */
  function getValidatorSigningKey(
    address validator
  ) external view returns (
    address signingKey
  );
}

/**
 * @title Interface for checking attribute assignment on YES token and for token
 * recovery.
 */
interface IERC20 {
  function balanceOf(address) external view returns (uint256);
  function transfer(address, uint256) external returns (bool);
}

/**
 * @title An extended TPL jurisdiction for assigning attributes to addresses.
 */
contract ExtendedJurisdiction is Ownable, Pausable, AttributeRegistryInterface, BasicJurisdictionInterface, ExtendedJurisdictionInterface {
  using ECDSA for bytes32;
  using SafeMath for uint256;

  // validators are entities who can add or authorize addition of new attributes
  struct Validator {
    bool exists;
    uint256 index; // NOTE: consider use of uint88 to pack struct
    address signingKey;
    string description;
  }

  // attributes are properties that validators associate with specific addresses
  struct IssuedAttribute {
    bool exists;
    bool setPersonally;
    address operator;
    address validator;
    uint256 value;
    uint256 stake;
  }

  // attributes also have associated type - metadata common to each attribute
  struct AttributeType {
    bool exists;
    bool restricted;
    bool onlyPersonal;
    uint256 index; // NOTE: consider use of uint72 to pack struct
    address secondarySource;
    uint256 secondaryAttributeTypeID;
    uint256 minimumStake;
    uint256 jurisdictionFee;
    string description;
    mapping(address => bool) approvedValidators;
  }

  // top-level information about attribute types is held in a mapping of structs
  mapping(uint256 => AttributeType) private _attributeTypes;

  // the jurisdiction retains a mapping of addresses with assigned attributes
  mapping(address => mapping(uint256 => IssuedAttribute)) private _issuedAttributes;

  // there is also a mapping to identify all approved validators and their keys
  mapping(address => Validator) private _validators;

  // each registered signing key maps back to a specific validator
  mapping(address => address) private _signingKeys;

  // once attribute types are assigned to an ID, they cannot be modified
  mapping(uint256 => bytes32) private _attributeTypeHashes;

  // submitted attribute approvals are retained to prevent reuse after removal 
  mapping(bytes32 => bool) private _invalidAttributeApprovalHashes;

  // attribute approvals by validator are held in a mapping
  mapping(address => uint256[]) private _validatorApprovals;

   // attribute approval index by validator is tracked as well
  mapping(address => mapping(uint256 => uint256)) private _validatorApprovalsIndex;

  // IDs for all supplied attributes are held in an array (enables enumeration)
  uint256[] private _attributeIDs;

  // addresses for all designated validators are also held in an array
  address[] private _validatorAccounts;

  // track any recoverable funds locked in the contract 
  uint256 private _recoverableFunds;

  /**
  * @notice Set the original owner of the jurisdiction using a supplied
  * constructor argument.
  */
  constructor(address owner) public Ownable(owner) {}

  /**
  * @notice Add an attribute type with ID `ID` and description `description` to
  * the jurisdiction.
  * @param ID uint256 The ID of the attribute type to add.
  * @param description string A description of the attribute type.
  * @dev Once an attribute type is added with a given ID, the description of the
  * attribute type cannot be changed, even if the attribute type is removed and
  * added back later.
  */
  function addAttributeType(
    uint256 ID,
    string description
  ) external onlyOwner whenNotPaused {
    // prevent existing attributes with the same id from being overwritten
    require(
      !isAttributeType(ID),
      "an attribute type with the provided ID already exists"
    );

    // calculate a hash of the attribute type based on the type's properties
    bytes32 hash = keccak256(
      abi.encodePacked(
        ID, false, description
      )
    );

    // store hash if attribute type is the first one registered with provided ID
    if (_attributeTypeHashes[ID] == bytes32(0)) {
      _attributeTypeHashes[ID] = hash;
    }

    // prevent addition if different attribute type with the same ID has existed
    require(
      hash == _attributeTypeHashes[ID],
      "attribute type properties must match initial properties assigned to ID"
    );

    // set the attribute mapping, assigning the index as the end of attributeID
    _attributeTypes[ID] = AttributeType({
      exists: true,
      restricted: false, // when true: users can't remove attribute
      onlyPersonal: false, // when true: operators can't add attribute
      index: _attributeIDs.length,
      secondarySource: address(0), // the address of a remote registry
      secondaryAttributeTypeID: uint256(0), // the attribute type id to query
      minimumStake: uint256(0), // when > 0: users must stake ether to set
      jurisdictionFee: uint256(0),
      description: description
      // NOTE: no approvedValidators variable declaration - must be added later
    });
    
    // add the attribute type id to the end of the attributeID array
    _attributeIDs.push(ID);

    // log the addition of the attribute type
    emit AttributeTypeAdded(ID, description);
  }

  /**
  * @notice Add a restricted attribute type with ID `ID` and description
  * `description` to the jurisdiction. Restricted attribute types can only be
  * removed by the issuing validator or the jurisdiction.
  * @param ID uint256 The ID of the restricted attribute type to add.
  * @param description string A description of the restricted attribute type.
  * @dev Once an attribute type is added with a given ID, the description or the
  * restricted status of the attribute type cannot be changed, even if the
  * attribute type is removed and added back later.
  */
  function addRestrictedAttributeType(
    uint256 ID,
    string description
  ) external onlyOwner whenNotPaused {
    // prevent existing attributes with the same id from being overwritten
    require(
      !isAttributeType(ID),
      "an attribute type with the provided ID already exists"
    );

    // calculate a hash of the attribute type based on the type's properties
    bytes32 hash = keccak256(
      abi.encodePacked(
        ID, true, description
      )
    );

    // store hash if attribute type is the first one registered with provided ID
    if (_attributeTypeHashes[ID] == bytes32(0)) {
      _attributeTypeHashes[ID] = hash;
    }

    // prevent addition if different attribute type with the same ID has existed
    require(
      hash == _attributeTypeHashes[ID],
      "attribute type properties must match initial properties assigned to ID"
    );

    // set the attribute mapping, assigning the index as the end of attributeID
    _attributeTypes[ID] = AttributeType({
      exists: true,
      restricted: true, // when true: users can't remove attribute
      onlyPersonal: false, // when true: operators can't add attribute
      index: _attributeIDs.length,
      secondarySource: address(0), // the address of a remote registry
      secondaryAttributeTypeID: uint256(0), // the attribute type id to query
      minimumStake: uint256(0), // when > 0: users must stake ether to set
      jurisdictionFee: uint256(0),
      description: description
      // NOTE: no approvedValidators variable declaration - must be added later
    });
    
    // add the attribute type id to the end of the attributeID array
    _attributeIDs.push(ID);

    // log the addition of the attribute type
    emit AttributeTypeAdded(ID, description);
  }

  /**
  * @notice Enable or disable a restriction for a given attribute type ID `ID`
  * that prevents attributes of the given type from being set by operators based
  * on the provided value for `onlyPersonal`.
  * @param ID uint256 The attribute type ID in question.
  * @param onlyPersonal bool Whether the address may only be set personally.
  */
  function setAttributeTypeOnlyPersonal(uint256 ID, bool onlyPersonal) external {
    // if the attribute type ID does not exist, there is nothing to remove
    require(
      isAttributeType(ID),
      "unable to set to only personal, no attribute type with the provided ID"
    );

    // modify the attribute type in the mapping
    _attributeTypes[ID].onlyPersonal = onlyPersonal;
  }

  /**
  * @notice Set a secondary source for a given attribute type ID `ID`, with an
  * address `registry` of the secondary source in question and a given
  * `sourceAttributeTypeID` for attribute type ID to check on the secondary
  * source. The secondary source will only be checked for the given attribute in
  * cases where no attribute of the given attribute type ID is assigned locally.
  * @param ID uint256 The attribute type ID to set the secondary source for.
  * @param attributeRegistry address The secondary attribute registry account.
  * @param sourceAttributeTypeID uint256 The attribute type ID on the secondary
  * source to check.
  * @dev To remove a secondary source on an attribute type, the registry address
  * should be set to the null address.
  */
  function setAttributeTypeSecondarySource(
    uint256 ID,
    address attributeRegistry,
    uint256 sourceAttributeTypeID
  ) external {
    // if the attribute type ID does not exist, there is nothing to remove
    require(
      isAttributeType(ID),
      "unable to set secondary source, no attribute type with the provided ID"
    );

    // modify the attribute type in the mapping
    _attributeTypes[ID].secondarySource = attributeRegistry;
    _attributeTypes[ID].secondaryAttributeTypeID = sourceAttributeTypeID;
  }

  /**
  * @notice Set a minimum required stake for a given attribute type ID `ID` and
  * an amount of `stake`, to be locked in the jurisdiction upon assignment of
  * attributes of the given type. The stake will be applied toward a transaction
  * rebate in the event the attribute is revoked, with the remainder returned to
  * the staker.
  * @param ID uint256 The attribute type ID to set a minimum required stake for.
  * @param minimumRequiredStake uint256 The minimum required funds to lock up.
  * @dev To remove a stake requirement from an attribute type, the stake amount
  * should be set to 0.
  */
  function setAttributeTypeMinimumRequiredStake(
    uint256 ID,
    uint256 minimumRequiredStake
  ) external {
    // if the attribute type ID does not exist, there is nothing to remove
    require(
      isAttributeType(ID),
      "unable to set minimum stake, no attribute type with the provided ID"
    );

    // modify the attribute type in the mapping
    _attributeTypes[ID].minimumStake = minimumRequiredStake;
  }

  /**
  * @notice Set a required fee for a given attribute type ID `ID` and an amount
  * of `fee`, to be paid to the owner of the jurisdiction upon assignment of
  * attributes of the given type.
  * @param ID uint256 The attribute type ID to set the required fee for.
  * @param fee uint256 The required fee amount to be paid upon assignment.
  * @dev To remove a fee requirement from an attribute type, the fee amount
  * should be set to 0.
  */
  function setAttributeTypeJurisdictionFee(uint256 ID, uint256 fee) external {
    // if the attribute type ID does not exist, there is nothing to remove
    require(
      isAttributeType(ID),
      "unable to set fee, no attribute type with the provided ID"
    );

    // modify the attribute type in the mapping
    _attributeTypes[ID].jurisdictionFee = fee;
  }

  /**
  * @notice Remove the attribute type with ID `ID` from the jurisdiction.
  * @param ID uint256 The ID of the attribute type to remove.
  * @dev All issued attributes of the given type will become invalid upon
  * removal, but will become valid again if the attribute is reinstated.
  */
  function removeAttributeType(uint256 ID) external onlyOwner whenNotPaused {
    // if the attribute type ID does not exist, there is nothing to remove
    require(
      isAttributeType(ID),
      "unable to remove, no attribute type with the provided ID"
    );

    // get the attribute ID at the last index of the array
    uint256 lastAttributeID = _attributeIDs[_attributeIDs.length.sub(1)];

    // set the attributeID at attribute-to-delete.index to the last attribute ID
    _attributeIDs[_attributeTypes[ID].index] = lastAttributeID;

    // update the index of the attribute type that was moved
    _attributeTypes[lastAttributeID].index = _attributeTypes[ID].index;
    
    // remove the (now duplicate) attribute ID at the end by trimming the array
    _attributeIDs.length--;

    // delete the attribute type's record from the mapping
    delete _attributeTypes[ID];

    // log the removal of the attribute type
    emit AttributeTypeRemoved(ID);
  }

  /**
  * @notice Add account `validator` as a validator with a description
  * `description` who can be approved to set attributes of specific types.
  * @param validator address The account to assign as the validator.
  * @param description string A description of the validator.
  * @dev Note that the jurisdiction can add iteslf as a validator if desired.
  */
  function addValidator(
    address validator,
    string description
  ) external onlyOwner whenNotPaused {
    // check that an empty address was not provided by mistake
    require(validator != address(0), "must supply a valid address");

    // prevent existing validators from being overwritten
    require(
      !isValidator(validator),
      "a validator with the provided address already exists"
    );

    // prevent duplicate signing keys from being created
    require(
      _signingKeys[validator] == address(0),
      "a signing key matching the provided address already exists"
    );
    
    // create a record for the validator
    _validators[validator] = Validator({
      exists: true,
      index: _validatorAccounts.length,
      signingKey: validator, // NOTE: this will be initially set to same address
      description: description
    });

    // set the initial signing key (the validator's address) resolving to itself
    _signingKeys[validator] = validator;

    // add the validator to the end of the _validatorAccounts array
    _validatorAccounts.push(validator);
    
    // log the addition of the new validator
    emit ValidatorAdded(validator, description);
  }

  /**
  * @notice Remove the validator at address `validator` from the jurisdiction.
  * @param validator address The account of the validator to remove.
  * @dev Any attributes issued by the validator will become invalid upon their
  * removal. If the validator is reinstated, those attributes will become valid
  * again. Any approvals to issue attributes of a given type will need to be
  * set from scratch in the event a validator is reinstated.
  */
  function removeValidator(address validator) external onlyOwner whenNotPaused {
    // check that a validator exists at the provided address
    require(
      isValidator(validator),
      "unable to remove, no validator located at the provided address"
    );

    // first, start removing validator approvals until gas is exhausted
    while (_validatorApprovals[validator].length > 0 && gasleft() > 25000) {
      // locate the index of last attribute ID in the validator approval group
      uint256 lastIndex = _validatorApprovals[validator].length.sub(1);

      // locate the validator approval to be removed
      uint256 targetApproval = _validatorApprovals[validator][lastIndex];

      // remove the record of the approval from the associated attribute type
      delete _attributeTypes[targetApproval].approvedValidators[validator];

      // remove the record of the index of the approval
      delete _validatorApprovalsIndex[validator][targetApproval];

      // drop the last attribute ID from the validator approval group
      _validatorApprovals[validator].length--;
    }

    // require that all approvals were successfully removed
    require(
      _validatorApprovals[validator].length == 0,
      "Cannot remove validator - first remove any existing validator approvals"
    );

    // get the validator address at the last index of the array
    address lastAccount = _validatorAccounts[_validatorAccounts.length.sub(1)];

    // set the address at validator-to-delete.index to last validator address
    _validatorAccounts[_validators[validator].index] = lastAccount;

    // update the index of the attribute type that was moved
    _validators[lastAccount].index = _validators[validator].index;
    
    // remove (duplicate) validator address at the end by trimming the array
    _validatorAccounts.length--;

    // remove the validator's signing key from its mapping
    delete _signingKeys[_validators[validator].signingKey];

    // remove the validator record
    delete _validators[validator];

    // log the removal of the validator
    emit ValidatorRemoved(validator);
  }

  /**
  * @notice Approve the validator at address `validator` to issue attributes of
  * the type with ID `attributeTypeID`.
  * @param validator address The account of the validator to approve.
  * @param attributeTypeID uint256 The ID of the approved attribute type.
  */
  function addValidatorApproval(
    address validator,
    uint256 attributeTypeID
  ) external onlyOwner whenNotPaused {
    // check that the attribute is predefined and that the validator exists
    require(
      isValidator(validator) && isAttributeType(attributeTypeID),
      "must specify both a valid attribute and an available validator"
    );

    // check that the validator is not already approved
    require(
      !_attributeTypes[attributeTypeID].approvedValidators[validator],
      "validator is already approved on the provided attribute"
    );

    // set the validator approval status on the attribute
    _attributeTypes[attributeTypeID].approvedValidators[validator] = true;

    // add the record of the index of the validator approval to be added
    uint256 index = _validatorApprovals[validator].length;
    _validatorApprovalsIndex[validator][attributeTypeID] = index;

    // include the attribute type in the validator approval mapping
    _validatorApprovals[validator].push(attributeTypeID);

    // log the addition of the validator's attribute type approval
    emit ValidatorApprovalAdded(validator, attributeTypeID);
  }

  /**
  * @notice Deny the validator at address `validator` the ability to continue to
  * issue attributes of the type with ID `attributeTypeID`.
  * @param validator address The account of the validator with removed approval.
  * @param attributeTypeID uint256 The ID of the attribute type to unapprove.
  * @dev Any attributes of the specified type issued by the validator in
  * question will become invalid once the approval is removed. If the approval
  * is reinstated, those attributes will become valid again. The approval will
  * also be removed if the approved validator is removed.
  */
  function removeValidatorApproval(
    address validator,
    uint256 attributeTypeID
  ) external onlyOwner whenNotPaused {
    // check that the attribute is predefined and that the validator exists
    require(
      canValidate(validator, attributeTypeID),
      "unable to remove validator approval, attribute is already unapproved"
    );

    // remove the validator approval status from the attribute
    delete _attributeTypes[attributeTypeID].approvedValidators[validator];

    // locate the index of the last validator approval
    uint256 lastIndex = _validatorApprovals[validator].length.sub(1);

    // locate the last attribute ID in the validator approval group
    uint256 lastAttributeID = _validatorApprovals[validator][lastIndex];

    // locate the index of the validator approval to be removed
    uint256 index = _validatorApprovalsIndex[validator][attributeTypeID];

    // replace the validator approval with the last approval in the array
    _validatorApprovals[validator][index] = lastAttributeID;

    // drop the last attribute ID from the validator approval group
    _validatorApprovals[validator].length--;

    // update the record of the index of the swapped-in approval
    _validatorApprovalsIndex[validator][lastAttributeID] = index;

    // remove the record of the index of the removed approval
    delete _validatorApprovalsIndex[validator][attributeTypeID];
    
    // log the removal of the validator's attribute type approval
    emit ValidatorApprovalRemoved(validator, attributeTypeID);
  }

  /**
  * @notice Set the public address associated with a validator signing key, used
  * to sign off-chain attribute approvals, as `newSigningKey`.
  * @param newSigningKey address The address associated with signing key to set.
  * @dev Consider having the validator submit a signed proof demonstrating that
  * the provided signing key is indeed a signing key in their control - this
  * helps mitigate the fringe attack vector where a validator could set the
  * address of another validator candidate (especially in the case of a deployed
  * smart contract) as their "signing key" in order to block them from being
  * added to the jurisdiction (due to the required property of signing keys
  * being unique, coupled with the fact that new validators are set up with
  * their address as the default initial signing key).
  */
  function setValidatorSigningKey(address newSigningKey) external {
    require(
      isValidator(msg.sender),
      "only validators may modify validator signing keys");
 
    // prevent duplicate signing keys from being created
    require(
      _signingKeys[newSigningKey] == address(0),
      "a signing key matching the provided address already exists"
    );

    // remove validator address as the resolved value for the old key
    delete _signingKeys[_validators[msg.sender].signingKey];

    // set the signing key to the new value
    _validators[msg.sender].signingKey = newSigningKey;

    // add validator address as the resolved value for the new key
    _signingKeys[newSigningKey] = msg.sender;

    // log the modification of the signing key
    emit ValidatorSigningKeyModified(msg.sender, newSigningKey);
  }

  /**
  * @notice Issue an attribute of the type with ID `attributeTypeID` and a value
  * of `value` to `account` if `message.caller.address()` is approved validator.
  * @param account address The account to issue the attribute on.
  * @param attributeTypeID uint256 The ID of the attribute type to issue.
  * @param value uint256 An optional value for the issued attribute.
  * @dev Existing attributes of the given type on the address must be removed
  * in order to set a new attribute. Be aware that ownership of the account to
  * which the attribute is assigned may still be transferable - restricting
  * assignment to externally-owned accounts may partially alleviate this issue.
  */
  function issueAttribute(
    address account,
    uint256 attributeTypeID,
    uint256 value
  ) external payable whenNotPaused {
    require(
      canValidate(msg.sender, attributeTypeID),
      "only approved validators may assign attributes of this type"
    );

    require(
      !_issuedAttributes[account][attributeTypeID].exists,
      "duplicate attributes are not supported, remove existing attribute first"
    );

    // retrieve required minimum stake and jurisdiction fees on attribute type
    uint256 minimumStake = _attributeTypes[attributeTypeID].minimumStake;
    uint256 jurisdictionFee = _attributeTypes[attributeTypeID].jurisdictionFee;
    uint256 stake = msg.value.sub(jurisdictionFee);

    require(
      stake >= minimumStake,
      "attribute requires a greater value than is currently provided"
    );

    // store attribute value and amount of ether staked in correct scope
    _issuedAttributes[account][attributeTypeID] = IssuedAttribute({
      exists: true,
      setPersonally: false,
      operator: address(0),
      validator: msg.sender,
      value: value,
      stake: stake
    });

    // log the addition of the attribute
    emit AttributeAdded(msg.sender, account, attributeTypeID, value);

    // log allocation of staked funds to the attribute if applicable
    if (stake > 0) {
      emit StakeAllocated(msg.sender, attributeTypeID, stake);
    }

    // pay jurisdiction fee to the owner of the jurisdiction if applicable
    if (jurisdictionFee > 0) {
      // NOTE: send is chosen over transfer to prevent cases where a improperly
      // configured fallback function could block addition of an attribute
      if (owner().send(jurisdictionFee)) {
        emit FeePaid(owner(), msg.sender, attributeTypeID, jurisdictionFee);
      } else {
        _recoverableFunds = _recoverableFunds.add(jurisdictionFee);
      }
    }
  }

  /**
  * @notice Revoke the attribute of the type with ID `attributeTypeID` from
  * `account` if `message.caller.address()` is the issuing validator.
  * @param account address The account to issue the attribute on.
  * @param attributeTypeID uint256 The ID of the attribute type to issue.
  * @dev Validators may still revoke issued attributes even after they have been
  * removed or had their approval to issue the attribute type removed - this
  * enables them to address any objectionable issuances before being reinstated.
  */
  function revokeAttribute(
    address account,
    uint256 attributeTypeID
  ) external whenNotPaused {
    // ensure that an attribute with the given account and attribute exists
    require(
      _issuedAttributes[account][attributeTypeID].exists,
      "only existing attributes may be removed"
    );

    // determine the assigned validator on the user attribute
    address validator = _issuedAttributes[account][attributeTypeID].validator;
    
    // caller must be either the jurisdiction owner or the assigning validator
    require(
      msg.sender == validator || msg.sender == owner(),
      "only jurisdiction or issuing validators may revoke arbitrary attributes"
    );

    // determine if attribute has any stake in order to refund transaction fee
    uint256 stake = _issuedAttributes[account][attributeTypeID].stake;

    // determine the correct address to refund the staked amount to
    address refundAddress;
    if (_issuedAttributes[account][attributeTypeID].setPersonally) {
      refundAddress = account;
    } else {
      address operator = _issuedAttributes[account][attributeTypeID].operator;
      if (operator == address(0)) {
        refundAddress = validator;
      } else {
        refundAddress = operator;
      }
    }

    // remove the attribute from the designated user account
    delete _issuedAttributes[account][attributeTypeID];

    // log the removal of the attribute
    emit AttributeRemoved(validator, account, attributeTypeID);

    // pay out any refunds and return the excess stake to the user
    if (stake > 0 && address(this).balance >= stake) {
      // NOTE: send is chosen over transfer to prevent cases where a malicious
      // fallback function could forcibly block an attribute's removal. Another
      // option is to allow a user to pull the staked amount after the removal.
      // NOTE: refine transaction rebate gas calculation! Setting this value too
      // high gives validators the incentive to revoke valid attributes. Simply
      // checking against gasLeft() & adding the final gas usage won't give the
      // correct transaction cost, as freeing space refunds gas upon completion.
      uint256 transactionGas = 37700; // <--- WARNING: THIS IS APPROXIMATE
      uint256 transactionCost = transactionGas.mul(tx.gasprice);

      // if stake exceeds allocated transaction cost, refund user the difference
      if (stake > transactionCost) {
        // refund the excess stake to the address that contributed the funds
        if (refundAddress.send(stake.sub(transactionCost))) {
          emit StakeRefunded(
            refundAddress,
            attributeTypeID,
            stake.sub(transactionCost)
          );
        } else {
          _recoverableFunds = _recoverableFunds.add(stake.sub(transactionCost));
        }

        // emit an event for the payment of the transaction rebate
        emit TransactionRebatePaid(
          tx.origin,
          refundAddress,
          attributeTypeID,
          transactionCost
        );

        // refund the cost of the transaction to the trasaction submitter
        tx.origin.transfer(transactionCost);

      // otherwise, allocate entire stake to partially refunding the transaction
      } else {
        // emit an event for the payment of the partial transaction rebate
        emit TransactionRebatePaid(
          tx.origin,
          refundAddress,
          attributeTypeID,
          stake
        );

        // refund the partial cost of the transaction to trasaction submitter
        tx.origin.transfer(stake);
      }
    }
  }

  /**
  * @notice Add an attribute of the type with ID `attributeTypeID`, an attribute
  * value of `value`, and an associated validator fee of `validatorFee` to
  * account of `msg.sender` by passing in a signed attribute approval with
  * signature `signature`.
  * @param attributeTypeID uint256 The ID of the attribute type to add.
  * @param value uint256 The value for the attribute to add.
  * @param validatorFee uint256 The fee to be paid to the issuing validator.
  * @param signature bytes The signature from the validator attribute approval.
  */
  function addAttribute(
    uint256 attributeTypeID,
    uint256 value,
    uint256 validatorFee,
    bytes signature
  ) external payable {
    // NOTE: determine best course of action when the attribute already exists
    // NOTE: consider utilizing bytes32 type for attributes and values
    // NOTE: does not currently support an extraData parameter, consider adding
    // NOTE: if msg.sender is a proxy contract, its ownership may be transferred
    // at will, circumventing any token transfer restrictions. Restricting usage
    // to only externally owned accounts may partially alleviate this concern.
    // NOTE: cosider including a salt (or better, nonce) parameter so that when
    // a user adds an attribute, then it gets revoked, the user can get a new
    // signature from the validator and renew the attribute using that. The main
    // downside is that everyone will have to keep track of the extra parameter.
    // Another solution is to just modifiy the required stake or fee amount.

    require(
      !_issuedAttributes[msg.sender][attributeTypeID].exists,
      "duplicate attributes are not supported, remove existing attribute first"
    );

    // retrieve required minimum stake and jurisdiction fees on attribute type
    uint256 minimumStake = _attributeTypes[attributeTypeID].minimumStake;
    uint256 jurisdictionFee = _attributeTypes[attributeTypeID].jurisdictionFee;
    uint256 stake = msg.value.sub(validatorFee).sub(jurisdictionFee);

    require(
      stake >= minimumStake,
      "attribute requires a greater value than is currently provided"
    );

    // signed data hash constructed according to EIP-191-0x45 to prevent replays
    bytes32 hash = keccak256(
      abi.encodePacked(
        address(this),
        msg.sender,
        address(0),
        msg.value,
        validatorFee,
        attributeTypeID,
        value
      )
    );

    require(
      !_invalidAttributeApprovalHashes[hash],
      "signed attribute approvals from validators may not be reused"
    );

    // extract the key used to sign the message hash
    address signingKey = hash.toEthSignedMessageHash().recover(signature);

    // retrieve the validator who controls the extracted key
    address validator = _signingKeys[signingKey];

    require(
      canValidate(validator, attributeTypeID),
      "signature does not match an approved validator for given attribute type"
    );

    // store attribute value and amount of ether staked in correct scope
    _issuedAttributes[msg.sender][attributeTypeID] = IssuedAttribute({
      exists: true,
      setPersonally: true,
      operator: address(0),
      validator: validator,
      value: value,
      stake: stake
      // NOTE: no extraData included
    });

    // flag the signed approval as invalid once it's been used to set attribute
    _invalidAttributeApprovalHashes[hash] = true;

    // log the addition of the attribute
    emit AttributeAdded(validator, msg.sender, attributeTypeID, value);

    // log allocation of staked funds to the attribute if applicable
    if (stake > 0) {
      emit StakeAllocated(msg.sender, attributeTypeID, stake);
    }

    // pay jurisdiction fee to the owner of the jurisdiction if applicable
    if (jurisdictionFee > 0) {
      // NOTE: send is chosen over transfer to prevent cases where a improperly
      // configured fallback function could block addition of an attribute
      if (owner().send(jurisdictionFee)) {
        emit FeePaid(owner(), msg.sender, attributeTypeID, jurisdictionFee);
      } else {
        _recoverableFunds = _recoverableFunds.add(jurisdictionFee);
      }
    }

    // pay validator fee to the issuing validator's address if applicable
    if (validatorFee > 0) {
      // NOTE: send is chosen over transfer to prevent cases where a improperly
      // configured fallback function could block addition of an attribute
      if (validator.send(validatorFee)) {
        emit FeePaid(validator, msg.sender, attributeTypeID, validatorFee);
      } else {
        _recoverableFunds = _recoverableFunds.add(validatorFee);
      }
    }
  }

  /**
  * @notice Remove an attribute of the type with ID `attributeTypeID` from
  * account of `msg.sender`.
  * @param attributeTypeID uint256 The ID of the attribute type to remove.
  */
  function removeAttribute(uint256 attributeTypeID) external {
    // attributes may only be removed by the user if they are not restricted
    require(
      !_attributeTypes[attributeTypeID].restricted,
      "only jurisdiction or issuing validator may remove a restricted attribute"
    );

    require(
      _issuedAttributes[msg.sender][attributeTypeID].exists,
      "only existing attributes may be removed"
    );

    // determine the assigned validator on the user attribute
    address validator = _issuedAttributes[msg.sender][attributeTypeID].validator;

    // determine if the attribute has a staked value
    uint256 stake = _issuedAttributes[msg.sender][attributeTypeID].stake;

    // determine the correct address to refund the staked amount to
    address refundAddress;
    if (_issuedAttributes[msg.sender][attributeTypeID].setPersonally) {
      refundAddress = msg.sender;
    } else {
      address operator = _issuedAttributes[msg.sender][attributeTypeID].operator;
      if (operator == address(0)) {
        refundAddress = validator;
      } else {
        refundAddress = operator;
      }
    }    

    // remove the attribute from the user address
    delete _issuedAttributes[msg.sender][attributeTypeID];

    // log the removal of the attribute
    emit AttributeRemoved(validator, msg.sender, attributeTypeID);

    // if the attribute has any staked balance, refund it to the user
    if (stake > 0 && address(this).balance >= stake) {
      // NOTE: send is chosen over transfer to prevent cases where a malicious
      // fallback function could forcibly block an attribute's removal
      if (refundAddress.send(stake)) {
        emit StakeRefunded(refundAddress, attributeTypeID, stake);
      } else {
        _recoverableFunds = _recoverableFunds.add(stake);
      }
    }
  }

  /**
  * @notice Add an attribute of the type with ID `attributeTypeID`, an attribute
  * value of `value`, and an associated validator fee of `validatorFee` to
  * account `account` by passing in a signed attribute approval with signature
  * `signature`.
  * @param account address The account to add the attribute to.
  * @param attributeTypeID uint256 The ID of the attribute type to add.
  * @param value uint256 The value for the attribute to add.
  * @param validatorFee uint256 The fee to be paid to the issuing validator.
  * @param signature bytes The signature from the validator attribute approval.
  * @dev Restricted attribute types can only be removed by issuing validators or
  * the jurisdiction itself.
  */
  function addAttributeFor(
    address account,
    uint256 attributeTypeID,
    uint256 value,
    uint256 validatorFee,
    bytes signature
  ) external payable {
    // NOTE: determine best course of action when the attribute already exists
    // NOTE: consider utilizing bytes32 type for attributes and values
    // NOTE: does not currently support an extraData parameter, consider adding
    // NOTE: if msg.sender is a proxy contract, its ownership may be transferred
    // at will, circumventing any token transfer restrictions. Restricting usage
    // to only externally owned accounts may partially alleviate this concern.
    // NOTE: consider including a salt (or better, nonce) parameter so that when
    // a user adds an attribute, then it gets revoked, the user can get a new
    // signature from the validator and renew the attribute using that. The main
    // downside is that everyone will have to keep track of the extra parameter.
    // Another solution is to just modifiy the required stake or fee amount.

    // attributes may only be added by a third party if onlyPersonal is false
    require(
      !_attributeTypes[attributeTypeID].onlyPersonal,
      "only operatable attributes may be added on behalf of another address"
    );

    require(
      !_issuedAttributes[account][attributeTypeID].exists,
      "duplicate attributes are not supported, remove existing attribute first"
    );

    // retrieve required minimum stake and jurisdiction fees on attribute type
    uint256 minimumStake = _attributeTypes[attributeTypeID].minimumStake;
    uint256 jurisdictionFee = _attributeTypes[attributeTypeID].jurisdictionFee;
    uint256 stake = msg.value.sub(validatorFee).sub(jurisdictionFee);

    require(
      stake >= minimumStake,
      "attribute requires a greater value than is currently provided"
    );

    // signed data hash constructed according to EIP-191-0x45 to prevent replays
    bytes32 hash = keccak256(
      abi.encodePacked(
        address(this),
        account,
        msg.sender,
        msg.value,
        validatorFee,
        attributeTypeID,
        value
      )
    );

    require(
      !_invalidAttributeApprovalHashes[hash],
      "signed attribute approvals from validators may not be reused"
    );

    // extract the key used to sign the message hash
    address signingKey = hash.toEthSignedMessageHash().recover(signature);

    // retrieve the validator who controls the extracted key
    address validator = _signingKeys[signingKey];

    require(
      canValidate(validator, attributeTypeID),
      "signature does not match an approved validator for provided attribute"
    );

    // store attribute value and amount of ether staked in correct scope
    _issuedAttributes[account][attributeTypeID] = IssuedAttribute({
      exists: true,
      setPersonally: false,
      operator: msg.sender,
      validator: validator,
      value: value,
      stake: stake
      // NOTE: no extraData included
    });

    // flag the signed approval as invalid once it's been used to set attribute
    _invalidAttributeApprovalHashes[hash] = true;

    // log the addition of the attribute
    emit AttributeAdded(validator, account, attributeTypeID, value);

    // log allocation of staked funds to the attribute if applicable
    // NOTE: the staker is the entity that pays the fee here!
    if (stake > 0) {
      emit StakeAllocated(msg.sender, attributeTypeID, stake);
    }

    // pay jurisdiction fee to the owner of the jurisdiction if applicable
    if (jurisdictionFee > 0) {
      // NOTE: send is chosen over transfer to prevent cases where a improperly
      // configured fallback function could block addition of an attribute
      if (owner().send(jurisdictionFee)) {
        emit FeePaid(owner(), msg.sender, attributeTypeID, jurisdictionFee);
      } else {
        _recoverableFunds = _recoverableFunds.add(jurisdictionFee);
      }
    }

    // pay validator fee to the issuing validator's address if applicable
    if (validatorFee > 0) {
      // NOTE: send is chosen over transfer to prevent cases where a improperly
      // configured fallback function could block addition of an attribute
      if (validator.send(validatorFee)) {
        emit FeePaid(validator, msg.sender, attributeTypeID, validatorFee);
      } else {
        _recoverableFunds = _recoverableFunds.add(validatorFee);
      }
    }
  }

  /**
  * @notice Remove an attribute of the type with ID `attributeTypeID` from
  * account of `account`.
  * @param account address The account to remove the attribute from.
  * @param attributeTypeID uint256 The ID of the attribute type to remove.
  * @dev Restricted attribute types can only be removed by issuing validators or
  * the jurisdiction itself.
  */
  function removeAttributeFor(address account, uint256 attributeTypeID) external {
    // attributes may only be removed by the user if they are not restricted
    require(
      !_attributeTypes[attributeTypeID].restricted,
      "only jurisdiction or issuing validator may remove a restricted attribute"
    );

    require(
      _issuedAttributes[account][attributeTypeID].exists,
      "only existing attributes may be removed"
    );

    require(
      _issuedAttributes[account][attributeTypeID].operator == msg.sender,
      "only an assigning operator may remove attribute on behalf of an address"
    );

    // determine the assigned validator on the user attribute
    address validator = _issuedAttributes[account][attributeTypeID].validator;

    // determine if the attribute has a staked value
    uint256 stake = _issuedAttributes[account][attributeTypeID].stake;

    // remove the attribute from the user address
    delete _issuedAttributes[account][attributeTypeID];

    // log the removal of the attribute
    emit AttributeRemoved(validator, account, attributeTypeID);

    // if the attribute has any staked balance, refund it to the user
    if (stake > 0 && address(this).balance >= stake) {
      // NOTE: send is chosen over transfer to prevent cases where a malicious
      // fallback function could forcibly block an attribute's removal
      if (msg.sender.send(stake)) {
        emit StakeRefunded(msg.sender, attributeTypeID, stake);
      } else {
        _recoverableFunds = _recoverableFunds.add(stake);
      }
    }
  }

  /**
   * @notice Invalidate a signed attribute approval before it has been set by
   * supplying the hash of the approval `hash` and the signature `signature`.
   * @param hash bytes32 The hash of the attribute approval.
   * @param signature bytes The hash's signature, resolving to the signing key.
   * @dev Attribute approvals can only be removed by issuing validators or the
   * jurisdiction itself.
   */
  function invalidateAttributeApproval(
    bytes32 hash,
    bytes signature
  ) external {
    // determine the assigned validator on the signed attribute approval
    address validator = _signingKeys[
      hash.toEthSignedMessageHash().recover(signature) // signingKey
    ];
    
    // caller must be either the jurisdiction owner or the assigning validator
    require(
      msg.sender == validator || msg.sender == owner(),
      "only jurisdiction or issuing validator may invalidate attribute approval"
    );

    // add the hash to the set of invalid attribute approval hashes
    _invalidAttributeApprovalHashes[hash] = true;
  }

  /**
   * @notice Check if an attribute of the type with ID `attributeTypeID` has
   * been assigned to the account at `account` and is currently valid.
   * @param account address The account to check for a valid attribute.
   * @param attributeTypeID uint256 The ID of the attribute type to check for.
   * @return True if the attribute is assigned and valid, false otherwise.
   * @dev This function MUST return either true or false - i.e. calling this
   * function MUST NOT cause the caller to revert.
   */
  function hasAttribute(
    address account, 
    uint256 attributeTypeID
  ) external view returns (bool) {
    address validator = _issuedAttributes[account][attributeTypeID].validator;
    return (
      (
        _validators[validator].exists &&   // isValidator(validator)
        _attributeTypes[attributeTypeID].approvedValidators[validator] &&
        _attributeTypes[attributeTypeID].exists //isAttributeType(attributeTypeID)
      ) || (
        _attributeTypes[attributeTypeID].secondarySource != address(0) &&
        secondaryHasAttribute(
          _attributeTypes[attributeTypeID].secondarySource,
          account,
          _attributeTypes[attributeTypeID].secondaryAttributeTypeID
        )
      )
    );
  }

  /**
   * @notice Retrieve the value of the attribute of the type with ID
   * `attributeTypeID` on the account at `account`, assuming it is valid.
   * @param account address The account to check for the given attribute value.
   * @param attributeTypeID uint256 The ID of the attribute type to check for.
   * @return The attribute value if the attribute is valid, reverts otherwise.
   * @dev This function MUST revert if a directly preceding or subsequent
   * function call to `hasAttribute` with identical `account` and
   * `attributeTypeID` parameters would return false.
   */
  function getAttributeValue(
    address account,
    uint256 attributeTypeID
  ) external view returns (uint256 value) {
    // gas optimization: get validator & call canValidate function body directly
    address validator = _issuedAttributes[account][attributeTypeID].validator;
    if (
      _validators[validator].exists &&   // isValidator(validator)
      _attributeTypes[attributeTypeID].approvedValidators[validator] &&
      _attributeTypes[attributeTypeID].exists //isAttributeType(attributeTypeID)
    ) {
      return _issuedAttributes[account][attributeTypeID].value;
    } else if (
      _attributeTypes[attributeTypeID].secondarySource != address(0)
    ) {
      // if attributeTypeID = uint256 of 'wyre-yes-token', use special handling
      if (_attributeTypes[attributeTypeID].secondaryAttributeTypeID == 2423228754106148037712574142965102) {
        require(
          IERC20(
            _attributeTypes[attributeTypeID].secondarySource
          ).balanceOf(account) >= 1,
          "no Yes Token has been issued to the provided account"
        );
        return 1; // this could also return a specific yes token's country code?
      }

      // first ensure hasAttribute on the secondary source returns true
      require(
        AttributeRegistryInterface(
          _attributeTypes[attributeTypeID].secondarySource
        ).hasAttribute(
          account, _attributeTypes[attributeTypeID].secondaryAttributeTypeID
        ),
        "attribute of the provided type is not assigned to the provided account"
      );

      return (
        AttributeRegistryInterface(
          _attributeTypes[attributeTypeID].secondarySource
        ).getAttributeValue(
          account, _attributeTypes[attributeTypeID].secondaryAttributeTypeID
        )
      );
    }

    // NOTE: checking for values of invalid attributes will revert
    revert("could not find an attribute value at the provided account and ID");
  }

  /**
   * @notice Determine if a validator at account `validator` is able to issue
   * attributes of the type with ID `attributeTypeID`.
   * @param validator address The account of the validator.
   * @param attributeTypeID uint256 The ID of the attribute type to check.
   * @return True if the validator can issue attributes of the given type, false
   * otherwise.
   */
  function canIssueAttributeType(
    address validator,
    uint256 attributeTypeID
  ) external view returns (bool) {
    return canValidate(validator, attributeTypeID);
  }

  /**
   * @notice Get a description of the attribute type with ID `attributeTypeID`.
   * @param attributeTypeID uint256 The ID of the attribute type to check for.
   * @return A description of the attribute type.
   */
  function getAttributeTypeDescription(
    uint256 attributeTypeID
  ) external view returns (
    string description
  ) {
    return _attributeTypes[attributeTypeID].description;
  }

  /**
   * @notice Get comprehensive information on an attribute type with ID
   * `attributeTypeID`.
   * @param attributeTypeID uint256 The attribute type ID in question.
   * @return Information on the attribute type in question.
   */
  function getAttributeTypeInformation(
    uint256 attributeTypeID
  ) external view returns (
    string description,
    bool isRestricted,
    bool isOnlyPersonal,
    address secondarySource,
    uint256 secondaryAttributeTypeID,
    uint256 minimumRequiredStake,
    uint256 jurisdictionFee
  ) {
    return (
      _attributeTypes[attributeTypeID].description,
      _attributeTypes[attributeTypeID].restricted,
      _attributeTypes[attributeTypeID].onlyPersonal,
      _attributeTypes[attributeTypeID].secondarySource,
      _attributeTypes[attributeTypeID].secondaryAttributeTypeID,
      _attributeTypes[attributeTypeID].minimumStake,
      _attributeTypes[attributeTypeID].jurisdictionFee
    );
  }

  /**
   * @notice Get a description of the validator at account `validator`.
   * @param validator address The account of the validator in question.
   * @return A description of the validator.
   */
  function getValidatorDescription(
    address validator
  ) external view returns (
    string description
  ) {
    return _validators[validator].description;
  }

  /**
   * @notice Get the signing key of the validator at account `validator`.
   * @param validator address The account of the validator in question.
   * @return The signing key of the validator.
   */
  function getValidatorSigningKey(
    address validator
  ) external view returns (
    address signingKey
  ) {
    return _validators[validator].signingKey;
  }

  /**
   * @notice Find the validator that issued the attribute of the type with ID
   * `attributeTypeID` on the account at `account` and determine if the
   * validator is still valid.
   * @param account address The account that contains the attribute be checked.
   * @param attributeTypeID uint256 The ID of the attribute type in question.
   * @return The validator and the current status of the validator as it
   * pertains to the attribute type in question.
   * @dev if no attribute of the given attribute type exists on the account, the
   * function will return (address(0), false).
   */
  function getAttributeValidator(
    address account,
    uint256 attributeTypeID
  ) external view returns (
    address validator,
    bool isStillValid
  ) {
    address issuer = _issuedAttributes[account][attributeTypeID].validator;
    return (issuer, canValidate(issuer, attributeTypeID));
  }

  /**
   * @notice Count the number of attribute types defined by the registry.
   * @return The number of available attribute types.
   * @dev This function MUST return a positive integer value  - i.e. calling
   * this function MUST NOT cause the caller to revert.
   */
  function countAttributeTypes() external view returns (uint256) {
    return _attributeIDs.length;
  }

  /**
   * @notice Get the ID of the attribute type at index `index`.
   * @param index uint256 The index of the attribute type in question.
   * @return The ID of the attribute type.
   * @dev This function MUST revert if the provided `index` value falls outside
   * of the range of the value returned from a directly preceding or subsequent
   * function call to `countAttributeTypes`. It MUST NOT revert if the provided
   * `index` value falls inside said range.
   */
  function getAttributeTypeID(uint256 index) external view returns (uint256) {
    require(
      index < _attributeIDs.length,
      "provided index is outside of the range of defined attribute type IDs"
    );

    return _attributeIDs[index];
  }

  /**
   * @notice Get the IDs of all available attribute types on the jurisdiction.
   * @return A dynamic array containing all available attribute type IDs.
   */
  function getAttributeTypeIDs() external view returns (uint256[]) {
    return _attributeIDs;
  }

  /**
   * @notice Count the number of validators defined by the jurisdiction.
   * @return The number of defined validators.
   */
  function countValidators() external view returns (uint256) {
    return _validatorAccounts.length;
  }

  /**
   * @notice Get the account of the validator at index `index`.
   * @param index uint256 The index of the validator in question.
   * @return The account of the validator.
   */
  function getValidator(
    uint256 index
  ) external view returns (address) {
    return _validatorAccounts[index];
  }

  /**
   * @notice Get the accounts of all available validators on the jurisdiction.
   * @return A dynamic array containing all available validator accounts.
   */
  function getValidators() external view returns (address[]) {
    return _validatorAccounts;
  }

  /**
   * @notice Determine if the interface ID `interfaceID` is supported (ERC-165)
   * @param interfaceID bytes4 The interface ID in question.
   * @return True if the interface is supported, false otherwise.
   * @dev this function will produce a compiler warning recommending that the
   * visibility be set to pure, but the interface expects a view function.
   * Supported interfaces include ERC-165 (0x01ffc9a7) and the attribute
   * registry interface (0x5f46473f).
   */
  function supportsInterface(bytes4 interfaceID) external view returns (bool) {
    return (
      interfaceID == this.supportsInterface.selector || // ERC165
      interfaceID == (
        this.hasAttribute.selector 
        ^ this.getAttributeValue.selector
        ^ this.countAttributeTypes.selector
        ^ this.getAttributeTypeID.selector
      ) // AttributeRegistryInterface
    ); // 0x01ffc9a7 || 0x5f46473f
  }

  /**
   * @notice Get the hash of a given attribute approval.
   * @param account address The account specified by the attribute approval.
   * @param operator address An optional account permitted to submit approval.
   * @param attributeTypeID uint256 The ID of the attribute type in question.
   * @param value uint256 The value of the attribute in the approval.
   * @param fundsRequired uint256 The amount to be included with the approval.
   * @param validatorFee uint256 The required fee to be paid to the validator.
   * @return The hash of the attribute approval.
   */
  function getAttributeApprovalHash(
    address account,
    address operator,
    uint256 attributeTypeID,
    uint256 value,
    uint256 fundsRequired,
    uint256 validatorFee
  ) external view returns (
    bytes32 hash
  ) {
    return calculateAttributeApprovalHash(
      account,
      operator,
      attributeTypeID,
      value,
      fundsRequired,
      validatorFee
    );
  }

  /**
   * @notice Check if a given signed attribute approval is currently valid when
   * submitted directly by `msg.sender`.
   * @param attributeTypeID uint256 The ID of the attribute type in question.
   * @param value uint256 The value of the attribute in the approval.
   * @param fundsRequired uint256 The amount to be included with the approval.
   * @param validatorFee uint256 The required fee to be paid to the validator.
   * @param signature bytes The attribute approval signature, based on a hash of
   * the other parameters and the submitting account.
   * @return True if the approval is currently valid, false otherwise.
   */
  function canAddAttribute(
    uint256 attributeTypeID,
    uint256 value,
    uint256 fundsRequired,
    uint256 validatorFee,
    bytes signature
  ) external view returns (bool) {
    // signed data hash constructed according to EIP-191-0x45 to prevent replays
    bytes32 hash = calculateAttributeApprovalHash(
      msg.sender,
      address(0),
      attributeTypeID,
      value,
      fundsRequired,
      validatorFee
    );

    // recover the address associated with the signature of the message hash
    address signingKey = hash.toEthSignedMessageHash().recover(signature);
    
    // retrieve variables necessary to perform checks
    address validator = _signingKeys[signingKey];
    uint256 minimumStake = _attributeTypes[attributeTypeID].minimumStake;
    uint256 jurisdictionFee = _attributeTypes[attributeTypeID].jurisdictionFee;

    // determine if the attribute can currently be added.
    // NOTE: consider returning an error code along with the boolean.
    return (
      fundsRequired >= minimumStake.add(jurisdictionFee).add(validatorFee) &&
      !_invalidAttributeApprovalHashes[hash] &&
      canValidate(validator, attributeTypeID) &&
      !_issuedAttributes[msg.sender][attributeTypeID].exists
    );
  }

  /**
   * @notice Check if a given signed attribute approval is currently valid for a
   * given account when submitted by the operator at `msg.sender`.
   * @param account address The account specified by the attribute approval.
   * @param attributeTypeID uint256 The ID of the attribute type in question.
   * @param value uint256 The value of the attribute in the approval.
   * @param fundsRequired uint256 The amount to be included with the approval.
   * @param validatorFee uint256 The required fee to be paid to the validator.
   * @param signature bytes The attribute approval signature, based on a hash of
   * the other parameters and the submitting account.
   * @return True if the approval is currently valid, false otherwise.
   */
  function canAddAttributeFor(
    address account,
    uint256 attributeTypeID,
    uint256 value,
    uint256 fundsRequired,
    uint256 validatorFee,
    bytes signature
  ) external view returns (bool) {
    // signed data hash constructed according to EIP-191-0x45 to prevent replays
    bytes32 hash = calculateAttributeApprovalHash(
      account,
      msg.sender,
      attributeTypeID,
      value,
      fundsRequired,
      validatorFee
    );

    // recover the address associated with the signature of the message hash
    address signingKey = hash.toEthSignedMessageHash().recover(signature);
    
    // retrieve variables necessary to perform checks
    address validator = _signingKeys[signingKey];
    uint256 minimumStake = _attributeTypes[attributeTypeID].minimumStake;
    uint256 jurisdictionFee = _attributeTypes[attributeTypeID].jurisdictionFee;

    // determine if the attribute can currently be added.
    // NOTE: consider returning an error code along with the boolean.
    return (
      fundsRequired >= minimumStake.add(jurisdictionFee).add(validatorFee) &&
      !_invalidAttributeApprovalHashes[hash] &&
      canValidate(validator, attributeTypeID) &&
      !_issuedAttributes[account][attributeTypeID].exists
    );
  }

  /**
   * @notice Determine if an attribute type with ID `attributeTypeID` is
   * currently defined on the jurisdiction.
   * @param attributeTypeID uint256 The attribute type ID in question.
   * @return True if the attribute type is defined, false otherwise.
   */
  function isAttributeType(uint256 attributeTypeID) public view returns (bool) {
    return _attributeTypes[attributeTypeID].exists;
  }

  /**
   * @notice Determine if the account `account` is currently assigned as a
   * validator on the jurisdiction.
   * @param account address The account to check for validator status.
   * @return True if the account is assigned as a validator, false otherwise.
   */
  function isValidator(address account) public view returns (bool) {
    return _validators[account].exists;
  }

  /**
   * @notice Check for recoverable funds that have become locked in the
   * jurisdiction as a result of improperly configured receivers for payments of
   * fees or remaining stake. Note that funds sent into the jurisdiction as a 
   * result of coinbase assignment or as the recipient of a selfdestruct will
   * not be recoverable.
   * @return The total tracked recoverable funds.
   */
  function recoverableFunds() public view returns (uint256) {
    // return the total tracked recoverable funds.
    return _recoverableFunds;
  }

  /**
   * @notice Check for recoverable tokens that are owned by the jurisdiction at
   * the token contract address of `token`.
   * @param token address The account where token contract is located.
   * @return The total recoverable tokens.
   */
  function recoverableTokens(address token) public view returns (uint256) {
    // return the total tracked recoverable tokens.
    return IERC20(token).balanceOf(address(this));
  }

  /**
   * @notice Recover funds that have become locked in the jurisdiction as a
   * result of improperly configured receivers for payments of fees or remaining
   * stake by transferring an amount of `value` to the address at `account`.
   * Note that funds sent into the jurisdiction as a result of coinbase
   * assignment or as the recipient of a selfdestruct will not be recoverable.
   * @param account address The account to send recovered tokens.
   * @param value uint256 The amount of tokens to be sent.
   */
  function recoverFunds(address account, uint256 value) public onlyOwner {    
    // safely deduct the value from the total tracked recoverable funds.
    _recoverableFunds = _recoverableFunds.sub(value);
    
    // transfer the value to the specified account & revert if any error occurs.
    account.transfer(value);
  }

  /**
   * @notice Recover tokens that are owned by the jurisdiction at the token
   * contract address of `token`, transferring an amount of `value` to the
   * address at `account`.
   * @param token address The account where token contract is located.
   * @param account address The account to send recovered funds.
   * @param value uint256 The amount of ether to be sent.
   */
  function recoverTokens(
    address token,
    address account,
    uint256 value
  ) public onlyOwner {
    // transfer the value to the specified account & revert if any error occurs.
    require(IERC20(token).transfer(account, value));
  }

  /**
   * @notice Internal function to determine if a validator at account
   * `validator` can issue attributes of the type with ID `attributeTypeID`.
   * @param validator address The account of the validator.
   * @param attributeTypeID uint256 The ID of the attribute type to check.
   * @return True if the validator can issue attributes of the given type, false
   * otherwise.
   */
  function canValidate(
    address validator,
    uint256 attributeTypeID
  ) internal view returns (bool) {
    return (
      _validators[validator].exists &&   // isValidator(validator)
      _attributeTypes[attributeTypeID].approvedValidators[validator] &&
      _attributeTypes[attributeTypeID].exists // isAttributeType(attributeTypeID)
    );
  }

  // internal helper function for getting the hash of an attribute approval
  function calculateAttributeApprovalHash(
    address account,
    address operator,
    uint256 attributeTypeID,
    uint256 value,
    uint256 fundsRequired,
    uint256 validatorFee
  ) internal view returns (bytes32 hash) {
    return keccak256(
      abi.encodePacked(
        address(this),
        account,
        operator,
        fundsRequired,
        validatorFee,
        attributeTypeID,
        value
      )
    );
  }

  // helper function, won't revert calling hasAttribute on secondary registries
  function secondaryHasAttribute(
    address source,
    address account,
    uint256 attributeTypeID
  ) internal view returns (bool result) {
    // if attributeTypeID = uint256 of 'wyre-yes-token', use special handling
    if (attributeTypeID == 2423228754106148037712574142965102) {
      return (IERC20(source).balanceOf(account) >= 1);
    }

    uint256 maxGas = gasleft() > 20000 ? 20000 : gasleft();
    bytes memory encodedParams = abi.encodeWithSelector(
      this.hasAttribute.selector,
      account,
      attributeTypeID
    );

    assembly {
      let encodedParams_data := add(0x20, encodedParams)
      let encodedParams_size := mload(encodedParams)
      
      let output := mload(0x40) // get storage start from free memory pointer
      mstore(output, 0x0)       // set up the location for output of staticcall

      let success := staticcall(
        maxGas,                 // maximum of 20k gas can be forwarded
        source,                 // address of attribute registry to call
        encodedParams_data,     // inputs are stored at pointer location
        encodedParams_size,     // inputs are 68 bytes (4 + 32 * 2)
        output,                 // return to designated free space
        0x20                    // output is one word, or 32 bytes
      )

      switch success            // instrumentation bug: use switch instead of if
      case 1 {                  // only recognize successful staticcall output 
        result := mload(output) // set the output to the return value
      }
    }
  }
}

Contract Security Audit

Contract ABI

[{"constant":true,"inputs":[{"name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getAttributeTypeID","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"hash","type":"bytes32"},{"name":"signature","type":"bytes"}],"name":"invalidateAttributeApproval","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ID","type":"uint256"},{"name":"onlyPersonal","type":"bool"}],"name":"setAttributeTypeOnlyPersonal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"},{"name":"attributeTypeID","type":"uint256"}],"name":"getAttributeValidator","outputs":[{"name":"validator","type":"address"},{"name":"isStillValid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"attributeTypeID","type":"uint256"}],"name":"removeAttribute","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newSigningKey","type":"address"}],"name":"setValidatorSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"recoverableFunds","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"attributeTypeID","type":"uint256"}],"name":"isAttributeType","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"}],"name":"removeValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isPauser","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"},{"name":"attributeTypeID","type":"uint256"}],"name":"hasAttribute","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"attributeTypeID","type":"uint256"},{"name":"value","type":"uint256"}],"name":"issueAttribute","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"value","type":"uint256"}],"name":"recoverFunds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"account","type":"address"},{"name":"value","type":"uint256"}],"name":"recoverTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"attributeTypeID","type":"uint256"},{"name":"value","type":"uint256"},{"name":"validatorFee","type":"uint256"},{"name":"signature","type":"bytes"}],"name":"addAttribute","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"description","type":"string"}],"name":"addValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"attributeTypeID","type":"uint256"}],"name":"getAttributeTypeInformation","outputs":[{"name":"description","type":"string"},{"name":"isRestricted","type":"bool"},{"name":"isOnlyPersonal","type":"bool"},{"name":"secondarySource","type":"address"},{"name":"secondaryAttributeTypeID","type":"uint256"},{"name":"minimumRequiredStake","type":"uint256"},{"name":"jurisdictionFee","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renouncePauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"recoverableTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"attributeTypeID","type":"uint256"}],"name":"addValidatorApproval","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ID","type":"uint256"}],"name":"removeAttributeType","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"attributeTypeID","type":"uint256"},{"name":"value","type":"uint256"},{"name":"validatorFee","type":"uint256"},{"name":"signature","type":"bytes"}],"name":"addAttributeFor","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"addPauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"validator","type":"address"}],"name":"getValidatorSigningKey","outputs":[{"name":"signingKey","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"attributeTypeID","type":"uint256"},{"name":"value","type":"uint256"},{"name":"fundsRequired","type":"uint256"},{"name":"validatorFee","type":"uint256"},{"name":"signature","type":"bytes"}],"name":"canAddAttribute","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAttributeTypeIDs","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"countValidators","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"validator","type":"address"}],"name":"getValidatorDescription","outputs":[{"name":"description","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"ID","type":"uint256"},{"name":"description","type":"string"}],"name":"addAttributeType","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ID","type":"uint256"},{"name":"fee","type":"uint256"}],"name":"setAttributeTypeJurisdictionFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"},{"name":"attributeTypeID","type":"uint256"},{"name":"value","type":"uint256"},{"name":"fundsRequired","type":"uint256"},{"name":"validatorFee","type":"uint256"},{"name":"signature","type":"bytes"}],"name":"canAddAttributeFor","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"attributeTypeID","type":"uint256"}],"name":"removeValidatorApproval","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getValidator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"},{"name":"attributeTypeID","type":"uint256"}],"name":"getAttributeValue","outputs":[{"name":"value","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"countAttributeTypes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"},{"name":"operator","type":"address"},{"name":"attributeTypeID","type":"uint256"},{"name":"value","type":"uint256"},{"name":"fundsRequired","type":"uint256"},{"name":"validatorFee","type":"uint256"}],"name":"getAttributeApprovalHash","outputs":[{"name":"hash","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"ID","type":"uint256"},{"name":"minimumRequiredStake","type":"uint256"}],"name":"setAttributeTypeMinimumRequiredStake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ID","type":"uint256"},{"name":"attributeRegistry","type":"address"},{"name":"sourceAttributeTypeID","type":"uint256"}],"name":"setAttributeTypeSecondarySource","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ID","type":"uint256"},{"name":"description","type":"string"}],"name":"addRestrictedAttributeType","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"validator","type":"address"},{"name":"attributeTypeID","type":"uint256"}],"name":"canIssueAttributeType","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"attributeTypeID","type":"uint256"}],"name":"revokeAttribute","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isValidator","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"attributeTypeID","type":"uint256"}],"name":"removeAttributeFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"attributeTypeID","type":"uint256"}],"name":"getAttributeTypeDescription","outputs":[{"name":"description","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"owner","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"validator","type":"address"},{"indexed":false,"name":"newSigningKey","type":"address"}],"name":"ValidatorSigningKeyModified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"staker","type":"address"},{"indexed":true,"name":"attribute","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"StakeAllocated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"staker","type":"address"},{"indexed":true,"name":"attribute","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"StakeRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipient","type":"address"},{"indexed":true,"name":"payee","type":"address"},{"indexed":true,"name":"attribute","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"FeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"submitter","type":"address"},{"indexed":true,"name":"payee","type":"address"},{"indexed":true,"name":"attribute","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"TransactionRebatePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"attributeTypeID","type":"uint256"},{"indexed":false,"name":"description","type":"string"}],"name":"AttributeTypeAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"attributeTypeID","type":"uint256"}],"name":"AttributeTypeRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"validator","type":"address"},{"indexed":false,"name":"description","type":"string"}],"name":"ValidatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"validator","type":"address"}],"name":"ValidatorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"validator","type":"address"},{"indexed":true,"name":"attributeTypeID","type":"uint256"}],"name":"ValidatorApprovalAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"validator","type":"address"},{"indexed":true,"name":"attributeTypeID","type":"uint256"}],"name":"ValidatorApprovalRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"validator","type":"address"},{"indexed":true,"name":"attributee","type":"address"},{"indexed":false,"name":"attributeTypeID","type":"uint256"},{"indexed":false,"name":"attributeValue","type":"uint256"}],"name":"AttributeAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"validator","type":"address"},{"indexed":true,"name":"attributee","type":"address"},{"indexed":false,"name":"attributeTypeID","type":"uint256"}],"name":"AttributeRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]

60806040523480156200001157600080fd5b5060405160208062005ee5833981016040819052905160008054600160a060020a031916600160a060020a03808416919091178083559293849390911691907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506200008a336401000000006200009b810204565b506002805460ff1916905562000180565b620000b660018264010000000062005bdb620000ed82021704565b604051600160a060020a038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b600160a060020a03811615156200010357600080fd5b62000118828264010000000062000148810204565b156200012357600080fd5b600160a060020a0316600090815260209190915260409020805460ff19166001179055565b6000600160a060020a03821615156200016057600080fd5b50600160a060020a03166000908152602091909152604090205460ff1690565b615d5580620001906000396000f30060806040526004361061027c5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166301ffc9a781146102815780630e62fde6146102cc5780630e9065df146102f657806313cbb9701461031c57806317cf31d81461033957806318bbfb9c146103805780632724a47714610398578063352f3627146103b95780633f4ba83a146103ce5780633f8ab725146103e357806340a141ff146103fb57806346fbf68e1461041c5780634b5f297a1461043d57806350135c3a14610461578063586097541461047b5780635c975abb1461049f5780635f3e849f146104b457806362e9674f146104de57806363e2a232146104fd5780636b6004621461052a5780636ef8d66d146105fe578063715018a614610613578063727ba802146106285780637756588c146106495780637aedf3e01461066d57806381050c651461068557806382dc1ec4146106b15780638456cb59146106d25780638da5cb5b146106e75780638f32d59b146107185780639302091f1461072d578063952600ac1461074e5780639679c72a1461077e57806397f3c806146107e3578063a43569b3146107f8578063acb291721461088e578063aee338ee146108b2578063b09b37d8146108cd578063b340ec811461090a578063b5d896271461092e578063b7ab4db514610946578063cd6c83431461095b578063d71710e01461097f578063d99f2c9714610994578063e4bbca9f146109c7578063e5541be7146109e2578063eb3b274c14610a09578063f287f8fb14610a2d578063f2fde38b14610a51578063f9292ffb14610a72578063facd743b14610a96578063fdf9101c14610ab7578063feec036f14610adb575b600080fd5b34801561028d57600080fd5b506102b87bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1960043516610af3565b604080519115158252519081900360200190f35b3480156102d857600080fd5b506102e4600435610b86565b60408051918252519081900360200190f35b34801561030257600080fd5b5061031a600480359060248035908101910135610c4f565b005b34801561032857600080fd5b5061031a6004356024351515610da5565b34801561034557600080fd5b5061035d600160a060020a0360043516602435610e79565b60408051600160a060020a03909316835290151560208301528051918290030190f35b34801561038c57600080fd5b5061031a600435610ebd565b3480156103a457600080fd5b5061031a600160a060020a03600435166111e6565b3480156103c557600080fd5b506102e461139a565b3480156103da57600080fd5b5061031a6113a1565b3480156103ef57600080fd5b506102b8600435611405565b34801561040757600080fd5b5061031a600160a060020a036004351661141a565b34801561042857600080fd5b506102b8600160a060020a03600435166117e2565b34801561044957600080fd5b506102b8600160a060020a03600435166024356117f5565b61031a600160a060020a03600435166024356044356118df565b34801561048757600080fd5b5061031a600160a060020a0360043516602435611d6f565b3480156104ab57600080fd5b506102b8611dd3565b3480156104c057600080fd5b5061031a600160a060020a0360043581169060243516604435611ddc565b61031a6004803590602480359160443591606435908101910135611ea2565b34801561050957600080fd5b5061031a60048035600160a060020a031690602480359081019101356125c3565b34801561053657600080fd5b50610542600435612904565b6040518080602001881515151581526020018715151515815260200186600160a060020a0316600160a060020a03168152602001858152602001848152602001838152602001828103825289818151815260200191508051906020019080838360005b838110156105bd5781810151838201526020016105a5565b50505050905090810190601f1680156105ea5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b34801561060a57600080fd5b5061031a612a05565b34801561061f57600080fd5b5061031a612a10565b34801561063457600080fd5b506102e4600160a060020a0360043516612a7a565b34801561065557600080fd5b5061031a600160a060020a0360043516602435612b10565b34801561067957600080fd5b5061031a600435612d0b565b61031a60048035600160a060020a03169060248035916044359160643591608435918201910135612edd565b3480156106bd57600080fd5b5061031a600160a060020a036004351661370c565b3480156106de57600080fd5b5061031a61372c565b3480156106f357600080fd5b506106fc613792565b60408051600160a060020a039092168252519081900360200190f35b34801561072457600080fd5b506102b86137a1565b34801561073957600080fd5b506106fc600160a060020a03600435166137b2565b34801561075a57600080fd5b506102b86004803590602480359160443591606435916084359182019101356137d3565b34801561078a57600080fd5b50610793613924565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156107cf5781810151838201526020016107b7565b505050509050019250505060405180910390f35b3480156107ef57600080fd5b506102e461397c565b34801561080457600080fd5b50610819600160a060020a0360043516613982565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561085357818101518382015260200161083b565b50505050905090810190601f1680156108805780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561089a57600080fd5b5061031a600480359060248035908101910135613a30565b3480156108be57600080fd5b5061031a600435602435613e3a565b3480156108d957600080fd5b506102b860048035600160a060020a031690602480359160443591606435916084359160a435908101910135613ed4565b34801561091657600080fd5b5061031a600160a060020a0360043516602435614022565b34801561093a57600080fd5b506106fc600435614253565b34801561095257600080fd5b5061079361427f565b34801561096757600080fd5b506102e4600160a060020a03600435166024356142e0565b34801561098b57600080fd5b506102e4614785565b3480156109a057600080fd5b506102e4600160a060020a036004358116906024351660443560643560843560a43561478b565b3480156109d357600080fd5b5061031a6004356024356147a6565b3480156109ee57600080fd5b5061031a600435600160a060020a0360243516604435614866565b348015610a1557600080fd5b5061031a600480359060248035908101910135614957565b348015610a3957600080fd5b506102b8600160a060020a0360043516602435614cd0565b348015610a5d57600080fd5b5061031a600160a060020a0360043516614ce3565b348015610a7e57600080fd5b5061031a600160a060020a0360043516602435614cff565b348015610aa257600080fd5b506102b8600160a060020a03600435166151b6565b348015610ac357600080fd5b5061031a600160a060020a03600435166024356151d4565b348015610ae757600080fd5b50610819600435615545565b60007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1982167f01ffc9a7000000000000000000000000000000000000000000000000000000001480610b8057507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1982167f5f46473f00000000000000000000000000000000000000000000000000000000145b92915050565b600b546000908210610c2f576040805160e560020a62461bcd028152602060048201526044602482018190527f70726f766964656420696e646578206973206f757473696465206f6620746865908201527f2072616e6765206f6620646566696e656420617474726962757465207479706560648201527f2049447300000000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b600b805483908110610c3d57fe5b90600052602060002001549050919050565b600060066000610ca085858080601f01602080910402602001604051908101604052809392919081815260200183838082843750610c9494508c93506155b292505050565b9063ffffffff61565c16565b600160a060020a03908116825260208201929092526040016000205416905033811480610ce55750610cd0613792565b600160a060020a031633600160a060020a0316145b1515610d87576040805160e560020a62461bcd02815260206004820152604860248201527f6f6e6c79206a7572697364696374696f6e206f722069737375696e672076616c60448201527f696461746f72206d617920696e76616c6964617465206174747269627574652060648201527f617070726f76616c000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b5050506000908152600860205260409020805460ff19166001179055565b610dae82611405565b1515610e50576040805160e560020a62461bcd02815260206004820152604660248201527f756e61626c6520746f2073657420746f206f6e6c7920706572736f6e616c2c2060448201527f6e6f2061747472696275746520747970652077697468207468652070726f766960648201527f6465642049440000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b6000918252600360205260409091208054911515620100000262ff000019909216919091179055565b600160a060020a038083166000908152600460209081526040808320858452909152812060010154909182911680610eb18186615731565b92509250509250929050565b600081815260036020526040812054819081908190610100900460ff1615610f7b576040805160e560020a62461bcd02815260206004820152604860248201527f6f6e6c79206a7572697364696374696f6e206f722069737375696e672076616c60448201527f696461746f72206d61792072656d6f766520612072657374726963746564206160648201527f7474726962757465000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b33600090815260046020908152604080832088845290915290205460ff161515611015576040805160e560020a62461bcd02815260206004820152602760248201527f6f6e6c79206578697374696e672061747472696275746573206d61792062652060448201527f72656d6f76656400000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b3360009081526004602090815260408083208884529091529020600181015460038201549154600160a060020a039091169550909350610100900460ff16156110605733915061109e565b50336000908152600460209081526040808320878452909152902054620100009004600160a060020a031680151561109a5783915061109e565b8091505b3360008181526004602090815260408083208984528252808320805475ffffffffffffffffffffffffffffffffffffffffffff1916815560018101805473ffffffffffffffffffffffffffffffffffffffff1916905560028101849055600301929092558151600160a060020a038816815290810188905281517faa5b822df0611950f79edb91a7f829d92df3d2ae66b54ee3b5b15ead069e1a67929181900390910190a2600083118015611154575030318311155b156111df57604051600160a060020a0383169084156108fc029085906000818181858888f19350505050156111c8576040805184815290518691600160a060020a038516917fcb777cb6ab680dc1db2889b92613a0640bc47be07dc40a8f640dfd7e7882790d9181900360200190a36111df565b600d546111db908463ffffffff61579d16565b600d555b5050505050565b6111ef336151b6565b151561126b576040805160e560020a62461bcd02815260206004820152603160248201527f6f6e6c792076616c696461746f7273206d6179206d6f646966792076616c696460448201527f61746f72207369676e696e67206b657973000000000000000000000000000000606482015290519081900360840190fd5b600160a060020a038181166000908152600660205260409020541615611301576040805160e560020a62461bcd02815260206004820152603a60248201527f61207369676e696e67206b6579206d61746368696e67207468652070726f766960448201527f646564206164647265737320616c726561647920657869737473000000000000606482015290519081900360840190fd5b3360008181526005602090815260408083206002018054600160a060020a03908116855260068452828520805473ffffffffffffffffffffffffffffffffffffffff1990811690915582548116918816918217909255808552938290208054909116851790558051928352517fa0d7a9c0cfc746249b49860852dbe114b817a004ed34bcb8bfadbda860ebfc159281900390910190a250565b600d545b90565b6113aa336117e2565b15156113b557600080fd5b60025460ff1615156113c657600080fd5b6002805460ff191690556040805133815290517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9181900360200190a1565b60009081526003602052604090205460ff1690565b60008060006114276137a1565b151561143257600080fd5b60025460ff161561144257600080fd5b61144b846151b6565b15156114c7576040805160e560020a62461bcd02815260206004820152603e60248201527f756e61626c6520746f2072656d6f76652c206e6f2076616c696461746f72206c60448201527f6f6361746564206174207468652070726f766964656420616464726573730000606482015290519081900360840190fd5b600160a060020a0384166000908152600960205260408120541180156114ee57506161a85a115b156115b257600160a060020a03841660009081526009602052604090205461151d90600163ffffffff6157af16565b600160a060020a03851660009081526009602052604090208054919450908490811061154557fe5b6000918252602080832090910154808352600382526040808420600160a060020a03891680865260079091018452818520805460ff19169055600a8452818520838652845281852085905584526009909252912080549193506115ac906000198301615c29565b506114c7565b600160a060020a0384166000908152600960205260409020541561166c576040805160e560020a62461bcd02815260206004820152604760248201527f43616e6e6f742072656d6f76652076616c696461746f72202d2066697273742060448201527f72656d6f766520616e79206578697374696e672076616c696461746f7220617060648201527f70726f76616c7300000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b600c805461168190600163ffffffff6157af16565b8154811061168b57fe5b6000918252602080832090910154600160a060020a0387811684526005909252604090922060010154600c805492909316935083929181106116c957fe5b6000918252602080832091909101805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039485161790558683168252600590526040808220600190810154938516835291200155600c80549061172e906000198301615c29565b50600160a060020a038085166000818152600560208181526040808420600281018054909716855260068352908420805473ffffffffffffffffffffffffffffffffffffffff19908116909155948452919052805460ff19168155600181018290558354909216909255906117a66003830182615c4d565b5050604051600160a060020a038516907fe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f190600090a250505050565b6000610b8060018363ffffffff6157c616565b600160a060020a03808316600090815260046020908152604080832085845282528083206001015490931680835260059091529181205490919060ff16801561186357506000838152600360209081526040808320600160a060020a038516845260070190915290205460ff165b801561187d575060008381526003602052604090205460ff165b806118d55750600083815260036020526040902060020154600160a060020a0316158015906118d55750600083815260036020819052604090912060028101549101546118d591600160a060020a03169086906157fd565b91505b5092915050565b6002546000908190819060ff16156118f657600080fd5b6119003386615731565b151561197c576040805160e560020a62461bcd02815260206004820152603b60248201527f6f6e6c7920617070726f7665642076616c696461746f7273206d61792061737360448201527f69676e2061747472696275746573206f66207468697320747970650000000000606482015290519081900360840190fd5b600160a060020a038616600090815260046020908152604080832088845290915290205460ff1615611a44576040805160e560020a62461bcd02815260206004820152604760248201527f6475706c6963617465206174747269627574657320617265206e6f742073757060448201527f706f727465642c2072656d6f7665206578697374696e6720617474726962757460648201527f6520666972737400000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b600085815260036020526040902060048101546005909101549093509150611a72348363ffffffff6157af16565b905082811015611af2576040805160e560020a62461bcd02815260206004820152603d60248201527f617474726962757465207265717569726573206120677265617465722076616c60448201527f7565207468616e2069732063757272656e746c792070726f7669646564000000606482015290519081900360840190fd5b60c0604051908101604052806001151581526020016000151581526020016000600160a060020a0316815260200133600160a060020a03168152602001858152602001828152506004600088600160a060020a0316600160a060020a03168152602001908152602001600020600087815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a815481600160a060020a030219169083600160a060020a0316021790555060608201518160010160006101000a815481600160a060020a030219169083600160a060020a031602179055506080820151816002015560a0820151816003015590505085600160a060020a03167ffc11e611c2bf07aa7dd09a4fb47124294eca7a7993ccc89e3b041fc41f3215773387876040518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a26000811115611cc457604080518281529051869133917f299c1112ccd1f86d83236b94ae590655a270301868085c8ac82b0d7df093a2fb9181900360200190a35b6000821115611d6757611cd5613792565b600160a060020a03166108fc839081150290604051600060405180830381858888f1935050505015611d50578433611d0b613792565b600160a060020a03167f6096acf19cd2d3142f2b1ec1b1cede21aa8b5d1698264582b552923bc5fbf464856040518082815260200191505060405180910390a4611d67565b600d54611d63908363ffffffff61579d16565b600d555b505050505050565b611d776137a1565b1515611d8257600080fd5b600d54611d95908263ffffffff6157af16565b600d55604051600160a060020a0383169082156108fc029083906000818181858888f19350505050158015611dce573d6000803e3d6000fd5b505050565b60025460ff1690565b611de46137a1565b1515611def57600080fd5b82600160a060020a031663a9059cbb83836040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015611e6b57600080fd5b505af1158015611e7f573d6000803e3d6000fd5b505050506040513d6020811015611e9557600080fd5b50511515611dce57600080fd5b3360009081526004602090815260408083208884529091528120548190819081908190819060ff1615611f6b576040805160e560020a62461bcd02815260206004820152604760248201527f6475706c6963617465206174747269627574657320617265206e6f742073757060448201527f706f727465642c2072656d6f7665206578697374696e6720617474726962757460648201527f6520666972737400000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b60008b815260036020526040902060048101546005909101549096509450611fa985611f9d348c63ffffffff6157af16565b9063ffffffff6157af16565b935085841015612029576040805160e560020a62461bcd02815260206004820152603d60248201527f617474726962757465207265717569726573206120677265617465722076616c60448201527f7565207468616e2069732063757272656e746c792070726f7669646564000000606482015290519081900360840190fd5b604080516c01000000000000000000000000308102602080840191909152339190910260348301526000604883015234605c830152607c82018c9052609c82018e905260bc8083018e90528351808403909101815260dc90920192839052815191929182918401908083835b602083106120b45780518252601f199092019160209182019101612095565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181526008909252929020549196505060ff161591506121709050576040805160e560020a62461bcd02815260206004820152603c60248201527f7369676e65642061747472696275746520617070726f76616c732066726f6d2060448201527f76616c696461746f7273206d6179206e6f742062652072657573656400000000606482015290519081900360840190fd5b6121af88888080601f01602080910402602001604051908101604052809392919081815260200183838082843750610c9494508993506155b292505050565b600160a060020a038082166000908152600660205260409020549193501690506121d9818c615731565b151561227b576040805160e560020a62461bcd02815260206004820152604760248201527f7369676e617475726520646f6573206e6f74206d6174636820616e206170707260448201527f6f7665642076616c696461746f7220666f7220676976656e206174747269627560648201527f7465207479706500000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b60c0604051908101604052806001151581526020016001151581526020016000600160a060020a0316815260200182600160a060020a031681526020018b8152602001858152506004600033600160a060020a0316600160a060020a0316815260200190815260200160002060008d815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a815481600160a060020a030219169083600160a060020a0316021790555060608201518160010160006101000a815481600160a060020a030219169083600160a060020a031602179055506080820151816002015560a08201518160030155905050600160086000856000191660001916815260200190815260200160002060006101000a81548160ff02191690831515021790555033600160a060020a03167ffc11e611c2bf07aa7dd09a4fb47124294eca7a7993ccc89e3b041fc41f321577828d8d6040518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a26000841115612481576040805185815290518c9133917f299c1112ccd1f86d83236b94ae590655a270301868085c8ac82b0d7df093a2fb9181900360200190a35b600085111561252457612492613792565b600160a060020a03166108fc869081150290604051600060405180830381858888f193505050501561250d578a336124c8613792565b600160a060020a03167f6096acf19cd2d3142f2b1ec1b1cede21aa8b5d1698264582b552923bc5fbf464886040518082815260200191505060405180910390a4612524565b600d54612520908663ffffffff61579d16565b600d555b60008911156125b657604051600160a060020a038216908a156108fc02908b906000818181858888f193505050501561259f57604080518a815290518c913391600160a060020a038516917f6096acf19cd2d3142f2b1ec1b1cede21aa8b5d1698264582b552923bc5fbf464919081900360200190a46125b6565b600d546125b2908a63ffffffff61579d16565b600d555b5050505050505050505050565b6125cb6137a1565b15156125d657600080fd5b60025460ff16156125e657600080fd5b600160a060020a0383161515612646576040805160e560020a62461bcd02815260206004820152601b60248201527f6d75737420737570706c7920612076616c696420616464726573730000000000604482015290519081900360640190fd5b61264f836151b6565b156126ca576040805160e560020a62461bcd02815260206004820152603460248201527f612076616c696461746f722077697468207468652070726f766964656420616460448201527f647265737320616c726561647920657869737473000000000000000000000000606482015290519081900360840190fd5b600160a060020a038381166000908152600660205260409020541615612760576040805160e560020a62461bcd02815260206004820152603a60248201527f61207369676e696e67206b6579206d61746368696e67207468652070726f766960448201527f646564206164647265737320616c726561647920657869737473000000000000606482015290519081900360840190fd5b608060405190810160405280600115158152602001600c80549050815260200184600160a060020a0316815260200183838080601f01602080910402602001604051908101604052809392919081815260200183838082843750505092909352505050600160a060020a038481166000908152600560209081526040918290208451815460ff19169015151781558482015160018201559184015160028301805473ffffffffffffffffffffffffffffffffffffffff1916919094161790925560608301518051919261283b92600385019290910190615c91565b505050600160a060020a0383166000818152600660209081526040808320805473ffffffffffffffffffffffffffffffffffffffff199081168617909155600c805460018101825594527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c79093018054909316841790925581518181529081018490527f1b7d03cceb084ba7be615fd8e4ed4d42b157b5accf0863d634316e93b2207b4491859185918190810184848082843760405192018290039550909350505050a2505050565b600081815260036020818152604080842080546002808301549583015460048401546005850154600690950180548751610100600183161581026000190190921695909504601f81018a90048a0286018a0190985287855260609a998a998a998a998a998a99969895810460ff90811698620100009092041696600160a060020a0390951695949093919290918991908301828280156129e55780601f106129ba576101008083540402835291602001916129e5565b820191906000526020600020905b8154815290600101906020018083116129c857829003601f168201915b505050505096509650965096509650965096509650919395979092949650565b612a0e33615984565b565b612a186137a1565b1515612a2357600080fd5b60008054604051600160a060020a03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a36000805473ffffffffffffffffffffffffffffffffffffffff19169055565b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600091600160a060020a038416916370a082319160248082019260209290919082900301818787803b158015612ade57600080fd5b505af1158015612af2573d6000803e3d6000fd5b505050506040513d6020811015612b0857600080fd5b505192915050565b6000612b1a6137a1565b1515612b2557600080fd5b60025460ff1615612b3557600080fd5b612b3e836151b6565b8015612b4e5750612b4e82611405565b1515612bca576040805160e560020a62461bcd02815260206004820152603e60248201527f6d757374207370656369667920626f746820612076616c69642061747472696260448201527f75746520616e6420616e20617661696c61626c652076616c696461746f720000606482015290519081900360840190fd5b6000828152600360209081526040808320600160a060020a038716845260070190915290205460ff1615612c6e576040805160e560020a62461bcd02815260206004820152603760248201527f76616c696461746f7220697320616c726561647920617070726f766564206f6e60448201527f207468652070726f766964656420617474726962757465000000000000000000606482015290519081900360840190fd5b506000818152600360209081526040808320600160a060020a03861680855260079091018352818420805460ff1916600190811790915560098085528386208054600a8752858820898952875285882081905591865291810182559085529383902084018590558151908152905184927fb85fe33f50f5937cbd24633a194ac0b16ca5db589959efada76f734bec961354928290030190a2505050565b6000612d156137a1565b1515612d2057600080fd5b60025460ff1615612d3057600080fd5b612d3982611405565b1515612db5576040805160e560020a62461bcd02815260206004820152603860248201527f756e61626c6520746f2072656d6f76652c206e6f20617474726962757465207460448201527f7970652077697468207468652070726f76696465642049440000000000000000606482015290519081900360840190fd5b600b8054612dca90600163ffffffff6157af16565b81548110612dd457fe5b9060005260206000200154905080600b6003600085815260200190815260200160002060010154815481101515612e0757fe5b6000918252602080832090910192909255838152600390915260408082206001908101548484529190922090910155600b805490612e49906000198301615c29565b5060008281526003602081905260408220805462ffffff191681556001810183905560028101805473ffffffffffffffffffffffffffffffffffffffff19169055908101829055600481018290556005810182905590612eac6006830182615c4d565b505060405182907f3302c92bb3443045711224b35c624d0a8c297a7b853f0084f2442de76f36e1a190600090a25050565b6000858152600360205260408120548190819081908190819062010000900460ff1615612fa1576040805160e560020a62461bcd028152602060048201526044602482018190527f6f6e6c79206f706572617461626c652061747472696275746573206d61792062908201527f65206164646564206f6e20626568616c66206f6620616e6f746865722061646460648201527f7265737300000000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b600160a060020a038c1660009081526004602090815260408083208e845290915290205460ff1615613069576040805160e560020a62461bcd02815260206004820152604760248201527f6475706c6963617465206174747269627574657320617265206e6f742073757060448201527f706f727465642c2072656d6f7665206578697374696e6720617474726962757460648201527f6520666972737400000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b60008b81526003602052604090206004810154600590910154909650945061309b85611f9d348c63ffffffff6157af16565b93508584101561311b576040805160e560020a62461bcd02815260206004820152603d60248201527f617474726962757465207265717569726573206120677265617465722076616c60448201527f7565207468616e2069732063757272656e746c792070726f7669646564000000606482015290519081900360840190fd5b308c33348c8f8f6040516020018088600160a060020a0316600160a060020a03166c0100000000000000000000000002815260140187600160a060020a0316600160a060020a03166c0100000000000000000000000002815260140186600160a060020a0316600160a060020a03166c010000000000000000000000000281526014018581526020018481526020018381526020018281526020019750505050505050506040516020818303038152906040526040518082805190602001908083835b602083106131fd5780518252601f1990920191602091820191016131de565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181526008909252929020549196505060ff161591506132b99050576040805160e560020a62461bcd02815260206004820152603c60248201527f7369676e65642061747472696275746520617070726f76616c732066726f6d2060448201527f76616c696461746f7273206d6179206e6f742062652072657573656400000000606482015290519081900360840190fd5b6132f888888080601f01602080910402602001604051908101604052809392919081815260200183838082843750610c9494508993506155b292505050565b600160a060020a03808216600090815260066020526040902054919350169050613322818c615731565b15156133c4576040805160e560020a62461bcd02815260206004820152604560248201527f7369676e617475726520646f6573206e6f74206d6174636820616e206170707260448201527f6f7665642076616c696461746f7220666f722070726f7669646564206174747260648201527f6962757465000000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b60c06040519081016040528060011515815260200160001515815260200133600160a060020a0316815260200182600160a060020a031681526020018b815260200185815250600460008e600160a060020a0316600160a060020a0316815260200190815260200160002060008d815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a815481600160a060020a030219169083600160a060020a0316021790555060608201518160010160006101000a815481600160a060020a030219169083600160a060020a031602179055506080820151816002015560a08201518160030155905050600160086000856000191660001916815260200190815260200160002060006101000a81548160ff0219169083151502179055508b600160a060020a03167ffc11e611c2bf07aa7dd09a4fb47124294eca7a7993ccc89e3b041fc41f321577828d8d6040518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a260008411156135c9576040805185815290518c9133917f299c1112ccd1f86d83236b94ae590655a270301868085c8ac82b0d7df093a2fb9181900360200190a35b600085111561366c576135da613792565b600160a060020a03166108fc869081150290604051600060405180830381858888f1935050505015613655578a33613610613792565b600160a060020a03167f6096acf19cd2d3142f2b1ec1b1cede21aa8b5d1698264582b552923bc5fbf464886040518082815260200191505060405180910390a461366c565b600d54613668908663ffffffff61579d16565b600d555b60008911156136fe57604051600160a060020a038216908a156108fc02908b906000818181858888f19350505050156136e757604080518a815290518c913391600160a060020a038516917f6096acf19cd2d3142f2b1ec1b1cede21aa8b5d1698264582b552923bc5fbf464919081900360200190a46136fe565b600d546136fa908a63ffffffff61579d16565b600d555b505050505050505050505050565b613715336117e2565b151561372057600080fd5b613729816159cc565b50565b613735336117e2565b151561374057600080fd5b60025460ff161561375057600080fd5b6002805460ff191660011790556040805133815290517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589181900360200190a1565b600054600160a060020a031690565b600054600160a060020a0316331490565b600160a060020a039081166000908152600560205260409020600201541690565b6000806000806000806137eb3360008e8e8e8e615a14565b945061382c88888080601f01602080910402602001604051908101604052809392919081815260200183838082843750610c9494508b93506155b292505050565b93506006600085600160a060020a0316600160a060020a0316815260200190815260200160002060009054906101000a9004600160a060020a03169250600360008d8152602001908152602001600020600401549150600360008d81526020019081526020016000206005015490506138be896138b2838561579d90919063ffffffff16565b9063ffffffff61579d16565b8a101580156138dc575060008581526008602052604090205460ff16155b80156138ed57506138ed838d615731565b801561391457503360009081526004602090815260408083208f845290915290205460ff16155b9c9b505050505050505050505050565b6060600b80548060200260200160405190810160405280929190818152602001828054801561397257602002820191906000526020600020905b81548152602001906001019080831161395e575b5050505050905090565b600c5490565b600160a060020a03811660009081526005602090815260409182902060030180548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845260609392830182828015613a245780601f106139f957610100808354040283529160200191613a24565b820191906000526020600020905b815481529060010190602001808311613a0757829003601f168201915b50505050509050919050565b6000613a3a6137a1565b1515613a4557600080fd5b60025460ff1615613a5557600080fd5b613a5e84611405565b15613ad9576040805160e560020a62461bcd02815260206004820152603560248201527f616e2061747472696275746520747970652077697468207468652070726f766960448201527f64656420494420616c7265616479206578697374730000000000000000000000606482015290519081900360840190fd5b83600084846040516020018085815260200184151515157f010000000000000000000000000000000000000000000000000000000000000002815260010183838082843782019150509450505050506040516020818303038152906040526040518082805190602001908083835b60208310613b665780518252601f199092019160209182019101613b47565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008a81526007909252929020549194505015159150613bbc90505760008481526007602052604090208190555b6000848152600760205260409020548114613c6d576040805160e560020a62461bcd02815260206004820152604660248201527f61747472696275746520747970652070726f70657274696573206d757374206d60448201527f6174636820696e697469616c2070726f706572746965732061737369676e656460648201527f20746f2049440000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b60408051610120810182526001815260006020808301829052828401829052600b5460608401526080830182905260a0830182905260c0830182905260e08301919091528251601f8601829004820281018201909352848352909161010083019186908690819084018382808284375050509290935250505060008581526003602081815260409283902084518154868401519587015160ff199091169115159190911761ff00191661010095151586021762ff00001916620100009115159190910217815560608501516001820155608085015160028201805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0390921691909117905560a08501519281019290925560c0840151600483015560e084015160058301559183015180519192613daa92600685019290910190615c91565b5050600b80546001810182556000919091527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90185905550604080516020808252810184905285917fe35410b0f290a348deb893293b1f80701853a037d58ed492bd031637bac2393e9186918691908190810184848082843760405192018290039550909350505050a250505050565b613e4382611405565b1515613ebf576040805160e560020a62461bcd02815260206004820152603960248201527f756e61626c6520746f20736574206665652c206e6f206174747269627574652060448201527f747970652077697468207468652070726f766964656420494400000000000000606482015290519081900360840190fd5b60009182526003602052604090912060050155565b600080600080600080613eeb8d338e8e8e8e615a14565b9450613f2c88888080601f01602080910402602001604051908101604052809392919081815260200183838082843750610c9494508b93506155b292505050565b93506006600085600160a060020a0316600160a060020a0316815260200190815260200160002060009054906101000a9004600160a060020a03169250600360008d8152602001908152602001600020600401549150600360008d8152602001908152602001600020600501549050613fb2896138b2838561579d90919063ffffffff16565b8a10158015613fd0575060008581526008602052604090205460ff16155b8015613fe15750613fe1838d615731565b80156140115750600160a060020a038d1660009081526004602090815260408083208f845290915290205460ff16155b9d9c50505050505050505050505050565b600080600061402f6137a1565b151561403a57600080fd5b60025460ff161561404a57600080fd5b6140548585615731565b15156140f7576040805160e560020a62461bcd028152602060048201526044602482018190527f756e61626c6520746f2072656d6f76652076616c696461746f7220617070726f908201527f76616c2c2061747472696275746520697320616c726561647920756e6170707260648201527f6f76656400000000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b6000848152600360209081526040808320600160a060020a03891684526007018252808320805460ff19169055600990915290205461413d90600163ffffffff6157af16565b600160a060020a03861660009081526009602052604090208054919450908490811061416557fe5b6000918252602080832090910154600160a060020a038816808452600a8352604080852089865284528085205491855260099093529190922080549294509092508391839081106141b257fe5b6000918252602080832090910192909255600160a060020a03871681526009909152604090208054906141e9906000198301615c29565b50600160a060020a0385166000818152600a602090815260408083208684528252808320859055878352808320929092558151928352905186927f615568160a38f8c266cda2edc0fe6ba12327fb9b9ccf68d71a045b6186047c8e92908290030190a25050505050565b6000600c8281548110151561426457fe5b600091825260209091200154600160a060020a031692915050565b6060600c80548060200260200160405190810160405280929190818152602001828054801561397257602002820191906000526020600020905b8154600160a060020a031681526001909101906020018083116142b9575050505050905090565b600160a060020a03808316600090815260046020908152604080832085845282528083206001015490931680835260059091529181205490919060ff16801561434e57506000838152600360209081526040808320600160a060020a038516845260070190915290205460ff165b8015614368575060008381526003602052604090205460ff165b1561439b57600160a060020a038416600090815260046020908152604080832086845290915290206002015491506118d8565b600083815260036020526040902060020154600160a060020a03161561470f57600083815260036020819052604090912001546d777972652d7965732d746f6b656e141561450c5760008381526003602090815260408083206002015481517f70a08231000000000000000000000000000000000000000000000000000000008152600160a060020a038981166004830152925160019593909216936370a082319360248084019492938390030190829087803b15801561445b57600080fd5b505af115801561446f573d6000803e3d6000fd5b505050506040513d602081101561448557600080fd5b50511015614503576040805160e560020a62461bcd02815260206004820152603460248201527f6e6f2059657320546f6b656e20686173206265656e2069737375656420746f2060448201527f7468652070726f7669646564206163636f756e74000000000000000000000000606482015290519081900360840190fd5b600191506118d8565b6000838152600360208181526040808420600281015493015481517f4b5f297a000000000000000000000000000000000000000000000000000000008152600160a060020a038a8116600483015260248201929092529151931693634b5f297a93604480840194939192918390030190829087803b15801561458d57600080fd5b505af11580156145a1573d6000803e3d6000fd5b505050506040513d60208110156145b757600080fd5b5051151561465b576040805160e560020a62461bcd02815260206004820152604660248201527f617474726962757465206f66207468652070726f76696465642074797065206960448201527f73206e6f742061737369676e656420746f207468652070726f7669646564206160648201527f63636f756e740000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b6000838152600360208181526040808420600281015493015481517fcd6c8343000000000000000000000000000000000000000000000000000000008152600160a060020a038a811660048301526024820192909252915193169363cd6c834393604480840194939192918390030190829087803b1580156146dc57600080fd5b505af11580156146f0573d6000803e3d6000fd5b505050506040513d602081101561470657600080fd5b505191506118d8565b6040805160e560020a62461bcd02815260206004820152602481018290527f636f756c64206e6f742066696e6420616e206174747269627574652076616c7560448201527f65206174207468652070726f7669646564206163636f756e7420616e64204944606482015290519081900360840190fd5b600b5490565b600061479b878787878787615a14565b979650505050505050565b6147af82611405565b1515614851576040805160e560020a62461bcd02815260206004820152604360248201527f756e61626c6520746f20736574206d696e696d756d207374616b652c206e6f2060448201527f61747472696275746520747970652077697468207468652070726f766964656460648201527f2049440000000000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b60009182526003602052604090912060040155565b61486f83611405565b1515614911576040805160e560020a62461bcd02815260206004820152604660248201527f756e61626c6520746f20736574207365636f6e6461727920736f757263652c2060448201527f6e6f2061747472696275746520747970652077697468207468652070726f766960648201527f6465642049440000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b600092835260036020819052604090932060028101805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039490941693909317909255910155565b60006149616137a1565b151561496c57600080fd5b60025460ff161561497c57600080fd5b61498584611405565b15614a00576040805160e560020a62461bcd02815260206004820152603560248201527f616e2061747472696275746520747970652077697468207468652070726f766960448201527f64656420494420616c7265616479206578697374730000000000000000000000606482015290519081900360840190fd5b83600184846040516020018085815260200184151515157f010000000000000000000000000000000000000000000000000000000000000002815260010183838082843782019150509450505050506040516020818303038152906040526040518082805190602001908083835b60208310614a8d5780518252601f199092019160209182019101614a6e565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008a81526007909252929020549194505015159150614ae390505760008481526007602052604090208190555b6000848152600760205260409020548114614b94576040805160e560020a62461bcd02815260206004820152604660248201527f61747472696275746520747970652070726f70657274696573206d757374206d60448201527f6174636820696e697469616c2070726f706572746965732061737369676e656460648201527f20746f2049440000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b604080516101208101825260018082526020808301919091526000828401819052600b5460608401526080830181905260a0830181905260c0830181905260e08301528251601f8601829004820281018201909352848352909161010083019186908690819084018382808284375050509290935250505060008581526003602081815260409283902084518154868401519587015160ff199091169115159190911761ff00191661010095151586021762ff00001916620100009115159190910217815560608501516001820155608085015160028201805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0390921691909117905560a08501519281019290925560c0840151600483015560e084015160058301559183015180519192613daa92600685019290910190615c91565b6000614cdc8383615731565b9392505050565b614ceb6137a1565b1515614cf657600080fd5b61372981615ae4565b6002546000908190819081908190819060ff1615614d1c57600080fd5b600160a060020a03881660009081526004602090815260408083208a845290915290205460ff161515614dbf576040805160e560020a62461bcd02815260206004820152602760248201527f6f6e6c79206578697374696e672061747472696275746573206d61792062652060448201527f72656d6f76656400000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b600160a060020a0380891660009081526004602090815260408083208b845290915290206001015416955033861480614e105750614dfb613792565b600160a060020a031633600160a060020a0316145b1515614eb2576040805160e560020a62461bcd02815260206004820152604760248201527f6f6e6c79206a7572697364696374696f6e206f722069737375696e672076616c60448201527f696461746f7273206d6179207265766f6b65206172626974726172792061747460648201527f7269627574657300000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b600160a060020a03881660009081526004602090815260408083208a8452909152902060038101549054909550610100900460ff1615614ef457879350614f35565b600160a060020a0380891660009081526004602090815260408083208b8452909152902054620100009004169250821515614f3157859350614f35565b8293505b600160a060020a0380891660008181526004602090815260408083208c84528252808320805475ffffffffffffffffffffffffffffffffffffffffffff1916815560018101805473ffffffffffffffffffffffffffffffffffffffff1916905560028101849055600301929092558151938a16845283018a9052805191927faa5b822df0611950f79edb91a7f829d92df3d2ae66b54ee3b5b15ead069e1a67929081900390910190a2600085118015614fef575030318511155b156151ac576193449150615009823a63ffffffff615b6116565b90508085111561513a57600160a060020a0384166108fc615030878463ffffffff6157af16565b6040518115909202916000818181858888f193505050501561509e5786600160a060020a0385167fcb777cb6ab680dc1db2889b92613a0640bc47be07dc40a8f640dfd7e7882790d615088888563ffffffff6157af16565b60408051918252519081900360200190a36150c4565b6150c06150b1868363ffffffff6157af16565b600d549063ffffffff61579d16565b600d555b6040805182815290518891600160a060020a0387169132917f016befcde2d759172ba1344b7a10f58a14adfcea6cd7cb248f891a1480a3cf4d919081900360200190a4604051329082156108fc029083906000818181858888f19350505050158015615134573d6000803e3d6000fd5b506151ac565b6040805186815290518891600160a060020a0387169132917f016befcde2d759172ba1344b7a10f58a14adfcea6cd7cb248f891a1480a3cf4d919081900360200190a4604051329086156108fc029087906000818181858888f193505050501580156151aa573d6000803e3d6000fd5b505b5050505050505050565b600160a060020a031660009081526005602052604090205460ff1690565b6000818152600360205260408120548190610100900460ff161561528e576040805160e560020a62461bcd02815260206004820152604860248201527f6f6e6c79206a7572697364696374696f6e206f722069737375696e672076616c60448201527f696461746f72206d61792072656d6f766520612072657374726963746564206160648201527f7474726962757465000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b600160a060020a038416600090815260046020908152604080832086845290915290205460ff161515615331576040805160e560020a62461bcd02815260206004820152602760248201527f6f6e6c79206578697374696e672061747472696275746573206d61792062652060448201527f72656d6f76656400000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b600160a060020a0384811660009081526004602090815260408083208784529091529020546201000090041633146153ff576040805160e560020a62461bcd02815260206004820152604760248201527f6f6e6c7920616e2061737369676e696e67206f70657261746f72206d6179207260448201527f656d6f766520617474726962757465206f6e20626568616c66206f6620616e2060648201527f6164647265737300000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b5050600160a060020a0382811660008181526004602090815260408083208684528252808320600181018054600383018054845475ffffffffffffffffffffffffffffffffffffffffffff1916855573ffffffffffffffffffffffffffffffffffffffff1983169093556002909301869055949091558151939095168084529183018690528051919493927faa5b822df0611950f79edb91a7f829d92df3d2ae66b54ee3b5b15ead069e1a67929081900390910190a26000811180156154c6575030318111155b1561553f57604051339082156108fc029083906000818181858888f193505050501561552857604080518281529051849133917fcb777cb6ab680dc1db2889b92613a0640bc47be07dc40a8f640dfd7e7882790d9181900360200190a361553f565b600d5461553b908263ffffffff61579d16565b600d555b50505050565b60008181526003602090815260409182902060060180548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845260609392830182828015613a245780601f106139f957610100808354040283529160200191613a24565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c80830185905283518084039091018152605c909201928390528151600093918291908401908083835b6020831061562a5780518252601f19909201916020918201910161560b565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912095945050505050565b600080600080845160411415156156765760009350615728565b50505060208201516040830151606084015160001a601b60ff8216101561569b57601b015b8060ff16601b141580156156b357508060ff16601c14155b156156c15760009350615728565b60408051600080825260208083018085528a905260ff8516838501526060830187905260808301869052925160019360a0808501949193601f19840193928390039091019190865af115801561571b573d6000803e3d6000fd5b5050506020604051035193505b50505092915050565b600160a060020a03821660009081526005602052604081205460ff16801561577e57506000828152600360209081526040808320600160a060020a038716845260070190915290205460ff165b8015614cdc57505060009081526003602052604090205460ff16919050565b600082820183811015614cdc57600080fd5b600080838311156157bf57600080fd5b5050900390565b6000600160a060020a03821615156157dd57600080fd5b50600160a060020a03166000908152602091909152604090205460ff1690565b6000806060836d777972652d7965732d746f6b656e14156158c357600186600160a060020a03166370a08231876040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561588e57600080fd5b505af11580156158a2573d6000803e3d6000fd5b505050506040513d60208110156158b857600080fd5b50511015925061597b565b614e205a116158d2575a6158d6565b614e205b60408051600160a060020a038816602482015260448082018890528251808303909101815260649091018252602081810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f4b5f297a0000000000000000000000000000000000000000000000000000000017815282519351600081529496509194509092908183858c89fa806001811461597057615975565b825197505b50505050505b50509392505050565b61599560018263ffffffff615b8f16565b604051600160a060020a038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b6159dd60018263ffffffff615bdb16565b604051600160a060020a038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b604080516c01000000000000000000000000308102602080840191909152600160a060020a03808b168302603485015289169091026048830152605c8201859052607c8201849052609c820187905260bc8083018790528351808403909101815260dc909201928390528151600093918291908401908083835b60208310615aad5780518252601f199092019160209182019101615a8e565b5181516020939093036101000a600019018019909116921691909117905260405192018290039091209a9950505050505050505050565b600160a060020a0381161515615af957600080fd5b60008054604051600160a060020a03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600080831515615b7457600091506118d8565b50828202828482811515615b8457fe5b0414614cdc57600080fd5b600160a060020a0381161515615ba457600080fd5b615bae82826157c6565b1515615bb957600080fd5b600160a060020a0316600090815260209190915260409020805460ff19169055565b600160a060020a0381161515615bf057600080fd5b615bfa82826157c6565b15615c0457600080fd5b600160a060020a0316600090815260209190915260409020805460ff19166001179055565b815481835581811115611dce57600083815260209020611dce918101908301615d0f565b50805460018160011615610100020316600290046000825580601f10615c735750613729565b601f0160209004906000526020600020908101906137299190615d0f565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615cd257805160ff1916838001178555615cff565b82800160010185558215615cff579182015b82811115615cff578251825591602001919060010190615ce4565b50615d0b929150615d0f565b5090565b61139e91905b80821115615d0b5760008155600101615d155600a165627a7a72305820a8ea3603d37dbe60eef96adfc91ed303a528b48f25dd80d7b821013e26cc5b1500290000000000000000000000000734d56da60852a03e2aafae8a36ffd8c12b32f1

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

0000000000000000000000000734d56da60852a03e2aafae8a36ffd8c12b32f1

-----Decoded View---------------
Arg [0] : owner (address): 0x0734d56da60852a03e2aafae8a36ffd8c12b32f1

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000734d56da60852a03e2aafae8a36ffd8c12b32f1


Deployed ByteCode Sourcemap

33489:66365:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88131:431;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;88131:431:0;-1:-1:-1;;88131:431:0;;;;;;;;;;;;;;;;;;;;;;;86268:254;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;86268:254:0;;;;;;;;;;;;;;;;;;;;;77209:658;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;77209:658:0;;;;;;;;;;;;;;;;;;41277:395;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;41277:395:0;;;;;;;;;85084:307;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;85084:307:0;-1:-1:-1;;;;;85084:307:0;;;;;;;;;;;-1:-1:-1;;;;;85084:307:0;;;;;;;;;;;;;;;;;;;;;67672:1866;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;67672:1866:0;;;;;54966:850;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;54966:850:0;-1:-1:-1;;;;;54966:850:0;;;;;94777:147;;8:9:-1;5:2;;;30:1;27;20:12;5:2;94777:147:0;;;;9047:108;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9047:108:0;;;;93834:136;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;93834:136:0;;;;;48288:2163;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;48288:2163:0;-1:-1:-1;;;;;48288:2163:0;;;;;7460:102;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;7460:102:0;-1:-1:-1;;;;;7460:102:0;;;;;78396:746;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;78396:746:0;-1:-1:-1;;;;;78396:746:0;;;;;;;56528:1933;;-1:-1:-1;;;;;56528:1933:0;;;;;;;;;95906:328;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;95906:328:0;-1:-1:-1;;;;;95906:328:0;;;;;;;8369:71;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8369:71:0;;;;96632:249;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;96632:249:0;-1:-1:-1;;;;;96632:249:0;;;;;;;;;;;;63263:4208;;;;;;;;;;;;;;;;;;;;;;;46581:1237;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;46581:1237:0;;;;-1:-1:-1;;;;;46581:1237:0;;;;;;;;;;;;;82973:729;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;82973:729:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;82973:729:0;-1:-1:-1;;;;;82973:729:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;82973:729:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7660:71;;8:9:-1;5:2;;;30:1;27;20:12;5:2;7660:71:0;;;;10469:130;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10469:130:0;;;;95186:183;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;95186:183:0;-1:-1:-1;;;;;95186:183:0;;;;;50738:1186;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;50738:1186:0;-1:-1:-1;;;;;50738:1186:0;;;;;;;45213:990;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;45213:990:0;;;;;70284:4520;;;;;-1:-1:-1;;;;;70284:4520:0;;;;;;;;;;;;;;;;;;;;;;7568:86;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;7568:86:0;-1:-1:-1;;;;;7568:86:0;;;;;8854:106;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8854:106:0;;;;9810:72;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9810:72:0;;;;;;;;-1:-1:-1;;;;;9810:72:0;;;;;;;;;;;;;;10112:85;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10112:85:0;;;;84299:167;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;84299:167:0;-1:-1:-1;;;;;84299:167:0;;;;;90227:1270;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;90227:1270:0;;;;;;;;;;;;;;;;;;;;;;;;;86697:98;;8:9:-1;5:2;;;30:1;27;20:12;5:2;86697:98:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;86697:98:0;;;;;;;;;;;;;;;;;86937:104;;8:9:-1;5:2;;;30:1;27;20:12;5:2;86937:104:0;;;;83914:169;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;83914:169:0;-1:-1:-1;;;;;83914:169:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;83914:169:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36701:1806;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;36701:1806:0;;;;;;;;;;;;;;;;44534:373;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;44534:373:0;;;;;;;92264:1289;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;92264:1289:0;;;;-1:-1:-1;;;;;92264:1289:0;;;;;;;;;;;;;;;;;;;;;;;;;52540:1573;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;52540:1573:0;-1:-1:-1;;;;;52540:1573:0;;;;;;;87237:124;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;87237:124:0;;;;;87536:97;;8:9:-1;5:2;;;30:1;27;20:12;5:2;87536:97:0;;;;79745:1987;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;79745:1987:0;-1:-1:-1;;;;;79745:1987:0;;;;;;;85676:103;;8:9:-1;5:2;;;30:1;27;20:12;5:2;85676:103:0;;;;89158:407;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;89158:407:0;-1:-1:-1;;;;;89158:407:0;;;;;;;;;;;;;;;;;;43635:434;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;43635:434:0;;;;;;;42467:540;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;42467:540:0;;;-1:-1:-1;;;;;42467:540:0;;;;;;;39099:1814;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;39099:1814:0;;;;;;;;;;;;;;;;82123:178;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;82123:178:0;-1:-1:-1;;;;;82123:178:0;;;;;;;10766:103;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;10766:103:0;-1:-1:-1;;;;;10766:103:0;;;;;59012:3676;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;59012:3676:0;-1:-1:-1;;;;;59012:3676:0;;;;;;;94254:112;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;94254:112:0;-1:-1:-1;;;;;94254:112:0;;;;;75184:1597;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;75184:1597:0;-1:-1:-1;;;;;75184:1597:0;;;;;;;82533:189;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;82533:189:0;;;;;88131:431;88201:4;-1:-1:-1;;88230:46:0;;88245:31;88230:46;;:261;;-1:-1:-1;;;88297:194:0;;88323:159;88297:194;88230:261;88214:314;88131:431;-1:-1:-1;;88131:431:0:o;86268:254::-;86374:13;:20;86334:7;;86366:28;;86350:130;;;;;-1:-1:-1;;;;;86350:130:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86496:13;:20;;86510:5;;86496:20;;;;;;;;;;;;;;86489:27;;86268:254;;;:::o;77209:658::-;77382:17;77402:12;:90;77423:48;77461:9;;77423:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;77423:29:0;;-1:-1:-1;77423:4:0;;-1:-1:-1;77423:27:0;;-1:-1:-1;;;77423:29:0:i;:::-;:37;:48;:37;:48;:::i;:::-;-1:-1:-1;;;;;77402:90:0;;;;;;;;;;;;;;-1:-1:-1;77402:90:0;;;;-1:-1:-1;77601:10:0;:23;;;:48;;;77642:7;:5;:7::i;:::-;-1:-1:-1;;;;;77628:21:0;:10;-1:-1:-1;;;;;77628:21:0;;77601:48;77585:154;;;;;;;-1:-1:-1;;;;;77585:154:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;77817:37:0;;;;:31;:37;;;;;:44;;-1:-1:-1;;77817:44:0;77857:4;77817:44;;;77209:658::o;41277:395::-;41454:19;41470:2;41454:15;:19::i;:::-;41438:123;;;;;;;-1:-1:-1;;;;;41438:123:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;41619:19;;;;:15;:19;;;;;;:47;;;;;;;-1:-1:-1;;41619:47:0;;;;;;;;;41277:395::o;85084:307::-;-1:-1:-1;;;;;85272:26:0;;;85201:17;85272:26;;;:17;:26;;;;;;;;:43;;;;;;;;:53;;;85201:17;;;;85272:53;;85348:36;85272:53;85299:15;85348:11;:36::i;:::-;85332:53;;;;85084:307;;;;;;:::o;67672:1866::-;68173:17;67833:32;;;:15;:32;;;;;:43;68173:17;;;;;;67833:43;;;;;67832:44;67816:150;;;;;-1:-1:-1;;;;;67816:150:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68009:10;67991:29;;;;:17;:29;;;;;;;;:46;;;;;;;;:53;;;67975:126;;;;;;;-1:-1:-1;;;;;67975:126:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68211:10;68193:29;;;;:17;:29;;;;;;;;:46;;;;;;;;:56;;;;68328:52;;;;68490:60;;-1:-1:-1;;;;;68193:56:0;;;;-1:-1:-1;68328:52:0;;-1:-1:-1;68193:56:0;68490:60;;;;68486:339;;;68577:10;68561:26;;68486:339;;;-1:-1:-1;68647:10:0;68629:29;;;;:17;:29;;;;;;;;:46;;;;;;;;:55;;;;-1:-1:-1;;;;;68629:55:0;68697:22;;68693:125;;;68748:9;68732:25;;68693:125;;;68800:8;68784:24;;68693:125;68913:10;68895:29;;;;:17;:29;;;;;;;;:46;;;;;;;;68888:53;;-1:-1:-1;;68888:53:0;;;;;;;;-1:-1:-1;;68888:53:0;;;;;;;;;;;;;;;68996:56;;-1:-1:-1;;;;;68996:56:0;;;;;;;;;;;;;;;;;;;;;;;69144:1;69136:5;:9;:43;;;;-1:-1:-1;69157:4:0;69149:21;:30;-1:-1:-1;69149:30:0;69136:43;69132:401;;;69346:25;;-1:-1:-1;;;;;69346:18:0;;;:25;;;;;69365:5;;69346:25;;;;69365:5;69346:18;:25;;;;;;;69342:184;;;69389:52;;;;;;;;69418:15;;-1:-1:-1;;;;;69389:52:0;;;;;;;;;;;;69342:184;;;69488:17;;:28;;69510:5;69488:28;:21;:28;:::i;:::-;69468:17;:48;69342:184;67672:1866;;;;;:::o;54966:850::-;55053:23;55065:10;55053:11;:23::i;:::-;55037:100;;;;;;;-1:-1:-1;;;;;55037:100:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;55221:27:0;;;55260:1;55221:27;;;:12;:27;;;;;;;:41;55205:133;;;;;-1:-1:-1;;;;;55205:133:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55450:10;55425:48;55438:23;;;:11;:23;;;;;;;;:34;;;;-1:-1:-1;;;;;55438:34:0;;;55425:48;;:12;:48;;;;;55418:55;;-1:-1:-1;;55418:55:0;;;;;;55527:50;;;;;;;;;;;;;55654:27;;;;;;;:40;;;;;;;;;55756:54;;;;;;;;;;;;;;;;54966:850;:::o;94777:147::-;94901:17;;94777:147;;:::o;9047:108::-;7419:20;7428:10;7419:8;:20::i;:::-;7411:29;;;;;;;;8748:7;;;;8740:16;;;;;;;;9102:7;:15;;-1:-1:-1;;9102:15:0;;;9129:20;;;9138:10;9129:20;;;;;;;;;;;;;9047:108::o;93834:136::-;93905:4;93925:32;;;:15;:32;;;;;:39;;;;93834:136::o;48288:2163::-;48794:17;48923:22;49692:19;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;8587:7;;;;8586:8;8578:17;;;;;;48450:22;48462:9;48450:11;:22::i;:::-;48434:118;;;;;;;-1:-1:-1;;;;;48434:118:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;48641:30:0;;48681:1;48641:30;;;:19;:30;;;;;:37;:41;:62;;;;;48698:5;48686:9;:17;48641:62;48634:768;;;-1:-1:-1;;;;;48814:30:0;;;;;;:19;:30;;;;;:37;:44;;48856:1;48814:44;:41;:44;:::i;:::-;-1:-1:-1;;;;;48948:30:0;;;;;;:19;:30;;;;;:41;;48794:64;;-1:-1:-1;48948:30:0;48794:64;;48948:41;;;;;;;;;;;;;;;;;;49086:31;;;:15;:31;;;;;;-1:-1:-1;;;;;49086:61:0;;;;;:50;;;;:61;;;;;49079:68;;-1:-1:-1;;49079:68:0;;;49222:24;:35;;;;;:51;;;;;;;;49215:58;;;49355:30;;:19;:30;;;;;:39;;48948:41;;-1:-1:-1;49355:39:0;;-1:-1:-1;;49355:39:0;;;:::i;:::-;;48634:768;;;-1:-1:-1;;;;;49487:30:0;;;;;;:19;:30;;;;;:37;:42;49471:147;;;;;-1:-1:-1;;;;;49471:147:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49714:18;49733:25;;:32;;49763:1;49733:32;:29;:32;:::i;:::-;49714:52;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;49873:22:0;;;;;:11;:22;;;;;;;49714:52;49873:28;;49854:18;:48;;49714:52;;;;;-1:-1:-1;49714:52:0;;49854:18;:48;;;;;;;;;;;;;;;;;;:62;;-1:-1:-1;;49854:62:0;-1:-1:-1;;;;;49854:62:0;;;;;;50020:22;;;;;:11;:22;;;;;;-1:-1:-1;50020:28:0;;;;49987:24;;;;;;;:30;:61;50139:18;:27;;;;;-1:-1:-1;;50139:27:0;;;:::i;:::-;-1:-1:-1;;;;;;50255:22:0;;;50242:47;50255:22;;;:11;:22;;;;;;;;:33;;;;;;;;50242:47;;:12;:47;;;;;50235:54;;-1:-1:-1;;50235:54:0;;;;;;50341:22;;;;;;50334:29;;-1:-1:-1;;50334:29:0;;;50255:33;50334:29;;;;;;;;;;;;;50255:22;50334:29;;;;50242:47;50334:29;:::i;:::-;-1:-1:-1;;50418:27:0;;-1:-1:-1;;;;;50418:27:0;;;;;;;;48288:2163;;;;:::o;7460:102::-;7516:4;7536:20;:7;7548;7536:20;:11;:20;:::i;78396:746::-;-1:-1:-1;;;;;78532:26:0;;;78499:4;78532:26;;;:17;:26;;;;;;;;:43;;;;;;;;:53;;;;;;78619:22;;;:11;:22;;;;;;:29;78499:4;;78532:53;78619:29;;:132;;;;-1:-1:-1;78689:32:0;;;;:15;:32;;;;;;;;-1:-1:-1;;;;;78689:62:0;;;;:51;;:62;;;;;;;;78619:132;:184;;;;-1:-1:-1;78764:32:0;;;;:15;:32;;;;;:39;;;78619:184;78608:521;;;-1:-1:-1;78922:1:0;78862:32;;;:15;:32;;;;;:48;;;-1:-1:-1;;;;;78862:48:0;:62;;;;:258;;-1:-1:-1;78971:32:0;;;;:15;:32;;;;;;;;:48;;;;79052:57;;;78937:183;;-1:-1:-1;;;;;78971:48:0;;79032:7;;78937:21;:183::i;:::-;78592:544;;78396:746;;;;;;:::o;56528:1933::-;8587:7;;57054:20;;;;;;8587:7;;8586:8;8578:17;;;;;;56683:40;56695:10;56707:15;56683:11;:40::i;:::-;56667:133;;;;;;;-1:-1:-1;;;;;56667:133:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;56826:26:0;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:50;;;56825:51;56809:156;;;;;-1:-1:-1;;;;;56809:156:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57077:32;;;;:15;:32;;;;;:45;;;;57155:48;;;;;57077:45;;-1:-1:-1;57155:48:0;-1:-1:-1;57226:30:0;:9;57155:48;57226:30;:13;:30;:::i;:::-;57210:46;-1:-1:-1;57281:21:0;;;;57265:116;;;;;-1:-1:-1;;;;;57265:116:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57510:175;;;;;;;;;57543:4;57510:175;;;;;;57571:5;57510:175;;;;;;57603:1;-1:-1:-1;;;;;57510:175:0;;;;;57625:10;-1:-1:-1;;;;;57510:175:0;;;;;57651:5;57510:175;;;;57672:5;57510:175;;;57464:17;:26;57482:7;-1:-1:-1;;;;;57464:26:0;-1:-1:-1;;;;;57464:26:0;;;;;;;;;;;;:43;57491:15;57464:43;;;;;;;;;;;:221;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;57464:221:0;;;;;-1:-1:-1;;;;;57464:221:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;57464:221:0;;;;;-1:-1:-1;;;;;57464:221:0;;;;;;;;;;;;;;;;;;;;;;;;;57768:7;-1:-1:-1;;;;;57741:59:0;;57756:10;57777:15;57794:5;57741:59;;;;-1:-1:-1;;;;;57741:59:0;-1:-1:-1;;;;;57741:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;57891:1;57883:5;:9;57879:87;;;57908:50;;;;;;;;57935:15;;57923:10;;57908:50;;;;;;;;;57879:87;58072:1;58054:15;:19;58050:406;;;58245:7;:5;:7::i;:::-;-1:-1:-1;;;;;58245:12:0;:29;58258:15;58245:29;;;;;;;;;;;;;;;;;;;;;;;58241:208;;;58321:15;58309:10;58300:7;:5;:7::i;:::-;-1:-1:-1;;;;;58292:62:0;;58338:15;58292:62;;;;;;;;;;;;;;;;;;58241:208;;;58401:17;;:38;;58423:15;58401:38;:21;:38;:::i;:::-;58381:17;:58;58241:208;56528:1933;;;;;;:::o;95906:328::-;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;96082:17;;:28;;96104:5;96082:28;:21;:28;:::i;:::-;96062:17;:48;96205:23;;-1:-1:-1;;;;;96205:16:0;;;:23;;;;;96222:5;;96205:23;;;;96222:5;96205:16;:23;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;96205:23:0;95906:328;;:::o;8369:71::-;8427:7;;;;8369:71;:::o;96632:249::-;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;96843:5;-1:-1:-1;;;;;96836:22:0;;96859:7;96868:5;96836:38;;;;;;;;;;;;;-1:-1:-1;;;;;96836:38:0;-1:-1:-1;;;;;96836:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;96836:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;96836:38:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;96836:38:0;96828:47;;;;;;;63263:4208;64329:10;64542:20;64311:29;;;:17;:29;;;;;;;;:46;;;;;;;;:53;64542:20;;;;;;;;;;64311:53;;64310:54;64294:159;;;;;-1:-1:-1;;;;;64294:159:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;64565:32;;;;:15;:32;;;;;:45;;;;64643:48;;;;;64565:45;;-1:-1:-1;64643:48:0;-1:-1:-1;64714:48:0;64643;64714:27;:9;64728:12;64714:27;:13;:27;:::i;:::-;:31;:48;:31;:48;:::i;:::-;64698:64;-1:-1:-1;64787:21:0;;;;64771:116;;;;;-1:-1:-1;;;;;64771:116:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65011:176;;;;65046:4;65011:176;;;;;;;;;;65062:10;65011:176;;;;;;;;65091:1;65011:176;;;;65104:9;65011:176;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;65011:176:0;;;;;;;;64993:201;;65011:176;;;;;64993:201;;;;65011:176;64993:201;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;64993:201:0;;;;;;;;;;;;;-1:-1:-1;65220:37:0;;;:31;:37;;;;;;;64993:201;;-1:-1:-1;;65220:37:0;;65219:38;;-1:-1:-1;65203:132:0;;-1:-1:-1;65203:132:0;;;;-1:-1:-1;;;;;65203:132:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65419:48;65457:9;;65419:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;65419:29:0;;-1:-1:-1;65419:4:0;;-1:-1:-1;65419:27:0;;-1:-1:-1;;;65419:29:0:i;:48::-;-1:-1:-1;;;;;65558:24:0;;;;;;;:12;:24;;;;;;65398:69;;-1:-1:-1;65558:24:0;;-1:-1:-1;65607:39:0;65558:24;65630:15;65607:11;:39::i;:::-;65591:144;;;;;;;-1:-1:-1;;;;;65591:144:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65867:211;;;;;;;;;65900:4;65867:211;;;;;;65928:4;65867:211;;;;;;65959:1;-1:-1:-1;;;;;65867:211:0;;;;;65981:9;-1:-1:-1;;;;;65867:211:0;;;;;66006:5;65867:211;;;;66027:5;65867:211;;;65818:17;:29;65836:10;-1:-1:-1;;;;;65818:29:0;-1:-1:-1;;;;;65818:29:0;;;;;;;;;;;;:46;65848:15;65818:46;;;;;;;;;;;:260;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65818:260:0;;;;;-1:-1:-1;;;;;65818:260:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65818:260:0;;;;;-1:-1:-1;;;;;65818:260:0;;;;;;;;;;;;;;;;;;;;;;;;;66208:4;66168:31;:37;66200:4;66168:37;;;;;;;;;;;;;;;;;;:44;;;;;;;;;;;;;;;;;;66294:10;-1:-1:-1;;;;;66268:61:0;;66283:9;66306:15;66323:5;66268:61;;;;-1:-1:-1;;;;;66268:61:0;-1:-1:-1;;;;;66268:61:0;;;;;;;;;;;;;;;;;;;;;;;;;;;66420:1;66412:5;:9;66408:87;;;66437:50;;;;;;;;66464:15;;66452:10;;66437:50;;;;;;;;;66408:87;66601:1;66583:15;:19;66579:406;;;66774:7;:5;:7::i;:::-;-1:-1:-1;;;;;66774:12:0;:29;66787:15;66774:29;;;;;;;;;;;;;;;;;;;;;;;66770:208;;;66850:15;66838:10;66829:7;:5;:7::i;:::-;-1:-1:-1;;;;;66821:62:0;;66867:15;66821:62;;;;;;;;;;;;;;;;;;66770:208;;;66930:17;;:38;;66952:15;66930:38;:21;:38;:::i;:::-;66910:17;:58;66770:208;67087:1;67072:12;:16;67068:398;;;67260:28;;-1:-1:-1;;;;;67260:14:0;;;:28;;;;;67275:12;;67260:28;;;;67275:12;67260:14;:28;;;;;;;67256:203;;;67306:61;;;;;;;;67337:15;;67325:10;;-1:-1:-1;;;;;67306:61:0;;;;;;;;;;;;;67256:203;;;67414:17;;:35;;67436:12;67414:35;:21;:35;:::i;:::-;67394:17;:55;67256:203;63263:4208;;;;;;;;;;;:::o;46581:1237::-;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;8587:7;;;;8586:8;8578:17;;;;;;-1:-1:-1;;;;;46769:23:0;;;;46761:63;;;;;-1:-1:-1;;;;;46761:63:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;46909:22;46921:9;46909:11;:22::i;:::-;46908:23;46892:109;;;;;-1:-1:-1;;;;;46892:109:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;47084:23:0;;;47119:1;47084:23;;;:12;:23;;;;;;;:37;47068:129;;;;;-1:-1:-1;;;;;47068:129:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47277:195;;;;;;;;;47304:4;47277:195;;;;;;47324:18;:25;;;;47277:195;;;;47370:9;-1:-1:-1;;;;;47277:195:0;;;;;47453:11;;47277:195;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;47277:195:0;;;;-1:-1:-1;;;;;;;;47252:22:0;;;;;;;:11;:22;;;;;;;;;:220;;;;-1:-1:-1;;47252:220:0;;;;;;;;;;;-1:-1:-1;47252:220:0;;;;;;;;;;;;-1:-1:-1;;47252:220:0;;;;;;;;;;;;;;;:22;;:220;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;;;;47563:23:0;;;;;;:12;:23;;;;;;;;:35;;-1:-1:-1;;47563:35:0;;;;;;;;47676:18;27:10:-1;;47563:35:0;23:18:-1;;45:23;;47676:34:0;;;;;;;;;;;;;;;;47774:38;;;;;;;;;;;;;47800:11;;;;47774:38;;;;47800:11;;;;47774:38;;;;;;;;;;-1:-1:-1;47774:38:0;;-1:-1:-1;;;;47774:38:0;46581:1237;;;:::o;82973:729::-;83099:17;83305:32;;;:15;:32;;;;;;;;83358:43;;83410:45;83464:48;;;;83521:57;;;;83587:45;;;;83641:48;;;;83305:44;;;;83289:407;;;;83358:43;;83289:407;;;;;-1:-1:-1;;83289:407:0;;;;;;;;;;;;;;;;;;;;;;;;;;83074:18;;83099:17;;;;;;;;;;;83305:44;;83358:43;;;;;;;;83410:45;;;;;;-1:-1:-1;;;;;83464:48:0;;;;83521:57;83587:45;;83641:48;;83289:407;;83305:44;;83289:407;;;83305:44;83289:407;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;82973:729;;;;;;;;;:::o;7660:71::-;7700:25;7714:10;7700:13;:25::i;:::-;7660:71::o;10469:130::-;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;10564:1;10548:6;;10527:40;;-1:-1:-1;;;;;10548:6:0;;;;10527:40;;10564:1;;10527:40;10591:1;10574:19;;-1:-1:-1;;10574:19:0;;;10469:130::o;95186:183::-;95325:38;;;;;;95357:4;95325:38;;;;;;95249:7;;-1:-1:-1;;;;;95325:23:0;;;;;:38;;;;;;;;;;;;;;;95249:7;95325:23;:38;;;5:2:-1;;;;30:1;27;20:12;5:2;95325:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;95325:38:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;95325:38:0;;95186:183;-1:-1:-1;;95186:183:0:o;50738:1186::-;51536:13;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;8587:7;;;;8586:8;8578:17;;;;;;50960:22;50972:9;50960:11;:22::i;:::-;:58;;;;;50986:32;51002:15;50986;:32::i;:::-;50944:154;;;;;;;-1:-1:-1;;;;;50944:154:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51181:32;;;;:15;:32;;;;;;;;-1:-1:-1;;;;;51181:62:0;;;;:51;;:62;;;;;;;;51180:63;51164:152;;;;;-1:-1:-1;;;;;51164:152:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;51384:32:0;;;;:15;:32;;;;;;;;-1:-1:-1;;;;;51384:62:0;;;;;:51;;;;:62;;;;;:69;;-1:-1:-1;;51384:69:0;51449:4;51384:69;;;;;;51552:19;:30;;;;;;:37;;51596:24;:35;;;;;:52;;;;;;;;:60;;;51734:30;;;23:18:-1;;;45:23;;51734:52:0;;;;;;;;;;;;51868:50;;;;;;;51400:15;;51868:50;;;;;;;;50738:1186;;;:::o;45213:990::-;45548:23;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;8587:7;;;;8586:8;8578:17;;;;;;45386:19;45402:2;45386:15;:19::i;:::-;45370:109;;;;;;;-1:-1:-1;;;;;45370:109:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45574:13;45588:20;;:27;;45613:1;45588:27;:24;:27;:::i;:::-;45574:42;;;;;;;;;;;;;;;;45548:68;;45750:15;45707:13;45721:15;:19;45737:2;45721:19;;;;;;;;;;;:25;;;45707:40;;;;;;;;;;;;;;;;;;;;;:58;;;;45877:19;;;:15;:19;;;;;;;:25;;;;;45836:32;;;;;;;:38;;;:66;45996:13;:22;;;;;-1:-1:-1;;45996:22:0;;;:::i;:::-;-1:-1:-1;46094:19:0;;;;:15;:19;;;;;;;46087:26;;-1:-1:-1;;46087:26:0;;;;;;;;;;;;;;-1:-1:-1;;46087:26:0;;;;;;;;;;;;;;;;;;;;;46094:19;46087:26;;;;46094:19;46087:26;:::i;:::-;-1:-1:-1;;46173:24:0;;46194:2;;46173:24;;;;;45213:990;;:::o;70284:4520::-;71822:20;71437:32;;;:15;:32;;;;;:45;71822:20;;;;;;;;;;71437:45;;;;;71436:46;71420:148;;;;;-1:-1:-1;;;;;71420:148:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;71594:26:0;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:50;;;71593:51;71577:156;;;;;-1:-1:-1;;;;;71577:156:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71845:32;;;;:15;:32;;;;;:45;;;;71923:48;;;;;71845:45;;-1:-1:-1;71923:48:0;-1:-1:-1;71994:48:0;71923;71994:27;:9;72008:12;71994:27;:13;:27;:::i;:48::-;71978:64;-1:-1:-1;72067:21:0;;;;72051:116;;;;;-1:-1:-1;;;;;72051:116:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;72326:4;72342:7;72360:10;72381:9;72401:12;72424:15;72450:5;72291:173;;;;;;-1:-1:-1;;;;;72291:173:0;-1:-1:-1;;;;;72291:173:0;;;;;;;;-1:-1:-1;;;;;72291:173:0;-1:-1:-1;;;;;72291:173:0;;;;;;;;-1:-1:-1;;;;;72291:173:0;-1:-1:-1;;;;;72291:173:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;72291:173:0;;;72273:198;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;72273:198:0;;;;;;;;;;;;;-1:-1:-1;72497:37:0;;;:31;:37;;;;;;;72273:198;;-1:-1:-1;;72497:37:0;;72496:38;;-1:-1:-1;72480:132:0;;-1:-1:-1;72480:132:0;;;;-1:-1:-1;;;;;72480:132:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;72696:48;72734:9;;72696:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;72696:29:0;;-1:-1:-1;72696:4:0;;-1:-1:-1;72696:27:0;;-1:-1:-1;;;72696:29:0:i;:48::-;-1:-1:-1;;;;;72835:24:0;;;;;;;:12;:24;;;;;;72675:69;;-1:-1:-1;72835:24:0;;-1:-1:-1;72884:39:0;72835:24;72907:15;72884:11;:39::i;:::-;72868:142;;;;;;;-1:-1:-1;;;;;72868:142:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73139:212;;;;;;;;;73172:4;73139:212;;;;;;73200:5;73139:212;;;;;;73224:10;-1:-1:-1;;;;;73139:212:0;;;;;73254:9;-1:-1:-1;;;;;73139:212:0;;;;;73279:5;73139:212;;;;73300:5;73139:212;;;73093:17;:26;73111:7;-1:-1:-1;;;;;73093:26:0;-1:-1:-1;;;;;73093:26:0;;;;;;;;;;;;:43;73120:15;73093:43;;;;;;;;;;;:258;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;73093:258:0;;;;;-1:-1:-1;;;;;73093:258:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;73093:258:0;;;;;-1:-1:-1;;;;;73093:258:0;;;;;;;;;;;;;;;;;;;;;;;;;73481:4;73441:31;:37;73473:4;73441:37;;;;;;;;;;;;;;;;;;:44;;;;;;;;;;;;;;;;;;73567:7;-1:-1:-1;;;;;73541:58:0;;73556:9;73576:15;73593:5;73541:58;;;;-1:-1:-1;;;;;73541:58:0;-1:-1:-1;;;;;73541:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;73753:1;73745:5;:9;73741:87;;;73770:50;;;;;;;;73797:15;;73785:10;;73770:50;;;;;;;;;73741:87;73934:1;73916:15;:19;73912:406;;;74107:7;:5;:7::i;:::-;-1:-1:-1;;;;;74107:12:0;:29;74120:15;74107:29;;;;;;;;;;;;;;;;;;;;;;;74103:208;;;74183:15;74171:10;74162:7;:5;:7::i;:::-;-1:-1:-1;;;;;74154:62:0;;74200:15;74154:62;;;;;;;;;;;;;;;;;;74103:208;;;74263:17;;:38;;74285:15;74263:38;:21;:38;:::i;:::-;74243:17;:58;74103:208;74420:1;74405:12;:16;74401:398;;;74593:28;;-1:-1:-1;;;;;74593:14:0;;;:28;;;;;74608:12;;74593:28;;;;74608:12;74593:14;:28;;;;;;;74589:203;;;74639:61;;;;;;;;74670:15;;74658:10;;-1:-1:-1;;;;;74639:61:0;;;;;;;;;;;;;74589:203;;;74747:17;;:35;;74769:12;74747:35;:21;:35;:::i;:::-;74727:17;:55;74589:203;70284:4520;;;;;;;;;;;;:::o;7568:86::-;7419:20;7428:10;7419:8;:20::i;:::-;7411:29;;;;;;;;7629:19;7640:7;7629:10;:19::i;:::-;7568:86;:::o;8854:106::-;7419:20;7428:10;7419:8;:20::i;:::-;7411:29;;;;;;;;8587:7;;;;8586:8;8578:17;;;;;;8910:7;:14;;-1:-1:-1;;8910:14:0;8920:4;8910:14;;;8936:18;;;8943:10;8936:18;;;;;;;;;;;;;8854:106::o;9810:72::-;9847:7;9870:6;-1:-1:-1;;;;;9870:6:0;9810:72;:::o;10112:85::-;10151:4;10185:6;-1:-1:-1;;;;;10185:6:0;10171:10;:20;;10112:85::o;84299:167::-;-1:-1:-1;;;;;84427:22:0;;;84389:18;84427:22;;;:11;:22;;;;;:33;;;;;84299:167::o;90227:1270::-;90407:4;90502:12;90760:18;90897:17;90948:20;91023:23;90517:156;90556:10;90583:1;90594:15;90618:5;90632:13;90654:12;90517:30;:156::i;:::-;90502:171;;90781:48;90819:9;;90781:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;90781:29:0;;-1:-1:-1;90781:4:0;;-1:-1:-1;90781:27:0;;-1:-1:-1;;;90781:29:0:i;:48::-;90760:69;;90917:12;:24;90930:10;-1:-1:-1;;;;;90917:24:0;-1:-1:-1;;;;;90917:24:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;90917:24:0;90897:44;;90971:15;:32;90987:15;90971:32;;;;;;;;;;;:45;;;90948:68;;91049:15;:32;91065:15;91049:32;;;;;;;;;;;:48;;;91023:74;;91269:51;91307:12;91269:33;91286:15;91269:12;:16;;:33;;;;:::i;:::-;:37;:51;:37;:51;:::i;:::-;91252:13;:68;;:117;;;;-1:-1:-1;91332:37:0;;;;:31;:37;;;;;;;;91331:38;91252:117;:167;;;;;91380:39;91392:9;91403:15;91380:11;:39::i;:::-;91252:232;;;;-1:-1:-1;91449:10:0;91431:29;;;;:17;:29;;;;;;;;:46;;;;;;;;:53;;;91430:54;91252:232;91236:255;90227:1270;-1:-1:-1;;;;;;;;;;;;90227:1270:0:o;86697:98::-;86751:9;86776:13;86769:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86697:98;:::o;86937:104::-;87010:18;:25;86937:104;:::o;83914:169::-;-1:-1:-1;;;;;84043:22:0;;;;;;:11;:22;;;;;;;;;:34;;84036:41;;;;;;-1:-1:-1;;84036:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84005:18;;84036:41;;;84043:34;84036:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83914:169;;;:::o;36701:1806::-;37084:12;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;8587:7;;;;8586:8;8578:17;;;;;;36907:19;36923:2;36907:15;:19::i;:::-;36906:20;36890:107;;;;;-1:-1:-1;;;;;36890:107:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37144:2;37148:5;37155:11;;37117:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;37117:58:0;;;37099:83;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;37099:83:0;;;;;;;;;;;;;-1:-1:-1;37277:24:0;;;:20;:24;;;;;;;37099:83;;-1:-1:-1;;37277:38:0;37273:92;;-1:-1:-1;37273:92:0;;-1:-1:-1;37273:92:0;37326:24;;;;:20;:24;;;;;:31;;;37273:92;37479:24;;;;:20;:24;;;;;;37471:32;;37455:136;;;;;-1:-1:-1;;;;;37455:136:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37703:597;;;;;;;;37734:4;37703:597;;-1:-1:-1;37703:597:0;;;;;;;;;;;;;37895:13;:20;37703:597;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38200:11;;;;;;37703:597;;38200:11;;;;37703:597;;-1:-1:-1;;;37703:597:0;;;;-1:-1:-1;;;37681:19:0;;;;:15;:19;;;;;;;;;:619;;;;;;;;;;;;-1:-1:-1;;37681:619:0;;;;;;;;;;-1:-1:-1;;37681:619:0;;;;;;;;-1:-1:-1;;37681:619:0;;;;;;;;;;;;;;;;-1:-1:-1;37681:619:0;;;;;;;;;;;;-1:-1:-1;;37681:619:0;-1:-1:-1;;;;;37681:619:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:19;;:619;;;;;;;;;;;:::i;:::-;-1:-1:-1;;38383:13:0;27:10:-1;;39:1;23:18;;45:23;;-1:-1;38383:22:0;;;;;;;;;-1:-1:-1;38466:35:0;;;38383:22;38466:35;;;;;;;;38402:2;;38466:35;;38489:11;;;;38466:35;;;;;38489:11;;;;38466:35;;;;;;;;;;-1:-1:-1;38466:35:0;;-1:-1:-1;;;;38466:35:0;36701:1806;;;;:::o;44534:373::-;44708:19;44724:2;44708:15;:19::i;:::-;44692:110;;;;;;;-1:-1:-1;;;;;44692:110:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44860:19;;;;:15;:19;;;;;;:35;;:41;44534:373::o;92264:1289::-;92469:4;92564:12;92819:18;92956:17;93007:20;93082:23;92579:153;92618:7;92634:10;92653:15;92677:5;92691:13;92713:12;92579:30;:153::i;:::-;92564:168;;92840:48;92878:9;;92840:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;92840:29:0;;-1:-1:-1;92840:4:0;;-1:-1:-1;92840:27:0;;-1:-1:-1;;;92840:29:0:i;:48::-;92819:69;;92976:12;:24;92989:10;-1:-1:-1;;;;;92976:24:0;-1:-1:-1;;;;;92976:24:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;92976:24:0;92956:44;;93030:15;:32;93046:15;93030:32;;;;;;;;;;;:45;;;93007:68;;93108:15;:32;93124:15;93108:32;;;;;;;;;;;:48;;;93082:74;;93328:51;93366:12;93328:33;93345:15;93328:12;:16;;:33;;;;:::i;:51::-;93311:13;:68;;:117;;;;-1:-1:-1;93391:37:0;;;;:31;:37;;;;;;;;93390:38;93311:117;:167;;;;;93439:39;93451:9;93462:15;93439:11;:39::i;:::-;93311:229;;;;-1:-1:-1;;;;;;93490:26:0;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:50;;;93489:51;93311:229;93295:252;92264:1289;-1:-1:-1;;;;;;;;;;;;;92264:1289:0:o;52540:1573::-;53097:17;53239:23;53380:13;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;8587:7;;;;8586:8;8578:17;;;;;;52765:39;52777:9;52788:15;52765:11;:39::i;:::-;52749:141;;;;;;;-1:-1:-1;;;;;52749:141:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52970:32;;;;:15;:32;;;;;;;;-1:-1:-1;;;;;52970:62:0;;;;:51;;:62;;;;;52963:69;;-1:-1:-1;;52963:69:0;;;53117:19;:30;;;;;:37;:44;;52963:69;53117:44;:41;:44;:::i;:::-;-1:-1:-1;;;;;53265:30:0;;;;;;:19;:30;;;;;:41;;53097:64;;-1:-1:-1;53265:30:0;53097:64;;53265:41;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;53396:35:0;;;;;:24;:35;;;;;;:52;;;;;;;;;53532:30;;;:19;:30;;;;;;;:37;;53265:41;;-1:-1:-1;53396:52:0;;-1:-1:-1;53265:41:0;;53396:52;;53532:37;;;;;;;;;;;;;;;;;:55;;;;-1:-1:-1;;;;;53665:30:0;;;;:19;:30;;;;;;:39;;;;;-1:-1:-1;;53665:39:0;;;:::i;:::-;-1:-1:-1;;;;;;53779:35:0;;;;;;:24;:35;;;;;;;;:52;;;;;;;;:60;;;53918:52;;;;;;53911:59;;;;54055:52;;;;;;;53918;;54055;;;;;;;;;52540:1573;;;;;:::o;87237:124::-;87307:7;87330:18;87349:5;87330:25;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;87330:25:0;;87237:124;-1:-1:-1;;87237:124:0:o;87536:97::-;87584:9;87609:18;87602:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;87602:25:0;;;;;;;;;;;;;;;;;;;;;;87536:97;:::o;79745:1987::-;-1:-1:-1;;;;;79976:26:0;;;79852:13;79976:26;;;:17;:26;;;;;;;;:43;;;;;;;;:53;;;;;;80048:22;;;:11;:22;;;;;;:29;79852:13;;79976:53;80048:29;;:130;;;;-1:-1:-1;80116:32:0;;;;:15;:32;;;;;;;;-1:-1:-1;;;;;80116:62:0;;;;:51;;:62;;;;;;;;80048:130;:180;;;;-1:-1:-1;80189:32:0;;;;:15;:32;;;;;:39;;;80048:180;80036:1540;;;-1:-1:-1;;;;;80287:26:0;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:49;;;;-1:-1:-1;80280:56:0;;80036:1540;80422:1;80362:32;;;:15;:32;;;;;:48;;;-1:-1:-1;;;;;80362:48:0;:62;80350:1226;;80526:32;;;;:15;:32;;;;;;;;:57;;80587:34;80526:95;80522:408;;;80675:32;;;;:15;:32;;;;;;;;:48;;;80654:101;;;;;-1:-1:-1;;;;;80654:101:0;;;;;;;;;80759:1;;80675:48;;;;;80654:92;;:101;;;;;80675:32;;80654:101;;;;;;;80675:48;80654:101;;;5:2:-1;;;;30:1;27;20:12;5:2;80654:101:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;80654:101:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;80654:101:0;:106;;80634:204;;;;;-1:-1:-1;;;;;80634:204:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80856:1;80849:8;;;;80522:408;81070:32;;;;:15;:32;;;;;;;;:48;;;;81164:57;;;81031:201;;;;;-1:-1:-1;;;;;81031:201:0;;;;;;;;;;;;;;;;81070:48;;;81031:111;;:201;;;;;81070:32;81031:201;;;;;;;;;;81070:48;81031:201;;;5:2:-1;;;;30:1;27;20:12;5:2;81031:201:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;81031:201:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;81031:201:0;81013:311;;;;;;;-1:-1:-1;;;;;81013:311:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81392:32;;;;:15;:32;;;;;;;;:48;;;;81491:57;;;81353:206;;;;;-1:-1:-1;;;;;81353:206:0;;;;;;;;;;;;;;;;81392:48;;;81353:116;;:206;;;;;81392:32;81353:206;;;;;;;;;;81392:48;81353:206;;;5:2:-1;;;;30:1;27;20:12;5:2;81353:206:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;81353:206:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;81353:206:0;;-1:-1:-1;81335:233:0;;80350:1226;81652:74;;;-1:-1:-1;;;;;81652:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85676:103;85753:13;:20;85676:103;:::o;89158:407::-;89376:12;89408:151;89447:7;89463:8;89480:15;89504:5;89518:13;89540:12;89408:30;:151::i;:::-;89401:158;89158:407;-1:-1:-1;;;;;;;89158:407:0:o;43635:434::-;43846:19;43862:2;43846:15;:19::i;:::-;43830:120;;;;;;;-1:-1:-1;;;;;43830:120:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44008:19;;;;:15;:19;;;;;;:32;;:55;43635:434::o;42467:540::-;42706:19;42722:2;42706:15;:19::i;:::-;42690:123;;;;;;;-1:-1:-1;;;;;42690:123:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;42871:19;;;;:15;:19;;;;;;;;:35;;;:55;;-1:-1:-1;;42871:55:0;-1:-1:-1;;;;;42871:55:0;;;;;;;;;;;42933:44;;:68;42467:540::o;39099:1814::-;39492:12;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;8587:7;;;;8586:8;8578:17;;;;;;39315:19;39331:2;39315:15;:19::i;:::-;39314:20;39298:107;;;;;-1:-1:-1;;;;;39298:107:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39552:2;39556:4;39562:11;;39525:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;39525:57:0;;;39507:82;;;;;;;;;;;;;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;39507:82:0;;;;;;;;;;;;;-1:-1:-1;39684:24:0;;;:20;:24;;;;;;;39507:82;;-1:-1:-1;;39684:38:0;39680:92;;-1:-1:-1;39680:92:0;;-1:-1:-1;39680:92:0;39733:24;;;;:20;:24;;;;;:31;;;39680:92;39886:24;;;;:20;:24;;;;;;39878:32;;39862:136;;;;;-1:-1:-1;;;;;39862:136:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40110:596;;;;;;;;40141:4;40110:596;;;;;;;;;;;-1:-1:-1;40110:596:0;;;;;;40301:13;:20;40110:596;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40606:11;;;;;;40110:596;;40606:11;;;;40110:596;;-1:-1:-1;;;40110:596:0;;;;-1:-1:-1;;;40088:19:0;;;;:15;:19;;;;;;;;;:618;;;;;;;;;;;;-1:-1:-1;;40088:618:0;;;;;;;;;;-1:-1:-1;;40088:618:0;;;;;;;;-1:-1:-1;;40088:618:0;;;;;;;;;;;;;;;;-1:-1:-1;40088:618:0;;;;;;;;;;;;-1:-1:-1;;40088:618:0;-1:-1:-1;;;;;40088:618:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:19;;:618;;;;;;;;;;;:::i;82123:178::-;82236:4;82256:39;82268:9;82279:15;82256:11;:39::i;:::-;82249:46;82123:178;-1:-1:-1;;;82123:178:0:o;10766:103::-;10003:9;:7;:9::i;:::-;9995:18;;;;;;;;10835:28;10854:8;10835:18;:28::i;59012:3676::-;8587:7;;59396:17;;;;;;;;;;;;8587:7;;8586:8;8578:17;;;;;;-1:-1:-1;;;;;59217:26:0;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:50;;;59201:123;;;;;;;-1:-1:-1;;;;;59201:123:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;59416:26:0;;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:53;;;;;-1:-1:-1;59578:10:0;:23;;;:48;;;59619:7;:5;:7::i;:::-;-1:-1:-1;;;;;59605:21:0;:10;-1:-1:-1;;;;;59605:21:0;;59578:48;59562:153;;;;;;;-1:-1:-1;;;;;59562:153:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;59820:26:0;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:49;;;;59979:57;;59820:49;;-1:-1:-1;59979:57:0;;;;;59975:330;;;60063:7;60047:23;;59975:330;;;-1:-1:-1;;;;;60112:26:0;;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:52;;;;;;-1:-1:-1;60177:22:0;;60173:125;;;60228:9;60212:25;;60173:125;;;60280:8;60264:24;;60173:125;-1:-1:-1;;;;;60382:26:0;;;;;;;:17;:26;;;;;;;;:43;;;;;;;;60375:50;;-1:-1:-1;;60375:50:0;;;;;;;;-1:-1:-1;;60375:50:0;;;;;;;;;;;;;;;60480:53;;;;;;;;;;;;;;60382:26;;60480:53;;;;;;;;;;;60622:1;60614:5;:9;:43;;;;-1:-1:-1;60635:4:0;60627:21;:30;-1:-1:-1;60627:30:0;60614:43;60610:2073;;;61261:5;;-1:-1:-1;61338:31:0;61261:5;61357:11;61338:31;:18;:31;:::i;:::-;61312:57;;61474:15;61466:5;:23;61462:1214;;;-1:-1:-1;;;;;61584:18:0;;:46;61603:26;:5;61613:15;61603:26;:9;:26;:::i;:::-;61584:46;;;;;;;;;;;;;;;;;;;;;61580:307;;;61706:15;-1:-1:-1;;;;;61650:125:0;;;61736:26;:5;61746:15;61736:26;:9;:26;:::i;:::-;61650:125;;;;;;;;;;;;;;;61580:307;;;61826:49;61848:26;:5;61858:15;61848:26;:9;:26;:::i;:::-;61826:17;;;:49;:21;:49;:::i;:::-;61806:17;:69;61580:307;61972:136;;;;;;;;62054:15;;-1:-1:-1;;;;;61972:136:0;;;62006:9;;61972:136;;;;;;;;;;62196:35;;:9;;:35;;;;;62215:15;;62196:35;;;;62215:15;62196:9;:35;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;62196:35:0;61462:1214;;;62423:126;;;;;;;;62505:15;;-1:-1:-1;;;;;62423:126:0;;;62457:9;;62423:126;;;;;;;;;;62641:25;;:9;;:25;;;;;62660:5;;62641:25;;;;62660:5;62641:9;:25;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;62641:25:0;61462:1214;59012:3676;;;;;;;;:::o;94254:112::-;-1:-1:-1;;;;;94333:20:0;94313:4;94333:20;;;:11;:20;;;;;:27;;;;94254:112::o;75184:1597::-;75882:17;75365:32;;;:15;:32;;;;;:43;75882:17;;75365:43;;;;;75364:44;75348:150;;;;;-1:-1:-1;;;;;75348:150:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;75523:26:0;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:50;;;75507:123;;;;;;;-1:-1:-1;;;;;75507:123:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;75655:26:0;;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:52;;;;;75711:10;75655:66;75639:171;;;;;-1:-1:-1;;;;;75639:171:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;75902:26:0;;;;;;;:17;:26;;;;;;;;:43;;;;;;;;:53;;;;;76034:49;;;;;76143:50;;-1:-1:-1;;76143:50:0;;;-1:-1:-1;;76143:50:0;;;;;-1:-1:-1;76143:50:0;;;;;;;;;;76248:53;;75902;;;;76248;;;;;;;;;;;75902;;76034:49;75902:26;76248:53;;;;;;;;;;;76393:1;76385:5;:9;:43;;;;-1:-1:-1;76406:4:0;76398:21;:30;-1:-1:-1;76398:30:0;76385:43;76381:395;;;76595:22;;:10;;:22;;;;;76611:5;;76595:22;;;;76611:5;76595:10;:22;;;;;;;76591:178;;;76635:49;;;;;;;;76661:15;;76649:10;;76635:49;;;;;;;;;76591:178;;;76731:17;;:28;;76753:5;76731:28;:21;:28;:::i;:::-;76711:17;:48;76591:178;75184:1597;;;;:::o;82533:189::-;82672:32;;;;:15;:32;;;;;;;;;:44;;82665:51;;;;;;-1:-1:-1;;82665:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;82634:18;;82665:51;;;82672:44;82665:51;;;;;;;;;;;;;;;;;;;;;;;;4231:287;4447:58;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;4447:58:0;;;;;;;;4429:83;;4315:7;;4447:58;;;4429:83;;;;;4447:58;4429:83;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;;;;365:33;;4429:83:0;;;;;;;;;;;;-1:-1:-1;;;;;4231:287:0:o;3082:1004::-;3168:7;3187:9;3203;3219:7;3274:9;:16;3294:2;3274:22;;3270:64;;;3323:1;3307:19;;;;3270:64;-1:-1:-1;;;3617:4:0;3602:20;;3596:27;3657:4;3642:20;;3636:27;3705:4;3690:20;;3684:27;3681:1;3676:36;3823:2;3819:6;;;;3815:36;;;3841:2;3836:7;3815:36;3923:1;:7;;3928:2;3923:7;;:18;;;;;3934:1;:7;;3939:2;3934:7;;3923:18;3919:162;;;3968:1;3952:19;;;;3919:162;4049:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4049:24:0;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4049:24:0;;;;;;;;4042:31;;3919:162;3082:1004;;;;;;;:::o;97286:361::-;-1:-1:-1;;;;;97418:22:0;;97389:4;97418:22;;;:11;:22;;;;;:29;;;:130;;;;-1:-1:-1;97486:32:0;;;;:15;:32;;;;;;;;-1:-1:-1;;;;;97486:62:0;;;;:51;;:62;;;;;;;;97418:130;:180;;;;-1:-1:-1;;97559:32:0;;;;:15;:32;;;;;:39;;;;97286:361;-1:-1:-1;97286:361:0:o;5818:136::-;5876:7;5904:5;;;5924:6;;;;5916:15;;;;;5614:136;5672:7;;5696:6;;;;5688:15;;;;;;-1:-1:-1;;5722:5:0;;;5614:136::o;6947:173::-;7034:4;-1:-1:-1;;;;;7058:21:0;;;;7050:30;;;;;;-1:-1:-1;;;;;;7094:20:0;:11;:20;;;;;;;;;;;;;;;6947:173::o;98269:1582::-;98401:11;98631:14;98692:26;98504:15;98523:34;98504:53;98500:123;;;98613:1;98583:6;-1:-1:-1;;;;;98576:24:0;;98601:7;98576:33;;;;;;;;;;;;;-1:-1:-1;;;;;98576:33:0;-1:-1:-1;;;;;98576:33:0;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;98576:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;98576:33:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;98576:33:0;:38;;;-1:-1:-1;98568:47:0;;98500:123;98660:5;98648:9;:17;:37;;98676:9;98648:37;;;98668:5;98648:37;98721:104;;;-1:-1:-1;;;;;98721:104:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;98721:104:0;;;;;;;25:18:-1;;;61:17;;98721:104:0;182:15:-1;98752:26:0;179:29:-1;160:49;;98936:20:0;;98986:11;;-1:-1:-1;99051:19:0;;98631:54;;-1:-1:-1;98721:104:0;;-1:-1:-1;25:18;;98986:11:0;;98936:20;25:18:-1;99242:6:0;98631:54;99149:445;99611:7;99691:1;99686:153;;;;99604:235;;99686:153;99785:6;99779:13;99769:23;;99604:235;;98843:1003;;;;;;;;;;;;:::o;7854:119::-;7910:23;:7;7925;7910:23;:14;:23;:::i;:::-;7945:22;;-1:-1:-1;;;;;7945:22:0;;;;;;;;7854:119;:::o;7737:111::-;7790:20;:7;7802;7790:20;:11;:20;:::i;:::-;7822;;-1:-1:-1;;;;;7822:20:0;;;;;;;;7737:111;:::o;97730:452::-;97994:175;;;;98029:4;97994:175;;;;;;;;;;-1:-1:-1;;;;;97994:175:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;97994:175:0;;;;;;;;97976:200;;97948:12;;97994:175;;;97976:200;;;;;97994:175;97976:200;36:153:-1;66:2;58:11;;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;;;;365:33;;97976:200:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;97730:452:0:o;11009:173::-;-1:-1:-1;;;;;11079:22:0;;;;11071:31;;;;;;11135:6;;;11114:38;;-1:-1:-1;;;;;11114:38:0;;;;11135:6;;;11114:38;;;11159:6;:17;;-1:-1:-1;;11159:17:0;-1:-1:-1;;;;;11159:17:0;;;;;;;;;;11009:173::o;4712:393::-;4770:7;;4998:6;;4994:37;;;5022:1;5015:8;;;;4994:37;-1:-1:-1;5051:5:0;;;5055:1;5051;:5;5071;;;;;;;;:10;5063:19;;;;;6688:175;-1:-1:-1;;;;;6764:21:0;;;;6756:30;;;;;;6801:18;6805:4;6811:7;6801:3;:18::i;:::-;6793:27;;;;;;;;-1:-1:-1;;;;;6829:20:0;6852:5;6829:20;;;;;;;;;;;:28;;-1:-1:-1;;6829:28:0;;;6688:175::o;6445:172::-;-1:-1:-1;;;;;6518:21:0;;;;6510:30;;;;;;6556:18;6560:4;6566:7;6556:3;:18::i;:::-;6555:19;6547:28;;;;;;-1:-1:-1;;;;;6584:20:0;:11;:20;;;;;;;;;;;:27;;-1:-1:-1;;6584:27:0;6607:4;6584:27;;;6445:172::o;33489:66365::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;33489:66365:0;;;-1:-1:-1;33489:66365:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;

Swarm Source

bzzr://a8ea3603d37dbe60eef96adfc91ed303a528b48f25dd80d7b821013e26cc5b15
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.