{
  "address": "0xF427c4AdED8B6dfde604865c1a7E953B160C26f0",
  "transactionHash": "0x027e94842740fec52dc25b17fcc9d4c0291ed08f6aacb9f4c54e08cb926a5631",
  "abi": [
    {
      "inputs": [
        {
          "internalType": "bytes",
          "name": "_anchors",
          "type": "bytes"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint8",
          "name": "id",
          "type": "uint8"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "AlgorithmUpdated",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint8",
          "name": "id",
          "type": "uint8"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "DigestUpdated",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [],
      "name": "Marker",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint8",
          "name": "id",
          "type": "uint8"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "NSEC3DigestUpdated",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "bytes",
          "name": "name",
          "type": "bytes"
        },
        {
          "indexed": false,
          "internalType": "bytes",
          "name": "rrset",
          "type": "bytes"
        }
      ],
      "name": "RRSetUpdated",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "t",
          "type": "uint256"
        }
      ],
      "name": "Test",
      "type": "event"
    },
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "",
          "type": "uint8"
        }
      ],
      "name": "algorithms",
      "outputs": [
        {
          "internalType": "contract Algorithm",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "anchors",
      "outputs": [
        {
          "internalType": "bytes",
          "name": "",
          "type": "bytes"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint16",
          "name": "deleteType",
          "type": "uint16"
        },
        {
          "internalType": "bytes",
          "name": "deleteName",
          "type": "bytes"
        },
        {
          "components": [
            {
              "internalType": "bytes",
              "name": "rrset",
              "type": "bytes"
            },
            {
              "internalType": "bytes",
              "name": "sig",
              "type": "bytes"
            }
          ],
          "internalType": "struct DNSSEC.RRSetWithSignature",
          "name": "nsec",
          "type": "tuple"
        },
        {
          "internalType": "bytes",
          "name": "proof",
          "type": "bytes"
        }
      ],
      "name": "deleteRRSet",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint16",
          "name": "deleteType",
          "type": "uint16"
        },
        {
          "internalType": "bytes",
          "name": "deleteName",
          "type": "bytes"
        },
        {
          "components": [
            {
              "internalType": "bytes",
              "name": "rrset",
              "type": "bytes"
            },
            {
              "internalType": "bytes",
              "name": "sig",
              "type": "bytes"
            }
          ],
          "internalType": "struct DNSSEC.RRSetWithSignature",
          "name": "closestEncloser",
          "type": "tuple"
        },
        {
          "components": [
            {
              "internalType": "bytes",
              "name": "rrset",
              "type": "bytes"
            },
            {
              "internalType": "bytes",
              "name": "sig",
              "type": "bytes"
            }
          ],
          "internalType": "struct DNSSEC.RRSetWithSignature",
          "name": "nextClosest",
          "type": "tuple"
        },
        {
          "internalType": "bytes",
          "name": "dnskey",
          "type": "bytes"
        }
      ],
      "name": "deleteRRSetNSEC3",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "",
          "type": "uint8"
        }
      ],
      "name": "digests",
      "outputs": [
        {
          "internalType": "contract Digest",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "",
          "type": "uint8"
        }
      ],
      "name": "nsec3Digests",
      "outputs": [
        {
          "internalType": "contract NSEC3Digest",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "owner",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint16",
          "name": "dnstype",
          "type": "uint16"
        },
        {
          "internalType": "bytes",
          "name": "name",
          "type": "bytes"
        }
      ],
      "name": "rrdata",
      "outputs": [
        {
          "internalType": "uint32",
          "name": "",
          "type": "uint32"
        },
        {
          "internalType": "uint32",
          "name": "",
          "type": "uint32"
        },
        {
          "internalType": "bytes20",
          "name": "",
          "type": "bytes20"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "id",
          "type": "uint8"
        },
        {
          "internalType": "contract Algorithm",
          "name": "algo",
          "type": "address"
        }
      ],
      "name": "setAlgorithm",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "id",
          "type": "uint8"
        },
        {
          "internalType": "contract Digest",
          "name": "digest",
          "type": "address"
        }
      ],
      "name": "setDigest",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "id",
          "type": "uint8"
        },
        {
          "internalType": "contract NSEC3Digest",
          "name": "digest",
          "type": "address"
        }
      ],
      "name": "setNSEC3Digest",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "newOwner",
          "type": "address"
        }
      ],
      "name": "setOwner",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "components": [
            {
              "internalType": "bytes",
              "name": "rrset",
              "type": "bytes"
            },
            {
              "internalType": "bytes",
              "name": "sig",
              "type": "bytes"
            }
          ],
          "internalType": "struct DNSSEC.RRSetWithSignature",
          "name": "input",
          "type": "tuple"
        },
        {
          "internalType": "bytes",
          "name": "proof",
          "type": "bytes"
        }
      ],
      "name": "submitRRSet",
      "outputs": [
        {
          "internalType": "bytes",
          "name": "",
          "type": "bytes"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "components": [
            {
              "internalType": "bytes",
              "name": "rrset",
              "type": "bytes"
            },
            {
              "internalType": "bytes",
              "name": "sig",
              "type": "bytes"
            }
          ],
          "internalType": "struct DNSSEC.RRSetWithSignature[]",
          "name": "input",
          "type": "tuple[]"
        },
        {
          "internalType": "bytes",
          "name": "_proof",
          "type": "bytes"
        }
      ],
      "name": "submitRRSets",
      "outputs": [
        {
          "internalType": "bytes",
          "name": "",
          "type": "bytes"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    }
  ],
  "transactionHash": "0x027e94842740fec52dc25b17fcc9d4c0291ed08f6aacb9f4c54e08cb926a5631",
  "receipt": {
    "to": null,
    "from": "0xa303ddC620aa7d1390BACcc8A495508B183fab59",
    "contractAddress": "0xF427c4AdED8B6dfde604865c1a7E953B160C26f0",
    "transactionIndex": 35,
    "gasUsed": "3198290",
    "logsBloom": "0x00000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000",
    "blockHash": "0x3bd90892eb6dfb4d6e63aa01ab9aee246385e5237f780553ae5783550f18b97c",
    "transactionHash": "0x027e94842740fec52dc25b17fcc9d4c0291ed08f6aacb9f4c54e08cb926a5631",
    "logs": [
      {
        "transactionIndex": 35,
        "blockNumber": 6470040,
        "transactionHash": "0x027e94842740fec52dc25b17fcc9d4c0291ed08f6aacb9f4c54e08cb926a5631",
        "address": "0xF427c4AdED8B6dfde604865c1a7E953B160C26f0",
        "topics": [
          "0x55ced933cdd5a34dd03eb5d4bef19ec6ebb251dcd7a988eee0c1b9a13baaa88b"
        ],
        "data": "0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d00002b000100000e1000244a5c080249aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb500002b000100000e1000244f660802e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d00002b000100000e10000404fefdfd00000000000000000000000000000000000000",
        "logIndex": 96,
        "blockHash": "0x3bd90892eb6dfb4d6e63aa01ab9aee246385e5237f780553ae5783550f18b97c"
      }
    ],
    "blockNumber": 6470040,
    "cumulativeGasUsed": "12458761",
    "status": 1,
    "byzantium": true
  },
  "args": [
    "0x00002b000100000e1000244a5c080249aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb500002b000100000e1000244f660802e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d00002b000100000e10000404fefdfd"
  ],
  "solcInputHash": "7948b60c3b601df824761a337a51d661",
  "metadata": "{\"compiler\":{\"version\":\"0.8.4+commit.c7e474f2\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_anchors\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"id\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"AlgorithmUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"id\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"DigestUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Marker\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"id\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"NSEC3DigestUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"name\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"rrset\",\"type\":\"bytes\"}],\"name\":\"RRSetUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"t\",\"type\":\"uint256\"}],\"name\":\"Test\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"algorithms\",\"outputs\":[{\"internalType\":\"contract Algorithm\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"anchors\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"deleteType\",\"type\":\"uint16\"},{\"internalType\":\"bytes\",\"name\":\"deleteName\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"rrset\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"struct DNSSEC.RRSetWithSignature\",\"name\":\"nsec\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"deleteRRSet\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"deleteType\",\"type\":\"uint16\"},{\"internalType\":\"bytes\",\"name\":\"deleteName\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"rrset\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"struct DNSSEC.RRSetWithSignature\",\"name\":\"closestEncloser\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"rrset\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"struct DNSSEC.RRSetWithSignature\",\"name\":\"nextClosest\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"dnskey\",\"type\":\"bytes\"}],\"name\":\"deleteRRSetNSEC3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"digests\",\"outputs\":[{\"internalType\":\"contract Digest\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"nsec3Digests\",\"outputs\":[{\"internalType\":\"contract NSEC3Digest\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"dnstype\",\"type\":\"uint16\"},{\"internalType\":\"bytes\",\"name\":\"name\",\"type\":\"bytes\"}],\"name\":\"rrdata\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes20\",\"name\":\"\",\"type\":\"bytes20\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"id\",\"type\":\"uint8\"},{\"internalType\":\"contract Algorithm\",\"name\":\"algo\",\"type\":\"address\"}],\"name\":\"setAlgorithm\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"id\",\"type\":\"uint8\"},{\"internalType\":\"contract Digest\",\"name\":\"digest\",\"type\":\"address\"}],\"name\":\"setDigest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"id\",\"type\":\"uint8\"},{\"internalType\":\"contract NSEC3Digest\",\"name\":\"digest\",\"type\":\"address\"}],\"name\":\"setNSEC3Digest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"rrset\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"struct DNSSEC.RRSetWithSignature\",\"name\":\"input\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"submitRRSet\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"rrset\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"struct DNSSEC.RRSetWithSignature[]\",\"name\":\"input\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"_proof\",\"type\":\"bytes\"}],\"name\":\"submitRRSets\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"details\":\"Constructor.\",\"params\":{\"_anchors\":\"The binary format RR entries for the root DS records.\"}},\"deleteRRSet(uint16,bytes,(bytes,bytes),bytes)\":{\"details\":\"Deletes an RR from the oracle.\",\"params\":{\"deleteName\":\"which you want to delete\",\"deleteType\":\"The DNS record type to delete.\",\"nsec\":\"The signed NSEC RRset. This is in the format described in section        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature        data, followed by a series of canonicalised RR records that the signature        applies to.\"}},\"deleteRRSetNSEC3(uint16,bytes,(bytes,bytes),(bytes,bytes),bytes)\":{\"details\":\"Deletes an RR from the oracle using an NSEC3 proof.      Deleting a record using NSEC3 requires using up to two NSEC3 records. There are two cases:       1. The name exists, but the record type doesn't. Eg, example.com has A records but no TXT records.       2. The name does not exist, but a parent name does.      In the first case, we submit one NSEC3 proof in `closestEncloser` that matches the target name      but does not have the bit for `deleteType` set in its type bitmap. In the second case, we submit      two proofs: closestEncloser and nextClosest, that together prove that the name does not exist.      NSEC3 records are in the format described in section 5.3.2 of RFC4035: The RRDATA section      from the RRSIG without the signature data, followed by a series of canonicalised RR records      that the signature applies to.\",\"params\":{\"closestEncloser\":\"An NSEC3 proof matching the closest enclosing name - that is,        the nearest ancestor of the target name that *does* exist.\",\"deleteName\":\"The name to delete.\",\"deleteType\":\"The DNS record type to delete.\",\"dnskey\":\"An encoded DNSKEY record that has already been submitted to the oracle and can be used        to verify the signatures closestEncloserSig and nextClosestSig\",\"nextClosest\":\"An NSEC3 proof covering the next closest name. This proves that the immediate        subdomain of the closestEncloser does not exist.\"}},\"rrdata(uint16,bytes)\":{\"details\":\"Returns data about the RRs (if any) known to this oracle with the provided type and name.\",\"params\":{\"dnstype\":\"The DNS record type to query.\",\"name\":\"The name to query, in DNS label-sequence format.\"},\"returns\":{\"_0\":\"inception The unix timestamp (wrapped) at which the signature for this RRSET was created.\",\"_1\":\"expiration The unix timestamp (wrapped) at which the signature for this RRSET expires.\",\"_2\":\"hash The hash of the RRset.\"}},\"setAlgorithm(uint8,address)\":{\"details\":\"Sets the contract address for a signature verification algorithm.      Callable only by the owner.\",\"params\":{\"algo\":\"The address of the algorithm contract.\",\"id\":\"The algorithm ID\"}},\"setDigest(uint8,address)\":{\"details\":\"Sets the contract address for a digest verification algorithm.      Callable only by the owner.\",\"params\":{\"digest\":\"The address of the digest contract.\",\"id\":\"The digest ID\"}},\"setNSEC3Digest(uint8,address)\":{\"details\":\"Sets the contract address for an NSEC3 digest algorithm.      Callable only by the owner.\",\"params\":{\"digest\":\"The address of the digest contract.\",\"id\":\"The digest ID\"}},\"submitRRSet((bytes,bytes),bytes)\":{\"details\":\"Submits a signed set of RRs to the oracle. RRSETs are only accepted if they are signed with a key that is already trusted, or if they are self-signed, and the signing key is identified by a DS record that is already trusted.\",\"params\":{\"input\":\"The signed RR set. This is in the format described in section        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature        data, followed by a series of canonicalised RR records that the signature        applies to.\",\"proof\":\"The DNSKEY or DS to validate the signature against. Must Already        have been submitted and proved previously.\"}},\"submitRRSets((bytes,bytes)[],bytes)\":{\"details\":\"Submits multiple RRSets\",\"params\":{\"_proof\":\"The DNSKEY or DS to validate the first signature against.\",\"input\":\"A list of RRSets and signatures forming a chain of trust from an existing known-good record.\"},\"returns\":{\"_0\":\"The last RRSET submitted.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/dnssec-oracle/DNSSECImpl.sol\":\"DNSSECImpl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"@ensdomains/buffer/contracts/Buffer.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\n/**\\n* @dev A library for working with mutable byte buffers in Solidity.\\n*\\n* Byte buffers are mutable and expandable, and provide a variety of primitives\\n* for writing to them. At any time you can fetch a bytes object containing the\\n* current contents of the buffer. The bytes object should not be stored between\\n* operations, as it may change due to resizing of the buffer.\\n*/\\nlibrary Buffer {\\n    /**\\n    * @dev Represents a mutable buffer. Buffers have a current value (buf) and\\n    *      a capacity. The capacity may be longer than the current value, in\\n    *      which case it can be extended without the need to allocate more memory.\\n    */\\n    struct buffer {\\n        bytes buf;\\n        uint capacity;\\n    }\\n\\n    /**\\n    * @dev Initializes a buffer with an initial capacity.\\n    * @param buf The buffer to initialize.\\n    * @param capacity The number of bytes of space to allocate the buffer.\\n    * @return The buffer, for chaining.\\n    */\\n    function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {\\n        if (capacity % 32 != 0) {\\n            capacity += 32 - (capacity % 32);\\n        }\\n        // Allocate space for the buffer data\\n        buf.capacity = capacity;\\n        assembly {\\n            let ptr := mload(0x40)\\n            mstore(buf, ptr)\\n            mstore(ptr, 0)\\n            mstore(0x40, add(32, add(ptr, capacity)))\\n        }\\n        return buf;\\n    }\\n\\n    /**\\n    * @dev Initializes a new buffer from an existing bytes object.\\n    *      Changes to the buffer may mutate the original value.\\n    * @param b The bytes object to initialize the buffer with.\\n    * @return A new buffer.\\n    */\\n    function fromBytes(bytes memory b) internal pure returns(buffer memory) {\\n        buffer memory buf;\\n        buf.buf = b;\\n        buf.capacity = b.length;\\n        return buf;\\n    }\\n\\n    function resize(buffer memory buf, uint capacity) private pure {\\n        bytes memory oldbuf = buf.buf;\\n        init(buf, capacity);\\n        append(buf, oldbuf);\\n    }\\n\\n    function max(uint a, uint b) private pure returns(uint) {\\n        if (a > b) {\\n            return a;\\n        }\\n        return b;\\n    }\\n\\n    /**\\n    * @dev Sets buffer length to 0.\\n    * @param buf The buffer to truncate.\\n    * @return The original buffer, for chaining..\\n    */\\n    function truncate(buffer memory buf) internal pure returns (buffer memory) {\\n        assembly {\\n            let bufptr := mload(buf)\\n            mstore(bufptr, 0)\\n        }\\n        return buf;\\n    }\\n\\n    /**\\n    * @dev Writes a byte string to a buffer. Resizes if doing so would exceed\\n    *      the capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param off The start offset to write to.\\n    * @param data The data to append.\\n    * @param len The number of bytes to copy.\\n    * @return The original buffer, for chaining.\\n    */\\n    function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) {\\n        require(len <= data.length);\\n\\n        if (off + len > buf.capacity) {\\n            resize(buf, max(buf.capacity, len + off) * 2);\\n        }\\n\\n        uint dest;\\n        uint src;\\n        assembly {\\n            // Memory address of the buffer data\\n            let bufptr := mload(buf)\\n            // Length of existing buffer data\\n            let buflen := mload(bufptr)\\n            // Start address = buffer address + offset + sizeof(buffer length)\\n            dest := add(add(bufptr, 32), off)\\n            // Update buffer length if we're extending it\\n            if gt(add(len, off), buflen) {\\n                mstore(bufptr, add(len, off))\\n            }\\n            src := add(data, 32)\\n        }\\n\\n        // Copy word-length chunks while possible\\n        for (; len >= 32; len -= 32) {\\n            assembly {\\n                mstore(dest, mload(src))\\n            }\\n            dest += 32;\\n            src += 32;\\n        }\\n\\n        // Copy remaining bytes\\n        unchecked {\\n            uint mask = (256 ** (32 - len)) - 1;\\n            assembly {\\n                let srcpart := and(mload(src), not(mask))\\n                let destpart := and(mload(dest), mask)\\n                mstore(dest, or(destpart, srcpart))\\n            }\\n        }\\n\\n        return buf;\\n    }\\n\\n    /**\\n    * @dev Appends a byte string to a buffer. Resizes if doing so would exceed\\n    *      the capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param data The data to append.\\n    * @param len The number of bytes to copy.\\n    * @return The original buffer, for chaining.\\n    */\\n    function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) {\\n        return write(buf, buf.buf.length, data, len);\\n    }\\n\\n    /**\\n    * @dev Appends a byte string to a buffer. Resizes if doing so would exceed\\n    *      the capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param data The data to append.\\n    * @return The original buffer, for chaining.\\n    */\\n    function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {\\n        return write(buf, buf.buf.length, data, data.length);\\n    }\\n\\n    /**\\n    * @dev Writes a byte to the buffer. Resizes if doing so would exceed the\\n    *      capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param off The offset to write the byte at.\\n    * @param data The data to append.\\n    * @return The original buffer, for chaining.\\n    */\\n    function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) {\\n        if (off >= buf.capacity) {\\n            resize(buf, buf.capacity * 2);\\n        }\\n\\n        assembly {\\n            // Memory address of the buffer data\\n            let bufptr := mload(buf)\\n            // Length of existing buffer data\\n            let buflen := mload(bufptr)\\n            // Address = buffer address + sizeof(buffer length) + off\\n            let dest := add(add(bufptr, off), 32)\\n            mstore8(dest, data)\\n            // Update buffer length if we extended it\\n            if eq(off, buflen) {\\n                mstore(bufptr, add(buflen, 1))\\n            }\\n        }\\n        return buf;\\n    }\\n\\n    /**\\n    * @dev Appends a byte to the buffer. Resizes if doing so would exceed the\\n    *      capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param data The data to append.\\n    * @return The original buffer, for chaining.\\n    */\\n    function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {\\n        return writeUint8(buf, buf.buf.length, data);\\n    }\\n\\n    /**\\n    * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would\\n    *      exceed the capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param off The offset to write at.\\n    * @param data The data to append.\\n    * @param len The number of bytes to write (left-aligned).\\n    * @return The original buffer, for chaining.\\n    */\\n    function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) {\\n        if (len + off > buf.capacity) {\\n            resize(buf, (len + off) * 2);\\n        }\\n\\n        unchecked {\\n            uint mask = (256 ** len) - 1;\\n            // Right-align data\\n            data = data >> (8 * (32 - len));\\n            assembly {\\n                // Memory address of the buffer data\\n                let bufptr := mload(buf)\\n                // Address = buffer address + sizeof(buffer length) + off + len\\n                let dest := add(add(bufptr, off), len)\\n                mstore(dest, or(and(mload(dest), not(mask)), data))\\n                // Update buffer length if we extended it\\n                if gt(add(off, len), mload(bufptr)) {\\n                    mstore(bufptr, add(off, len))\\n                }\\n            }\\n        }\\n        return buf;\\n    }\\n\\n    /**\\n    * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the\\n    *      capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param off The offset to write at.\\n    * @param data The data to append.\\n    * @return The original buffer, for chaining.\\n    */\\n    function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) {\\n        return write(buf, off, bytes32(data), 20);\\n    }\\n\\n    /**\\n    * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed\\n    *      the capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param data The data to append.\\n    * @return The original buffer, for chhaining.\\n    */\\n    function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {\\n        return write(buf, buf.buf.length, bytes32(data), 20);\\n    }\\n\\n    /**\\n    * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed\\n    *      the capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param data The data to append.\\n    * @return The original buffer, for chaining.\\n    */\\n    function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {\\n        return write(buf, buf.buf.length, data, 32);\\n    }\\n\\n    /**\\n    * @dev Writes an integer to the buffer. Resizes if doing so would exceed\\n    *      the capacity of the buffer.\\n    * @param buf The buffer to append to.\\n    * @param off The offset to write at.\\n    * @param data The data to append.\\n    * @param len The number of bytes to write (right-aligned).\\n    * @return The original buffer, for chaining.\\n    */\\n    function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) {\\n        if (len + off > buf.capacity) {\\n            resize(buf, (len + off) * 2);\\n        }\\n\\n        uint mask = (256 ** len) - 1;\\n        assembly {\\n            // Memory address of the buffer data\\n            let bufptr := mload(buf)\\n            // Address = buffer address + off + sizeof(buffer length) + len\\n            let dest := add(add(bufptr, off), len)\\n            mstore(dest, or(and(mload(dest), not(mask)), data))\\n            // Update buffer length if we extended it\\n            if gt(add(off, len), mload(bufptr)) {\\n                mstore(bufptr, add(off, len))\\n            }\\n        }\\n        return buf;\\n    }\\n\\n    /**\\n     * @dev Appends a byte to the end of the buffer. Resizes if doing so would\\n     * exceed the capacity of the buffer.\\n     * @param buf The buffer to append to.\\n     * @param data The data to append.\\n     * @return The original buffer.\\n     */\\n    function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {\\n        return writeInt(buf, buf.buf.length, data, len);\\n    }\\n}\\n\",\"keccak256\":\"0x18e42be1a3e4f7b4442d7ab0b524af5e09163503439954faf0ab3792cce91caa\"},\"contracts/dnssec-oracle/BytesUtils.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\nlibrary BytesUtils {\\n    /*\\n    * @dev Returns the keccak-256 hash of a byte range.\\n    * @param self The byte string to hash.\\n    * @param offset The position to start hashing at.\\n    * @param len The number of bytes to hash.\\n    * @return The hash of the byte range.\\n    */\\n    function keccak(bytes memory self, uint offset, uint len) internal pure returns (bytes32 ret) {\\n        require(offset + len <= self.length);\\n        assembly {\\n            ret := keccak256(add(add(self, 32), offset), len)\\n        }\\n    }\\n\\n\\n    /*\\n    * @dev Returns a positive number if `other` comes lexicographically after\\n    *      `self`, a negative number if it comes before, or zero if the\\n    *      contents of the two bytes are equal.\\n    * @param self The first bytes to compare.\\n    * @param other The second bytes to compare.\\n    * @return The result of the comparison.\\n    */\\n    function compare(bytes memory self, bytes memory other) internal pure returns (int) {\\n        return compare(self, 0, self.length, other, 0, other.length);\\n    }\\n\\n    /*\\n    * @dev Returns a positive number if `other` comes lexicographically after\\n    *      `self`, a negative number if it comes before, or zero if the\\n    *      contents of the two bytes are equal. Comparison is done per-rune,\\n    *      on unicode codepoints.\\n    * @param self The first bytes to compare.\\n    * @param offset The offset of self.\\n    * @param len    The length of self.\\n    * @param other The second bytes to compare.\\n    * @param otheroffset The offset of the other string.\\n    * @param otherlen    The length of the other string.\\n    * @return The result of the comparison.\\n    */\\n    function compare(bytes memory self, uint offset, uint len, bytes memory other, uint otheroffset, uint otherlen) internal pure returns (int) {\\n        uint shortest = len;\\n        if (otherlen < len)\\n        shortest = otherlen;\\n\\n        uint selfptr;\\n        uint otherptr;\\n\\n        assembly {\\n            selfptr := add(self, add(offset, 32))\\n            otherptr := add(other, add(otheroffset, 32))\\n        }\\n        for (uint idx = 0; idx < shortest; idx += 32) {\\n            uint a;\\n            uint b;\\n            assembly {\\n                a := mload(selfptr)\\n                b := mload(otherptr)\\n            }\\n            if (a != b) {\\n                // Mask out irrelevant bytes and check again\\n                uint mask;\\n                if (shortest > 32) {\\n                    mask = type(uint256).max;\\n                } else {\\n                    mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);\\n                }\\n                int diff = int(a & mask) - int(b & mask);\\n                if (diff != 0)\\n                return diff;\\n            }\\n            selfptr += 32;\\n            otherptr += 32;\\n        }\\n\\n        return int(len) - int(otherlen);\\n    }\\n\\n    /*\\n    * @dev Returns true if the two byte ranges are equal.\\n    * @param self The first byte range to compare.\\n    * @param offset The offset into the first byte range.\\n    * @param other The second byte range to compare.\\n    * @param otherOffset The offset into the second byte range.\\n    * @param len The number of bytes to compare\\n    * @return True if the byte ranges are equal, false otherwise.\\n    */\\n    function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset, uint len) internal pure returns (bool) {\\n        return keccak(self, offset, len) == keccak(other, otherOffset, len);\\n    }\\n\\n    /*\\n    * @dev Returns true if the two byte ranges are equal with offsets.\\n    * @param self The first byte range to compare.\\n    * @param offset The offset into the first byte range.\\n    * @param other The second byte range to compare.\\n    * @param otherOffset The offset into the second byte range.\\n    * @return True if the byte ranges are equal, false otherwise.\\n    */\\n    function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset) internal pure returns (bool) {\\n        return keccak(self, offset, self.length - offset) == keccak(other, otherOffset, other.length - otherOffset);\\n    }\\n\\n    /*\\n    * @dev Compares a range of 'self' to all of 'other' and returns True iff\\n    *      they are equal.\\n    * @param self The first byte range to compare.\\n    * @param offset The offset into the first byte range.\\n    * @param other The second byte range to compare.\\n    * @return True if the byte ranges are equal, false otherwise.\\n    */\\n    function equals(bytes memory self, uint offset, bytes memory other) internal pure returns (bool) {\\n        return self.length >= offset + other.length && equals(self, offset, other, 0, other.length);\\n    }\\n\\n    /*\\n    * @dev Returns true if the two byte ranges are equal.\\n    * @param self The first byte range to compare.\\n    * @param other The second byte range to compare.\\n    * @return True if the byte ranges are equal, false otherwise.\\n    */\\n    function equals(bytes memory self, bytes memory other) internal pure returns(bool) {\\n        return self.length == other.length && equals(self, 0, other, 0, self.length);\\n    }\\n\\n    /*\\n    * @dev Returns the 8-bit number at the specified index of self.\\n    * @param self The byte string.\\n    * @param idx The index into the bytes\\n    * @return The specified 8 bits of the string, interpreted as an integer.\\n    */\\n    function readUint8(bytes memory self, uint idx) internal pure returns (uint8 ret) {\\n        return uint8(self[idx]);\\n    }\\n\\n    /*\\n    * @dev Returns the 16-bit number at the specified index of self.\\n    * @param self The byte string.\\n    * @param idx The index into the bytes\\n    * @return The specified 16 bits of the string, interpreted as an integer.\\n    */\\n    function readUint16(bytes memory self, uint idx) internal pure returns (uint16 ret) {\\n        require(idx + 2 <= self.length);\\n        assembly {\\n            ret := and(mload(add(add(self, 2), idx)), 0xFFFF)\\n        }\\n    }\\n\\n    /*\\n    * @dev Returns the 32-bit number at the specified index of self.\\n    * @param self The byte string.\\n    * @param idx The index into the bytes\\n    * @return The specified 32 bits of the string, interpreted as an integer.\\n    */\\n    function readUint32(bytes memory self, uint idx) internal pure returns (uint32 ret) {\\n        require(idx + 4 <= self.length);\\n        assembly {\\n            ret := and(mload(add(add(self, 4), idx)), 0xFFFFFFFF)\\n        }\\n    }\\n\\n    /*\\n    * @dev Returns the 32 byte value at the specified index of self.\\n    * @param self The byte string.\\n    * @param idx The index into the bytes\\n    * @return The specified 32 bytes of the string.\\n    */\\n    function readBytes32(bytes memory self, uint idx) internal pure returns (bytes32 ret) {\\n        require(idx + 32 <= self.length);\\n        assembly {\\n            ret := mload(add(add(self, 32), idx))\\n        }\\n    }\\n\\n    /*\\n    * @dev Returns the 32 byte value at the specified index of self.\\n    * @param self The byte string.\\n    * @param idx The index into the bytes\\n    * @return The specified 32 bytes of the string.\\n    */\\n    function readBytes20(bytes memory self, uint idx) internal pure returns (bytes20 ret) {\\n        require(idx + 20 <= self.length);\\n        assembly {\\n            ret := and(mload(add(add(self, 32), idx)), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000)\\n        }\\n    }\\n\\n    /*\\n    * @dev Returns the n byte value at the specified index of self.\\n    * @param self The byte string.\\n    * @param idx The index into the bytes.\\n    * @param len The number of bytes.\\n    * @return The specified 32 bytes of the string.\\n    */\\n    function readBytesN(bytes memory self, uint idx, uint len) internal pure returns (bytes32 ret) {\\n        require(len <= 32);\\n        require(idx + len <= self.length);\\n        assembly {\\n            let mask := not(sub(exp(256, sub(32, len)), 1))\\n            ret := and(mload(add(add(self, 32), idx)),  mask)\\n        }\\n    }\\n\\n    function memcpy(uint dest, uint src, uint len) private pure {\\n        // Copy word-length chunks while possible\\n        for (; len >= 32; len -= 32) {\\n            assembly {\\n                mstore(dest, mload(src))\\n            }\\n            dest += 32;\\n            src += 32;\\n        }\\n\\n        // Copy remaining bytes\\n        unchecked {\\n            uint mask = (256 ** (32 - len)) - 1;\\n            assembly {\\n                let srcpart := and(mload(src), not(mask))\\n                let destpart := and(mload(dest), mask)\\n                mstore(dest, or(destpart, srcpart))\\n            }\\n        }\\n    }\\n\\n    /*\\n    * @dev Copies a substring into a new byte string.\\n    * @param self The byte string to copy from.\\n    * @param offset The offset to start copying at.\\n    * @param len The number of bytes to copy.\\n    */\\n    function substring(bytes memory self, uint offset, uint len) internal pure returns(bytes memory) {\\n        require(offset + len <= self.length);\\n\\n        bytes memory ret = new bytes(len);\\n        uint dest;\\n        uint src;\\n\\n        assembly {\\n            dest := add(ret, 32)\\n            src := add(add(self, 32), offset)\\n        }\\n        memcpy(dest, src, len);\\n\\n        return ret;\\n    }\\n\\n    // Maps characters from 0x30 to 0x7A to their base32 values.\\n    // 0xFF represents invalid characters in that range.\\n    bytes constant base32HexTable = hex'00010203040506070809FFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1FFFFFFFFFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1F';\\n\\n    /**\\n     * @dev Decodes unpadded base32 data of up to one word in length.\\n     * @param self The data to decode.\\n     * @param off Offset into the string to start at.\\n     * @param len Number of characters to decode.\\n     * @return The decoded data, left aligned.\\n     */\\n    function base32HexDecodeWord(bytes memory self, uint off, uint len) internal pure returns(bytes32) {\\n        require(len <= 52);\\n\\n        uint ret = 0;\\n        uint8 decoded;\\n        for(uint i = 0; i < len; i++) {\\n            bytes1 char = self[off + i];\\n            require(char >= 0x30 && char <= 0x7A);\\n            decoded = uint8(base32HexTable[uint(uint8(char)) - 0x30]);\\n            require(decoded <= 0x20);\\n            if(i == len - 1) {\\n                break;\\n            }\\n            ret = (ret << 5) | decoded;\\n        }\\n\\n        uint bitlen = len * 5;\\n        if(len % 8 == 0) {\\n            // Multiple of 8 characters, no padding\\n            ret = (ret << 5) | decoded;\\n        } else if(len % 8 == 2) {\\n            // Two extra characters - 1 byte\\n            ret = (ret << 3) | (decoded >> 2);\\n            bitlen -= 2;\\n        } else if(len % 8 == 4) {\\n            // Four extra characters - 2 bytes\\n            ret = (ret << 1) | (decoded >> 4);\\n            bitlen -= 4;\\n        } else if(len % 8 == 5) {\\n            // Five extra characters - 3 bytes\\n            ret = (ret << 4) | (decoded >> 1);\\n            bitlen -= 1;\\n        } else if(len % 8 == 7) {\\n            // Seven extra characters - 4 bytes\\n            ret = (ret << 2) | (decoded >> 3);\\n            bitlen -= 3;\\n        } else {\\n            revert();\\n        }\\n\\n        return bytes32(ret << (256 - bitlen));\\n    }\\n}\",\"keccak256\":\"0x83315df2e54c74451577c70da2c267c3459802b08b9aeec6516302eee70f796e\"},\"contracts/dnssec-oracle/DNSSEC.sol\":{\"content\":\"pragma solidity ^0.8.4;\\npragma experimental ABIEncoderV2;\\n\\nabstract contract DNSSEC {\\n\\n    bytes public anchors;\\n\\n    struct RRSetWithSignature {\\n        bytes rrset;\\n        bytes sig;\\n    }\\n\\n    event AlgorithmUpdated(uint8 id, address addr);\\n    event DigestUpdated(uint8 id, address addr);\\n    event NSEC3DigestUpdated(uint8 id, address addr);\\n    event RRSetUpdated(bytes name, bytes rrset);\\n\\n    function submitRRSets(RRSetWithSignature[] memory input, bytes calldata proof) public virtual returns (bytes memory);\\n    function submitRRSet(RRSetWithSignature calldata input, bytes calldata proof) public virtual returns (bytes memory);\\n    function deleteRRSet(uint16 deleteType, bytes calldata deleteName, RRSetWithSignature calldata nsec, bytes calldata proof) public virtual;\\n    function deleteRRSetNSEC3(uint16 deleteType, bytes memory deleteName, RRSetWithSignature memory closestEncloser, RRSetWithSignature memory nextClosest, bytes memory dnskey) public virtual;\\n    function rrdata(uint16 dnstype, bytes calldata name) external virtual view returns (uint32, uint32, bytes20);\\n}\\n\",\"keccak256\":\"0x5b8d2391f66e878e09aa88a97fe8ea5b26604a0c0ad9247feb6124db9817f6c1\"},\"contracts/dnssec-oracle/DNSSECImpl.sol\":{\"content\":\"pragma solidity ^0.8.4;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./Owned.sol\\\";\\nimport \\\"./BytesUtils.sol\\\";\\nimport \\\"./RRUtils.sol\\\";\\nimport \\\"./DNSSEC.sol\\\";\\nimport \\\"./algorithms/Algorithm.sol\\\";\\nimport \\\"./digests/Digest.sol\\\";\\nimport \\\"./nsec3digests/NSEC3Digest.sol\\\";\\nimport \\\"@ensdomains/buffer/contracts/Buffer.sol\\\";\\n\\n/*\\n * @dev An oracle contract that verifies and stores DNSSEC-validated DNS records.\\n *\\n * TODO: Support for NSEC3 records\\n */\\ncontract DNSSECImpl is DNSSEC, Owned {\\n    using Buffer for Buffer.buffer;\\n    using BytesUtils for bytes;\\n    using RRUtils for *;\\n\\n    uint16 constant DNSCLASS_IN = 1;\\n\\n    uint16 constant DNSTYPE_NS = 2;\\n    uint16 constant DNSTYPE_SOA = 6;\\n    uint16 constant DNSTYPE_DNAME = 39;\\n    uint16 constant DNSTYPE_DS = 43;\\n    uint16 constant DNSTYPE_RRSIG = 46;\\n    uint16 constant DNSTYPE_NSEC = 47;\\n    uint16 constant DNSTYPE_DNSKEY = 48;\\n    uint16 constant DNSTYPE_NSEC3 = 50;\\n\\n    uint constant DNSKEY_FLAG_ZONEKEY = 0x100;\\n\\n    uint8 constant ALGORITHM_RSASHA256 = 8;\\n\\n    uint8 constant DIGEST_ALGORITHM_SHA256 = 2;\\n\\n    struct RRSet {\\n        uint32 inception;\\n        uint32 expiration;\\n        bytes20 hash;\\n    }\\n\\n    // (name, type) => RRSet\\n    mapping (bytes32 => mapping(uint16 => RRSet)) rrsets;\\n\\n    mapping (uint8 => Algorithm) public algorithms;\\n    mapping (uint8 => Digest) public digests;\\n    mapping (uint8 => NSEC3Digest) public nsec3Digests;\\n\\n    event Test(uint t);\\n    event Marker();\\n\\n    /**\\n     * @dev Constructor.\\n     * @param _anchors The binary format RR entries for the root DS records.\\n     */\\n    constructor(bytes memory _anchors) {\\n        // Insert the 'trust anchors' - the key hashes that start the chain\\n        // of trust for all other records.\\n        anchors = _anchors;\\n        rrsets[keccak256(hex\\\"00\\\")][DNSTYPE_DS] = RRSet({\\n            inception: uint32(0),\\n            expiration: uint32(3767581600), // May 22 2089 - the latest date we can encode as of writing this\\n            hash: bytes20(keccak256(anchors))\\n        });\\n        emit RRSetUpdated(hex\\\"00\\\", anchors);\\n    }\\n\\n    /**\\n     * @dev Sets the contract address for a signature verification algorithm.\\n     *      Callable only by the owner.\\n     * @param id The algorithm ID\\n     * @param algo The address of the algorithm contract.\\n     */\\n    function setAlgorithm(uint8 id, Algorithm algo) public owner_only {\\n        algorithms[id] = algo;\\n        emit AlgorithmUpdated(id, address(algo));\\n    }\\n\\n    /**\\n     * @dev Sets the contract address for a digest verification algorithm.\\n     *      Callable only by the owner.\\n     * @param id The digest ID\\n     * @param digest The address of the digest contract.\\n     */\\n    function setDigest(uint8 id, Digest digest) public owner_only {\\n        digests[id] = digest;\\n        emit DigestUpdated(id, address(digest));\\n    }\\n\\n    /**\\n     * @dev Sets the contract address for an NSEC3 digest algorithm.\\n     *      Callable only by the owner.\\n     * @param id The digest ID\\n     * @param digest The address of the digest contract.\\n     */\\n    function setNSEC3Digest(uint8 id, NSEC3Digest digest) public owner_only {\\n        nsec3Digests[id] = digest;\\n        emit NSEC3DigestUpdated(id, address(digest));\\n    }\\n\\n    /**\\n     * @dev Submits multiple RRSets\\n     * @param input A list of RRSets and signatures forming a chain of trust from an existing known-good record.\\n     * @param _proof The DNSKEY or DS to validate the first signature against.\\n     * @return The last RRSET submitted.\\n     */\\n    function submitRRSets(RRSetWithSignature[] memory input, bytes calldata _proof) public override returns (bytes memory) {\\n        bytes memory proof = _proof;\\n        for(uint i = 0; i < input.length; i++) {\\n            proof = _submitRRSet(input[i], proof);\\n        }\\n        return proof;\\n    }\\n\\n    /**\\n     * @dev Submits a signed set of RRs to the oracle.\\n     *\\n     * RRSETs are only accepted if they are signed with a key that is already\\n     * trusted, or if they are self-signed, and the signing key is identified by\\n     * a DS record that is already trusted.\\n     *\\n     * @param input The signed RR set. This is in the format described in section\\n     *        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature\\n     *        data, followed by a series of canonicalised RR records that the signature\\n     *        applies to.\\n     * @param proof The DNSKEY or DS to validate the signature against. Must Already\\n     *        have been submitted and proved previously.\\n     */\\n    function submitRRSet(RRSetWithSignature memory input, bytes memory proof)\\n        public override\\n        returns (bytes memory)\\n    {\\n        return _submitRRSet(input, proof);\\n    }\\n\\n    /**\\n     * @dev Deletes an RR from the oracle.\\n     *\\n     * @param deleteType The DNS record type to delete.\\n     * @param deleteName which you want to delete\\n     * @param nsec The signed NSEC RRset. This is in the format described in section\\n     *        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature\\n     *        data, followed by a series of canonicalised RR records that the signature\\n     *        applies to.\\n     */\\n    function deleteRRSet(uint16 deleteType, bytes memory deleteName, RRSetWithSignature memory nsec, bytes memory proof)\\n        public override\\n    {\\n        RRUtils.SignedSet memory rrset;\\n        rrset = validateSignedSet(nsec, proof);\\n        require(rrset.typeCovered == DNSTYPE_NSEC);\\n\\n        // Don't let someone use an old proof to delete a new name\\n        require(RRUtils.serialNumberGte(rrset.inception, rrsets[keccak256(deleteName)][deleteType].inception));\\n\\n        for (RRUtils.RRIterator memory iter = rrset.rrs(); !iter.done(); iter.next()) {\\n            // We're dealing with three names here:\\n            //   - deleteName is the name the user wants us to delete\\n            //   - nsecName is the owner name of the NSEC record\\n            //   - nextName is the next name specified in the NSEC record\\n            //\\n            // And three cases:\\n            //   - deleteName equals nsecName, in which case we can delete the\\n            //     record if it's not in the type bitmap.\\n            //   - nextName comes after nsecName, in which case we can delete\\n            //     the record if deleteName comes between nextName and nsecName.\\n            //   - nextName comes before nsecName, in which case nextName is the\\n            //     zone apex, and deleteName must come after nsecName.\\n            checkNsecName(iter, rrset.name, deleteName, deleteType);\\n            delete rrsets[keccak256(deleteName)][deleteType];\\n            return;\\n        }\\n        // We should never reach this point\\n        revert();\\n    }\\n\\n    function checkNsecName(RRUtils.RRIterator memory iter, bytes memory nsecName, bytes memory deleteName, uint16 deleteType) private pure {\\n        uint rdataOffset = iter.rdataOffset;\\n        uint nextNameLength = iter.data.nameLength(rdataOffset);\\n        uint rDataLength = iter.nextOffset - iter.rdataOffset;\\n\\n        // We assume that there is always typed bitmap after the next domain name\\n        require(rDataLength > nextNameLength);\\n\\n        int compareResult = deleteName.compareNames(nsecName);\\n        if(compareResult == 0) {\\n            // Name to delete is on the same label as the NSEC record\\n            require(!iter.data.checkTypeBitmap(rdataOffset + nextNameLength, deleteType));\\n        } else {\\n            // First check if the NSEC next name comes after the NSEC name.\\n            bytes memory nextName = iter.data.substring(rdataOffset,nextNameLength);\\n            // deleteName must come after nsecName\\n            require(compareResult > 0);\\n            if(nsecName.compareNames(nextName) < 0) {\\n                // deleteName must also come before nextName\\n                require(deleteName.compareNames(nextName) < 0);\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @dev Deletes an RR from the oracle using an NSEC3 proof.\\n     *      Deleting a record using NSEC3 requires using up to two NSEC3 records. There are two cases:\\n     *       1. The name exists, but the record type doesn't. Eg, example.com has A records but no TXT records.\\n     *       2. The name does not exist, but a parent name does.\\n     *      In the first case, we submit one NSEC3 proof in `closestEncloser` that matches the target name\\n     *      but does not have the bit for `deleteType` set in its type bitmap. In the second case, we submit\\n     *      two proofs: closestEncloser and nextClosest, that together prove that the name does not exist.\\n     *      NSEC3 records are in the format described in section 5.3.2 of RFC4035: The RRDATA section\\n     *      from the RRSIG without the signature data, followed by a series of canonicalised RR records\\n     *      that the signature applies to.\\n     *\\n     * @param deleteType The DNS record type to delete.\\n     * @param deleteName The name to delete.\\n     * @param closestEncloser An NSEC3 proof matching the closest enclosing name - that is,\\n     *        the nearest ancestor of the target name that *does* exist.\\n     * @param nextClosest An NSEC3 proof covering the next closest name. This proves that the immediate\\n     *        subdomain of the closestEncloser does not exist.\\n     * @param dnskey An encoded DNSKEY record that has already been submitted to the oracle and can be used\\n     *        to verify the signatures closestEncloserSig and nextClosestSig\\n     */\\n    function deleteRRSetNSEC3(uint16 deleteType, bytes memory deleteName, RRSetWithSignature memory closestEncloser, RRSetWithSignature memory nextClosest, bytes memory dnskey)\\n        public override\\n    {\\n        uint32 originalInception = rrsets[keccak256(deleteName)][deleteType].inception;\\n\\n        RRUtils.SignedSet memory ce = validateSignedSet(closestEncloser, dnskey);\\n        checkNSEC3Validity(ce, deleteName, originalInception);\\n\\n        RRUtils.SignedSet memory nc;\\n        if(nextClosest.rrset.length > 0) {\\n            nc = validateSignedSet(nextClosest, dnskey);\\n            checkNSEC3Validity(nc, deleteName, originalInception);\\n        }\\n\\n        RRUtils.NSEC3 memory ceNSEC3 = readNSEC3(ce);\\n        // The flags field must be 0 or 1 (RFC5155 section 8.2).\\n        require(ceNSEC3.flags & 0xfe == 0);\\n        // Check that the closest encloser is from the correct zone (RFC5155 section 8.3)\\n        // \\\"The DNAME type bit must not be set and the NS type bit may only be set if the SOA type bit is set.\\\"\\n        require(!ceNSEC3.checkTypeBitmap(DNSTYPE_DNAME) && (!ceNSEC3.checkTypeBitmap(DNSTYPE_NS) || ceNSEC3.checkTypeBitmap(DNSTYPE_SOA)));\\n\\n        // Case 1: deleteName does exist, but no records of RRTYPE deleteType do.\\n        if(isMatchingNSEC3Record(deleteType, deleteName, ce.name, ceNSEC3)) {\\n            delete rrsets[keccak256(deleteName)][deleteType];\\n        // Case 2: deleteName does not exist.\\n        } else if(isCoveringNSEC3Record(deleteName, ce.name, ceNSEC3, nc.name, readNSEC3(nc))) {\\n            delete rrsets[keccak256(deleteName)][deleteType];\\n        } else {\\n            revert();\\n        }\\n    }\\n\\n    function checkNSEC3Validity(RRUtils.SignedSet memory nsec, bytes memory deleteName, uint32 originalInception) private pure {\\n        // The records must have been signed after the record we're trying to delete\\n        require(RRUtils.serialNumberGte(nsec.inception, originalInception));\\n\\n        // The record must be an NSEC3\\n        require(nsec.typeCovered == DNSTYPE_NSEC3);\\n\\n        // nsecName is of the form <hash>.zone.xyz. <hash> is the NSEC3 hash of the entire name the NSEC3 record matches, while\\n        // zone.xyz can be any ancestor of that name. We'll check that, so someone can't use a record on foo.com\\n        // as proof of the nonexistence of bar.org.\\n        require(checkNSEC3OwnerName(nsec.name, deleteName));\\n    }\\n\\n    function isMatchingNSEC3Record(uint16 deleteType, bytes memory deleteName, bytes memory closestEncloserName, RRUtils.NSEC3 memory closestEncloser) private view returns(bool) {\\n        // Check the record matches the hashed name, but the type bitmap does not include the type\\n        if(checkNSEC3Name(closestEncloser, closestEncloserName, deleteName)) {\\n            return !closestEncloser.checkTypeBitmap(deleteType);\\n        }\\n\\n        return false;\\n    }\\n\\n    function isCoveringNSEC3Record(bytes memory deleteName, bytes memory ceName, RRUtils.NSEC3 memory ce, bytes memory ncName, RRUtils.NSEC3 memory nc) private view returns(bool) {\\n        // The flags field must be 0 or 1 (RFC5155 section 8.2).\\n        require(nc.flags & 0xfe == 0);\\n\\n        bytes32 ceNameHash = decodeOwnerNameHash(ceName);\\n        bytes32 ncNameHash = decodeOwnerNameHash(ncName);\\n\\n        uint lastOffset = 0;\\n        // Iterate over suffixes of the name to delete until one matches the closest encloser\\n        for(uint offset = deleteName.readUint8(0) + 1; offset < deleteName.length; offset += deleteName.readUint8(offset) + 1) {\\n            if(hashName(ce, deleteName.substring(offset, deleteName.length - offset)) == ceNameHash) {\\n                // Check that the next closest record encloses the name one label longer\\n                bytes32 checkHash = hashName(nc, deleteName.substring(lastOffset, deleteName.length - lastOffset));\\n                if(ncNameHash < nc.nextHashedOwnerName) {\\n                    return checkHash > ncNameHash && checkHash < nc.nextHashedOwnerName;\\n                } else {\\n                    return checkHash > ncNameHash || checkHash < nc.nextHashedOwnerName;\\n                }\\n            }\\n            lastOffset = offset;\\n        }\\n        // If we reached the root without finding a match, return false.\\n        return false;\\n    }\\n\\n    function readNSEC3(RRUtils.SignedSet memory ss) private pure returns(RRUtils.NSEC3 memory) {\\n        RRUtils.RRIterator memory iter = ss.rrs();\\n        return iter.data.readNSEC3(iter.rdataOffset, iter.nextOffset - iter.rdataOffset);\\n    }\\n\\n    function checkNSEC3Name(RRUtils.NSEC3 memory nsec, bytes memory ownerName, bytes memory deleteName) private view returns(bool) {\\n        // Compute the NSEC3 name hash of the name to delete.\\n        bytes32 deleteNameHash = hashName(nsec, deleteName);\\n\\n        // Decode the NSEC3 name hash from the first label of the NSEC3 owner name.\\n        bytes32 nsecNameHash = decodeOwnerNameHash(ownerName);\\n\\n        return deleteNameHash == nsecNameHash;\\n    }\\n\\n    function hashName(RRUtils.NSEC3 memory nsec, bytes memory name) private view returns(bytes32) {\\n        return nsec3Digests[nsec.hashAlgorithm].hash(nsec.salt, name, nsec.iterations);\\n    }\\n\\n    function decodeOwnerNameHash(bytes memory name) private pure returns(bytes32) {\\n        return name.base32HexDecodeWord(1, uint(name.readUint8(0)));\\n    }\\n\\n    function checkNSEC3OwnerName(bytes memory nsecName, bytes memory deleteName) private pure returns(bool) {\\n        uint nsecNameOffset = nsecName.readUint8(0) + 1;\\n        uint deleteNameOffset = 0;\\n        while(deleteNameOffset < deleteName.length) {\\n            if(deleteName.equals(deleteNameOffset, nsecName, nsecNameOffset)) {\\n                return true;\\n            }\\n            deleteNameOffset += deleteName.readUint8(deleteNameOffset) + 1;\\n        }\\n        return false;\\n    }\\n\\n    /**\\n     * @dev Returns data about the RRs (if any) known to this oracle with the provided type and name.\\n     * @param dnstype The DNS record type to query.\\n     * @param name The name to query, in DNS label-sequence format.\\n     * @return inception The unix timestamp (wrapped) at which the signature for this RRSET was created.\\n     * @return expiration The unix timestamp (wrapped) at which the signature for this RRSET expires.\\n     * @return hash The hash of the RRset.\\n     */\\n    function rrdata(uint16 dnstype, bytes calldata name) external override view returns (uint32, uint32, bytes20) {\\n        RRSet storage result = rrsets[keccak256(name)][dnstype];\\n        return (result.inception, result.expiration, result.hash);\\n    }\\n\\n    function _submitRRSet(RRSetWithSignature memory input, bytes memory proof) internal returns (bytes memory) {\\n        RRUtils.SignedSet memory rrset;\\n        rrset = validateSignedSet(input, proof);\\n\\n        RRSet storage storedSet = rrsets[keccak256(rrset.name)][rrset.typeCovered];\\n        if (storedSet.hash != bytes20(0)) {\\n            // To replace an existing rrset, the signature must be at least as new\\n            require(RRUtils.serialNumberGte(rrset.inception, storedSet.inception));\\n        }\\n        rrsets[keccak256(rrset.name)][rrset.typeCovered] = RRSet({\\n            inception: rrset.inception,\\n            expiration: rrset.expiration,\\n            hash: bytes20(keccak256(rrset.data))\\n        });\\n\\n        emit RRSetUpdated(rrset.name, rrset.data);\\n\\n        return rrset.data;\\n    }\\n\\n    /**\\n     * @dev Submits a signed set of RRs to the oracle.\\n     *\\n     * RRSETs are only accepted if they are signed with a key that is already\\n     * trusted, or if they are self-signed, and the signing key is identified by\\n     * a DS record that is already trusted.\\n     *\\n     * @param input The signed RR set. This is in the format described in section\\n     *        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature\\n     *        data, followed by a series of canonicalised RR records that the signature\\n     *        applies to.\\n     * @param proof The DNSKEY or DS to validate the signature against. Must Already\\n     *        have been submitted and proved previously.\\n     */\\n    function validateSignedSet(RRSetWithSignature memory input, bytes memory proof) internal view returns(RRUtils.SignedSet memory rrset) {\\n        rrset = input.rrset.readSignedSet();\\n        require(validProof(rrset.signerName, proof));\\n\\n        // Do some basic checks on the RRs and extract the name\\n        bytes memory name = validateRRs(rrset, rrset.typeCovered);\\n        require(name.labelCount(0) == rrset.labels);\\n        rrset.name = name;\\n\\n        // All comparisons involving the Signature Expiration and\\n        // Inception fields MUST use \\\"serial number arithmetic\\\", as\\n        // defined in RFC 1982\\n\\n        // o  The validator's notion of the current time MUST be less than or\\n        //    equal to the time listed in the RRSIG RR's Expiration field.\\n        require(RRUtils.serialNumberGte(rrset.expiration, uint32(block.timestamp)));\\n\\n        // o  The validator's notion of the current time MUST be greater than or\\n        //    equal to the time listed in the RRSIG RR's Inception field.\\n        require(RRUtils.serialNumberGte(uint32(block.timestamp), rrset.inception));\\n\\n        // Validate the signature\\n        verifySignature(name, rrset, input, proof);\\n\\n        return rrset;\\n    }\\n\\n    function validProof(bytes memory name, bytes memory proof) internal view returns(bool) {\\n        uint16 dnstype = proof.readUint16(proof.nameLength(0));\\n        return rrsets[keccak256(name)][dnstype].hash == bytes20(keccak256(proof));\\n    }\\n\\n    /**\\n     * @dev Validates a set of RRs.\\n     * @param rrset The RR set.\\n     * @param typecovered The type covered by the RRSIG record.\\n     */\\n    function validateRRs(RRUtils.SignedSet memory rrset, uint16 typecovered) internal pure returns (bytes memory name) {\\n        // Iterate over all the RRs\\n        for (RRUtils.RRIterator memory iter = rrset.rrs(); !iter.done(); iter.next()) {\\n            // We only support class IN (Internet)\\n            require(iter.class == DNSCLASS_IN);\\n\\n            if(name.length == 0) {\\n                name = iter.name();\\n            } else {\\n                // Name must be the same on all RRs. We do things this way to avoid copying the name\\n                // repeatedly.\\n                require(name.length == iter.data.nameLength(iter.offset));\\n                require(name.equals(0, iter.data, iter.offset, name.length));\\n            }\\n\\n            // o  The RRSIG RR's Type Covered field MUST equal the RRset's type.\\n            require(iter.dnstype == typecovered);\\n        }\\n    }\\n\\n    /**\\n     * @dev Performs signature verification.\\n     *\\n     * Throws or reverts if unable to verify the record.\\n     *\\n     * @param name The name of the RRSIG record, in DNS label-sequence format.\\n     * @param data The original data to verify.\\n     * @param proof A DS or DNSKEY record that's already verified by the oracle.\\n     */\\n    function verifySignature(bytes memory name, RRUtils.SignedSet memory rrset, RRSetWithSignature memory data, bytes memory proof) internal view {\\n        // o  The RRSIG RR's Signer's Name field MUST be the name of the zone\\n        //    that contains the RRset.\\n        require(rrset.signerName.length <= name.length);\\n        require(rrset.signerName.equals(0, name, name.length - rrset.signerName.length));\\n\\n        RRUtils.RRIterator memory proofRR = proof.iterateRRs(0);\\n        // Check the proof\\n        if (proofRR.dnstype == DNSTYPE_DS) {\\n            require(verifyWithDS(rrset, data, proofRR));\\n        } else if (proofRR.dnstype == DNSTYPE_DNSKEY) {\\n            require(verifyWithKnownKey(rrset, data, proofRR));\\n        } else {\\n            revert(\\\"No valid proof found\\\");\\n        }\\n    }\\n\\n    /**\\n     * @dev Attempts to verify a signed RRSET against an already known public key.\\n     * @param rrset The signed set to verify.\\n     * @param data The original data the signed set was read from.\\n     * @param proof The serialized DS or DNSKEY record to use as proof.\\n     * @return True if the RRSET could be verified, false otherwise.\\n     */\\n    function verifyWithKnownKey(RRUtils.SignedSet memory rrset, RRSetWithSignature memory data, RRUtils.RRIterator memory proof) internal view returns(bool) {\\n        // Check the DNSKEY's owner name matches the signer name on the RRSIG\\n        require(proof.name().equals(rrset.signerName));\\n        for(; !proof.done(); proof.next()) {\\n            require(proof.name().equals(rrset.signerName));\\n            bytes memory keyrdata = proof.rdata();\\n            RRUtils.DNSKEY memory dnskey = keyrdata.readDNSKEY(0, keyrdata.length);\\n            if(verifySignatureWithKey(dnskey, keyrdata, rrset, data)) {\\n                return true;\\n            }\\n        }\\n        return false;\\n    }\\n\\n    /**\\n     * @dev Attempts to verify some data using a provided key and a signature.\\n     * @param dnskey The dns key record to verify the signature with.\\n     * @param rrset The signed RRSET being verified.\\n     * @param data The original data `rrset` was decoded from.\\n     * @return True iff the key verifies the signature.\\n     */\\n    function verifySignatureWithKey(RRUtils.DNSKEY memory dnskey, bytes memory keyrdata, RRUtils.SignedSet memory rrset, RRSetWithSignature memory data)\\n        internal\\n        view\\n        returns (bool)\\n    {\\n        // TODO: Check key isn't expired, unless updating key itself\\n\\n        // The Protocol Field MUST have value 3 (RFC4034 2.1.2)\\n        if(dnskey.protocol != 3) {\\n            return false;\\n        }\\n\\n        // o The RRSIG RR's Signer's Name, Algorithm, and Key Tag fields MUST\\n        //   match the owner name, algorithm, and key tag for some DNSKEY RR in\\n        //   the zone's apex DNSKEY RRset.\\n        if(dnskey.algorithm != rrset.algorithm) {\\n            return false;\\n        }\\n        uint16 computedkeytag = keyrdata.computeKeytag();\\n        if (computedkeytag != rrset.keytag) {\\n            return false;\\n        }\\n\\n        // o The matching DNSKEY RR MUST be present in the zone's apex DNSKEY\\n        //   RRset, and MUST have the Zone Flag bit (DNSKEY RDATA Flag bit 7)\\n        //   set.\\n        if (dnskey.flags & DNSKEY_FLAG_ZONEKEY == 0) {\\n            return false;\\n        }\\n\\n        return algorithms[dnskey.algorithm].verify(keyrdata, data.rrset, data.sig);\\n    }\\n\\n    /**\\n     * @dev Attempts to verify a signed RRSET against an already known hash. This function assumes\\n     *      that the record \\n     * @param rrset The signed set to verify.\\n     * @param data The original data the signed set was read from.\\n     * @param proof The serialized DS or DNSKEY record to use as proof.\\n     * @return True if the RRSET could be verified, false otherwise.\\n     */\\n    function verifyWithDS(RRUtils.SignedSet memory rrset, RRSetWithSignature memory data, RRUtils.RRIterator memory proof) internal view returns(bool) {\\n        for(RRUtils.RRIterator memory iter = rrset.rrs(); !iter.done(); iter.next()) {\\n            require(iter.dnstype == DNSTYPE_DNSKEY);\\n            bytes memory keyrdata = iter.rdata();\\n            RRUtils.DNSKEY memory dnskey = keyrdata.readDNSKEY(0, keyrdata.length);\\n            if (verifySignatureWithKey(dnskey, keyrdata, rrset, data)) {\\n                // It's self-signed - look for a DS record to verify it.\\n                return verifyKeyWithDS(iter.name(), proof, dnskey, keyrdata);\\n            }\\n        }\\n        return false;\\n    }\\n\\n    /**\\n     * @dev Attempts to verify a key using DS records.\\n     * @param keyname The DNS name of the key, in DNS label-sequence format.\\n     * @param dsrrs The DS records to use in verification.\\n     * @param dnskey The dnskey to verify.\\n     * @param keyrdata The RDATA section of the key.\\n     * @return True if a DS record verifies this key.\\n     */\\n    function verifyKeyWithDS(bytes memory keyname, RRUtils.RRIterator memory dsrrs, RRUtils.DNSKEY memory dnskey, bytes memory keyrdata)\\n        internal view returns (bool)\\n    {\\n        uint16 keytag = keyrdata.computeKeytag();\\n        for (; !dsrrs.done(); dsrrs.next()) {\\n            RRUtils.DS memory ds = dsrrs.data.readDS(dsrrs.rdataOffset, dsrrs.nextOffset - dsrrs.rdataOffset);\\n            if(ds.keytag != keytag) {\\n                continue;\\n            }\\n            if (ds.algorithm != dnskey.algorithm) {\\n                continue;\\n            }\\n\\n            Buffer.buffer memory buf;\\n            buf.init(keyname.length + keyrdata.length);\\n            buf.append(keyname);\\n            buf.append(keyrdata);\\n            if (verifyDSHash(ds.digestType, buf.buf, ds.digest)) {\\n                return true;\\n            }\\n        }\\n        return false;\\n    }\\n\\n    /**\\n     * @dev Attempts to verify a DS record's hash value against some data.\\n     * @param digesttype The digest ID from the DS record.\\n     * @param data The data to digest.\\n     * @param digest The digest data to check against.\\n     * @return True iff the digest matches.\\n     */\\n    function verifyDSHash(uint8 digesttype, bytes memory data, bytes memory digest) internal view returns (bool) {\\n        if (address(digests[digesttype]) == address(0)) {\\n            return false;\\n        }\\n        return digests[digesttype].verify(data, digest);\\n    }\\n}\\n\",\"keccak256\":\"0x347fdc38971b863831f00f0e5a8e791ace9dda1196da57fbf726a125c9d99a04\"},\"contracts/dnssec-oracle/Owned.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\n/**\\n* @dev Contract mixin for 'owned' contracts.\\n*/\\ncontract Owned {\\n    address public owner;\\n    \\n    modifier owner_only() {\\n        require(msg.sender == owner);\\n        _;\\n    }\\n\\n    constructor() public {\\n        owner = msg.sender;\\n    }\\n\\n    function setOwner(address newOwner) public owner_only {\\n        owner = newOwner;\\n    }\\n}\\n\",\"keccak256\":\"0x14ca1cbae3a361b9d868147498af8bdea7e7d5b0829e207fb7719f607cce5ab3\"},\"contracts/dnssec-oracle/RRUtils.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\nimport \\\"./BytesUtils.sol\\\";\\nimport \\\"@ensdomains/buffer/contracts/Buffer.sol\\\";\\n\\n/**\\n* @dev RRUtils is a library that provides utilities for parsing DNS resource records.\\n*/\\nlibrary RRUtils {\\n    using BytesUtils for *;\\n    using Buffer for *;\\n\\n    /**\\n    * @dev Returns the number of bytes in the DNS name at 'offset' in 'self'.\\n    * @param self The byte array to read a name from.\\n    * @param offset The offset to start reading at.\\n    * @return The length of the DNS name at 'offset', in bytes.\\n    */\\n    function nameLength(bytes memory self, uint offset) internal pure returns(uint) {\\n        uint idx = offset;\\n        while (true) {\\n            assert(idx < self.length);\\n            uint labelLen = self.readUint8(idx);\\n            idx += labelLen + 1;\\n            if (labelLen == 0) {\\n                break;\\n            }\\n        }\\n        return idx - offset;\\n    }\\n\\n    /**\\n    * @dev Returns a DNS format name at the specified offset of self.\\n    * @param self The byte array to read a name from.\\n    * @param offset The offset to start reading at.\\n    * @return ret The name.\\n    */\\n    function readName(bytes memory self, uint offset) internal pure returns(bytes memory ret) {\\n        uint len = nameLength(self, offset);\\n        return self.substring(offset, len);\\n    }\\n\\n    /**\\n    * @dev Returns the number of labels in the DNS name at 'offset' in 'self'.\\n    * @param self The byte array to read a name from.\\n    * @param offset The offset to start reading at.\\n    * @return The number of labels in the DNS name at 'offset', in bytes.\\n    */\\n    function labelCount(bytes memory self, uint offset) internal pure returns(uint) {\\n        uint count = 0;\\n        while (true) {\\n            assert(offset < self.length);\\n            uint labelLen = self.readUint8(offset);\\n            offset += labelLen + 1;\\n            if (labelLen == 0) {\\n                break;\\n            }\\n            count += 1;\\n        }\\n        return count;\\n    }\\n\\n    uint constant RRSIG_TYPE = 0;\\n    uint constant RRSIG_ALGORITHM = 2;\\n    uint constant RRSIG_LABELS = 3;\\n    uint constant RRSIG_TTL = 4;\\n    uint constant RRSIG_EXPIRATION = 8;\\n    uint constant RRSIG_INCEPTION = 12;\\n    uint constant RRSIG_KEY_TAG = 16;\\n    uint constant RRSIG_SIGNER_NAME = 18;\\n\\n    struct SignedSet {\\n        uint16 typeCovered;\\n        uint8 algorithm;\\n        uint8 labels;\\n        uint32 ttl;\\n        uint32 expiration;\\n        uint32 inception;\\n        uint16 keytag;\\n        bytes signerName;\\n        bytes data;\\n        bytes name;\\n    }\\n\\n    function readSignedSet(bytes memory data) internal pure returns(SignedSet memory self) {\\n        self.typeCovered = data.readUint16(RRSIG_TYPE);\\n        self.algorithm = data.readUint8(RRSIG_ALGORITHM);\\n        self.labels = data.readUint8(RRSIG_LABELS);\\n        self.ttl = data.readUint32(RRSIG_TTL);\\n        self.expiration = data.readUint32(RRSIG_EXPIRATION);\\n        self.inception = data.readUint32(RRSIG_INCEPTION);\\n        self.keytag = data.readUint16(RRSIG_KEY_TAG);\\n        self.signerName = readName(data, RRSIG_SIGNER_NAME);\\n        self.data = data.substring(RRSIG_SIGNER_NAME + self.signerName.length, data.length - RRSIG_SIGNER_NAME - self.signerName.length);\\n    }\\n\\n    function rrs(SignedSet memory rrset) internal pure returns(RRIterator memory) {\\n        return iterateRRs(rrset.data, 0);\\n    }\\n\\n    /**\\n    * @dev An iterator over resource records.\\n    */\\n    struct RRIterator {\\n        bytes data;\\n        uint offset;\\n        uint16 dnstype;\\n        uint16 class;\\n        uint32 ttl;\\n        uint rdataOffset;\\n        uint nextOffset;\\n    }\\n\\n    /**\\n    * @dev Begins iterating over resource records.\\n    * @param self The byte string to read from.\\n    * @param offset The offset to start reading at.\\n    * @return ret An iterator object.\\n    */\\n    function iterateRRs(bytes memory self, uint offset) internal pure returns (RRIterator memory ret) {\\n        ret.data = self;\\n        ret.nextOffset = offset;\\n        next(ret);\\n    }\\n\\n    /**\\n    * @dev Returns true iff there are more RRs to iterate.\\n    * @param iter The iterator to check.\\n    * @return True iff the iterator has finished.\\n    */\\n    function done(RRIterator memory iter) internal pure returns(bool) {\\n        return iter.offset >= iter.data.length;\\n    }\\n\\n    /**\\n    * @dev Moves the iterator to the next resource record.\\n    * @param iter The iterator to advance.\\n    */\\n    function next(RRIterator memory iter) internal pure {\\n        iter.offset = iter.nextOffset;\\n        if (iter.offset >= iter.data.length) {\\n            return;\\n        }\\n\\n        // Skip the name\\n        uint off = iter.offset + nameLength(iter.data, iter.offset);\\n\\n        // Read type, class, and ttl\\n        iter.dnstype = iter.data.readUint16(off);\\n        off += 2;\\n        iter.class = iter.data.readUint16(off);\\n        off += 2;\\n        iter.ttl = iter.data.readUint32(off);\\n        off += 4;\\n\\n        // Read the rdata\\n        uint rdataLength = iter.data.readUint16(off);\\n        off += 2;\\n        iter.rdataOffset = off;\\n        iter.nextOffset = off + rdataLength;\\n    }\\n\\n    /**\\n    * @dev Returns the name of the current record.\\n    * @param iter The iterator.\\n    * @return A new bytes object containing the owner name from the RR.\\n    */\\n    function name(RRIterator memory iter) internal pure returns(bytes memory) {\\n        return iter.data.substring(iter.offset, nameLength(iter.data, iter.offset));\\n    }\\n\\n    /**\\n    * @dev Returns the rdata portion of the current record.\\n    * @param iter The iterator.\\n    * @return A new bytes object containing the RR's RDATA.\\n    */\\n    function rdata(RRIterator memory iter) internal pure returns(bytes memory) {\\n        return iter.data.substring(iter.rdataOffset, iter.nextOffset - iter.rdataOffset);\\n    }\\n\\n    uint constant DNSKEY_FLAGS = 0;\\n    uint constant DNSKEY_PROTOCOL = 2;\\n    uint constant DNSKEY_ALGORITHM = 3;\\n    uint constant DNSKEY_PUBKEY = 4;\\n\\n    struct DNSKEY {\\n        uint16 flags;\\n        uint8 protocol;\\n        uint8 algorithm;\\n        bytes publicKey;\\n    }\\n\\n    function readDNSKEY(bytes memory data, uint offset, uint length) internal pure returns(DNSKEY memory self) {\\n        self.flags = data.readUint16(offset + DNSKEY_FLAGS);\\n        self.protocol = data.readUint8(offset + DNSKEY_PROTOCOL);\\n        self.algorithm = data.readUint8(offset + DNSKEY_ALGORITHM);\\n        self.publicKey = data.substring(offset + DNSKEY_PUBKEY, length - DNSKEY_PUBKEY);\\n    } \\n\\n    uint constant DS_KEY_TAG = 0;\\n    uint constant DS_ALGORITHM = 2;\\n    uint constant DS_DIGEST_TYPE = 3;\\n    uint constant DS_DIGEST = 4;\\n\\n    struct DS {\\n        uint16 keytag;\\n        uint8 algorithm;\\n        uint8 digestType;\\n        bytes digest;\\n    }\\n\\n    function readDS(bytes memory data, uint offset, uint length) internal pure returns(DS memory self) {\\n        self.keytag = data.readUint16(offset + DS_KEY_TAG);\\n        self.algorithm = data.readUint8(offset + DS_ALGORITHM);\\n        self.digestType = data.readUint8(offset + DS_DIGEST_TYPE);\\n        self.digest = data.substring(offset + DS_DIGEST, length - DS_DIGEST);\\n    }\\n\\n    struct NSEC3 {\\n        uint8 hashAlgorithm;\\n        uint8 flags;\\n        uint16 iterations;\\n        bytes salt;\\n        bytes32 nextHashedOwnerName;\\n        bytes typeBitmap;\\n    }\\n\\n    uint constant NSEC3_HASH_ALGORITHM = 0;\\n    uint constant NSEC3_FLAGS = 1;\\n    uint constant NSEC3_ITERATIONS = 2;\\n    uint constant NSEC3_SALT_LENGTH = 4;\\n    uint constant NSEC3_SALT = 5;\\n\\n    function readNSEC3(bytes memory data, uint offset, uint length) internal pure returns(NSEC3 memory self) {\\n        uint end = offset + length;\\n        self.hashAlgorithm = data.readUint8(offset + NSEC3_HASH_ALGORITHM);\\n        self.flags = data.readUint8(offset + NSEC3_FLAGS);\\n        self.iterations = data.readUint16(offset + NSEC3_ITERATIONS);\\n        uint8 saltLength = data.readUint8(offset + NSEC3_SALT_LENGTH);\\n        offset = offset + NSEC3_SALT;\\n        self.salt = data.substring(offset, saltLength);\\n        offset += saltLength;\\n        uint8 nextLength = data.readUint8(offset);\\n        require(nextLength <= 32);\\n        offset += 1;\\n        self.nextHashedOwnerName = data.readBytesN(offset, nextLength);\\n        offset += nextLength;\\n        self.typeBitmap = data.substring(offset, end - offset);\\n    }\\n\\n    function checkTypeBitmap(NSEC3 memory self, uint16 rrtype) internal pure returns(bool) {\\n        return checkTypeBitmap(self.typeBitmap, 0, rrtype);\\n    }\\n\\n    /**\\n    * @dev Checks if a given RR type exists in a type bitmap.\\n    * @param bitmap The byte string to read the type bitmap from.\\n    * @param offset The offset to start reading at.\\n    * @param rrtype The RR type to check for.\\n    * @return True if the type is found in the bitmap, false otherwise.\\n    */\\n    function checkTypeBitmap(bytes memory bitmap, uint offset, uint16 rrtype) internal pure returns (bool) {\\n        uint8 typeWindow = uint8(rrtype >> 8);\\n        uint8 windowByte = uint8((rrtype & 0xff) / 8);\\n        uint8 windowBitmask = uint8(uint8(1) << (uint8(7) - uint8(rrtype & 0x7)));\\n        for (uint off = offset; off < bitmap.length;) {\\n            uint8 window = bitmap.readUint8(off);\\n            uint8 len = bitmap.readUint8(off + 1);\\n            if (typeWindow < window) {\\n                // We've gone past our window; it's not here.\\n                return false;\\n            } else if (typeWindow == window) {\\n                // Check this type bitmap\\n                if (len <= windowByte) {\\n                    // Our type is past the end of the bitmap\\n                    return false;\\n                }\\n                return (bitmap.readUint8(off + windowByte + 2) & windowBitmask) != 0;\\n            } else {\\n                // Skip this type bitmap\\n                off += len + 2;\\n            }\\n        }\\n\\n        return false;\\n    }\\n\\n    function compareNames(bytes memory self, bytes memory other) internal pure returns (int) {\\n        if (self.equals(other)) {\\n            return 0;\\n        }\\n\\n        uint off;\\n        uint otheroff;\\n        uint prevoff;\\n        uint otherprevoff;\\n        uint counts = labelCount(self, 0);\\n        uint othercounts = labelCount(other, 0);\\n\\n        // Keep removing labels from the front of the name until both names are equal length\\n        while (counts > othercounts) {\\n            prevoff = off;\\n            off = progress(self, off);\\n            counts--;\\n        }\\n\\n        while (othercounts > counts) {\\n            otherprevoff = otheroff;\\n            otheroff = progress(other, otheroff);\\n            othercounts--;\\n        }\\n\\n        // Compare the last nonequal labels to each other\\n        while (counts > 0 && !self.equals(off, other, otheroff)) {\\n            prevoff = off;\\n            off = progress(self, off);\\n            otherprevoff = otheroff;\\n            otheroff = progress(other, otheroff);\\n            counts -= 1;\\n        }\\n\\n        if (off == 0) {\\n            return -1;\\n        }\\n        if(otheroff == 0) {\\n            return 1;\\n        }\\n\\n        return self.compare(prevoff + 1, self.readUint8(prevoff), other, otherprevoff + 1, other.readUint8(otherprevoff));\\n    }\\n\\n    /**\\n     * @dev Compares two serial numbers using RFC1982 serial number math.\\n     */\\n    function serialNumberGte(uint32 i1, uint32 i2) internal pure returns(bool) {\\n        return int32(i1) - int32(i2) >= 0;\\n    }\\n\\n    function progress(bytes memory body, uint off) internal pure returns(uint) {\\n        return off + 1 + body.readUint8(off);\\n    }\\n\\n    /**\\n     * @dev Computes the keytag for a chunk of data.\\n     * @param data The data to compute a keytag for.\\n     * @return The computed key tag.\\n     */\\n    function computeKeytag(bytes memory data) internal pure returns (uint16) {\\n        /* This function probably deserves some explanation.\\n         * The DNSSEC keytag function is a checksum that relies on summing up individual bytes\\n         * from the input string, with some mild bitshifting. Here's a Naive solidity implementation:\\n         *\\n         *     function computeKeytag(bytes memory data) internal pure returns (uint16) {\\n         *         uint ac;\\n         *         for (uint i = 0; i < data.length; i++) {\\n         *             ac += i & 1 == 0 ? uint16(data.readUint8(i)) << 8 : data.readUint8(i);\\n         *         }\\n         *         return uint16(ac + (ac >> 16));\\n         *     }\\n         *\\n         * The EVM, with its 256 bit words, is exceedingly inefficient at doing byte-by-byte operations;\\n         * the code above, on reasonable length inputs, consumes over 100k gas. But we can make the EVM's\\n         * large words work in our favour.\\n         *\\n         * The code below works by treating the input as a series of 256 bit words. It first masks out\\n         * even and odd bytes from each input word, adding them to two separate accumulators `ac1` and `ac2`.\\n         * The bytes are separated by empty bytes, so as long as no individual sum exceeds 2^16-1, we're\\n         * effectively summing 16 different numbers with each EVM ADD opcode.\\n         *\\n         * Once it's added up all the inputs, it has to add all the 16 bit values in `ac1` and `ac2` together.\\n         * It does this using the same trick - mask out every other value, shift to align them, add them together.\\n         * After the first addition on both accumulators, there's enough room to add the two accumulators together,\\n         * and the remaining sums can be done just on ac1.\\n         */\\n        unchecked {\\n            require(data.length <= 8192, \\\"Long keys not permitted\\\");\\n            uint ac1;\\n            uint ac2;\\n            for(uint i = 0; i < data.length + 31; i += 32) {\\n                uint word;\\n                assembly {\\n                    word := mload(add(add(data, 32), i))\\n                }\\n                if(i + 32 > data.length) {\\n                    uint unused = 256 - (data.length - i) * 8;\\n                    word = (word >> unused) << unused;\\n                }\\n                ac1 += (word & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8;\\n                ac2 += (word & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF);\\n            }\\n            ac1 = (ac1 & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF)\\n                + ((ac1 & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16);\\n            ac2 = (ac2 & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF)\\n                + ((ac2 & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16);\\n            ac1 = (ac1 << 8) + ac2;\\n            ac1 = (ac1 & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF)\\n                + ((ac1 & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32);\\n            ac1 = (ac1 & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF)\\n                + ((ac1 & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64);\\n            ac1 = (ac1 & 0x00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)\\n                + (ac1 >> 128);\\n            ac1 += (ac1 >> 16) & 0xFFFF;\\n            return uint16(ac1);\\n        }\\n    }\\n}\",\"keccak256\":\"0x811642c86c539d645ef99a15fa1bf0eb4ce963cf1a618ef2a6f34d27a5e34030\"},\"contracts/dnssec-oracle/algorithms/Algorithm.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\n/**\\n* @dev An interface for contracts implementing a DNSSEC (signing) algorithm.\\n*/\\ninterface Algorithm {\\n    /**\\n    * @dev Verifies a signature.\\n    * @param key The public key to verify with.\\n    * @param data The signed data to verify.\\n    * @param signature The signature to verify.\\n    * @return True iff the signature is valid.\\n    */\\n    function verify(bytes calldata key, bytes calldata data, bytes calldata signature) external virtual view returns (bool);\\n}\\n\",\"keccak256\":\"0x51d6251568844e435f58952354abe8c8c8e978ab40ecb0bbb2f5bd767838b3a7\"},\"contracts/dnssec-oracle/digests/Digest.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\n/**\\n* @dev An interface for contracts implementing a DNSSEC digest.\\n*/\\ninterface Digest {\\n    /**\\n    * @dev Verifies a cryptographic hash.\\n    * @param data The data to hash.\\n    * @param hash The hash to compare to.\\n    * @return True iff the hashed data matches the provided hash value.\\n    */\\n    function verify(bytes calldata data, bytes calldata hash) external virtual pure returns (bool);\\n}\\n\",\"keccak256\":\"0x259720cef78c019d38b908bc7dd524f087c58d8c40792cebcdd4e982c628bc9a\"},\"contracts/dnssec-oracle/nsec3digests/NSEC3Digest.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\n/**\\n * @dev Interface for contracts that implement NSEC3 digest algorithms.\\n */\\ninterface NSEC3Digest {\\n    /**\\n     * @dev Performs an NSEC3 iterated hash.\\n     * @param salt The salt value to use on each iteration.\\n     * @param data The data to hash.\\n     * @param iterations The number of iterations to perform.\\n     * @return The result of the iterated hash operation.\\n     */\\n     function hash(bytes calldata salt, bytes calldata data, uint iterations) external virtual pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xb3b61aee6bb472158b7ace6b5644dcb668271296b98a6dcde24dc72e3cdf4950\"}},\"version\":1}",
  "bytecode": "0x60806040523480156200001157600080fd5b5060405162003a4c38038062003a4c833981016040819052620000349162000226565b600180546001600160a01b0319163317905580516200005b90600090602084019062000180565b5060408051606081018252600080825263e090bba0602083015282519192830191620000889190620002fc565b60408051918290039091206001600160601b031916909152602b60009081527fc92a43746f20f69898978a3075767b860ba247ac0639d1831bf8c942c5db2389602090815283517f95c6356c1b7a542b884d2484ef785c9c7224e77e1016c20007bddc15c23b452f8054928601519585015160601c6801000000000000000002600160401b600160e01b031963ffffffff978816640100000000026001600160401b03199095169790931696909617929092171693909317909255517f55ced933cdd5a34dd03eb5d4bef19ec6ebb251dcd7a988eee0c1b9a13baaa88b91620001719162000373565b60405180910390a15062000463565b8280546200018e9062000410565b90600052602060002090601f016020900481019282620001b25760008555620001fd565b82601f10620001cd57805160ff1916838001178555620001fd565b82800160010185558215620001fd579182015b82811115620001fd578251825591602001919060010190620001e0565b506200020b9291506200020f565b5090565b5b808211156200020b576000815560010162000210565b6000602080838503121562000239578182fd5b82516001600160401b038082111562000250578384fd5b818501915085601f83011262000264578384fd5b8151818111156200027957620002796200044d565b604051601f8201601f19908116603f01168101908382118183101715620002a457620002a46200044d565b816040528281528886848701011115620002bc578687fd5b8693505b82841015620002df5784840186015181850187015292850192620002c0565b82841115620002f057868684830101525b98975050505050505050565b60008083546200030c8162000410565b60018281168015620003275760018114620003395762000367565b60ff1984168752828701945062000367565b8786526020808720875b858110156200035e5781548a82015290840190820162000343565b50505082870194505b50929695505050505050565b604081526000600180604084015281606084015260206080818501528285546200039d8162000410565b80608088015260a085831660008114620003c05760018114620003d55762000402565b60ff1984168983015260c08901945062000402565b898852858820885b84811015620003fa5781548b8201850152908801908701620003dd565b8a0183019550505b509298975050505050505050565b600181811c908216806200042557607f821691505b602082108114156200044757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b6135d980620004736000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806373cc48a61161008c57806398d35f201161006657806398d35f201461025b578063bd7ed31a14610263578063c327deef14610299578063d7b82ebe146102cf57600080fd5b806373cc48a6146101cd5780638438dc04146102285780638da5cb5b1461023b57600080fd5b806313af4035116100c857806313af40351461017457806328e7677d146101875780632c095cbb1461019a578063435cc162146101ad57600080fd5b8063020ed8d3146100ef578063087991bc146101045780630b1a249514610161575b600080fd5b6101026100fd366004612ff3565b6102e2565b005b610117610112366004612e47565b610396565b6040805163ffffffff94851681529390921660208401527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016908201526060015b60405180910390f35b61010261016f366004612f20565b61040b565b610102610182366004612ca9565b6105fa565b610102610195366004612ff3565b610665565b6101026101a8366004612e8b565b610711565b6101c06101bb366004612cc5565b61084f565b60405161015891906130a2565b6102036101db366004612fd9565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610158565b610102610236366004612ff3565b6108fe565b6001546102039073ffffffffffffffffffffffffffffffffffffffff1681565b6101c06109aa565b610203610271366004612fd9565b60056020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6102036102a7366004612fd9565b60036020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6101c06102dd366004612de6565b610a38565b60015473ffffffffffffffffffffffffffffffffffffffff16331461030657600080fd5b60ff821660008181526003602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251938452908301527ff73c3c226af96b7f1ba666a21b3ceaf2be3ee6a365e3178fd9cd1eaae0075aa891015b60405180910390a15050565b6000806000806002600087876040516103b0929190613092565b60408051918290039091208252602080830193909352908101600090812061ffff8b16825290925290205463ffffffff8082169550640100000000820416935068010000000000000000900460601b91505093509350939050565b8351602080860191909120600090815260028252604080822061ffff891683529092529081205463ffffffff16906104438584610a4d565b9050610450818784610b3e565b604080516101408101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e081018290526101008101829052610120810191909152845151156104c2576104b58585610a4d565b90506104c2818885610b3e565b60006104cd83610b84565b602081015190915060fe16156104e257600080fd5b6104ed816027610be3565b1580156105125750610500816002610be3565b15806105125750610512816006610be3565b61051b57600080fd5b61052c898985610120015184610bf5565b156105805787516020808a0191909120600090815260028252604080822061ffff8d1683529092522080547fffffffff000000000000000000000000000000000000000000000000000000001690556105ef565b61059f888461012001518385610120015161059a87610b84565b610c25565b156100ea5787516020808a0191909120600090815260028252604080822061ffff8d1683529092522080547fffffffff000000000000000000000000000000000000000000000000000000001690555b505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461061e57600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff16331461068957600080fd5b60ff821660008181526004602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251938452908301527f2fcc274c3b72dd483ab201bfa87295e3817e8b9b10693219873b722ca1af00c7910161038a565b604080516101408101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e08101829052610100810182905261012081019190915261076e8383610a4d565b805190915061ffff16602f1461078357600080fd5b60a08101518451602080870191909120600090815260028252604080822061ffff8a16835290925220546107bd919063ffffffff16610d41565b6107c657600080fd5b60006107d182610d5a565b905080515160208201511015610843576107f2818361012001518789610db8565b50508251602080850191909120600090815260028252604080822061ffff881683529092522080547fffffffff00000000000000000000000000000000000000000000000000000000169055610849565b50600080fd5b50505050565b6060600083838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b85518110156108f3576108df8682815181106108d1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015183610f63565b9150806108eb8161347b565b91505061088c565b5090505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461092257600080fd5b60ff821660008181526005602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251938452908301527fc7eec866a7a1386188cc3ca20ffea75b71bd3e90a60b6791b1d3f0971145118d910161038a565b600080546109b79061342d565b80601f01602080910402602001604051908101604052809291908181526020018280546109e39061342d565b8015610a305780601f10610a0557610100808354040283529160200191610a30565b820191906000526020600020905b815481529060010190602001808311610a1357829003601f168201915b505050505081565b6060610a448383610f63565b90505b92915050565b604080516101408101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e0810182905261010081018290526101208101919091528251610aab9061118b565b9050610abb8160e00151836112cd565b610ac457600080fd5b6000610ad4828360000151611352565b604083015190915060ff16610aea8260006113fd565b14610af457600080fd5b61012082018190526080820151610b0b9042610d41565b610b1457600080fd5b610b22428360a00151610d41565b610b2b57600080fd5b610b378183868661147e565b5092915050565b610b4c8360a0015182610d41565b610b5557600080fd5b825161ffff16603214610b6757600080fd5b610b7683610120015183611582565b610b7f57600080fd5b505050565b6040805160c08101825260008082526020820181905291810182905260608082018190526080820183905260a082015290610bbe83610d5a565b60a081015160c08201519192506108f791610bda9082906133dc565b835191906115f0565b6000610a448360a00151600084611737565b6000610c0282848661184d565b15610c1957610c118286610be3565b159050610c1d565b5060005b949350505050565b602081015160009060fe1615610c3a57600080fd5b6000610c4586611874565b90506000610c5285611874565b9050600080610c618a82611890565b610c6c9060016131b4565b60ff1690505b8951811015610d2f5783610c9e89610c9984858f51610c9191906133dc565b8f91906118db565b611984565b1415610d03576000610cbb87610c9985868f51610c9191906133dc565b90508660800151841015610ce7578381118015610cdb5750866080015181105b95505050505050610d38565b83811180610cdb57508660800151811095505050505050610d38565b905080610d108a82611890565b610d1b9060016131b4565b610d289060ff168261319c565b9050610c72565b50600093505050505b95945050505050565b600080610d4e8385613378565b60030b12159392505050565b610da86040518060e001604052806060815260200160008152602001600061ffff168152602001600061ffff168152602001600063ffffffff16815260200160008152602001600081525090565b610a478261010001516000611a45565b60a08401518451600090610dcc9083611aa6565b905060008660a001518760c00151610de491906133dc565b9050818111610df257600080fd5b6000610dfe8688611b24565b905080610e2a57610e1b610e12848661319c565b89519087611737565b15610e2557600080fd5b610e71565b8751600090610e3a9086866118db565b905060008213610e4957600080fd5b6000610e558983611b24565b12156105ef576000610e678883611b24565b126105ef57600080fd5b5050505050505050565b60c08101516020820181905281515111610e925750565b6000610ea682600001518360200151611aa6565b8260200151610eb5919061319c565b8251909150610ec49082611c77565b61ffff166040830152610ed860028261319c565b8251909150610ee79082611c77565b61ffff166060830152610efb60028261319c565b8251909150610f0a9082611c9f565b63ffffffff166080830152610f2060048261319c565b8251909150600090610f329083611c77565b61ffff169050610f4360028361319c565b60a084018190529150610f56818361319c565b60c0909301929092525050565b604080516101408101825260008082526020820181905291810182905260608181018390526080820183905260a0820183905260c082019290925260e0810182905261010081018290526101208101829052610fbf8484610a4d565b61012081015180516020918201206000908152600282526040808220845161ffff1683529092522080549192509068010000000000000000900460601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016156110435760a0820151815461103a919063ffffffff16610d41565b61104357600080fd5b604080516060808201835260a085015163ffffffff9081168352608086015181166020808501918252610100880180518051908301207fffffffffffffffffffffffffffffffffffffffff000000000000000000000000168688019081526101208a0180518051908501206000908152600285528981208c5161ffff16825290945292889020965187549451915190961c68010000000000000000027fffffffff0000000000000000000000000000000000000000ffffffffffffffff918616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909516969095169590951792909217939093169190911790925551905191517f55ced933cdd5a34dd03eb5d4bef19ec6ebb251dcd7a988eee0c1b9a13baaa88b9261117692916130b5565b60405180910390a15061010001519392505050565b604080516101408101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018190526101008201819052610120820152906111e6908390611c77565b61ffff1681526111f7826002611890565b60ff16602082015261120a826003611890565b60ff16604082015261121d826004611c9f565b63ffffffff9081166060830152611239908390600890611c9f16565b63ffffffff9081166080830152611255908390600c90611c9f16565b63ffffffff90811660a0830152611271908390601090611c7716565b61ffff1660c0820152611285826012611cc9565b60e08201819052516112c29061129c90601261319c565b8260e0015151601285516112b091906133dc565b6112ba91906133dc565b8491906118db565b610100820152919050565b6000806112e46112dd8483611aa6565b8490611c77565b8351602080860191909120865187830120600090815260028352604080822061ffff9095168252939092529190205468010000000000000000900460601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090811691161491505092915050565b6060600061135f84610d5a565b90505b80515160208201511015610b3757606081015161ffff1660011461138557600080fd5b815161139b5761139481611ce4565b91506113d7565b602081015181516113ab91611aa6565b8251146113b757600080fd5b8051602082015183516113ce928592600092611d05565b6113d757600080fd5b8261ffff16816040015161ffff16146113ef57600080fd5b6113f881610e7b565b611362565b6000805b83518310611438577f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60006114448585611890565b60ff16905061145481600161319c565b61145e908561319c565b93508061146b5750610a44565b61147660018361319c565b915050611401565b83518360e0015151111561149157600080fd5b6114b66000858560e001515187516114a991906133dc565b60e0870151929190611d28565b6114bf57600080fd5b60006114cb8282611a45565b604081015190915061ffff16602b14156114f8576114ea848483611d5d565b6114f357600080fd5b61157b565b604081015161ffff1660301415611514576114ea848483611df6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f2076616c69642070726f6f6620666f756e6400000000000000000000000060448201526064015b60405180910390fd5b5050505050565b60008061158f8482611890565b61159a9060016131b4565b60ff16905060005b8351811015610c19576115b784828785611d28565b156115c757600192505050610a47565b6115d18482611890565b6115dc9060016131b4565b6115e99060ff168261319c565b90506115a2565b6040805160c08101825260008082526020820181905291810182905260608082018190526080820183905260a08201529061162b838561319c565b905061164261163b60008661319c565b8690611890565b60ff16825261165561163b60018661319c565b60ff16602083015261167261166b60028661319c565b8690611c77565b61ffff166040830152600061169261168b60048761319c565b8790611890565b905061169f60058661319c565b94506116af868660ff84166118db565b60608401526116c160ff82168661319c565b945060006116cf8787611890565b905060208160ff1611156116e257600080fd5b6116ed60018761319c565b95506116fd878760ff8416611e9e565b608085015261170f60ff82168761319c565b95506117278661171f81866133dc565b8991906118db565b60a0850152509195945050505050565b600060ff600883811c82169183916117509186166131d9565b905060006117626007808716906133f3565b600160ff919091161b9050855b875181101561183f5760006117848983611890565b9050600061179d61179684600161319c565b8b90611890565b90508160ff168660ff1610156117bc57600096505050505050506108f7565b8160ff168660ff16141561181e578460ff168160ff16116117e657600096505050505050506108f7565b836118096117f760ff88168661319c565b61180290600261319c565b8c90611890565b1660ff166000141596505050505050506108f7565b6118298160026131b4565b6118369060ff168461319c565b9250505061176f565b506000979650505050505050565b60008061185a8584611984565b9050600061186785611874565b9190911495945050505050565b6000610a4760016118858484611890565b84919060ff16611edf565b60008282815181106118cb577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b016020015160f81c905092915050565b82516060906118ea838561319c565b11156118f557600080fd5b60008267ffffffffffffffff811115611937577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015611961576020820181803683370190505b509050602080820190868601016119798282876121af565b509095945050505050565b815160ff166000908152600560205260408082205460608501518286015192517f68f9dab200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216926368f9dab2926119f592918791600401613113565b60206040518083038186803b158015611a0d57600080fd5b505afa158015611a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a449190612dce565b611a936040518060e001604052806060815260200160008152602001600061ffff168152602001600061ffff168152602001600063ffffffff16815260200160008152602001600081525090565b82815260c08101829052610a4781610e7b565b6000815b83518110611ae1577f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b6000611aed8583611890565b60ff169050611afd81600161319c565b611b07908361319c565b915080611b145750611b1a565b50611aaa565b610c1d83826133dc565b6000611b308383612205565b15611b3d57506000610a47565b6000806000806000611b508860006113fd565b90506000611b5f8860006113fd565b90505b80821115611b8b57859350611b778987612223565b955081611b8381613416565b925050611b62565b81811115611bb457849250611ba08886612223565b945080611bac81613416565b915050611b8b565b600082118015611bcd5750611bcb89878a88611d28565b155b15611c0257859350611bdf8987612223565b9550849250611bee8886612223565b9450611bfb6001836133dc565b9150611bb4565b85611c17576000199650505050505050610a47565b84611c2b5760019650505050505050610a47565b611c6a611c3985600161319c565b611c438b87611890565b60ff168a611c5287600161319c565b611c5c8d89611890565b8e949392919060ff16612247565b9998505050505050505050565b8151600090611c8783600261319c565b1115611c9257600080fd5b50016002015161ffff1690565b8151600090611caf83600461319c565b1115611cba57600080fd5b50016004015163ffffffff1690565b60606000611cd78484611aa6565b9050610c1d8484836118db565b60208101518151606091610a4791611cfc9082611aa6565b845191906118db565b6000611d1284848461233c565b611d1d87878561233c565b149695505050505050565b6000611d418383848651611d3c91906133dc565b61233c565b611d538686878951611d3c91906133dc565b1495945050505050565b600080611d6985610d5a565b90505b80515160208201511015610c1957604081015161ffff16603014611d8f57600080fd5b6000611d9a82612360565b90506000611db5600083518461237c9092919063ffffffff16565b9050611dc38183898961241a565b15611de657611ddc611dd484611ce4565b868385612551565b93505050506108f7565b5050611df181610e7b565b611d6c565b6000611e0f8460e00151611e0984611ce4565b90612205565b611e1857600080fd5b81515160208301511015611e9457611e378460e00151611e0984611ce4565b611e4057600080fd5b6000611e4b83612360565b90506000611e66600083518461237c9092919063ffffffff16565b9050611e748183888861241a565b15611e84576001925050506108f7565b5050611e8f82610e7b565b611e18565b5060009392505050565b60006020821115611eae57600080fd5b8351611eba838561319c565b1115611ec557600080fd5b506020919092018101519190036101000a60001901191690565b60006034821115611eef57600080fd5b600080805b8481101561209257600087611f09838961319c565b81518110611f40577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b01602001517fff000000000000000000000000000000000000000000000000000000000000001690507f30000000000000000000000000000000000000000000000000000000000000008110801590611fdb57507f7a000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821611155b611fe457600080fd5b60405180608001604052806047815260200161355d6047913961200c603060f884901c6133dc565b81518110612043577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b0160209081015160f81c935083111561205b57600080fd5b6120666001876133dc565b8214156120735750612092565b5060059290921b60ff821617918061208a8161347b565b915050611ef4565b5060006120a08560056132e5565b90506120ad600886613496565b6120c2578160ff16600584901b179250612195565b6120cd600886613496565b600214156120fc5760028260ff16901c60ff16600384901b1792506002816120f591906133dc565b9050612195565b612107600886613496565b6004141561212f5760048260ff16901c60ff16600184901b1792506004816120f591906133dc565b61213a600886613496565b600514156121625760018260ff16901c60ff16600484901b1792506001816120f591906133dc565b61216d600886613496565b600714156100ea5760038260ff16901c60ff16600284901b1792506003816120f591906133dc565b6121a1816101006133dc565b9290921b9695505050505050565b602081106121e757815183526121c660208461319c565b92506121d360208361319c565b91506121e06020826133dc565b90506121af565b905182516020929092036101000a6000190180199091169116179052565b600081518351148015610a445750610a448360008460008751611d05565b600061222f8383611890565b60ff1661223d83600161319c565b610a44919061319c565b600084808310156122555750815b60208789018101908587010160005b8381101561232157825182518082146122f1576000602087111561228b57506000196122c7565b6001846122998960206133dc565b6122a3919061319c565b6122ae9060086132e5565b6122b990600261323d565b6122c391906133dc565b1990505b60006122d7838316858416613304565b905080156122ee5797506123329650505050505050565b50505b6122fc60208661319c565b945061230960208561319c565b9350505060208161231a919061319c565b9050612264565b5061232c8589613304565b93505050505b9695505050505050565b825160009061234b838561319c565b111561235657600080fd5b5091016020012090565b60a081015160c0820151606091610a4791611cfc9082906133dc565b60408051608081018252600080825260208201819052918101919091526060808201526123b46123ad60008561319c565b8590611c77565b61ffff1681526123cf6123c860028561319c565b8590611890565b60ff1660208201526123e56123c860038561319c565b60ff16604082015261240e6123fb60048561319c565b6124066004856133dc565b8691906118db565b60608201529392505050565b6000846020015160ff1660031461243357506000610c1d565b826020015160ff16856040015160ff161461245057506000610c1d565b600061245b85612652565b90508360c0015161ffff168161ffff161461247a576000915050610c1d565b85516101001661248e576000915050610c1d565b60408087015160ff16600090815260036020908152908290205485519186015192517fde8f50a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169263de8f50a192612501928a92906004016130da565b60206040518083038186803b15801561251957600080fd5b505afa15801561252d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123329190612dae565b60008061255d83612652565b90505b845151602086015110156126465760a085015160c08601516000916125939161258a9082906133dc565b8851919061237c565b90508161ffff16816000015161ffff16146125ae5750612638565b846040015160ff16816020015160ff16146125c95750612638565b6040805180820190915260608152600060208201526125f6855189516125ef919061319c565b8290612896565b5061260181896128fb565b5061260c81866128fb565b50612624826040015182600001518460600151612922565b156126355760019350505050610c1d565b50505b61264185610e7b565b612560565b50600095945050505050565b6000612000825111156126c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4c6f6e67206b657973206e6f74207065726d69747465640000000000000000006044820152606401611572565b60008060005b8451601f0181101561273657600081602087010151905085518260200111156126fc5785518290036008026101000390811c901b5b7eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff600882901c811694909401931691909101906020016126c7565b506010827fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c827dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff160191506010817fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c817dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff1601905080600883901b0191506020827fffffffff00000000ffffffff00000000ffffffff00000000ffffffff0000000016901c827bffffffff00000000ffffffff00000000ffffffff00000000ffffffff160191506040827fffffffffffffffff0000000000000000ffffffffffffffff000000000000000016901c8277ffffffffffffffff0000000000000000ffffffffffffffff16019150608082901c826fffffffffffffffffffffffffffffffff16019150601082901c61ffff16820191508192505050919050565b6040805180820190915260608152600060208201526128b6602083613496565b156128de576128c6602083613496565b6128d19060206133dc565b6128db908361319c565b91505b506020828101829052604080518085526000815290920101905290565b604080518082019091526060815260006020820152610a4483846000015151848551612a10565b60ff831660009081526004602052604081205473ffffffffffffffffffffffffffffffffffffffff16612957575060006108f7565b60ff84166000908152600460208190526040918290205491517ff7e83aee00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9092169163f7e83aee916129c09187918791016130b5565b60206040518083038186803b1580156129d857600080fd5b505afa1580156129ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1d9190612dae565b6040805180820190915260608152600060208201528251821115612a3357600080fd5b6020850151612a42838661319c565b1115612a7557612a7585612a6587602001518786612a60919061319c565b612afa565b612a709060026132e5565b612b11565b600080865180518760208301019350808887011115612a945787860182525b505050602084015b60208410612ad45780518252612ab360208361319c565b9150612ac060208261319c565b9050612acd6020856133dc565b9350612a9c565b51815160001960208690036101000a019081169019919091161790525083949350505050565b600081831115612b0b575081610a47565b50919050565b8151612b1d8383612896565b5061084983826128fb565b60008083601f840112612b39578182fd5b50813567ffffffffffffffff811115612b50578182fd5b602083019150836020828501011115612b6857600080fd5b9250929050565b600082601f830112612b7f578081fd5b813567ffffffffffffffff811115612b9957612b99613508565b612bca60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161314d565b818152846020838601011115612bde578283fd5b816020850160208301379081016020019190915292915050565b600060408284031215612c09578081fd5b6040516040810167ffffffffffffffff8282108183111715612c2d57612c2d613508565b816040528293508435915080821115612c4557600080fd5b612c5186838701612b6f565b83526020850135915080821115612c6757600080fd5b50612c7485828601612b6f565b6020830152505092915050565b803561ffff81168114612c9357600080fd5b919050565b803560ff81168114612c9357600080fd5b600060208284031215612cba578081fd5b8135610a4481613537565b600080600060408486031215612cd9578182fd5b833567ffffffffffffffff80821115612cf0578384fd5b818601915086601f830112612d03578384fd5b8135602082821115612d1757612d17613508565b8160051b612d2682820161314d565b8381528281019086840183880185018d1015612d4057898afd5b8993505b85841015612d7d57803587811115612d5a578a8bfd5b612d688e87838c0101612bf8565b84525060019390930192918401918401612d44565b509850505087013592505080821115612d94578384fd5b50612da186828701612b28565b9497909650939450505050565b600060208284031215612dbf578081fd5b81518015158114610a44578182fd5b600060208284031215612ddf578081fd5b5051919050565b60008060408385031215612df8578182fd5b823567ffffffffffffffff80821115612e0f578384fd5b612e1b86838701612bf8565b93506020850135915080821115612e30578283fd5b50612e3d85828601612b6f565b9150509250929050565b600080600060408486031215612e5b578283fd5b612e6484612c81565b9250602084013567ffffffffffffffff811115612e7f578283fd5b612da186828701612b28565b60008060008060808587031215612ea0578081fd5b612ea985612c81565b9350602085013567ffffffffffffffff80821115612ec5578283fd5b612ed188838901612b6f565b94506040870135915080821115612ee6578283fd5b612ef288838901612bf8565b93506060870135915080821115612f07578283fd5b50612f1487828801612b6f565b91505092959194509250565b600080600080600060a08688031215612f37578081fd5b612f4086612c81565b9450602086013567ffffffffffffffff80821115612f5c578283fd5b612f6889838a01612b6f565b95506040880135915080821115612f7d578283fd5b612f8989838a01612bf8565b94506060880135915080821115612f9e578283fd5b612faa89838a01612bf8565b93506080880135915080821115612fbf578283fd5b50612fcc88828901612b6f565b9150509295509295909350565b600060208284031215612fea578081fd5b610a4482612c98565b60008060408385031215613005578182fd5b61300e83612c98565b9150602083013561301e81613537565b809150509250929050565b60008151808452815b8181101561304e57602081850181015186830182015201613032565b8181111561305f5782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8183823760009101908152919050565b602081526000610a446020830184613029565b6040815260006130c86040830185613029565b8281036020840152610d388185613029565b6060815260006130ed6060830186613029565b82810360208401526130ff8186613029565b905082810360408401526123328185613029565b6060815260006131266060830186613029565b82810360208401526131388186613029565b91505061ffff83166040830152949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561319457613194613508565b604052919050565b600082198211156131af576131af6134aa565b500190565b600060ff821660ff84168060ff038211156131d1576131d16134aa565b019392505050565b600061ffff808416806131ee576131ee6134d9565b92169190910492915050565b600181815b8085111561323557816000190482111561321b5761321b6134aa565b8085161561322857918102915b93841c93908002906131ff565b509250929050565b6000610a44838360008261325357506001610a47565b8161326057506000610a47565b816001811461327657600281146132805761329c565b6001915050610a47565b60ff841115613291576132916134aa565b50506001821b610a47565b5060208310610133831016604e8410600b84101617156132bf575081810a610a47565b6132c983836131fa565b80600019048211156132dd576132dd6134aa565b029392505050565b60008160001904831182151516156132ff576132ff6134aa565b500290565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561333e5761333e6134aa565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018313811615613372576133726134aa565b50500390565b60008160030b8360030b828112817fffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000018312811516156133ba576133ba6134aa565b81637fffffff0183138116156133d2576133d26134aa565b5090039392505050565b6000828210156133ee576133ee6134aa565b500390565b600060ff821660ff84168082101561340d5761340d6134aa565b90039392505050565b600081613425576134256134aa565b506000190190565b600181811c9082168061344157607f821691505b60208210811415612b0b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060001982141561348f5761348f6134aa565b5060010190565b6000826134a5576134a56134d9565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461355957600080fd5b5056fe00010203040506070809ffffffffffffff0a0b0c0d0e0f101112131415161718191a1b1c1d1e1fffffffffffffffffffff0a0b0c0d0e0f101112131415161718191a1b1c1d1e1fa264697066735822122021dd1abc05c3cbc1d56c91af7ce4f1050efc7b81ed60cdbe68e35a4dc1df0bb364736f6c63430008040033",
  "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c806373cc48a61161008c57806398d35f201161006657806398d35f201461025b578063bd7ed31a14610263578063c327deef14610299578063d7b82ebe146102cf57600080fd5b806373cc48a6146101cd5780638438dc04146102285780638da5cb5b1461023b57600080fd5b806313af4035116100c857806313af40351461017457806328e7677d146101875780632c095cbb1461019a578063435cc162146101ad57600080fd5b8063020ed8d3146100ef578063087991bc146101045780630b1a249514610161575b600080fd5b6101026100fd366004612ff3565b6102e2565b005b610117610112366004612e47565b610396565b6040805163ffffffff94851681529390921660208401527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016908201526060015b60405180910390f35b61010261016f366004612f20565b61040b565b610102610182366004612ca9565b6105fa565b610102610195366004612ff3565b610665565b6101026101a8366004612e8b565b610711565b6101c06101bb366004612cc5565b61084f565b60405161015891906130a2565b6102036101db366004612fd9565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610158565b610102610236366004612ff3565b6108fe565b6001546102039073ffffffffffffffffffffffffffffffffffffffff1681565b6101c06109aa565b610203610271366004612fd9565b60056020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6102036102a7366004612fd9565b60036020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6101c06102dd366004612de6565b610a38565b60015473ffffffffffffffffffffffffffffffffffffffff16331461030657600080fd5b60ff821660008181526003602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251938452908301527ff73c3c226af96b7f1ba666a21b3ceaf2be3ee6a365e3178fd9cd1eaae0075aa891015b60405180910390a15050565b6000806000806002600087876040516103b0929190613092565b60408051918290039091208252602080830193909352908101600090812061ffff8b16825290925290205463ffffffff8082169550640100000000820416935068010000000000000000900460601b91505093509350939050565b8351602080860191909120600090815260028252604080822061ffff891683529092529081205463ffffffff16906104438584610a4d565b9050610450818784610b3e565b604080516101408101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e081018290526101008101829052610120810191909152845151156104c2576104b58585610a4d565b90506104c2818885610b3e565b60006104cd83610b84565b602081015190915060fe16156104e257600080fd5b6104ed816027610be3565b1580156105125750610500816002610be3565b15806105125750610512816006610be3565b61051b57600080fd5b61052c898985610120015184610bf5565b156105805787516020808a0191909120600090815260028252604080822061ffff8d1683529092522080547fffffffff000000000000000000000000000000000000000000000000000000001690556105ef565b61059f888461012001518385610120015161059a87610b84565b610c25565b156100ea5787516020808a0191909120600090815260028252604080822061ffff8d1683529092522080547fffffffff000000000000000000000000000000000000000000000000000000001690555b505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461061e57600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff16331461068957600080fd5b60ff821660008181526004602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251938452908301527f2fcc274c3b72dd483ab201bfa87295e3817e8b9b10693219873b722ca1af00c7910161038a565b604080516101408101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e08101829052610100810182905261012081019190915261076e8383610a4d565b805190915061ffff16602f1461078357600080fd5b60a08101518451602080870191909120600090815260028252604080822061ffff8a16835290925220546107bd919063ffffffff16610d41565b6107c657600080fd5b60006107d182610d5a565b905080515160208201511015610843576107f2818361012001518789610db8565b50508251602080850191909120600090815260028252604080822061ffff881683529092522080547fffffffff00000000000000000000000000000000000000000000000000000000169055610849565b50600080fd5b50505050565b6060600083838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b85518110156108f3576108df8682815181106108d1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015183610f63565b9150806108eb8161347b565b91505061088c565b5090505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461092257600080fd5b60ff821660008181526005602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251938452908301527fc7eec866a7a1386188cc3ca20ffea75b71bd3e90a60b6791b1d3f0971145118d910161038a565b600080546109b79061342d565b80601f01602080910402602001604051908101604052809291908181526020018280546109e39061342d565b8015610a305780601f10610a0557610100808354040283529160200191610a30565b820191906000526020600020905b815481529060010190602001808311610a1357829003601f168201915b505050505081565b6060610a448383610f63565b90505b92915050565b604080516101408101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e0810182905261010081018290526101208101919091528251610aab9061118b565b9050610abb8160e00151836112cd565b610ac457600080fd5b6000610ad4828360000151611352565b604083015190915060ff16610aea8260006113fd565b14610af457600080fd5b61012082018190526080820151610b0b9042610d41565b610b1457600080fd5b610b22428360a00151610d41565b610b2b57600080fd5b610b378183868661147e565b5092915050565b610b4c8360a0015182610d41565b610b5557600080fd5b825161ffff16603214610b6757600080fd5b610b7683610120015183611582565b610b7f57600080fd5b505050565b6040805160c08101825260008082526020820181905291810182905260608082018190526080820183905260a082015290610bbe83610d5a565b60a081015160c08201519192506108f791610bda9082906133dc565b835191906115f0565b6000610a448360a00151600084611737565b6000610c0282848661184d565b15610c1957610c118286610be3565b159050610c1d565b5060005b949350505050565b602081015160009060fe1615610c3a57600080fd5b6000610c4586611874565b90506000610c5285611874565b9050600080610c618a82611890565b610c6c9060016131b4565b60ff1690505b8951811015610d2f5783610c9e89610c9984858f51610c9191906133dc565b8f91906118db565b611984565b1415610d03576000610cbb87610c9985868f51610c9191906133dc565b90508660800151841015610ce7578381118015610cdb5750866080015181105b95505050505050610d38565b83811180610cdb57508660800151811095505050505050610d38565b905080610d108a82611890565b610d1b9060016131b4565b610d289060ff168261319c565b9050610c72565b50600093505050505b95945050505050565b600080610d4e8385613378565b60030b12159392505050565b610da86040518060e001604052806060815260200160008152602001600061ffff168152602001600061ffff168152602001600063ffffffff16815260200160008152602001600081525090565b610a478261010001516000611a45565b60a08401518451600090610dcc9083611aa6565b905060008660a001518760c00151610de491906133dc565b9050818111610df257600080fd5b6000610dfe8688611b24565b905080610e2a57610e1b610e12848661319c565b89519087611737565b15610e2557600080fd5b610e71565b8751600090610e3a9086866118db565b905060008213610e4957600080fd5b6000610e558983611b24565b12156105ef576000610e678883611b24565b126105ef57600080fd5b5050505050505050565b60c08101516020820181905281515111610e925750565b6000610ea682600001518360200151611aa6565b8260200151610eb5919061319c565b8251909150610ec49082611c77565b61ffff166040830152610ed860028261319c565b8251909150610ee79082611c77565b61ffff166060830152610efb60028261319c565b8251909150610f0a9082611c9f565b63ffffffff166080830152610f2060048261319c565b8251909150600090610f329083611c77565b61ffff169050610f4360028361319c565b60a084018190529150610f56818361319c565b60c0909301929092525050565b604080516101408101825260008082526020820181905291810182905260608181018390526080820183905260a0820183905260c082019290925260e0810182905261010081018290526101208101829052610fbf8484610a4d565b61012081015180516020918201206000908152600282526040808220845161ffff1683529092522080549192509068010000000000000000900460601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016156110435760a0820151815461103a919063ffffffff16610d41565b61104357600080fd5b604080516060808201835260a085015163ffffffff9081168352608086015181166020808501918252610100880180518051908301207fffffffffffffffffffffffffffffffffffffffff000000000000000000000000168688019081526101208a0180518051908501206000908152600285528981208c5161ffff16825290945292889020965187549451915190961c68010000000000000000027fffffffff0000000000000000000000000000000000000000ffffffffffffffff918616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909516969095169590951792909217939093169190911790925551905191517f55ced933cdd5a34dd03eb5d4bef19ec6ebb251dcd7a988eee0c1b9a13baaa88b9261117692916130b5565b60405180910390a15061010001519392505050565b604080516101408101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018190526101008201819052610120820152906111e6908390611c77565b61ffff1681526111f7826002611890565b60ff16602082015261120a826003611890565b60ff16604082015261121d826004611c9f565b63ffffffff9081166060830152611239908390600890611c9f16565b63ffffffff9081166080830152611255908390600c90611c9f16565b63ffffffff90811660a0830152611271908390601090611c7716565b61ffff1660c0820152611285826012611cc9565b60e08201819052516112c29061129c90601261319c565b8260e0015151601285516112b091906133dc565b6112ba91906133dc565b8491906118db565b610100820152919050565b6000806112e46112dd8483611aa6565b8490611c77565b8351602080860191909120865187830120600090815260028352604080822061ffff9095168252939092529190205468010000000000000000900460601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090811691161491505092915050565b6060600061135f84610d5a565b90505b80515160208201511015610b3757606081015161ffff1660011461138557600080fd5b815161139b5761139481611ce4565b91506113d7565b602081015181516113ab91611aa6565b8251146113b757600080fd5b8051602082015183516113ce928592600092611d05565b6113d757600080fd5b8261ffff16816040015161ffff16146113ef57600080fd5b6113f881610e7b565b611362565b6000805b83518310611438577f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60006114448585611890565b60ff16905061145481600161319c565b61145e908561319c565b93508061146b5750610a44565b61147660018361319c565b915050611401565b83518360e0015151111561149157600080fd5b6114b66000858560e001515187516114a991906133dc565b60e0870151929190611d28565b6114bf57600080fd5b60006114cb8282611a45565b604081015190915061ffff16602b14156114f8576114ea848483611d5d565b6114f357600080fd5b61157b565b604081015161ffff1660301415611514576114ea848483611df6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f2076616c69642070726f6f6620666f756e6400000000000000000000000060448201526064015b60405180910390fd5b5050505050565b60008061158f8482611890565b61159a9060016131b4565b60ff16905060005b8351811015610c19576115b784828785611d28565b156115c757600192505050610a47565b6115d18482611890565b6115dc9060016131b4565b6115e99060ff168261319c565b90506115a2565b6040805160c08101825260008082526020820181905291810182905260608082018190526080820183905260a08201529061162b838561319c565b905061164261163b60008661319c565b8690611890565b60ff16825261165561163b60018661319c565b60ff16602083015261167261166b60028661319c565b8690611c77565b61ffff166040830152600061169261168b60048761319c565b8790611890565b905061169f60058661319c565b94506116af868660ff84166118db565b60608401526116c160ff82168661319c565b945060006116cf8787611890565b905060208160ff1611156116e257600080fd5b6116ed60018761319c565b95506116fd878760ff8416611e9e565b608085015261170f60ff82168761319c565b95506117278661171f81866133dc565b8991906118db565b60a0850152509195945050505050565b600060ff600883811c82169183916117509186166131d9565b905060006117626007808716906133f3565b600160ff919091161b9050855b875181101561183f5760006117848983611890565b9050600061179d61179684600161319c565b8b90611890565b90508160ff168660ff1610156117bc57600096505050505050506108f7565b8160ff168660ff16141561181e578460ff168160ff16116117e657600096505050505050506108f7565b836118096117f760ff88168661319c565b61180290600261319c565b8c90611890565b1660ff166000141596505050505050506108f7565b6118298160026131b4565b6118369060ff168461319c565b9250505061176f565b506000979650505050505050565b60008061185a8584611984565b9050600061186785611874565b9190911495945050505050565b6000610a4760016118858484611890565b84919060ff16611edf565b60008282815181106118cb577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b016020015160f81c905092915050565b82516060906118ea838561319c565b11156118f557600080fd5b60008267ffffffffffffffff811115611937577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015611961576020820181803683370190505b509050602080820190868601016119798282876121af565b509095945050505050565b815160ff166000908152600560205260408082205460608501518286015192517f68f9dab200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216926368f9dab2926119f592918791600401613113565b60206040518083038186803b158015611a0d57600080fd5b505afa158015611a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a449190612dce565b611a936040518060e001604052806060815260200160008152602001600061ffff168152602001600061ffff168152602001600063ffffffff16815260200160008152602001600081525090565b82815260c08101829052610a4781610e7b565b6000815b83518110611ae1577f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b6000611aed8583611890565b60ff169050611afd81600161319c565b611b07908361319c565b915080611b145750611b1a565b50611aaa565b610c1d83826133dc565b6000611b308383612205565b15611b3d57506000610a47565b6000806000806000611b508860006113fd565b90506000611b5f8860006113fd565b90505b80821115611b8b57859350611b778987612223565b955081611b8381613416565b925050611b62565b81811115611bb457849250611ba08886612223565b945080611bac81613416565b915050611b8b565b600082118015611bcd5750611bcb89878a88611d28565b155b15611c0257859350611bdf8987612223565b9550849250611bee8886612223565b9450611bfb6001836133dc565b9150611bb4565b85611c17576000199650505050505050610a47565b84611c2b5760019650505050505050610a47565b611c6a611c3985600161319c565b611c438b87611890565b60ff168a611c5287600161319c565b611c5c8d89611890565b8e949392919060ff16612247565b9998505050505050505050565b8151600090611c8783600261319c565b1115611c9257600080fd5b50016002015161ffff1690565b8151600090611caf83600461319c565b1115611cba57600080fd5b50016004015163ffffffff1690565b60606000611cd78484611aa6565b9050610c1d8484836118db565b60208101518151606091610a4791611cfc9082611aa6565b845191906118db565b6000611d1284848461233c565b611d1d87878561233c565b149695505050505050565b6000611d418383848651611d3c91906133dc565b61233c565b611d538686878951611d3c91906133dc565b1495945050505050565b600080611d6985610d5a565b90505b80515160208201511015610c1957604081015161ffff16603014611d8f57600080fd5b6000611d9a82612360565b90506000611db5600083518461237c9092919063ffffffff16565b9050611dc38183898961241a565b15611de657611ddc611dd484611ce4565b868385612551565b93505050506108f7565b5050611df181610e7b565b611d6c565b6000611e0f8460e00151611e0984611ce4565b90612205565b611e1857600080fd5b81515160208301511015611e9457611e378460e00151611e0984611ce4565b611e4057600080fd5b6000611e4b83612360565b90506000611e66600083518461237c9092919063ffffffff16565b9050611e748183888861241a565b15611e84576001925050506108f7565b5050611e8f82610e7b565b611e18565b5060009392505050565b60006020821115611eae57600080fd5b8351611eba838561319c565b1115611ec557600080fd5b506020919092018101519190036101000a60001901191690565b60006034821115611eef57600080fd5b600080805b8481101561209257600087611f09838961319c565b81518110611f40577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b01602001517fff000000000000000000000000000000000000000000000000000000000000001690507f30000000000000000000000000000000000000000000000000000000000000008110801590611fdb57507f7a000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821611155b611fe457600080fd5b60405180608001604052806047815260200161355d6047913961200c603060f884901c6133dc565b81518110612043577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b0160209081015160f81c935083111561205b57600080fd5b6120666001876133dc565b8214156120735750612092565b5060059290921b60ff821617918061208a8161347b565b915050611ef4565b5060006120a08560056132e5565b90506120ad600886613496565b6120c2578160ff16600584901b179250612195565b6120cd600886613496565b600214156120fc5760028260ff16901c60ff16600384901b1792506002816120f591906133dc565b9050612195565b612107600886613496565b6004141561212f5760048260ff16901c60ff16600184901b1792506004816120f591906133dc565b61213a600886613496565b600514156121625760018260ff16901c60ff16600484901b1792506001816120f591906133dc565b61216d600886613496565b600714156100ea5760038260ff16901c60ff16600284901b1792506003816120f591906133dc565b6121a1816101006133dc565b9290921b9695505050505050565b602081106121e757815183526121c660208461319c565b92506121d360208361319c565b91506121e06020826133dc565b90506121af565b905182516020929092036101000a6000190180199091169116179052565b600081518351148015610a445750610a448360008460008751611d05565b600061222f8383611890565b60ff1661223d83600161319c565b610a44919061319c565b600084808310156122555750815b60208789018101908587010160005b8381101561232157825182518082146122f1576000602087111561228b57506000196122c7565b6001846122998960206133dc565b6122a3919061319c565b6122ae9060086132e5565b6122b990600261323d565b6122c391906133dc565b1990505b60006122d7838316858416613304565b905080156122ee5797506123329650505050505050565b50505b6122fc60208661319c565b945061230960208561319c565b9350505060208161231a919061319c565b9050612264565b5061232c8589613304565b93505050505b9695505050505050565b825160009061234b838561319c565b111561235657600080fd5b5091016020012090565b60a081015160c0820151606091610a4791611cfc9082906133dc565b60408051608081018252600080825260208201819052918101919091526060808201526123b46123ad60008561319c565b8590611c77565b61ffff1681526123cf6123c860028561319c565b8590611890565b60ff1660208201526123e56123c860038561319c565b60ff16604082015261240e6123fb60048561319c565b6124066004856133dc565b8691906118db565b60608201529392505050565b6000846020015160ff1660031461243357506000610c1d565b826020015160ff16856040015160ff161461245057506000610c1d565b600061245b85612652565b90508360c0015161ffff168161ffff161461247a576000915050610c1d565b85516101001661248e576000915050610c1d565b60408087015160ff16600090815260036020908152908290205485519186015192517fde8f50a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169263de8f50a192612501928a92906004016130da565b60206040518083038186803b15801561251957600080fd5b505afa15801561252d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123329190612dae565b60008061255d83612652565b90505b845151602086015110156126465760a085015160c08601516000916125939161258a9082906133dc565b8851919061237c565b90508161ffff16816000015161ffff16146125ae5750612638565b846040015160ff16816020015160ff16146125c95750612638565b6040805180820190915260608152600060208201526125f6855189516125ef919061319c565b8290612896565b5061260181896128fb565b5061260c81866128fb565b50612624826040015182600001518460600151612922565b156126355760019350505050610c1d565b50505b61264185610e7b565b612560565b50600095945050505050565b6000612000825111156126c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4c6f6e67206b657973206e6f74207065726d69747465640000000000000000006044820152606401611572565b60008060005b8451601f0181101561273657600081602087010151905085518260200111156126fc5785518290036008026101000390811c901b5b7eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff600882901c811694909401931691909101906020016126c7565b506010827fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c827dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff160191506010817fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c817dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff1601905080600883901b0191506020827fffffffff00000000ffffffff00000000ffffffff00000000ffffffff0000000016901c827bffffffff00000000ffffffff00000000ffffffff00000000ffffffff160191506040827fffffffffffffffff0000000000000000ffffffffffffffff000000000000000016901c8277ffffffffffffffff0000000000000000ffffffffffffffff16019150608082901c826fffffffffffffffffffffffffffffffff16019150601082901c61ffff16820191508192505050919050565b6040805180820190915260608152600060208201526128b6602083613496565b156128de576128c6602083613496565b6128d19060206133dc565b6128db908361319c565b91505b506020828101829052604080518085526000815290920101905290565b604080518082019091526060815260006020820152610a4483846000015151848551612a10565b60ff831660009081526004602052604081205473ffffffffffffffffffffffffffffffffffffffff16612957575060006108f7565b60ff84166000908152600460208190526040918290205491517ff7e83aee00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9092169163f7e83aee916129c09187918791016130b5565b60206040518083038186803b1580156129d857600080fd5b505afa1580156129ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1d9190612dae565b6040805180820190915260608152600060208201528251821115612a3357600080fd5b6020850151612a42838661319c565b1115612a7557612a7585612a6587602001518786612a60919061319c565b612afa565b612a709060026132e5565b612b11565b600080865180518760208301019350808887011115612a945787860182525b505050602084015b60208410612ad45780518252612ab360208361319c565b9150612ac060208261319c565b9050612acd6020856133dc565b9350612a9c565b51815160001960208690036101000a019081169019919091161790525083949350505050565b600081831115612b0b575081610a47565b50919050565b8151612b1d8383612896565b5061084983826128fb565b60008083601f840112612b39578182fd5b50813567ffffffffffffffff811115612b50578182fd5b602083019150836020828501011115612b6857600080fd5b9250929050565b600082601f830112612b7f578081fd5b813567ffffffffffffffff811115612b9957612b99613508565b612bca60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161314d565b818152846020838601011115612bde578283fd5b816020850160208301379081016020019190915292915050565b600060408284031215612c09578081fd5b6040516040810167ffffffffffffffff8282108183111715612c2d57612c2d613508565b816040528293508435915080821115612c4557600080fd5b612c5186838701612b6f565b83526020850135915080821115612c6757600080fd5b50612c7485828601612b6f565b6020830152505092915050565b803561ffff81168114612c9357600080fd5b919050565b803560ff81168114612c9357600080fd5b600060208284031215612cba578081fd5b8135610a4481613537565b600080600060408486031215612cd9578182fd5b833567ffffffffffffffff80821115612cf0578384fd5b818601915086601f830112612d03578384fd5b8135602082821115612d1757612d17613508565b8160051b612d2682820161314d565b8381528281019086840183880185018d1015612d4057898afd5b8993505b85841015612d7d57803587811115612d5a578a8bfd5b612d688e87838c0101612bf8565b84525060019390930192918401918401612d44565b509850505087013592505080821115612d94578384fd5b50612da186828701612b28565b9497909650939450505050565b600060208284031215612dbf578081fd5b81518015158114610a44578182fd5b600060208284031215612ddf578081fd5b5051919050565b60008060408385031215612df8578182fd5b823567ffffffffffffffff80821115612e0f578384fd5b612e1b86838701612bf8565b93506020850135915080821115612e30578283fd5b50612e3d85828601612b6f565b9150509250929050565b600080600060408486031215612e5b578283fd5b612e6484612c81565b9250602084013567ffffffffffffffff811115612e7f578283fd5b612da186828701612b28565b60008060008060808587031215612ea0578081fd5b612ea985612c81565b9350602085013567ffffffffffffffff80821115612ec5578283fd5b612ed188838901612b6f565b94506040870135915080821115612ee6578283fd5b612ef288838901612bf8565b93506060870135915080821115612f07578283fd5b50612f1487828801612b6f565b91505092959194509250565b600080600080600060a08688031215612f37578081fd5b612f4086612c81565b9450602086013567ffffffffffffffff80821115612f5c578283fd5b612f6889838a01612b6f565b95506040880135915080821115612f7d578283fd5b612f8989838a01612bf8565b94506060880135915080821115612f9e578283fd5b612faa89838a01612bf8565b93506080880135915080821115612fbf578283fd5b50612fcc88828901612b6f565b9150509295509295909350565b600060208284031215612fea578081fd5b610a4482612c98565b60008060408385031215613005578182fd5b61300e83612c98565b9150602083013561301e81613537565b809150509250929050565b60008151808452815b8181101561304e57602081850181015186830182015201613032565b8181111561305f5782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8183823760009101908152919050565b602081526000610a446020830184613029565b6040815260006130c86040830185613029565b8281036020840152610d388185613029565b6060815260006130ed6060830186613029565b82810360208401526130ff8186613029565b905082810360408401526123328185613029565b6060815260006131266060830186613029565b82810360208401526131388186613029565b91505061ffff83166040830152949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561319457613194613508565b604052919050565b600082198211156131af576131af6134aa565b500190565b600060ff821660ff84168060ff038211156131d1576131d16134aa565b019392505050565b600061ffff808416806131ee576131ee6134d9565b92169190910492915050565b600181815b8085111561323557816000190482111561321b5761321b6134aa565b8085161561322857918102915b93841c93908002906131ff565b509250929050565b6000610a44838360008261325357506001610a47565b8161326057506000610a47565b816001811461327657600281146132805761329c565b6001915050610a47565b60ff841115613291576132916134aa565b50506001821b610a47565b5060208310610133831016604e8410600b84101617156132bf575081810a610a47565b6132c983836131fa565b80600019048211156132dd576132dd6134aa565b029392505050565b60008160001904831182151516156132ff576132ff6134aa565b500290565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561333e5761333e6134aa565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018313811615613372576133726134aa565b50500390565b60008160030b8360030b828112817fffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000018312811516156133ba576133ba6134aa565b81637fffffff0183138116156133d2576133d26134aa565b5090039392505050565b6000828210156133ee576133ee6134aa565b500390565b600060ff821660ff84168082101561340d5761340d6134aa565b90039392505050565b600081613425576134256134aa565b506000190190565b600181811c9082168061344157607f821691505b60208210811415612b0b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060001982141561348f5761348f6134aa565b5060010190565b6000826134a5576134a56134d9565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461355957600080fd5b5056fe00010203040506070809ffffffffffffff0a0b0c0d0e0f101112131415161718191a1b1c1d1e1fffffffffffffffffffff0a0b0c0d0e0f101112131415161718191a1b1c1d1e1fa264697066735822122021dd1abc05c3cbc1d56c91af7ce4f1050efc7b81ed60cdbe68e35a4dc1df0bb364736f6c63430008040033",
  "devdoc": {
    "kind": "dev",
    "methods": {
      "constructor": {
        "details": "Constructor.",
        "params": {
          "_anchors": "The binary format RR entries for the root DS records."
        }
      },
      "deleteRRSet(uint16,bytes,(bytes,bytes),bytes)": {
        "details": "Deletes an RR from the oracle.",
        "params": {
          "deleteName": "which you want to delete",
          "deleteType": "The DNS record type to delete.",
          "nsec": "The signed NSEC RRset. This is in the format described in section        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature        data, followed by a series of canonicalised RR records that the signature        applies to."
        }
      },
      "deleteRRSetNSEC3(uint16,bytes,(bytes,bytes),(bytes,bytes),bytes)": {
        "details": "Deletes an RR from the oracle using an NSEC3 proof.      Deleting a record using NSEC3 requires using up to two NSEC3 records. There are two cases:       1. The name exists, but the record type doesn't. Eg, example.com has A records but no TXT records.       2. The name does not exist, but a parent name does.      In the first case, we submit one NSEC3 proof in `closestEncloser` that matches the target name      but does not have the bit for `deleteType` set in its type bitmap. In the second case, we submit      two proofs: closestEncloser and nextClosest, that together prove that the name does not exist.      NSEC3 records are in the format described in section 5.3.2 of RFC4035: The RRDATA section      from the RRSIG without the signature data, followed by a series of canonicalised RR records      that the signature applies to.",
        "params": {
          "closestEncloser": "An NSEC3 proof matching the closest enclosing name - that is,        the nearest ancestor of the target name that *does* exist.",
          "deleteName": "The name to delete.",
          "deleteType": "The DNS record type to delete.",
          "dnskey": "An encoded DNSKEY record that has already been submitted to the oracle and can be used        to verify the signatures closestEncloserSig and nextClosestSig",
          "nextClosest": "An NSEC3 proof covering the next closest name. This proves that the immediate        subdomain of the closestEncloser does not exist."
        }
      },
      "rrdata(uint16,bytes)": {
        "details": "Returns data about the RRs (if any) known to this oracle with the provided type and name.",
        "params": {
          "dnstype": "The DNS record type to query.",
          "name": "The name to query, in DNS label-sequence format."
        },
        "returns": {
          "_0": "inception The unix timestamp (wrapped) at which the signature for this RRSET was created.",
          "_1": "expiration The unix timestamp (wrapped) at which the signature for this RRSET expires.",
          "_2": "hash The hash of the RRset."
        }
      },
      "setAlgorithm(uint8,address)": {
        "details": "Sets the contract address for a signature verification algorithm.      Callable only by the owner.",
        "params": {
          "algo": "The address of the algorithm contract.",
          "id": "The algorithm ID"
        }
      },
      "setDigest(uint8,address)": {
        "details": "Sets the contract address for a digest verification algorithm.      Callable only by the owner.",
        "params": {
          "digest": "The address of the digest contract.",
          "id": "The digest ID"
        }
      },
      "setNSEC3Digest(uint8,address)": {
        "details": "Sets the contract address for an NSEC3 digest algorithm.      Callable only by the owner.",
        "params": {
          "digest": "The address of the digest contract.",
          "id": "The digest ID"
        }
      },
      "submitRRSet((bytes,bytes),bytes)": {
        "details": "Submits a signed set of RRs to the oracle. RRSETs are only accepted if they are signed with a key that is already trusted, or if they are self-signed, and the signing key is identified by a DS record that is already trusted.",
        "params": {
          "input": "The signed RR set. This is in the format described in section        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature        data, followed by a series of canonicalised RR records that the signature        applies to.",
          "proof": "The DNSKEY or DS to validate the signature against. Must Already        have been submitted and proved previously."
        }
      },
      "submitRRSets((bytes,bytes)[],bytes)": {
        "details": "Submits multiple RRSets",
        "params": {
          "_proof": "The DNSKEY or DS to validate the first signature against.",
          "input": "A list of RRSets and signatures forming a chain of trust from an existing known-good record."
        },
        "returns": {
          "_0": "The last RRSET submitted."
        }
      }
    },
    "version": 1
  },
  "userdoc": {
    "kind": "user",
    "methods": {},
    "version": 1
  },
  "storageLayout": {
    "storage": [
      {
        "astId": 4199,
        "contract": "contracts/dnssec-oracle/DNSSECImpl.sol:DNSSECImpl",
        "label": "anchors",
        "offset": 0,
        "slot": "0",
        "type": "t_bytes_storage"
      },
      {
        "astId": 6039,
        "contract": "contracts/dnssec-oracle/DNSSECImpl.sol:DNSSECImpl",
        "label": "owner",
        "offset": 0,
        "slot": "1",
        "type": "t_address"
      },
      {
        "astId": 4364,
        "contract": "contracts/dnssec-oracle/DNSSECImpl.sol:DNSSECImpl",
        "label": "rrsets",
        "offset": 0,
        "slot": "2",
        "type": "t_mapping(t_bytes32,t_mapping(t_uint16,t_struct(RRSet)4357_storage))"
      },
      {
        "astId": 4369,
        "contract": "contracts/dnssec-oracle/DNSSECImpl.sol:DNSSECImpl",
        "label": "algorithms",
        "offset": 0,
        "slot": "3",
        "type": "t_mapping(t_uint8,t_contract(Algorithm)7446)"
      },
      {
        "astId": 4374,
        "contract": "contracts/dnssec-oracle/DNSSECImpl.sol:DNSSECImpl",
        "label": "digests",
        "offset": 0,
        "slot": "4",
        "type": "t_mapping(t_uint8,t_contract(Digest)9287)"
      },
      {
        "astId": 4379,
        "contract": "contracts/dnssec-oracle/DNSSECImpl.sol:DNSSECImpl",
        "label": "nsec3Digests",
        "offset": 0,
        "slot": "5",
        "type": "t_mapping(t_uint8,t_contract(NSEC3Digest)9409)"
      }
    ],
    "types": {
      "t_address": {
        "encoding": "inplace",
        "label": "address",
        "numberOfBytes": "20"
      },
      "t_bytes20": {
        "encoding": "inplace",
        "label": "bytes20",
        "numberOfBytes": "20"
      },
      "t_bytes32": {
        "encoding": "inplace",
        "label": "bytes32",
        "numberOfBytes": "32"
      },
      "t_bytes_storage": {
        "encoding": "bytes",
        "label": "bytes",
        "numberOfBytes": "32"
      },
      "t_contract(Algorithm)7446": {
        "encoding": "inplace",
        "label": "contract Algorithm",
        "numberOfBytes": "20"
      },
      "t_contract(Digest)9287": {
        "encoding": "inplace",
        "label": "contract Digest",
        "numberOfBytes": "20"
      },
      "t_contract(NSEC3Digest)9409": {
        "encoding": "inplace",
        "label": "contract NSEC3Digest",
        "numberOfBytes": "20"
      },
      "t_mapping(t_bytes32,t_mapping(t_uint16,t_struct(RRSet)4357_storage))": {
        "encoding": "mapping",
        "key": "t_bytes32",
        "label": "mapping(bytes32 => mapping(uint16 => struct DNSSECImpl.RRSet))",
        "numberOfBytes": "32",
        "value": "t_mapping(t_uint16,t_struct(RRSet)4357_storage)"
      },
      "t_mapping(t_uint16,t_struct(RRSet)4357_storage)": {
        "encoding": "mapping",
        "key": "t_uint16",
        "label": "mapping(uint16 => struct DNSSECImpl.RRSet)",
        "numberOfBytes": "32",
        "value": "t_struct(RRSet)4357_storage"
      },
      "t_mapping(t_uint8,t_contract(Algorithm)7446)": {
        "encoding": "mapping",
        "key": "t_uint8",
        "label": "mapping(uint8 => contract Algorithm)",
        "numberOfBytes": "32",
        "value": "t_contract(Algorithm)7446"
      },
      "t_mapping(t_uint8,t_contract(Digest)9287)": {
        "encoding": "mapping",
        "key": "t_uint8",
        "label": "mapping(uint8 => contract Digest)",
        "numberOfBytes": "32",
        "value": "t_contract(Digest)9287"
      },
      "t_mapping(t_uint8,t_contract(NSEC3Digest)9409)": {
        "encoding": "mapping",
        "key": "t_uint8",
        "label": "mapping(uint8 => contract NSEC3Digest)",
        "numberOfBytes": "32",
        "value": "t_contract(NSEC3Digest)9409"
      },
      "t_struct(RRSet)4357_storage": {
        "encoding": "inplace",
        "label": "struct DNSSECImpl.RRSet",
        "members": [
          {
            "astId": 4352,
            "contract": "contracts/dnssec-oracle/DNSSECImpl.sol:DNSSECImpl",
            "label": "inception",
            "offset": 0,
            "slot": "0",
            "type": "t_uint32"
          },
          {
            "astId": 4354,
            "contract": "contracts/dnssec-oracle/DNSSECImpl.sol:DNSSECImpl",
            "label": "expiration",
            "offset": 4,
            "slot": "0",
            "type": "t_uint32"
          },
          {
            "astId": 4356,
            "contract": "contracts/dnssec-oracle/DNSSECImpl.sol:DNSSECImpl",
            "label": "hash",
            "offset": 8,
            "slot": "0",
            "type": "t_bytes20"
          }
        ],
        "numberOfBytes": "32"
      },
      "t_uint16": {
        "encoding": "inplace",
        "label": "uint16",
        "numberOfBytes": "2"
      },
      "t_uint32": {
        "encoding": "inplace",
        "label": "uint32",
        "numberOfBytes": "4"
      },
      "t_uint8": {
        "encoding": "inplace",
        "label": "uint8",
        "numberOfBytes": "1"
      }
    }
  }
}