ETH Price: $2,240.52 (+6.02%)

Transaction Decoder

Block:
10518087 at Jul-23-2020 09:22:42 PM +UTC
Transaction Fee:
0.015181893 ETH $34.02
Gas Used:
266,349 Gas / 57 Gwei

Emitted Events:

145 BaseRegistrarImplementation.Transfer( from=0x00000000...000000000, to=[Receiver] ETHRegistrarController, tokenId=98800760229682114531554428816786762944555554902562679152541034542790158378352 )
146 ENSRegistryWithFallback.NewOwner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE, label=DA6F3FA35D84584A9EBD4B811077A1C1A61A65F3C844923FACD5124DD544E570, owner=[Receiver] ETHRegistrarController )
147 BaseRegistrarImplementation.NameRegistered( id=98800760229682114531554428816786762944555554902562679152541034542790158378352, owner=[Receiver] ETHRegistrarController, expires=1627096314 )
148 ENSRegistryWithFallback.NewResolver( node=7BEB0D820B8534A24DFD5AC8E7E8D118ACB4595CEF47A7B46AF5F3B292AFEEA2, resolver=PublicResolver )
149 PublicResolver.AddressChanged( node=7BEB0D820B8534A24DFD5AC8E7E8D118ACB4595CEF47A7B46AF5F3B292AFEEA2, coinType=60, newAddress=[Sender] 0x33edd419b05e8f519792f50380fa4bec775d4c7f )
150 PublicResolver.AddrChanged( node=7BEB0D820B8534A24DFD5AC8E7E8D118ACB4595CEF47A7B46AF5F3B292AFEEA2, a=[Sender] 0x33edd419b05e8f519792f50380fa4bec775d4c7f )
151 ENSRegistryWithFallback.NewOwner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE, label=DA6F3FA35D84584A9EBD4B811077A1C1A61A65F3C844923FACD5124DD544E570, owner=[Sender] 0x33edd419b05e8f519792f50380fa4bec775d4c7f )
152 BaseRegistrarImplementation.Transfer( from=[Receiver] ETHRegistrarController, to=[Sender] 0x33edd419b05e8f519792f50380fa4bec775d4c7f, tokenId=98800760229682114531554428816786762944555554902562679152541034542790158378352 )
153 ETHRegistrarController.NameRegistered( name=1dave, label=DA6F3FA35D84584A9EBD4B811077A1C1A61A65F3C844923FACD5124DD544E570, owner=[Sender] 0x33edd419b05e8f519792f50380fa4bec775d4c7f, cost=18305800006920511, expires=1627096314 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...A6C7d2e1e
(ENS: Registry with Fallback)
0x283Af0B2...A627EB7F5
(ENS: Old ETH Registrar Controller)
2,035.386845715591485824 Eth2,035.405151515598406335 Eth0.018305800006920511
0x33eDD419...C775D4c7F
0.091815712110155051 Eth
Nonce: 2
0.05832801910323454 Eth
Nonce: 3
0.033487693006920511
0x4976fb03...78EBaBa41
(ENS: Public Resolver 2)
0x57f1887a...Af147eA85
(Spark Pool)
66.2947644900324296 Eth66.3099463830324296 Eth0.015181893

Execution Trace

ETH 0.019221090007266536 ETHRegistrarController.registerWithConfig( name=1dave, owner=0x33eDD419B05E8f519792F50380FA4BEC775D4c7F, duration=31556952, secret=F4EC099AD47053FA31782A8D0EE64865478FAC291F92E80A39AF104E5809ACA1, resolver=0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41, addr=0x33eDD419B05E8f519792F50380FA4BEC775D4c7F )
  • BaseRegistrarImplementation.available( id=98800760229682114531554428816786762944555554902562679152541034542790158378352 ) => ( True )
  • BaseRegistrarImplementation.nameExpires( id=98800760229682114531554428816786762944555554902562679152541034542790158378352 ) => ( 0 )
  • LinearPremiumPriceOracle.price( name=1dave, expires=0, duration=31556952 ) => ( 18305800006920511 )
    • Aggregator.STATICCALL( )
    • BaseRegistrarImplementation.register( id=98800760229682114531554428816786762944555554902562679152541034542790158378352, owner=0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5, duration=31556952 ) => ( 1627096314 )
      • ENSRegistryWithFallback.owner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE ) => ( 0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85 )
      • ENSRegistryWithFallback.setSubnodeOwner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE, label=DA6F3FA35D84584A9EBD4B811077A1C1A61A65F3C844923FACD5124DD544E570, owner=0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5 ) => ( 7BEB0D820B8534A24DFD5AC8E7E8D118ACB4595CEF47A7B46AF5F3B292AFEEA2 )
      • BaseRegistrarImplementation.STATICCALL( )
      • BaseRegistrarImplementation.STATICCALL( )
      • ENSRegistryWithFallback.setResolver( node=7BEB0D820B8534A24DFD5AC8E7E8D118ACB4595CEF47A7B46AF5F3B292AFEEA2, resolver=0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41 )
      • PublicResolver.setAddr( node=7BEB0D820B8534A24DFD5AC8E7E8D118ACB4595CEF47A7B46AF5F3B292AFEEA2, a=0x33eDD419B05E8f519792F50380FA4BEC775D4c7F )
        • ENSRegistryWithFallback.owner( node=7BEB0D820B8534A24DFD5AC8E7E8D118ACB4595CEF47A7B46AF5F3B292AFEEA2 ) => ( 0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5 )
        • ENSRegistryWithFallback.owner( node=7BEB0D820B8534A24DFD5AC8E7E8D118ACB4595CEF47A7B46AF5F3B292AFEEA2 ) => ( 0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5 )
        • BaseRegistrarImplementation.reclaim( id=98800760229682114531554428816786762944555554902562679152541034542790158378352, owner=0x33eDD419B05E8f519792F50380FA4BEC775D4c7F )
          • ENSRegistryWithFallback.owner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE ) => ( 0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85 )
          • ENSRegistryWithFallback.setSubnodeOwner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE, label=DA6F3FA35D84584A9EBD4B811077A1C1A61A65F3C844923FACD5124DD544E570, owner=0x33eDD419B05E8f519792F50380FA4BEC775D4c7F ) => ( 7BEB0D820B8534A24DFD5AC8E7E8D118ACB4595CEF47A7B46AF5F3B292AFEEA2 )
          • BaseRegistrarImplementation.transferFrom( from=0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5, to=0x33eDD419B05E8f519792F50380FA4BEC775D4c7F, tokenId=98800760229682114531554428816786762944555554902562679152541034542790158378352 )
          • ETH 0.000915290000346025 0x33edd419b05e8f519792f50380fa4bec775d4c7f.CALL( )
            File 1 of 6: ETHRegistrarController
            // File: @ensdomains/ethregistrar/contracts/PriceOracle.sol
            
            pragma solidity >=0.4.24;
            
            interface PriceOracle {
                /**
                 * @dev Returns the price to register or renew a name.
                 * @param name The name being registered or renewed.
                 * @param expires When the name presently expires (0 if this is a new registration).
                 * @param duration How long the name is being registered or extended for, in seconds.
                 * @return The price of this renewal or registration, in wei.
                 */
                function price(string calldata name, uint expires, uint duration) external view returns(uint);
            }
            
            // File: @ensdomains/ens/contracts/ENS.sol
            
            pragma solidity >=0.4.24;
            
            interface ENS {
            
                // Logged when the owner of a node assigns a new owner to a subnode.
                event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
            
                // Logged when the owner of a node transfers ownership to a new account.
                event Transfer(bytes32 indexed node, address owner);
            
                // Logged when the resolver for a node changes.
                event NewResolver(bytes32 indexed node, address resolver);
            
                // Logged when the TTL of a node changes
                event NewTTL(bytes32 indexed node, uint64 ttl);
            
                // Logged when an operator is added or removed.
                event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            
                function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external;
                function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external;
                function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external returns(bytes32);
                function setResolver(bytes32 node, address resolver) external;
                function setOwner(bytes32 node, address owner) external;
                function setTTL(bytes32 node, uint64 ttl) external;
                function setApprovalForAll(address operator, bool approved) external;
                function owner(bytes32 node) external view returns (address);
                function resolver(bytes32 node) external view returns (address);
                function ttl(bytes32 node) external view returns (uint64);
                function recordExists(bytes32 node) external view returns (bool);
                function isApprovedForAll(address owner, address operator) external view returns (bool);
            }
            
            // File: openzeppelin-solidity/contracts/introspection/IERC165.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title IERC165
             * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
             */
            interface IERC165 {
                /**
                 * @notice Query if a contract implements an interface
                 * @param interfaceId The interface identifier, as specified in ERC-165
                 * @dev Interface identification is specified in ERC-165. This function
                 * uses less than 30,000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol
            
            pragma solidity ^0.5.0;
            
            
            /**
             * @title ERC721 Non-Fungible Token Standard basic interface
             * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
             */
            contract IERC721 is IERC165 {
                event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
                event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
                event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            
                function balanceOf(address owner) public view returns (uint256 balance);
                function ownerOf(uint256 tokenId) public view returns (address owner);
            
                function approve(address to, uint256 tokenId) public;
                function getApproved(uint256 tokenId) public view returns (address operator);
            
                function setApprovalForAll(address operator, bool _approved) public;
                function isApprovedForAll(address owner, address operator) public view returns (bool);
            
                function transferFrom(address from, address to, uint256 tokenId) public;
                function safeTransferFrom(address from, address to, uint256 tokenId) public;
            
                function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
            }
            
            // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title Ownable
             * @dev The Ownable contract has an owner address, and provides basic authorization control
             * functions, this simplifies the implementation of "user permissions".
             */
            contract Ownable {
                address private _owner;
            
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            
                /**
                 * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                 * account.
                 */
                constructor () internal {
                    _owner = msg.sender;
                    emit OwnershipTransferred(address(0), _owner);
                }
            
                /**
                 * @return the address of the owner.
                 */
                function owner() public view returns (address) {
                    return _owner;
                }
            
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    require(isOwner());
                    _;
                }
            
                /**
                 * @return true if `msg.sender` is the owner of the contract.
                 */
                function isOwner() public view returns (bool) {
                    return msg.sender == _owner;
                }
            
                /**
                 * @dev Allows the current owner to relinquish control of the contract.
                 * @notice Renouncing to ownership will leave the contract without an owner.
                 * It will not be possible to call the functions with the `onlyOwner`
                 * modifier anymore.
                 */
                function renounceOwnership() public onlyOwner {
                    emit OwnershipTransferred(_owner, address(0));
                    _owner = address(0);
                }
            
                /**
                 * @dev Allows the current owner to transfer control of the contract to a newOwner.
                 * @param newOwner The address to transfer ownership to.
                 */
                function transferOwnership(address newOwner) public onlyOwner {
                    _transferOwnership(newOwner);
                }
            
                /**
                 * @dev Transfers control of the contract to a newOwner.
                 * @param newOwner The address to transfer ownership to.
                 */
                function _transferOwnership(address newOwner) internal {
                    require(newOwner != address(0));
                    emit OwnershipTransferred(_owner, newOwner);
                    _owner = newOwner;
                }
            }
            
            // File: @ensdomains/ethregistrar/contracts/BaseRegistrar.sol
            
            pragma solidity >=0.4.24;
            
            
            
            
            contract BaseRegistrar is IERC721, Ownable {
                uint constant public GRACE_PERIOD = 90 days;
            
                event ControllerAdded(address indexed controller);
                event ControllerRemoved(address indexed controller);
                event NameMigrated(uint256 indexed id, address indexed owner, uint expires);
                event NameRegistered(uint256 indexed id, address indexed owner, uint expires);
                event NameRenewed(uint256 indexed id, uint expires);
            
                // The ENS registry
                ENS public ens;
            
                // The namehash of the TLD this registrar owns (eg, .eth)
                bytes32 public baseNode;
            
                // A map of addresses that are authorised to register and renew names.
                mapping(address=>bool) public controllers;
            
                // Authorises a controller, who can register and renew domains.
                function addController(address controller) external;
            
                // Revoke controller permission for an address.
                function removeController(address controller) external;
            
                // Set the resolver for the TLD this registrar manages.
                function setResolver(address resolver) external;
            
                // Returns the expiration timestamp of the specified label hash.
                function nameExpires(uint256 id) external view returns(uint);
            
                // Returns true iff the specified name is available for registration.
                function available(uint256 id) public view returns(bool);
            
                /**
                 * @dev Register a name.
                 */
                function register(uint256 id, address owner, uint duration) external returns(uint);
            
                function renew(uint256 id, uint duration) external returns(uint);
            
                /**
                 * @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
                 */
                function reclaim(uint256 id, address owner) external;
            }
            
            // File: @ensdomains/ethregistrar/contracts/StringUtils.sol
            
            pragma solidity >=0.4.24;
            
            library StringUtils {
                /**
                 * @dev Returns the length of a given string
                 *
                 * @param s The string to measure the length of
                 * @return The length of the input string
                 */
                function strlen(string memory s) internal pure returns (uint) {
                    uint len;
                    uint i = 0;
                    uint bytelength = bytes(s).length;
                    for(len = 0; i < bytelength; len++) {
                        byte b = bytes(s)[i];
                        if(b < 0x80) {
                            i += 1;
                        } else if (b < 0xE0) {
                            i += 2;
                        } else if (b < 0xF0) {
                            i += 3;
                        } else if (b < 0xF8) {
                            i += 4;
                        } else if (b < 0xFC) {
                            i += 5;
                        } else {
                            i += 6;
                        }
                    }
                    return len;
                }
            }
            
            // File: @ensdomains/resolver/contracts/Resolver.sol
            
            pragma solidity >=0.4.25;
            
            /**
             * A generic resolver interface which includes all the functions including the ones deprecated
             */
            interface Resolver{
                event AddrChanged(bytes32 indexed node, address a);
                event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
                event NameChanged(bytes32 indexed node, string name);
                event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
                event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
                event TextChanged(bytes32 indexed node, string indexed indexedKey, string key);
                event ContenthashChanged(bytes32 indexed node, bytes hash);
                /* Deprecated events */
                event ContentChanged(bytes32 indexed node, bytes32 hash);
            
                function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory);
                function addr(bytes32 node) external view returns (address);
                function addr(bytes32 node, uint coinType) external view returns(bytes memory);
                function contenthash(bytes32 node) external view returns (bytes memory);
                function dnsrr(bytes32 node) external view returns (bytes memory);
                function name(bytes32 node) external view returns (string memory);
                function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y);
                function text(bytes32 node, string calldata key) external view returns (string memory);
                function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address);
            
                function setABI(bytes32 node, uint256 contentType, bytes calldata data) external;
                function setAddr(bytes32 node, address addr) external;
                function setAddr(bytes32 node, uint coinType, bytes calldata a) external;
                function setContenthash(bytes32 node, bytes calldata hash) external;
                function setDnsrr(bytes32 node, bytes calldata data) external;
                function setName(bytes32 node, string calldata _name) external;
                function setPubkey(bytes32 node, bytes32 x, bytes32 y) external;
                function setText(bytes32 node, string calldata key, string calldata value) external;
                function setInterface(bytes32 node, bytes4 interfaceID, address implementer) external;
            
                function supportsInterface(bytes4 interfaceID) external pure returns (bool);
            
                /* Deprecated functions */
                function content(bytes32 node) external view returns (bytes32);
                function multihash(bytes32 node) external view returns (bytes memory);
                function setContent(bytes32 node, bytes32 hash) external;
                function setMultihash(bytes32 node, bytes calldata hash) external;
            }
            
            // File: @ensdomains/ethregistrar/contracts/ETHRegistrarController.sol
            
            pragma solidity ^0.5.0;
            
            
            
            
            
            
            /**
             * @dev A registrar controller for registering and renewing names at fixed cost.
             */
            contract ETHRegistrarController is Ownable {
                using StringUtils for *;
            
                uint constant public MIN_REGISTRATION_DURATION = 28 days;
            
                bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
                bytes4 constant private COMMITMENT_CONTROLLER_ID = bytes4(
                    keccak256("rentPrice(string,uint256)") ^
                    keccak256("available(string)") ^
                    keccak256("makeCommitment(string,address,bytes32)") ^
                    keccak256("commit(bytes32)") ^
                    keccak256("register(string,address,uint256,bytes32)") ^
                    keccak256("renew(string,uint256)")
                );
            
                bytes4 constant private COMMITMENT_WITH_CONFIG_CONTROLLER_ID = bytes4(
                    keccak256("registerWithConfig(string,address,uint256,bytes32,address,address)") ^
                    keccak256("makeCommitmentWithConfig(string,address,bytes32,address,address)")
                );
            
                BaseRegistrar base;
                PriceOracle prices;
                uint public minCommitmentAge;
                uint public maxCommitmentAge;
            
                mapping(bytes32=>uint) public commitments;
            
                event NameRegistered(string name, bytes32 indexed label, address indexed owner, uint cost, uint expires);
                event NameRenewed(string name, bytes32 indexed label, uint cost, uint expires);
                event NewPriceOracle(address indexed oracle);
            
                constructor(BaseRegistrar _base, PriceOracle _prices, uint _minCommitmentAge, uint _maxCommitmentAge) public {
                    require(_maxCommitmentAge > _minCommitmentAge);
            
                    base = _base;
                    prices = _prices;
                    minCommitmentAge = _minCommitmentAge;
                    maxCommitmentAge = _maxCommitmentAge;
                }
            
                function rentPrice(string memory name, uint duration) view public returns(uint) {
                    bytes32 hash = keccak256(bytes(name));
                    return prices.price(name, base.nameExpires(uint256(hash)), duration);
                }
            
                function valid(string memory name) public pure returns(bool) {
                    return name.strlen() >= 3;
                }
            
                function available(string memory name) public view returns(bool) {
                    bytes32 label = keccak256(bytes(name));
                    return valid(name) && base.available(uint256(label));
                }
            
                function makeCommitment(string memory name, address owner, bytes32 secret) pure public returns(bytes32) {
                    return makeCommitmentWithConfig(name, owner, secret, address(0), address(0));
                }
            
                function makeCommitmentWithConfig(string memory name, address owner, bytes32 secret, address resolver, address addr) pure public returns(bytes32) {
                    bytes32 label = keccak256(bytes(name));
                    if (resolver == address(0) && addr == address(0)) {
                        return keccak256(abi.encodePacked(label, owner, secret));
                    }
                    require(resolver != address(0));
                    return keccak256(abi.encodePacked(label, owner, resolver, addr, secret));
                }
            
                function commit(bytes32 commitment) public {
                    require(commitments[commitment] + maxCommitmentAge < now);
                    commitments[commitment] = now;
                }
            
                function register(string calldata name, address owner, uint duration, bytes32 secret) external payable {
                  registerWithConfig(name, owner, duration, secret, address(0), address(0));
                }
            
                function registerWithConfig(string memory name, address owner, uint duration, bytes32 secret, address resolver, address addr) public payable {
                    bytes32 commitment = makeCommitmentWithConfig(name, owner, secret, resolver, addr);
                    uint cost = _consumeCommitment(name, duration, commitment);
            
                    bytes32 label = keccak256(bytes(name));
                    uint256 tokenId = uint256(label);
            
                    uint expires;
                    if(resolver != address(0)) {
                        // Set this contract as the (temporary) owner, giving it
                        // permission to set up the resolver.
                        expires = base.register(tokenId, address(this), duration);
            
                        // The nodehash of this label
                        bytes32 nodehash = keccak256(abi.encodePacked(base.baseNode(), label));
            
                        // Set the resolver
                        base.ens().setResolver(nodehash, resolver);
            
                        // Configure the resolver
                        if (addr != address(0)) {
                            Resolver(resolver).setAddr(nodehash, addr);
                        }
            
                        // Now transfer full ownership to the expeceted owner
                        base.reclaim(tokenId, owner);
                        base.transferFrom(address(this), owner, tokenId);
                    } else {
                        require(addr == address(0));
                        expires = base.register(tokenId, owner, duration);
                    }
            
                    emit NameRegistered(name, label, owner, cost, expires);
            
                    // Refund any extra payment
                    if(msg.value > cost) {
                        msg.sender.transfer(msg.value - cost);
                    }
                }
            
                function renew(string calldata name, uint duration) external payable {
                    uint cost = rentPrice(name, duration);
                    require(msg.value >= cost);
            
                    bytes32 label = keccak256(bytes(name));
                    uint expires = base.renew(uint256(label), duration);
            
                    if(msg.value > cost) {
                        msg.sender.transfer(msg.value - cost);
                    }
            
                    emit NameRenewed(name, label, cost, expires);
                }
            
                function setPriceOracle(PriceOracle _prices) public onlyOwner {
                    prices = _prices;
                    emit NewPriceOracle(address(prices));
                }
            
                function setCommitmentAges(uint _minCommitmentAge, uint _maxCommitmentAge) public onlyOwner {
                    minCommitmentAge = _minCommitmentAge;
                    maxCommitmentAge = _maxCommitmentAge;
                }
            
                function withdraw() public onlyOwner {
                    msg.sender.transfer(address(this).balance);
                }
            
                function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
                    return interfaceID == INTERFACE_META_ID ||
                           interfaceID == COMMITMENT_CONTROLLER_ID ||
                           interfaceID == COMMITMENT_WITH_CONFIG_CONTROLLER_ID;
                }
            
                function _consumeCommitment(string memory name, uint duration, bytes32 commitment) internal returns (uint256) {
                    // Require a valid commitment
                    require(commitments[commitment] + minCommitmentAge <= now);
            
                    // If the commitment is too old, or the name is registered, stop
                    require(commitments[commitment] + maxCommitmentAge > now);
                    require(available(name));
            
                    delete(commitments[commitment]);
            
                    uint cost = rentPrice(name, duration);
                    require(duration >= MIN_REGISTRATION_DURATION);
                    require(msg.value >= cost);
            
                    return cost;
                }
            }

            File 2 of 6: BaseRegistrarImplementation
            // File: @ensdomains/ens/contracts/ENS.sol
            
            pragma solidity >=0.4.24;
            
            interface ENS {
            
                // Logged when the owner of a node assigns a new owner to a subnode.
                event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
            
                // Logged when the owner of a node transfers ownership to a new account.
                event Transfer(bytes32 indexed node, address owner);
            
                // Logged when the resolver for a node changes.
                event NewResolver(bytes32 indexed node, address resolver);
            
                // Logged when the TTL of a node changes
                event NewTTL(bytes32 indexed node, uint64 ttl);
            
                // Logged when an operator is added or removed.
                event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            
                function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external;
                function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external;
                function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external returns(bytes32);
                function setResolver(bytes32 node, address resolver) external;
                function setOwner(bytes32 node, address owner) external;
                function setTTL(bytes32 node, uint64 ttl) external;
                function setApprovalForAll(address operator, bool approved) external;
                function owner(bytes32 node) external view returns (address);
                function resolver(bytes32 node) external view returns (address);
                function ttl(bytes32 node) external view returns (uint64);
                function recordExists(bytes32 node) external view returns (bool);
                function isApprovedForAll(address owner, address operator) external view returns (bool);
            }
            
            // File: openzeppelin-solidity/contracts/introspection/IERC165.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title IERC165
             * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
             */
            interface IERC165 {
                /**
                 * @notice Query if a contract implements an interface
                 * @param interfaceId The interface identifier, as specified in ERC-165
                 * @dev Interface identification is specified in ERC-165. This function
                 * uses less than 30,000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol
            
            pragma solidity ^0.5.0;
            
            
            /**
             * @title ERC721 Non-Fungible Token Standard basic interface
             * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
             */
            contract IERC721 is IERC165 {
                event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
                event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
                event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            
                function balanceOf(address owner) public view returns (uint256 balance);
                function ownerOf(uint256 tokenId) public view returns (address owner);
            
                function approve(address to, uint256 tokenId) public;
                function getApproved(uint256 tokenId) public view returns (address operator);
            
                function setApprovalForAll(address operator, bool _approved) public;
                function isApprovedForAll(address owner, address operator) public view returns (bool);
            
                function transferFrom(address from, address to, uint256 tokenId) public;
                function safeTransferFrom(address from, address to, uint256 tokenId) public;
            
                function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title ERC721 token receiver interface
             * @dev Interface for any contract that wants to support safeTransfers
             * from ERC721 asset contracts.
             */
            contract IERC721Receiver {
                /**
                 * @notice Handle the receipt of an NFT
                 * @dev The ERC721 smart contract calls this function on the recipient
                 * after a `safeTransfer`. This function MUST return the function selector,
                 * otherwise the caller will revert the transaction. The selector to be
                 * returned can be obtained as `this.onERC721Received.selector`. This
                 * function MAY throw to revert and reject the transfer.
                 * Note: the ERC721 contract address is always the message sender.
                 * @param operator The address which called `safeTransferFrom` function
                 * @param from The address which previously owned the token
                 * @param tokenId The NFT identifier which is being transferred
                 * @param data Additional data with no specified format
                 * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
                 */
                function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
                public returns (bytes4);
            }
            
            // File: openzeppelin-solidity/contracts/math/SafeMath.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title SafeMath
             * @dev Unsigned math operations with safety checks that revert on error
             */
            library SafeMath {
                /**
                * @dev Multiplies two unsigned integers, reverts on overflow.
                */
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                    // benefit is lost if 'b' is also tested.
                    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                    if (a == 0) {
                        return 0;
                    }
            
                    uint256 c = a * b;
                    require(c / a == b);
            
                    return c;
                }
            
                /**
                * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                */
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Solidity only automatically asserts when dividing by 0
                    require(b > 0);
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            
                    return c;
                }
            
                /**
                * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                */
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b <= a);
                    uint256 c = a - b;
            
                    return c;
                }
            
                /**
                * @dev Adds two unsigned integers, reverts on overflow.
                */
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    require(c >= a);
            
                    return c;
                }
            
                /**
                * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                * reverts when dividing by zero.
                */
                function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b != 0);
                    return a % b;
                }
            }
            
            // File: openzeppelin-solidity/contracts/utils/Address.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * Utility library of inline functions on addresses
             */
            library Address {
                /**
                 * Returns whether the target address is a contract
                 * @dev This function will return false if invoked during the constructor of a contract,
                 * as the code is not actually created until after the constructor finishes.
                 * @param account address of the account to check
                 * @return whether the target address is a contract
                 */
                function isContract(address account) internal view returns (bool) {
                    uint256 size;
                    // XXX Currently there is no better way to check if there is a contract in an address
                    // than to check the size of the code at that address.
                    // See https://ethereum.stackexchange.com/a/14016/36603
                    // for more details about how this works.
                    // TODO Check this again before the Serenity release, because all addresses will be
                    // contracts then.
                    // solhint-disable-next-line no-inline-assembly
                    assembly { size := extcodesize(account) }
                    return size > 0;
                }
            }
            
            // File: openzeppelin-solidity/contracts/introspection/ERC165.sol
            
            pragma solidity ^0.5.0;
            
            
            /**
             * @title ERC165
             * @author Matt Condon (@shrugs)
             * @dev Implements ERC165 using a lookup table.
             */
            contract ERC165 is IERC165 {
                bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
                /**
                 * 0x01ffc9a7 ===
                 *     bytes4(keccak256('supportsInterface(bytes4)'))
                 */
            
                /**
                 * @dev a mapping of interface id to whether or not it's supported
                 */
                mapping(bytes4 => bool) private _supportedInterfaces;
            
                /**
                 * @dev A contract implementing SupportsInterfaceWithLookup
                 * implement ERC165 itself
                 */
                constructor () internal {
                    _registerInterface(_INTERFACE_ID_ERC165);
                }
            
                /**
                 * @dev implement supportsInterface(bytes4) using a lookup table
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool) {
                    return _supportedInterfaces[interfaceId];
                }
            
                /**
                 * @dev internal method for registering an interface
                 */
                function _registerInterface(bytes4 interfaceId) internal {
                    require(interfaceId != 0xffffffff);
                    _supportedInterfaces[interfaceId] = true;
                }
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
            
            pragma solidity ^0.5.0;
            
            
            
            
            
            
            /**
             * @title ERC721 Non-Fungible Token Standard basic implementation
             * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
             */
            contract ERC721 is ERC165, IERC721 {
                using SafeMath for uint256;
                using Address for address;
            
                // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
                // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
                bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
            
                // Mapping from token ID to owner
                mapping (uint256 => address) private _tokenOwner;
            
                // Mapping from token ID to approved address
                mapping (uint256 => address) private _tokenApprovals;
            
                // Mapping from owner to number of owned token
                mapping (address => uint256) private _ownedTokensCount;
            
                // Mapping from owner to operator approvals
                mapping (address => mapping (address => bool)) private _operatorApprovals;
            
                bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
                /*
                 * 0x80ac58cd ===
                 *     bytes4(keccak256('balanceOf(address)')) ^
                 *     bytes4(keccak256('ownerOf(uint256)')) ^
                 *     bytes4(keccak256('approve(address,uint256)')) ^
                 *     bytes4(keccak256('getApproved(uint256)')) ^
                 *     bytes4(keccak256('setApprovalForAll(address,bool)')) ^
                 *     bytes4(keccak256('isApprovedForAll(address,address)')) ^
                 *     bytes4(keccak256('transferFrom(address,address,uint256)')) ^
                 *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
                 *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
                 */
            
                constructor () public {
                    // register the supported interfaces to conform to ERC721 via ERC165
                    _registerInterface(_INTERFACE_ID_ERC721);
                }
            
                /**
                 * @dev Gets the balance of the specified address
                 * @param owner address to query the balance of
                 * @return uint256 representing the amount owned by the passed address
                 */
                function balanceOf(address owner) public view returns (uint256) {
                    require(owner != address(0));
                    return _ownedTokensCount[owner];
                }
            
                /**
                 * @dev Gets the owner of the specified token ID
                 * @param tokenId uint256 ID of the token to query the owner of
                 * @return owner address currently marked as the owner of the given token ID
                 */
                function ownerOf(uint256 tokenId) public view returns (address) {
                    address owner = _tokenOwner[tokenId];
                    require(owner != address(0));
                    return owner;
                }
            
                /**
                 * @dev Approves another address to transfer the given token ID
                 * The zero address indicates there is no approved address.
                 * There can only be one approved address per token at a given time.
                 * Can only be called by the token owner or an approved operator.
                 * @param to address to be approved for the given token ID
                 * @param tokenId uint256 ID of the token to be approved
                 */
                function approve(address to, uint256 tokenId) public {
                    address owner = ownerOf(tokenId);
                    require(to != owner);
                    require(msg.sender == owner || isApprovedForAll(owner, msg.sender));
            
                    _tokenApprovals[tokenId] = to;
                    emit Approval(owner, to, tokenId);
                }
            
                /**
                 * @dev Gets the approved address for a token ID, or zero if no address set
                 * Reverts if the token ID does not exist.
                 * @param tokenId uint256 ID of the token to query the approval of
                 * @return address currently approved for the given token ID
                 */
                function getApproved(uint256 tokenId) public view returns (address) {
                    require(_exists(tokenId));
                    return _tokenApprovals[tokenId];
                }
            
                /**
                 * @dev Sets or unsets the approval of a given operator
                 * An operator is allowed to transfer all tokens of the sender on their behalf
                 * @param to operator address to set the approval
                 * @param approved representing the status of the approval to be set
                 */
                function setApprovalForAll(address to, bool approved) public {
                    require(to != msg.sender);
                    _operatorApprovals[msg.sender][to] = approved;
                    emit ApprovalForAll(msg.sender, to, approved);
                }
            
                /**
                 * @dev Tells whether an operator is approved by a given owner
                 * @param owner owner address which you want to query the approval of
                 * @param operator operator address which you want to query the approval of
                 * @return bool whether the given operator is approved by the given owner
                 */
                function isApprovedForAll(address owner, address operator) public view returns (bool) {
                    return _operatorApprovals[owner][operator];
                }
            
                /**
                 * @dev Transfers the ownership of a given token ID to another address
                 * Usage of this method is discouraged, use `safeTransferFrom` whenever possible
                 * Requires the msg sender to be the owner, approved, or operator
                 * @param from current owner of the token
                 * @param to address to receive the ownership of the given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                */
                function transferFrom(address from, address to, uint256 tokenId) public {
                    require(_isApprovedOrOwner(msg.sender, tokenId));
            
                    _transferFrom(from, to, tokenId);
                }
            
                /**
                 * @dev Safely transfers the ownership of a given token ID to another address
                 * If the target address is a contract, it must implement `onERC721Received`,
                 * which is called upon a safe transfer, and return the magic value
                 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
                 * the transfer is reverted.
                 *
                 * Requires the msg sender to be the owner, approved, or operator
                 * @param from current owner of the token
                 * @param to address to receive the ownership of the given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                */
                function safeTransferFrom(address from, address to, uint256 tokenId) public {
                    safeTransferFrom(from, to, tokenId, "");
                }
            
                /**
                 * @dev Safely transfers the ownership of a given token ID to another address
                 * If the target address is a contract, it must implement `onERC721Received`,
                 * which is called upon a safe transfer, and return the magic value
                 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
                 * the transfer is reverted.
                 * Requires the msg sender to be the owner, approved, or operator
                 * @param from current owner of the token
                 * @param to address to receive the ownership of the given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                 * @param _data bytes data to send along with a safe transfer check
                 */
                function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
                    transferFrom(from, to, tokenId);
                    require(_checkOnERC721Received(from, to, tokenId, _data));
                }
            
                /**
                 * @dev Returns whether the specified token exists
                 * @param tokenId uint256 ID of the token to query the existence of
                 * @return whether the token exists
                 */
                function _exists(uint256 tokenId) internal view returns (bool) {
                    address owner = _tokenOwner[tokenId];
                    return owner != address(0);
                }
            
                /**
                 * @dev Returns whether the given spender can transfer a given token ID
                 * @param spender address of the spender to query
                 * @param tokenId uint256 ID of the token to be transferred
                 * @return bool whether the msg.sender is approved for the given token ID,
                 *    is an operator of the owner, or is the owner of the token
                 */
                function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
                    address owner = ownerOf(tokenId);
                    return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
                }
            
                /**
                 * @dev Internal function to mint a new token
                 * Reverts if the given token ID already exists
                 * @param to The address that will own the minted token
                 * @param tokenId uint256 ID of the token to be minted
                 */
                function _mint(address to, uint256 tokenId) internal {
                    require(to != address(0));
                    require(!_exists(tokenId));
            
                    _tokenOwner[tokenId] = to;
                    _ownedTokensCount[to] = _ownedTokensCount[to].add(1);
            
                    emit Transfer(address(0), to, tokenId);
                }
            
                /**
                 * @dev Internal function to burn a specific token
                 * Reverts if the token does not exist
                 * Deprecated, use _burn(uint256) instead.
                 * @param owner owner of the token to burn
                 * @param tokenId uint256 ID of the token being burned
                 */
                function _burn(address owner, uint256 tokenId) internal {
                    require(ownerOf(tokenId) == owner);
            
                    _clearApproval(tokenId);
            
                    _ownedTokensCount[owner] = _ownedTokensCount[owner].sub(1);
                    _tokenOwner[tokenId] = address(0);
            
                    emit Transfer(owner, address(0), tokenId);
                }
            
                /**
                 * @dev Internal function to burn a specific token
                 * Reverts if the token does not exist
                 * @param tokenId uint256 ID of the token being burned
                 */
                function _burn(uint256 tokenId) internal {
                    _burn(ownerOf(tokenId), tokenId);
                }
            
                /**
                 * @dev Internal function to transfer ownership of a given token ID to another address.
                 * As opposed to transferFrom, this imposes no restrictions on msg.sender.
                 * @param from current owner of the token
                 * @param to address to receive the ownership of the given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                */
                function _transferFrom(address from, address to, uint256 tokenId) internal {
                    require(ownerOf(tokenId) == from);
                    require(to != address(0));
            
                    _clearApproval(tokenId);
            
                    _ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
                    _ownedTokensCount[to] = _ownedTokensCount[to].add(1);
            
                    _tokenOwner[tokenId] = to;
            
                    emit Transfer(from, to, tokenId);
                }
            
                /**
                 * @dev Internal function to invoke `onERC721Received` on a target address
                 * The call is not executed if the target address is not a contract
                 * @param from address representing the previous owner of the given token ID
                 * @param to target address that will receive the tokens
                 * @param tokenId uint256 ID of the token to be transferred
                 * @param _data bytes optional data to send along with the call
                 * @return whether the call correctly returned the expected magic value
                 */
                function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
                    internal returns (bool)
                {
                    if (!to.isContract()) {
                        return true;
                    }
            
                    bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
                    return (retval == _ERC721_RECEIVED);
                }
            
                /**
                 * @dev Private function to clear current approval of a given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                 */
                function _clearApproval(uint256 tokenId) private {
                    if (_tokenApprovals[tokenId] != address(0)) {
                        _tokenApprovals[tokenId] = address(0);
                    }
                }
            }
            
            // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title Ownable
             * @dev The Ownable contract has an owner address, and provides basic authorization control
             * functions, this simplifies the implementation of "user permissions".
             */
            contract Ownable {
                address private _owner;
            
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            
                /**
                 * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                 * account.
                 */
                constructor () internal {
                    _owner = msg.sender;
                    emit OwnershipTransferred(address(0), _owner);
                }
            
                /**
                 * @return the address of the owner.
                 */
                function owner() public view returns (address) {
                    return _owner;
                }
            
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    require(isOwner());
                    _;
                }
            
                /**
                 * @return true if `msg.sender` is the owner of the contract.
                 */
                function isOwner() public view returns (bool) {
                    return msg.sender == _owner;
                }
            
                /**
                 * @dev Allows the current owner to relinquish control of the contract.
                 * @notice Renouncing to ownership will leave the contract without an owner.
                 * It will not be possible to call the functions with the `onlyOwner`
                 * modifier anymore.
                 */
                function renounceOwnership() public onlyOwner {
                    emit OwnershipTransferred(_owner, address(0));
                    _owner = address(0);
                }
            
                /**
                 * @dev Allows the current owner to transfer control of the contract to a newOwner.
                 * @param newOwner The address to transfer ownership to.
                 */
                function transferOwnership(address newOwner) public onlyOwner {
                    _transferOwnership(newOwner);
                }
            
                /**
                 * @dev Transfers control of the contract to a newOwner.
                 * @param newOwner The address to transfer ownership to.
                 */
                function _transferOwnership(address newOwner) internal {
                    require(newOwner != address(0));
                    emit OwnershipTransferred(_owner, newOwner);
                    _owner = newOwner;
                }
            }
            
            // File: @ensdomains/ethregistrar/contracts/BaseRegistrar.sol
            
            pragma solidity >=0.4.24;
            
            
            
            
            contract BaseRegistrar is IERC721, Ownable {
                uint constant public GRACE_PERIOD = 90 days;
            
                event ControllerAdded(address indexed controller);
                event ControllerRemoved(address indexed controller);
                event NameMigrated(uint256 indexed id, address indexed owner, uint expires);
                event NameRegistered(uint256 indexed id, address indexed owner, uint expires);
                event NameRenewed(uint256 indexed id, uint expires);
            
                // The ENS registry
                ENS public ens;
            
                // The namehash of the TLD this registrar owns (eg, .eth)
                bytes32 public baseNode;
            
                // A map of addresses that are authorised to register and renew names.
                mapping(address=>bool) public controllers;
            
                // Authorises a controller, who can register and renew domains.
                function addController(address controller) external;
            
                // Revoke controller permission for an address.
                function removeController(address controller) external;
            
                // Set the resolver for the TLD this registrar manages.
                function setResolver(address resolver) external;
            
                // Returns the expiration timestamp of the specified label hash.
                function nameExpires(uint256 id) external view returns(uint);
            
                // Returns true iff the specified name is available for registration.
                function available(uint256 id) public view returns(bool);
            
                /**
                 * @dev Register a name.
                 */
                function register(uint256 id, address owner, uint duration) external returns(uint);
            
                function renew(uint256 id, uint duration) external returns(uint);
            
                /**
                 * @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
                 */
                function reclaim(uint256 id, address owner) external;
            }
            
            // File: @ensdomains/ethregistrar/contracts/BaseRegistrarImplementation.sol
            
            pragma solidity ^0.5.0;
            
            
            
            
            contract BaseRegistrarImplementation is BaseRegistrar, ERC721 {
                // A map of expiry times
                mapping(uint256=>uint) expiries;
            
                bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
                bytes4 constant private ERC721_ID = bytes4(
                    keccak256("balanceOf(address)") ^
                    keccak256("ownerOf(uint256)") ^
                    keccak256("approve(address,uint256)") ^
                    keccak256("getApproved(uint256)") ^
                    keccak256("setApprovalForAll(address,bool)") ^
                    keccak256("isApprovedForAll(address,address)") ^
                    keccak256("transferFrom(address,address,uint256)") ^
                    keccak256("safeTransferFrom(address,address,uint256)") ^
                    keccak256("safeTransferFrom(address,address,uint256,bytes)")
                );
                bytes4 constant private RECLAIM_ID = bytes4(keccak256("reclaim(uint256,address)"));
            
                constructor(ENS _ens, bytes32 _baseNode) public {
                    ens = _ens;
                    baseNode = _baseNode;
                }
            
                modifier live {
                    require(ens.owner(baseNode) == address(this));
                    _;
                }
            
                modifier onlyController {
                    require(controllers[msg.sender]);
                    _;
                }
            
                /**
                 * @dev Gets the owner of the specified token ID. Names become unowned
                 *      when their registration expires.
                 * @param tokenId uint256 ID of the token to query the owner of
                 * @return address currently marked as the owner of the given token ID
                 */
                function ownerOf(uint256 tokenId) public view returns (address) {
                    require(expiries[tokenId] > now);
                    return super.ownerOf(tokenId);
                }
            
                // Authorises a controller, who can register and renew domains.
                function addController(address controller) external onlyOwner {
                    controllers[controller] = true;
                    emit ControllerAdded(controller);
                }
            
                // Revoke controller permission for an address.
                function removeController(address controller) external onlyOwner {
                    controllers[controller] = false;
                    emit ControllerRemoved(controller);
                }
            
                // Set the resolver for the TLD this registrar manages.
                function setResolver(address resolver) external onlyOwner {
                    ens.setResolver(baseNode, resolver);
                }
            
                // Returns the expiration timestamp of the specified id.
                function nameExpires(uint256 id) external view returns(uint) {
                    return expiries[id];
                }
            
                // Returns true iff the specified name is available for registration.
                function available(uint256 id) public view returns(bool) {
                    // Not available if it's registered here or in its grace period.
                    return expiries[id] + GRACE_PERIOD < now;
                }
            
                /**
                 * @dev Register a name.
                 * @param id The token ID (keccak256 of the label).
                 * @param owner The address that should own the registration.
                 * @param duration Duration in seconds for the registration.
                 */
                function register(uint256 id, address owner, uint duration) external returns(uint) {
                  return _register(id, owner, duration, true);
                }
            
                /**
                 * @dev Register a name, without modifying the registry.
                 * @param id The token ID (keccak256 of the label).
                 * @param owner The address that should own the registration.
                 * @param duration Duration in seconds for the registration.
                 */
                function registerOnly(uint256 id, address owner, uint duration) external returns(uint) {
                  return _register(id, owner, duration, false);
                }
            
                function _register(uint256 id, address owner, uint duration, bool updateRegistry) internal live onlyController returns(uint) {
                    require(available(id));
                    require(now + duration + GRACE_PERIOD > now + GRACE_PERIOD); // Prevent future overflow
            
                    expiries[id] = now + duration;
                    if(_exists(id)) {
                        // Name was previously owned, and expired
                        _burn(id);
                    }
                    _mint(owner, id);
                    if(updateRegistry) {
                        ens.setSubnodeOwner(baseNode, bytes32(id), owner);
                    }
            
                    emit NameRegistered(id, owner, now + duration);
            
                    return now + duration;
                }
            
                function renew(uint256 id, uint duration) external live onlyController returns(uint) {
                    require(expiries[id] + GRACE_PERIOD >= now); // Name must be registered here or in grace period
                    require(expiries[id] + duration + GRACE_PERIOD > duration + GRACE_PERIOD); // Prevent future overflow
            
                    expiries[id] += duration;
                    emit NameRenewed(id, expiries[id]);
                    return expiries[id];
                }
            
                /**
                 * @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
                 */
                function reclaim(uint256 id, address owner) external live {
                    require(_isApprovedOrOwner(msg.sender, id));
                    ens.setSubnodeOwner(baseNode, bytes32(id), owner);
                }
            
                function supportsInterface(bytes4 interfaceID) external view returns (bool) {
                    return interfaceID == INTERFACE_META_ID ||
                           interfaceID == ERC721_ID ||
                           interfaceID == RECLAIM_ID;
                }
            }

            File 3 of 6: ENSRegistryWithFallback
            // File: @ensdomains/ens/contracts/ENS.sol
            
            pragma solidity >=0.4.24;
            
            interface ENS {
            
                // Logged when the owner of a node assigns a new owner to a subnode.
                event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
            
                // Logged when the owner of a node transfers ownership to a new account.
                event Transfer(bytes32 indexed node, address owner);
            
                // Logged when the resolver for a node changes.
                event NewResolver(bytes32 indexed node, address resolver);
            
                // Logged when the TTL of a node changes
                event NewTTL(bytes32 indexed node, uint64 ttl);
            
                // Logged when an operator is added or removed.
                event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            
                function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external;
                function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external;
                function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external returns(bytes32);
                function setResolver(bytes32 node, address resolver) external;
                function setOwner(bytes32 node, address owner) external;
                function setTTL(bytes32 node, uint64 ttl) external;
                function setApprovalForAll(address operator, bool approved) external;
                function owner(bytes32 node) external view returns (address);
                function resolver(bytes32 node) external view returns (address);
                function ttl(bytes32 node) external view returns (uint64);
                function recordExists(bytes32 node) external view returns (bool);
                function isApprovedForAll(address owner, address operator) external view returns (bool);
            }
            
            // File: @ensdomains/ens/contracts/ENSRegistry.sol
            
            pragma solidity ^0.5.0;
            
            
            /**
             * The ENS registry contract.
             */
            contract ENSRegistry is ENS {
            
                struct Record {
                    address owner;
                    address resolver;
                    uint64 ttl;
                }
            
                mapping (bytes32 => Record) records;
                mapping (address => mapping(address => bool)) operators;
            
                // Permits modifications only by the owner of the specified node.
                modifier authorised(bytes32 node) {
                    address owner = records[node].owner;
                    require(owner == msg.sender || operators[owner][msg.sender]);
                    _;
                }
            
                /**
                 * @dev Constructs a new ENS registrar.
                 */
                constructor() public {
                    records[0x0].owner = msg.sender;
                }
            
                /**
                 * @dev Sets the record for a node.
                 * @param node The node to update.
                 * @param owner The address of the new owner.
                 * @param resolver The address of the resolver.
                 * @param ttl The TTL in seconds.
                 */
                function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external {
                    setOwner(node, owner);
                    _setResolverAndTTL(node, resolver, ttl);
                }
            
                /**
                 * @dev Sets the record for a subnode.
                 * @param node The parent node.
                 * @param label The hash of the label specifying the subnode.
                 * @param owner The address of the new owner.
                 * @param resolver The address of the resolver.
                 * @param ttl The TTL in seconds.
                 */
                function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external {
                    bytes32 subnode = setSubnodeOwner(node, label, owner);
                    _setResolverAndTTL(subnode, resolver, ttl);
                }
            
                /**
                 * @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node.
                 * @param node The node to transfer ownership of.
                 * @param owner The address of the new owner.
                 */
                function setOwner(bytes32 node, address owner) public authorised(node) {
                    _setOwner(node, owner);
                    emit Transfer(node, owner);
                }
            
                /**
                 * @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node.
                 * @param node The parent node.
                 * @param label The hash of the label specifying the subnode.
                 * @param owner The address of the new owner.
                 */
                function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public authorised(node) returns(bytes32) {
                    bytes32 subnode = keccak256(abi.encodePacked(node, label));
                    _setOwner(subnode, owner);
                    emit NewOwner(node, label, owner);
                    return subnode;
                }
            
                /**
                 * @dev Sets the resolver address for the specified node.
                 * @param node The node to update.
                 * @param resolver The address of the resolver.
                 */
                function setResolver(bytes32 node, address resolver) public authorised(node) {
                    emit NewResolver(node, resolver);
                    records[node].resolver = resolver;
                }
            
                /**
                 * @dev Sets the TTL for the specified node.
                 * @param node The node to update.
                 * @param ttl The TTL in seconds.
                 */
                function setTTL(bytes32 node, uint64 ttl) public authorised(node) {
                    emit NewTTL(node, ttl);
                    records[node].ttl = ttl;
                }
            
                /**
                 * @dev Enable or disable approval for a third party ("operator") to manage
                 *  all of `msg.sender`'s ENS records. Emits the ApprovalForAll event.
                 * @param operator Address to add to the set of authorized operators.
                 * @param approved True if the operator is approved, false to revoke approval.
                 */
                function setApprovalForAll(address operator, bool approved) external {
                    operators[msg.sender][operator] = approved;
                    emit ApprovalForAll(msg.sender, operator, approved);
                }
            
                /**
                 * @dev Returns the address that owns the specified node.
                 * @param node The specified node.
                 * @return address of the owner.
                 */
                function owner(bytes32 node) public view returns (address) {
                    address addr = records[node].owner;
                    if (addr == address(this)) {
                        return address(0x0);
                    }
            
                    return addr;
                }
            
                /**
                 * @dev Returns the address of the resolver for the specified node.
                 * @param node The specified node.
                 * @return address of the resolver.
                 */
                function resolver(bytes32 node) public view returns (address) {
                    return records[node].resolver;
                }
            
                /**
                 * @dev Returns the TTL of a node, and any records associated with it.
                 * @param node The specified node.
                 * @return ttl of the node.
                 */
                function ttl(bytes32 node) public view returns (uint64) {
                    return records[node].ttl;
                }
            
                /**
                 * @dev Returns whether a record has been imported to the registry.
                 * @param node The specified node.
                 * @return Bool if record exists
                 */
                function recordExists(bytes32 node) public view returns (bool) {
                    return records[node].owner != address(0x0);
                }
            
                /**
                 * @dev Query if an address is an authorized operator for another address.
                 * @param owner The address that owns the records.
                 * @param operator The address that acts on behalf of the owner.
                 * @return True if `operator` is an approved operator for `owner`, false otherwise.
                 */
                function isApprovedForAll(address owner, address operator) external view returns (bool) {
                    return operators[owner][operator];
                }
            
                function _setOwner(bytes32 node, address owner) internal {
                    records[node].owner = owner;
                }
            
                function _setResolverAndTTL(bytes32 node, address resolver, uint64 ttl) internal {
                    if(resolver != records[node].resolver) {
                        records[node].resolver = resolver;
                        emit NewResolver(node, resolver);
                    }
            
                    if(ttl != records[node].ttl) {
                        records[node].ttl = ttl;
                        emit NewTTL(node, ttl);
                    }
                }
            }
            
            // File: @ensdomains/ens/contracts/ENSRegistryWithFallback.sol
            
            pragma solidity ^0.5.0;
            
            
            
            /**
             * The ENS registry contract.
             */
            contract ENSRegistryWithFallback is ENSRegistry {
            
                ENS public old;
            
                /**
                 * @dev Constructs a new ENS registrar.
                 */
                constructor(ENS _old) public ENSRegistry() {
                    old = _old;
                }
            
                /**
                 * @dev Returns the address of the resolver for the specified node.
                 * @param node The specified node.
                 * @return address of the resolver.
                 */
                function resolver(bytes32 node) public view returns (address) {
                    if (!recordExists(node)) {
                        return old.resolver(node);
                    }
            
                    return super.resolver(node);
                }
            
                /**
                 * @dev Returns the address that owns the specified node.
                 * @param node The specified node.
                 * @return address of the owner.
                 */
                function owner(bytes32 node) public view returns (address) {
                    if (!recordExists(node)) {
                        return old.owner(node);
                    }
            
                    return super.owner(node);
                }
            
                /**
                 * @dev Returns the TTL of a node, and any records associated with it.
                 * @param node The specified node.
                 * @return ttl of the node.
                 */
                function ttl(bytes32 node) public view returns (uint64) {
                    if (!recordExists(node)) {
                        return old.ttl(node);
                    }
            
                    return super.ttl(node);
                }
            
                function _setOwner(bytes32 node, address owner) internal {
                    address addr = owner;
                    if (addr == address(0x0)) {
                        addr = address(this);
                    }
            
                    super._setOwner(node, addr);
                }
            }

            File 4 of 6: PublicResolver
            // File: @ensdomains/ens/contracts/ENS.sol
            
            pragma solidity >=0.4.24;
            
            interface ENS {
            
                // Logged when the owner of a node assigns a new owner to a subnode.
                event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
            
                // Logged when the owner of a node transfers ownership to a new account.
                event Transfer(bytes32 indexed node, address owner);
            
                // Logged when the resolver for a node changes.
                event NewResolver(bytes32 indexed node, address resolver);
            
                // Logged when the TTL of a node changes
                event NewTTL(bytes32 indexed node, uint64 ttl);
            
            
                function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external;
                function setResolver(bytes32 node, address resolver) external;
                function setOwner(bytes32 node, address owner) external;
                function setTTL(bytes32 node, uint64 ttl) external;
                function owner(bytes32 node) external view returns (address);
                function resolver(bytes32 node) external view returns (address);
                function ttl(bytes32 node) external view returns (uint64);
            
            }
            
            // File: contracts/ResolverBase.sol
            
            pragma solidity ^0.5.0;
            
            contract ResolverBase {
                bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;
            
                function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                    return interfaceID == INTERFACE_META_ID;
                }
            
                function isAuthorised(bytes32 node) internal view returns(bool);
            
                modifier authorised(bytes32 node) {
                    require(isAuthorised(node));
                    _;
                }
            
                function bytesToAddress(bytes memory b) internal pure returns(address payable a) {
                    require(b.length == 20);
                    assembly {
                        a := div(mload(add(b, 32)), exp(256, 12))
                    }
                }
            
                function addressToBytes(address a) internal pure returns(bytes memory b) {
                    b = new bytes(20);
                    assembly {
                        mstore(add(b, 32), mul(a, exp(256, 12)))
                    }
                }
            }
            
            // File: contracts/profiles/ABIResolver.sol
            
            pragma solidity ^0.5.0;
            
            
            contract ABIResolver is ResolverBase {
                bytes4 constant private ABI_INTERFACE_ID = 0x2203ab56;
            
                event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
            
                mapping(bytes32=>mapping(uint256=>bytes)) abis;
            
                /**
                 * Sets the ABI associated with an ENS node.
                 * Nodes may have one ABI of each content type. To remove an ABI, set it to
                 * the empty string.
                 * @param node The node to update.
                 * @param contentType The content type of the ABI
                 * @param data The ABI data.
                 */
                function setABI(bytes32 node, uint256 contentType, bytes calldata data) external authorised(node) {
                    // Content types must be powers of 2
                    require(((contentType - 1) & contentType) == 0);
            
                    abis[node][contentType] = data;
                    emit ABIChanged(node, contentType);
                }
            
                /**
                 * Returns the ABI associated with an ENS node.
                 * Defined in EIP205.
                 * @param node The ENS node to query
                 * @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
                 * @return contentType The content type of the return value
                 * @return data The ABI data
                 */
                function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory) {
                    mapping(uint256=>bytes) storage abiset = abis[node];
            
                    for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) {
                        if ((contentType & contentTypes) != 0 && abiset[contentType].length > 0) {
                            return (contentType, abiset[contentType]);
                        }
                    }
            
                    return (0, bytes(""));
                }
            
                function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                    return interfaceID == ABI_INTERFACE_ID || super.supportsInterface(interfaceID);
                }
            }
            
            // File: contracts/profiles/AddrResolver.sol
            
            pragma solidity ^0.5.0;
            
            
            contract AddrResolver is ResolverBase {
                bytes4 constant private ADDR_INTERFACE_ID = 0x3b3b57de;
                bytes4 constant private ADDRESS_INTERFACE_ID = 0xf1cb7e06;
                uint constant private COIN_TYPE_ETH = 60;
            
                event AddrChanged(bytes32 indexed node, address a);
                event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
            
                mapping(bytes32=>mapping(uint=>bytes)) _addresses;
            
                /**
                 * Sets the address associated with an ENS node.
                 * May only be called by the owner of that node in the ENS registry.
                 * @param node The node to update.
                 * @param a The address to set.
                 */
                function setAddr(bytes32 node, address a) external authorised(node) {
                    setAddr(node, COIN_TYPE_ETH, addressToBytes(a));
                }
            
                /**
                 * Returns the address associated with an ENS node.
                 * @param node The ENS node to query.
                 * @return The associated address.
                 */
                function addr(bytes32 node) public view returns (address payable) {
                    bytes memory a = addr(node, COIN_TYPE_ETH);
                    if(a.length == 0) {
                        return address(0);
                    }
                    return bytesToAddress(a);
                }
            
                function setAddr(bytes32 node, uint coinType, bytes memory a) public authorised(node) {
                    emit AddressChanged(node, coinType, a);
                    if(coinType == COIN_TYPE_ETH) {
                        emit AddrChanged(node, bytesToAddress(a));
                    }
                    _addresses[node][coinType] = a;
                }
            
                function addr(bytes32 node, uint coinType) public view returns(bytes memory) {
                    return _addresses[node][coinType];
                }
            
                function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                    return interfaceID == ADDR_INTERFACE_ID || interfaceID == ADDRESS_INTERFACE_ID || super.supportsInterface(interfaceID);
                }
            }
            
            // File: contracts/profiles/ContentHashResolver.sol
            
            pragma solidity ^0.5.0;
            
            
            contract ContentHashResolver is ResolverBase {
                bytes4 constant private CONTENT_HASH_INTERFACE_ID = 0xbc1c58d1;
            
                event ContenthashChanged(bytes32 indexed node, bytes hash);
            
                mapping(bytes32=>bytes) hashes;
            
                /**
                 * Sets the contenthash associated with an ENS node.
                 * May only be called by the owner of that node in the ENS registry.
                 * @param node The node to update.
                 * @param hash The contenthash to set
                 */
                function setContenthash(bytes32 node, bytes calldata hash) external authorised(node) {
                    hashes[node] = hash;
                    emit ContenthashChanged(node, hash);
                }
            
                /**
                 * Returns the contenthash associated with an ENS node.
                 * @param node The ENS node to query.
                 * @return The associated contenthash.
                 */
                function contenthash(bytes32 node) external view returns (bytes memory) {
                    return hashes[node];
                }
            
                function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                    return interfaceID == CONTENT_HASH_INTERFACE_ID || super.supportsInterface(interfaceID);
                }
            }
            
            // File: @ensdomains/dnssec-oracle/contracts/BytesUtils.sol
            
            pragma solidity >0.4.23;
            
            library BytesUtils {
                /*
                * @dev Returns the keccak-256 hash of a byte range.
                * @param self The byte string to hash.
                * @param offset The position to start hashing at.
                * @param len The number of bytes to hash.
                * @return The hash of the byte range.
                */
                function keccak(bytes memory self, uint offset, uint len) internal pure returns (bytes32 ret) {
                    require(offset + len <= self.length);
                    assembly {
                        ret := keccak256(add(add(self, 32), offset), len)
                    }
                }
            
            
                /*
                * @dev Returns a positive number if `other` comes lexicographically after
                *      `self`, a negative number if it comes before, or zero if the
                *      contents of the two bytes are equal.
                * @param self The first bytes to compare.
                * @param other The second bytes to compare.
                * @return The result of the comparison.
                */
                function compare(bytes memory self, bytes memory other) internal pure returns (int) {
                    return compare(self, 0, self.length, other, 0, other.length);
                }
            
                /*
                * @dev Returns a positive number if `other` comes lexicographically after
                *      `self`, a negative number if it comes before, or zero if the
                *      contents of the two bytes are equal. Comparison is done per-rune,
                *      on unicode codepoints.
                * @param self The first bytes to compare.
                * @param offset The offset of self.
                * @param len    The length of self.
                * @param other The second bytes to compare.
                * @param otheroffset The offset of the other string.
                * @param otherlen    The length of the other string.
                * @return The result of the comparison.
                */
                function compare(bytes memory self, uint offset, uint len, bytes memory other, uint otheroffset, uint otherlen) internal pure returns (int) {
                    uint shortest = len;
                    if (otherlen < len)
                    shortest = otherlen;
            
                    uint selfptr;
                    uint otherptr;
            
                    assembly {
                        selfptr := add(self, add(offset, 32))
                        otherptr := add(other, add(otheroffset, 32))
                    }
                    for (uint idx = 0; idx < shortest; idx += 32) {
                        uint a;
                        uint b;
                        assembly {
                            a := mload(selfptr)
                            b := mload(otherptr)
                        }
                        if (a != b) {
                            // Mask out irrelevant bytes and check again
                            uint mask;
                            if (shortest > 32) {
                                mask = uint256(- 1); // aka 0xffffff....
                            } else {
                                mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
                            }
                            uint diff = (a & mask) - (b & mask);
                            if (diff != 0)
                            return int(diff);
                        }
                        selfptr += 32;
                        otherptr += 32;
                    }
            
                    return int(len) - int(otherlen);
                }
            
                /*
                * @dev Returns true if the two byte ranges are equal.
                * @param self The first byte range to compare.
                * @param offset The offset into the first byte range.
                * @param other The second byte range to compare.
                * @param otherOffset The offset into the second byte range.
                * @param len The number of bytes to compare
                * @return True if the byte ranges are equal, false otherwise.
                */
                function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset, uint len) internal pure returns (bool) {
                    return keccak(self, offset, len) == keccak(other, otherOffset, len);
                }
            
                /*
                * @dev Returns true if the two byte ranges are equal with offsets.
                * @param self The first byte range to compare.
                * @param offset The offset into the first byte range.
                * @param other The second byte range to compare.
                * @param otherOffset The offset into the second byte range.
                * @return True if the byte ranges are equal, false otherwise.
                */
                function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset) internal pure returns (bool) {
                    return keccak(self, offset, self.length - offset) == keccak(other, otherOffset, other.length - otherOffset);
                }
            
                /*
                * @dev Compares a range of 'self' to all of 'other' and returns True iff
                *      they are equal.
                * @param self The first byte range to compare.
                * @param offset The offset into the first byte range.
                * @param other The second byte range to compare.
                * @return True if the byte ranges are equal, false otherwise.
                */
                function equals(bytes memory self, uint offset, bytes memory other) internal pure returns (bool) {
                    return self.length >= offset + other.length && equals(self, offset, other, 0, other.length);
                }
            
                /*
                * @dev Returns true if the two byte ranges are equal.
                * @param self The first byte range to compare.
                * @param other The second byte range to compare.
                * @return True if the byte ranges are equal, false otherwise.
                */
                function equals(bytes memory self, bytes memory other) internal pure returns(bool) {
                    return self.length == other.length && equals(self, 0, other, 0, self.length);
                }
            
                /*
                * @dev Returns the 8-bit number at the specified index of self.
                * @param self The byte string.
                * @param idx The index into the bytes
                * @return The specified 8 bits of the string, interpreted as an integer.
                */
                function readUint8(bytes memory self, uint idx) internal pure returns (uint8 ret) {
                    return uint8(self[idx]);
                }
            
                /*
                * @dev Returns the 16-bit number at the specified index of self.
                * @param self The byte string.
                * @param idx The index into the bytes
                * @return The specified 16 bits of the string, interpreted as an integer.
                */
                function readUint16(bytes memory self, uint idx) internal pure returns (uint16 ret) {
                    require(idx + 2 <= self.length);
                    assembly {
                        ret := and(mload(add(add(self, 2), idx)), 0xFFFF)
                    }
                }
            
                /*
                * @dev Returns the 32-bit number at the specified index of self.
                * @param self The byte string.
                * @param idx The index into the bytes
                * @return The specified 32 bits of the string, interpreted as an integer.
                */
                function readUint32(bytes memory self, uint idx) internal pure returns (uint32 ret) {
                    require(idx + 4 <= self.length);
                    assembly {
                        ret := and(mload(add(add(self, 4), idx)), 0xFFFFFFFF)
                    }
                }
            
                /*
                * @dev Returns the 32 byte value at the specified index of self.
                * @param self The byte string.
                * @param idx The index into the bytes
                * @return The specified 32 bytes of the string.
                */
                function readBytes32(bytes memory self, uint idx) internal pure returns (bytes32 ret) {
                    require(idx + 32 <= self.length);
                    assembly {
                        ret := mload(add(add(self, 32), idx))
                    }
                }
            
                /*
                * @dev Returns the 32 byte value at the specified index of self.
                * @param self The byte string.
                * @param idx The index into the bytes
                * @return The specified 32 bytes of the string.
                */
                function readBytes20(bytes memory self, uint idx) internal pure returns (bytes20 ret) {
                    require(idx + 20 <= self.length);
                    assembly {
                        ret := and(mload(add(add(self, 32), idx)), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000)
                    }
                }
            
                /*
                * @dev Returns the n byte value at the specified index of self.
                * @param self The byte string.
                * @param idx The index into the bytes.
                * @param len The number of bytes.
                * @return The specified 32 bytes of the string.
                */
                function readBytesN(bytes memory self, uint idx, uint len) internal pure returns (bytes32 ret) {
                    require(len <= 32);
                    require(idx + len <= self.length);
                    assembly {
                        let mask := not(sub(exp(256, sub(32, len)), 1))
                        ret := and(mload(add(add(self, 32), idx)),  mask)
                    }
                }
            
                function memcpy(uint dest, uint src, uint len) private pure {
                    // Copy word-length chunks while possible
                    for (; len >= 32; len -= 32) {
                        assembly {
                            mstore(dest, mload(src))
                        }
                        dest += 32;
                        src += 32;
                    }
            
                    // Copy remaining bytes
                    uint mask = 256 ** (32 - len) - 1;
                    assembly {
                        let srcpart := and(mload(src), not(mask))
                        let destpart := and(mload(dest), mask)
                        mstore(dest, or(destpart, srcpart))
                    }
                }
            
                /*
                * @dev Copies a substring into a new byte string.
                * @param self The byte string to copy from.
                * @param offset The offset to start copying at.
                * @param len The number of bytes to copy.
                */
                function substring(bytes memory self, uint offset, uint len) internal pure returns(bytes memory) {
                    require(offset + len <= self.length);
            
                    bytes memory ret = new bytes(len);
                    uint dest;
                    uint src;
            
                    assembly {
                        dest := add(ret, 32)
                        src := add(add(self, 32), offset)
                    }
                    memcpy(dest, src, len);
            
                    return ret;
                }
            
                // Maps characters from 0x30 to 0x7A to their base32 values.
                // 0xFF represents invalid characters in that range.
                bytes constant base32HexTable = hex'00010203040506070809FFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1FFFFFFFFFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1F';
            
                /**
                 * @dev Decodes unpadded base32 data of up to one word in length.
                 * @param self The data to decode.
                 * @param off Offset into the string to start at.
                 * @param len Number of characters to decode.
                 * @return The decoded data, left aligned.
                 */
                function base32HexDecodeWord(bytes memory self, uint off, uint len) internal pure returns(bytes32) {
                    require(len <= 52);
            
                    uint ret = 0;
                    uint8 decoded;
                    for(uint i = 0; i < len; i++) {
                        bytes1 char = self[off + i];
                        require(char >= 0x30 && char <= 0x7A);
                        decoded = uint8(base32HexTable[uint(uint8(char)) - 0x30]);
                        require(decoded <= 0x20);
                        if(i == len - 1) {
                            break;
                        }
                        ret = (ret << 5) | decoded;
                    }
            
                    uint bitlen = len * 5;
                    if(len % 8 == 0) {
                        // Multiple of 8 characters, no padding
                        ret = (ret << 5) | decoded;
                    } else if(len % 8 == 2) {
                        // Two extra characters - 1 byte
                        ret = (ret << 3) | (decoded >> 2);
                        bitlen -= 2;
                    } else if(len % 8 == 4) {
                        // Four extra characters - 2 bytes
                        ret = (ret << 1) | (decoded >> 4);
                        bitlen -= 4;
                    } else if(len % 8 == 5) {
                        // Five extra characters - 3 bytes
                        ret = (ret << 4) | (decoded >> 1);
                        bitlen -= 1;
                    } else if(len % 8 == 7) {
                        // Seven extra characters - 4 bytes
                        ret = (ret << 2) | (decoded >> 3);
                        bitlen -= 3;
                    } else {
                        revert();
                    }
            
                    return bytes32(ret << (256 - bitlen));
                }
            }
            
            // File: @ensdomains/buffer/contracts/Buffer.sol
            
            pragma solidity >0.4.18;
            
            /**
            * @dev A library for working with mutable byte buffers in Solidity.
            *
            * Byte buffers are mutable and expandable, and provide a variety of primitives
            * for writing to them. At any time you can fetch a bytes object containing the
            * current contents of the buffer. The bytes object should not be stored between
            * operations, as it may change due to resizing of the buffer.
            */
            library Buffer {
                /**
                * @dev Represents a mutable buffer. Buffers have a current value (buf) and
                *      a capacity. The capacity may be longer than the current value, in
                *      which case it can be extended without the need to allocate more memory.
                */
                struct buffer {
                    bytes buf;
                    uint capacity;
                }
            
                /**
                * @dev Initializes a buffer with an initial capacity.
                * @param buf The buffer to initialize.
                * @param capacity The number of bytes of space to allocate the buffer.
                * @return The buffer, for chaining.
                */
                function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
                    if (capacity % 32 != 0) {
                        capacity += 32 - (capacity % 32);
                    }
                    // Allocate space for the buffer data
                    buf.capacity = capacity;
                    assembly {
                        let ptr := mload(0x40)
                        mstore(buf, ptr)
                        mstore(ptr, 0)
                        mstore(0x40, add(32, add(ptr, capacity)))
                    }
                    return buf;
                }
            
                /**
                * @dev Initializes a new buffer from an existing bytes object.
                *      Changes to the buffer may mutate the original value.
                * @param b The bytes object to initialize the buffer with.
                * @return A new buffer.
                */
                function fromBytes(bytes memory b) internal pure returns(buffer memory) {
                    buffer memory buf;
                    buf.buf = b;
                    buf.capacity = b.length;
                    return buf;
                }
            
                function resize(buffer memory buf, uint capacity) private pure {
                    bytes memory oldbuf = buf.buf;
                    init(buf, capacity);
                    append(buf, oldbuf);
                }
            
                function max(uint a, uint b) private pure returns(uint) {
                    if (a > b) {
                        return a;
                    }
                    return b;
                }
            
                /**
                * @dev Sets buffer length to 0.
                * @param buf The buffer to truncate.
                * @return The original buffer, for chaining..
                */
                function truncate(buffer memory buf) internal pure returns (buffer memory) {
                    assembly {
                        let bufptr := mload(buf)
                        mstore(bufptr, 0)
                    }
                    return buf;
                }
            
                /**
                * @dev Writes a byte string to a buffer. Resizes if doing so would exceed
                *      the capacity of the buffer.
                * @param buf The buffer to append to.
                * @param off The start offset to write to.
                * @param data The data to append.
                * @param len The number of bytes to copy.
                * @return The original buffer, for chaining.
                */
                function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) {
                    require(len <= data.length);
            
                    if (off + len > buf.capacity) {
                        resize(buf, max(buf.capacity, len + off) * 2);
                    }
            
                    uint dest;
                    uint src;
                    assembly {
                        // Memory address of the buffer data
                        let bufptr := mload(buf)
                        // Length of existing buffer data
                        let buflen := mload(bufptr)
                        // Start address = buffer address + offset + sizeof(buffer length)
                        dest := add(add(bufptr, 32), off)
                        // Update buffer length if we're extending it
                        if gt(add(len, off), buflen) {
                            mstore(bufptr, add(len, off))
                        }
                        src := add(data, 32)
                    }
            
                    // Copy word-length chunks while possible
                    for (; len >= 32; len -= 32) {
                        assembly {
                            mstore(dest, mload(src))
                        }
                        dest += 32;
                        src += 32;
                    }
            
                    // Copy remaining bytes
                    uint mask = 256 ** (32 - len) - 1;
                    assembly {
                        let srcpart := and(mload(src), not(mask))
                        let destpart := and(mload(dest), mask)
                        mstore(dest, or(destpart, srcpart))
                    }
            
                    return buf;
                }
            
                /**
                * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
                *      the capacity of the buffer.
                * @param buf The buffer to append to.
                * @param data The data to append.
                * @param len The number of bytes to copy.
                * @return The original buffer, for chaining.
                */
                function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) {
                    return write(buf, buf.buf.length, data, len);
                }
            
                /**
                * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
                *      the capacity of the buffer.
                * @param buf The buffer to append to.
                * @param data The data to append.
                * @return The original buffer, for chaining.
                */
                function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
                    return write(buf, buf.buf.length, data, data.length);
                }
            
                /**
                * @dev Writes a byte to the buffer. Resizes if doing so would exceed the
                *      capacity of the buffer.
                * @param buf The buffer to append to.
                * @param off The offset to write the byte at.
                * @param data The data to append.
                * @return The original buffer, for chaining.
                */
                function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) {
                    if (off >= buf.capacity) {
                        resize(buf, buf.capacity * 2);
                    }
            
                    assembly {
                        // Memory address of the buffer data
                        let bufptr := mload(buf)
                        // Length of existing buffer data
                        let buflen := mload(bufptr)
                        // Address = buffer address + sizeof(buffer length) + off
                        let dest := add(add(bufptr, off), 32)
                        mstore8(dest, data)
                        // Update buffer length if we extended it
                        if eq(off, buflen) {
                            mstore(bufptr, add(buflen, 1))
                        }
                    }
                    return buf;
                }
            
                /**
                * @dev Appends a byte to the buffer. Resizes if doing so would exceed the
                *      capacity of the buffer.
                * @param buf The buffer to append to.
                * @param data The data to append.
                * @return The original buffer, for chaining.
                */
                function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {
                    return writeUint8(buf, buf.buf.length, data);
                }
            
                /**
                * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would
                *      exceed the capacity of the buffer.
                * @param buf The buffer to append to.
                * @param off The offset to write at.
                * @param data The data to append.
                * @param len The number of bytes to write (left-aligned).
                * @return The original buffer, for chaining.
                */
                function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) {
                    if (len + off > buf.capacity) {
                        resize(buf, (len + off) * 2);
                    }
            
                    uint mask = 256 ** len - 1;
                    // Right-align data
                    data = data >> (8 * (32 - len));
                    assembly {
                        // Memory address of the buffer data
                        let bufptr := mload(buf)
                        // Address = buffer address + sizeof(buffer length) + off + len
                        let dest := add(add(bufptr, off), len)
                        mstore(dest, or(and(mload(dest), not(mask)), data))
                        // Update buffer length if we extended it
                        if gt(add(off, len), mload(bufptr)) {
                            mstore(bufptr, add(off, len))
                        }
                    }
                    return buf;
                }
            
                /**
                * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the
                *      capacity of the buffer.
                * @param buf The buffer to append to.
                * @param off The offset to write at.
                * @param data The data to append.
                * @return The original buffer, for chaining.
                */
                function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) {
                    return write(buf, off, bytes32(data), 20);
                }
            
                /**
                * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
                *      the capacity of the buffer.
                * @param buf The buffer to append to.
                * @param data The data to append.
                * @return The original buffer, for chhaining.
                */
                function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
                    return write(buf, buf.buf.length, bytes32(data), 20);
                }
            
                /**
                * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
                *      the capacity of the buffer.
                * @param buf The buffer to append to.
                * @param data The data to append.
                * @return The original buffer, for chaining.
                */
                function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
                    return write(buf, buf.buf.length, data, 32);
                }
            
                /**
                * @dev Writes an integer to the buffer. Resizes if doing so would exceed
                *      the capacity of the buffer.
                * @param buf The buffer to append to.
                * @param off The offset to write at.
                * @param data The data to append.
                * @param len The number of bytes to write (right-aligned).
                * @return The original buffer, for chaining.
                */
                function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) {
                    if (len + off > buf.capacity) {
                        resize(buf, (len + off) * 2);
                    }
            
                    uint mask = 256 ** len - 1;
                    assembly {
                        // Memory address of the buffer data
                        let bufptr := mload(buf)
                        // Address = buffer address + off + sizeof(buffer length) + len
                        let dest := add(add(bufptr, off), len)
                        mstore(dest, or(and(mload(dest), not(mask)), data))
                        // Update buffer length if we extended it
                        if gt(add(off, len), mload(bufptr)) {
                            mstore(bufptr, add(off, len))
                        }
                    }
                    return buf;
                }
            
                /**
                 * @dev Appends a byte to the end of the buffer. Resizes if doing so would
                 * exceed the capacity of the buffer.
                 * @param buf The buffer to append to.
                 * @param data The data to append.
                 * @return The original buffer.
                 */
                function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
                    return writeInt(buf, buf.buf.length, data, len);
                }
            }
            
            // File: @ensdomains/dnssec-oracle/contracts/RRUtils.sol
            
            pragma solidity >0.4.23;
            
            
            
            /**
            * @dev RRUtils is a library that provides utilities for parsing DNS resource records.
            */
            library RRUtils {
                using BytesUtils for *;
                using Buffer for *;
            
                /**
                * @dev Returns the number of bytes in the DNS name at 'offset' in 'self'.
                * @param self The byte array to read a name from.
                * @param offset The offset to start reading at.
                * @return The length of the DNS name at 'offset', in bytes.
                */
                function nameLength(bytes memory self, uint offset) internal pure returns(uint) {
                    uint idx = offset;
                    while (true) {
                        assert(idx < self.length);
                        uint labelLen = self.readUint8(idx);
                        idx += labelLen + 1;
                        if (labelLen == 0) {
                            break;
                        }
                    }
                    return idx - offset;
                }
            
                /**
                * @dev Returns a DNS format name at the specified offset of self.
                * @param self The byte array to read a name from.
                * @param offset The offset to start reading at.
                * @return The name.
                */
                function readName(bytes memory self, uint offset) internal pure returns(bytes memory ret) {
                    uint len = nameLength(self, offset);
                    return self.substring(offset, len);
                }
            
                /**
                * @dev Returns the number of labels in the DNS name at 'offset' in 'self'.
                * @param self The byte array to read a name from.
                * @param offset The offset to start reading at.
                * @return The number of labels in the DNS name at 'offset', in bytes.
                */
                function labelCount(bytes memory self, uint offset) internal pure returns(uint) {
                    uint count = 0;
                    while (true) {
                        assert(offset < self.length);
                        uint labelLen = self.readUint8(offset);
                        offset += labelLen + 1;
                        if (labelLen == 0) {
                            break;
                        }
                        count += 1;
                    }
                    return count;
                }
            
                /**
                * @dev An iterator over resource records.
                */
                struct RRIterator {
                    bytes data;
                    uint offset;
                    uint16 dnstype;
                    uint16 class;
                    uint32 ttl;
                    uint rdataOffset;
                    uint nextOffset;
                }
            
                /**
                * @dev Begins iterating over resource records.
                * @param self The byte string to read from.
                * @param offset The offset to start reading at.
                * @return An iterator object.
                */
                function iterateRRs(bytes memory self, uint offset) internal pure returns (RRIterator memory ret) {
                    ret.data = self;
                    ret.nextOffset = offset;
                    next(ret);
                }
            
                /**
                * @dev Returns true iff there are more RRs to iterate.
                * @param iter The iterator to check.
                * @return True iff the iterator has finished.
                */
                function done(RRIterator memory iter) internal pure returns(bool) {
                    return iter.offset >= iter.data.length;
                }
            
                /**
                * @dev Moves the iterator to the next resource record.
                * @param iter The iterator to advance.
                */
                function next(RRIterator memory iter) internal pure {
                    iter.offset = iter.nextOffset;
                    if (iter.offset >= iter.data.length) {
                        return;
                    }
            
                    // Skip the name
                    uint off = iter.offset + nameLength(iter.data, iter.offset);
            
                    // Read type, class, and ttl
                    iter.dnstype = iter.data.readUint16(off);
                    off += 2;
                    iter.class = iter.data.readUint16(off);
                    off += 2;
                    iter.ttl = iter.data.readUint32(off);
                    off += 4;
            
                    // Read the rdata
                    uint rdataLength = iter.data.readUint16(off);
                    off += 2;
                    iter.rdataOffset = off;
                    iter.nextOffset = off + rdataLength;
                }
            
                /**
                * @dev Returns the name of the current record.
                * @param iter The iterator.
                * @return A new bytes object containing the owner name from the RR.
                */
                function name(RRIterator memory iter) internal pure returns(bytes memory) {
                    return iter.data.substring(iter.offset, nameLength(iter.data, iter.offset));
                }
            
                /**
                * @dev Returns the rdata portion of the current record.
                * @param iter The iterator.
                * @return A new bytes object containing the RR's RDATA.
                */
                function rdata(RRIterator memory iter) internal pure returns(bytes memory) {
                    return iter.data.substring(iter.rdataOffset, iter.nextOffset - iter.rdataOffset);
                }
            
                /**
                * @dev Checks if a given RR type exists in a type bitmap.
                * @param self The byte string to read the type bitmap from.
                * @param offset The offset to start reading at.
                * @param rrtype The RR type to check for.
                * @return True if the type is found in the bitmap, false otherwise.
                */
                function checkTypeBitmap(bytes memory self, uint offset, uint16 rrtype) internal pure returns (bool) {
                    uint8 typeWindow = uint8(rrtype >> 8);
                    uint8 windowByte = uint8((rrtype & 0xff) / 8);
                    uint8 windowBitmask = uint8(uint8(1) << (uint8(7) - uint8(rrtype & 0x7)));
                    for (uint off = offset; off < self.length;) {
                        uint8 window = self.readUint8(off);
                        uint8 len = self.readUint8(off + 1);
                        if (typeWindow < window) {
                            // We've gone past our window; it's not here.
                            return false;
                        } else if (typeWindow == window) {
                            // Check this type bitmap
                            if (len * 8 <= windowByte) {
                                // Our type is past the end of the bitmap
                                return false;
                            }
                            return (self.readUint8(off + windowByte + 2) & windowBitmask) != 0;
                        } else {
                            // Skip this type bitmap
                            off += len + 2;
                        }
                    }
            
                    return false;
                }
            
                function compareNames(bytes memory self, bytes memory other) internal pure returns (int) {
                    if (self.equals(other)) {
                        return 0;
                    }
            
                    uint off;
                    uint otheroff;
                    uint prevoff;
                    uint otherprevoff;
                    uint counts = labelCount(self, 0);
                    uint othercounts = labelCount(other, 0);
            
                    // Keep removing labels from the front of the name until both names are equal length
                    while (counts > othercounts) {
                        prevoff = off;
                        off = progress(self, off);
                        counts--;
                    }
            
                    while (othercounts > counts) {
                        otherprevoff = otheroff;
                        otheroff = progress(other, otheroff);
                        othercounts--;
                    }
            
                    // Compare the last nonequal labels to each other
                    while (counts > 0 && !self.equals(off, other, otheroff)) {
                        prevoff = off;
                        off = progress(self, off);
                        otherprevoff = otheroff;
                        otheroff = progress(other, otheroff);
                        counts -= 1;
                    }
            
                    if (off == 0) {
                        return -1;
                    }
                    if(otheroff == 0) {
                        return 1;
                    }
            
                    return self.compare(prevoff + 1, self.readUint8(prevoff), other, otherprevoff + 1, other.readUint8(otherprevoff));
                }
            
                function progress(bytes memory body, uint off) internal pure returns(uint) {
                    return off + 1 + body.readUint8(off);
                }
            }
            
            // File: contracts/profiles/DNSResolver.sol
            
            pragma solidity ^0.5.0;
            
            
            
            contract DNSResolver is ResolverBase {
                using RRUtils for *;
                using BytesUtils for bytes;
            
                bytes4 constant private DNS_RECORD_INTERFACE_ID = 0xa8fa5682;
            
                // DNSRecordChanged is emitted whenever a given node/name/resource's RRSET is updated.
                event DNSRecordChanged(bytes32 indexed node, bytes name, uint16 resource, bytes record);
                // DNSRecordDeleted is emitted whenever a given node/name/resource's RRSET is deleted.
                event DNSRecordDeleted(bytes32 indexed node, bytes name, uint16 resource);
                // DNSZoneCleared is emitted whenever a given node's zone information is cleared.
                event DNSZoneCleared(bytes32 indexed node);
            
                // Version the mapping for each zone.  This allows users who have lost
                // track of their entries to effectively delete an entire zone by bumping
                // the version number.
                // node => version
                mapping(bytes32=>uint256) private versions;
            
                // The records themselves.  Stored as binary RRSETs
                // node => version => name => resource => data
                mapping(bytes32=>mapping(uint256=>mapping(bytes32=>mapping(uint16=>bytes)))) private records;
            
                // Count of number of entries for a given name.  Required for DNS resolvers
                // when resolving wildcards.
                // node => version => name => number of records
                mapping(bytes32=>mapping(uint256=>mapping(bytes32=>uint16))) private nameEntriesCount;
            
                /**
                 * Set one or more DNS records.  Records are supplied in wire-format.
                 * Records with the same node/name/resource must be supplied one after the
                 * other to ensure the data is updated correctly. For example, if the data
                 * was supplied:
                 *     a.example.com IN A 1.2.3.4
                 *     a.example.com IN A 5.6.7.8
                 *     www.example.com IN CNAME a.example.com.
                 * then this would store the two A records for a.example.com correctly as a
                 * single RRSET, however if the data was supplied:
                 *     a.example.com IN A 1.2.3.4
                 *     www.example.com IN CNAME a.example.com.
                 *     a.example.com IN A 5.6.7.8
                 * then this would store the first A record, the CNAME, then the second A
                 * record which would overwrite the first.
                 *
                 * @param node the namehash of the node for which to set the records
                 * @param data the DNS wire format records to set
                 */
                function setDNSRecords(bytes32 node, bytes calldata data) external authorised(node) {
                    uint16 resource = 0;
                    uint256 offset = 0;
                    bytes memory name;
                    bytes memory value;
                    bytes32 nameHash;
                    // Iterate over the data to add the resource records
                    for (RRUtils.RRIterator memory iter = data.iterateRRs(0); !iter.done(); iter.next()) {
                        if (resource == 0) {
                            resource = iter.dnstype;
                            name = iter.name();
                            nameHash = keccak256(abi.encodePacked(name));
                            value = bytes(iter.rdata());
                        } else {
                            bytes memory newName = iter.name();
                            if (resource != iter.dnstype || !name.equals(newName)) {
                                setDNSRRSet(node, name, resource, data, offset, iter.offset - offset, value.length == 0);
                                resource = iter.dnstype;
                                offset = iter.offset;
                                name = newName;
                                nameHash = keccak256(name);
                                value = bytes(iter.rdata());
                            }
                        }
                    }
                    if (name.length > 0) {
                        setDNSRRSet(node, name, resource, data, offset, data.length - offset, value.length == 0);
                    }
                }
            
                /**
                 * Obtain a DNS record.
                 * @param node the namehash of the node for which to fetch the record
                 * @param name the keccak-256 hash of the fully-qualified name for which to fetch the record
                 * @param resource the ID of the resource as per https://en.wikipedia.org/wiki/List_of_DNS_record_types
                 * @return the DNS record in wire format if present, otherwise empty
                 */
                function dnsRecord(bytes32 node, bytes32 name, uint16 resource) public view returns (bytes memory) {
                    return records[node][versions[node]][name][resource];
                }
            
                /**
                 * Check if a given node has records.
                 * @param node the namehash of the node for which to check the records
                 * @param name the namehash of the node for which to check the records
                 */
                function hasDNSRecords(bytes32 node, bytes32 name) public view returns (bool) {
                    return (nameEntriesCount[node][versions[node]][name] != 0);
                }
            
                /**
                 * Clear all information for a DNS zone.
                 * @param node the namehash of the node for which to clear the zone
                 */
                function clearDNSZone(bytes32 node) public authorised(node) {
                    versions[node]++;
                    emit DNSZoneCleared(node);
                }
            
                function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                    return interfaceID == DNS_RECORD_INTERFACE_ID || super.supportsInterface(interfaceID);
                }
            
                function setDNSRRSet(
                    bytes32 node,
                    bytes memory name,
                    uint16 resource,
                    bytes memory data,
                    uint256 offset,
                    uint256 size,
                    bool deleteRecord) private
                {
                    uint256 version = versions[node];
                    bytes32 nameHash = keccak256(name);
                    bytes memory rrData = data.substring(offset, size);
                    if (deleteRecord) {
                        if (records[node][version][nameHash][resource].length != 0) {
                            nameEntriesCount[node][version][nameHash]--;
                        }
                        delete(records[node][version][nameHash][resource]);
                        emit DNSRecordDeleted(node, name, resource);
                    } else {
                        if (records[node][version][nameHash][resource].length == 0) {
                            nameEntriesCount[node][version][nameHash]++;
                        }
                        records[node][version][nameHash][resource] = rrData;
                        emit DNSRecordChanged(node, name, resource, rrData);
                    }
                }
            }
            
            // File: contracts/profiles/InterfaceResolver.sol
            
            pragma solidity ^0.5.0;
            
            
            
            contract InterfaceResolver is ResolverBase, AddrResolver {
                bytes4 constant private INTERFACE_INTERFACE_ID = bytes4(keccak256("interfaceImplementer(bytes32,bytes4)"));
                bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;
            
                event InterfaceChanged(bytes32 indexed node, bytes4 indexed interfaceID, address implementer);
            
                mapping(bytes32=>mapping(bytes4=>address)) interfaces;
            
                /**
                 * Sets an interface associated with a name.
                 * Setting the address to 0 restores the default behaviour of querying the contract at `addr()` for interface support.
                 * @param node The node to update.
                 * @param interfaceID The EIP 168 interface ID.
                 * @param implementer The address of a contract that implements this interface for this node.
                 */
                function setInterface(bytes32 node, bytes4 interfaceID, address implementer) external authorised(node) {
                    interfaces[node][interfaceID] = implementer;
                    emit InterfaceChanged(node, interfaceID, implementer);
                }
            
                /**
                 * Returns the address of a contract that implements the specified interface for this name.
                 * If an implementer has not been set for this interfaceID and name, the resolver will query
                 * the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that
                 * contract implements EIP168 and returns `true` for the specified interfaceID, its address
                 * will be returned.
                 * @param node The ENS node to query.
                 * @param interfaceID The EIP 168 interface ID to check for.
                 * @return The address that implements this interface, or 0 if the interface is unsupported.
                 */
                function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address) {
                    address implementer = interfaces[node][interfaceID];
                    if(implementer != address(0)) {
                        return implementer;
                    }
            
                    address a = addr(node);
                    if(a == address(0)) {
                        return address(0);
                    }
            
                    (bool success, bytes memory returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", INTERFACE_META_ID));
                    if(!success || returnData.length < 32 || returnData[31] == 0) {
                        // EIP 168 not supported by target
                        return address(0);
                    }
            
                    (success, returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", interfaceID));
                    if(!success || returnData.length < 32 || returnData[31] == 0) {
                        // Specified interface not supported by target
                        return address(0);
                    }
            
                    return a;
                }
            
                function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                    return interfaceID == INTERFACE_INTERFACE_ID || super.supportsInterface(interfaceID);
                }
            }
            
            // File: contracts/profiles/NameResolver.sol
            
            pragma solidity ^0.5.0;
            
            
            contract NameResolver is ResolverBase {
                bytes4 constant private NAME_INTERFACE_ID = 0x691f3431;
            
                event NameChanged(bytes32 indexed node, string name);
            
                mapping(bytes32=>string) names;
            
                /**
                 * Sets the name associated with an ENS node, for reverse records.
                 * May only be called by the owner of that node in the ENS registry.
                 * @param node The node to update.
                 * @param name The name to set.
                 */
                function setName(bytes32 node, string calldata name) external authorised(node) {
                    names[node] = name;
                    emit NameChanged(node, name);
                }
            
                /**
                 * Returns the name associated with an ENS node, for reverse records.
                 * Defined in EIP181.
                 * @param node The ENS node to query.
                 * @return The associated name.
                 */
                function name(bytes32 node) external view returns (string memory) {
                    return names[node];
                }
            
                function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                    return interfaceID == NAME_INTERFACE_ID || super.supportsInterface(interfaceID);
                }
            }
            
            // File: contracts/profiles/PubkeyResolver.sol
            
            pragma solidity ^0.5.0;
            
            
            contract PubkeyResolver is ResolverBase {
                bytes4 constant private PUBKEY_INTERFACE_ID = 0xc8690233;
            
                event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
            
                struct PublicKey {
                    bytes32 x;
                    bytes32 y;
                }
            
                mapping(bytes32=>PublicKey) pubkeys;
            
                /**
                 * Sets the SECP256k1 public key associated with an ENS node.
                 * @param node The ENS node to query
                 * @param x the X coordinate of the curve point for the public key.
                 * @param y the Y coordinate of the curve point for the public key.
                 */
                function setPubkey(bytes32 node, bytes32 x, bytes32 y) external authorised(node) {
                    pubkeys[node] = PublicKey(x, y);
                    emit PubkeyChanged(node, x, y);
                }
            
                /**
                 * Returns the SECP256k1 public key associated with an ENS node.
                 * Defined in EIP 619.
                 * @param node The ENS node to query
                 * @return x, y the X and Y coordinates of the curve point for the public key.
                 */
                function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y) {
                    return (pubkeys[node].x, pubkeys[node].y);
                }
            
                function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                    return interfaceID == PUBKEY_INTERFACE_ID || super.supportsInterface(interfaceID);
                }
            }
            
            // File: contracts/profiles/TextResolver.sol
            
            pragma solidity ^0.5.0;
            
            
            contract TextResolver is ResolverBase {
                bytes4 constant private TEXT_INTERFACE_ID = 0x59d1d43c;
            
                event TextChanged(bytes32 indexed node, string indexed indexedKey, string key);
            
                mapping(bytes32=>mapping(string=>string)) texts;
            
                /**
                 * Sets the text data associated with an ENS node and key.
                 * May only be called by the owner of that node in the ENS registry.
                 * @param node The node to update.
                 * @param key The key to set.
                 * @param value The text data value to set.
                 */
                function setText(bytes32 node, string calldata key, string calldata value) external authorised(node) {
                    texts[node][key] = value;
                    emit TextChanged(node, key, key);
                }
            
                /**
                 * Returns the text data associated with an ENS node and key.
                 * @param node The ENS node to query.
                 * @param key The text data key to query.
                 * @return The associated text data.
                 */
                function text(bytes32 node, string calldata key) external view returns (string memory) {
                    return texts[node][key];
                }
            
                function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                    return interfaceID == TEXT_INTERFACE_ID || super.supportsInterface(interfaceID);
                }
            }
            
            // File: contracts/PublicResolver.sol
            
            pragma solidity ^0.5.0;
            pragma experimental ABIEncoderV2;
            
            
            
            
            
            
            
            
            
            
            /**
             * A simple resolver anyone can use; only allows the owner of a node to set its
             * address.
             */
            contract PublicResolver is ABIResolver, AddrResolver, ContentHashResolver, DNSResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver {
                ENS ens;
            
                /**
                 * A mapping of authorisations. An address that is authorised for a name
                 * may make any changes to the name that the owner could, but may not update
                 * the set of authorisations.
                 * (node, owner, caller) => isAuthorised
                 */
                mapping(bytes32=>mapping(address=>mapping(address=>bool))) public authorisations;
            
                event AuthorisationChanged(bytes32 indexed node, address indexed owner, address indexed target, bool isAuthorised);
            
                constructor(ENS _ens) public {
                    ens = _ens;
                }
            
                /**
                 * @dev Sets or clears an authorisation.
                 * Authorisations are specific to the caller. Any account can set an authorisation
                 * for any name, but the authorisation that is checked will be that of the
                 * current owner of a name. Thus, transferring a name effectively clears any
                 * existing authorisations, and new authorisations can be set in advance of
                 * an ownership transfer if desired.
                 *
                 * @param node The name to change the authorisation on.
                 * @param target The address that is to be authorised or deauthorised.
                 * @param isAuthorised True if the address should be authorised, or false if it should be deauthorised.
                 */
                function setAuthorisation(bytes32 node, address target, bool isAuthorised) external {
                    authorisations[node][msg.sender][target] = isAuthorised;
                    emit AuthorisationChanged(node, msg.sender, target, isAuthorised);
                }
            
                function isAuthorised(bytes32 node) internal view returns(bool) {
                    address owner = ens.owner(node);
                    return owner == msg.sender || authorisations[node][owner][msg.sender];
                }
            
                function multicall(bytes[] calldata data) external returns(bytes[] memory results) {
                    results = new bytes[](data.length);
                    for(uint i = 0; i < data.length; i++) {
                        (bool success, bytes memory result) = address(this).delegatecall(data[i]);
                        require(success);
                        results[i] = result;
                    }
                    return results;
                }
            }

            File 5 of 6: LinearPremiumPriceOracle
            // File: contracts/SafeMath.sol
            
            pragma solidity >=0.4.24;
            
            /**
             * @title SafeMath
             * @dev Unsigned math operations with safety checks that revert on error
             */
            library SafeMath {
                /**
                * @dev Multiplies two unsigned integers, reverts on overflow.
                */
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                    // benefit is lost if 'b' is also tested.
                    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                    if (a == 0) {
                        return 0;
                    }
            
                    uint256 c = a * b;
                    require(c / a == b);
            
                    return c;
                }
            
                /**
                * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                */
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Solidity only automatically asserts when dividing by 0
                    require(b > 0);
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            
                    return c;
                }
            
                /**
                * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                */
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b <= a);
                    uint256 c = a - b;
            
                    return c;
                }
            
                /**
                * @dev Adds two unsigned integers, reverts on overflow.
                */
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    require(c >= a);
            
                    return c;
                }
            
                /**
                * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                * reverts when dividing by zero.
                */
                function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b != 0);
                    return a % b;
                }
            }
            
            // File: contracts/PriceOracle.sol
            
            pragma solidity >=0.4.24;
            
            interface PriceOracle {
                /**
                 * @dev Returns the price to register or renew a name.
                 * @param name The name being registered or renewed.
                 * @param expires When the name presently expires (0 if this is a new registration).
                 * @param duration How long the name is being registered or extended for, in seconds.
                 * @return The price of this renewal or registration, in wei.
                 */
                function price(string calldata name, uint expires, uint duration) external view returns(uint);
            }
            
            // File: contracts/StringUtils.sol
            
            pragma solidity >=0.4.24;
            
            library StringUtils {
                /**
                 * @dev Returns the length of a given string
                 *
                 * @param s The string to measure the length of
                 * @return The length of the input string
                 */
                function strlen(string memory s) internal pure returns (uint) {
                    uint len;
                    uint i = 0;
                    uint bytelength = bytes(s).length;
                    for(len = 0; i < bytelength; len++) {
                        byte b = bytes(s)[i];
                        if(b < 0x80) {
                            i += 1;
                        } else if (b < 0xE0) {
                            i += 2;
                        } else if (b < 0xF0) {
                            i += 3;
                        } else if (b < 0xF8) {
                            i += 4;
                        } else if (b < 0xFC) {
                            i += 5;
                        } else {
                            i += 6;
                        }
                    }
                    return len;
                }
            }
            
            // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title Ownable
             * @dev The Ownable contract has an owner address, and provides basic authorization control
             * functions, this simplifies the implementation of "user permissions".
             */
            contract Ownable {
                address private _owner;
            
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            
                /**
                 * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                 * account.
                 */
                constructor () internal {
                    _owner = msg.sender;
                    emit OwnershipTransferred(address(0), _owner);
                }
            
                /**
                 * @return the address of the owner.
                 */
                function owner() public view returns (address) {
                    return _owner;
                }
            
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    require(isOwner());
                    _;
                }
            
                /**
                 * @return true if `msg.sender` is the owner of the contract.
                 */
                function isOwner() public view returns (bool) {
                    return msg.sender == _owner;
                }
            
                /**
                 * @dev Allows the current owner to relinquish control of the contract.
                 * @notice Renouncing to ownership will leave the contract without an owner.
                 * It will not be possible to call the functions with the `onlyOwner`
                 * modifier anymore.
                 */
                function renounceOwnership() public onlyOwner {
                    emit OwnershipTransferred(_owner, address(0));
                    _owner = address(0);
                }
            
                /**
                 * @dev Allows the current owner to transfer control of the contract to a newOwner.
                 * @param newOwner The address to transfer ownership to.
                 */
                function transferOwnership(address newOwner) public onlyOwner {
                    _transferOwnership(newOwner);
                }
            
                /**
                 * @dev Transfers control of the contract to a newOwner.
                 * @param newOwner The address to transfer ownership to.
                 */
                function _transferOwnership(address newOwner) internal {
                    require(newOwner != address(0));
                    emit OwnershipTransferred(_owner, newOwner);
                    _owner = newOwner;
                }
            }
            
            // File: contracts/StablePriceOracle.sol
            
            pragma solidity >=0.5.0;
            
            
            
            
            
            interface AggregatorInterface {
              function latestAnswer() external view returns (int256);
            }
            
            
            // StablePriceOracle sets a price in USD, based on an oracle.
            contract StablePriceOracle is Ownable, PriceOracle {
                using SafeMath for *;
                using StringUtils for *;
            
                // Rent in base price units by length. Element 0 is for 1-length names, and so on.
                uint[] public rentPrices;
            
                // Oracle address
                AggregatorInterface public usdOracle;
            
                event OracleChanged(address oracle);
            
                event RentPriceChanged(uint[] prices);
            
                bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
                bytes4 constant private ORACLE_ID = bytes4(keccak256("price(string,uint256,uint256)") ^ keccak256("premium(string,uint256,uint256)"));
            
                constructor(AggregatorInterface _usdOracle, uint[] memory _rentPrices) public {
                    usdOracle = _usdOracle;
                    setPrices(_rentPrices);
                }
            
                function price(string calldata name, uint expires, uint duration) external view returns(uint) {
                    uint len = name.strlen();
                    if(len > rentPrices.length) {
                        len = rentPrices.length;
                    }
                    require(len > 0);
                    
                    uint basePrice = rentPrices[len - 1].mul(duration);
                    basePrice = basePrice.add(_premium(name, expires, duration));
            
                    return attoUSDToWei(basePrice);
                }
            
                /**
                 * @dev Sets rent prices.
                 * @param _rentPrices The price array. Each element corresponds to a specific
                 *                    name length; names longer than the length of the array
                 *                    default to the price of the last element. Values are
                 *                    in base price units, equal to one attodollar (1e-18
                 *                    dollar) each.
                 */
                function setPrices(uint[] memory _rentPrices) public onlyOwner {
                    rentPrices = _rentPrices;
                    emit RentPriceChanged(_rentPrices);
                }
            
                /**
                 * @dev Sets the price oracle address
                 * @param _usdOracle The address of the price oracle to use.
                 */
                function setOracle(AggregatorInterface _usdOracle) public onlyOwner {
                    usdOracle = _usdOracle;
                    emit OracleChanged(address(_usdOracle));
                }
            
                /**
                 * @dev Returns the pricing premium in wei.
                 */
                function premium(string calldata name, uint expires, uint duration) external view returns(uint) {
                    return attoUSDToWei(_premium(name, expires, duration));
                }
            
                /**
                 * @dev Returns the pricing premium in internal base units.
                 */
                function _premium(string memory name, uint expires, uint duration) internal view returns(uint) {
                    return 0;
                }
            
                function attoUSDToWei(uint amount) internal view returns(uint) {
                    uint ethPrice = uint(usdOracle.latestAnswer());
                    return amount.mul(1e8).div(ethPrice);
                }
            
                function weiToAttoUSD(uint amount) internal view returns(uint) {
                    uint ethPrice = uint(usdOracle.latestAnswer());
                    return amount.mul(ethPrice).div(1e8);
                }
            
                function supportsInterface(bytes4 interfaceID) public view returns (bool) {
                    return interfaceID == INTERFACE_META_ID || interfaceID == ORACLE_ID;
                }
            }
            
            // File: contracts/LinearPremiumPriceOracle.sol
            
            pragma solidity >=0.5.0;
            
            
            
            contract LinearPremiumPriceOracle is StablePriceOracle {
                using SafeMath for *;
            
                uint GRACE_PERIOD = 90 days;
            
                uint public initialPremium;
                uint public premiumDecreaseRate;
            
                bytes4 constant private TIME_UNTIL_PREMIUM_ID = bytes4(keccak256("timeUntilPremium(uint,uint"));
            
                constructor(AggregatorInterface _usdOracle, uint[] memory _rentPrices, uint _initialPremium, uint _premiumDecreaseRate) public
                    StablePriceOracle(_usdOracle, _rentPrices)
                {
                    initialPremium = _initialPremium;
                    premiumDecreaseRate = _premiumDecreaseRate;
                }
            
                function _premium(string memory name, uint expires, uint /*duration*/) internal view returns(uint) {
                    expires = expires.add(GRACE_PERIOD);
                    if(expires > now) {
                        // No premium for renewals
                        return 0;
                    }
            
                    // Calculate the discount off the maximum premium
                    uint discount = premiumDecreaseRate.mul(now.sub(expires));
            
                    // If we've run out the premium period, return 0.
                    if(discount > initialPremium) {
                        return 0;
                    }
                    
                    return initialPremium - discount;
                }
            
                /**
                 * @dev Returns the timestamp at which a name with the specified expiry date will have
                 *      the specified re-registration price premium.
                 * @param expires The timestamp at which the name expires.
                 * @param amount The amount, in wei, the caller is willing to pay
                 * @return The timestamp at which the premium for this domain will be `amount`.
                 */
                function timeUntilPremium(uint expires, uint amount) external view returns(uint) {
                    amount = weiToAttoUSD(amount);
                    require(amount <= initialPremium);
            
                    expires = expires.add(GRACE_PERIOD);
            
                    uint discount = initialPremium.sub(amount);
                    uint duration = discount.div(premiumDecreaseRate);
                    return expires.add(duration);
                }
            
                function supportsInterface(bytes4 interfaceID) public view returns (bool) {
                    return (interfaceID == TIME_UNTIL_PREMIUM_ID) || super.supportsInterface(interfaceID);
                }
            }

            File 6 of 6: Aggregator
            /**
            * @dev A library for working with mutable byte buffers in Solidity.
            *
            * Byte buffers are mutable and expandable, and provide a variety of primitives
            * for writing to them. At any time you can fetch a bytes object containing the
            * current contents of the buffer. The bytes object should not be stored between
            * operations, as it may change due to resizing of the buffer.
            */
            library Buffer {
              /**
              * @dev Represents a mutable buffer. Buffers have a current value (buf) and
              *      a capacity. The capacity may be longer than the current value, in
              *      which case it can be extended without the need to allocate more memory.
              */
              struct buffer {
                bytes buf;
                uint capacity;
              }
            
              /**
              * @dev Initializes a buffer with an initial capacity.
              * @param buf The buffer to initialize.
              * @param capacity The number of bytes of space to allocate the buffer.
              * @return The buffer, for chaining.
              */
              function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
                if (capacity % 32 != 0) {
                  capacity += 32 - (capacity % 32);
                }
                // Allocate space for the buffer data
                buf.capacity = capacity;
                assembly {
                  let ptr := mload(0x40)
                  mstore(buf, ptr)
                  mstore(ptr, 0)
                  mstore(0x40, add(32, add(ptr, capacity)))
                }
                return buf;
              }
            
              /**
              * @dev Initializes a new buffer from an existing bytes object.
              *      Changes to the buffer may mutate the original value.
              * @param b The bytes object to initialize the buffer with.
              * @return A new buffer.
              */
              function fromBytes(bytes memory b) internal pure returns(buffer memory) {
                buffer memory buf;
                buf.buf = b;
                buf.capacity = b.length;
                return buf;
              }
            
              function resize(buffer memory buf, uint capacity) private pure {
                bytes memory oldbuf = buf.buf;
                init(buf, capacity);
                append(buf, oldbuf);
              }
            
              function max(uint a, uint b) private pure returns(uint) {
                if (a > b) {
                  return a;
                }
                return b;
              }
            
              /**
              * @dev Sets buffer length to 0.
              * @param buf The buffer to truncate.
              * @return The original buffer, for chaining..
              */
              function truncate(buffer memory buf) internal pure returns (buffer memory) {
                assembly {
                  let bufptr := mload(buf)
                  mstore(bufptr, 0)
                }
                return buf;
              }
            
              /**
              * @dev Writes a byte string to a buffer. Resizes if doing so would exceed
              *      the capacity of the buffer.
              * @param buf The buffer to append to.
              * @param off The start offset to write to.
              * @param data The data to append.
              * @param len The number of bytes to copy.
              * @return The original buffer, for chaining.
              */
              function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) {
                require(len <= data.length);
            
                if (off + len > buf.capacity) {
                  resize(buf, max(buf.capacity, len + off) * 2);
                }
            
                uint dest;
                uint src;
                assembly {
                  // Memory address of the buffer data
                  let bufptr := mload(buf)
                  // Length of existing buffer data
                  let buflen := mload(bufptr)
                  // Start address = buffer address + offset + sizeof(buffer length)
                  dest := add(add(bufptr, 32), off)
                  // Update buffer length if we're extending it
                  if gt(add(len, off), buflen) {
                    mstore(bufptr, add(len, off))
                  }
                  src := add(data, 32)
                }
            
                // Copy word-length chunks while possible
                for (; len >= 32; len -= 32) {
                  assembly {
                    mstore(dest, mload(src))
                  }
                  dest += 32;
                  src += 32;
                }
            
                // Copy remaining bytes
                uint mask = 256 ** (32 - len) - 1;
                assembly {
                  let srcpart := and(mload(src), not(mask))
                  let destpart := and(mload(dest), mask)
                  mstore(dest, or(destpart, srcpart))
                }
            
                return buf;
              }
            
              /**
              * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
              *      the capacity of the buffer.
              * @param buf The buffer to append to.
              * @param data The data to append.
              * @param len The number of bytes to copy.
              * @return The original buffer, for chaining.
              */
              function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) {
                return write(buf, buf.buf.length, data, len);
              }
            
              /**
              * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
              *      the capacity of the buffer.
              * @param buf The buffer to append to.
              * @param data The data to append.
              * @return The original buffer, for chaining.
              */
              function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
                return write(buf, buf.buf.length, data, data.length);
              }
            
              /**
              * @dev Writes a byte to the buffer. Resizes if doing so would exceed the
              *      capacity of the buffer.
              * @param buf The buffer to append to.
              * @param off The offset to write the byte at.
              * @param data The data to append.
              * @return The original buffer, for chaining.
              */
              function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) {
                if (off >= buf.capacity) {
                  resize(buf, buf.capacity * 2);
                }
            
                assembly {
                  // Memory address of the buffer data
                  let bufptr := mload(buf)
                  // Length of existing buffer data
                  let buflen := mload(bufptr)
                  // Address = buffer address + sizeof(buffer length) + off
                  let dest := add(add(bufptr, off), 32)
                  mstore8(dest, data)
                  // Update buffer length if we extended it
                  if eq(off, buflen) {
                    mstore(bufptr, add(buflen, 1))
                  }
                }
                return buf;
              }
            
              /**
              * @dev Appends a byte to the buffer. Resizes if doing so would exceed the
              *      capacity of the buffer.
              * @param buf The buffer to append to.
              * @param data The data to append.
              * @return The original buffer, for chaining.
              */
              function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {
                return writeUint8(buf, buf.buf.length, data);
              }
            
              /**
              * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would
              *      exceed the capacity of the buffer.
              * @param buf The buffer to append to.
              * @param off The offset to write at.
              * @param data The data to append.
              * @param len The number of bytes to write (left-aligned).
              * @return The original buffer, for chaining.
              */
              function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) {
                if (len + off > buf.capacity) {
                  resize(buf, (len + off) * 2);
                }
            
                uint mask = 256 ** len - 1;
                // Right-align data
                data = data >> (8 * (32 - len));
                assembly {
                  // Memory address of the buffer data
                  let bufptr := mload(buf)
                  // Address = buffer address + sizeof(buffer length) + off + len
                  let dest := add(add(bufptr, off), len)
                  mstore(dest, or(and(mload(dest), not(mask)), data))
                  // Update buffer length if we extended it
                  if gt(add(off, len), mload(bufptr)) {
                    mstore(bufptr, add(off, len))
                  }
                }
                return buf;
              }
            
              /**
              * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the
              *      capacity of the buffer.
              * @param buf The buffer to append to.
              * @param off The offset to write at.
              * @param data The data to append.
              * @return The original buffer, for chaining.
              */
              function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) {
                return write(buf, off, bytes32(data), 20);
              }
            
              /**
              * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
              *      the capacity of the buffer.
              * @param buf The buffer to append to.
              * @param data The data to append.
              * @return The original buffer, for chhaining.
              */
              function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
                return write(buf, buf.buf.length, bytes32(data), 20);
              }
            
              /**
              * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
              *      the capacity of the buffer.
              * @param buf The buffer to append to.
              * @param data The data to append.
              * @return The original buffer, for chaining.
              */
              function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
                return write(buf, buf.buf.length, data, 32);
              }
            
              /**
              * @dev Writes an integer to the buffer. Resizes if doing so would exceed
              *      the capacity of the buffer.
              * @param buf The buffer to append to.
              * @param off The offset to write at.
              * @param data The data to append.
              * @param len The number of bytes to write (right-aligned).
              * @return The original buffer, for chaining.
              */
              function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) {
                if (len + off > buf.capacity) {
                  resize(buf, (len + off) * 2);
                }
            
                uint mask = 256 ** len - 1;
                assembly {
                  // Memory address of the buffer data
                  let bufptr := mload(buf)
                  // Address = buffer address + off + sizeof(buffer length) + len
                  let dest := add(add(bufptr, off), len)
                  mstore(dest, or(and(mload(dest), not(mask)), data))
                  // Update buffer length if we extended it
                  if gt(add(off, len), mload(bufptr)) {
                    mstore(bufptr, add(off, len))
                  }
                }
                return buf;
              }
            
              /**
               * @dev Appends a byte to the end of the buffer. Resizes if doing so would
               * exceed the capacity of the buffer.
               * @param buf The buffer to append to.
               * @param data The data to append.
               * @return The original buffer.
               */
              function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
                return writeInt(buf, buf.buf.length, data, len);
              }
            }
            
            library CBOR {
              using Buffer for Buffer.buffer;
            
              uint8 private constant MAJOR_TYPE_INT = 0;
              uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
              uint8 private constant MAJOR_TYPE_BYTES = 2;
              uint8 private constant MAJOR_TYPE_STRING = 3;
              uint8 private constant MAJOR_TYPE_ARRAY = 4;
              uint8 private constant MAJOR_TYPE_MAP = 5;
              uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;
            
              function encodeType(Buffer.buffer memory buf, uint8 major, uint value) private pure {
                if(value <= 23) {
                  buf.appendUint8(uint8((major << 5) | value));
                } else if(value <= 0xFF) {
                  buf.appendUint8(uint8((major << 5) | 24));
                  buf.appendInt(value, 1);
                } else if(value <= 0xFFFF) {
                  buf.appendUint8(uint8((major << 5) | 25));
                  buf.appendInt(value, 2);
                } else if(value <= 0xFFFFFFFF) {
                  buf.appendUint8(uint8((major << 5) | 26));
                  buf.appendInt(value, 4);
                } else if(value <= 0xFFFFFFFFFFFFFFFF) {
                  buf.appendUint8(uint8((major << 5) | 27));
                  buf.appendInt(value, 8);
                }
              }
            
              function encodeIndefiniteLengthType(Buffer.buffer memory buf, uint8 major) private pure {
                buf.appendUint8(uint8((major << 5) | 31));
              }
            
              function encodeUInt(Buffer.buffer memory buf, uint value) internal pure {
                encodeType(buf, MAJOR_TYPE_INT, value);
              }
            
              function encodeInt(Buffer.buffer memory buf, int value) internal pure {
                if(value >= 0) {
                  encodeType(buf, MAJOR_TYPE_INT, uint(value));
                } else {
                  encodeType(buf, MAJOR_TYPE_NEGATIVE_INT, uint(-1 - value));
                }
              }
            
              function encodeBytes(Buffer.buffer memory buf, bytes value) internal pure {
                encodeType(buf, MAJOR_TYPE_BYTES, value.length);
                buf.append(value);
              }
            
              function encodeString(Buffer.buffer memory buf, string value) internal pure {
                encodeType(buf, MAJOR_TYPE_STRING, bytes(value).length);
                buf.append(bytes(value));
              }
            
              function startArray(Buffer.buffer memory buf) internal pure {
                encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
              }
            
              function startMap(Buffer.buffer memory buf) internal pure {
                encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
              }
            
              function endSequence(Buffer.buffer memory buf) internal pure {
                encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
              }
            }
            
            /**
             * @title Library for common Chainlink functions
             * @dev Uses imported CBOR library for encoding to buffer
             */
            library Chainlink {
              uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase
            
              using CBOR for Buffer.buffer;
            
              struct Request {
                bytes32 id;
                address callbackAddress;
                bytes4 callbackFunctionId;
                uint256 nonce;
                Buffer.buffer buf;
              }
            
              /**
               * @notice Initializes a Chainlink request
               * @dev Sets the ID, callback address, and callback function signature on the request
               * @param self The uninitialized request
               * @param _id The Job Specification ID
               * @param _callbackAddress The callback address
               * @param _callbackFunction The callback function signature
               * @return The initialized request
               */
              function initialize(
                Request memory self,
                bytes32 _id,
                address _callbackAddress,
                bytes4 _callbackFunction
              ) internal pure returns (Chainlink.Request memory) {
                Buffer.init(self.buf, defaultBufferSize);
                self.id = _id;
                self.callbackAddress = _callbackAddress;
                self.callbackFunctionId = _callbackFunction;
                return self;
              }
            
              /**
               * @notice Sets the data for the buffer without encoding CBOR on-chain
               * @dev CBOR can be closed with curly-brackets {} or they can be left off
               * @param self The initialized request
               * @param _data The CBOR data
               */
              function setBuffer(Request memory self, bytes _data)
                internal pure
              {
                Buffer.init(self.buf, _data.length);
                Buffer.append(self.buf, _data);
              }
            
              /**
               * @notice Adds a string value to the request with a given key name
               * @param self The initialized request
               * @param _key The name of the key
               * @param _value The string value to add
               */
              function add(Request memory self, string _key, string _value)
                internal pure
              {
                self.buf.encodeString(_key);
                self.buf.encodeString(_value);
              }
            
              /**
               * @notice Adds a bytes value to the request with a given key name
               * @param self The initialized request
               * @param _key The name of the key
               * @param _value The bytes value to add
               */
              function addBytes(Request memory self, string _key, bytes _value)
                internal pure
              {
                self.buf.encodeString(_key);
                self.buf.encodeBytes(_value);
              }
            
              /**
               * @notice Adds a int256 value to the request with a given key name
               * @param self The initialized request
               * @param _key The name of the key
               * @param _value The int256 value to add
               */
              function addInt(Request memory self, string _key, int256 _value)
                internal pure
              {
                self.buf.encodeString(_key);
                self.buf.encodeInt(_value);
              }
            
              /**
               * @notice Adds a uint256 value to the request with a given key name
               * @param self The initialized request
               * @param _key The name of the key
               * @param _value The uint256 value to add
               */
              function addUint(Request memory self, string _key, uint256 _value)
                internal pure
              {
                self.buf.encodeString(_key);
                self.buf.encodeUInt(_value);
              }
            
              /**
               * @notice Adds an array of strings to the request with a given key name
               * @param self The initialized request
               * @param _key The name of the key
               * @param _values The array of string values to add
               */
              function addStringArray(Request memory self, string _key, string[] memory _values)
                internal pure
              {
                self.buf.encodeString(_key);
                self.buf.startArray();
                for (uint256 i = 0; i < _values.length; i++) {
                  self.buf.encodeString(_values[i]);
                }
                self.buf.endSequence();
              }
            }
            
            interface ENSInterface {
            
              // Logged when the owner of a node assigns a new owner to a subnode.
              event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
            
              // Logged when the owner of a node transfers ownership to a new account.
              event Transfer(bytes32 indexed node, address owner);
            
              // Logged when the resolver for a node changes.
              event NewResolver(bytes32 indexed node, address resolver);
            
              // Logged when the TTL of a node changes
              event NewTTL(bytes32 indexed node, uint64 ttl);
            
            
              function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external;
              function setResolver(bytes32 node, address resolver) external;
              function setOwner(bytes32 node, address owner) external;
              function setTTL(bytes32 node, uint64 ttl) external;
              function owner(bytes32 node) external view returns (address);
              function resolver(bytes32 node) external view returns (address);
              function ttl(bytes32 node) external view returns (uint64);
            
            }
            
            interface LinkTokenInterface {
              function allowance(address owner, address spender) external returns (uint256 remaining);
              function approve(address spender, uint256 value) external returns (bool success);
              function balanceOf(address owner) external returns (uint256 balance);
              function decimals() external returns (uint8 decimalPlaces);
              function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
              function increaseApproval(address spender, uint256 subtractedValue) external;
              function name() external returns (string tokenName);
              function symbol() external returns (string tokenSymbol);
              function totalSupply() external returns (uint256 totalTokensIssued);
              function transfer(address to, uint256 value) external returns (bool success);
              function transferAndCall(address to, uint256 value, bytes data) external returns (bool success);
              function transferFrom(address from, address to, uint256 value) external returns (bool success);
            }
            
            interface ChainlinkRequestInterface {
              function oracleRequest(
                address sender,
                uint256 payment,
                bytes32 id,
                address callbackAddress,
                bytes4 callbackFunctionId,
                uint256 nonce,
                uint256 version,
                bytes data
              ) external;
            
              function cancelOracleRequest(
                bytes32 requestId,
                uint256 payment,
                bytes4 callbackFunctionId,
                uint256 expiration
              ) external;
            }
            
            interface PointerInterface {
              function getAddress() external view returns (address);
            }
            
            
            contract ENSResolver {
              function addr(bytes32 node) public view returns (address);
            }
            
            
            /**
             * @title SafeMath
             * @dev Math operations with safety checks that throw on error
             */
            library SafeMath {
            
              /**
              * @dev Multiplies two numbers, throws on overflow.
              */
              function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
                // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
                // benefit is lost if 'b' is also tested.
                // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                if (_a == 0) {
                  return 0;
                }
            
                c = _a * _b;
                assert(c / _a == _b);
                return c;
              }
            
              /**
              * @dev Integer division of two numbers, truncating the quotient.
              */
              function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
                // assert(_b > 0); // Solidity automatically throws when dividing by 0
                // uint256 c = _a / _b;
                // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
                return _a / _b;
              }
            
              /**
              * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
              */
              function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
                assert(_b <= _a);
                return _a - _b;
              }
            
              /**
              * @dev Adds two numbers, throws on overflow.
              */
              function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
                c = _a + _b;
                assert(c >= _a);
                return c;
              }
            }
            
            /**
             * @title The ChainlinkClient contract
             * @notice Contract writers can inherit this contract in order to create requests for the
             * Chainlink network
             */
            contract ChainlinkClient {
              using Chainlink for Chainlink.Request;
              using SafeMath for uint256;
            
              uint256 constant internal LINK = 10**18;
              uint256 constant private AMOUNT_OVERRIDE = 0;
              address constant private SENDER_OVERRIDE = 0x0;
              uint256 constant private ARGS_VERSION = 1;
              bytes32 constant private ENS_TOKEN_SUBNAME = keccak256("link");
              bytes32 constant private ENS_ORACLE_SUBNAME = keccak256("oracle");
              address constant private LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571;
            
              ENSInterface private ens;
              bytes32 private ensNode;
              LinkTokenInterface private link;
              ChainlinkRequestInterface private oracle;
              uint256 private requests = 1;
              mapping(bytes32 => address) private pendingRequests;
            
              event ChainlinkRequested(bytes32 indexed id);
              event ChainlinkFulfilled(bytes32 indexed id);
              event ChainlinkCancelled(bytes32 indexed id);
            
              /**
               * @notice Creates a request that can hold additional parameters
               * @param _specId The Job Specification ID that the request will be created for
               * @param _callbackAddress The callback address that the response will be sent to
               * @param _callbackFunctionSignature The callback function signature to use for the callback address
               * @return A Chainlink Request struct in memory
               */
              function buildChainlinkRequest(
                bytes32 _specId,
                address _callbackAddress,
                bytes4 _callbackFunctionSignature
              ) internal pure returns (Chainlink.Request memory) {
                Chainlink.Request memory req;
                return req.initialize(_specId, _callbackAddress, _callbackFunctionSignature);
              }
            
              /**
               * @notice Creates a Chainlink request to the stored oracle address
               * @dev Calls `chainlinkRequestTo` with the stored oracle address
               * @param _req The initialized Chainlink Request
               * @param _payment The amount of LINK to send for the request
               * @return The request ID
               */
              function sendChainlinkRequest(Chainlink.Request memory _req, uint256 _payment)
                internal
                returns (bytes32)
              {
                return sendChainlinkRequestTo(oracle, _req, _payment);
              }
            
              /**
               * @notice Creates a Chainlink request to the specified oracle address
               * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to
               * send LINK which creates a request on the target oracle contract.
               * Emits ChainlinkRequested event.
               * @param _oracle The address of the oracle for the request
               * @param _req The initialized Chainlink Request
               * @param _payment The amount of LINK to send for the request
               * @return The request ID
               */
              function sendChainlinkRequestTo(address _oracle, Chainlink.Request memory _req, uint256 _payment)
                internal
                returns (bytes32 requestId)
              {
                requestId = keccak256(abi.encodePacked(this, requests));
                _req.nonce = requests;
                pendingRequests[requestId] = _oracle;
                emit ChainlinkRequested(requestId);
                require(link.transferAndCall(_oracle, _payment, encodeRequest(_req)), "unable to transferAndCall to oracle");
                requests += 1;
            
                return requestId;
              }
            
              /**
               * @notice Allows a request to be cancelled if it has not been fulfilled
               * @dev Requires keeping track of the expiration value emitted from the oracle contract.
               * Deletes the request from the `pendingRequests` mapping.
               * Emits ChainlinkCancelled event.
               * @param _requestId The request ID
               * @param _payment The amount of LINK sent for the request
               * @param _callbackFunc The callback function specified for the request
               * @param _expiration The time of the expiration for the request
               */
              function cancelChainlinkRequest(
                bytes32 _requestId,
                uint256 _payment,
                bytes4 _callbackFunc,
                uint256 _expiration
              )
                internal
              {
                ChainlinkRequestInterface requested = ChainlinkRequestInterface(pendingRequests[_requestId]);
                delete pendingRequests[_requestId];
                emit ChainlinkCancelled(_requestId);
                requested.cancelOracleRequest(_requestId, _payment, _callbackFunc, _expiration);
              }
            
              /**
               * @notice Sets the stored oracle address
               * @param _oracle The address of the oracle contract
               */
              function setChainlinkOracle(address _oracle) internal {
                oracle = ChainlinkRequestInterface(_oracle);
              }
            
              /**
               * @notice Sets the LINK token address
               * @param _link The address of the LINK token contract
               */
              function setChainlinkToken(address _link) internal {
                link = LinkTokenInterface(_link);
              }
            
              /**
               * @notice Sets the Chainlink token address for the public
               * network as given by the Pointer contract
               */
              function setPublicChainlinkToken() internal {
                setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress());
              }
            
              /**
               * @notice Retrieves the stored address of the LINK token
               * @return The address of the LINK token
               */
              function chainlinkTokenAddress()
                internal
                view
                returns (address)
              {
                return address(link);
              }
            
              /**
               * @notice Retrieves the stored address of the oracle contract
               * @return The address of the oracle contract
               */
              function chainlinkOracleAddress()
                internal
                view
                returns (address)
              {
                return address(oracle);
              }
            
              /**
               * @notice Allows for a request which was created on another contract to be fulfilled
               * on this contract
               * @param _oracle The address of the oracle contract that will fulfill the request
               * @param _requestId The request ID used for the response
               */
              function addChainlinkExternalRequest(address _oracle, bytes32 _requestId)
                internal
                notPendingRequest(_requestId)
              {
                pendingRequests[_requestId] = _oracle;
              }
            
              /**
               * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS
               * @dev Accounts for subnodes having different resolvers
               * @param _ens The address of the ENS contract
               * @param _node The ENS node hash
               */
              function useChainlinkWithENS(address _ens, bytes32 _node)
                internal
              {
                ens = ENSInterface(_ens);
                ensNode = _node;
                bytes32 linkSubnode = keccak256(abi.encodePacked(ensNode, ENS_TOKEN_SUBNAME));
                ENSResolver resolver = ENSResolver(ens.resolver(linkSubnode));
                setChainlinkToken(resolver.addr(linkSubnode));
                updateChainlinkOracleWithENS();
              }
            
              /**
               * @notice Sets the stored oracle contract with the address resolved by ENS
               * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously
               */
              function updateChainlinkOracleWithENS()
                internal
              {
                bytes32 oracleSubnode = keccak256(abi.encodePacked(ensNode, ENS_ORACLE_SUBNAME));
                ENSResolver resolver = ENSResolver(ens.resolver(oracleSubnode));
                setChainlinkOracle(resolver.addr(oracleSubnode));
              }
            
              /**
               * @notice Encodes the request to be sent to the oracle contract
               * @dev The Chainlink node expects values to be in order for the request to be picked up. Order of types
               * will be validated in the oracle contract.
               * @param _req The initialized Chainlink Request
               * @return The bytes payload for the `transferAndCall` method
               */
              function encodeRequest(Chainlink.Request memory _req)
                private
                view
                returns (bytes memory)
              {
                return abi.encodeWithSelector(
                  oracle.oracleRequest.selector,
                  SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address
                  AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent
                  _req.id,
                  _req.callbackAddress,
                  _req.callbackFunctionId,
                  _req.nonce,
                  ARGS_VERSION,
                  _req.buf.buf);
              }
            
              /**
               * @notice Ensures that the fulfillment is valid for this contract
               * @dev Use if the contract developer prefers methods instead of modifiers for validation
               * @param _requestId The request ID for fulfillment
               */
              function validateChainlinkCallback(bytes32 _requestId)
                internal
                recordChainlinkFulfillment(_requestId)
                // solhint-disable-next-line no-empty-blocks
              {}
            
              /**
               * @dev Reverts if the sender is not the oracle of the request.
               * Emits ChainlinkFulfilled event.
               * @param _requestId The request ID for fulfillment
               */
              modifier recordChainlinkFulfillment(bytes32 _requestId) {
                require(msg.sender == pendingRequests[_requestId], "Source must be the oracle of the request");
                delete pendingRequests[_requestId];
                emit ChainlinkFulfilled(_requestId);
                _;
              }
            
              /**
               * @dev Reverts if the request is already pending
               * @param _requestId The request ID for fulfillment
               */
              modifier notPendingRequest(bytes32 _requestId) {
                require(pendingRequests[_requestId] == address(0), "Request is already pending");
                _;
              }
            }
            
            interface AggregatorInterface {
              function latestAnswer() external view returns (int256);
              function latestTimestamp() external view returns (uint256);
              function latestRound() external view returns (uint256);
              function getAnswer(uint256 roundId) external view returns (int256);
              function getTimestamp(uint256 roundId) external view returns (uint256);
            
              event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);
              event NewRound(uint256 indexed roundId, address indexed startedBy);
            }
            
            library SignedSafeMath {
            
              /**
               * @dev Adds two int256s and makes sure the result doesn't overflow. Signed
               * integers aren't supported by the SafeMath library, thus this method
               * @param _a The first number to be added
               * @param _a The second number to be added
               */
              function add(int256 _a, int256 _b)
                internal
                pure
                returns (int256)
              {
                int256 c = _a + _b;
                require((_b >= 0 && c >= _a) || (_b < 0 && c < _a), "SignedSafeMath: addition overflow");
            
                return c;
              }
            }
            
            /**
             * @title Ownable
             * @dev The Ownable contract has an owner address, and provides basic authorization control
             * functions, this simplifies the implementation of "user permissions".
             */
            contract Ownable {
              address public owner;
            
            
              event OwnershipRenounced(address indexed previousOwner);
              event OwnershipTransferred(
                address indexed previousOwner,
                address indexed newOwner
              );
            
            
              /**
               * @dev The Ownable constructor sets the original `owner` of the contract to the sender
               * account.
               */
              constructor() public {
                owner = msg.sender;
              }
            
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                require(msg.sender == owner);
                _;
              }
            
              /**
               * @dev Allows the current owner to relinquish control of the contract.
               * @notice Renouncing to ownership will leave the contract without an owner.
               * It will not be possible to call the functions with the `onlyOwner`
               * modifier anymore.
               */
              function renounceOwnership() public onlyOwner {
                emit OwnershipRenounced(owner);
                owner = address(0);
              }
            
              /**
               * @dev Allows the current owner to transfer control of the contract to a newOwner.
               * @param _newOwner The address to transfer ownership to.
               */
              function transferOwnership(address _newOwner) public onlyOwner {
                _transferOwnership(_newOwner);
              }
            
              /**
               * @dev Transfers control of the contract to a newOwner.
               * @param _newOwner The address to transfer ownership to.
               */
              function _transferOwnership(address _newOwner) internal {
                require(_newOwner != address(0));
                emit OwnershipTransferred(owner, _newOwner);
                owner = _newOwner;
              }
            }
            
            /**
             * @title An example Chainlink contract with aggregation
             * @notice Requesters can use this contract as a framework for creating
             * requests to multiple Chainlink nodes and running aggregation
             * as the contract receives answers.
             */
            contract Aggregator is AggregatorInterface, ChainlinkClient, Ownable {
              using SignedSafeMath for int256;
            
              struct Answer {
                uint128 minimumResponses;
                uint128 maxResponses;
                int256[] responses;
              }
            
              event ResponseReceived(int256 indexed response, uint256 indexed answerId, address indexed sender);
            
              int256 private currentAnswerValue;
              uint256 private updatedTimestampValue;
              uint256 private latestCompletedAnswer;
              uint128 public paymentAmount;
              uint128 public minimumResponses;
              bytes32[] public jobIds;
              address[] public oracles;
            
              uint256 private answerCounter = 1;
              mapping(address => bool) public authorizedRequesters;
              mapping(bytes32 => uint256) private requestAnswers;
              mapping(uint256 => Answer) private answers;
              mapping(uint256 => int256) private currentAnswers;
              mapping(uint256 => uint256) private updatedTimestamps;
            
              uint256 constant private MAX_ORACLE_COUNT = 45;
            
              /**
               * @notice Deploy with the address of the LINK token and arrays of matching
               * length containing the addresses of the oracles and their corresponding
               * Job IDs.
               * @dev Sets the LinkToken address for the network, addresses of the oracles,
               * and jobIds in storage.
               * @param _link The address of the LINK token
               * @param _paymentAmount the amount of LINK to be sent to each oracle for each request
               * @param _minimumResponses the minimum number of responses
               * before an answer will be calculated
               * @param _oracles An array of oracle addresses
               * @param _jobIds An array of Job IDs
               */
              constructor(
                address _link,
                uint128 _paymentAmount,
                uint128 _minimumResponses,
                address[] _oracles,
                bytes32[] _jobIds
              ) public Ownable() {
                setChainlinkToken(_link);
                updateRequestDetails(_paymentAmount, _minimumResponses, _oracles, _jobIds);
              }
            
              /**
               * @notice Creates a Chainlink request for each oracle in the oracles array.
               * @dev This example does not include request parameters. Reference any documentation
               * associated with the Job IDs used to determine the required parameters per-request.
               */
              function requestRateUpdate()
                external
                ensureAuthorizedRequester()
              {
                Chainlink.Request memory request;
                bytes32 requestId;
                uint256 oraclePayment = paymentAmount;
            
                for (uint i = 0; i < oracles.length; i++) {
                  request = buildChainlinkRequest(jobIds[i], this, this.chainlinkCallback.selector);
                  requestId = sendChainlinkRequestTo(oracles[i], request, oraclePayment);
                  requestAnswers[requestId] = answerCounter;
                }
                answers[answerCounter].minimumResponses = minimumResponses;
                answers[answerCounter].maxResponses = uint128(oracles.length);
                answerCounter = answerCounter.add(1);
            
                emit NewRound(answerCounter, msg.sender);
              }
            
              /**
               * @notice Receives the answer from the Chainlink node.
               * @dev This function can only be called by the oracle that received the request.
               * @param _clRequestId The Chainlink request ID associated with the answer
               * @param _response The answer provided by the Chainlink node
               */
              function chainlinkCallback(bytes32 _clRequestId, int256 _response)
                external
              {
                validateChainlinkCallback(_clRequestId);
            
                uint256 answerId = requestAnswers[_clRequestId];
                delete requestAnswers[_clRequestId];
            
                answers[answerId].responses.push(_response);
                emit ResponseReceived(_response, answerId, msg.sender);
                updateLatestAnswer(answerId);
                deleteAnswer(answerId);
              }
            
              /**
               * @notice Updates the arrays of oracles and jobIds with new values,
               * overwriting the old values.
               * @dev Arrays are validated to be equal length.
               * @param _paymentAmount the amount of LINK to be sent to each oracle for each request
               * @param _minimumResponses the minimum number of responses
               * before an answer will be calculated
               * @param _oracles An array of oracle addresses
               * @param _jobIds An array of Job IDs
               */
              function updateRequestDetails(
                uint128 _paymentAmount,
                uint128 _minimumResponses,
                address[] _oracles,
                bytes32[] _jobIds
              )
                public
                onlyOwner()
                validateAnswerRequirements(_minimumResponses, _oracles, _jobIds)
              {
                paymentAmount = _paymentAmount;
                minimumResponses = _minimumResponses;
                jobIds = _jobIds;
                oracles = _oracles;
              }
            
              /**
               * @notice Allows the owner of the contract to withdraw any LINK balance
               * available on the contract.
               * @dev The contract will need to have a LINK balance in order to create requests.
               * @param _recipient The address to receive the LINK tokens
               * @param _amount The amount of LINK to send from the contract
               */
              function transferLINK(address _recipient, uint256 _amount)
                public
                onlyOwner()
              {
                LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress());
                require(linkToken.transfer(_recipient, _amount), "LINK transfer failed");
              }
            
              /**
               * @notice Called by the owner to permission other addresses to generate new
               * requests to oracles.
               * @param _requester the address whose permissions are being set
               * @param _allowed boolean that determines whether the requester is
               * permissioned or not
               */
              function setAuthorization(address _requester, bool _allowed)
                external
                onlyOwner()
              {
                authorizedRequesters[_requester] = _allowed;
              }
            
              /**
               * @notice Cancels an outstanding Chainlink request.
               * The oracle contract requires the request ID and additional metadata to
               * validate the cancellation. Only old answers can be cancelled.
               * @param _requestId is the identifier for the chainlink request being cancelled
               * @param _payment is the amount of LINK paid to the oracle for the request
               * @param _expiration is the time when the request expires
               */
              function cancelRequest(
                bytes32 _requestId,
                uint256 _payment,
                uint256 _expiration
              )
                external
                ensureAuthorizedRequester()
              {
                uint256 answerId = requestAnswers[_requestId];
                require(answerId < latestCompletedAnswer, "Cannot modify an in-progress answer");
            
                delete requestAnswers[_requestId];
                answers[answerId].responses.push(0);
                deleteAnswer(answerId);
            
                cancelChainlinkRequest(
                  _requestId,
                  _payment,
                  this.chainlinkCallback.selector,
                  _expiration
                );
              }
            
              /**
               * @notice Called by the owner to kill the contract. This transfers all LINK
               * balance and ETH balance (if there is any) to the owner.
               */
              function destroy()
                external
                onlyOwner()
              {
                LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress());
                transferLINK(owner, linkToken.balanceOf(address(this)));
                selfdestruct(owner);
              }
            
              /**
               * @dev Performs aggregation of the answers received from the Chainlink nodes.
               * Assumes that at least half the oracles are honest and so can't contol the
               * middle of the ordered responses.
               * @param _answerId The answer ID associated with the group of requests
               */
              function updateLatestAnswer(uint256 _answerId)
                private
                ensureMinResponsesReceived(_answerId)
                ensureOnlyLatestAnswer(_answerId)
              {
                uint256 responseLength = answers[_answerId].responses.length;
                uint256 middleIndex = responseLength.div(2);
                int256 currentAnswerTemp;
                if (responseLength % 2 == 0) {
                  int256 median1 = quickselect(answers[_answerId].responses, middleIndex);
                  int256 median2 = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
                  currentAnswerTemp = median1.add(median2) / 2; // signed integers are not supported by SafeMath
                } else {
                  currentAnswerTemp = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
                }
                currentAnswerValue = currentAnswerTemp;
                latestCompletedAnswer = _answerId;
                updatedTimestampValue = now;
                updatedTimestamps[_answerId] = now;
                currentAnswers[_answerId] = currentAnswerTemp;
                emit AnswerUpdated(currentAnswerTemp, _answerId, now);
              }
            
              /**
               * @notice get the most recently reported answer
               */
              function latestAnswer()
                external
                view
                returns (int256)
              {
                return currentAnswers[latestCompletedAnswer];
              }
            
              /**
               * @notice get the last updated at block timestamp
               */
              function latestTimestamp()
                external
                view
                returns (uint256)
              {
                return updatedTimestamps[latestCompletedAnswer];
              }
            
              /**
               * @notice get past rounds answers
               * @param _roundId the answer number to retrieve the answer for
               */
              function getAnswer(uint256 _roundId)
                external
                view
                returns (int256)
              {
                return currentAnswers[_roundId];
              }
            
              /**
               * @notice get block timestamp when an answer was last updated
               * @param _roundId the answer number to retrieve the updated timestamp for
               */
              function getTimestamp(uint256 _roundId)
                external
                view
                returns (uint256)
              {
                return updatedTimestamps[_roundId];
              }
            
              /**
               * @notice get the latest completed round where the answer was updated
               */
              function latestRound() external view returns (uint256) {
                return latestCompletedAnswer;
              }
            
              /**
               * @dev Returns the kth value of the ordered array
               * See: http://www.cs.yale.edu/homes/aspnes/pinewiki/QuickSelect.html
               * @param _a The list of elements to pull from
               * @param _k The index, 1 based, of the elements you want to pull from when ordered
               */
              function quickselect(int256[] memory _a, uint256 _k)
                private
                pure
                returns (int256)
              {
                int256[] memory a = _a;
                uint256 k = _k;
                uint256 aLen = a.length;
                int256[] memory a1 = new int256[](aLen);
                int256[] memory a2 = new int256[](aLen);
                uint256 a1Len;
                uint256 a2Len;
                int256 pivot;
                uint256 i;
            
                while (true) {
                  pivot = a[aLen.div(2)];
                  a1Len = 0;
                  a2Len = 0;
                  for (i = 0; i < aLen; i++) {
                    if (a[i] < pivot) {
                      a1[a1Len] = a[i];
                      a1Len++;
                    } else if (a[i] > pivot) {
                      a2[a2Len] = a[i];
                      a2Len++;
                    }
                  }
                  if (k <= a1Len) {
                    aLen = a1Len;
                    (a, a1) = swap(a, a1);
                  } else if (k > (aLen.sub(a2Len))) {
                    k = k.sub(aLen.sub(a2Len));
                    aLen = a2Len;
                    (a, a2) = swap(a, a2);
                  } else {
                    return pivot;
                  }
                }
              }
            
              /**
               * @dev Swaps the pointers to two uint256 arrays in memory
               * @param _a The pointer to the first in memory array
               * @param _b The pointer to the second in memory array
               */
              function swap(int256[] memory _a, int256[] memory _b)
                private
                pure
                returns(int256[] memory, int256[] memory)
              {
                return (_b, _a);
              }
            
              /**
               * @dev Cleans up the answer record if all responses have been received.
               * @param _answerId The identifier of the answer to be deleted
               */
              function deleteAnswer(uint256 _answerId)
                private
                ensureAllResponsesReceived(_answerId)
              {
                delete answers[_answerId];
              }
            
              /**
               * @dev Prevents taking an action if the minimum number of responses has not
               * been received for an answer.
               * @param _answerId The the identifier of the answer that keeps track of the responses.
               */
              modifier ensureMinResponsesReceived(uint256 _answerId) {
                if (answers[_answerId].responses.length >= answers[_answerId].minimumResponses) {
                  _;
                }
              }
            
              /**
               * @dev Prevents taking an action if not all responses are received for an answer.
               * @param _answerId The the identifier of the answer that keeps track of the responses.
               */
              modifier ensureAllResponsesReceived(uint256 _answerId) {
                if (answers[_answerId].responses.length == answers[_answerId].maxResponses) {
                  _;
                }
              }
            
              /**
               * @dev Prevents taking an action if a newer answer has been recorded.
               * @param _answerId The current answer's identifier.
               * Answer IDs are in ascending order.
               */
              modifier ensureOnlyLatestAnswer(uint256 _answerId) {
                if (latestCompletedAnswer <= _answerId) {
                  _;
                }
              }
            
              /**
               * @dev Ensures corresponding number of oracles and jobs.
               * @param _oracles The list of oracles.
               * @param _jobIds The list of jobs.
               */
              modifier validateAnswerRequirements(
                uint256 _minimumResponses,
                address[] _oracles,
                bytes32[] _jobIds
              ) {
                require(_oracles.length <= MAX_ORACLE_COUNT, "cannot have more than 45 oracles");
                require(_oracles.length >= _minimumResponses, "must have at least as many oracles as responses");
                require(_oracles.length == _jobIds.length, "must have exactly as many oracles as job IDs");
                _;
              }
            
              /**
               * @dev Reverts if `msg.sender` is not authorized to make requests.
               */
              modifier ensureAuthorizedRequester() {
                require(authorizedRequesters[msg.sender] || msg.sender == owner, "Not an authorized address for creating requests");
                _;
              }
            
            }