Address Details
contract

0xaaeC0C52945a85d0ED9C831B01c62906a9c3f286

Contract Name
Validators
Creator
0x0cc59e–f1502d at 0x1b8fee–bb9ee6
Balance
0 CELO
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
2113674
Contract name:
Validators




Optimization enabled
false
Compiler version
v0.5.8+commit.23d335f2




Verified at
2020-08-11T19:22:18.315439Z

Contract source code

pragma solidity ^0.5.3;


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

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

    
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

library SafeMath {
    
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        
        
        
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        
        require(b > 0, errorMessage);
        uint256 c = a / b;
        

        return c;
    }

    
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

contract Context {
    
    
    constructor () internal { }
    

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; 
        return msg.data;
    }
}

contract Ownable is Context {
    address private _owner;

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

    
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    
    function owner() public view returns (address) {
        return _owner;
    }

    
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

library BytesLib {
    function concat(
        bytes memory _preBytes,
        bytes memory _postBytes
    )
        internal
        pure
        returns (bytes memory)
    {
        bytes memory tempBytes;

        assembly {
            
            
            tempBytes := mload(0x40)

            
            
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            
            
            
            let mc := add(tempBytes, 0x20)
            
            
            let end := add(mc, length)

            for {
                
                
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                
                
                mstore(mc, mload(cc))
            }

            
            
            
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            
            
            mc := end
            
            
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            
            
            
            
            
            mstore(0x40, and(
              add(add(end, iszero(add(length, mload(_preBytes)))), 31),
              not(31) 
            ))
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            
            
            
            let fslot := sload(_preBytes_slot)
            
            
            
            
            
            
            
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            
            
            
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                
                
                
                sstore(
                    _preBytes_slot,
                    
                    
                    add(
                        
                        
                        fslot,
                        add(
                            mul(
                                div(
                                    
                                    mload(add(_postBytes, 0x20)),
                                    
                                    exp(0x100, sub(32, mlength))
                                ),
                                
                                
                                exp(0x100, sub(32, newlength))
                            ),
                            
                            
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                
                
                
                mstore(0x0, _preBytes_slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                
                sstore(_preBytes_slot, add(mul(newlength, 2), 1))

                
                
                
                
                
                
                
                

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(
                            fslot,
                            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                        ),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                
                mstore(0x0, _preBytes_slot)
                
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                
                sstore(_preBytes_slot, add(mul(newlength, 2), 1))

                
                
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))
                
                for { 
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(
        bytes memory _bytes,
        uint _start,
        uint _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_bytes.length >= (_start + _length));

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                
                
                tempBytes := mload(0x40)

                
                
                
                
                
                
                
                
                let lengthmod := and(_length, 31)

                
                
                
                
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    
                    
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                
                
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            
            default {
                tempBytes := mload(0x40)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint _start) internal  pure returns (address) {
        require(_bytes.length >= (_start + 20));
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint _start) internal  pure returns (uint8) {
        require(_bytes.length >= (_start + 1));
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint _start) internal  pure returns (uint16) {
        require(_bytes.length >= (_start + 2));
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint _start) internal  pure returns (uint32) {
        require(_bytes.length >= (_start + 4));
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint(bytes memory _bytes, uint _start) internal  pure returns (uint256) {
        require(_bytes.length >= (_start + 32));
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint _start) internal  pure returns (bytes32) {
        require(_bytes.length >= (_start + 32));
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            
            switch eq(length, mload(_postBytes))
            case 1 {
                
                
                
                
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(_postBytes, 0x20)
                
                
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    
                    if iszero(eq(mload(mc), mload(cc))) {
                        
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                
                success := 0
            }
        }

        return success;
    }

    function equalStorage(
        bytes storage _preBytes,
        bytes memory _postBytes
    )
        internal
        view
        returns (bool)
    {
        bool success = true;

        assembly {
            
            let fslot := sload(_preBytes_slot)
            
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            
            switch eq(slength, mlength)
            case 1 {
                
                
                
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            
                            success := 0
                        }
                    }
                    default {
                        
                        
                        
                        
                        let cb := 1

                        
                        mstore(0x0, _preBytes_slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        
                        
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                
                success := 0
            }
        }

        return success;
    }
}

interface IValidators {
  function getAccountLockedGoldRequirement(address) external view returns (uint256);
  function meetsAccountLockedGoldRequirements(address) external view returns (bool);
  function getGroupNumMembers(address) external view returns (uint256);
  function getGroupsNumMembers(address[] calldata) external view returns (uint256[] memory);
  function getNumRegisteredValidators() external view returns (uint256);
  function getTopGroupValidators(address, uint256) external view returns (address[] memory);
  function updateEcdsaPublicKey(address, address, bytes calldata) external returns (bool);
  function updatePublicKeys(address, address, bytes calldata, bytes calldata, bytes calldata)
    external
    returns (bool);
  function isValidator(address) external view returns (bool);
  function isValidatorGroup(address) external view returns (bool);
  function calculateGroupEpochScore(uint256[] calldata uptimes) external view returns (uint256);
  function groupMembershipInEpoch(address account, uint256 epochNumber, uint256 index)
    external
    view
    returns (address);
  function halveSlashingMultiplier(address group) external;
  function forceDeaffiliateIfValidator(address validator) external;
  function getValidatorGroupSlashingMultiplier(address) external view returns (uint256);
  function affiliate(address group) external returns (bool);
}

interface IRandom {
  function revealAndCommit(bytes32, bytes32, address) external;
  function randomnessBlockRetentionWindow() external view returns (uint256);
  function random() external view returns (bytes32);
  function getBlockRandomness(uint256) external view returns (bytes32);
}

contract CalledByVm {
  modifier onlyVm() {
    require(msg.sender == address(0), "Only VM can call");
    _;
  }
}

contract Initializable {
  bool public initialized;

  modifier initializer() {
    require(!initialized, "contract already initialized");
    initialized = true;
    _;
  }
}

library FixidityLib {
  struct Fraction {
    uint256 value;
  }

  
  function digits() internal pure returns (uint8) {
    return 24;
  }

  uint256 private constant FIXED1_UINT = 1000000000000000000000000;

  
  function fixed1() internal pure returns (Fraction memory) {
    return Fraction(FIXED1_UINT);
  }

  
  function wrap(uint256 x) internal pure returns (Fraction memory) {
    return Fraction(x);
  }

  
  function unwrap(Fraction memory x) internal pure returns (uint256) {
    return x.value;
  }

  
  function mulPrecision() internal pure returns (uint256) {
    return 1000000000000;
  }

  
  function maxNewFixed() internal pure returns (uint256) {
    return 115792089237316195423570985008687907853269984665640564;
  }

  
  function newFixed(uint256 x) internal pure returns (Fraction memory) {
    require(x <= maxNewFixed(), "can't create fixidity number larger than maxNewFixed()");
    return Fraction(x * FIXED1_UINT);
  }

  
  function fromFixed(Fraction memory x) internal pure returns (uint256) {
    return x.value / FIXED1_UINT;
  }

  
  function newFixedFraction(uint256 numerator, uint256 denominator)
    internal
    pure
    returns (Fraction memory)
  {
    Fraction memory convertedNumerator = newFixed(numerator);
    Fraction memory convertedDenominator = newFixed(denominator);
    return divide(convertedNumerator, convertedDenominator);
  }

  
  function integer(Fraction memory x) internal pure returns (Fraction memory) {
    return Fraction((x.value / FIXED1_UINT) * FIXED1_UINT); 
  }

  
  function fractional(Fraction memory x) internal pure returns (Fraction memory) {
    return Fraction(x.value - (x.value / FIXED1_UINT) * FIXED1_UINT); 
  }

  
  function add(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {
    uint256 z = x.value + y.value;
    require(z >= x.value, "add overflow detected");
    return Fraction(z);
  }

  
  function subtract(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {
    require(x.value >= y.value, "substraction underflow detected");
    return Fraction(x.value - y.value);
  }

  
  function multiply(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {
    if (x.value == 0 || y.value == 0) return Fraction(0);
    if (y.value == FIXED1_UINT) return x;
    if (x.value == FIXED1_UINT) return y;

    
    
    uint256 x1 = integer(x).value / FIXED1_UINT;
    uint256 x2 = fractional(x).value;
    uint256 y1 = integer(y).value / FIXED1_UINT;
    uint256 y2 = fractional(y).value;

    
    uint256 x1y1 = x1 * y1;
    if (x1 != 0) require(x1y1 / x1 == y1, "overflow x1y1 detected");

    
    
    uint256 fixed_x1y1 = x1y1 * FIXED1_UINT;
    if (x1y1 != 0) require(fixed_x1y1 / x1y1 == FIXED1_UINT, "overflow x1y1 * fixed1 detected");
    x1y1 = fixed_x1y1;

    uint256 x2y1 = x2 * y1;
    if (x2 != 0) require(x2y1 / x2 == y1, "overflow x2y1 detected");

    uint256 x1y2 = x1 * y2;
    if (x1 != 0) require(x1y2 / x1 == y2, "overflow x1y2 detected");

    x2 = x2 / mulPrecision();
    y2 = y2 / mulPrecision();
    uint256 x2y2 = x2 * y2;
    if (x2 != 0) require(x2y2 / x2 == y2, "overflow x2y2 detected");

    
    Fraction memory result = Fraction(x1y1);
    result = add(result, Fraction(x2y1)); 
    result = add(result, Fraction(x1y2)); 
    result = add(result, Fraction(x2y2)); 
    return result;
  }

  
  function reciprocal(Fraction memory x) internal pure returns (Fraction memory) {
    require(x.value != 0, "can't call reciprocal(0)");
    return Fraction((FIXED1_UINT * FIXED1_UINT) / x.value); 
  }

  
  function divide(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {
    require(y.value != 0, "can't divide by 0");
    uint256 X = x.value * FIXED1_UINT;
    require(X / FIXED1_UINT == x.value, "overflow at divide");
    return Fraction(X / y.value);
  }

  
  function gt(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value > y.value;
  }

  
  function gte(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value >= y.value;
  }

  
  function lt(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value < y.value;
  }

  
  function lte(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value <= y.value;
  }

  
  function equals(Fraction memory x, Fraction memory y) internal pure returns (bool) {
    return x.value == y.value;
  }

  
  function isProperFraction(Fraction memory x) internal pure returns (bool) {
    return lte(x, fixed1());
  }
}

library LinkedList {
  using SafeMath for uint256;

  struct Element {
    bytes32 previousKey;
    bytes32 nextKey;
    bool exists;
  }

  struct List {
    bytes32 head;
    bytes32 tail;
    uint256 numElements;
    mapping(bytes32 => Element) elements;
  }

  
  function insert(List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey) public {
    require(key != bytes32(0), "Key must be defined");
    require(!contains(list, key), "Can't insert an existing element");
    require(
      previousKey != key && nextKey != key,
      "Key cannot be the same as previousKey or nextKey"
    );

    Element storage element = list.elements[key];
    element.exists = true;

    if (list.numElements == 0) {
      list.tail = key;
      list.head = key;
    } else {
      require(
        previousKey != bytes32(0) || nextKey != bytes32(0),
        "Either previousKey or nextKey must be defined"
      );

      element.previousKey = previousKey;
      element.nextKey = nextKey;

      if (previousKey != bytes32(0)) {
        require(
          contains(list, previousKey),
          "If previousKey is defined, it must exist in the list"
        );
        Element storage previousElement = list.elements[previousKey];
        require(previousElement.nextKey == nextKey, "previousKey must be adjacent to nextKey");
        previousElement.nextKey = key;
      } else {
        list.tail = key;
      }

      if (nextKey != bytes32(0)) {
        require(contains(list, nextKey), "If nextKey is defined, it must exist in the list");
        Element storage nextElement = list.elements[nextKey];
        require(nextElement.previousKey == previousKey, "previousKey must be adjacent to nextKey");
        nextElement.previousKey = key;
      } else {
        list.head = key;
      }
    }

    list.numElements = list.numElements.add(1);
  }

  
  function push(List storage list, bytes32 key) public {
    insert(list, key, bytes32(0), list.tail);
  }

  
  function remove(List storage list, bytes32 key) public {
    Element storage element = list.elements[key];
    require(key != bytes32(0) && contains(list, key), "key not in list");
    if (element.previousKey != bytes32(0)) {
      Element storage previousElement = list.elements[element.previousKey];
      previousElement.nextKey = element.nextKey;
    } else {
      list.tail = element.nextKey;
    }

    if (element.nextKey != bytes32(0)) {
      Element storage nextElement = list.elements[element.nextKey];
      nextElement.previousKey = element.previousKey;
    } else {
      list.head = element.previousKey;
    }

    delete list.elements[key];
    list.numElements = list.numElements.sub(1);
  }

  
  function update(List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey) public {
    require(
      key != bytes32(0) && key != previousKey && key != nextKey && contains(list, key),
      "key on in list"
    );
    remove(list, key);
    insert(list, key, previousKey, nextKey);
  }

  
  function contains(List storage list, bytes32 key) public view returns (bool) {
    return list.elements[key].exists;
  }

  
  function headN(List storage list, uint256 n) public view returns (bytes32[] memory) {
    require(n <= list.numElements, "not enough elements");
    bytes32[] memory keys = new bytes32[](n);
    bytes32 key = list.head;
    for (uint256 i = 0; i < n; i = i.add(1)) {
      keys[i] = key;
      key = list.elements[key].previousKey;
    }
    return keys;
  }

  
  function getKeys(List storage list) public view returns (bytes32[] memory) {
    return headN(list, list.numElements);
  }
}

library AddressLinkedList {
  using LinkedList for LinkedList.List;
  using SafeMath for uint256;

  function toBytes(address a) public pure returns (bytes32) {
    return bytes32(uint256(a) << 96);
  }

  function toAddress(bytes32 b) public pure returns (address) {
    return address(uint256(b) >> 96);
  }

  
  function insert(LinkedList.List storage list, address key, address previousKey, address nextKey)
    public
  {
    list.insert(toBytes(key), toBytes(previousKey), toBytes(nextKey));
  }

  
  function push(LinkedList.List storage list, address key) public {
    list.insert(toBytes(key), bytes32(0), list.tail);
  }

  
  function remove(LinkedList.List storage list, address key) public {
    list.remove(toBytes(key));
  }

  
  function update(LinkedList.List storage list, address key, address previousKey, address nextKey)
    public
  {
    list.update(toBytes(key), toBytes(previousKey), toBytes(nextKey));
  }

  
  function contains(LinkedList.List storage list, address key) public view returns (bool) {
    return list.elements[toBytes(key)].exists;
  }

  
  function headN(LinkedList.List storage list, uint256 n) public view returns (address[] memory) {
    bytes32[] memory byteKeys = list.headN(n);
    address[] memory keys = new address[](n);
    for (uint256 i = 0; i < n; i = i.add(1)) {
      keys[i] = toAddress(byteKeys[i]);
    }
    return keys;
  }

  
  function getKeys(LinkedList.List storage list) public view returns (address[] memory) {
    return headN(list, list.numElements);
  }
}

interface IERC20 {
    
    function totalSupply() external view returns (uint256);

    
    function balanceOf(address account) external view returns (uint256);

    
    function transfer(address recipient, uint256 amount) external returns (bool);

    
    function allowance(address owner, address spender) external view returns (uint256);

    
    function approve(address spender, uint256 amount) external returns (bool);

    
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    
    event Transfer(address indexed from, address indexed to, uint256 value);

    
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

interface IAccounts {
  function isAccount(address) external view returns (bool);
  function voteSignerToAccount(address) external view returns (address);
  function validatorSignerToAccount(address) external view returns (address);
  function attestationSignerToAccount(address) external view returns (address);
  function signerToAccount(address) external view returns (address);
  function getAttestationSigner(address) external view returns (address);
  function getValidatorSigner(address) external view returns (address);
  function getVoteSigner(address) external view returns (address);
  function hasAuthorizedVoteSigner(address) external view returns (bool);
  function hasAuthorizedValidatorSigner(address) external view returns (bool);
  function hasAuthorizedAttestationSigner(address) external view returns (bool);

  function setAccountDataEncryptionKey(bytes calldata) external;
  function setMetadataURL(string calldata) external;
  function setName(string calldata) external;
  function setWalletAddress(address, uint8, bytes32, bytes32) external;
  function setAccount(string calldata, bytes calldata, address, uint8, bytes32, bytes32) external;

  function getDataEncryptionKey(address) external view returns (bytes memory);
  function getWalletAddress(address) external view returns (address);
  function getMetadataURL(address) external view returns (string memory);
  function batchGetMetadataURL(address[] calldata)
    external
    view
    returns (uint256[] memory, bytes memory);
  function getName(address) external view returns (string memory);

  function authorizeVoteSigner(address, uint8, bytes32, bytes32) external;
  function authorizeValidatorSigner(address, uint8, bytes32, bytes32) external;
  function authorizeValidatorSignerWithPublicKey(address, uint8, bytes32, bytes32, bytes calldata)
    external;
  function authorizeValidatorSignerWithKeys(
    address,
    uint8,
    bytes32,
    bytes32,
    bytes calldata,
    bytes calldata,
    bytes calldata
  ) external;
  function authorizeAttestationSigner(address, uint8, bytes32, bytes32) external;
  function createAccount() external returns (bool);
}

interface IFeeCurrencyWhitelist {
  function addToken(address) external;
  function getWhitelist() external view returns (address[] memory);
}

interface IFreezer {
  function isFrozen(address) external view returns (bool);
}

interface IRegistry {
  function setAddressFor(string calldata, address) external;
  function getAddressForOrDie(bytes32) external view returns (address);
  function getAddressFor(bytes32) external view returns (address);
  function isOneOf(bytes32[] calldata, address) external view returns (bool);
}

interface IElection {
  function getTotalVotes() external view returns (uint256);
  function getActiveVotes() external view returns (uint256);
  function getTotalVotesByAccount(address) external view returns (uint256);
  function markGroupIneligible(address) external;
  function markGroupEligible(address, address, address) external;
  function electValidatorSigners() external view returns (address[] memory);
  function vote(address, uint256, address, address) external returns (bool);
  function activate(address) external returns (bool);
  function revokeActive(address, uint256, address, address, uint256) external returns (bool);
  function revokeAllActive(address, address, address, uint256) external returns (bool);
  function revokePending(address, uint256, address, address, uint256) external returns (bool);
  function forceDecrementVotes(
    address,
    uint256,
    address[] calldata,
    address[] calldata,
    uint256[] calldata
  ) external returns (uint256);
}

interface IGovernance {
  function isVoting(address) external view returns (bool);
}

interface ILockedGold {
  function incrementNonvotingAccountBalance(address, uint256) external;
  function decrementNonvotingAccountBalance(address, uint256) external;
  function getAccountTotalLockedGold(address) external view returns (uint256);
  function getTotalLockedGold() external view returns (uint256);
  function getPendingWithdrawals(address)
    external
    view
    returns (uint256[] memory, uint256[] memory);
  function getTotalPendingWithdrawals(address) external view returns (uint256);
  function lock() external payable;
  function unlock(uint256) external;
  function relock(uint256, uint256) external;
  function withdraw(uint256) external;
  function slash(
    address account,
    uint256 penalty,
    address reporter,
    uint256 reward,
    address[] calldata lessers,
    address[] calldata greaters,
    uint256[] calldata indices
  ) external;
  function isSlasher(address) external view returns (bool);
}

interface IAttestations {
  function setAttestationRequestFee(address, uint256) external;
  function request(bytes32, uint256, address) external;
  function selectIssuers(bytes32) external;
  function complete(bytes32, uint8, bytes32, bytes32) external;
  function revoke(bytes32, uint256) external;
  function withdraw(address) external;

  function setAttestationExpiryBlocks(uint256) external;

  function getMaxAttestations() external view returns (uint256);

  function getUnselectedRequest(bytes32, address) external view returns (uint32, uint32, address);
  function getAttestationRequestFee(address) external view returns (uint256);

  function lookupAccountsForIdentifier(bytes32) external view returns (address[] memory);

  function getAttestationStats(bytes32, address) external view returns (uint32, uint32);

  function getAttestationState(bytes32, address, address)
    external
    view
    returns (uint8, uint32, address);
  function getCompletableAttestations(bytes32, address)
    external
    view
    returns (uint32[] memory, address[] memory, uint256[] memory, bytes memory);
}

interface IExchange {
  function exchange(uint256, uint256, bool) external returns (uint256);
  function setUpdateFrequency(uint256) external;
  function getBuyTokenAmount(uint256, bool) external view returns (uint256);
  function getSellTokenAmount(uint256, bool) external view returns (uint256);
  function getBuyAndSellBuckets(bool) external view returns (uint256, uint256);
}

interface IReserve {
  function setTobinTaxStalenessThreshold(uint256) external;
  function addToken(address) external returns (bool);
  function removeToken(address, uint256) external returns (bool);
  function transferGold(address payable, uint256) external returns (bool);
  function transferExchangeGold(address payable, uint256) external returns (bool);
  function getReserveGoldBalance() external view returns (uint256);
  function getUnfrozenReserveGoldBalance() external view returns (uint256);
  function getOrComputeTobinTax() external returns (uint256, uint256);
  function getTokens() external view returns (address[] memory);
  function getReserveRatio() external view returns (uint256);
}

interface ISortedOracles {
  function addOracle(address, address) external;
  function removeOracle(address, address, uint256) external;
  function report(address, uint256, address, address) external;
  function removeExpiredReports(address, uint256) external;
  function isOldestReportExpired(address token) external view returns (bool, address);
  function numRates(address) external view returns (uint256);
  function medianRate(address) external view returns (uint256, uint256);
  function numTimestamps(address) external view returns (uint256);
  function medianTimestamp(address) external view returns (uint256);
}

interface IStableToken {
  function mint(address, uint256) external returns (bool);
  function burn(uint256) external returns (bool);
  function setInflationParameters(uint256, uint256) external;
  function valueToUnits(uint256) external view returns (uint256);
  function unitsToValue(uint256) external view returns (uint256);
  function getInflationParameters() external view returns (uint256, uint256, uint256, uint256);

  
  function balanceOf(address) external view returns (uint256);
}

contract UsingRegistry is Ownable {
  event RegistrySet(address indexed registryAddress);

  
  bytes32 constant ACCOUNTS_REGISTRY_ID = keccak256(abi.encodePacked("Accounts"));
  bytes32 constant ATTESTATIONS_REGISTRY_ID = keccak256(abi.encodePacked("Attestations"));
  bytes32 constant DOWNTIME_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("DowntimeSlasher"));
  bytes32 constant DOUBLE_SIGNING_SLASHER_REGISTRY_ID = keccak256(
    abi.encodePacked("DoubleSigningSlasher")
  );
  bytes32 constant ELECTION_REGISTRY_ID = keccak256(abi.encodePacked("Election"));
  bytes32 constant EXCHANGE_REGISTRY_ID = keccak256(abi.encodePacked("Exchange"));
  bytes32 constant FEE_CURRENCY_WHITELIST_REGISTRY_ID = keccak256(
    abi.encodePacked("FeeCurrencyWhitelist")
  );
  bytes32 constant FREEZER_REGISTRY_ID = keccak256(abi.encodePacked("Freezer"));
  bytes32 constant GOLD_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("GoldToken"));
  bytes32 constant GOVERNANCE_REGISTRY_ID = keccak256(abi.encodePacked("Governance"));
  bytes32 constant GOVERNANCE_SLASHER_REGISTRY_ID = keccak256(
    abi.encodePacked("GovernanceSlasher")
  );
  bytes32 constant LOCKED_GOLD_REGISTRY_ID = keccak256(abi.encodePacked("LockedGold"));
  bytes32 constant RESERVE_REGISTRY_ID = keccak256(abi.encodePacked("Reserve"));
  bytes32 constant RANDOM_REGISTRY_ID = keccak256(abi.encodePacked("Random"));
  bytes32 constant SORTED_ORACLES_REGISTRY_ID = keccak256(abi.encodePacked("SortedOracles"));
  bytes32 constant STABLE_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("StableToken"));
  bytes32 constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked("Validators"));
  

  IRegistry public registry;

  modifier onlyRegisteredContract(bytes32 identifierHash) {
    require(registry.getAddressForOrDie(identifierHash) == msg.sender, "only registered contract");
    _;
  }

  modifier onlyRegisteredContracts(bytes32[] memory identifierHashes) {
    require(registry.isOneOf(identifierHashes, msg.sender), "only registered contracts");
    _;
  }

  
  function setRegistry(address registryAddress) public onlyOwner {
    require(registryAddress != address(0), "Cannot register the null address");
    registry = IRegistry(registryAddress);
    emit RegistrySet(registryAddress);
  }

  function getAccounts() internal view returns (IAccounts) {
    return IAccounts(registry.getAddressForOrDie(ACCOUNTS_REGISTRY_ID));
  }

  function getAttestations() internal view returns (IAttestations) {
    return IAttestations(registry.getAddressForOrDie(ATTESTATIONS_REGISTRY_ID));
  }

  function getElection() internal view returns (IElection) {
    return IElection(registry.getAddressForOrDie(ELECTION_REGISTRY_ID));
  }

  function getExchange() internal view returns (IExchange) {
    return IExchange(registry.getAddressForOrDie(EXCHANGE_REGISTRY_ID));
  }

  function getFeeCurrencyWhitelistRegistry() internal view returns (IFeeCurrencyWhitelist) {
    return IFeeCurrencyWhitelist(registry.getAddressForOrDie(FEE_CURRENCY_WHITELIST_REGISTRY_ID));
  }

  function getFreezer() internal view returns (IFreezer) {
    return IFreezer(registry.getAddressForOrDie(FREEZER_REGISTRY_ID));
  }

  function getGoldToken() internal view returns (IERC20) {
    return IERC20(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID));
  }

  function getGovernance() internal view returns (IGovernance) {
    return IGovernance(registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID));
  }

  function getLockedGold() internal view returns (ILockedGold) {
    return ILockedGold(registry.getAddressForOrDie(LOCKED_GOLD_REGISTRY_ID));
  }

  function getRandom() internal view returns (IRandom) {
    return IRandom(registry.getAddressForOrDie(RANDOM_REGISTRY_ID));
  }

  function getReserve() internal view returns (IReserve) {
    return IReserve(registry.getAddressForOrDie(RESERVE_REGISTRY_ID));
  }

  function getSortedOracles() internal view returns (ISortedOracles) {
    return ISortedOracles(registry.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID));
  }

  function getStableToken() internal view returns (IStableToken) {
    return IStableToken(registry.getAddressForOrDie(STABLE_TOKEN_REGISTRY_ID));
  }

  function getValidators() internal view returns (IValidators) {
    return IValidators(registry.getAddressForOrDie(VALIDATORS_REGISTRY_ID));
  }
}

contract UsingPrecompiles {
  using SafeMath for uint256;

  address constant TRANSFER = address(0xff - 2);
  address constant FRACTION_MUL = address(0xff - 3);
  address constant PROOF_OF_POSSESSION = address(0xff - 4);
  address constant GET_VALIDATOR = address(0xff - 5);
  address constant NUMBER_VALIDATORS = address(0xff - 6);
  address constant EPOCH_SIZE = address(0xff - 7);
  address constant BLOCK_NUMBER_FROM_HEADER = address(0xff - 8);
  address constant HASH_HEADER = address(0xff - 9);
  address constant GET_PARENT_SEAL_BITMAP = address(0xff - 10);
  address constant GET_VERIFIED_SEAL_BITMAP = address(0xff - 11);

  
  function fractionMulExp(
    uint256 aNumerator,
    uint256 aDenominator,
    uint256 bNumerator,
    uint256 bDenominator,
    uint256 exponent,
    uint256 _decimals
  ) public view returns (uint256, uint256) {
    require(aDenominator != 0 && bDenominator != 0, "a denominator is zero");
    uint256 returnNumerator;
    uint256 returnDenominator;
    bool success;
    bytes memory out;
    (success, out) = FRACTION_MUL.staticcall(
      abi.encodePacked(aNumerator, aDenominator, bNumerator, bDenominator, exponent, _decimals)
    );
    require(success, "error calling fractionMulExp precompile");
    returnNumerator = getUint256FromBytes(out, 0);
    returnDenominator = getUint256FromBytes(out, 32);
    return (returnNumerator, returnDenominator);
  }

  
  function getEpochSize() public view returns (uint256) {
    bytes memory out;
    bool success;
    (success, out) = EPOCH_SIZE.staticcall(abi.encodePacked());
    require(success, "error calling getEpochSize precompile");
    return getUint256FromBytes(out, 0);
  }

  
  function getEpochNumberOfBlock(uint256 blockNumber) public view returns (uint256) {
    return epochNumberOfBlock(blockNumber, getEpochSize());
  }

  
  function getEpochNumber() public view returns (uint256) {
    return getEpochNumberOfBlock(block.number);
  }

  
  function epochNumberOfBlock(uint256 blockNumber, uint256 epochSize)
    internal
    pure
    returns (uint256)
  {
    
    uint256 epochNumber = blockNumber / epochSize;
    if (blockNumber % epochSize == 0) {
      return epochNumber;
    } else {
      return epochNumber + 1;
    }
  }

  
  function validatorSignerAddressFromCurrentSet(uint256 index) public view returns (address) {
    bytes memory out;
    bool success;
    (success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, uint256(block.number)));
    require(success, "error calling validatorSignerAddressFromCurrentSet precompile");
    return address(getUint256FromBytes(out, 0));
  }

  
  function validatorSignerAddressFromSet(uint256 index, uint256 blockNumber)
    public
    view
    returns (address)
  {
    bytes memory out;
    bool success;
    (success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, blockNumber));
    require(success, "error calling validatorSignerAddressFromSet precompile");
    return address(getUint256FromBytes(out, 0));
  }

  
  function numberValidatorsInCurrentSet() public view returns (uint256) {
    bytes memory out;
    bool success;
    (success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(uint256(block.number)));
    require(success, "error calling numberValidatorsInCurrentSet precompile");
    return getUint256FromBytes(out, 0);
  }

  
  function numberValidatorsInSet(uint256 blockNumber) public view returns (uint256) {
    bytes memory out;
    bool success;
    (success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(blockNumber));
    require(success, "error calling numberValidatorsInSet precompile");
    return getUint256FromBytes(out, 0);
  }

  
  function checkProofOfPossession(address sender, bytes memory blsKey, bytes memory blsPop)
    public
    view
    returns (bool)
  {
    bool success;
    (success, ) = PROOF_OF_POSSESSION.staticcall(abi.encodePacked(sender, blsKey, blsPop));
    return success;
  }

  
  function getBlockNumberFromHeader(bytes memory header) public view returns (uint256) {
    bytes memory out;
    bool success;
    (success, out) = BLOCK_NUMBER_FROM_HEADER.staticcall(abi.encodePacked(header));
    require(success, "error calling getBlockNumberFromHeader precompile");
    return getUint256FromBytes(out, 0);
  }

  
  function hashHeader(bytes memory header) public view returns (bytes32) {
    bytes memory out;
    bool success;
    (success, out) = HASH_HEADER.staticcall(abi.encodePacked(header));
    require(success, "error calling hashHeader precompile");
    return getBytes32FromBytes(out, 0);
  }

  
  function getParentSealBitmap(uint256 blockNumber) public view returns (bytes32) {
    bytes memory out;
    bool success;
    (success, out) = GET_PARENT_SEAL_BITMAP.staticcall(abi.encodePacked(blockNumber));
    require(success, "error calling getParentSealBitmap precompile");
    return getBytes32FromBytes(out, 0);
  }

  
  function getVerifiedSealBitmapFromHeader(bytes memory header) public view returns (bytes32) {
    bytes memory out;
    bool success;
    (success, out) = GET_VERIFIED_SEAL_BITMAP.staticcall(abi.encodePacked(header));
    require(success, "error calling getVerifiedSealBitmapFromHeader precompile");
    return getBytes32FromBytes(out, 0);
  }

  
  function getUint256FromBytes(bytes memory bs, uint256 start) internal pure returns (uint256) {
    return uint256(getBytes32FromBytes(bs, start));
  }

  
  function getBytes32FromBytes(bytes memory bs, uint256 start) internal pure returns (bytes32) {
    require(bs.length >= start + 32, "slicing out of range");
    bytes32 x;
    assembly {
      x := mload(add(bs, add(start, 32)))
    }
    return x;
  }

  
  function minQuorumSize(uint256 blockNumber) public view returns (uint256) {
    return numberValidatorsInSet(blockNumber).mul(2).add(2).div(3);
  }

  
  function minQuorumSizeInCurrentSet() public view returns (uint256) {
    return minQuorumSize(block.number);
  }

}

contract ReentrancyGuard {
  
  uint256 private _guardCounter;

  constructor() internal {
    
    
    _guardCounter = 1;
  }

  
  modifier nonReentrant() {
    _guardCounter += 1;
    uint256 localCounter = _guardCounter;
    _;
    require(localCounter == _guardCounter, "reentrant call");
  }
}

contract Validators is
  IValidators,
  Ownable,
  ReentrancyGuard,
  Initializable,
  UsingRegistry,
  UsingPrecompiles,
  CalledByVm
{
  using FixidityLib for FixidityLib.Fraction;
  using AddressLinkedList for LinkedList.List;
  using SafeMath for uint256;
  using BytesLib for bytes;

  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  struct LockedGoldRequirements {
    uint256 value;
    
    uint256 duration;
  }

  struct ValidatorGroup {
    bool exists;
    LinkedList.List members;
    FixidityLib.Fraction commission;
    FixidityLib.Fraction nextCommission;
    uint256 nextCommissionBlock;
    
    uint256[] sizeHistory;
    SlashingInfo slashInfo;
  }

  
  struct MembershipHistoryEntry {
    uint256 epochNumber;
    address group;
  }

  
  
  
  
  struct MembershipHistory {
    
    uint256 tail;
    
    uint256 numEntries;
    mapping(uint256 => MembershipHistoryEntry) entries;
    uint256 lastRemovedFromGroupTimestamp;
  }

  struct SlashingInfo {
    FixidityLib.Fraction multiplier;
    uint256 lastSlashed;
  }

  struct PublicKeys {
    bytes ecdsa;
    bytes bls;
  }

  struct Validator {
    PublicKeys publicKeys;
    address affiliation;
    FixidityLib.Fraction score;
    MembershipHistory membershipHistory;
  }

  
  struct ValidatorScoreParameters {
    uint256 exponent;
    FixidityLib.Fraction adjustmentSpeed;
  }

  mapping(address => ValidatorGroup) private groups;
  mapping(address => Validator) private validators;
  address[] private registeredGroups;
  address[] private registeredValidators;
  LockedGoldRequirements public validatorLockedGoldRequirements;
  LockedGoldRequirements public groupLockedGoldRequirements;
  ValidatorScoreParameters private validatorScoreParameters;
  uint256 public membershipHistoryLength;
  uint256 public maxGroupSize;
  
  uint256 public commissionUpdateDelay;
  uint256 public slashingMultiplierResetPeriod;

  event MaxGroupSizeSet(uint256 size);
  event CommissionUpdateDelaySet(uint256 delay);
  event ValidatorScoreParametersSet(uint256 exponent, uint256 adjustmentSpeed);
  event GroupLockedGoldRequirementsSet(uint256 value, uint256 duration);
  event ValidatorLockedGoldRequirementsSet(uint256 value, uint256 duration);
  event MembershipHistoryLengthSet(uint256 length);
  event ValidatorRegistered(address indexed validator);
  event ValidatorDeregistered(address indexed validator);
  event ValidatorAffiliated(address indexed validator, address indexed group);
  event ValidatorDeaffiliated(address indexed validator, address indexed group);
  event ValidatorEcdsaPublicKeyUpdated(address indexed validator, bytes ecdsaPublicKey);
  event ValidatorBlsPublicKeyUpdated(address indexed validator, bytes blsPublicKey);
  event ValidatorScoreUpdated(address indexed validator, uint256 score, uint256 epochScore);
  event ValidatorGroupRegistered(address indexed group, uint256 commission);
  event ValidatorGroupDeregistered(address indexed group);
  event ValidatorGroupMemberAdded(address indexed group, address indexed validator);
  event ValidatorGroupMemberRemoved(address indexed group, address indexed validator);
  event ValidatorGroupMemberReordered(address indexed group, address indexed validator);
  event ValidatorGroupCommissionUpdateQueued(
    address indexed group,
    uint256 commission,
    uint256 activationBlock
  );
  event ValidatorGroupCommissionUpdated(address indexed group, uint256 commission);
  event ValidatorEpochPaymentDistributed(
    address indexed validator,
    uint256 validatorPayment,
    address indexed group,
    uint256 groupPayment
  );

  modifier onlySlasher() {
    require(getLockedGold().isSlasher(msg.sender), "Only registered slasher can call");
    _;
  }

  
  function initialize(
    address registryAddress,
    uint256 groupRequirementValue,
    uint256 groupRequirementDuration,
    uint256 validatorRequirementValue,
    uint256 validatorRequirementDuration,
    uint256 validatorScoreExponent,
    uint256 validatorScoreAdjustmentSpeed,
    uint256 _membershipHistoryLength,
    uint256 _slashingMultiplierResetPeriod,
    uint256 _maxGroupSize,
    uint256 _commissionUpdateDelay
  ) external initializer {
    _transferOwnership(msg.sender);
    setRegistry(registryAddress);
    setGroupLockedGoldRequirements(groupRequirementValue, groupRequirementDuration);
    setValidatorLockedGoldRequirements(validatorRequirementValue, validatorRequirementDuration);
    setValidatorScoreParameters(validatorScoreExponent, validatorScoreAdjustmentSpeed);
    setMaxGroupSize(_maxGroupSize);
    setCommissionUpdateDelay(_commissionUpdateDelay);
    setMembershipHistoryLength(_membershipHistoryLength);
    setSlashingMultiplierResetPeriod(_slashingMultiplierResetPeriod);
  }

  
  function setCommissionUpdateDelay(uint256 delay) public onlyOwner {
    require(delay != commissionUpdateDelay, "commission update delay not changed");
    commissionUpdateDelay = delay;
    emit CommissionUpdateDelaySet(delay);
  }

  
  function setMaxGroupSize(uint256 size) public onlyOwner returns (bool) {
    require(0 < size, "Max group size cannot be zero");
    require(size != maxGroupSize, "Max group size not changed");
    maxGroupSize = size;
    emit MaxGroupSizeSet(size);
    return true;
  }

  
  function setMembershipHistoryLength(uint256 length) public onlyOwner returns (bool) {
    require(0 < length, "Membership history length cannot be zero");
    require(length != membershipHistoryLength, "Membership history length not changed");
    membershipHistoryLength = length;
    emit MembershipHistoryLengthSet(length);
    return true;
  }

  
  function setValidatorScoreParameters(uint256 exponent, uint256 adjustmentSpeed)
    public
    onlyOwner
    returns (bool)
  {
    require(
      adjustmentSpeed <= FixidityLib.fixed1().unwrap(),
      "Adjustment speed cannot be larger than 1"
    );
    require(
      exponent != validatorScoreParameters.exponent ||
        !FixidityLib.wrap(adjustmentSpeed).equals(validatorScoreParameters.adjustmentSpeed),
      "Adjustment speed and exponent not changed"
    );
    validatorScoreParameters = ValidatorScoreParameters(
      exponent,
      FixidityLib.wrap(adjustmentSpeed)
    );
    emit ValidatorScoreParametersSet(exponent, adjustmentSpeed);
    return true;
  }

  
  function getMaxGroupSize() external view returns (uint256) {
    return maxGroupSize;
  }

  
  function getCommissionUpdateDelay() external view returns (uint256) {
    return commissionUpdateDelay;
  }

  
  function setGroupLockedGoldRequirements(uint256 value, uint256 duration)
    public
    onlyOwner
    returns (bool)
  {
    LockedGoldRequirements storage requirements = groupLockedGoldRequirements;
    require(
      value != requirements.value || duration != requirements.duration,
      "Group requirements not changed"
    );
    groupLockedGoldRequirements = LockedGoldRequirements(value, duration);
    emit GroupLockedGoldRequirementsSet(value, duration);
    return true;
  }

  
  function setValidatorLockedGoldRequirements(uint256 value, uint256 duration)
    public
    onlyOwner
    returns (bool)
  {
    LockedGoldRequirements storage requirements = validatorLockedGoldRequirements;
    require(
      value != requirements.value || duration != requirements.duration,
      "Validator requirements not changed"
    );
    validatorLockedGoldRequirements = LockedGoldRequirements(value, duration);
    emit ValidatorLockedGoldRequirementsSet(value, duration);
    return true;
  }

  
  function registerValidator(
    bytes calldata ecdsaPublicKey,
    bytes calldata blsPublicKey,
    bytes calldata blsPop
  ) external nonReentrant returns (bool) {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(!isValidator(account) && !isValidatorGroup(account), "Already registered");
    uint256 lockedGoldBalance = getLockedGold().getAccountTotalLockedGold(account);
    require(lockedGoldBalance >= validatorLockedGoldRequirements.value, "Deposit too small");
    Validator storage validator = validators[account];
    address signer = getAccounts().getValidatorSigner(account);
    _updateEcdsaPublicKey(validator, account, signer, ecdsaPublicKey);
    _updateBlsPublicKey(validator, account, blsPublicKey, blsPop);
    registeredValidators.push(account);
    updateMembershipHistory(account, address(0));
    emit ValidatorRegistered(account);
    return true;
  }

  
  function getValidatorScoreParameters() external view returns (uint256, uint256) {
    return (validatorScoreParameters.exponent, validatorScoreParameters.adjustmentSpeed.unwrap());
  }

  
  function getMembershipHistory(address account)
    external
    view
    returns (uint256[] memory, address[] memory, uint256, uint256)
  {
    MembershipHistory storage history = validators[account].membershipHistory;
    uint256[] memory epochs = new uint256[](history.numEntries);
    address[] memory membershipGroups = new address[](history.numEntries);
    for (uint256 i = 0; i < history.numEntries; i = i.add(1)) {
      uint256 index = history.tail.add(i);
      epochs[i] = history.entries[index].epochNumber;
      membershipGroups[i] = history.entries[index].group;
    }
    return (epochs, membershipGroups, history.lastRemovedFromGroupTimestamp, history.tail);
  }

  
  function calculateEpochScore(uint256 uptime) public view returns (uint256) {
    require(uptime <= FixidityLib.fixed1().unwrap(), "Uptime cannot be larger than one");
    uint256 numerator;
    uint256 denominator;
    (numerator, denominator) = fractionMulExp(
      FixidityLib.fixed1().unwrap(),
      FixidityLib.fixed1().unwrap(),
      uptime,
      FixidityLib.fixed1().unwrap(),
      validatorScoreParameters.exponent,
      18
    );
    return FixidityLib.newFixedFraction(numerator, denominator).unwrap();
  }

  
  function calculateGroupEpochScore(uint256[] calldata uptimes) external view returns (uint256) {
    require(uptimes.length > 0, "Uptime array empty");
    require(uptimes.length <= maxGroupSize, "Uptime array larger than maximum group size");
    FixidityLib.Fraction memory sum;
    for (uint256 i = 0; i < uptimes.length; i = i.add(1)) {
      sum = sum.add(FixidityLib.wrap(calculateEpochScore(uptimes[i])));
    }
    return sum.divide(FixidityLib.newFixed(uptimes.length)).unwrap();
  }

  
  function updateValidatorScoreFromSigner(address signer, uint256 uptime) external onlyVm() {
    _updateValidatorScoreFromSigner(signer, uptime);
  }

  
  function _updateValidatorScoreFromSigner(address signer, uint256 uptime) internal {
    address account = getAccounts().signerToAccount(signer);
    require(isValidator(account), "Not a validator");

    FixidityLib.Fraction memory epochScore = FixidityLib.wrap(calculateEpochScore(uptime));
    FixidityLib.Fraction memory newComponent = validatorScoreParameters.adjustmentSpeed.multiply(
      epochScore
    );

    FixidityLib.Fraction memory currentComponent = FixidityLib.fixed1().subtract(
      validatorScoreParameters.adjustmentSpeed
    );
    currentComponent = currentComponent.multiply(validators[account].score);
    validators[account].score = FixidityLib.wrap(
      Math.min(epochScore.unwrap(), newComponent.add(currentComponent).unwrap())
    );
    emit ValidatorScoreUpdated(account, validators[account].score.unwrap(), epochScore.unwrap());
  }

  
  function distributeEpochPaymentsFromSigner(address signer, uint256 maxPayment)
    external
    onlyVm()
    returns (uint256)
  {
    return _distributeEpochPaymentsFromSigner(signer, maxPayment);
  }

  
  function _distributeEpochPaymentsFromSigner(address signer, uint256 maxPayment)
    internal
    returns (uint256)
  {
    address account = getAccounts().signerToAccount(signer);
    require(isValidator(account), "Not a validator");
    
    
    address group = getMembershipInLastEpoch(account);
    require(group != address(0), "Validator not registered with a group");
    
    
    if (meetsAccountLockedGoldRequirements(account) && meetsAccountLockedGoldRequirements(group)) {
      FixidityLib.Fraction memory totalPayment = FixidityLib
        .newFixed(maxPayment)
        .multiply(validators[account].score)
        .multiply(groups[group].slashInfo.multiplier);
      uint256 groupPayment = totalPayment.multiply(groups[group].commission).fromFixed();
      uint256 validatorPayment = totalPayment.fromFixed().sub(groupPayment);
      getStableToken().mint(group, groupPayment);
      getStableToken().mint(account, validatorPayment);
      emit ValidatorEpochPaymentDistributed(account, validatorPayment, group, groupPayment);
      return totalPayment.fromFixed();
    } else {
      return 0;
    }
  }

  
  function deregisterValidator(uint256 index) external nonReentrant returns (bool) {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(isValidator(account), "Not a validator");

    
    
    Validator storage validator = validators[account];
    if (validator.affiliation != address(0)) {
      require(
        !groups[validator.affiliation].members.contains(account),
        "Has been group member recently"
      );
    }
    uint256 requirementEndTime = validator.membershipHistory.lastRemovedFromGroupTimestamp.add(
      validatorLockedGoldRequirements.duration
    );
    require(requirementEndTime < now, "Not yet requirement end time");

    
    deleteElement(registeredValidators, account, index);
    delete validators[account];
    emit ValidatorDeregistered(account);
    return true;
  }

  
  function affiliate(address group) external nonReentrant returns (bool) {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(isValidator(account), "Not a validator");
    require(isValidatorGroup(group), "Not a validator group");
    require(meetsAccountLockedGoldRequirements(account), "Validator doesn't meet requirements");
    require(meetsAccountLockedGoldRequirements(group), "Group doesn't meet requirements");
    Validator storage validator = validators[account];
    if (validator.affiliation != address(0)) {
      _deaffiliate(validator, account);
    }
    validator.affiliation = group;
    emit ValidatorAffiliated(account, group);
    return true;
  }

  
  function deaffiliate() external nonReentrant returns (bool) {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(isValidator(account), "Not a validator");
    Validator storage validator = validators[account];
    require(validator.affiliation != address(0), "deaffiliate: not affiliated");
    _deaffiliate(validator, account);
    return true;
  }

  
  function updateBlsPublicKey(bytes calldata blsPublicKey, bytes calldata blsPop)
    external
    returns (bool)
  {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(isValidator(account), "Not a validator");
    Validator storage validator = validators[account];
    require(
      _updateBlsPublicKey(validator, account, blsPublicKey, blsPop),
      "Error updating BLS public key"
    );
    return true;
  }

  
  function _updateBlsPublicKey(
    Validator storage validator,
    address account,
    bytes memory blsPublicKey,
    bytes memory blsPop
  ) private returns (bool) {
    require(blsPublicKey.length == 96, "Wrong BLS public key length");
    require(blsPop.length == 48, "Wrong BLS PoP length");
    require(checkProofOfPossession(account, blsPublicKey, blsPop), "Invalid BLS PoP");
    validator.publicKeys.bls = blsPublicKey;
    emit ValidatorBlsPublicKeyUpdated(account, blsPublicKey);
    return true;
  }

  
  function updateEcdsaPublicKey(address account, address signer, bytes calldata ecdsaPublicKey)
    external
    onlyRegisteredContract(ACCOUNTS_REGISTRY_ID)
    returns (bool)
  {
    require(isValidator(account), "Not a validator");
    Validator storage validator = validators[account];
    require(
      _updateEcdsaPublicKey(validator, account, signer, ecdsaPublicKey),
      "Error updating ECDSA public key"
    );
    return true;
  }

  
  function _updateEcdsaPublicKey(
    Validator storage validator,
    address account,
    address signer,
    bytes memory ecdsaPublicKey
  ) private returns (bool) {
    require(ecdsaPublicKey.length == 64, "Wrong ECDSA public key length");
    require(
      address(uint160(uint256(keccak256(ecdsaPublicKey)))) == signer,
      "ECDSA key does not match signer"
    );
    validator.publicKeys.ecdsa = ecdsaPublicKey;
    emit ValidatorEcdsaPublicKeyUpdated(account, ecdsaPublicKey);
    return true;
  }

  
  function updatePublicKeys(
    address account,
    address signer,
    bytes calldata ecdsaPublicKey,
    bytes calldata blsPublicKey,
    bytes calldata blsPop
  ) external onlyRegisteredContract(ACCOUNTS_REGISTRY_ID) returns (bool) {
    require(isValidator(account), "Not a validator");
    Validator storage validator = validators[account];
    require(
      _updateEcdsaPublicKey(validator, account, signer, ecdsaPublicKey),
      "Error updating ECDSA public key"
    );
    require(
      _updateBlsPublicKey(validator, account, blsPublicKey, blsPop),
      "Error updating BLS public key"
    );
    return true;
  }

  
  function registerValidatorGroup(uint256 commission) external nonReentrant returns (bool) {
    require(commission <= FixidityLib.fixed1().unwrap(), "Commission can't be greater than 100%");
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(!isValidator(account), "Already registered as validator");
    require(!isValidatorGroup(account), "Already registered as group");
    uint256 lockedGoldBalance = getLockedGold().getAccountTotalLockedGold(account);
    require(lockedGoldBalance >= groupLockedGoldRequirements.value, "Not enough locked gold");
    ValidatorGroup storage group = groups[account];
    group.exists = true;
    group.commission = FixidityLib.wrap(commission);
    group.slashInfo = SlashingInfo(FixidityLib.fixed1(), 0);
    registeredGroups.push(account);
    emit ValidatorGroupRegistered(account, commission);
    return true;
  }

  
  function deregisterValidatorGroup(uint256 index) external nonReentrant returns (bool) {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    
    
    require(isValidatorGroup(account), "Not a validator group");
    require(groups[account].members.numElements == 0, "Validator group not empty");
    uint256[] storage sizeHistory = groups[account].sizeHistory;
    if (sizeHistory.length > 1) {
      require(
        sizeHistory[1].add(groupLockedGoldRequirements.duration) < now,
        "Hasn't been empty for long enough"
      );
    }
    delete groups[account];
    deleteElement(registeredGroups, account, index);
    emit ValidatorGroupDeregistered(account);
    return true;
  }

  
  function addMember(address validator) external nonReentrant returns (bool) {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(groups[account].members.numElements > 0, "Validator group empty");
    return _addMember(account, validator, address(0), address(0));
  }

  
  function addFirstMember(address validator, address lesser, address greater)
    external
    nonReentrant
    returns (bool)
  {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(groups[account].members.numElements == 0, "Validator group not empty");
    return _addMember(account, validator, lesser, greater);
  }

  
  function _addMember(address group, address validator, address lesser, address greater)
    private
    returns (bool)
  {
    require(isValidatorGroup(group) && isValidator(validator), "Not validator and group");
    ValidatorGroup storage _group = groups[group];
    require(_group.members.numElements < maxGroupSize, "group would exceed maximum size");
    require(validators[validator].affiliation == group, "Not affiliated to group");
    require(!_group.members.contains(validator), "Already in group");
    uint256 numMembers = _group.members.numElements.add(1);
    _group.members.push(validator);
    require(meetsAccountLockedGoldRequirements(group), "Group requirements not met");
    require(meetsAccountLockedGoldRequirements(validator), "Validator requirements not met");
    if (numMembers == 1) {
      getElection().markGroupEligible(group, lesser, greater);
    }
    updateMembershipHistory(validator, group);
    updateSizeHistory(group, numMembers.sub(1));
    emit ValidatorGroupMemberAdded(group, validator);
    return true;
  }

  
  function removeMember(address validator) external nonReentrant returns (bool) {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(isValidatorGroup(account) && isValidator(validator), "is not group and validator");
    return _removeMember(account, validator);
  }

  
  function reorderMember(address validator, address lesserMember, address greaterMember)
    external
    nonReentrant
    returns (bool)
  {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(isValidatorGroup(account), "Not a group");
    require(isValidator(validator), "Not a validator");
    ValidatorGroup storage group = groups[account];
    require(group.members.contains(validator), "Not a member of the group");
    group.members.update(validator, lesserMember, greaterMember);
    emit ValidatorGroupMemberReordered(account, validator);
    return true;
  }

  
  function setNextCommissionUpdate(uint256 commission) external {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(isValidatorGroup(account), "Not a validator group");
    ValidatorGroup storage group = groups[account];
    require(commission <= FixidityLib.fixed1().unwrap(), "Commission can't be greater than 100%");
    require(commission != group.commission.unwrap(), "Commission must be different");

    group.nextCommission = FixidityLib.wrap(commission);
    group.nextCommissionBlock = block.number.add(commissionUpdateDelay);
    emit ValidatorGroupCommissionUpdateQueued(account, commission, group.nextCommissionBlock);
  }
  
  function updateCommission() external {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(isValidatorGroup(account), "Not a validator group");
    ValidatorGroup storage group = groups[account];

    require(group.nextCommissionBlock != 0, "No commission update queued");
    require(group.nextCommissionBlock <= block.number, "Can't apply commission update yet");

    group.commission = group.nextCommission;
    delete group.nextCommission;
    delete group.nextCommissionBlock;
    emit ValidatorGroupCommissionUpdated(account, group.commission.unwrap());
  }

  
  function getAccountLockedGoldRequirement(address account) public view returns (uint256) {
    if (isValidator(account)) {
      return validatorLockedGoldRequirements.value;
    } else if (isValidatorGroup(account)) {
      uint256 multiplier = Math.max(1, groups[account].members.numElements);
      uint256[] storage sizeHistory = groups[account].sizeHistory;
      if (sizeHistory.length > 0) {
        for (uint256 i = sizeHistory.length.sub(1); i > 0; i = i.sub(1)) {
          if (sizeHistory[i].add(groupLockedGoldRequirements.duration) >= now) {
            multiplier = Math.max(i, multiplier);
            break;
          }
        }
      }
      return groupLockedGoldRequirements.value.mul(multiplier);
    }
    return 0;
  }

  
  function meetsAccountLockedGoldRequirements(address account) public view returns (bool) {
    uint256 balance = getLockedGold().getAccountTotalLockedGold(account);
    return balance >= getAccountLockedGoldRequirement(account);
  }

  
  function getValidatorBlsPublicKeyFromSigner(address signer)
    external
    view
    returns (bytes memory blsPublicKey)
  {
    address account = getAccounts().signerToAccount(signer);
    require(isValidator(account), "Not a validator");
    return validators[account].publicKeys.bls;
  }

  
  function getValidator(address account)
    public
    view
    returns (
      bytes memory ecdsaPublicKey,
      bytes memory blsPublicKey,
      address affiliation,
      uint256 score,
      address signer
    )
  {
    require(isValidator(account), "Not a validator");
    Validator storage validator = validators[account];
    return (
      validator.publicKeys.ecdsa,
      validator.publicKeys.bls,
      validator.affiliation,
      validator.score.unwrap(),
      getAccounts().getValidatorSigner(account)
    );
  }

  
  function getValidatorGroup(address account)
    external
    view
    returns (address[] memory, uint256, uint256, uint256, uint256[] memory, uint256, uint256)
  {
    require(isValidatorGroup(account), "Not a validator group");
    ValidatorGroup storage group = groups[account];
    return (
      group.members.getKeys(),
      group.commission.unwrap(),
      group.nextCommission.unwrap(),
      group.nextCommissionBlock,
      group.sizeHistory,
      group.slashInfo.multiplier.unwrap(),
      group.slashInfo.lastSlashed
    );
  }

  
  function getGroupNumMembers(address account) public view returns (uint256) {
    require(isValidatorGroup(account), "Not validator group");
    return groups[account].members.numElements;
  }

  
  function getTopGroupValidators(address account, uint256 n)
    external
    view
    returns (address[] memory)
  {
    address[] memory topAccounts = groups[account].members.headN(n);
    address[] memory topValidators = new address[](n);
    for (uint256 i = 0; i < n; i = i.add(1)) {
      topValidators[i] = getAccounts().getValidatorSigner(topAccounts[i]);
    }
    return topValidators;
  }

  
  function getGroupsNumMembers(address[] calldata accounts)
    external
    view
    returns (uint256[] memory)
  {
    uint256[] memory numMembers = new uint256[](accounts.length);
    for (uint256 i = 0; i < accounts.length; i = i.add(1)) {
      numMembers[i] = getGroupNumMembers(accounts[i]);
    }
    return numMembers;
  }

  
  function getNumRegisteredValidators() external view returns (uint256) {
    return registeredValidators.length;
  }

  
  function getValidatorLockedGoldRequirements() external view returns (uint256, uint256) {
    return (validatorLockedGoldRequirements.value, validatorLockedGoldRequirements.duration);
  }

  
  function getGroupLockedGoldRequirements() external view returns (uint256, uint256) {
    return (groupLockedGoldRequirements.value, groupLockedGoldRequirements.duration);
  }

  
  function getRegisteredValidators() external view returns (address[] memory) {
    return registeredValidators;
  }

  
  function getRegisteredValidatorSigners() external view returns (address[] memory) {
    IAccounts accounts = getAccounts();
    address[] memory signers = new address[](registeredValidators.length);
    for (uint256 i = 0; i < signers.length; i = i.add(1)) {
      signers[i] = accounts.getValidatorSigner(registeredValidators[i]);
    }
    return signers;
  }

  
  function getRegisteredValidatorGroups() external view returns (address[] memory) {
    return registeredGroups;
  }

  
  function isValidatorGroup(address account) public view returns (bool) {
    return groups[account].exists;
  }

  
  function isValidator(address account) public view returns (bool) {
    return validators[account].publicKeys.bls.length > 0;
  }

  
  function deleteElement(address[] storage list, address element, uint256 index) private {
    require(index < list.length && list[index] == element, "deleteElement: index out of range");
    uint256 lastIndex = list.length.sub(1);
    list[index] = list[lastIndex];
    delete list[lastIndex];
    list.length = lastIndex;
  }

  
  function _removeMember(address group, address validator) private returns (bool) {
    ValidatorGroup storage _group = groups[group];
    require(validators[validator].affiliation == group, "Not affiliated to group");
    require(_group.members.contains(validator), "Not a member of the group");
    _group.members.remove(validator);
    uint256 numMembers = _group.members.numElements;
    
    if (numMembers == 0) {
      getElection().markGroupIneligible(group);
    }
    updateMembershipHistory(validator, address(0));
    updateSizeHistory(group, numMembers.add(1));
    emit ValidatorGroupMemberRemoved(group, validator);
    return true;
  }

  
  function updateMembershipHistory(address account, address group) private returns (bool) {
    MembershipHistory storage history = validators[account].membershipHistory;
    uint256 epochNumber = getEpochNumber();
    uint256 head = history.numEntries == 0 ? 0 : history.tail.add(history.numEntries.sub(1));

    if (history.numEntries > 0 && group == address(0)) {
      history.lastRemovedFromGroupTimestamp = now;
    }

    if (history.entries[head].epochNumber == epochNumber) {
      
      
      history.entries[head] = MembershipHistoryEntry(epochNumber, group);
      return true;
    }

    
    uint256 index = history.numEntries == 0 ? 0 : head.add(1);
    history.entries[index] = MembershipHistoryEntry(epochNumber, group);
    if (history.numEntries < membershipHistoryLength) {
      
      history.numEntries = history.numEntries.add(1);
    } else if (history.numEntries == membershipHistoryLength) {
      
      delete history.entries[history.tail];
      history.tail = history.tail.add(1);
    } else {
      
      delete history.entries[history.tail];
      delete history.entries[history.tail.add(1)];
      history.numEntries = history.numEntries.sub(1);
      history.tail = history.tail.add(2);
    }
    return true;
  }

  
  function updateSizeHistory(address group, uint256 size) private {
    uint256[] storage sizeHistory = groups[group].sizeHistory;
    if (size == sizeHistory.length) {
      sizeHistory.push(now);
    } else if (size < sizeHistory.length) {
      sizeHistory[size] = now;
    } else {
      require(false, "Unable to update size history");
    }
  }

  
  function getMembershipInLastEpochFromSigner(address signer) external view returns (address) {
    address account = getAccounts().signerToAccount(signer);
    require(isValidator(account), "Not a validator");
    return getMembershipInLastEpoch(account);
  }

  
  function getMembershipInLastEpoch(address account) public view returns (address) {
    uint256 epochNumber = getEpochNumber();
    MembershipHistory storage history = validators[account].membershipHistory;
    uint256 head = history.numEntries == 0 ? 0 : history.tail.add(history.numEntries.sub(1));
    
    
    if (history.entries[head].epochNumber == epochNumber) {
      if (head > history.tail) {
        head = head.sub(1);
      }
    }
    return history.entries[head].group;
  }

  
  function _deaffiliate(Validator storage validator, address validatorAccount)
    private
    returns (bool)
  {
    address affiliation = validator.affiliation;
    ValidatorGroup storage group = groups[affiliation];
    if (group.members.contains(validatorAccount)) {
      _removeMember(affiliation, validatorAccount);
    }
    validator.affiliation = address(0);
    emit ValidatorDeaffiliated(validatorAccount, affiliation);
    return true;
  }

  
  function forceDeaffiliateIfValidator(address validatorAccount) external nonReentrant onlySlasher {
    if (isValidator(validatorAccount)) {
      Validator storage validator = validators[validatorAccount];
      if (validator.affiliation != address(0)) {
        _deaffiliate(validator, validatorAccount);
      }
    }
  }

  
  function setSlashingMultiplierResetPeriod(uint256 value) public nonReentrant onlyOwner {
    slashingMultiplierResetPeriod = value;
  }

  
  function resetSlashingMultiplier() external nonReentrant {
    address account = getAccounts().validatorSignerToAccount(msg.sender);
    require(isValidatorGroup(account), "Not a validator group");
    ValidatorGroup storage group = groups[account];
    require(
      now >= group.slashInfo.lastSlashed.add(slashingMultiplierResetPeriod),
      "`resetSlashingMultiplier` called before resetPeriod expired"
    );
    group.slashInfo.multiplier = FixidityLib.fixed1();
  }

  
  function halveSlashingMultiplier(address account) external nonReentrant onlySlasher {
    require(isValidatorGroup(account), "Not a validator group");
    ValidatorGroup storage group = groups[account];
    group.slashInfo.multiplier = FixidityLib.wrap(group.slashInfo.multiplier.unwrap().div(2));
    group.slashInfo.lastSlashed = now;
  }

  
  function getValidatorGroupSlashingMultiplier(address account) external view returns (uint256) {
    require(isValidatorGroup(account), "Not a validator group");
    ValidatorGroup storage group = groups[account];
    return group.slashInfo.multiplier.unwrap();
  }

  
  function groupMembershipInEpoch(address account, uint256 epochNumber, uint256 index)
    external
    view
    returns (address)
  {
    require(isValidator(account), "Not a validator");
    require(epochNumber <= getEpochNumber(), "Epoch cannot be larger than current");
    MembershipHistory storage history = validators[account].membershipHistory;
    require(index < history.tail.add(history.numEntries), "index out of bounds");
    require(index >= history.tail && history.numEntries > 0, "index out of bounds");
    bool isExactMatch = history.entries[index].epochNumber == epochNumber;
    bool isLastEntry = index.sub(history.tail) == history.numEntries.sub(1);
    bool isWithinRange = history.entries[index].epochNumber < epochNumber &&
      (history.entries[index.add(1)].epochNumber > epochNumber || isLastEntry);
    require(
      isExactMatch || isWithinRange,
      "provided index does not match provided epochNumber at index in history."
    );
    return history.entries[index].group;
  }

}
        

Contract ABI

[{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"removeMember","inputs":[{"type":"address","name":"validator"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getMembershipInLastEpoch","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"validatorSignerAddressFromCurrentSet","inputs":[{"type":"uint256","name":"index"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"initialized","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":"ecdsaPublicKey"},{"type":"bytes","name":"blsPublicKey"},{"type":"address","name":"affiliation"},{"type":"uint256","name":"score"},{"type":"address","name":"signer"}],"name":"getValidator","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"getValidatorScoreParameters","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"checkProofOfPossession","inputs":[{"type":"address","name":"sender"},{"type":"bytes","name":"blsKey"},{"type":"bytes","name":"blsPop"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"addFirstMember","inputs":[{"type":"address","name":"validator"},{"type":"address","name":"lesser"},{"type":"address","name":"greater"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":""},{"type":"address[]","name":""},{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"getMembershipHistory","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"slashingMultiplierResetPeriod","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getGroupNumMembers","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getEpochNumberOfBlock","inputs":[{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""}],"name":"getRegisteredValidatorGroups","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getMaxGroupSize","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"getVerifiedSealBitmapFromHeader","inputs":[{"type":"bytes","name":"header"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"membershipHistoryLength","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"updateEcdsaPublicKey","inputs":[{"type":"address","name":"account"},{"type":"address","name":"signer"},{"type":"bytes","name":"ecdsaPublicKey"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getNumRegisteredValidators","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getMembershipInLastEpochFromSigner","inputs":[{"type":"address","name":"signer"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isValidatorGroup","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"maxGroupSize","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"setGroupLockedGoldRequirements","inputs":[{"type":"uint256","name":"value"},{"type":"uint256","name":"duration"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"validatorSignerAddressFromSet","inputs":[{"type":"uint256","name":"index"},{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"deregisterValidatorGroup","inputs":[{"type":"uint256","name":"index"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"hashHeader","inputs":[{"type":"bytes","name":"header"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setSlashingMultiplierResetPeriod","inputs":[{"type":"uint256","name":"value"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setCommissionUpdateDelay","inputs":[{"type":"uint256","name":"delay"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"getGroupLockedGoldRequirements","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":""}],"name":"getGroupsNumMembers","inputs":[{"type":"address[]","name":"accounts"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"updatePublicKeys","inputs":[{"type":"address","name":"account"},{"type":"address","name":"signer"},{"type":"bytes","name":"ecdsaPublicKey"},{"type":"bytes","name":"blsPublicKey"},{"type":"bytes","name":"blsPop"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"minQuorumSizeInCurrentSet","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"setValidatorLockedGoldRequirements","inputs":[{"type":"uint256","name":"value"},{"type":"uint256","name":"duration"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"calculateGroupEpochScore","inputs":[{"type":"uint256[]","name":"uptimes"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"registryAddress"},{"type":"uint256","name":"groupRequirementValue"},{"type":"uint256","name":"groupRequirementDuration"},{"type":"uint256","name":"validatorRequirementValue"},{"type":"uint256","name":"validatorRequirementDuration"},{"type":"uint256","name":"validatorScoreExponent"},{"type":"uint256","name":"validatorScoreAdjustmentSpeed"},{"type":"uint256","name":"_membershipHistoryLength"},{"type":"uint256","name":"_slashingMultiplierResetPeriod"},{"type":"uint256","name":"_maxGroupSize"},{"type":"uint256","name":"_commissionUpdateDelay"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"registry","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setNextCommissionUpdate","inputs":[{"type":"uint256","name":"commission"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numberValidatorsInCurrentSet","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getBlockNumberFromHeader","inputs":[{"type":"bytes","name":"header"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"deregisterValidator","inputs":[{"type":"uint256","name":"index"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""}],"name":"getTopGroupValidators","inputs":[{"type":"address","name":"account"},{"type":"uint256","name":"n"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"calculateEpochScore","inputs":[{"type":"uint256","name":"uptime"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"reorderMember","inputs":[{"type":"address","name":"validator"},{"type":"address","name":"lesserMember"},{"type":"address","name":"greaterMember"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getEpochNumber","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numberValidatorsInSet","inputs":[{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""},{"type":"uint256","name":""},{"type":"uint256","name":""},{"type":"uint256","name":""},{"type":"uint256[]","name":""},{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"getValidatorGroup","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRegistry","inputs":[{"type":"address","name":"registryAddress"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"affiliate","inputs":[{"type":"address","name":"group"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":"blsPublicKey"}],"name":"getValidatorBlsPublicKeyFromSigner","inputs":[{"type":"address","name":"signer"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"resetSlashingMultiplier","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getCommissionUpdateDelay","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"value"},{"type":"uint256","name":"duration"}],"name":"validatorLockedGoldRequirements","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"updateBlsPublicKey","inputs":[{"type":"bytes","name":"blsPublicKey"},{"type":"bytes","name":"blsPop"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateValidatorScoreFromSigner","inputs":[{"type":"address","name":"signer"},{"type":"uint256","name":"uptime"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"getValidatorLockedGoldRequirements","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"halveSlashingMultiplier","inputs":[{"type":"address","name":"account"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"meetsAccountLockedGoldRequirements","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"value"},{"type":"uint256","name":"duration"}],"name":"groupLockedGoldRequirements","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"addMember","inputs":[{"type":"address","name":"validator"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"setValidatorScoreParameters","inputs":[{"type":"uint256","name":"exponent"},{"type":"uint256","name":"adjustmentSpeed"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""}],"name":"getRegisteredValidatorSigners","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"distributeEpochPaymentsFromSigner","inputs":[{"type":"address","name":"signer"},{"type":"uint256","name":"maxPayment"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""}],"name":"getRegisteredValidators","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getValidatorGroupSlashingMultiplier","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getAccountLockedGoldRequirement","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getEpochSize","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"commissionUpdateDelay","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"setMaxGroupSize","inputs":[{"type":"uint256","name":"size"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"forceDeaffiliateIfValidator","inputs":[{"type":"address","name":"validatorAccount"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"minQuorumSize","inputs":[{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateCommission","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"registerValidator","inputs":[{"type":"bytes","name":"ecdsaPublicKey"},{"type":"bytes","name":"blsPublicKey"},{"type":"bytes","name":"blsPop"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"groupMembershipInEpoch","inputs":[{"type":"address","name":"account"},{"type":"uint256","name":"epochNumber"},{"type":"uint256","name":"index"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"fractionMulExp","inputs":[{"type":"uint256","name":"aNumerator"},{"type":"uint256","name":"aDenominator"},{"type":"uint256","name":"bNumerator"},{"type":"uint256","name":"bDenominator"},{"type":"uint256","name":"exponent"},{"type":"uint256","name":"_decimals"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"registerValidatorGroup","inputs":[{"type":"uint256","name":"commission"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"setMembershipHistoryLength","inputs":[{"type":"uint256","name":"length"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isValidator","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"getParentSealBitmap","inputs":[{"type":"uint256","name":"blockNumber"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"deaffiliate","inputs":[],"constant":false},{"type":"event","name":"MaxGroupSizeSet","inputs":[{"type":"uint256","name":"size","indexed":false}],"anonymous":false},{"type":"event","name":"CommissionUpdateDelaySet","inputs":[{"type":"uint256","name":"delay","indexed":false}],"anonymous":false},{"type":"event","name":"ValidatorScoreParametersSet","inputs":[{"type":"uint256","name":"exponent","indexed":false},{"type":"uint256","name":"adjustmentSpeed","indexed":false}],"anonymous":false},{"type":"event","name":"GroupLockedGoldRequirementsSet","inputs":[{"type":"uint256","name":"value","indexed":false},{"type":"uint256","name":"duration","indexed":false}],"anonymous":false},{"type":"event","name":"ValidatorLockedGoldRequirementsSet","inputs":[{"type":"uint256","name":"value","indexed":false},{"type":"uint256","name":"duration","indexed":false}],"anonymous":false},{"type":"event","name":"MembershipHistoryLengthSet","inputs":[{"type":"uint256","name":"length","indexed":false}],"anonymous":false},{"type":"event","name":"ValidatorRegistered","inputs":[{"type":"address","name":"validator","indexed":true}],"anonymous":false},{"type":"event","name":"ValidatorDeregistered","inputs":[{"type":"address","name":"validator","indexed":true}],"anonymous":false},{"type":"event","name":"ValidatorAffiliated","inputs":[{"type":"address","name":"validator","indexed":true},{"type":"address","name":"group","indexed":true}],"anonymous":false},{"type":"event","name":"ValidatorDeaffiliated","inputs":[{"type":"address","name":"validator","indexed":true},{"type":"address","name":"group","indexed":true}],"anonymous":false},{"type":"event","name":"ValidatorEcdsaPublicKeyUpdated","inputs":[{"type":"address","name":"validator","indexed":true},{"type":"bytes","name":"ecdsaPublicKey","indexed":false}],"anonymous":false},{"type":"event","name":"ValidatorBlsPublicKeyUpdated","inputs":[{"type":"address","name":"validator","indexed":true},{"type":"bytes","name":"blsPublicKey","indexed":false}],"anonymous":false},{"type":"event","name":"ValidatorScoreUpdated","inputs":[{"type":"address","name":"validator","indexed":true},{"type":"uint256","name":"score","indexed":false},{"type":"uint256","name":"epochScore","indexed":false}],"anonymous":false},{"type":"event","name":"ValidatorGroupRegistered","inputs":[{"type":"address","name":"group","indexed":true},{"type":"uint256","name":"commission","indexed":false}],"anonymous":false},{"type":"event","name":"ValidatorGroupDeregistered","inputs":[{"type":"address","name":"group","indexed":true}],"anonymous":false},{"type":"event","name":"ValidatorGroupMemberAdded","inputs":[{"type":"address","name":"group","indexed":true},{"type":"address","name":"validator","indexed":true}],"anonymous":false},{"type":"event","name":"ValidatorGroupMemberRemoved","inputs":[{"type":"address","name":"group","indexed":true},{"type":"address","name":"validator","indexed":true}],"anonymous":false},{"type":"event","name":"ValidatorGroupMemberReordered","inputs":[{"type":"address","name":"group","indexed":true},{"type":"address","name":"validator","indexed":true}],"anonymous":false},{"type":"event","name":"ValidatorGroupCommissionUpdateQueued","inputs":[{"type":"address","name":"group","indexed":true},{"type":"uint256","name":"commission","indexed":false},{"type":"uint256","name":"activationBlock","indexed":false}],"anonymous":false},{"type":"event","name":"ValidatorGroupCommissionUpdated","inputs":[{"type":"address","name":"group","indexed":true},{"type":"uint256","name":"commission","indexed":false}],"anonymous":false},{"type":"event","name":"ValidatorEpochPaymentDistributed","inputs":[{"type":"address","name":"validator","indexed":true},{"type":"uint256","name":"validatorPayment","indexed":false},{"type":"address","name":"group","indexed":true},{"type":"uint256","name":"groupPayment","indexed":false}],"anonymous":false},{"type":"event","name":"RegistrySet","inputs":[{"type":"address","name":"registryAddress","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false}]
              

Contract Creation Code

0x6080604052600062000016620000c160201b60201c565b9050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35060018081905550620000c9565b600033905090565b61df3780620000d96000396000f3fe608060405234801561001057600080fd5b50600436106104965760003560e01c80638dd31e3911610262578063cb8f98e011610151578063e50e652d116100ce578063ee09831011610092578063ee098310146123df578063eff2ea3f14612425578063f2fde38b1461246b578063facd743b146124af578063fae8db0a1461250b578063fffdfccb1461254d57610496565b8063e50e652d14612145578063e7f0376614612187578063ea684f7714612191578063eb1d0b42146122cc578063ec6830721461236457610496565b8063dcff4cf611610115578063dcff4cf614612027578063df4da4611461207f578063e0e3ffe61461209d578063e1497ff7146120bb578063e33301aa1461210157610496565b8063cb8f98e014611e5f578063d55dcbcf14611eaf578063d69ef6cf14611f0e578063d93ab5ad14611f70578063dba94fcd14611fcf57610496565b8063b8f93943116101df578063c10c96ef116101a3578063c10c96ef14611d19578063c22d3bba14611d3e578063c54c1cd414611d82578063c580514014611dde578063ca6d56dc14611e0357610496565b8063b8f9394314611b98578063b915f53014611ba2578063bd9e9d9414611bc0578063bfdb741714611be5578063c0c6ad6f14611ccb57610496565b80639b2b592f116102265780639b2b592f146118f55780639b9d516114611937578063a91ee0dc14611a3b578063b591d3a514611a7f578063b730a29914611adb57610496565b80638dd31e39146117345780638f32d59b146117d757806394903a97146117f9578063988dcd1f1461183b5780639a7b3be7146118d757610496565b80635779e93d11610389578063715018a6116103065780637b103999116102ca5780637b1039991461153f57806386d81a5a1461158957806387ee8a0f146115b75780638a883626146115d55780638b16b1c6146116a45780638da5cb5b146116ea57610496565b8063715018a6146113915780637385e5da1461139b57806376c0a9ed146113b957806376f7425d1461140957806378d254561461149657610496565b80636ab951a01161034d5780636ab951a0146110c75780636c620d90146110f55780636fa47647146111235780637044775414611148578063713ea0f31461121657610496565b80635779e93d14610ecc5780635a61d15b14610eea5780635d180adb14610f3a57806360fb822c14610fb257806367960e9114610ff857610496565b806339e618e8116104175780634cd76db4116103db5780634cd76db414610cdf5780634e06fd8a14610cfd578063517f6d3314610dce57806351b5222514610dec57806352f13a4e14610e7057610496565b806339e618e814610af95780633b1eb4bf14610b515780633f27089814610b9357806343d9669914610bf25780634b2c2f4414610c1057610496565b806319113e3b1161045e57806319113e3b146107a157806323f0ab65146107c65780633173b8db1461095057806335244f51146109ec57806336407b7014610adb57610496565b80630b1ca49a1461049b5780630d1312b8146104f7578063123633ea1461057b578063158ef93e146105e95780631904bb2e1461060b575b600080fd5b6104dd600480360360208110156104b157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061256f565b604051808215151515815260200191505060405180910390f35b6105396004803603602081101561050d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612761565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105a76004803603602081101561059157600080fd5b8101908080359060200190929190505050612880565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105f16129d1565b604051808215151515815260200191505060405180910390f35b61064d6004803603602081101561062157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506129e4565b6040518080602001806020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838103835288818151815260200191508051906020019080838360005b838110156106fb5780820151818401526020810190506106e0565b50505050905090810190601f1680156107285780820380516001836020036101000a031916815260200191505b50838103825287818151815260200191508051906020019080838360005b83811015610761578082015181840152602081019050610746565b50505050905090810190601f16801561078e5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390f35b6107a9612d09565b604051808381526020018281526020019250505060405180910390f35b610936600480360360608110156107dc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561081957600080fd5b82018360208201111561082b57600080fd5b8035906020019184600183028401116401000000008311171561084d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156108b057600080fd5b8201836020820111156108c257600080fd5b803590602001918460018302840111640100000000831117156108e457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612d3c565b604051808215151515815260200191505060405180910390f35b6109d26004803603606081101561096657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612ef5565b604051808215151515815260200191505060405180910390f35b610a2e60048036036020811015610a0257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061311a565b604051808060200180602001858152602001848152602001838103835287818151815260200191508051906020019060200280838360005b83811015610a81578082015181840152602081019050610a66565b50505050905001838103825286818151815260200191508051906020019060200280838360005b83811015610ac3578082015181840152602081019050610aa8565b50505050905001965050505050505060405180910390f35b610ae36132ee565b6040518082815260200191505060405180910390f35b610b3b60048036036020811015610b0f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506132f4565b6040518082815260200191505060405180910390f35b610b7d60048036036020811015610b6757600080fd5b81019080803590602001909291905050506133be565b6040518082815260200191505060405180910390f35b610b9b6133d8565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610bde578082015181840152602081019050610bc3565b505050509050019250505060405180910390f35b610bfa613466565b6040518082815260200191505060405180910390f35b610cc960048036036020811015610c2657600080fd5b8101908080359060200190640100000000811115610c4357600080fd5b820183602082011115610c5557600080fd5b80359060200191846001830284011164010000000083111715610c7757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050613470565b6040518082815260200191505060405180910390f35b610ce7613604565b6040518082815260200191505060405180910390f35b610db460048036036060811015610d1357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610d7057600080fd5b820183602082011115610d8257600080fd5b80359060200191846001830284011164010000000083111715610da457600080fd5b909192939192939050505061360a565b604051808215151515815260200191505060405180910390f35b610dd661392f565b6040518082815260200191505060405180910390f35b610e2e60048036036020811015610e0257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061393c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610eb260048036036020811015610e8657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613a8c565b604051808215151515815260200191505060405180910390f35b610ed4613ae5565b6040518082815260200191505060405180910390f35b610f2060048036036040811015610f0057600080fd5b810190808035906020019092919080359060200190929190505050613aeb565b604051808215151515815260200191505060405180910390f35b610f7060048036036040811015610f5057600080fd5b810190808035906020019092919080359060200190929190505050613c6e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610fde60048036036020811015610fc857600080fd5b8101908080359060200190929190505050613dc0565b604051808215151515815260200191505060405180910390f35b6110b16004803603602081101561100e57600080fd5b810190808035906020019064010000000081111561102b57600080fd5b82018360208201111561103d57600080fd5b8035906020019184600183028401116401000000008311171561105f57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050614247565b6040518082815260200191505060405180910390f35b6110f3600480360360208110156110dd57600080fd5b81019080803590602001909291905050506143db565b005b6111216004803603602081101561110b57600080fd5b81019080803590602001909291905050506144ee565b005b61112b614604565b604051808381526020018281526020019250505060405180910390f35b6111bf6004803603602081101561115e57600080fd5b810190808035906020019064010000000081111561117b57600080fd5b82018360208201111561118d57600080fd5b803590602001918460208302840111640100000000831117156111af57600080fd5b909192939192939050505061461b565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156112025780820151818401526020810190506111e7565b505050509050019250505060405180910390f35b611377600480360360a081101561122c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561128957600080fd5b82018360208201111561129b57600080fd5b803590602001918460018302840111640100000000831117156112bd57600080fd5b9091929391929390803590602001906401000000008111156112de57600080fd5b8201836020820111156112f057600080fd5b8035906020019184600183028401116401000000008311171561131257600080fd5b90919293919293908035906020019064010000000081111561133357600080fd5b82018360208201111561134557600080fd5b8035906020019184600183028401116401000000008311171561136757600080fd5b90919293919293905050506146d3565b604051808215151515815260200191505060405180910390f35b611399614b02565b005b6113a3614c3b565b6040518082815260200191505060405180910390f35b6113ef600480360360408110156113cf57600080fd5b810190808035906020019092919080359060200190929190505050614c4b565b604051808215151515815260200191505060405180910390f35b6114806004803603602081101561141f57600080fd5b810190808035906020019064010000000081111561143c57600080fd5b82018360208201111561144e57600080fd5b8035906020019184602083028401116401000000008311171561147057600080fd5b9091929391929390505050614db1565b6040518082815260200191505060405180910390f35b61153d60048036036101608110156114ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190505050614f24565b005b611547615028565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6115b56004803603602081101561159f57600080fd5b810190808035906020019092919050505061504e565b005b6115bf615363565b6040518082815260200191505060405180910390f35b61168e600480360360208110156115eb57600080fd5b810190808035906020019064010000000081111561160857600080fd5b82018360208201111561161a57600080fd5b8035906020019184600183028401116401000000008311171561163c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506154aa565b6040518082815260200191505060405180910390f35b6116d0600480360360208110156116ba57600080fd5b810190808035906020019092919050505061563e565b604051808215151515815260200191505060405180910390f35b6116f2615bf2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6117806004803603604081101561174a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050615c1b565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156117c35780820151818401526020810190506117a8565b505050509050019250505060405180910390f35b6117df615ecc565b604051808215151515815260200191505060405180910390f35b6118256004803603602081101561180f57600080fd5b8101908080359060200190929190505050615f2a565b6040518082815260200191505060405180910390f35b6118bd6004803603606081101561185157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050616018565b604051808215151515815260200191505060405180910390f35b6118df616549565b6040518082815260200191505060405180910390f35b6119216004803603602081101561190b57600080fd5b8101908080359060200190929190505050616559565b6040518082815260200191505060405180910390f35b6119796004803603602081101561194d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506166a2565b60405180806020018881526020018781526020018681526020018060200185815260200184815260200183810383528a818151815260200191508051906020019060200280838360005b838110156119de5780820151818401526020810190506119c3565b50505050905001838103825286818151815260200191508051906020019060200280838360005b83811015611a20578082015181840152602081019050611a05565b50505050905001995050505050505050505060405180910390f35b611a7d60048036036020811015611a5157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050616934565b005b611ac160048036036020811015611a9557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050616ad8565b604051808215151515815260200191505060405180910390f35b611b1d60048036036020811015611af157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050616f4a565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015611b5d578082015181840152602081019050611b42565b50505050905090810190601f168015611b8a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b611ba0617170565b005b611baa617414565b6040518082815260200191505060405180910390f35b611bc861741e565b604051808381526020018281526020019250505060405180910390f35b611cb160048036036040811015611bfb57600080fd5b8101908080359060200190640100000000811115611c1857600080fd5b820183602082011115611c2a57600080fd5b80359060200191846001830284011164010000000083111715611c4c57600080fd5b909192939192939080359060200190640100000000811115611c6d57600080fd5b820183602082011115611c7f57600080fd5b80359060200191846001830284011164010000000083111715611ca157600080fd5b9091929391929390505050617430565b604051808215151515815260200191505060405180910390f35b611d1760048036036040811015611ce157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506176c6565b005b611d21617776565b604051808381526020018281526020019250505060405180910390f35b611d8060048036036020811015611d5457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061778d565b005b611dc460048036036020811015611d9857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050617a6e565b604051808215151515815260200191505060405180910390f35b611de6617b46565b604051808381526020018281526020019250505060405180910390f35b611e4560048036036020811015611e1957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050617b58565b604051808215151515815260200191505060405180910390f35b611e9560048036036040811015611e7557600080fd5b810190808035906020019092919080359060200190929190505050617d7c565b604051808215151515815260200191505060405180910390f35b611eb7617f84565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015611efa578082015181840152602081019050611edf565b505050509050019250505060405180910390f35b611f5a60048036036040811015611f2457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050618133565b6040518082815260200191505060405180910390f35b611f786181e8565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015611fbb578082015181840152602081019050611fa0565b505050509050019250505060405180910390f35b61201160048036036020811015611fe557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050618276565b6040518082815260200191505060405180910390f35b6120696004803603602081101561203d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050618362565b6040518082815260200191505060405180910390f35b6120876184e7565b6040518082815260200191505060405180910390f35b6120a5618623565b6040518082815260200191505060405180910390f35b6120e7600480360360208110156120d157600080fd5b8101908080359060200190929190505050618629565b604051808215151515815260200191505060405180910390f35b6121436004803603602081101561211757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506187da565b005b6121716004803603602081101561215b57600080fd5b8101908080359060200190929190505050618a54565b6040518082815260200191505060405180910390f35b61218f618a9f565b005b6122b2600480360360608110156121a757600080fd5b81019080803590602001906401000000008111156121c457600080fd5b8201836020820111156121d657600080fd5b803590602001918460018302840111640100000000831117156121f857600080fd5b90919293919293908035906020019064010000000081111561221957600080fd5b82018360208201111561222b57600080fd5b8035906020019184600183028401116401000000008311171561224d57600080fd5b90919293919293908035906020019064010000000081111561226e57600080fd5b82018360208201111561228057600080fd5b803590602001918460018302840111640100000000831117156122a257600080fd5b9091929391929390505050618d96565b604051808215151515815260200191505060405180910390f35b612322600480360360608110156122e257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190505050619369565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6123c2600480360360c081101561237a57600080fd5b810190808035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190803590602001909291905050506196f9565b604051808381526020018281526020019250505060405180910390f35b61240b600480360360208110156123f557600080fd5b810190808035906020019092919050505061990d565b604051808215151515815260200191505060405180910390f35b6124516004803603602081101561243b57600080fd5b8101908080359060200190929190505050619e7c565b604051808215151515815260200191505060405180910390f35b6124ad6004803603602081101561248157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050619ff3565b005b6124f1600480360360208110156124c557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061a079565b604051808215151515815260200191505060405180910390f35b6125376004803603602081101561252157600080fd5b810190808035906020019092919050505061a0de565b6040518082815260200191505060405180910390f35b61255561a227565b604051808215151515815260200191505060405180910390f35b60006001806000828254019250508190555060006001549050600061259261a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561260e57600080fd5b505afa158015612622573d6000803e3d6000fd5b505050506040513d602081101561263857600080fd5b8101908080519060200190929190505050905061265481613a8c565b801561266557506126648461a079565b5b6126d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f6973206e6f742067726f757020616e642076616c696461746f7200000000000081525060200191505060405180910390fd5b6126e1818561a60f565b925050600154811461275b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60008061276c616549565b90506000600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060040190506000808260010154146127f4576127ef6127dc6001846001015461aa6e90919063ffffffff16565b836000015461aab890919063ffffffff16565b6127f7565b60005b90508282600201600083815260200190815260200160002060000154141561283d57816000015481111561283c5761283960018261aa6e90919063ffffffff16565b90505b5b81600201600082815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169350505050919050565b60006060600060fa73ffffffffffffffffffffffffffffffffffffffff16844360405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b602083106128f957805182526020820191506020810190506020830392506128d6565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612959576040519150601f19603f3d011682016040523d82523d6000602084013e61295e565b606091505b508093508192505050806129bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603d81526020018061dc2c603d913960400191505060405180910390fd5b6129c882600061ab40565b92505050919050565b600260009054906101000a900460ff1681565b60608060008060006129f58661a079565b612a67576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905080600001600001816000016001018260020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16612afe8460030160405180602001604052908160008201548152505061ab57565b612b0661a514565b73ffffffffffffffffffffffffffffffffffffffff16634ce38b5f8c6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612b8257600080fd5b505afa158015612b96573d6000803e3d6000fd5b505050506040513d6020811015612bac57600080fd5b8101908080519060200190929190505050848054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612c525780601f10612c2757610100808354040283529160200191612c52565b820191906000526020600020905b815481529060010190602001808311612c3557829003601f168201915b50505050509450838054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612cee5780601f10612cc357610100808354040283529160200191612cee565b820191906000526020600020905b815481529060010190602001808311612cd157829003601f168201915b50505050509350955095509550955095505091939590929450565b600080600b60000154612d34600b60010160405180602001604052908160008201548152505061ab57565b915091509091565b60008060fb73ffffffffffffffffffffffffffffffffffffffff16858585604051602001808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140183805190602001908083835b60208310612dc55780518252602082019150602081019050602083039250612da2565b6001836020036101000a03801982511681845116808217855250505050505090500182805190602001908083835b60208310612e165780518252602082019150602081019050602083039250612df3565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b60208310612e7f5780518252602082019150602081019050602083039250612e5c565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612edf576040519150601f19603f3d011682016040523d82523d6000602084013e612ee4565b606091505b505080915050809150509392505050565b600060018060008282540192505081905550600060015490506000612f1861a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612f9457600080fd5b505afa158015612fa8573d6000803e3d6000fd5b505050506040513d6020811015612fbe57600080fd5b810190808051906020019092919050505090506000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101600201541461308c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f56616c696461746f722067726f7570206e6f7420656d7074790000000000000081525060200191505060405180910390fd5b6130988187878761ab65565b9250506001548114613112576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b509392505050565b6060806000806000600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060040190506060816001015460405190808252806020026020018201604052801561319b5781602001602082028038833980820191505090505b509050606082600101546040519080825280602002602001820160405280156131d35781602001602082028038833980820191505090505b50905060008090505b83600101548110156132cf57600061320182866000015461aab890919063ffffffff16565b90508460020160008281526020019081526020016000206000015484838151811061322857fe5b60200260200101818152505084600201600082815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683838151811061327957fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050506132c860018261aab890919063ffffffff16565b90506131dc565b5081818460030154856000015496509650965096505050509193509193565b60105481565b60006132ff82613a8c565b613371576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f4e6f742076616c696461746f722067726f75700000000000000000000000000081525060200191505060405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101600201549050919050565b60006133d1826133cc6184e7565b61b242565b9050919050565b6060600580548060200260200160405190810160405280929190818152602001828054801561345c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311613412575b5050505050905090565b6000600e54905090565b60006060600060f473ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b602083106134c557805182526020820191506020810190506020830392506134a2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b6020831061352c5780518252602082019150602081019050602083039250613509565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461358c576040519150601f19603f3d011682016040523d82523d6000602084013e613591565b606091505b508093508192505050806135f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603881526020018061db526038913960400191505060405180910390fd5b6135fb82600061b27a565b92505050919050565b600d5481565b600060405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156136dd57600080fd5b505afa1580156136f1573d6000803e3d6000fd5b505050506040513d602081101561370757600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16146137a1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b6137aa8661a079565b61381c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506138af81888888888080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b30b565b613921576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f4572726f72207570646174696e67204543445341207075626c6963206b65790081525060200191505060405180910390fd5b600192505050949350505050565b6000600680549050905090565b60008061394761a514565b73ffffffffffffffffffffffffffffffffffffffff166393c5c487846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156139c357600080fd5b505afa1580156139d7573d6000803e3d6000fd5b505050506040513d60208110156139ed57600080fd5b81019080805190602001909291905050509050613a098161a079565b613a7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b613a8481612761565b915050919050565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900460ff169050919050565b600e5481565b6000613af5615ecc565b613b67576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600060099050806000015484141580613b84575080600101548314155b613bf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f47726f757020726571756972656d656e7473206e6f74206368616e676564000081525060200191505060405180910390fd5b604051806040016040528085815260200184815250600960008201518160000155602082015181600101559050507f999f7ee1917e6d7ea08360edfe9250cda3eda859c38dcb71a92623665de64dd48484604051808381526020018281526020019250505060405180910390a1600191505092915050565b60006060600060fa73ffffffffffffffffffffffffffffffffffffffff16858560405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310613ce75780518252602082019150602081019050602083039250613cc4565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114613d47576040519150601f19603f3d011682016040523d82523d6000602084013e613d4c565b606091505b50809350819250505080613dab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061dc9e6036913960400191505060405180910390fd5b613db682600061ab40565b9250505092915050565b600060018060008282540192505081905550600060015490506000613de361a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613e5f57600080fd5b505afa158015613e73573d6000803e3d6000fd5b505050506040513d6020811015613e8957600080fd5b81019080805190602001909291905050509050613ea581613a8c565b613f17576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001016002015414613fd2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f56616c696461746f722067726f7570206e6f7420656d7074790000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080190506001818054905011156140ac57426140556009600101548360018154811061403c57fe5b906000526020600020015461aab890919063ffffffff16565b106140ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061de526021913960400191505060405180910390fd5b5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160006101000a81549060ff0219169055600182016000808201600090556001820160009055600282016000905550506005820160008082016000905550506006820160008082016000905550506007820160009055600882016000614155919061d8e4565b60098201600080820160008082016000905550506001820160009055505050506141816005838761b50a565b8173ffffffffffffffffffffffffffffffffffffffff167fae7e034b0748a10a219b46074b20977a9170bf4027b156c797093773619a866960405160405180910390a26001935050506001548114614241576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60006060600060f673ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b6020831061429c5780518252602082019150602081019050602083039250614279565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b6020831061430357805182526020820191506020810190506020830392506142e0565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114614363576040519150601f19603f3d011682016040523d82523d6000602084013e614368565b606091505b508093508192505050806143c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061dec06023913960400191505060405180910390fd5b6143d282600061b27a565b92505050919050565b60018060008282540192505081905550600060015490506143fa615ecc565b61446c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8160108190555060015481146144ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b6144f6615ecc565b614568576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600f548114156145c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061ddfe6023913960400191505060405180910390fd5b80600f819055507ff2da07d08fd8dc9c5dcf87ad6f540e306f884a47dd8de14b718a4d5395f1ca9b816040518082815260200191505060405180910390a150565b600080600960000154600960010154915091509091565b606080838390506040519080825280602002602001820160405280156146505781602001602082028038833980820191505090505b50905060008090505b848490508110156146c85761469585858381811061467357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166132f4565b8282815181106146a157fe5b6020026020010181815250506146c160018261aab890919063ffffffff16565b9050614659565b508091505092915050565b600060405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156147a657600080fd5b505afa1580156147ba573d6000803e3d6000fd5b505050506040513d60208110156147d057600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161461486a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b6148738a61a079565b6148e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050614978818c8c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b30b565b6149ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f4572726f72207570646174696e67204543445341207075626c6963206b65790081525060200191505060405180910390fd5b614a7e818c89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b6c7565b614af0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4572726f72207570646174696e6720424c53207075626c6963206b657900000081525060200191505060405180910390fd5b60019250505098975050505050505050565b614b0a615ecc565b614b7c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000614c4643618a54565b905090565b6000614c55615ecc565b614cc7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600060079050806000015484141580614ce4575080600101548314155b614d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602281526020018061db306022913960400191505060405180910390fd5b604051806040016040528085815260200184815250600760008201518160000155602082015181600101559050507f62d947118dd4c1f5ece7f787a9cad4e1127d14d403b71133e95792b473bf83898484604051808381526020018281526020019250505060405180910390a1600191505092915050565b6000808383905011614e2b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f557074696d6520617272617920656d707479000000000000000000000000000081525060200191505060405180910390fd5b600e54838390501115614e89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b81526020018061db05602b913960400191505060405180910390fd5b614e9161d905565b60008090505b84849050811015614ef457614ed7614ec8614ec3878785818110614eb757fe5b90506020020135615f2a565b61b90f565b8361b92d90919063ffffffff16565b9150614eed60018261aab890919063ffffffff16565b9050614e97565b50614f1b614f16614f078686905061b9d6565b8361ba6090919063ffffffff16565b61ab57565b91505092915050565b600260009054906101000a900460ff1615614fa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600260006101000a81548160ff021916908315150217905550614fcb3361bba9565b614fd48b616934565b614fde8a8a613aeb565b50614fe98888614c4b565b50614ff48686617d7c565b50614ffe82618629565b50615008816144ee565b61501184619e7c565b5061501b836143db565b5050505050505050505050565b600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061505861a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156150d457600080fd5b505afa1580156150e8573d6000803e3d6000fd5b505050506040513d60208110156150fe57600080fd5b8101908080519060200190929190505050905061511a81613a8c565b61518c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506151df6151da61bced565b61ab57565b831115615237576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061de736025913960400191505060405180910390fd5b6152588160050160405180602001604052908160008201548152505061ab57565b8314156152cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f436f6d6d697373696f6e206d75737420626520646966666572656e740000000081525060200191505060405180910390fd5b6152d68361b90f565b81600601600082015181600001559050506152fc600f544361aab890919063ffffffff16565b81600701819055508173ffffffffffffffffffffffffffffffffffffffff167f557d39a57520d9835859d4b7eda805a7f4115a59c3a374eeed488436fc62a152848360070154604051808381526020018281526020019250505060405180910390a2505050565b60006060600060f973ffffffffffffffffffffffffffffffffffffffff1643604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106153d457805182526020820191506020810190506020830392506153b1565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114615434576040519150601f19603f3d011682016040523d82523d6000602084013e615439565b606091505b50809350819250505080615498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603581526020018061dc696035913960400191505060405180910390fd5b6154a382600061ab40565b9250505090565b60006060600060f773ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b602083106154ff57805182526020820191506020810190506020830392506154dc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b602083106155665780518252602082019150602081019050602083039250615543565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146155c6576040519150601f19603f3d011682016040523d82523d6000602084013e6155cb565b606091505b5080935081925050508061562a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603181526020018061de216031913960400191505060405180910390fd5b61563582600061ab40565b92505050919050565b60006001806000828254019250508190555060006001549050600061566161a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156156dd57600080fd5b505afa1580156156f1573d6000803e3d6000fd5b505050506040513d602081101561570757600080fd5b810190808051906020019092919050505090506157238161a079565b615795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146159c957600360008260020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561591a57600080fd5b505af415801561592e573d6000803e3d6000fd5b505050506040513d602081101561594457600080fd5b8101908080519060200190929190505050156159c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f486173206265656e2067726f7570206d656d62657220726563656e746c79000081525060200191505060405180910390fd5b5b60006159ea600760010154836004016003015461aab890919063ffffffff16565b9050428110615a61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4e6f742079657420726571756972656d656e7420656e642074696d650000000081525060200191505060405180910390fd5b615a6d6006848861b50a565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160008082016000615ac2919061d918565b600182016000615ad2919061d918565b50506002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556003820160008082016000905550506004820160008082016000905560018201600090556003820160009055505050508273ffffffffffffffffffffffffffffffffffffffff167f51407fafe7ef9bec39c65a12a4885a274190991bf1e9057fcc384fc77ff1a7f060405160405180910390a2600194505050506001548114615bec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606080600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763b1cfea439091856040518363ffffffff1660e01b8152600401808381526020018281526020019250505060006040518083038186803b158015615cb857600080fd5b505af4158015615ccc573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052506020811015615cf657600080fd5b810190808051640100000000811115615d0e57600080fd5b82810190506020810184811115615d2457600080fd5b8151856020820283011164010000000082111715615d4157600080fd5b50509291905050509050606083604051908082528060200260200182016040528015615d7c5781602001602082028038833980820191505090505b50905060008090505b84811015615ec057615d9561a514565b73ffffffffffffffffffffffffffffffffffffffff16634ce38b5f848381518110615dbc57fe5b60200260200101516040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015615e2457600080fd5b505afa158015615e38573d6000803e3d6000fd5b505050506040513d6020811015615e4e57600080fd5b8101908080519060200190929190505050828281518110615e6b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050615eb960018261aab890919063ffffffff16565b9050615d85565b50809250505092915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16615f0e61bd13565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b6000615f3c615f3761bced565b61ab57565b821115615fb1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f557074696d652063616e6e6f74206265206c6172676572207468616e206f6e6581525060200191505060405180910390fd5b600080615ff5615fc7615fc261bced565b61ab57565b615fd7615fd261bced565b61ab57565b86615fe8615fe361bced565b61ab57565b600b6000015460126196f9565b809250819350505061600f61600a838361bd1b565b61ab57565b92505050919050565b60006001806000828254019250508190555060006001549050600061603b61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156160b757600080fd5b505afa1580156160cb573d6000803e3d6000fd5b505050506040513d60208110156160e157600080fd5b810190808051906020019092919050505090506160fd81613a8c565b61616f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600b8152602001807f4e6f7420612067726f757000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6161788661a079565b6161ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091896040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b1580156162b557600080fd5b505af41580156162c9573d6000803e3d6000fd5b505050506040513d60208110156162df57600080fd5b8101908080519060200190929190505050616362576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4e6f742061206d656d626572206f66207468652067726f75700000000000000081525060200191505060405180910390fd5b806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763b2f8fe9690918989896040518563ffffffff1660e01b8152600401808581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200194505050505060006040518083038186803b15801561645257600080fd5b505af4158015616466573d6000803e3d6000fd5b505050508673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f38819cc49a343985b478d72f531a35b15384c398dd80fd191a14662170f895c660405160405180910390a36001935050506001548114616541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b509392505050565b6000616554436133be565b905090565b60006060600060f973ffffffffffffffffffffffffffffffffffffffff1684604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106165ca57805182526020820191506020810190506020830392506165a7565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461662a576040519150601f19603f3d011682016040523d82523d6000602084013e61662f565b606091505b5080935081925050508061668e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e81526020018061da55602e913960400191505060405180910390fd5b61669982600061ab40565b92505050919050565b6060600080600060606000806166b788613a8c565b616729576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763fe3c7a8e90916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b1580156167c057600080fd5b505af41580156167d4573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060208110156167fe57600080fd5b81019080805164010000000081111561681657600080fd5b8281019050602081018481111561682c57600080fd5b815185602082028301116401000000008211171561684957600080fd5b50509291905050506168728260050160405180602001604052908160008201548152505061ab57565b6168938360060160405180602001604052908160008201548152505061ab57565b8360070154846008016168c08660090160000160405180602001604052908160008201548152505061ab57565b86600901600101548280548060200260200160405190810160405280929190818152602001828054801561691357602002820191906000526020600020905b8154815260200190600101908083116168ff575b50505050509250975097509750975097509750975050919395979092949650565b61693c615ecc565b6169ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415616a51576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f43616e6e6f7420726567697374657220746865206e756c6c206164647265737381525060200191505060405180910390fd5b80600260016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b60405160405180910390a250565b600060018060008282540192505081905550600060015490506000616afb61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015616b7757600080fd5b505afa158015616b8b573d6000803e3d6000fd5b505050506040513d6020811015616ba157600080fd5b81019080805190602001909291905050509050616bbd8161a079565b616c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b616c3884613a8c565b616caa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b616cb381617a6e565b616d08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061da326023913960400191505060405180910390fd5b616d1184617a6e565b616d83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f47726f757020646f65736e2774206d65657420726571756972656d656e74730081525060200191505060405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614616e2a57616e28818361bd5d565b505b848160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f91ef92227057e201e406c3451698dd780fe7672ad74328591c88d281af31581d60405160405180910390a36001935050506001548114616f44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60606000616f5661a514565b73ffffffffffffffffffffffffffffffffffffffff166393c5c487846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015616fd257600080fd5b505afa158015616fe6573d6000803e3d6000fd5b505050506040513d6020811015616ffc57600080fd5b810190808051906020019092919050505090506170188161a079565b61708a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b600460008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156171635780601f1061713857610100808354040283529160200191617163565b820191906000526020600020905b81548152906001019060200180831161714657829003601f168201915b5050505050915050919050565b6001806000828254019250508190555060006001549050600061719161a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561720d57600080fd5b505afa158015617221573d6000803e3d6000fd5b505050506040513d602081101561723757600080fd5b8101908080519060200190929190505050905061725381613a8c565b6172c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050617324601054826009016001015461aab890919063ffffffff16565b42101561737c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b81526020018061daa9603b913960400191505060405180910390fd5b61738461bced565b816009016000016000820151816000015590505050506001548114617411576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50565b6000600f54905090565b60078060000154908060010154905082565b60008061743b61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156174b757600080fd5b505afa1580156174cb573d6000803e3d6000fd5b505050506040513d60208110156174e157600080fd5b810190808051906020019092919050505090506174fd8161a079565b61756f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050617646818389898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b6c7565b6176b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4572726f72207570646174696e6720424c53207075626c6963206b657900000081525060200191505060405180910390fd5b600192505050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614617768576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f4f6e6c7920564d2063616e2063616c6c0000000000000000000000000000000081525060200191505060405180910390fd5b617772828261bf48565b5050565b600080600760000154600760010154915091509091565b60018060008282540192505081905550600060015490506177ac61c2c6565b73ffffffffffffffffffffffffffffffffffffffff166357601c5d336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561782857600080fd5b505afa15801561783c573d6000803e3d6000fd5b505050506040513d602081101561785257600080fd5b81019080805190602001909291905050506178d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f6e6c79207265676973746572656420736c61736865722063616e2063616c6c81525060200191505060405180910390fd5b6178de82613a8c565b617950576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506179d26179cd60026179bf8460090160000160405180602001604052908160008201548152505061ab57565b61c3c190919063ffffffff16565b61b90f565b8160090160000160008201518160000155905050428160090160010181905550506001548114617a6a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b600080617a7961c2c6565b73ffffffffffffffffffffffffffffffffffffffff166330ec70f5846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015617af557600080fd5b505afa158015617b09573d6000803e3d6000fd5b505050506040513d6020811015617b1f57600080fd5b81019080805190602001909291905050509050617b3b83618362565b811015915050919050565b60098060000154908060010154905082565b600060018060008282540192505081905550600060015490506000617b7b61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015617bf757600080fd5b505afa158015617c0b573d6000803e3d6000fd5b505050506040513d6020811015617c2157600080fd5b810190808051906020019092919050505090506000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001016002015411617cef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f56616c696461746f722067726f757020656d707479000000000000000000000081525060200191505060405180910390fd5b617cfc818560008061ab65565b9250506001548114617d76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b6000617d86615ecc565b617df8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b617e08617e0361bced565b61ab57565b821115617e60576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061de986028913960400191505060405180910390fd5b600b6000015483141580617ea55750617ea3600b600101604051806020016040529081600082015481525050617e958461b90f565b61c40b90919063ffffffff16565b155b617efa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602981526020018061dee36029913960400191505060405180910390fd5b6040518060400160405280848152602001617f148461b90f565b815250600b600082015181600001556020820151816001016000820151816000015550509050507f4b48724280029c2ea7a445c9cea30838525342e7a9ea9468f630b52e75d6c5368383604051808381526020018281526020019250505060405180910390a16001905092915050565b60606000617f9061a514565b90506060600680549050604051908082528060200260200182016040528015617fc85781602001602082028038833980820191505090505b50905060008090505b815181101561812a578273ffffffffffffffffffffffffffffffffffffffff16634ce38b5f6006838154811061800357fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561808e57600080fd5b505afa1580156180a2573d6000803e3d6000fd5b505050506040513d60208110156180b857600080fd5b81019080805190602001909291905050508282815181106180d557fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505061812360018261aab890919063ffffffff16565b9050617fd1565b50809250505090565b60008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146181d6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f4f6e6c7920564d2063616e2063616c6c0000000000000000000000000000000081525060200191505060405180910390fd5b6181e0838361c420565b905092915050565b6060600680548060200260200160405190810160405280929190818152602001828054801561826c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311618222575b5050505050905090565b600061828182613a8c565b6182f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061835a8160090160000160405180602001604052908160008201548152505061ab57565b915050919050565b600061836d8261a079565b1561837f5760076000015490506184e2565b61838882613a8c565b156184dd5760006183df6001600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001016002015461c9ae565b90506000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080190506000818054905011156184bc57600061844e6001838054905061aa6e90919063ffffffff16565b90505b60008111156184ba574261848960096001015484848154811061847057fe5b906000526020600020015461aab890919063ffffffff16565b1061849f57618498818461c9ae565b92506184ba565b6184b360018261aa6e90919063ffffffff16565b9050618451565b505b6184d48260096000015461c9c890919063ffffffff16565b925050506184e2565b600090505b919050565b60006060600060f873ffffffffffffffffffffffffffffffffffffffff166040516020016040516020818303038152906040526040518082805190602001908083835b6020831061854d578051825260208201915060208101905060208303925061852a565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146185ad576040519150601f19603f3d011682016040523d82523d6000602084013e6185b2565b606091505b50809350819250505080618611576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061ddad6025913960400191505060405180910390fd5b61861c82600061ab40565b9250505090565b600f5481565b6000618633615ecc565b6186a5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8160001061871b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4d61782067726f75702073697a652063616e6e6f74206265207a65726f00000081525060200191505060405180910390fd5b600e54821415618793576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d61782067726f75702073697a65206e6f74206368616e67656400000000000081525060200191505060405180910390fd5b81600e819055507f603fe12c33c253a23da1680aa453dc70c3a0ee07763569bd5f602406ebd4e5d5826040518082815260200191505060405180910390a160019050919050565b60018060008282540192505081905550600060015490506187f961c2c6565b73ffffffffffffffffffffffffffffffffffffffff166357601c5d336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561887557600080fd5b505afa158015618889573d6000803e3d6000fd5b505050506040513d602081101561889f57600080fd5b8101908080519060200190929190505050618922576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f6e6c79207265676973746572656420736c61736865722063616e2063616c6c81525060200191505060405180910390fd5b61892b8261a079565b156189d9576000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146189d7576189d5818461bd5d565b505b505b6001548114618a50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b6000618a986003618a8a6002618a7c6002618a6e88616559565b61c9c890919063ffffffff16565b61aab890919063ffffffff16565b61c3c190919063ffffffff16565b9050919050565b6000618aa961a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015618b2557600080fd5b505afa158015618b39573d6000803e3d6000fd5b505050506040513d6020811015618b4f57600080fd5b81019080805190602001909291905050509050618b6b81613a8c565b618bdd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600701541415618c9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f4e6f20636f6d6d697373696f6e2075706461746520717565756564000000000081525060200191505060405180910390fd5b4381600701541115618cf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061dae46021913960400191505060405180910390fd5b80600601816005016000820154816000015590505080600601600080820160009055505080600701600090558173ffffffffffffffffffffffffffffffffffffffff167f815d292dbc1a08dfb3103aabb6611233dd2393903e57bdf4c5b3db91198a826c618d7d8360050160405180602001604052908160008201548152505061ab57565b6040518082815260200191505060405180910390a25050565b600060018060008282540192505081905550600060015490506000618db961a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015618e3557600080fd5b505afa158015618e49573d6000803e3d6000fd5b505050506040513d6020811015618e5f57600080fd5b81019080805190602001909291905050509050618e7b8161a079565b158015618e8e5750618e8c81613a8c565b155b618f00576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f416c72656164792072656769737465726564000000000000000000000000000081525060200191505060405180910390fd5b6000618f0a61c2c6565b73ffffffffffffffffffffffffffffffffffffffff166330ec70f5836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015618f8657600080fd5b505afa158015618f9a573d6000803e3d6000fd5b505050506040513d6020811015618fb057600080fd5b8101908080519060200190929190505050905060076000015481101561903e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f4465706f73697420746f6f20736d616c6c00000000000000000000000000000081525060200191505060405180910390fd5b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600061908b61a514565b73ffffffffffffffffffffffffffffffffffffffff16634ce38b5f856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561910757600080fd5b505afa15801561911b573d6000803e3d6000fd5b505050506040513d602081101561913157600080fd5b810190808051906020019092919050505090506191948285838f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b30b565b5061922982858c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b6c7565b5060068490806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061929b84600061ca4e565b508373ffffffffffffffffffffffffffffffffffffffff167fd09501348473474a20c772c79c653e1fd7e8b437e418fe235d277d2c8885325160405160405180910390a26001955050505050600154811461935e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b509695505050505050565b60006193748461a079565b6193e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6193ee616549565b831115619446576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061dcfc6023913960400191505060405180910390fd5b6000600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060040190506194a78160010154826000015461aab890919063ffffffff16565b831061951b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f696e646578206f7574206f6620626f756e64730000000000000000000000000081525060200191505060405180910390fd5b80600001548310158015619533575060008160010154115b6195a5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f696e646578206f7574206f6620626f756e64730000000000000000000000000081525060200191505060405180910390fd5b6000848260020160008681526020019081526020016000206000015414905060006195de6001846001015461aa6e90919063ffffffff16565b6195f584600001548761aa6e90919063ffffffff16565b1490506000868460020160008881526020019081526020016000206000015410801561965357508684600201600061963760018a61aab890919063ffffffff16565b81526020019081526020016000206000015411806196525750815b5b9050828061965e5750805b6196b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252604781526020018061dbe56047913960600191505060405180910390fd5b83600201600087815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169450505050509392505050565b6000806000871415801561970e575060008514155b619780576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f612064656e6f6d696e61746f72206973207a65726f000000000000000000000081525060200191505060405180910390fd5b6000806000606060fc73ffffffffffffffffffffffffffffffffffffffff168c8c8c8c8c8c6040516020018087815260200186815260200185815260200184815260200183815260200182815260200196505050505050506040516020818303038152906040526040518082805190602001908083835b6020831061981a57805182526020820191506020810190506020830392506197f7565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461987a576040519150601f19603f3d011682016040523d82523d6000602084013e61987f565b606091505b508092508193505050816198de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061dd656027913960400191505060405180910390fd5b6198e981600061ab40565b93506198f681602061ab40565b925083839550955050505050965096945050505050565b6000600180600082825401925050819055506000600154905061993661993161bced565b61ab57565b83111561998e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061de736025913960400191505060405180910390fd5b600061999861a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015619a1457600080fd5b505afa158015619a28573d6000803e3d6000fd5b505050506040513d6020811015619a3e57600080fd5b81019080805190602001909291905050509050619a5a8161a079565b15619acd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f416c726561647920726567697374657265642061732076616c696461746f720081525060200191505060405180910390fd5b619ad681613a8c565b15619b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f416c726561647920726567697374657265642061732067726f7570000000000081525060200191505060405180910390fd5b6000619b5361c2c6565b73ffffffffffffffffffffffffffffffffffffffff166330ec70f5836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015619bcf57600080fd5b505afa158015619be3573d6000803e3d6000fd5b505050506040513d6020811015619bf957600080fd5b81019080805190602001909291905050509050600960000154811015619c87576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f4e6f7420656e6f756768206c6f636b656420676f6c640000000000000000000081525060200191505060405180910390fd5b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060018160000160006101000a81548160ff021916908315150217905550619cf08661b90f565b81600501600082015181600001559050506040518060400160405280619d1461bced565b81526020016000815250816009016000820151816000016000820151816000015550506020820151816001015590505060058390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508273ffffffffffffffffffffffffffffffffffffffff167fbf4b45570f1907a94775f8449817051a492a676918e38108bb762e991e6b58dc876040518082815260200191505060405180910390a2600194505050506001548114619e76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b6000619e86615ecc565b619ef8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b81600010619f51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061dcd46028913960400191505060405180910390fd5b600d54821415619fac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061dd406025913960400191505060405180910390fd5b81600d819055507f1c75c7fb3ee9d13d8394372d8c7cdf1702fa947faa03f6ccfa500f787b09b48a826040518082815260200191505060405180910390a160019050919050565b619ffb615ecc565b61a06d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b61a0768161bba9565b50565b600080600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600101805460018160011615610100020316600290049050119050919050565b60006060600060f573ffffffffffffffffffffffffffffffffffffffff1684604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061a14f578051825260208201915060208101905060208303925061a12c565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461a1af576040519150601f19603f3d011682016040523d82523d6000602084013e61a1b4565b606091505b5080935081925050508061a213576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c81526020018061ddd2602c913960400191505060405180910390fd5b61a21e82600061b27a565b92505050919050565b60006001806000828254019250508190555060006001549050600061a24a61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561a2c657600080fd5b505afa15801561a2da573d6000803e3d6000fd5b505050506040513d602081101561a2f057600080fd5b8101908080519060200190929190505050905061a30c8161a079565b61a37e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561a488576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f6465616666696c696174653a206e6f7420616666696c6961746564000000000081525060200191505060405180910390fd5b61a492818361bd5d565b50600193505050600154811461a510576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5090565b6000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561a5cf57600080fd5b505afa15801561a5e3573d6000803e3d6000fd5b505050506040513d602081101561a5f957600080fd5b8101908080519060200190929190505050905090565b600080600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508373ffffffffffffffffffffffffffffffffffffffff16600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461a756576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f4e6f7420616666696c696174656420746f2067726f757000000000000000000081525060200191505060405180910390fd5b806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091856040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561a7de57600080fd5b505af415801561a7f2573d6000803e3d6000fd5b505050506040513d602081101561a80857600080fd5b810190808051906020019092919050505061a88b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4e6f742061206d656d626572206f66207468652067726f75700000000000000081525060200191505060405180910390fd5b806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763e2c0c56a9091856040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561a91357600080fd5b505af415801561a927573d6000803e3d6000fd5b50505050600081600101600201549050600081141561a9df5761a94861ce5f565b73ffffffffffffffffffffffffffffffffffffffff1663a8e45871866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561a9c657600080fd5b505af115801561a9da573d6000803e3d6000fd5b505050505b61a9ea84600061ca4e565b5061aa088561aa0360018461aab890919063ffffffff16565b61cf5a565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fc7666a52a66ff601ff7c0d4d6efddc9ac20a34792f6aa003d1804c9d4d5baa5760405160405180910390a360019250505092915050565b600061aab083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061d083565b905092915050565b60008082840190508381101561ab36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600061ab4c838361b27a565b60001c905092915050565b600081600001519050919050565b600061ab7085613a8c565b801561ab81575061ab808461a079565b5b61abf3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f4e6f742076616c696461746f7220616e642067726f757000000000000000000081525060200191505060405180910390fd5b6000600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600e5481600101600201541061acb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f67726f757020776f756c6420657863656564206d6178696d756d2073697a650081525060200191505060405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff16600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461adb7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f4e6f7420616666696c696174656420746f2067726f757000000000000000000081525060200191505060405180910390fd5b806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091876040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561ae3f57600080fd5b505af415801561ae53573d6000803e3d6000fd5b505050506040513d602081101561ae6957600080fd5b81019080805190602001909291905050501561aeed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f416c726561647920696e2067726f75700000000000000000000000000000000081525060200191505060405180910390fd5b600061af0a6001836001016002015461aab890919063ffffffff16565b9050816001017399dc63c6a9f533aac37df3153f6fc72ed8094cf76326afac499091886040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561af9457600080fd5b505af415801561afa8573d6000803e3d6000fd5b5050505061afb587617a6e565b61b027576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f47726f757020726571756972656d656e7473206e6f74206d657400000000000081525060200191505060405180910390fd5b61b03086617a6e565b61b0a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f56616c696461746f7220726571756972656d656e7473206e6f74206d6574000081525060200191505060405180910390fd5b600181141561b1b25761b0b361ce5f565b73ffffffffffffffffffffffffffffffffffffffff1663a18fb2db8887876040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019350505050600060405180830381600087803b15801561b19957600080fd5b505af115801561b1ad573d6000803e3d6000fd5b505050505b61b1bc868861ca4e565b5061b1da8761b1d560018461aa6e90919063ffffffff16565b61cf5a565b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fbdf7e616a6943f81e07a7984c9d4c00197dc2f481486ce4ffa6af52a113974ad60405160405180910390a3600192505050949350505050565b60008082848161b24e57fe5b049050600083858161b25c57fe5b06141561b26c578091505061b274565b600181019150505b92915050565b6000602082018351101561b2f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f736c6963696e67206f7574206f662072616e676500000000000000000000000081525060200191505060405180910390fd5b60006020830184015190508091505092915050565b6000604082511461b384576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f57726f6e67204543445341207075626c6963206b6579206c656e67746800000081525060200191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff16828051906020012060001c73ffffffffffffffffffffffffffffffffffffffff161461b42f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f4543445341206b657920646f6573206e6f74206d61746368207369676e65720081525060200191505060405180910390fd5b8185600001600001908051906020019061b44a92919061d960565b508373ffffffffffffffffffffffffffffffffffffffff167f213377eec2c15b21fa7abcbb0cb87a67e893cdb94a2564aa4bb4d380869473c8836040518080602001828103825283818151815260200191508051906020019080838360005b8381101561b4c457808201518184015260208101905061b4a9565b50505050905090810190601f16801561b4f15780820380516001836020036101000a031916815260200191505b509250505060405180910390a260019050949350505050565b82805490508110801561b57e57508173ffffffffffffffffffffffffffffffffffffffff1683828154811061b53b57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b61b5d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061dd8c6021913960400191505060405180910390fd5b600061b5ed6001858054905061aa6e90919063ffffffff16565b905083818154811061b5fb57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684838154811061b63257fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083818154811061b68657fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905580848161b6c0919061d9e0565b5050505050565b6000606083511461b740576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f57726f6e6720424c53207075626c6963206b6579206c656e677468000000000081525060200191505060405180910390fd5b603082511461b7b7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f57726f6e6720424c5320506f50206c656e67746800000000000000000000000081525060200191505060405180910390fd5b61b7c2848484612d3c565b61b834576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f496e76616c696420424c5320506f50000000000000000000000000000000000081525060200191505060405180910390fd5b8285600001600101908051906020019061b84f92919061d960565b508373ffffffffffffffffffffffffffffffffffffffff167f36a1aabe506bbe8802233cbb9aad628e91269e77077c953f9db3e02d7092ee33846040518080602001828103825283818151815260200191508051906020019080838360005b8381101561b8c957808201518184015260208101905061b8ae565b50505050905090810190601f16801561b8f65780820380516001836020036101000a031916815260200191505b509250505060405180910390a260019050949350505050565b61b91761d905565b6040518060200160405280838152509050919050565b61b93561d905565b600082600001518460000151019050836000015181101561b9be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f616464206f766572666c6f77206465746563746564000000000000000000000081525060200191505060405180910390fd5b60405180602001604052808281525091505092915050565b61b9de61d905565b61b9e661d143565b82111561ba3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061db8a6036913960400191505060405180910390fd5b604051806020016040528069d3c21bcecceda100000084028152509050919050565b61ba6861d905565b60008260000151141561bae3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f63616e277420646976696465206279203000000000000000000000000000000081525060200191505060405180910390fd5b600069d3c21bcecceda10000008460000151029050836000015169d3c21bcecceda1000000828161bb1057fe5b041461bb84576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f6f766572666c6f7720617420646976696465000000000000000000000000000081525060200191505060405180910390fd5b60405180602001604052808460000151838161bb9c57fe5b0481525091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561bc2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602681526020018061da836026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61bcf561d905565b604051806020016040528069d3c21bcecceda1000000815250905090565b600033905090565b61bd2361d905565b61bd2b61d905565b61bd348461b9d6565b905061bd3e61d905565b61bd478461b9d6565b905061bd53828261ba60565b9250505092915050565b6000808360020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091866040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561be5257600080fd5b505af415801561be66573d6000803e3d6000fd5b505050506040513d602081101561be7c57600080fd5b81019080805190602001909291905050501561be9e5761be9c828561a60f565b505b60008560020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f71815121f0622b31a3e7270eb28acb9fd10825ff418c9a18591f617bb8a31a6c60405160405180910390a360019250505092915050565b600061bf5261a514565b73ffffffffffffffffffffffffffffffffffffffff166393c5c487846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561bfce57600080fd5b505afa15801561bfe2573d6000803e3d6000fd5b505050506040513d602081101561bff857600080fd5b8101908080519060200190929190505050905061c0148161a079565b61c086576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b61c08e61d905565b61c09f61c09a84615f2a565b61b90f565b905061c0a961d905565b61c0d582600b60010160405180602001604052908160008201548152505061d16290919063ffffffff16565b905061c0df61d905565b61c112600b60010160405180602001604052908160008201548152505061c10461bced565b61d5c190919063ffffffff16565b905061c17d600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003016040518060200160405290816000820154815250508261d16290919063ffffffff16565b905061c1b361c1ae61c18e8561ab57565b61c1a961c1a4858761b92d90919063ffffffff16565b61ab57565b61d668565b61b90f565b600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600301600082015181600001559050508373ffffffffffffffffffffffffffffffffffffffff167fedf9f87e50e10c533bf3ae7f5a7894ae66c23e6cbbe8773d7765d20ad6f995e961c299600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030160405180602001604052908160008201548152505061ab57565b61c2a28661ab57565b604051808381526020018281526020019250505060405180910390a2505050505050565b6000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4c6f636b6564476f6c6400000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561c38157600080fd5b505afa15801561c395573d6000803e3d6000fd5b505050506040513d602081101561c3ab57600080fd5b8101908080519060200190929190505050905090565b600061c40383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061d681565b905092915050565b60008160000151836000015114905092915050565b60008061c42b61a514565b73ffffffffffffffffffffffffffffffffffffffff166393c5c487856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561c4a757600080fd5b505afa15801561c4bb573d6000803e3d6000fd5b505050506040513d602081101561c4d157600080fd5b8101908080519060200190929190505050905061c4ed8161a079565b61c55f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b600061c56a82612761565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561c5f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061dbc06025913960400191505060405180910390fd5b61c5fb82617a6e565b801561c60c575061c60b81617a6e565b5b1561c9a15761c61961d905565b61c6f5600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060090160000160405180602001604052908160008201548152505061c6e7600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030160405180602001604052908160008201548152505061c6d98961b9d6565b61d16290919063ffffffff16565b61d16290919063ffffffff16565b9050600061c76a61c765600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206005016040518060200160405290816000820154815250508461d16290919063ffffffff16565b61d747565b9050600061c7898261c77b8561d747565b61aa6e90919063ffffffff16565b905061c79361d768565b73ffffffffffffffffffffffffffffffffffffffff166340c10f1985846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561c81957600080fd5b505af115801561c82d573d6000803e3d6000fd5b505050506040513d602081101561c84357600080fd5b81019080805190602001909291905050505061c85d61d768565b73ffffffffffffffffffffffffffffffffffffffff166340c10f1986836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561c8e357600080fd5b505af115801561c8f7573d6000803e3d6000fd5b505050506040513d602081101561c90d57600080fd5b8101908080519060200190929190505050508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6f5937add2ec38a0fa4959bccd86e3fcc2aafb706cd3e6c0565f87a7b36b99758385604051808381526020018281526020019250505060405180910390a361c9958361d747565b9550505050505061c9a8565b6000925050505b92915050565b60008183101561c9be578161c9c0565b825b905092915050565b60008083141561c9db576000905061ca48565b600082840290508284828161c9ec57fe5b041461ca43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061dd1f6021913960400191505060405180910390fd5b809150505b92915050565b600080600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206004019050600061ca9f616549565b905060008083600101541461cae15761cadc61cac96001856001015461aa6e90919063ffffffff16565b846000015461aab890919063ffffffff16565b61cae4565b60005b90506000836001015411801561cb265750600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b1561cb35574283600301819055505b8183600201600083815260200190815260200160002060000154141561cbf55760405180604001604052808381526020018673ffffffffffffffffffffffffffffffffffffffff168152508360020160008381526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506001935050505061ce59565b60008084600101541461cc1b5761cc1660018361aab890919063ffffffff16565b61cc1e565b60005b905060405180604001604052808481526020018773ffffffffffffffffffffffffffffffffffffffff168152508460020160008381526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050600d548460010154101561cce75761ccda6001856001015461aab890919063ffffffff16565b846001018190555061ce50565b600d548460010154141561cd6557836002016000856000015481526020019081526020016000206000808201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505061cd586001856000015461aab890919063ffffffff16565b846000018190555061ce4f565b836002016000856000015481526020019081526020016000206000808201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505083600201600061cdce6001876000015461aab890919063ffffffff16565b81526020019081526020016000206000808201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505061ce266001856001015461aa6e90919063ffffffff16565b846001018190555061ce466002856000015461aab890919063ffffffff16565b84600001819055505b5b60019450505050505b92915050565b6000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f456c656374696f6e0000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561cf1a57600080fd5b505afa15801561cf2e573d6000803e3d6000fd5b505050506040513d602081101561cf4457600080fd5b8101908080519060200190929190505050905090565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206008019050808054905082141561cfdc578042908060018154018082558091505090600182039060005260206000200160009091929091909150555061d07e565b808054905082101561d008574281838154811061cff557fe5b906000526020600020018190555061d07d565b600061d07c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f556e61626c6520746f207570646174652073697a6520686973746f727900000081525060200191505060405180910390fd5b5b5b505050565b600083831115829061d130576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561d0f557808201518184015260208101905061d0da565b50505050905090810190601f16801561d1225780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b60007601357c299a88ea76a58924d52ce4f26a85af186c2b9e74905090565b61d16a61d905565b60008360000151148061d181575060008260000151145b1561d19d5760405180602001604052806000815250905061d5bb565b69d3c21bcecceda10000008260000151141561d1bb5782905061d5bb565b69d3c21bcecceda10000008360000151141561d1d95781905061d5bb565b600069d3c21bcecceda100000061d1ef8561d863565b600001518161d1fa57fe5b049050600061d2088561d89a565b600001519050600069d3c21bcecceda100000061d2248661d863565b600001518161d22f57fe5b049050600061d23d8661d89a565b600001519050600082850290506000851461d2d1578285828161d25c57fe5b041461d2d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b600069d3c21bcecceda1000000820290506000821461d3735769d3c21bcecceda100000082828161d2fe57fe5b041461d372576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f6f766572666c6f772078317931202a206669786564312064657465637465640081525060200191505060405180910390fd5b5b809150600084860290506000861461d404578486828161d38f57fe5b041461d403576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b600084880290506000881461d492578488828161d41d57fe5b041461d491576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b61d49a61d8d7565b878161d4a257fe5b04965061d4ad61d8d7565b858161d4b557fe5b049450600085880290506000881461d546578588828161d4d157fe5b041461d545576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b61d54e61d905565b604051806020016040528087815250905061d5778160405180602001604052808781525061b92d565b905061d5918160405180602001604052808681525061b92d565b905061d5ab8160405180602001604052808581525061b92d565b9050809a50505050505050505050505b92915050565b61d5c961d905565b81600001518360000151101561d647576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f737562737472616374696f6e20756e646572666c6f772064657465637465640081525060200191505060405180910390fd5b60405180602001604052808360000151856000015103815250905092915050565b600081831061d677578161d679565b825b905092915050565b6000808311829061d72d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561d6f257808201518184015260208101905061d6d7565b50505050905090810190601f16801561d71f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161d73957fe5b049050809150509392505050565b600069d3c21bcecceda100000082600001518161d76057fe5b049050919050565b6000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f537461626c65546f6b656e000000000000000000000000000000000000000000815250600b019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561d82357600080fd5b505afa15801561d837573d6000803e3d6000fd5b505050506040513d602081101561d84d57600080fd5b8101908080519060200190929190505050905090565b61d86b61d905565b604051806020016040528069d3c21bcecceda10000008085600001518161d88e57fe5b04028152509050919050565b61d8a261d905565b604051806020016040528069d3c21bcecceda10000008085600001518161d8c557fe5b04028460000151038152509050919050565b600064e8d4a51000905090565b508054600082559060005260206000209081019061d902919061da0c565b50565b6040518060200160405280600081525090565b50805460018160011615610100020316600290046000825580601f1061d93e575061d95d565b601f01602090049060005260206000209081019061d95c919061da0c565b5b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061d9a157805160ff191683800117855561d9cf565b8280016001018555821561d9cf579182015b8281111561d9ce57825182559160200191906001019061d9b3565b5b50905061d9dc919061da0c565b5090565b81548183558181111561da075781836000526020600020918201910161da06919061da0c565b5b505050565b61da2e91905b8082111561da2a57600081600090555060010161da12565b5090565b9056fe56616c696461746f7220646f65736e2774206d65657420726571756972656d656e74736572726f722063616c6c696e67206e756d62657256616c696461746f7273496e53657420707265636f6d70696c654f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373607265736574536c617368696e674d756c7469706c696572602063616c6c6564206265666f7265207265736574506572696f64206578706972656443616e2774206170706c7920636f6d6d697373696f6e2075706461746520796574557074696d65206172726179206c6172676572207468616e206d6178696d756d2067726f75702073697a6556616c696461746f7220726571756972656d656e7473206e6f74206368616e6765646572726f722063616c6c696e672067657456657269666965645365616c4269746d617046726f6d48656164657220707265636f6d70696c6563616e277420637265617465206669786964697479206e756d626572206c6172676572207468616e206d61784e65774669786564282956616c696461746f72206e6f742072656769737465726564207769746820612067726f757070726f766964656420696e64657820646f6573206e6f74206d617463682070726f76696465642065706f63684e756d62657220617420696e64657820696e20686973746f72792e6572726f722063616c6c696e672076616c696461746f725369676e65724164647265737346726f6d43757272656e7453657420707265636f6d70696c656572726f722063616c6c696e67206e756d62657256616c696461746f7273496e43757272656e7453657420707265636f6d70696c656572726f722063616c6c696e672076616c696461746f725369676e65724164647265737346726f6d53657420707265636f6d70696c654d656d6265727368697020686973746f7279206c656e6774682063616e6e6f74206265207a65726f45706f63682063616e6e6f74206265206c6172676572207468616e2063757272656e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774d656d6265727368697020686973746f7279206c656e677468206e6f74206368616e6765646572726f722063616c6c696e67206672616374696f6e4d756c45787020707265636f6d70696c6564656c657465456c656d656e743a20696e646578206f7574206f662072616e67656572726f722063616c6c696e672067657445706f636853697a6520707265636f6d70696c656572726f722063616c6c696e6720676574506172656e745365616c4269746d617020707265636f6d70696c65636f6d6d697373696f6e207570646174652064656c6179206e6f74206368616e6765646572726f722063616c6c696e6720676574426c6f636b4e756d62657246726f6d48656164657220707265636f6d70696c654861736e2774206265656e20656d70747920666f72206c6f6e6720656e6f756768436f6d6d697373696f6e2063616e27742062652067726561746572207468616e203130302541646a7573746d656e742073706565642063616e6e6f74206265206c6172676572207468616e20316572726f722063616c6c696e67206861736848656164657220707265636f6d70696c6541646a7573746d656e7420737065656420616e64206578706f6e656e74206e6f74206368616e676564a165627a7a72305820619b3bc67036ab7d118a8b3de96061f39f82056b7d829dbbcac49816e90060bd0029

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106104965760003560e01c80638dd31e3911610262578063cb8f98e011610151578063e50e652d116100ce578063ee09831011610092578063ee098310146123df578063eff2ea3f14612425578063f2fde38b1461246b578063facd743b146124af578063fae8db0a1461250b578063fffdfccb1461254d57610496565b8063e50e652d14612145578063e7f0376614612187578063ea684f7714612191578063eb1d0b42146122cc578063ec6830721461236457610496565b8063dcff4cf611610115578063dcff4cf614612027578063df4da4611461207f578063e0e3ffe61461209d578063e1497ff7146120bb578063e33301aa1461210157610496565b8063cb8f98e014611e5f578063d55dcbcf14611eaf578063d69ef6cf14611f0e578063d93ab5ad14611f70578063dba94fcd14611fcf57610496565b8063b8f93943116101df578063c10c96ef116101a3578063c10c96ef14611d19578063c22d3bba14611d3e578063c54c1cd414611d82578063c580514014611dde578063ca6d56dc14611e0357610496565b8063b8f9394314611b98578063b915f53014611ba2578063bd9e9d9414611bc0578063bfdb741714611be5578063c0c6ad6f14611ccb57610496565b80639b2b592f116102265780639b2b592f146118f55780639b9d516114611937578063a91ee0dc14611a3b578063b591d3a514611a7f578063b730a29914611adb57610496565b80638dd31e39146117345780638f32d59b146117d757806394903a97146117f9578063988dcd1f1461183b5780639a7b3be7146118d757610496565b80635779e93d11610389578063715018a6116103065780637b103999116102ca5780637b1039991461153f57806386d81a5a1461158957806387ee8a0f146115b75780638a883626146115d55780638b16b1c6146116a45780638da5cb5b146116ea57610496565b8063715018a6146113915780637385e5da1461139b57806376c0a9ed146113b957806376f7425d1461140957806378d254561461149657610496565b80636ab951a01161034d5780636ab951a0146110c75780636c620d90146110f55780636fa47647146111235780637044775414611148578063713ea0f31461121657610496565b80635779e93d14610ecc5780635a61d15b14610eea5780635d180adb14610f3a57806360fb822c14610fb257806367960e9114610ff857610496565b806339e618e8116104175780634cd76db4116103db5780634cd76db414610cdf5780634e06fd8a14610cfd578063517f6d3314610dce57806351b5222514610dec57806352f13a4e14610e7057610496565b806339e618e814610af95780633b1eb4bf14610b515780633f27089814610b9357806343d9669914610bf25780634b2c2f4414610c1057610496565b806319113e3b1161045e57806319113e3b146107a157806323f0ab65146107c65780633173b8db1461095057806335244f51146109ec57806336407b7014610adb57610496565b80630b1ca49a1461049b5780630d1312b8146104f7578063123633ea1461057b578063158ef93e146105e95780631904bb2e1461060b575b600080fd5b6104dd600480360360208110156104b157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061256f565b604051808215151515815260200191505060405180910390f35b6105396004803603602081101561050d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612761565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105a76004803603602081101561059157600080fd5b8101908080359060200190929190505050612880565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105f16129d1565b604051808215151515815260200191505060405180910390f35b61064d6004803603602081101561062157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506129e4565b6040518080602001806020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838103835288818151815260200191508051906020019080838360005b838110156106fb5780820151818401526020810190506106e0565b50505050905090810190601f1680156107285780820380516001836020036101000a031916815260200191505b50838103825287818151815260200191508051906020019080838360005b83811015610761578082015181840152602081019050610746565b50505050905090810190601f16801561078e5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390f35b6107a9612d09565b604051808381526020018281526020019250505060405180910390f35b610936600480360360608110156107dc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561081957600080fd5b82018360208201111561082b57600080fd5b8035906020019184600183028401116401000000008311171561084d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156108b057600080fd5b8201836020820111156108c257600080fd5b803590602001918460018302840111640100000000831117156108e457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612d3c565b604051808215151515815260200191505060405180910390f35b6109d26004803603606081101561096657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612ef5565b604051808215151515815260200191505060405180910390f35b610a2e60048036036020811015610a0257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061311a565b604051808060200180602001858152602001848152602001838103835287818151815260200191508051906020019060200280838360005b83811015610a81578082015181840152602081019050610a66565b50505050905001838103825286818151815260200191508051906020019060200280838360005b83811015610ac3578082015181840152602081019050610aa8565b50505050905001965050505050505060405180910390f35b610ae36132ee565b6040518082815260200191505060405180910390f35b610b3b60048036036020811015610b0f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506132f4565b6040518082815260200191505060405180910390f35b610b7d60048036036020811015610b6757600080fd5b81019080803590602001909291905050506133be565b6040518082815260200191505060405180910390f35b610b9b6133d8565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610bde578082015181840152602081019050610bc3565b505050509050019250505060405180910390f35b610bfa613466565b6040518082815260200191505060405180910390f35b610cc960048036036020811015610c2657600080fd5b8101908080359060200190640100000000811115610c4357600080fd5b820183602082011115610c5557600080fd5b80359060200191846001830284011164010000000083111715610c7757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050613470565b6040518082815260200191505060405180910390f35b610ce7613604565b6040518082815260200191505060405180910390f35b610db460048036036060811015610d1357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610d7057600080fd5b820183602082011115610d8257600080fd5b80359060200191846001830284011164010000000083111715610da457600080fd5b909192939192939050505061360a565b604051808215151515815260200191505060405180910390f35b610dd661392f565b6040518082815260200191505060405180910390f35b610e2e60048036036020811015610e0257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061393c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610eb260048036036020811015610e8657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613a8c565b604051808215151515815260200191505060405180910390f35b610ed4613ae5565b6040518082815260200191505060405180910390f35b610f2060048036036040811015610f0057600080fd5b810190808035906020019092919080359060200190929190505050613aeb565b604051808215151515815260200191505060405180910390f35b610f7060048036036040811015610f5057600080fd5b810190808035906020019092919080359060200190929190505050613c6e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610fde60048036036020811015610fc857600080fd5b8101908080359060200190929190505050613dc0565b604051808215151515815260200191505060405180910390f35b6110b16004803603602081101561100e57600080fd5b810190808035906020019064010000000081111561102b57600080fd5b82018360208201111561103d57600080fd5b8035906020019184600183028401116401000000008311171561105f57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050614247565b6040518082815260200191505060405180910390f35b6110f3600480360360208110156110dd57600080fd5b81019080803590602001909291905050506143db565b005b6111216004803603602081101561110b57600080fd5b81019080803590602001909291905050506144ee565b005b61112b614604565b604051808381526020018281526020019250505060405180910390f35b6111bf6004803603602081101561115e57600080fd5b810190808035906020019064010000000081111561117b57600080fd5b82018360208201111561118d57600080fd5b803590602001918460208302840111640100000000831117156111af57600080fd5b909192939192939050505061461b565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156112025780820151818401526020810190506111e7565b505050509050019250505060405180910390f35b611377600480360360a081101561122c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561128957600080fd5b82018360208201111561129b57600080fd5b803590602001918460018302840111640100000000831117156112bd57600080fd5b9091929391929390803590602001906401000000008111156112de57600080fd5b8201836020820111156112f057600080fd5b8035906020019184600183028401116401000000008311171561131257600080fd5b90919293919293908035906020019064010000000081111561133357600080fd5b82018360208201111561134557600080fd5b8035906020019184600183028401116401000000008311171561136757600080fd5b90919293919293905050506146d3565b604051808215151515815260200191505060405180910390f35b611399614b02565b005b6113a3614c3b565b6040518082815260200191505060405180910390f35b6113ef600480360360408110156113cf57600080fd5b810190808035906020019092919080359060200190929190505050614c4b565b604051808215151515815260200191505060405180910390f35b6114806004803603602081101561141f57600080fd5b810190808035906020019064010000000081111561143c57600080fd5b82018360208201111561144e57600080fd5b8035906020019184602083028401116401000000008311171561147057600080fd5b9091929391929390505050614db1565b6040518082815260200191505060405180910390f35b61153d60048036036101608110156114ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190505050614f24565b005b611547615028565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6115b56004803603602081101561159f57600080fd5b810190808035906020019092919050505061504e565b005b6115bf615363565b6040518082815260200191505060405180910390f35b61168e600480360360208110156115eb57600080fd5b810190808035906020019064010000000081111561160857600080fd5b82018360208201111561161a57600080fd5b8035906020019184600183028401116401000000008311171561163c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506154aa565b6040518082815260200191505060405180910390f35b6116d0600480360360208110156116ba57600080fd5b810190808035906020019092919050505061563e565b604051808215151515815260200191505060405180910390f35b6116f2615bf2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6117806004803603604081101561174a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050615c1b565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156117c35780820151818401526020810190506117a8565b505050509050019250505060405180910390f35b6117df615ecc565b604051808215151515815260200191505060405180910390f35b6118256004803603602081101561180f57600080fd5b8101908080359060200190929190505050615f2a565b6040518082815260200191505060405180910390f35b6118bd6004803603606081101561185157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050616018565b604051808215151515815260200191505060405180910390f35b6118df616549565b6040518082815260200191505060405180910390f35b6119216004803603602081101561190b57600080fd5b8101908080359060200190929190505050616559565b6040518082815260200191505060405180910390f35b6119796004803603602081101561194d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506166a2565b60405180806020018881526020018781526020018681526020018060200185815260200184815260200183810383528a818151815260200191508051906020019060200280838360005b838110156119de5780820151818401526020810190506119c3565b50505050905001838103825286818151815260200191508051906020019060200280838360005b83811015611a20578082015181840152602081019050611a05565b50505050905001995050505050505050505060405180910390f35b611a7d60048036036020811015611a5157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050616934565b005b611ac160048036036020811015611a9557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050616ad8565b604051808215151515815260200191505060405180910390f35b611b1d60048036036020811015611af157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050616f4a565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015611b5d578082015181840152602081019050611b42565b50505050905090810190601f168015611b8a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b611ba0617170565b005b611baa617414565b6040518082815260200191505060405180910390f35b611bc861741e565b604051808381526020018281526020019250505060405180910390f35b611cb160048036036040811015611bfb57600080fd5b8101908080359060200190640100000000811115611c1857600080fd5b820183602082011115611c2a57600080fd5b80359060200191846001830284011164010000000083111715611c4c57600080fd5b909192939192939080359060200190640100000000811115611c6d57600080fd5b820183602082011115611c7f57600080fd5b80359060200191846001830284011164010000000083111715611ca157600080fd5b9091929391929390505050617430565b604051808215151515815260200191505060405180910390f35b611d1760048036036040811015611ce157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506176c6565b005b611d21617776565b604051808381526020018281526020019250505060405180910390f35b611d8060048036036020811015611d5457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061778d565b005b611dc460048036036020811015611d9857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050617a6e565b604051808215151515815260200191505060405180910390f35b611de6617b46565b604051808381526020018281526020019250505060405180910390f35b611e4560048036036020811015611e1957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050617b58565b604051808215151515815260200191505060405180910390f35b611e9560048036036040811015611e7557600080fd5b810190808035906020019092919080359060200190929190505050617d7c565b604051808215151515815260200191505060405180910390f35b611eb7617f84565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015611efa578082015181840152602081019050611edf565b505050509050019250505060405180910390f35b611f5a60048036036040811015611f2457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050618133565b6040518082815260200191505060405180910390f35b611f786181e8565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015611fbb578082015181840152602081019050611fa0565b505050509050019250505060405180910390f35b61201160048036036020811015611fe557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050618276565b6040518082815260200191505060405180910390f35b6120696004803603602081101561203d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050618362565b6040518082815260200191505060405180910390f35b6120876184e7565b6040518082815260200191505060405180910390f35b6120a5618623565b6040518082815260200191505060405180910390f35b6120e7600480360360208110156120d157600080fd5b8101908080359060200190929190505050618629565b604051808215151515815260200191505060405180910390f35b6121436004803603602081101561211757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506187da565b005b6121716004803603602081101561215b57600080fd5b8101908080359060200190929190505050618a54565b6040518082815260200191505060405180910390f35b61218f618a9f565b005b6122b2600480360360608110156121a757600080fd5b81019080803590602001906401000000008111156121c457600080fd5b8201836020820111156121d657600080fd5b803590602001918460018302840111640100000000831117156121f857600080fd5b90919293919293908035906020019064010000000081111561221957600080fd5b82018360208201111561222b57600080fd5b8035906020019184600183028401116401000000008311171561224d57600080fd5b90919293919293908035906020019064010000000081111561226e57600080fd5b82018360208201111561228057600080fd5b803590602001918460018302840111640100000000831117156122a257600080fd5b9091929391929390505050618d96565b604051808215151515815260200191505060405180910390f35b612322600480360360608110156122e257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190505050619369565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6123c2600480360360c081101561237a57600080fd5b810190808035906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190929190803590602001909291905050506196f9565b604051808381526020018281526020019250505060405180910390f35b61240b600480360360208110156123f557600080fd5b810190808035906020019092919050505061990d565b604051808215151515815260200191505060405180910390f35b6124516004803603602081101561243b57600080fd5b8101908080359060200190929190505050619e7c565b604051808215151515815260200191505060405180910390f35b6124ad6004803603602081101561248157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050619ff3565b005b6124f1600480360360208110156124c557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061a079565b604051808215151515815260200191505060405180910390f35b6125376004803603602081101561252157600080fd5b810190808035906020019092919050505061a0de565b6040518082815260200191505060405180910390f35b61255561a227565b604051808215151515815260200191505060405180910390f35b60006001806000828254019250508190555060006001549050600061259261a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561260e57600080fd5b505afa158015612622573d6000803e3d6000fd5b505050506040513d602081101561263857600080fd5b8101908080519060200190929190505050905061265481613a8c565b801561266557506126648461a079565b5b6126d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f6973206e6f742067726f757020616e642076616c696461746f7200000000000081525060200191505060405180910390fd5b6126e1818561a60f565b925050600154811461275b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60008061276c616549565b90506000600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060040190506000808260010154146127f4576127ef6127dc6001846001015461aa6e90919063ffffffff16565b836000015461aab890919063ffffffff16565b6127f7565b60005b90508282600201600083815260200190815260200160002060000154141561283d57816000015481111561283c5761283960018261aa6e90919063ffffffff16565b90505b5b81600201600082815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169350505050919050565b60006060600060fa73ffffffffffffffffffffffffffffffffffffffff16844360405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b602083106128f957805182526020820191506020810190506020830392506128d6565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612959576040519150601f19603f3d011682016040523d82523d6000602084013e61295e565b606091505b508093508192505050806129bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603d81526020018061dc2c603d913960400191505060405180910390fd5b6129c882600061ab40565b92505050919050565b600260009054906101000a900460ff1681565b60608060008060006129f58661a079565b612a67576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905080600001600001816000016001018260020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16612afe8460030160405180602001604052908160008201548152505061ab57565b612b0661a514565b73ffffffffffffffffffffffffffffffffffffffff16634ce38b5f8c6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612b8257600080fd5b505afa158015612b96573d6000803e3d6000fd5b505050506040513d6020811015612bac57600080fd5b8101908080519060200190929190505050848054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612c525780601f10612c2757610100808354040283529160200191612c52565b820191906000526020600020905b815481529060010190602001808311612c3557829003601f168201915b50505050509450838054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612cee5780601f10612cc357610100808354040283529160200191612cee565b820191906000526020600020905b815481529060010190602001808311612cd157829003601f168201915b50505050509350955095509550955095505091939590929450565b600080600b60000154612d34600b60010160405180602001604052908160008201548152505061ab57565b915091509091565b60008060fb73ffffffffffffffffffffffffffffffffffffffff16858585604051602001808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140183805190602001908083835b60208310612dc55780518252602082019150602081019050602083039250612da2565b6001836020036101000a03801982511681845116808217855250505050505090500182805190602001908083835b60208310612e165780518252602082019150602081019050602083039250612df3565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b60208310612e7f5780518252602082019150602081019050602083039250612e5c565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114612edf576040519150601f19603f3d011682016040523d82523d6000602084013e612ee4565b606091505b505080915050809150509392505050565b600060018060008282540192505081905550600060015490506000612f1861a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612f9457600080fd5b505afa158015612fa8573d6000803e3d6000fd5b505050506040513d6020811015612fbe57600080fd5b810190808051906020019092919050505090506000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101600201541461308c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f56616c696461746f722067726f7570206e6f7420656d7074790000000000000081525060200191505060405180910390fd5b6130988187878761ab65565b9250506001548114613112576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b509392505050565b6060806000806000600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060040190506060816001015460405190808252806020026020018201604052801561319b5781602001602082028038833980820191505090505b509050606082600101546040519080825280602002602001820160405280156131d35781602001602082028038833980820191505090505b50905060008090505b83600101548110156132cf57600061320182866000015461aab890919063ffffffff16565b90508460020160008281526020019081526020016000206000015484838151811061322857fe5b60200260200101818152505084600201600082815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683838151811061327957fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050506132c860018261aab890919063ffffffff16565b90506131dc565b5081818460030154856000015496509650965096505050509193509193565b60105481565b60006132ff82613a8c565b613371576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f4e6f742076616c696461746f722067726f75700000000000000000000000000081525060200191505060405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101600201549050919050565b60006133d1826133cc6184e7565b61b242565b9050919050565b6060600580548060200260200160405190810160405280929190818152602001828054801561345c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311613412575b5050505050905090565b6000600e54905090565b60006060600060f473ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b602083106134c557805182526020820191506020810190506020830392506134a2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b6020831061352c5780518252602082019150602081019050602083039250613509565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461358c576040519150601f19603f3d011682016040523d82523d6000602084013e613591565b606091505b508093508192505050806135f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603881526020018061db526038913960400191505060405180910390fd5b6135fb82600061b27a565b92505050919050565b600d5481565b600060405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156136dd57600080fd5b505afa1580156136f1573d6000803e3d6000fd5b505050506040513d602081101561370757600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16146137a1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b6137aa8661a079565b61381c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506138af81888888888080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b30b565b613921576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f4572726f72207570646174696e67204543445341207075626c6963206b65790081525060200191505060405180910390fd5b600192505050949350505050565b6000600680549050905090565b60008061394761a514565b73ffffffffffffffffffffffffffffffffffffffff166393c5c487846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156139c357600080fd5b505afa1580156139d7573d6000803e3d6000fd5b505050506040513d60208110156139ed57600080fd5b81019080805190602001909291905050509050613a098161a079565b613a7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b613a8481612761565b915050919050565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900460ff169050919050565b600e5481565b6000613af5615ecc565b613b67576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600060099050806000015484141580613b84575080600101548314155b613bf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f47726f757020726571756972656d656e7473206e6f74206368616e676564000081525060200191505060405180910390fd5b604051806040016040528085815260200184815250600960008201518160000155602082015181600101559050507f999f7ee1917e6d7ea08360edfe9250cda3eda859c38dcb71a92623665de64dd48484604051808381526020018281526020019250505060405180910390a1600191505092915050565b60006060600060fa73ffffffffffffffffffffffffffffffffffffffff16858560405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310613ce75780518252602082019150602081019050602083039250613cc4565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114613d47576040519150601f19603f3d011682016040523d82523d6000602084013e613d4c565b606091505b50809350819250505080613dab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061dc9e6036913960400191505060405180910390fd5b613db682600061ab40565b9250505092915050565b600060018060008282540192505081905550600060015490506000613de361a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613e5f57600080fd5b505afa158015613e73573d6000803e3d6000fd5b505050506040513d6020811015613e8957600080fd5b81019080805190602001909291905050509050613ea581613a8c565b613f17576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001016002015414613fd2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f56616c696461746f722067726f7570206e6f7420656d7074790000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080190506001818054905011156140ac57426140556009600101548360018154811061403c57fe5b906000526020600020015461aab890919063ffffffff16565b106140ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061de526021913960400191505060405180910390fd5b5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160006101000a81549060ff0219169055600182016000808201600090556001820160009055600282016000905550506005820160008082016000905550506006820160008082016000905550506007820160009055600882016000614155919061d8e4565b60098201600080820160008082016000905550506001820160009055505050506141816005838761b50a565b8173ffffffffffffffffffffffffffffffffffffffff167fae7e034b0748a10a219b46074b20977a9170bf4027b156c797093773619a866960405160405180910390a26001935050506001548114614241576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60006060600060f673ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b6020831061429c5780518252602082019150602081019050602083039250614279565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b6020831061430357805182526020820191506020810190506020830392506142e0565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114614363576040519150601f19603f3d011682016040523d82523d6000602084013e614368565b606091505b508093508192505050806143c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061dec06023913960400191505060405180910390fd5b6143d282600061b27a565b92505050919050565b60018060008282540192505081905550600060015490506143fa615ecc565b61446c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8160108190555060015481146144ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b6144f6615ecc565b614568576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600f548114156145c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061ddfe6023913960400191505060405180910390fd5b80600f819055507ff2da07d08fd8dc9c5dcf87ad6f540e306f884a47dd8de14b718a4d5395f1ca9b816040518082815260200191505060405180910390a150565b600080600960000154600960010154915091509091565b606080838390506040519080825280602002602001820160405280156146505781602001602082028038833980820191505090505b50905060008090505b848490508110156146c85761469585858381811061467357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166132f4565b8282815181106146a157fe5b6020026020010181815250506146c160018261aab890919063ffffffff16565b9050614659565b508091505092915050565b600060405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001203373ffffffffffffffffffffffffffffffffffffffff16600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156147a657600080fd5b505afa1580156147ba573d6000803e3d6000fd5b505050506040513d60208110156147d057600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161461486a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f6f6e6c79207265676973746572656420636f6e7472616374000000000000000081525060200191505060405180910390fd5b6148738a61a079565b6148e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050614978818c8c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b30b565b6149ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f4572726f72207570646174696e67204543445341207075626c6963206b65790081525060200191505060405180910390fd5b614a7e818c89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b6c7565b614af0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4572726f72207570646174696e6720424c53207075626c6963206b657900000081525060200191505060405180910390fd5b60019250505098975050505050505050565b614b0a615ecc565b614b7c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000614c4643618a54565b905090565b6000614c55615ecc565b614cc7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600060079050806000015484141580614ce4575080600101548314155b614d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602281526020018061db306022913960400191505060405180910390fd5b604051806040016040528085815260200184815250600760008201518160000155602082015181600101559050507f62d947118dd4c1f5ece7f787a9cad4e1127d14d403b71133e95792b473bf83898484604051808381526020018281526020019250505060405180910390a1600191505092915050565b6000808383905011614e2b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f557074696d6520617272617920656d707479000000000000000000000000000081525060200191505060405180910390fd5b600e54838390501115614e89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b81526020018061db05602b913960400191505060405180910390fd5b614e9161d905565b60008090505b84849050811015614ef457614ed7614ec8614ec3878785818110614eb757fe5b90506020020135615f2a565b61b90f565b8361b92d90919063ffffffff16565b9150614eed60018261aab890919063ffffffff16565b9050614e97565b50614f1b614f16614f078686905061b9d6565b8361ba6090919063ffffffff16565b61ab57565b91505092915050565b600260009054906101000a900460ff1615614fa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600260006101000a81548160ff021916908315150217905550614fcb3361bba9565b614fd48b616934565b614fde8a8a613aeb565b50614fe98888614c4b565b50614ff48686617d7c565b50614ffe82618629565b50615008816144ee565b61501184619e7c565b5061501b836143db565b5050505050505050505050565b600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061505861a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156150d457600080fd5b505afa1580156150e8573d6000803e3d6000fd5b505050506040513d60208110156150fe57600080fd5b8101908080519060200190929190505050905061511a81613a8c565b61518c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506151df6151da61bced565b61ab57565b831115615237576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061de736025913960400191505060405180910390fd5b6152588160050160405180602001604052908160008201548152505061ab57565b8314156152cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f436f6d6d697373696f6e206d75737420626520646966666572656e740000000081525060200191505060405180910390fd5b6152d68361b90f565b81600601600082015181600001559050506152fc600f544361aab890919063ffffffff16565b81600701819055508173ffffffffffffffffffffffffffffffffffffffff167f557d39a57520d9835859d4b7eda805a7f4115a59c3a374eeed488436fc62a152848360070154604051808381526020018281526020019250505060405180910390a2505050565b60006060600060f973ffffffffffffffffffffffffffffffffffffffff1643604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106153d457805182526020820191506020810190506020830392506153b1565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114615434576040519150601f19603f3d011682016040523d82523d6000602084013e615439565b606091505b50809350819250505080615498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603581526020018061dc696035913960400191505060405180910390fd5b6154a382600061ab40565b9250505090565b60006060600060f773ffffffffffffffffffffffffffffffffffffffff16846040516020018082805190602001908083835b602083106154ff57805182526020820191506020810190506020830392506154dc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b602083106155665780518252602082019150602081019050602083039250615543565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146155c6576040519150601f19603f3d011682016040523d82523d6000602084013e6155cb565b606091505b5080935081925050508061562a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603181526020018061de216031913960400191505060405180910390fd5b61563582600061ab40565b92505050919050565b60006001806000828254019250508190555060006001549050600061566161a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156156dd57600080fd5b505afa1580156156f1573d6000803e3d6000fd5b505050506040513d602081101561570757600080fd5b810190808051906020019092919050505090506157238161a079565b615795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146159c957600360008260020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561591a57600080fd5b505af415801561592e573d6000803e3d6000fd5b505050506040513d602081101561594457600080fd5b8101908080519060200190929190505050156159c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f486173206265656e2067726f7570206d656d62657220726563656e746c79000081525060200191505060405180910390fd5b5b60006159ea600760010154836004016003015461aab890919063ffffffff16565b9050428110615a61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4e6f742079657420726571756972656d656e7420656e642074696d650000000081525060200191505060405180910390fd5b615a6d6006848861b50a565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160008082016000615ac2919061d918565b600182016000615ad2919061d918565b50506002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556003820160008082016000905550506004820160008082016000905560018201600090556003820160009055505050508273ffffffffffffffffffffffffffffffffffffffff167f51407fafe7ef9bec39c65a12a4885a274190991bf1e9057fcc384fc77ff1a7f060405160405180910390a2600194505050506001548114615bec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606080600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763b1cfea439091856040518363ffffffff1660e01b8152600401808381526020018281526020019250505060006040518083038186803b158015615cb857600080fd5b505af4158015615ccc573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052506020811015615cf657600080fd5b810190808051640100000000811115615d0e57600080fd5b82810190506020810184811115615d2457600080fd5b8151856020820283011164010000000082111715615d4157600080fd5b50509291905050509050606083604051908082528060200260200182016040528015615d7c5781602001602082028038833980820191505090505b50905060008090505b84811015615ec057615d9561a514565b73ffffffffffffffffffffffffffffffffffffffff16634ce38b5f848381518110615dbc57fe5b60200260200101516040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015615e2457600080fd5b505afa158015615e38573d6000803e3d6000fd5b505050506040513d6020811015615e4e57600080fd5b8101908080519060200190929190505050828281518110615e6b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050615eb960018261aab890919063ffffffff16565b9050615d85565b50809250505092915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16615f0e61bd13565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b6000615f3c615f3761bced565b61ab57565b821115615fb1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f557074696d652063616e6e6f74206265206c6172676572207468616e206f6e6581525060200191505060405180910390fd5b600080615ff5615fc7615fc261bced565b61ab57565b615fd7615fd261bced565b61ab57565b86615fe8615fe361bced565b61ab57565b600b6000015460126196f9565b809250819350505061600f61600a838361bd1b565b61ab57565b92505050919050565b60006001806000828254019250508190555060006001549050600061603b61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156160b757600080fd5b505afa1580156160cb573d6000803e3d6000fd5b505050506040513d60208110156160e157600080fd5b810190808051906020019092919050505090506160fd81613a8c565b61616f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600b8152602001807f4e6f7420612067726f757000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6161788661a079565b6161ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091896040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b1580156162b557600080fd5b505af41580156162c9573d6000803e3d6000fd5b505050506040513d60208110156162df57600080fd5b8101908080519060200190929190505050616362576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4e6f742061206d656d626572206f66207468652067726f75700000000000000081525060200191505060405180910390fd5b806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763b2f8fe9690918989896040518563ffffffff1660e01b8152600401808581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200194505050505060006040518083038186803b15801561645257600080fd5b505af4158015616466573d6000803e3d6000fd5b505050508673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f38819cc49a343985b478d72f531a35b15384c398dd80fd191a14662170f895c660405160405180910390a36001935050506001548114616541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b509392505050565b6000616554436133be565b905090565b60006060600060f973ffffffffffffffffffffffffffffffffffffffff1684604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106165ca57805182526020820191506020810190506020830392506165a7565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461662a576040519150601f19603f3d011682016040523d82523d6000602084013e61662f565b606091505b5080935081925050508061668e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e81526020018061da55602e913960400191505060405180910390fd5b61669982600061ab40565b92505050919050565b6060600080600060606000806166b788613a8c565b616729576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763fe3c7a8e90916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b1580156167c057600080fd5b505af41580156167d4573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060208110156167fe57600080fd5b81019080805164010000000081111561681657600080fd5b8281019050602081018481111561682c57600080fd5b815185602082028301116401000000008211171561684957600080fd5b50509291905050506168728260050160405180602001604052908160008201548152505061ab57565b6168938360060160405180602001604052908160008201548152505061ab57565b8360070154846008016168c08660090160000160405180602001604052908160008201548152505061ab57565b86600901600101548280548060200260200160405190810160405280929190818152602001828054801561691357602002820191906000526020600020905b8154815260200190600101908083116168ff575b50505050509250975097509750975097509750975050919395979092949650565b61693c615ecc565b6169ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415616a51576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f43616e6e6f7420726567697374657220746865206e756c6c206164647265737381525060200191505060405180910390fd5b80600260016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b60405160405180910390a250565b600060018060008282540192505081905550600060015490506000616afb61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015616b7757600080fd5b505afa158015616b8b573d6000803e3d6000fd5b505050506040513d6020811015616ba157600080fd5b81019080805190602001909291905050509050616bbd8161a079565b616c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b616c3884613a8c565b616caa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b616cb381617a6e565b616d08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061da326023913960400191505060405180910390fd5b616d1184617a6e565b616d83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f47726f757020646f65736e2774206d65657420726571756972656d656e74730081525060200191505060405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614616e2a57616e28818361bd5d565b505b848160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f91ef92227057e201e406c3451698dd780fe7672ad74328591c88d281af31581d60405160405180910390a36001935050506001548114616f44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b60606000616f5661a514565b73ffffffffffffffffffffffffffffffffffffffff166393c5c487846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015616fd257600080fd5b505afa158015616fe6573d6000803e3d6000fd5b505050506040513d6020811015616ffc57600080fd5b810190808051906020019092919050505090506170188161a079565b61708a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b600460008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156171635780601f1061713857610100808354040283529160200191617163565b820191906000526020600020905b81548152906001019060200180831161714657829003601f168201915b5050505050915050919050565b6001806000828254019250508190555060006001549050600061719161a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561720d57600080fd5b505afa158015617221573d6000803e3d6000fd5b505050506040513d602081101561723757600080fd5b8101908080519060200190929190505050905061725381613a8c565b6172c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050617324601054826009016001015461aab890919063ffffffff16565b42101561737c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b81526020018061daa9603b913960400191505060405180910390fd5b61738461bced565b816009016000016000820151816000015590505050506001548114617411576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50565b6000600f54905090565b60078060000154908060010154905082565b60008061743b61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156174b757600080fd5b505afa1580156174cb573d6000803e3d6000fd5b505050506040513d60208110156174e157600080fd5b810190808051906020019092919050505090506174fd8161a079565b61756f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050617646818389898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b6c7565b6176b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4572726f72207570646174696e6720424c53207075626c6963206b657900000081525060200191505060405180910390fd5b600192505050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614617768576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f4f6e6c7920564d2063616e2063616c6c0000000000000000000000000000000081525060200191505060405180910390fd5b617772828261bf48565b5050565b600080600760000154600760010154915091509091565b60018060008282540192505081905550600060015490506177ac61c2c6565b73ffffffffffffffffffffffffffffffffffffffff166357601c5d336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561782857600080fd5b505afa15801561783c573d6000803e3d6000fd5b505050506040513d602081101561785257600080fd5b81019080805190602001909291905050506178d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f6e6c79207265676973746572656420736c61736865722063616e2063616c6c81525060200191505060405180910390fd5b6178de82613a8c565b617950576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506179d26179cd60026179bf8460090160000160405180602001604052908160008201548152505061ab57565b61c3c190919063ffffffff16565b61b90f565b8160090160000160008201518160000155905050428160090160010181905550506001548114617a6a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b600080617a7961c2c6565b73ffffffffffffffffffffffffffffffffffffffff166330ec70f5846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015617af557600080fd5b505afa158015617b09573d6000803e3d6000fd5b505050506040513d6020811015617b1f57600080fd5b81019080805190602001909291905050509050617b3b83618362565b811015915050919050565b60098060000154908060010154905082565b600060018060008282540192505081905550600060015490506000617b7b61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015617bf757600080fd5b505afa158015617c0b573d6000803e3d6000fd5b505050506040513d6020811015617c2157600080fd5b810190808051906020019092919050505090506000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001016002015411617cef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f56616c696461746f722067726f757020656d707479000000000000000000000081525060200191505060405180910390fd5b617cfc818560008061ab65565b9250506001548114617d76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b6000617d86615ecc565b617df8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b617e08617e0361bced565b61ab57565b821115617e60576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061de986028913960400191505060405180910390fd5b600b6000015483141580617ea55750617ea3600b600101604051806020016040529081600082015481525050617e958461b90f565b61c40b90919063ffffffff16565b155b617efa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602981526020018061dee36029913960400191505060405180910390fd5b6040518060400160405280848152602001617f148461b90f565b815250600b600082015181600001556020820151816001016000820151816000015550509050507f4b48724280029c2ea7a445c9cea30838525342e7a9ea9468f630b52e75d6c5368383604051808381526020018281526020019250505060405180910390a16001905092915050565b60606000617f9061a514565b90506060600680549050604051908082528060200260200182016040528015617fc85781602001602082028038833980820191505090505b50905060008090505b815181101561812a578273ffffffffffffffffffffffffffffffffffffffff16634ce38b5f6006838154811061800357fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561808e57600080fd5b505afa1580156180a2573d6000803e3d6000fd5b505050506040513d60208110156180b857600080fd5b81019080805190602001909291905050508282815181106180d557fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505061812360018261aab890919063ffffffff16565b9050617fd1565b50809250505090565b60008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146181d6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f4f6e6c7920564d2063616e2063616c6c0000000000000000000000000000000081525060200191505060405180910390fd5b6181e0838361c420565b905092915050565b6060600680548060200260200160405190810160405280929190818152602001828054801561826c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311618222575b5050505050905090565b600061828182613a8c565b6182f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061835a8160090160000160405180602001604052908160008201548152505061ab57565b915050919050565b600061836d8261a079565b1561837f5760076000015490506184e2565b61838882613a8c565b156184dd5760006183df6001600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001016002015461c9ae565b90506000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060080190506000818054905011156184bc57600061844e6001838054905061aa6e90919063ffffffff16565b90505b60008111156184ba574261848960096001015484848154811061847057fe5b906000526020600020015461aab890919063ffffffff16565b1061849f57618498818461c9ae565b92506184ba565b6184b360018261aa6e90919063ffffffff16565b9050618451565b505b6184d48260096000015461c9c890919063ffffffff16565b925050506184e2565b600090505b919050565b60006060600060f873ffffffffffffffffffffffffffffffffffffffff166040516020016040516020818303038152906040526040518082805190602001908083835b6020831061854d578051825260208201915060208101905060208303925061852a565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146185ad576040519150601f19603f3d011682016040523d82523d6000602084013e6185b2565b606091505b50809350819250505080618611576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061ddad6025913960400191505060405180910390fd5b61861c82600061ab40565b9250505090565b600f5481565b6000618633615ecc565b6186a5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8160001061871b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f4d61782067726f75702073697a652063616e6e6f74206265207a65726f00000081525060200191505060405180910390fd5b600e54821415618793576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d61782067726f75702073697a65206e6f74206368616e67656400000000000081525060200191505060405180910390fd5b81600e819055507f603fe12c33c253a23da1680aa453dc70c3a0ee07763569bd5f602406ebd4e5d5826040518082815260200191505060405180910390a160019050919050565b60018060008282540192505081905550600060015490506187f961c2c6565b73ffffffffffffffffffffffffffffffffffffffff166357601c5d336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561887557600080fd5b505afa158015618889573d6000803e3d6000fd5b505050506040513d602081101561889f57600080fd5b8101908080519060200190929190505050618922576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f6e6c79207265676973746572656420736c61736865722063616e2063616c6c81525060200191505060405180910390fd5b61892b8261a079565b156189d9576000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146189d7576189d5818461bd5d565b505b505b6001548114618a50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5050565b6000618a986003618a8a6002618a7c6002618a6e88616559565b61c9c890919063ffffffff16565b61aab890919063ffffffff16565b61c3c190919063ffffffff16565b9050919050565b6000618aa961a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015618b2557600080fd5b505afa158015618b39573d6000803e3d6000fd5b505050506040513d6020811015618b4f57600080fd5b81019080805190602001909291905050509050618b6b81613a8c565b618bdd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f7420612076616c696461746f722067726f7570000000000000000000000081525060200191505060405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600701541415618c9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f4e6f20636f6d6d697373696f6e2075706461746520717565756564000000000081525060200191505060405180910390fd5b4381600701541115618cf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061dae46021913960400191505060405180910390fd5b80600601816005016000820154816000015590505080600601600080820160009055505080600701600090558173ffffffffffffffffffffffffffffffffffffffff167f815d292dbc1a08dfb3103aabb6611233dd2393903e57bdf4c5b3db91198a826c618d7d8360050160405180602001604052908160008201548152505061ab57565b6040518082815260200191505060405180910390a25050565b600060018060008282540192505081905550600060015490506000618db961a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015618e3557600080fd5b505afa158015618e49573d6000803e3d6000fd5b505050506040513d6020811015618e5f57600080fd5b81019080805190602001909291905050509050618e7b8161a079565b158015618e8e5750618e8c81613a8c565b155b618f00576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f416c72656164792072656769737465726564000000000000000000000000000081525060200191505060405180910390fd5b6000618f0a61c2c6565b73ffffffffffffffffffffffffffffffffffffffff166330ec70f5836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015618f8657600080fd5b505afa158015618f9a573d6000803e3d6000fd5b505050506040513d6020811015618fb057600080fd5b8101908080519060200190929190505050905060076000015481101561903e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f4465706f73697420746f6f20736d616c6c00000000000000000000000000000081525060200191505060405180910390fd5b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600061908b61a514565b73ffffffffffffffffffffffffffffffffffffffff16634ce38b5f856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561910757600080fd5b505afa15801561911b573d6000803e3d6000fd5b505050506040513d602081101561913157600080fd5b810190808051906020019092919050505090506191948285838f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b30b565b5061922982858c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061b6c7565b5060068490806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061929b84600061ca4e565b508373ffffffffffffffffffffffffffffffffffffffff167fd09501348473474a20c772c79c653e1fd7e8b437e418fe235d277d2c8885325160405160405180910390a26001955050505050600154811461935e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b509695505050505050565b60006193748461a079565b6193e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6193ee616549565b831115619446576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602381526020018061dcfc6023913960400191505060405180910390fd5b6000600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060040190506194a78160010154826000015461aab890919063ffffffff16565b831061951b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f696e646578206f7574206f6620626f756e64730000000000000000000000000081525060200191505060405180910390fd5b80600001548310158015619533575060008160010154115b6195a5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f696e646578206f7574206f6620626f756e64730000000000000000000000000081525060200191505060405180910390fd5b6000848260020160008681526020019081526020016000206000015414905060006195de6001846001015461aa6e90919063ffffffff16565b6195f584600001548761aa6e90919063ffffffff16565b1490506000868460020160008881526020019081526020016000206000015410801561965357508684600201600061963760018a61aab890919063ffffffff16565b81526020019081526020016000206000015411806196525750815b5b9050828061965e5750805b6196b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252604781526020018061dbe56047913960600191505060405180910390fd5b83600201600087815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169450505050509392505050565b6000806000871415801561970e575060008514155b619780576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f612064656e6f6d696e61746f72206973207a65726f000000000000000000000081525060200191505060405180910390fd5b6000806000606060fc73ffffffffffffffffffffffffffffffffffffffff168c8c8c8c8c8c6040516020018087815260200186815260200185815260200184815260200183815260200182815260200196505050505050506040516020818303038152906040526040518082805190602001908083835b6020831061981a57805182526020820191506020810190506020830392506197f7565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461987a576040519150601f19603f3d011682016040523d82523d6000602084013e61987f565b606091505b508092508193505050816198de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061dd656027913960400191505060405180910390fd5b6198e981600061ab40565b93506198f681602061ab40565b925083839550955050505050965096945050505050565b6000600180600082825401925050819055506000600154905061993661993161bced565b61ab57565b83111561998e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061de736025913960400191505060405180910390fd5b600061999861a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015619a1457600080fd5b505afa158015619a28573d6000803e3d6000fd5b505050506040513d6020811015619a3e57600080fd5b81019080805190602001909291905050509050619a5a8161a079565b15619acd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f416c726561647920726567697374657265642061732076616c696461746f720081525060200191505060405180910390fd5b619ad681613a8c565b15619b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f416c726561647920726567697374657265642061732067726f7570000000000081525060200191505060405180910390fd5b6000619b5361c2c6565b73ffffffffffffffffffffffffffffffffffffffff166330ec70f5836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015619bcf57600080fd5b505afa158015619be3573d6000803e3d6000fd5b505050506040513d6020811015619bf957600080fd5b81019080805190602001909291905050509050600960000154811015619c87576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f4e6f7420656e6f756768206c6f636b656420676f6c640000000000000000000081525060200191505060405180910390fd5b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060018160000160006101000a81548160ff021916908315150217905550619cf08661b90f565b81600501600082015181600001559050506040518060400160405280619d1461bced565b81526020016000815250816009016000820151816000016000820151816000015550506020820151816001015590505060058390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508273ffffffffffffffffffffffffffffffffffffffff167fbf4b45570f1907a94775f8449817051a492a676918e38108bb762e991e6b58dc876040518082815260200191505060405180910390a2600194505050506001548114619e76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b50919050565b6000619e86615ecc565b619ef8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b81600010619f51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061dcd46028913960400191505060405180910390fd5b600d54821415619fac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061dd406025913960400191505060405180910390fd5b81600d819055507f1c75c7fb3ee9d13d8394372d8c7cdf1702fa947faa03f6ccfa500f787b09b48a826040518082815260200191505060405180910390a160019050919050565b619ffb615ecc565b61a06d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b61a0768161bba9565b50565b600080600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600101805460018160011615610100020316600290049050119050919050565b60006060600060f573ffffffffffffffffffffffffffffffffffffffff1684604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061a14f578051825260208201915060208101905060208303925061a12c565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461a1af576040519150601f19603f3d011682016040523d82523d6000602084013e61a1b4565b606091505b5080935081925050508061a213576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c81526020018061ddd2602c913960400191505060405180910390fd5b61a21e82600061b27a565b92505050919050565b60006001806000828254019250508190555060006001549050600061a24a61a514565b73ffffffffffffffffffffffffffffffffffffffff166364439b43336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561a2c657600080fd5b505afa15801561a2da573d6000803e3d6000fd5b505050506040513d602081101561a2f057600080fd5b8101908080519060200190929190505050905061a30c8161a079565b61a37e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561a488576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f6465616666696c696174653a206e6f7420616666696c6961746564000000000081525060200191505060405180910390fd5b61a492818361bd5d565b50600193505050600154811461a510576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f7265656e7472616e742063616c6c00000000000000000000000000000000000081525060200191505060405180910390fd5b5090565b6000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561a5cf57600080fd5b505afa15801561a5e3573d6000803e3d6000fd5b505050506040513d602081101561a5f957600080fd5b8101908080519060200190929190505050905090565b600080600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508373ffffffffffffffffffffffffffffffffffffffff16600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461a756576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f4e6f7420616666696c696174656420746f2067726f757000000000000000000081525060200191505060405180910390fd5b806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091856040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561a7de57600080fd5b505af415801561a7f2573d6000803e3d6000fd5b505050506040513d602081101561a80857600080fd5b810190808051906020019092919050505061a88b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4e6f742061206d656d626572206f66207468652067726f75700000000000000081525060200191505060405180910390fd5b806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763e2c0c56a9091856040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561a91357600080fd5b505af415801561a927573d6000803e3d6000fd5b50505050600081600101600201549050600081141561a9df5761a94861ce5f565b73ffffffffffffffffffffffffffffffffffffffff1663a8e45871866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561a9c657600080fd5b505af115801561a9da573d6000803e3d6000fd5b505050505b61a9ea84600061ca4e565b5061aa088561aa0360018461aab890919063ffffffff16565b61cf5a565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fc7666a52a66ff601ff7c0d4d6efddc9ac20a34792f6aa003d1804c9d4d5baa5760405160405180910390a360019250505092915050565b600061aab083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061d083565b905092915050565b60008082840190508381101561ab36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600061ab4c838361b27a565b60001c905092915050565b600081600001519050919050565b600061ab7085613a8c565b801561ab81575061ab808461a079565b5b61abf3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f4e6f742076616c696461746f7220616e642067726f757000000000000000000081525060200191505060405180910390fd5b6000600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600e5481600101600201541061acb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f67726f757020776f756c6420657863656564206d6178696d756d2073697a650081525060200191505060405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff16600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461adb7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f4e6f7420616666696c696174656420746f2067726f757000000000000000000081525060200191505060405180910390fd5b806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091876040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561ae3f57600080fd5b505af415801561ae53573d6000803e3d6000fd5b505050506040513d602081101561ae6957600080fd5b81019080805190602001909291905050501561aeed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f416c726561647920696e2067726f75700000000000000000000000000000000081525060200191505060405180910390fd5b600061af0a6001836001016002015461aab890919063ffffffff16565b9050816001017399dc63c6a9f533aac37df3153f6fc72ed8094cf76326afac499091886040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561af9457600080fd5b505af415801561afa8573d6000803e3d6000fd5b5050505061afb587617a6e565b61b027576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f47726f757020726571756972656d656e7473206e6f74206d657400000000000081525060200191505060405180910390fd5b61b03086617a6e565b61b0a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f56616c696461746f7220726571756972656d656e7473206e6f74206d6574000081525060200191505060405180910390fd5b600181141561b1b25761b0b361ce5f565b73ffffffffffffffffffffffffffffffffffffffff1663a18fb2db8887876040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019350505050600060405180830381600087803b15801561b19957600080fd5b505af115801561b1ad573d6000803e3d6000fd5b505050505b61b1bc868861ca4e565b5061b1da8761b1d560018461aa6e90919063ffffffff16565b61cf5a565b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fbdf7e616a6943f81e07a7984c9d4c00197dc2f481486ce4ffa6af52a113974ad60405160405180910390a3600192505050949350505050565b60008082848161b24e57fe5b049050600083858161b25c57fe5b06141561b26c578091505061b274565b600181019150505b92915050565b6000602082018351101561b2f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f736c6963696e67206f7574206f662072616e676500000000000000000000000081525060200191505060405180910390fd5b60006020830184015190508091505092915050565b6000604082511461b384576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f57726f6e67204543445341207075626c6963206b6579206c656e67746800000081525060200191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff16828051906020012060001c73ffffffffffffffffffffffffffffffffffffffff161461b42f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f4543445341206b657920646f6573206e6f74206d61746368207369676e65720081525060200191505060405180910390fd5b8185600001600001908051906020019061b44a92919061d960565b508373ffffffffffffffffffffffffffffffffffffffff167f213377eec2c15b21fa7abcbb0cb87a67e893cdb94a2564aa4bb4d380869473c8836040518080602001828103825283818151815260200191508051906020019080838360005b8381101561b4c457808201518184015260208101905061b4a9565b50505050905090810190601f16801561b4f15780820380516001836020036101000a031916815260200191505b509250505060405180910390a260019050949350505050565b82805490508110801561b57e57508173ffffffffffffffffffffffffffffffffffffffff1683828154811061b53b57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b61b5d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061dd8c6021913960400191505060405180910390fd5b600061b5ed6001858054905061aa6e90919063ffffffff16565b905083818154811061b5fb57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684838154811061b63257fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083818154811061b68657fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905580848161b6c0919061d9e0565b5050505050565b6000606083511461b740576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f57726f6e6720424c53207075626c6963206b6579206c656e677468000000000081525060200191505060405180910390fd5b603082511461b7b7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f57726f6e6720424c5320506f50206c656e67746800000000000000000000000081525060200191505060405180910390fd5b61b7c2848484612d3c565b61b834576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f496e76616c696420424c5320506f50000000000000000000000000000000000081525060200191505060405180910390fd5b8285600001600101908051906020019061b84f92919061d960565b508373ffffffffffffffffffffffffffffffffffffffff167f36a1aabe506bbe8802233cbb9aad628e91269e77077c953f9db3e02d7092ee33846040518080602001828103825283818151815260200191508051906020019080838360005b8381101561b8c957808201518184015260208101905061b8ae565b50505050905090810190601f16801561b8f65780820380516001836020036101000a031916815260200191505b509250505060405180910390a260019050949350505050565b61b91761d905565b6040518060200160405280838152509050919050565b61b93561d905565b600082600001518460000151019050836000015181101561b9be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f616464206f766572666c6f77206465746563746564000000000000000000000081525060200191505060405180910390fd5b60405180602001604052808281525091505092915050565b61b9de61d905565b61b9e661d143565b82111561ba3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061db8a6036913960400191505060405180910390fd5b604051806020016040528069d3c21bcecceda100000084028152509050919050565b61ba6861d905565b60008260000151141561bae3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f63616e277420646976696465206279203000000000000000000000000000000081525060200191505060405180910390fd5b600069d3c21bcecceda10000008460000151029050836000015169d3c21bcecceda1000000828161bb1057fe5b041461bb84576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f6f766572666c6f7720617420646976696465000000000000000000000000000081525060200191505060405180910390fd5b60405180602001604052808460000151838161bb9c57fe5b0481525091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561bc2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602681526020018061da836026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61bcf561d905565b604051806020016040528069d3c21bcecceda1000000815250905090565b600033905090565b61bd2361d905565b61bd2b61d905565b61bd348461b9d6565b905061bd3e61d905565b61bd478461b9d6565b905061bd53828261ba60565b9250505092915050565b6000808360020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806001017399dc63c6a9f533aac37df3153f6fc72ed8094cf763542424fb9091866040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561be5257600080fd5b505af415801561be66573d6000803e3d6000fd5b505050506040513d602081101561be7c57600080fd5b81019080805190602001909291905050501561be9e5761be9c828561a60f565b505b60008560020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f71815121f0622b31a3e7270eb28acb9fd10825ff418c9a18591f617bb8a31a6c60405160405180910390a360019250505092915050565b600061bf5261a514565b73ffffffffffffffffffffffffffffffffffffffff166393c5c487846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561bfce57600080fd5b505afa15801561bfe2573d6000803e3d6000fd5b505050506040513d602081101561bff857600080fd5b8101908080519060200190929190505050905061c0148161a079565b61c086576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b61c08e61d905565b61c09f61c09a84615f2a565b61b90f565b905061c0a961d905565b61c0d582600b60010160405180602001604052908160008201548152505061d16290919063ffffffff16565b905061c0df61d905565b61c112600b60010160405180602001604052908160008201548152505061c10461bced565b61d5c190919063ffffffff16565b905061c17d600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003016040518060200160405290816000820154815250508261d16290919063ffffffff16565b905061c1b361c1ae61c18e8561ab57565b61c1a961c1a4858761b92d90919063ffffffff16565b61ab57565b61d668565b61b90f565b600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600301600082015181600001559050508373ffffffffffffffffffffffffffffffffffffffff167fedf9f87e50e10c533bf3ae7f5a7894ae66c23e6cbbe8773d7765d20ad6f995e961c299600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030160405180602001604052908160008201548152505061ab57565b61c2a28661ab57565b604051808381526020018281526020019250505060405180910390a2505050505050565b6000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4c6f636b6564476f6c6400000000000000000000000000000000000000000000815250600a019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561c38157600080fd5b505afa15801561c395573d6000803e3d6000fd5b505050506040513d602081101561c3ab57600080fd5b8101908080519060200190929190505050905090565b600061c40383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061d681565b905092915050565b60008160000151836000015114905092915050565b60008061c42b61a514565b73ffffffffffffffffffffffffffffffffffffffff166393c5c487856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561c4a757600080fd5b505afa15801561c4bb573d6000803e3d6000fd5b505050506040513d602081101561c4d157600080fd5b8101908080519060200190929190505050905061c4ed8161a079565b61c55f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f7420612076616c696461746f72000000000000000000000000000000000081525060200191505060405180910390fd5b600061c56a82612761565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561c5f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061dbc06025913960400191505060405180910390fd5b61c5fb82617a6e565b801561c60c575061c60b81617a6e565b5b1561c9a15761c61961d905565b61c6f5600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060090160000160405180602001604052908160008201548152505061c6e7600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030160405180602001604052908160008201548152505061c6d98961b9d6565b61d16290919063ffffffff16565b61d16290919063ffffffff16565b9050600061c76a61c765600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206005016040518060200160405290816000820154815250508461d16290919063ffffffff16565b61d747565b9050600061c7898261c77b8561d747565b61aa6e90919063ffffffff16565b905061c79361d768565b73ffffffffffffffffffffffffffffffffffffffff166340c10f1985846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561c81957600080fd5b505af115801561c82d573d6000803e3d6000fd5b505050506040513d602081101561c84357600080fd5b81019080805190602001909291905050505061c85d61d768565b73ffffffffffffffffffffffffffffffffffffffff166340c10f1986836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561c8e357600080fd5b505af115801561c8f7573d6000803e3d6000fd5b505050506040513d602081101561c90d57600080fd5b8101908080519060200190929190505050508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6f5937add2ec38a0fa4959bccd86e3fcc2aafb706cd3e6c0565f87a7b36b99758385604051808381526020018281526020019250505060405180910390a361c9958361d747565b9550505050505061c9a8565b6000925050505b92915050565b60008183101561c9be578161c9c0565b825b905092915050565b60008083141561c9db576000905061ca48565b600082840290508284828161c9ec57fe5b041461ca43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061dd1f6021913960400191505060405180910390fd5b809150505b92915050565b600080600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206004019050600061ca9f616549565b905060008083600101541461cae15761cadc61cac96001856001015461aa6e90919063ffffffff16565b846000015461aab890919063ffffffff16565b61cae4565b60005b90506000836001015411801561cb265750600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b1561cb35574283600301819055505b8183600201600083815260200190815260200160002060000154141561cbf55760405180604001604052808381526020018673ffffffffffffffffffffffffffffffffffffffff168152508360020160008381526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506001935050505061ce59565b60008084600101541461cc1b5761cc1660018361aab890919063ffffffff16565b61cc1e565b60005b905060405180604001604052808481526020018773ffffffffffffffffffffffffffffffffffffffff168152508460020160008381526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050600d548460010154101561cce75761ccda6001856001015461aab890919063ffffffff16565b846001018190555061ce50565b600d548460010154141561cd6557836002016000856000015481526020019081526020016000206000808201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505061cd586001856000015461aab890919063ffffffff16565b846000018190555061ce4f565b836002016000856000015481526020019081526020016000206000808201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505083600201600061cdce6001876000015461aab890919063ffffffff16565b81526020019081526020016000206000808201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505061ce266001856001015461aa6e90919063ffffffff16565b846001018190555061ce466002856000015461aab890919063ffffffff16565b84600001819055505b5b60019450505050505b92915050565b6000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f456c656374696f6e0000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561cf1a57600080fd5b505afa15801561cf2e573d6000803e3d6000fd5b505050506040513d602081101561cf4457600080fd5b8101908080519060200190929190505050905090565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206008019050808054905082141561cfdc578042908060018154018082558091505090600182039060005260206000200160009091929091909150555061d07e565b808054905082101561d008574281838154811061cff557fe5b906000526020600020018190555061d07d565b600061d07c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f556e61626c6520746f207570646174652073697a6520686973746f727900000081525060200191505060405180910390fd5b5b5b505050565b600083831115829061d130576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561d0f557808201518184015260208101905061d0da565b50505050905090810190601f16801561d1225780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b60007601357c299a88ea76a58924d52ce4f26a85af186c2b9e74905090565b61d16a61d905565b60008360000151148061d181575060008260000151145b1561d19d5760405180602001604052806000815250905061d5bb565b69d3c21bcecceda10000008260000151141561d1bb5782905061d5bb565b69d3c21bcecceda10000008360000151141561d1d95781905061d5bb565b600069d3c21bcecceda100000061d1ef8561d863565b600001518161d1fa57fe5b049050600061d2088561d89a565b600001519050600069d3c21bcecceda100000061d2248661d863565b600001518161d22f57fe5b049050600061d23d8661d89a565b600001519050600082850290506000851461d2d1578285828161d25c57fe5b041461d2d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b600069d3c21bcecceda1000000820290506000821461d3735769d3c21bcecceda100000082828161d2fe57fe5b041461d372576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f6f766572666c6f772078317931202a206669786564312064657465637465640081525060200191505060405180910390fd5b5b809150600084860290506000861461d404578486828161d38f57fe5b041461d403576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279312064657465637465640000000000000000000081525060200191505060405180910390fd5b5b600084880290506000881461d492578488828161d41d57fe5b041461d491576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783179322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b61d49a61d8d7565b878161d4a257fe5b04965061d4ad61d8d7565b858161d4b557fe5b049450600085880290506000881461d546578588828161d4d157fe5b041461d545576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6f766572666c6f7720783279322064657465637465640000000000000000000081525060200191505060405180910390fd5b5b61d54e61d905565b604051806020016040528087815250905061d5778160405180602001604052808781525061b92d565b905061d5918160405180602001604052808681525061b92d565b905061d5ab8160405180602001604052808581525061b92d565b9050809a50505050505050505050505b92915050565b61d5c961d905565b81600001518360000151101561d647576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f737562737472616374696f6e20756e646572666c6f772064657465637465640081525060200191505060405180910390fd5b60405180602001604052808360000151856000015103815250905092915050565b600081831061d677578161d679565b825b905092915050565b6000808311829061d72d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561d6f257808201518184015260208101905061d6d7565b50505050905090810190601f16801561d71f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161d73957fe5b049050809150509392505050565b600069d3c21bcecceda100000082600001518161d76057fe5b049050919050565b6000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f537461626c65546f6b656e000000000000000000000000000000000000000000815250600b019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561d82357600080fd5b505afa15801561d837573d6000803e3d6000fd5b505050506040513d602081101561d84d57600080fd5b8101908080519060200190929190505050905090565b61d86b61d905565b604051806020016040528069d3c21bcecceda10000008085600001518161d88e57fe5b04028152509050919050565b61d8a261d905565b604051806020016040528069d3c21bcecceda10000008085600001518161d8c557fe5b04028460000151038152509050919050565b600064e8d4a51000905090565b508054600082559060005260206000209081019061d902919061da0c565b50565b6040518060200160405280600081525090565b50805460018160011615610100020316600290046000825580601f1061d93e575061d95d565b601f01602090049060005260206000209081019061d95c919061da0c565b5b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061d9a157805160ff191683800117855561d9cf565b8280016001018555821561d9cf579182015b8281111561d9ce57825182559160200191906001019061d9b3565b5b50905061d9dc919061da0c565b5090565b81548183558181111561da075781836000526020600020918201910161da06919061da0c565b5b505050565b61da2e91905b8082111561da2a57600081600090555060010161da12565b5090565b9056fe56616c696461746f7220646f65736e2774206d65657420726571756972656d656e74736572726f722063616c6c696e67206e756d62657256616c696461746f7273496e53657420707265636f6d70696c654f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373607265736574536c617368696e674d756c7469706c696572602063616c6c6564206265666f7265207265736574506572696f64206578706972656443616e2774206170706c7920636f6d6d697373696f6e2075706461746520796574557074696d65206172726179206c6172676572207468616e206d6178696d756d2067726f75702073697a6556616c696461746f7220726571756972656d656e7473206e6f74206368616e6765646572726f722063616c6c696e672067657456657269666965645365616c4269746d617046726f6d48656164657220707265636f6d70696c6563616e277420637265617465206669786964697479206e756d626572206c6172676572207468616e206d61784e65774669786564282956616c696461746f72206e6f742072656769737465726564207769746820612067726f757070726f766964656420696e64657820646f6573206e6f74206d617463682070726f76696465642065706f63684e756d62657220617420696e64657820696e20686973746f72792e6572726f722063616c6c696e672076616c696461746f725369676e65724164647265737346726f6d43757272656e7453657420707265636f6d70696c656572726f722063616c6c696e67206e756d62657256616c696461746f7273496e43757272656e7453657420707265636f6d70696c656572726f722063616c6c696e672076616c696461746f725369676e65724164647265737346726f6d53657420707265636f6d70696c654d656d6265727368697020686973746f7279206c656e6774682063616e6e6f74206265207a65726f45706f63682063616e6e6f74206265206c6172676572207468616e2063757272656e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774d656d6265727368697020686973746f7279206c656e677468206e6f74206368616e6765646572726f722063616c6c696e67206672616374696f6e4d756c45787020707265636f6d70696c6564656c657465456c656d656e743a20696e646578206f7574206f662072616e67656572726f722063616c6c696e672067657445706f636853697a6520707265636f6d70696c656572726f722063616c6c696e6720676574506172656e745365616c4269746d617020707265636f6d70696c65636f6d6d697373696f6e207570646174652064656c6179206e6f74206368616e6765646572726f722063616c6c696e6720676574426c6f636b4e756d62657246726f6d48656164657220707265636f6d70696c654861736e2774206265656e20656d70747920666f72206c6f6e6720656e6f756768436f6d6d697373696f6e2063616e27742062652067726561746572207468616e203130302541646a7573746d656e742073706565642063616e6e6f74206265206c6172676572207468616e20316572726f722063616c6c696e67206861736848656164657220707265636f6d70696c6541646a7573746d656e7420737065656420616e64206578706f6e656e74206e6f74206368616e676564a165627a7a72305820619b3bc67036ab7d118a8b3de96061f39f82056b7d829dbbcac49816e90060bd0029

External libraries