Address Details
contract

0x4abb96Ce263E7cc70cDfd657A6D90d6BDa3dC604

Contract Name
SortedOracles
Creator
0x0cc59e–f1502d at 0xd66d9a–e80b0b
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
2159432
Contract name:
SortedOracles




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




Verified at
2020-08-11T19:20:11.909101Z

Contract source code

pragma solidity ^0.5.3;


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;
    }
}

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);
}

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());
  }
}

contract Initializable {
  bool public initialized;

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

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 SortedLinkedList {
  using SafeMath for uint256;
  using LinkedList for LinkedList.List;

  struct List {
    LinkedList.List list;
    mapping(bytes32 => uint256) values;
  }

  
  function insert(
    List storage list,
    bytes32 key,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) public {
    require(
      key != bytes32(0) && key != lesserKey && key != greaterKey && !contains(list, key),
      "invalid key"
    );
    require(
      (lesserKey != bytes32(0) || greaterKey != bytes32(0)) || list.list.numElements == 0,
      "greater and lesser key zero"
    );
    require(contains(list, lesserKey) || lesserKey == bytes32(0), "invalid lesser key");
    require(contains(list, greaterKey) || greaterKey == bytes32(0), "invalid greater key");
    (lesserKey, greaterKey) = getLesserAndGreater(list, value, lesserKey, greaterKey);
    list.list.insert(key, lesserKey, greaterKey);
    list.values[key] = value;
  }

  
  function remove(List storage list, bytes32 key) public {
    list.list.remove(key);
    list.values[key] = 0;
  }

  
  function update(
    List storage list,
    bytes32 key,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) public {
    
    
    
    remove(list, key);
    insert(list, key, value, lesserKey, greaterKey);
  }

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

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

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

  
  function getValue(List storage list, bytes32 key) public view returns (uint256) {
    return list.values[key];
  }

  
  function getElements(List storage list) public view returns (bytes32[] memory, uint256[] memory) {
    bytes32[] memory keys = getKeys(list);
    uint256[] memory values = new uint256[](keys.length);
    for (uint256 i = 0; i < keys.length; i = i.add(1)) {
      values[i] = list.values[keys[i]];
    }
    return (keys, values);
  }

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

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

  
  
  function getLesserAndGreater(
    List storage list,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) private view returns (bytes32, bytes32) {
    
    
    
    
    
    if (lesserKey == bytes32(0) && isValueBetween(list, value, lesserKey, list.list.tail)) {
      return (lesserKey, list.list.tail);
    } else if (
      greaterKey == bytes32(0) && isValueBetween(list, value, list.list.head, greaterKey)
    ) {
      return (list.list.head, greaterKey);
    } else if (
      lesserKey != bytes32(0) &&
      isValueBetween(list, value, lesserKey, list.list.elements[lesserKey].nextKey)
    ) {
      return (lesserKey, list.list.elements[lesserKey].nextKey);
    } else if (
      greaterKey != bytes32(0) &&
      isValueBetween(list, value, list.list.elements[greaterKey].previousKey, greaterKey)
    ) {
      return (list.list.elements[greaterKey].previousKey, greaterKey);
    } else {
      require(false, "get lesser and greater failure");
    }
  }

  
  function isValueBetween(List storage list, uint256 value, bytes32 lesserKey, bytes32 greaterKey)
    private
    view
    returns (bool)
  {
    bool isLesser = lesserKey == bytes32(0) || list.values[lesserKey] <= value;
    bool isGreater = greaterKey == bytes32(0) || list.values[greaterKey] >= value;
    return isLesser && isGreater;
  }
}

library SortedLinkedListWithMedian {
  using SafeMath for uint256;
  using SortedLinkedList for SortedLinkedList.List;

  enum MedianAction { None, Lesser, Greater }

  enum MedianRelation { Undefined, Lesser, Greater, Equal }

  struct List {
    SortedLinkedList.List list;
    bytes32 median;
    mapping(bytes32 => MedianRelation) relation;
  }

  
  function insert(
    List storage list,
    bytes32 key,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) public {
    list.list.insert(key, value, lesserKey, greaterKey);
    LinkedList.Element storage element = list.list.list.elements[key];

    MedianAction action = MedianAction.None;
    if (list.list.list.numElements == 1) {
      list.median = key;
      list.relation[key] = MedianRelation.Equal;
    } else if (list.list.list.numElements % 2 == 1) {
      
      
      
      if (
        element.previousKey == bytes32(0) ||
        list.relation[element.previousKey] == MedianRelation.Lesser
      ) {
        action = MedianAction.Lesser;
        list.relation[key] = MedianRelation.Lesser;
      } else {
        list.relation[key] = MedianRelation.Greater;
      }
    } else {
      
      
      
      if (
        element.nextKey == bytes32(0) || list.relation[element.nextKey] == MedianRelation.Greater
      ) {
        action = MedianAction.Greater;
        list.relation[key] = MedianRelation.Greater;
      } else {
        list.relation[key] = MedianRelation.Lesser;
      }
    }
    updateMedian(list, action);
  }

  
  function remove(List storage list, bytes32 key) public {
    MedianAction action = MedianAction.None;
    if (list.list.list.numElements == 0) {
      list.median = bytes32(0);
    } else if (list.list.list.numElements % 2 == 0) {
      
      
      
      if (
        list.relation[key] == MedianRelation.Greater || list.relation[key] == MedianRelation.Equal
      ) {
        action = MedianAction.Lesser;
      }
    } else {
      
      
      
      if (
        list.relation[key] == MedianRelation.Lesser || list.relation[key] == MedianRelation.Equal
      ) {
        action = MedianAction.Greater;
      }
    }
    updateMedian(list, action);

    list.list.remove(key);
  }

  
  function update(
    List storage list,
    bytes32 key,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) public {
    
    
    
    remove(list, key);
    insert(list, key, value, lesserKey, greaterKey);
  }

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

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

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

  
  function getValue(List storage list, bytes32 key) public view returns (uint256) {
    return list.list.values[key];
  }

  
  function getMedianValue(List storage list) public view returns (uint256) {
    return getValue(list, list.median);
  }

  
  function getHead(List storage list) external view returns (bytes32) {
    return list.list.list.head;
  }

  
  function getMedian(List storage list) external view returns (bytes32) {
    return list.median;
  }

  
  function getTail(List storage list) external view returns (bytes32) {
    return list.list.list.tail;
  }

  
  function getNumElements(List storage list) external view returns (uint256) {
    return list.list.list.numElements;
  }

  
  function getElements(List storage list)
    public
    view
    returns (bytes32[] memory, uint256[] memory, MedianRelation[] memory)
  {
    bytes32[] memory keys = getKeys(list);
    uint256[] memory values = new uint256[](keys.length);
    MedianRelation[] memory relations = new MedianRelation[](keys.length);
    for (uint256 i = 0; i < keys.length; i = i.add(1)) {
      values[i] = list.list.values[keys[i]];
      relations[i] = list.relation[keys[i]];
    }
    return (keys, values, relations);
  }

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

  
  function updateMedian(List storage list, MedianAction action) private {
    LinkedList.Element storage previousMedian = list.list.list.elements[list.median];
    if (action == MedianAction.Lesser) {
      list.relation[list.median] = MedianRelation.Greater;
      list.median = previousMedian.previousKey;
    } else if (action == MedianAction.Greater) {
      list.relation[list.median] = MedianRelation.Lesser;
      list.median = previousMedian.nextKey;
    }
    list.relation[list.median] = MedianRelation.Equal;
  }
}

library AddressSortedLinkedListWithMedian {
  using SafeMath for uint256;
  using SortedLinkedListWithMedian for SortedLinkedListWithMedian.List;

  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(
    SortedLinkedListWithMedian.List storage list,
    address key,
    uint256 value,
    address lesserKey,
    address greaterKey
  ) public {
    list.insert(toBytes(key), value, toBytes(lesserKey), toBytes(greaterKey));
  }

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

  
  function update(
    SortedLinkedListWithMedian.List storage list,
    address key,
    uint256 value,
    address lesserKey,
    address greaterKey
  ) public {
    list.update(toBytes(key), value, toBytes(lesserKey), toBytes(greaterKey));
  }

  
  function contains(SortedLinkedListWithMedian.List storage list, address key)
    public
    view
    returns (bool)
  {
    return list.contains(toBytes(key));
  }

  
  function getValue(SortedLinkedListWithMedian.List storage list, address key)
    public
    view
    returns (uint256)
  {
    return list.getValue(toBytes(key));
  }

  
  function getMedianValue(SortedLinkedListWithMedian.List storage list)
    public
    view
    returns (uint256)
  {
    return list.getValue(list.median);
  }

  
  function getHead(SortedLinkedListWithMedian.List storage list) external view returns (address) {
    return toAddress(list.getHead());
  }

  
  function getMedian(SortedLinkedListWithMedian.List storage list) external view returns (address) {
    return toAddress(list.getMedian());
  }

  
  function getTail(SortedLinkedListWithMedian.List storage list) external view returns (address) {
    return toAddress(list.getTail());
  }

  
  function getNumElements(SortedLinkedListWithMedian.List storage list)
    external
    view
    returns (uint256)
  {
    return list.getNumElements();
  }

  
  function getElements(SortedLinkedListWithMedian.List storage list)
    public
    view
    returns (address[] memory, uint256[] memory, SortedLinkedListWithMedian.MedianRelation[] memory)
  {
    bytes32[] memory byteKeys = list.getKeys();
    address[] memory keys = new address[](byteKeys.length);
    uint256[] memory values = new uint256[](byteKeys.length);
    
    SortedLinkedListWithMedian.MedianRelation[] memory relations =
      new SortedLinkedListWithMedian.MedianRelation[](keys.length);
    for (uint256 i = 0; i < byteKeys.length; i = i.add(1)) {
      keys[i] = toAddress(byteKeys[i]);
      values[i] = list.getValue(byteKeys[i]);
      relations[i] = list.relation[byteKeys[i]];
    }
    return (keys, values, relations);
  }
}

contract SortedOracles is ISortedOracles, Ownable, Initializable {
  using SafeMath for uint256;
  using AddressSortedLinkedListWithMedian for SortedLinkedListWithMedian.List;
  using FixidityLib for FixidityLib.Fraction;

  uint256 private constant FIXED1_UINT = 1000000000000000000000000;

  
  mapping(address => SortedLinkedListWithMedian.List) private rates;
  
  mapping(address => SortedLinkedListWithMedian.List) private timestamps;
  mapping(address => mapping(address => bool)) public isOracle;
  mapping(address => address[]) public oracles;

  uint256 public reportExpirySeconds;

  event OracleAdded(address indexed token, address indexed oracleAddress);
  event OracleRemoved(address indexed token, address indexed oracleAddress);
  event OracleReported(
    address indexed token,
    address indexed oracle,
    uint256 timestamp,
    uint256 value
  );
  event OracleReportRemoved(address indexed token, address indexed oracle);
  event MedianUpdated(address indexed token, uint256 value);
  event ReportExpirySet(uint256 reportExpiry);

  modifier onlyOracle(address token) {
    require(isOracle[token][msg.sender], "sender was not an oracle for token addr");
    _;
  }

  
  function initialize(uint256 _reportExpirySeconds) external initializer {
    _transferOwnership(msg.sender);
    setReportExpiry(_reportExpirySeconds);
  }

  
  function setReportExpiry(uint256 _reportExpirySeconds) public onlyOwner {
    require(_reportExpirySeconds > 0, "report expiry seconds must be > 0");
    require(_reportExpirySeconds != reportExpirySeconds, "reportExpirySeconds hasn't changed");
    reportExpirySeconds = _reportExpirySeconds;
    emit ReportExpirySet(_reportExpirySeconds);
  }

  
  function addOracle(address token, address oracleAddress) external onlyOwner {
    require(
      token != address(0) && oracleAddress != address(0) && !isOracle[token][oracleAddress],
      "token addr was null or oracle addr was null or oracle addr is not an oracle for token addr"
    );
    isOracle[token][oracleAddress] = true;
    oracles[token].push(oracleAddress);
    emit OracleAdded(token, oracleAddress);
  }

  
  function removeOracle(address token, address oracleAddress, uint256 index) external onlyOwner {
    require(
      token != address(0) &&
        oracleAddress != address(0) &&
        oracles[token].length > index &&
        oracles[token][index] == oracleAddress,
      "token addr null or oracle addr null or index of token oracle not mapped to oracle addr"
    );
    isOracle[token][oracleAddress] = false;
    oracles[token][index] = oracles[token][oracles[token].length.sub(1)];
    oracles[token].length = oracles[token].length.sub(1);
    if (reportExists(token, oracleAddress)) {
      removeReport(token, oracleAddress);
    }
    emit OracleRemoved(token, oracleAddress);
  }

  
  function removeExpiredReports(address token, uint256 n) external {
    require(
      token != address(0) && n < timestamps[token].getNumElements(),
      "token addr null or trying to remove too many reports"
    );
    for (uint256 i = 0; i < n; i = i.add(1)) {
      (bool isExpired, address oldestAddress) = isOldestReportExpired(token);
      if (isExpired) {
        removeReport(token, oldestAddress);
      } else {
        break;
      }
    }
  }

  
  function isOldestReportExpired(address token) public view returns (bool, address) {
    require(token != address(0));
    address oldest = timestamps[token].getTail();
    uint256 timestamp = timestamps[token].getValue(oldest);
    
    if (now.sub(timestamp) >= reportExpirySeconds) {
      return (true, oldest);
    }
    return (false, oldest);
  }

  
  function report(address token, uint256 value, address lesserKey, address greaterKey)
    external
    onlyOracle(token)
  {
    uint256 originalMedian = rates[token].getMedianValue();
    if (rates[token].contains(msg.sender)) {
      rates[token].update(msg.sender, value, lesserKey, greaterKey);

      
      
      
      
      
      
      
      
      
      
      timestamps[token].remove(msg.sender);
    } else {
      rates[token].insert(msg.sender, value, lesserKey, greaterKey);
    }
    timestamps[token].insert(
      msg.sender,
      
      now,
      timestamps[token].getHead(),
      address(0)
    );
    emit OracleReported(token, msg.sender, now, value);
    uint256 newMedian = rates[token].getMedianValue();
    if (newMedian != originalMedian) {
      emit MedianUpdated(token, newMedian);
    }
  }

  
  function numRates(address token) public view returns (uint256) {
    return rates[token].getNumElements();
  }

  
  function medianRate(address token) external view returns (uint256, uint256) {
    return (rates[token].getMedianValue(), numRates(token) == 0 ? 0 : FIXED1_UINT);
  }

  
  function getRates(address token)
    external
    view
    returns (address[] memory, uint256[] memory, SortedLinkedListWithMedian.MedianRelation[] memory)
  {
    return rates[token].getElements();
  }

  
  function numTimestamps(address token) public view returns (uint256) {
    return timestamps[token].getNumElements();
  }

  
  function medianTimestamp(address token) external view returns (uint256) {
    return timestamps[token].getMedianValue();
  }

  
  function getTimestamps(address token)
    external
    view
    returns (address[] memory, uint256[] memory, SortedLinkedListWithMedian.MedianRelation[] memory)
  {
    return timestamps[token].getElements();
  }

  
  function reportExists(address token, address oracle) internal view returns (bool) {
    return rates[token].contains(oracle) && timestamps[token].contains(oracle);
  }

  
  function getOracles(address token) external view returns (address[] memory) {
    return oracles[token];
  }

  
  function removeReport(address token, address oracle) private {
    if (numTimestamps(token) == 1 && reportExists(token, oracle)) return;
    uint256 originalMedian = rates[token].getMedianValue();
    rates[token].remove(oracle);
    timestamps[token].remove(oracle);
    emit OracleReportRemoved(token, oracle);
    uint256 newMedian = rates[token].getMedianValue();
    if (newMedian != originalMedian) {
      emit MedianUpdated(token, newMedian);
    }
  }
}
        

Contract ABI

[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""},{"type":"uint256[]","name":""},{"type":"uint8[]","name":""}],"name":"getRates","inputs":[{"type":"address","name":"token"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"medianTimestamp","inputs":[{"type":"address","name":"token"}],"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":"bool","name":""}],"name":"isOracle","inputs":[{"type":"address","name":""},{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"reportExpirySeconds","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeOracle","inputs":[{"type":"address","name":"token"},{"type":"address","name":"oracleAddress"},{"type":"uint256","name":"index"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numTimestamps","inputs":[{"type":"address","name":"token"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"report","inputs":[{"type":"address","name":"token"},{"type":"uint256","name":"value"},{"type":"address","name":"lesserKey"},{"type":"address","name":"greaterKey"}],"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":"getOracles","inputs":[{"type":"address","name":"token"}],"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":"address","name":""}],"name":"oracles","inputs":[{"type":"address","name":""},{"type":"uint256","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""},{"type":"uint256[]","name":""},{"type":"uint8[]","name":""}],"name":"getTimestamps","inputs":[{"type":"address","name":"token"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numRates","inputs":[{"type":"address","name":"token"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeExpiredReports","inputs":[{"type":"address","name":"token"},{"type":"uint256","name":"n"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setReportExpiry","inputs":[{"type":"uint256","name":"_reportExpirySeconds"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"medianRate","inputs":[{"type":"address","name":"token"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addOracle","inputs":[{"type":"address","name":"token"},{"type":"address","name":"oracleAddress"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"uint256","name":"_reportExpirySeconds"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""},{"type":"address","name":""}],"name":"isOldestReportExpired","inputs":[{"type":"address","name":"token"}],"constant":true},{"type":"event","name":"OracleAdded","inputs":[{"type":"address","name":"token","indexed":true},{"type":"address","name":"oracleAddress","indexed":true}],"anonymous":false},{"type":"event","name":"OracleRemoved","inputs":[{"type":"address","name":"token","indexed":true},{"type":"address","name":"oracleAddress","indexed":true}],"anonymous":false},{"type":"event","name":"OracleReported","inputs":[{"type":"address","name":"token","indexed":true},{"type":"address","name":"oracle","indexed":true},{"type":"uint256","name":"timestamp","indexed":false},{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"OracleReportRemoved","inputs":[{"type":"address","name":"token","indexed":true},{"type":"address","name":"oracle","indexed":true}],"anonymous":false},{"type":"event","name":"MedianUpdated","inputs":[{"type":"address","name":"token","indexed":true},{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"ReportExpirySet","inputs":[{"type":"uint256","name":"reportExpiry","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false}]
              

Contract Creation Code

0x608060405260006100146100b760201b60201c565b9050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3506100bf565b600033905090565b61388e80620000cf6000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c80638f32d59b116100b8578063ebc1d6bb1161007c578063ebc1d6bb14610844578063ef90e1b014610872578063f0ca4adb146108d1578063f2fde38b14610935578063fe4b84df14610979578063ffe736bf146109a757610142565b80638f32d59b146105c5578063a00a8b2c146105e7578063b929215814610675578063bbc66a941461079e578063dd34ca3b146107f657610142565b806353a572971161010a57806353a57297146103845780636dd6ef0c146103f2578063715018a61461044a57806380e50744146104545780638da5cb5b146104e25780638e7492811461052c57610142565b806302f55b6114610147578063071b48fc14610270578063158ef93e146102c8578063370c998e146102ea578063493a353c14610366575b600080fd5b6101896004803603602081101561015d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610a36565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156101d45780820151818401526020810190506101b9565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156102165780820151818401526020810190506101fb565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561025857808201518184015260208101905061023d565b50505050905001965050505050505060405180910390f35b6102b26004803603602081101561028657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c06565b6040518082815260200191505060405180910390f35b6102d0610cd9565b604051808215151515815260200191505060405180910390f35b61034c6004803603604081101561030057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cec565b604051808215151515815260200191505060405180910390f35b61036e610d1b565b6040518082815260200191505060405180910390f35b6103f06004803603606081101561039a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610d21565b005b6104346004803603602081101561040857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061125d565b6040518082815260200191505060405180910390f35b610452611330565b005b6104e06004803603608081101561046a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611469565b005b6104ea611e40565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61056e6004803603602081101561054257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e69565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156105b1578082015181840152602081019050610596565b505050509050019250505060405180910390f35b6105cd611f36565b604051808215151515815260200191505060405180910390f35b610633600480360360408110156105fd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611f94565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6106b76004803603602081101561068b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611fdf565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156107025780820151818401526020810190506106e7565b50505050905001848103835286818151815260200191508051906020019060200280838360005b83811015610744578082015181840152602081019050610729565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561078657808201518184015260208101905061076b565b50505050905001965050505050505060405180910390f35b6107e0600480360360208110156107b457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506121af565b6040518082815260200191505060405180910390f35b6108426004803603604081101561080c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612282565b005b6108706004803603602081101561085a57600080fd5b8101908080359060200190929190505050612438565b005b6108b46004803603602081101561088857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506125a7565b604051808381526020018281526020019250505060405180910390f35b610933600480360360408110156108e757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506126a0565b005b6109776004803603602081101561094b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612a02565b005b6109a56004803603602081101561098f57600080fd5b8101908080359060200190929190505050612a88565b005b6109e9600480360360208110156109bd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612b3b565b60405180831515151581526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390f35b6060806060600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636cfa387390916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b158015610aca57600080fd5b505af4158015610ade573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052506060811015610b0857600080fd5b810190808051640100000000811115610b2057600080fd5b82810190506020810184811115610b3657600080fd5b8151856020820283011164010000000082111715610b5357600080fd5b50509291906020018051640100000000811115610b6f57600080fd5b82810190506020810184811115610b8557600080fd5b8151856020820283011164010000000082111715610ba257600080fd5b50509291906020018051640100000000811115610bbe57600080fd5b82810190506020810184811115610bd457600080fd5b8151856020820283011164010000000082111715610bf157600080fd5b50509291905050509250925092509193909250565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610c9757600080fd5b505af4158015610cab573d6000803e3d6000fd5b505050506040513d6020811015610cc157600080fd5b81019080805190602001909291905050509050919050565b600060149054906101000a900460ff1681565b60036020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b60055481565b610d29611f36565b610d9b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015610e055750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b8015610e52575080600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050115b8015610efd57508173ffffffffffffffffffffffffffffffffffffffff16600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110610eba57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b610f52576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260568152602001806137496056913960600191505060405180910390fd5b6000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061107c6001600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612d8090919063ffffffff16565b8154811061108657fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002082815481106110fb57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111996001600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612d8090919063ffffffff16565b600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020816111e3919061369d565b506111ee8383612dca565b156111fe576111fd8383612fd8565b5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f6dc84b66cc948d847632b9d829f7cb1cb904fbf2c084554a9bc22ad9d845334060405160405180910390a3505050565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636eafa6c390916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156112ee57600080fd5b505af4158015611302573d6000803e3d6000fd5b505050506040513d602081101561131857600080fd5b81019080805190602001909291905050509050919050565b611338611f36565b6113aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b83600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611549576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806137f96027913960400191505060405180910390fd5b6000600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156115da57600080fd5b505af41580156115ee573d6000803e3d6000fd5b505050506040513d602081101561160457600080fd5b81019080805190602001909291905050509050600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6395073a799091336040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b1580156116da57600080fd5b505af41580156116ee573d6000803e3d6000fd5b505050506040513d602081101561170457600080fd5b81019080805190602001909291905050501561194557600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63832a21479091338888886040518663ffffffff1660e01b8152600401808681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019550505050505060006040518083038186803b15801561184d57600080fd5b505af4158015611861573d6000803e3d6000fd5b50505050600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63c1e728e99091336040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561192857600080fd5b505af415801561193c573d6000803e3d6000fd5b50505050611a91565b600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63d4a092729091338888886040518663ffffffff1660e01b8152600401808681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019550505050505060006040518083038186803b158015611a7857600080fd5b505af4158015611a8c573d6000803e3d6000fd5b505050505b600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63d4a0927290913342600260008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b630944c59490916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611b7d57600080fd5b505af4158015611b91573d6000803e3d6000fd5b505050506040513d6020811015611ba757600080fd5b810190808051906020019092919050505060006040518663ffffffff1660e01b8152600401808681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019550505050505060006040518083038186803b158015611c8e57600080fd5b505af4158015611ca2573d6000803e3d6000fd5b505050503373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f7cebb17173a9ed273d2b7538f64395c0ebf352ff743f1cf8ce66b437a61442134288604051808381526020018281526020019250505060405180910390a36000600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611da457600080fd5b505af4158015611db8573d6000803e3d6000fd5b505050506040513d6020811015611dce57600080fd5b81019080805190602001909291905050509050818114611e37578673ffffffffffffffffffffffffffffffffffffffff167fa9981ebfc3b766a742486e898f54959b050a66006dbce1a4155c1f84a08bcf41826040518082815260200191505060405180910390a25b50505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6060600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015611f2a57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611ee0575b50505050509050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611f78613409565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60046020528160005260406000208181548110611fad57fe5b906000526020600020016000915091509054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060806060600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636cfa387390916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b15801561207357600080fd5b505af4158015612087573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060608110156120b157600080fd5b8101908080516401000000008111156120c957600080fd5b828101905060208101848111156120df57600080fd5b81518560208202830111640100000000821117156120fc57600080fd5b5050929190602001805164010000000081111561211857600080fd5b8281019050602081018481111561212e57600080fd5b815185602082028301116401000000008211171561214b57600080fd5b5050929190602001805164010000000081111561216757600080fd5b8281019050602081018481111561217d57600080fd5b815185602082028301116401000000008211171561219a57600080fd5b50509291905050509250925092509193909250565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636eafa6c390916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561224057600080fd5b505af4158015612254573d6000803e3d6000fd5b505050506040513d602081101561226a57600080fd5b81019080805190602001909291905050509050919050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156123875750600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636eafa6c390916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561234957600080fd5b505af415801561235d573d6000803e3d6000fd5b505050506040513d602081101561237357600080fd5b810190808051906020019092919050505081105b6123dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260348152602001806137156034913960400191505060405180910390fd5b60008090505b81811015612433576000806123f685612b3b565b91509150811561240f5761240a8582612fd8565b612416565b5050612433565b505061242c60018261341190919063ffffffff16565b90506123e2565b505050565b612440611f36565b6124b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6000811161250b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806138426021913960400191505060405180910390fd5b600554811415612566576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806138206022913960400191505060405180910390fd5b806005819055507fc68a9b88effd8a11611ff410efbc83569f0031b7bc70dd455b61344c7f0a042f816040518082815260200191505060405180910390a150565b600080600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561263957600080fd5b505af415801561264d573d6000803e3d6000fd5b505050506040513d602081101561266357600080fd5b8101908080519060200190929190505050600061267f856121af565b146126945769d3c21bcecceda1000000612697565b60005b91509150915091565b6126a8611f36565b61271a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156127845750600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b80156128175750600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b61286c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252605a81526020018061379f605a913960600191505060405180910390fd5b6001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f828d2be040dede7698182e08dfa8bfbd663c879aee772509c4a2bd961d0ed43f60405160405180910390a35050565b612a0a611f36565b612a7c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b612a8581613499565b50565b600060149054906101000a900460ff1615612b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff021916908315150217905550612b2f33613499565b612b3881612438565b50565b600080600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612b7857600080fd5b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63d938ec7b90916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015612c0957600080fd5b505af4158015612c1d573d6000803e3d6000fd5b505050506040513d6020811015612c3357600080fd5b810190808051906020019092919050505090506000600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b637c6bb8629091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b158015612d0b57600080fd5b505af4158015612d1f573d6000803e3d6000fd5b505050506040513d6020811015612d3557600080fd5b81019080805190602001909291905050509050600554612d5e8242612d8090919063ffffffff16565b10612d7157600182935093505050612d7b565b6000829350935050505b915091565b6000612dc283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506135dd565b905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6395073a799091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b158015612e8f57600080fd5b505af4158015612ea3573d6000803e3d6000fd5b505050506040513d6020811015612eb957600080fd5b81019080805190602001909291905050508015612fd05750600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6395073a799091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b158015612f9457600080fd5b505af4158015612fa8573d6000803e3d6000fd5b505050506040513d6020811015612fbe57600080fd5b81019080805190602001909291905050505b905092915050565b6001612fe38361125d565b148015612ff65750612ff58282612dca565b5b1561300057613405565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561309157600080fd5b505af41580156130a5573d6000803e3d6000fd5b505050506040513d60208110156130bb57600080fd5b81019080805190602001909291905050509050600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63c1e728e99091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561319157600080fd5b505af41580156131a5573d6000803e3d6000fd5b50505050600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63c1e728e99091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561326c57600080fd5b505af4158015613280573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fe21a44017b6fa1658d84e937d56ff408501facdb4ff7427c479ac460d76f789360405160405180910390a36000600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561336f57600080fd5b505af4158015613383573d6000803e3d6000fd5b505050506040513d602081101561339957600080fd5b81019080805190602001909291905050509050818114613402578373ffffffffffffffffffffffffffffffffffffffff167fa9981ebfc3b766a742486e898f54959b050a66006dbce1a4155c1f84a08bcf41826040518082815260200191505060405180910390a25b50505b5050565b600033905090565b60008082840190508381101561348f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561351f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806136ef6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600083831115829061368a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561364f578082015181840152602081019050613634565b50505050905090810190601f16801561367c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b8154818355818111156136c4578183600052602060002091820191016136c391906136c9565b5b505050565b6136eb91905b808211156136e75760008160009055506001016136cf565b5090565b9056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373746f6b656e2061646472206e756c6c206f7220747279696e6720746f2072656d6f766520746f6f206d616e79207265706f727473746f6b656e2061646472206e756c6c206f72206f7261636c652061646472206e756c6c206f7220696e646578206f6620746f6b656e206f7261636c65206e6f74206d617070656420746f206f7261636c652061646472746f6b656e206164647220776173206e756c6c206f72206f7261636c65206164647220776173206e756c6c206f72206f7261636c652061646472206973206e6f7420616e206f7261636c6520666f7220746f6b656e206164647273656e64657220776173206e6f7420616e206f7261636c6520666f7220746f6b656e20616464727265706f72744578706972795365636f6e6473206861736e2774206368616e6765647265706f727420657870697279207365636f6e6473206d757374206265203e2030a165627a7a7230582060b57140fb588509ccc502157dbe00d246dd2ba1d27546ce5a6cef6c8681293b0029

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101425760003560e01c80638f32d59b116100b8578063ebc1d6bb1161007c578063ebc1d6bb14610844578063ef90e1b014610872578063f0ca4adb146108d1578063f2fde38b14610935578063fe4b84df14610979578063ffe736bf146109a757610142565b80638f32d59b146105c5578063a00a8b2c146105e7578063b929215814610675578063bbc66a941461079e578063dd34ca3b146107f657610142565b806353a572971161010a57806353a57297146103845780636dd6ef0c146103f2578063715018a61461044a57806380e50744146104545780638da5cb5b146104e25780638e7492811461052c57610142565b806302f55b6114610147578063071b48fc14610270578063158ef93e146102c8578063370c998e146102ea578063493a353c14610366575b600080fd5b6101896004803603602081101561015d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610a36565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156101d45780820151818401526020810190506101b9565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156102165780820151818401526020810190506101fb565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561025857808201518184015260208101905061023d565b50505050905001965050505050505060405180910390f35b6102b26004803603602081101561028657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c06565b6040518082815260200191505060405180910390f35b6102d0610cd9565b604051808215151515815260200191505060405180910390f35b61034c6004803603604081101561030057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cec565b604051808215151515815260200191505060405180910390f35b61036e610d1b565b6040518082815260200191505060405180910390f35b6103f06004803603606081101561039a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610d21565b005b6104346004803603602081101561040857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061125d565b6040518082815260200191505060405180910390f35b610452611330565b005b6104e06004803603608081101561046a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611469565b005b6104ea611e40565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61056e6004803603602081101561054257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e69565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156105b1578082015181840152602081019050610596565b505050509050019250505060405180910390f35b6105cd611f36565b604051808215151515815260200191505060405180910390f35b610633600480360360408110156105fd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611f94565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6106b76004803603602081101561068b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611fdf565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156107025780820151818401526020810190506106e7565b50505050905001848103835286818151815260200191508051906020019060200280838360005b83811015610744578082015181840152602081019050610729565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561078657808201518184015260208101905061076b565b50505050905001965050505050505060405180910390f35b6107e0600480360360208110156107b457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506121af565b6040518082815260200191505060405180910390f35b6108426004803603604081101561080c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612282565b005b6108706004803603602081101561085a57600080fd5b8101908080359060200190929190505050612438565b005b6108b46004803603602081101561088857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506125a7565b604051808381526020018281526020019250505060405180910390f35b610933600480360360408110156108e757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506126a0565b005b6109776004803603602081101561094b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612a02565b005b6109a56004803603602081101561098f57600080fd5b8101908080359060200190929190505050612a88565b005b6109e9600480360360208110156109bd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612b3b565b60405180831515151581526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390f35b6060806060600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636cfa387390916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b158015610aca57600080fd5b505af4158015610ade573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052506060811015610b0857600080fd5b810190808051640100000000811115610b2057600080fd5b82810190506020810184811115610b3657600080fd5b8151856020820283011164010000000082111715610b5357600080fd5b50509291906020018051640100000000811115610b6f57600080fd5b82810190506020810184811115610b8557600080fd5b8151856020820283011164010000000082111715610ba257600080fd5b50509291906020018051640100000000811115610bbe57600080fd5b82810190506020810184811115610bd457600080fd5b8151856020820283011164010000000082111715610bf157600080fd5b50509291905050509250925092509193909250565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610c9757600080fd5b505af4158015610cab573d6000803e3d6000fd5b505050506040513d6020811015610cc157600080fd5b81019080805190602001909291905050509050919050565b600060149054906101000a900460ff1681565b60036020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b60055481565b610d29611f36565b610d9b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015610e055750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b8015610e52575080600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050115b8015610efd57508173ffffffffffffffffffffffffffffffffffffffff16600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110610eba57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b610f52576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260568152602001806137496056913960600191505060405180910390fd5b6000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061107c6001600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612d8090919063ffffffff16565b8154811061108657fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002082815481106110fb57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111996001600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612d8090919063ffffffff16565b600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020816111e3919061369d565b506111ee8383612dca565b156111fe576111fd8383612fd8565b5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f6dc84b66cc948d847632b9d829f7cb1cb904fbf2c084554a9bc22ad9d845334060405160405180910390a3505050565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636eafa6c390916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156112ee57600080fd5b505af4158015611302573d6000803e3d6000fd5b505050506040513d602081101561131857600080fd5b81019080805190602001909291905050509050919050565b611338611f36565b6113aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b83600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16611549576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806137f96027913960400191505060405180910390fd5b6000600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156115da57600080fd5b505af41580156115ee573d6000803e3d6000fd5b505050506040513d602081101561160457600080fd5b81019080805190602001909291905050509050600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6395073a799091336040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b1580156116da57600080fd5b505af41580156116ee573d6000803e3d6000fd5b505050506040513d602081101561170457600080fd5b81019080805190602001909291905050501561194557600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63832a21479091338888886040518663ffffffff1660e01b8152600401808681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019550505050505060006040518083038186803b15801561184d57600080fd5b505af4158015611861573d6000803e3d6000fd5b50505050600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63c1e728e99091336040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561192857600080fd5b505af415801561193c573d6000803e3d6000fd5b50505050611a91565b600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63d4a092729091338888886040518663ffffffff1660e01b8152600401808681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019550505050505060006040518083038186803b158015611a7857600080fd5b505af4158015611a8c573d6000803e3d6000fd5b505050505b600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63d4a0927290913342600260008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b630944c59490916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611b7d57600080fd5b505af4158015611b91573d6000803e3d6000fd5b505050506040513d6020811015611ba757600080fd5b810190808051906020019092919050505060006040518663ffffffff1660e01b8152600401808681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019550505050505060006040518083038186803b158015611c8e57600080fd5b505af4158015611ca2573d6000803e3d6000fd5b505050503373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f7cebb17173a9ed273d2b7538f64395c0ebf352ff743f1cf8ce66b437a61442134288604051808381526020018281526020019250505060405180910390a36000600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611da457600080fd5b505af4158015611db8573d6000803e3d6000fd5b505050506040513d6020811015611dce57600080fd5b81019080805190602001909291905050509050818114611e37578673ffffffffffffffffffffffffffffffffffffffff167fa9981ebfc3b766a742486e898f54959b050a66006dbce1a4155c1f84a08bcf41826040518082815260200191505060405180910390a25b50505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6060600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015611f2a57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611ee0575b50505050509050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611f78613409565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60046020528160005260406000208181548110611fad57fe5b906000526020600020016000915091509054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060806060600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636cfa387390916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b15801561207357600080fd5b505af4158015612087573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060608110156120b157600080fd5b8101908080516401000000008111156120c957600080fd5b828101905060208101848111156120df57600080fd5b81518560208202830111640100000000821117156120fc57600080fd5b5050929190602001805164010000000081111561211857600080fd5b8281019050602081018481111561212e57600080fd5b815185602082028301116401000000008211171561214b57600080fd5b5050929190602001805164010000000081111561216757600080fd5b8281019050602081018481111561217d57600080fd5b815185602082028301116401000000008211171561219a57600080fd5b50509291905050509250925092509193909250565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636eafa6c390916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561224057600080fd5b505af4158015612254573d6000803e3d6000fd5b505050506040513d602081101561226a57600080fd5b81019080805190602001909291905050509050919050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156123875750600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b636eafa6c390916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561234957600080fd5b505af415801561235d573d6000803e3d6000fd5b505050506040513d602081101561237357600080fd5b810190808051906020019092919050505081105b6123dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260348152602001806137156034913960400191505060405180910390fd5b60008090505b81811015612433576000806123f685612b3b565b91509150811561240f5761240a8582612fd8565b612416565b5050612433565b505061242c60018261341190919063ffffffff16565b90506123e2565b505050565b612440611f36565b6124b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6000811161250b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806138426021913960400191505060405180910390fd5b600554811415612566576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806138206022913960400191505060405180910390fd5b806005819055507fc68a9b88effd8a11611ff410efbc83569f0031b7bc70dd455b61344c7f0a042f816040518082815260200191505060405180910390a150565b600080600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561263957600080fd5b505af415801561264d573d6000803e3d6000fd5b505050506040513d602081101561266357600080fd5b8101908080519060200190929190505050600061267f856121af565b146126945769d3c21bcecceda1000000612697565b60005b91509150915091565b6126a8611f36565b61271a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156127845750600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b80156128175750600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b61286c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252605a81526020018061379f605a913960600191505060405180910390fd5b6001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f828d2be040dede7698182e08dfa8bfbd663c879aee772509c4a2bd961d0ed43f60405160405180910390a35050565b612a0a611f36565b612a7c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b612a8581613499565b50565b600060149054906101000a900460ff1615612b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff021916908315150217905550612b2f33613499565b612b3881612438565b50565b600080600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612b7857600080fd5b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63d938ec7b90916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015612c0957600080fd5b505af4158015612c1d573d6000803e3d6000fd5b505050506040513d6020811015612c3357600080fd5b810190808051906020019092919050505090506000600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b637c6bb8629091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b158015612d0b57600080fd5b505af4158015612d1f573d6000803e3d6000fd5b505050506040513d6020811015612d3557600080fd5b81019080805190602001909291905050509050600554612d5e8242612d8090919063ffffffff16565b10612d7157600182935093505050612d7b565b6000829350935050505b915091565b6000612dc283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506135dd565b905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6395073a799091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b158015612e8f57600080fd5b505af4158015612ea3573d6000803e3d6000fd5b505050506040513d6020811015612eb957600080fd5b81019080805190602001909291905050508015612fd05750600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6395073a799091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b158015612f9457600080fd5b505af4158015612fa8573d6000803e3d6000fd5b505050506040513d6020811015612fbe57600080fd5b81019080805190602001909291905050505b905092915050565b6001612fe38361125d565b148015612ff65750612ff58282612dca565b5b1561300057613405565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561309157600080fd5b505af41580156130a5573d6000803e3d6000fd5b505050506040513d60208110156130bb57600080fd5b81019080805190602001909291905050509050600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63c1e728e99091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561319157600080fd5b505af41580156131a5573d6000803e3d6000fd5b50505050600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b63c1e728e99091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b15801561326c57600080fd5b505af4158015613280573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fe21a44017b6fa1658d84e937d56ff408501facdb4ff7427c479ac460d76f789360405160405180910390a36000600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002073a3d1ef4f8119cb6b0ada6fa14d5d40d9e6b7594b6359d556a890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561336f57600080fd5b505af4158015613383573d6000803e3d6000fd5b505050506040513d602081101561339957600080fd5b81019080805190602001909291905050509050818114613402578373ffffffffffffffffffffffffffffffffffffffff167fa9981ebfc3b766a742486e898f54959b050a66006dbce1a4155c1f84a08bcf41826040518082815260200191505060405180910390a25b50505b5050565b600033905090565b60008082840190508381101561348f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561351f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806136ef6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600083831115829061368a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561364f578082015181840152602081019050613634565b50505050905090810190601f16801561367c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b8154818355818111156136c4578183600052602060002091820191016136c391906136c9565b5b505050565b6136eb91905b808211156136e75760008160009055506001016136cf565b5090565b9056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373746f6b656e2061646472206e756c6c206f7220747279696e6720746f2072656d6f766520746f6f206d616e79207265706f727473746f6b656e2061646472206e756c6c206f72206f7261636c652061646472206e756c6c206f7220696e646578206f6620746f6b656e206f7261636c65206e6f74206d617070656420746f206f7261636c652061646472746f6b656e206164647220776173206e756c6c206f72206f7261636c65206164647220776173206e756c6c206f72206f7261636c652061646472206973206e6f7420616e206f7261636c6520666f7220746f6b656e206164647273656e64657220776173206e6f7420616e206f7261636c6520666f7220746f6b656e20616464727265706f72744578706972795365636f6e6473206861736e2774206368616e6765647265706f727420657870697279207365636f6e6473206d757374206265203e2030a165627a7a7230582060b57140fb588509ccc502157dbe00d246dd2ba1d27546ce5a6cef6c8681293b0029

External libraries

AddressSortedLinkedListWithMedian : 0xa3d1eF4f8119CB6B0aDa6fa14D5d40D9E6b7594B